Applications - GPIO Based IRQ
Introduction
This topic shows how the General Purpose Input/Output (GPIO) Interrupt Request (IRQ) functionality of the SAMA5D2 Series Arm® Cortex®-A5 Microprocessor Unit (MPU) is enabled in the Linux® kernel and how to access the GPIO IRQ in User Space.
The GPIO IRQ functionality has been introduced into the Linux kernel and can be accessed via the standard kernel API request_irq().
Since the IRQ of SAMA5D2 is also shared by the Peripheral Input/Output (PIO) controller, every GPIO pin can be used as an external interrupt. In this kind of application, the GPIO pins can be configured to be monitored. When there is an input change on a specific GPIO pin, the IRQ interrupt will be asserted by the PIO controller.
The GPIO-based IRQ uses a lower IRQ handle level than external IRQs, so the response time is slower. However, the GPIO-based IRQ may be good enough in most cases for your application. This topic shows you how to request and handle a GPIO IRQ in User Space via the /dev/gpiochip0 device node.
Prerequisites
This application is developed for the ATSAMA5D27-SOM1-EK1 development platform:
This application is developed using the Buildroot build system.
Hardware
For this application, you will be controlling the GPIO IRQ pin of the mikroBUS™ 1 expansion socket of the ATSAMA5D27-SOM1-EK1. The accompanying figure shows the expansion capability of the SOM1-EK1.
mikroBUS
You will monitor and control the INT_mBUS1 pin on the mikroBUS 1 connector. It is connected to the ATSAMA5D27-SOM1 pin PB0 which is assigned the IRQ number 83. The IRQ number was assigned by the software when registering the interrupt. We’ll show you how it was done below.
mikroBUS 1 pin | Schematic Name | IRQ Number | Package Pin |
---|---|---|---|
J25 pin 2 | INT_mBUS1 | 83 | PB0 |
mikroBUS 1
Buildroot Configuration
Objective: Using Buildroot, build a bootable image and FLASH onto an SD Memory Card for the ATSAMA5D27-SOM1-EK1 development board.
Follow the steps for building the image in the topic Create Project with Default Configuration. In the topic, you will use the default configuration file: atmel_sama5d27_som1_ek_mmc_dev_defconfig.
Device Tree
Objective: Observe how the GPIO IRQ functionality was configured in the device tree. No changes are required.
Once Buildroot has completed its build, the IRQ definitions for the ATSAMA5D27-SOM1-EK1 were configured by a Device Tree. The Device Tree Source (DTS) include files (*.dtsi and *.dts) are located in the Buildroot output directory: /output/build/linux-linux4sam_6.0/arch/arm/boot/dts/.
Examine the sama5d2.dtsi file and observe the GPIO IRQ functionality assignments:
668 #clock-cells = <0>;
669 reg = <18>;
670 atmel,clk-output-range = <0 83000000>;
671 };
.
.
1493 pioA: pinctrl@fc038000 {
1494 compatible = "atmel,sama5d2-pinctrl";
1495 reg = <0xfc038000 0x600>;
1496 interrupts = <18 IRQ_TYPE_LEVEL_HIGH 7>,
1497 <68 IRQ_TYPE_LEVEL_HIGH 7>,
1498 <69 IRQ_TYPE_LEVEL_HIGH 7>,
1499 <70 IRQ_TYPE_LEVEL_HIGH 7>;
1500 interrupt-controller;
1501 #interrupt-cells = <2>;
1502 gpio-controller;
1503 #gpio-cells = <2>;
1504 clocks = <&pioA_clk>;
1505 };
Line 669 shows the PID of pioA is 18. This definition of the offset will be used to enable the pioA clock in the PMC.
Line 670 shows the pioA input clock, the maximum frequency is 83 MHz.
Line 1494 specifies which driver will be used for the pioA device.
Line 1495 shows the pioA address is 0xfc038000, size is 0x600.
Lines 1496 to 1499 show that there are 128 GPIO pins divided into four banks, each GPIO bank has its own IRQ line.
Line 1497 shows each GPIO bank has its own IRQ line.
Line 1504 shows the definition of pioA clock source.
Kernel
Objective: Observe how GPIO IRQ functionality was configured in the Linux kernel. No changes are required.
The GPIO IRQ functionality is made available in User Space by the GPIO chip driver. Thus, you can develop IRQ functionality applications in User Space.
From the buildroot directory, run the Linux kernel menuconfig:
The top-level menu will be displayed:
Device Driver
Select Device Drivers ---->
Observe that -*- AT91 PIO4 pinctrl driver is selected.
With this setting, pinctrl and gpio drivers will be built into the kernel. Then, you can access the GPIO driver via the device node in rootfs: /dev/gpiochip0.
Rootfs
User Space:
As discussed in the Device Tree section above, the GPIO IRQ functionality is registered as gpiochip0. Enabling the kernel feature (default) you can access GPIO driver via /dev/gpiochip0 device node.
Application
The following is a C-Language demonstration program (gpio_irq.c) for demonstrating the GPIO based IRQ in User Space:
To compile:
Source code:
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <string.h>
#include <linux/gpio.h>
#include <sys/ioctl.h>
#define DEV_GPIO "/dev/gpiochip0"
#define POLL_TIMEOUT -1 /* No timeout */
int main(int argc, char *argv[])
{
int fd, fd_in;
int ret;
int flags;
struct gpioevent_request req;
struct gpioevent_data evdata;
struct pollfd fdset;
/* open gpio */
fd = open(DEV_GPIO, O_RDWR);
if (fd < 0) {
printf("ERROR: open %s ret=%d\n", DEV_GPIO, fd);
return -1;
}
/* Request gpio_pb0 interrupt */
// 128 gpio in gpiochip0
// 0 ~ 31 PA0 -> PA31
// 32 ~ 63 PB0 -> PB31
// 33 ~ 95 PC0 -> PC31
// 96 ~ 127 PD0 -> PD31
req.lineoffset = 32;
req.handleflags = GPIOHANDLE_REQUEST_INPUT;
req.eventflags = GPIOEVENT_REQUEST_BOTH_EDGES;
strncpy(req.consumer_label, "gpio_irq", sizeof(req.consumer_label) - 1);
/* requrest line event handle */
ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &req);
if (ret) {
printf("ERROR: ioctl get line event ret=%d\n", ret);
return -1;
}
/* set event fd nonbloack read */
fd_in = req.fd;
flags = fcntl(fd_in, F_GETFL);
flags |= O_NONBLOCK;
ret = fcntl(fd_in, F_SETFL, flags);
if (ret) {
printf("ERROR: fcntl set nonblock read\n");
}
for (;;) {
fdset.fd = fd_in;
fdset.events = POLLIN;
fdset.revents = 0;
/* poll gpio line event */
ret = poll(&fdset, 1, POLL_TIMEOUT);
if (ret <= 0)
continue;
if (fdset.revents & POLLIN) {
printf("irq received.\n");
/* read event data */
ret = read(fd_in, &evdata, sizeof(evdata));
if (ret == sizeof(evdata))
printf("id: %d, timestamp: %lld\n", evdata.id, evdata.timestamp);
}
}
/* close gpio */
close(fd);
return 0;
}
Hands On
Copy the irq_test program to the target and execute.
Trigger the INT_mBUS1 pin with a falling edge or rising edge signal.
# ./irq_test
irq received.
id: 2, timestamp: 1326702743513717054
irq received.
id: 1, timestamp: 1326702744536525542
irq received.
id: 2, timestamp: 1326702745118564762
irq received.
id: 1, timestamp: 1326702745694055688
Summary
In this topic, you used Buildroot to build an image with GPIO IRQ functionality for the ATSAMA5D2 Series MPU. You accessed the GPIO IRQ via User Space by the /dev/gpiochip0 device node. You also accessed the GPIO IRQ driver using a C-Language program. You walked through the device tree and kernel to observe how the embedded Linux system configures the source code for building.