Applications - GPIO Based IRQ

Last modified by Microchip on 2024/06/20 12:43

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.

Back to Top

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.

Expansion features of the ATSAMA5D27-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 pinSchematic NameIRQ NumberPackage Pin
J25 pin 2INT_mBUS183PB0

​For more details on the Package and Pinout of the SAMA5D2, refer to “Table 6-2. Pinouts” in the SAMA5D2 Series Datasheet.

mikroBUS 1

Schematic of mikrobus socket 1 on the ATSAMA5D27-SOM1-EK1

Back to Top

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.

Back to Top

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:

667   pioA_clk: pioA_clk {
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.

​The definitions of IRQ_TYPE are available in the file: buildroot/output/build/linux-linux4sam_6.0/include/dt-bindings/interrupt-controller/irq.h

Line 1504 shows the definition of pioA clock source.

Back to Top

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:

$ make linux-menuconfig

The top-level menu will be displayed:

Linux menuconfig top menu

Device Driver

Select Device Drivers ---->

Linux menuconfig device drivers


Select Pin controllers ---->

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.

Pin controllers > AT91 PIO4 pinctrl driver

Back to Top


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.

Back to Top

Application

The following is a C-Language demonstration program (gpio_irq.c) for demonstrating the GPIO based IRQ in User Space:

To compile:

$ buildroot/output/host/bin/arm-buildroot-linux-uclibcgnueabihf-gcc gpio_irq.c -o irq_test

Be sure to type in the location of the cross-compiler on your host computer.

Source code:

#include <stdio.h>
#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;
}

Back to Top

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.

# chmod +x irq_test
# ./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

Back to Top

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.

Back to Top