Repository navigation
GPIO Interrupt
We can get information from a GPIO in two main ways: actively polling the pin for updated data or waiting for the pin to trigger an interrupt. The latter is often the better alternative, allowing the code not to be actively waiting all the time.
In this example, we have a button with a pull-down resistor connected on pin P9_27 (GPIO_115) and an LED on pin P9_23 (GPIO_49).
We get the 5V for the button from SYS_5V on pin P9_7.
This time, we won't need a character device, hence the base module is the Hello World example.
We need a couple of new includes,
#include <linux/gpio.h>
#include <linux/interrupt.h>to define the GPIO pins,
#define GPIO_BUTTON 115
#define GPIO_LED 49and to create a global variable to hold the interrupt number.
unsigned int irq_number;The initialisation of the module is vastly similar to the GPIO module, minus the character device creation. The main steps are as follow:
- Request the GPIO using
gpio_request(unsigned gpio, const char *label) - Set the GPIO direction as an output (
gpio_direction_output(unsigned gpio, int value)) or input (gpio_direction_input(unsigned gpio)) - Export the GPIO using
gpio_export(unsigned gpio, bool direction_may_change)
Don't forget to manage the possible failures for all these calls.
We can improve the behaviour of the button by setting a software debounce using gpio_set_debounce(unsigned gpio, unsigned debounce);, where debounce is a time in milli-seconds during which edge changes will be ignored after the first triggering, effectively ignoring bounces (but also ignoring anything else happening on the pin).
First, we need to tell the kernel that we want to map the GPIO to an interrupt. It will answer back with a unique interrupt number.
irq_number = gpio_to_irq(GPIO_BUTTON);Next we have to register that interrupt number with a function callback that will be executed when the interrupt is triggered. The function return 0 upon success.
request_irq(irq_number, (irq_handler_t) gpio_irq_handler, IRQF_TRIGGER_RISING, "custom_gpio_irq", NULL);-
irqis our interrupt number given bygpio_to_irq() -
handleris a function pointer to our callback -
flagsare defined in<linux/interrupt.h>. For example, if we want the interrupt to trigger on a rising edge, we would set this field toIRQF_TRIGGER_RISING. -
nameis a custom name for our interrupt registration. -
devis used for debug purposes, we can set it toNULL.
The interrupt handler given as a pointer in request_irq() needs to be defined.
Its signature is as follows:
static irq_handler_t gpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);Upon success, it returns (irq_handler_t) IRQ_HANDLED;
As an exercise, write a couple of lines that reverse the LED status (on to off or off to on).
When removing the module from the kernel, we have to free the IRQ and GPIOS.
free_irq(irq_number, NULL);
gpio_unexport(GPIO_LED);
gpio_unexport(GPIO_BUTTON);
gpio_free(GPIO_LED);
gpio_free(GPIO_BUTTON);If everything went well, we should see the interrupt in a couple of places.
debian@beaglebone:~/LKM/GPIO_irq$ cat /proc/interrupts
[...]
70: 0 481ae000.gpio 19 Edge custom_gpio_irq
[...]where custom_gpio_irq is the name field given to request_irq().
Also, we can check the two GPIOs we set, as well as the fact that there is an IRQ link to the button pin.
debian@beaglebone:~/LKM/GPIO_irq$ cat /sys/kernel/debug/gpio
[...]
gpio-49 (GPMC_A1 |P9_23 ) out lo
[...]
gpio-115 (MCASP0_FSR |P9_27 ) in lo IRQ
[...]Now, every time you press the button, the LED should turn on or off.
A full code example is available in the repository.
- Implement a timer to control how long the LED will stay on after the button press.
- Wire up a second button to a GPIO. Press the first button in a known pattern (e.g. Morse code), then press the second button once. Upon pressing the second button, the LED should reproduce the same pattern as you input on the first button.
- linux/gpio.h on kernel 4.19.94
- linux/interrupt.h on kernel 4.19.94
- [Let's code a Linux Driver - 11: Using GPIO Interrupts in a Linux Kernel Module](Let's code a Linux Driver - 11: Using GPIO Interrupts in a Linux Kernel Module)
- Writing a Linux Kernel Module — Part 3: Buttons and LEDs
→ Stuck ? Check the troubleshooting page.
→ More resources.
→ Suggest updates and new topics by submitting an issue.