Documentation:NGW/Newbie/Detailed IO Tutorial
From AVRFreaks Wiki
THIS IS STILL UNDER DEVELOPMENT
THIS IS STILL UNDER DEVELOPMENT
THIS IS STILL UNDER DEVELOPMENT
Please comment or amend if you like
Contents |
[edit] 4 IO Project Demo
This is a Project by a Newbie, for Newbie's
The Project is a Simple IO Demo
4 Pushbuttons or Switches wired to port E
The Pushbuttons will turn the LED's on the NGW100 on and off.
Look at Reading a Switched Input for GPIO Switch Info
Other Newbie INFO at Newbie
[edit] NGW100 Header
The first thing I had to do was solder a header onto the board.
I chose to use a 40 pin IDC header with a Key (Same as your old PATA Hard drive Cable)
Using pointy-noised pliers I pulled out 2 pins at each end. (pin 1, 2, 39,40) So now its a 36 way IDE Header.
Line up the key so Pin 1 lines up with Pin 1 on the NGW100 (Do the same to your DEV board. This way you can't cross the wires over and blow things up (maybe :) )
I chose to solder a 40way header to J7 & J5 (You Can't solder a 40way header into J6 & J7 at the same time, its one or the other. Just use a normal 36 way Dual in-line header on the other).
See here for board layout Mechanical dimensions
[edit] PushButton Input Design
I have created a 4 pushbutton IO Board with a limited debounce circuit.
Pushbutton A is wired to PE01 (J7 Pin 25)
Pushbutton B is wired to PE02 (J7 Pin 26)
Pushbutton C is wired to PE03 (J7 Pin 1)
Pushbutton D is wired to PE04 (J7 Pin 2)
See the Schematics page 10
[edit] Setting up the GPIO
Setting the pin to be an input pin
see PushButton Information create this file
vi switch
copy and paste this into the switch file
mkdir /config/gpio/switch0 cd /config/gpio/switch0 echo 4 > gpio_id echo 0x00000002 > pin_mask echo 0x00000000 > oe_mask echo 1 > enabled mkdir /config/gpio/switch1 cd /config/gpio/switch1 echo 4 > gpio_id echo 0x00000008 > pin_mask echo 0x00000000 > oe_mask echo 1 > enabled mkdir /config/gpio/switch2 cd /config/gpio/switch2 echo 4 > gpio_id echo 0x00000004 > pin_mask echo 0x00000000 > oe_mask echo 1 > enabled mkdir /config/gpio/switch3 cd /config/gpio/switch3 echo 4 > gpio_id echo 0x00000010 > pin_mask echo 0x00000000 > oe_mask
Now make it executable
chmod +x switch
Now run switch
./switch
[edit] Testing IO from Command line
Testing the pushbutton using the command line see PushButton Information
Run this command and then push the Pushbutton A a couple of times
less /dev/gpio3
You should see some garbage characters when you press the button
do the same for Pushbutton B
less /dev/gpio4
do the same for Pushbutton C
less /dev/gpio5
do the same for Pushbutton D
less /dev/gpio6
[edit] Testing IO from C Program
Compile this Program
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
static int fd;
static unsigned long old_state, new_state;
static int use_nonblock;
static int use_async;
static int use_poll;
/*
* When the -a option is given, this handler will be called whenever
* the pin state changes.
*/
static void sigio_handler(int sig, siginfo_t *info, void *context)
{
struct pollfd fds = {
.fd = fd,
.events = POLLIN,
};
unsigned long pin_state;
int ret;
if (use_poll) {
/* There should be data available immediately */
ret = poll(&fds, 1, 0);
if (ret < 0) {
perror("sigio_handler: poll:");
return;
} else if (ret == 0) {
fprintf(stderr,
"No data available in sigio_handler!\n");
return;
} else {
fprintf(stderr, "sigio_handler: poll() returned %d\n",
ret);
}
}
/*
* Even if use_nonblock is set, this should never fail as we
* shouldn't be here if no new data is available.
*/
if (read(fd, &pin_state, sizeof(pin_state)) < 0)
perror("read error in sigio_handler");
else
new_state = pin_state;
}
static void display_usage(const char *cmd)
{
fprintf(stderr, "Usage: %s [-ahnp] [gpio-device]\n\n", cmd);
fprintf(stderr, " -a Use asynchronous I/O (O_ASYNC)\n");
fprintf(stderr, " -h Display usage information (this message)\n");
fprintf(stderr, " -n Use nonblocking I/O (O_NONBLOCK)\n");
fprintf(stderr, " -p Use poll() to wait for I/O\n");
fprintf(stderr, "\nIf no gpio-device is specified, /dev/gpio0 is used\n");
}
int main(int argc, char **argv)
{
const char *dev_name = "/dev/gpio0";
while (1) {
int c;
c = getopt(argc, argv, "ahnp");
if (c == -1)
break;
switch (c) {
case 'a':
use_async = 1;
break;
case 'n':
use_nonblock = 1;
break;
case 'p':
use_poll = 1;
break;
case 'h':
case '?':
display_usage(argv[0]);
return 1;
default:
abort();
}
}
if (optind < argc)
dev_name = argv[optind++];
fd = open(dev_name, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "failed to open %s: %s\n",
dev_name, strerror(errno));
return 1;
}
if (use_async) {
struct sigaction sigio_action = {
.sa_sigaction = sigio_handler,
.sa_flags = SA_SIGINFO,
};
int flags;
/*
* Don't mask any signals when handling SIGIO (except
* SIGIO itself, which is masked by default.)
*/
sigemptyset(&sigio_action.sa_mask);
if (sigaction(SIGIO, &sigio_action, NULL)) {
perror("failed to install SIGIO handler");
return 1;
}
/* Tell the kernel that our process will take care of SIGIO */
if (fcntl(fd, F_SETOWN, getpid())) {
perror("failed to set fd owner");
return 1;
}
/* Enable asynchronous I/O */
flags = fcntl(fd, F_GETFL);
if (fcntl(fd, F_SETFL, flags | O_ASYNC) < 0) {
perror("failed to set O_ASYNC");
return 1;
}
}
if (use_nonblock) {
int flags;
/* Enable non-blocking I/O */
flags = fcntl(fd, F_GETFL);
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
perror("failed to set O_NONBLOCK");
return 1;
}
}
if (read(fd, &old_state, sizeof(old_state)) < 0) {
perror("failed to read initial pin state");
return 1;
}
new_state = old_state;
printf("0x%08lx\n", old_state);
if (use_async) {
sigset_t sigio_mask, saved_mask;
sigemptyset(&sigio_mask);
sigaddset(&sigio_mask, SIGIO);
/*
* In order to avoid race conditions with
* sigio_handler, we need to mask SIGIO while checking
* for updates to the pin state. sigsuspend() will
* atomically restore the sigmask (i.e. unmask SIGIO)
* and suspend the process until a signal comes along.
*/
sigprocmask(SIG_BLOCK, &sigio_mask, &saved_mask);
while (1) {
if (new_state != old_state) {
printf("0x%08lx\n", new_state);
old_state = new_state;
}
/*
* If SIGIO comes along here, we would miss an
* update. However, that won't happen since
* we've masked it.
*/
sigsuspend(&saved_mask);
/*
* sigsuspend() always returns with an
* error. If everything is normal, errno will
* be set to EINTR because we received a
* signal, and "Interrupted system call" will
* be displayed here.
*/
perror("sigsuspend");
}
} else {
struct pollfd fds = {
.fd = fd,
.events = POLLIN,
};
while (1) {
if (use_poll) {
int ret;
ret = poll(&fds, 1, 1000);
if (ret < 0) {
perror("poll");
return 1;
} else if (ret == 0) {
/*
* This is normal if no
* buttons are pushed for one
* second.
*/
fprintf(stderr, "poll() timed out\n");
continue;
} else {
/* ret should always be 1 here */
fprintf(stderr, "poll() returned %d\n",
ret);
}
}
if (read(fd, &new_state, sizeof(new_state)) < 0) {
/*
* If -n is given and not -p or -a,
* read() will fail with EAGAIN, and
* "Resource temporarily unavailable"
* will be printed regularly. This is
* normal.
*
* However, if -p is given, no errors
* should ever happen here, even with
* -n, as poll() will ensure that we
* never get here unless data is
* available for reading.
*/
perror("read error");
sleep(1);
} else {
printf("0x%08lx\n", new_state);
old_state = new_state;
}
}
}
}
I got it from GPIO Demo
run this for each GPIO
/media/mmcblk0p1/GPIOc.elf /dev/gpio4
Test Pushbutton output should look like this
0x00000008 0x00000000 Push Button B Pressed 0x00000008 Push Button B Released 0x00000000 Push Button B Pressed 0x00000008 Push Button B Released
Congratulation you have test all 4 push button switches independently
[edit] The END of Push Button TESTING
Now that we have tested each input we can bring it all together
Reboot to remove all the gpio configs
Create this file
vi SwitchPortE
copy and paste this into the SwitchPortE file
mkdir /config/gpio/SwitchPortE cd /config/gpio/SwitchPortE echo 4 > gpio_id echo 0x0000001E > pin_mask echo 0x00000000 > oe_mask echo 1 > enabled cd /
Now make it executable
chmod +x SwitchPortE
Now run SwitchPortE
./SwitchPortE
NOTE: When we are happy with all the code you can add it to /etc/init.d/S99gpio and delete SwitchPortE & switch
Run this
/media/mmcblk0p1/GPIOc.elf /dev/gpio3
Test Pushbutton output should look like this
0x0000001e Push Button Released 0x0000001c Push Button A Pressed 0x0000001e Push Button Released 0x00000016 Push Button B Pressed 0x0000001e Push Button Released 0x0000001a Push Button C Pressed 0x0000001e Push Button Released 0x0000000e Push Button D Pressed 0x0000001e Push Button Released
Press Push Button A & B (Together)
0x0000001e Push Button Released 0x0000001c Push Button A Pressed and Held 0x00000014 Push Button B Pressed 0x0000001c Push Button B Released 0x0000001e Push Button Released
Congratulation you have test all 4 push button switches
[edit] Make the Push Button turn LED's on & off
Ok this program will toggle the LED A on Press and toggle on release
Going to add more code to make it interesting
Compile this Program
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define BUFFERSIZE 257
#define LED_OFFSET 19
static int fd;
static unsigned long old_state, new_state;
static void display_usage(const char *cmd)
{
fprintf(stderr, "Usage: %s [gpio-device]\n\n", cmd);
fprintf(stderr, " -h Display usage information (this message)\n");
fprintf(stderr, "\nIf no gpio-device is specified, /dev/gpio0 is used\n");
}
int main(int argc, char **argv)
{
int led_on = -1;
unsigned int pio_buffer;
int pio = 0;
int retval = 0;
const char *dev_name = "/dev/gpio3";
while (1) {
int c;
c = getopt(argc, argv, "ahnp");
if (c == -1)
break;
switch (c) {
case 'h':
case '?':
display_usage(argv[0]);
return 1;
default:
abort();
}
}
if (optind < argc)
dev_name = argv[optind++];
fd = open(dev_name, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "failed to open %s: %s\n",
dev_name, strerror(errno));
return 1;
}
if (read(fd, &old_state, sizeof(old_state)) < 0) {
perror("failed to read initial pin state");
return 1;
}
new_state = old_state;
printf("0x%08lx\n", old_state);
while (1) {
if (read(fd, &new_state, sizeof(new_state)) < 0) {
perror("read error");
sleep(1);
} else {
printf("0x%08lx\n", new_state);
old_state = new_state;
/* Get status on LED */
pio = open("/dev/gpio1", O_RDWR|O_NONBLOCK);
if (pio < 0) {
printf("Error: I could not open the GPIO device.</p>\n");
return 1;
} else {
retval = read(pio, &pio_buffer, 4);
if (retval == 4) {
led_on = pio_buffer & (1<<LED_OFFSET) ? 0 : 1;
} else {
if (retval >= 0) {
printf("Error: I could only read %d bytes from the GPIO device.</p>\n", retval);
} else {
if (errno != EAGAIN) {
printf("Error: I could not read from the GPIO device (%d).</p>\n", errno);
}
}
}
}
if (led_on) {
printf("LED is on => ");
unsigned int off = 1<<LED_OFFSET;
write(pio, &off, 4);
printf("turning LED off => ");
} else {
printf("LED is off => ");
unsigned int on = 0;
write(pio, &on, 4);
printf("turning LED on => ");
}
close(pio);
}
}
}
The LED should now react with the 4 Push Buttons
