GPIO_Interrupt

GPIO Notification Driver


The gpio-notify driver is an event-based notification driver for the Gumstix which responds to GPIO hardware interrupts, inspects GPIO pin states to determine if pins have changed state, and sends SIGIO signals to user-space processes to notify them of any pin state changes. It has improved efficiency over sampling the GPIO pin status by continuous polling, which is very cpu-intensive.


Derivation from gpio-event


The gpio-notify driver is based on the gpio-event sample driver, which is a package available in the Gumstix OpenEmbedded distribution. Source for gpio-event consists of an archive, available at http://davehylands.com/gumstix-wiki/gpio-event/gpio-event-2.6.21-1444-select.tar.gz , and a Makefile patch, makefile.patch, located in the com.gumstix.collection/packages/gpio-event/files directory.


In order to decrease overhead, event queuing and passing through file calls like read() has been dropped from the driver level. The fasync signaling mechanism has been added to the driver so that user-space programs can wait for the driver to signal them when pin changes occur.


The first attempt at a high-performance driver based on gpio-event was gpio-event-fasync, which added the asynchronous notification mechanism described in Chapter 6 of Linux Device Drivers, 3rd Edition. However, during testing gpio-event-fasync was not able to deliver events reliably at a rate of 3000 events per second, likely because the overhead associated with timestamping each event and writing each event to the character device file /dev/gpio-event. In an attempt to reduce overhead and number of dropped events, gpio-event-fasync-simple removed the timestamping from events. However, this version of the driver still dropped events unreliably.


The second major revision, gpio-notify, dropped file i/o of events altogether. As we have the ability in our user-space programs to access GPIO pin status directly through the gpio.c and spi.c modules, it was unnecessary overhead for the driver to creating and queue data structures detailing pin status change events, and it was also unnecessary overhead for the user-space program to read these data structures from the device file. Hence, gpio-notify relies instead on the user-space program to determine pin status for itself, and the only role of this version of the driver is to notify the user-space process (though the fasync notification method) that a pin change has occurred.

fasync notification method


The driver will send SIGIO kernel signals to any process which wishes to be informed of pin changes.


To inform the driver that it wishes to receive notification signals, a user-space process should open the /dev/gpio-event device file, set itself as owner of the file, and then set the F_ASYNC flag on the file:


int fd = open(GPIO_DEVICE_FILENAME, O_RDONLY | O_NONBLOCK);

if(fd == -1) {

fprintf(stderr, "Could not open %s\n", GPIO_DEVICE_FILENAME);

exit(1);

}

GPIO_DEVICE_FILENAME, fd);


// set this process as owner of the device file

fcntl(fd, F_SETOWN, getpid());


// enable SIGIO notifications

int oflags = fcntl(fd, F_GETFL);

fcntl(fd, F_SETFL, oflags | FASYNC);


After opening the file, the user-space program must also use an ioctl() to tell the driver about each pin it wishes to monitor:


GPIO_EventMonitor_t monitor;


monitor.gpio = gpio;

monitor.onOff = onOff;

monitor.edgeType = GPIO_EventBothEdges;

monitor.debounceMilliSec = 0;


// enable monitoring on the selected pins

ioctl(fd, GPIO_EVENT_IOCTL_MONITOR_GPIO, &monitor);


At the driver level, gpio-notify uses standard kernel fasync helper calls (documented in LDD3, Chapter 6) to register user-space processes for notification and to send SIGIO signals when a pin’s status changes.


The user-space program can then establish a pthread-safe signal handling loop with sigwait() and, upon receiving SIGIO, notify waiting threads of any pin changes by signaling pthread condition variables with pthread_cond_signal().

BitBake notes


BitBake was configured for Gumstix Basix in gumstix-oe/build/auto.conf by selecting the line MACHINE = "gumstix-custom-basix". Also, to decrease compilation times, the Psyco Python just-in-time compiler was installed on the workstation.


Buildling gpio-notify


The driver is located within the gumstix/gumstix-oe/user.collection directory as a BitBake package called gpio-notify. The OpenEmbedded BitBake build system cross-compiles the driver to run on the Gumstix ARM processor. It first builds the gumstix-kernel-x.xx.xx (Linux kernel) package as a dependency if that has not been built yet.


To build gpio-notify, first clean the work directory with the command


bitbake gpio-notify –c clean


Then compile the package with the command


bitbake gpio-notify –c compile


Using the test program, gpio-notify


The driver module, gpio-notify-drv.ko, should be copied to the Gumstix device with scp and then inserted into the kernel with the command


insmod ./gpio-notify-drv.ko


The user-space test program, gpio-notify, can also be copied to the Gumstix and run after the driver module has been inserted. It will continually count rising pin edges fom the three SPI GPIO pins. Upon receipt of a SIGTERM or SIGINT (Ctrl-C), the program will display counts of pin changes and approximate elapsed time. Sending SIGHUP to gpio-notify will cause the program to reset its start time to the current time and input counts to zero.

Other BitBake packages: gpio-event-fasync, gpio-poll


In addition to gpio-event (included with Gumstix OpenEmbedded) and gpio-notify, there are packages for gpio-event-fasync, the first version of the driver supporting fasync notification, and gpio-poll, a test program for comparison which continuously polls GPIO pin status from user-space with no kernel-level driver code. They may be built using analogous BitBake commands to those given above for gpio-notify.


Evaluation


While running, gpio-notify uses approximately 18% of cpu time on the Gumstix, as measured with top, while gpio-poll uses approximately 97% of cpu time. Despite the much-reduced cpu utilization, gpio-notify collects events as reliably as gpio-poll based on input counts from the three SPI units over approximately 15-second intervals.


root@gumstix-custom-basix:~/gpio-event-fasync$ ./gpio-poll

seconds elapsed: 17.669

input count 0: 18557 (1050.285629/sec)

input count 1: 18554 (1050.115836/sec)

input count 2: 18553 (1050.059238/sec)


root@gumstix-custom-basix:~/gpio-event-fasync$ ./gpio-poll

seconds elapsed: 17.669

input count 0: 18557 (1050.285629/sec)

input count 1: 18554 (1050.115836/sec)

input count 2: 18553 (1050.059238/sec)


More thorough testing of gpio-notify’s reliability is necessary, such as generating a sequence of SPI data on the Gumstix and verifying that the data is read in correct order with no missed events.



Applying GPIO Interrupt to the SPI Communication. 

There is a sample code for merging a gpio interrupt method into the SPI communication in RoverOld.

The procedure is following.

First of all, gpio-kotify-drv.ko generated by gpio-notify project needs to be downloaded to the Gumstix.

Insert the driver is required by

insmod ./gpio-notify-drv.ko

./RoverOld


Č
ċ
ď
Unknown user,
Dec 15, 2008, 10:18 AM
Comments