Applications - Pin Control and GPIO

Introduction

Writing to General Purpose Input/Output (GPIO) is useful to control external circuits such as Light Emitting Diodes (LEDs) or relays. You can also read GPIO pins to sense button presses and contact switches. You can control single or multiple GPIO pins depending on the circuit(s) you are controlling.

In this topic, using Buildroot, you will

  • Build a bootable image to include GPIO Devices library (libgpiod) in the Linux® kernel that will provide a straightforward Application Programming Interface (API) to control GPIO.
  • Observe how the device tree and kernel are configured and controls GPIO pins.
  • Write a C Language application and use shell commands to read and write to GPIO pins of a SAMA5D2 Series ARM® Cortex®-A5 Microprocessor Unit (MPU).

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 a single GPIO pin of the mikroBUS 1 expansion socket of the ATSAMA5D27-SOM1-EK1. The figure below shows the expansion capability of the SOM1-EK1.

ATSAMA5D27_SOM1_EK1_expansion_01.png

You will control pin PB2 from the ATSAMA5D27 SOM1 which connects to J24 pin 2 of the mikroBUS 1 connector (labeled RST_mBUS1 on the schematic).

mikrobus1_R1.png

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

There is one change to the _defconfig you will need to make in order to compile in the libgpiod (Library GPIO Device) code.

1

Select Target packages —->

2

Select Libraries —->

3

Select Hardware handling —->

4

Select [*] libgpiod

Observe a new submenu appears below [*] libgpiod

5

Select [*] install tools

6

Return to the top menu, save changes, and exit.

7

Build the image by typing the command:

$ make


Device Tree

Objective: Observe how the peripheral I/O pins were configured as GPIO in the device tree. No changes are required.

Once Buildroot has completed its build, the pin assignments for the ATSAMA5D27-SOM1-EK1 were configured by a device tree. The device tree source include (*.dtsi) file is located in the Buildroot output directory: /output/build/linux-linux4sam_6.0/arch/arm/boot/dts/sama5d2.dtsi

Examine the sama5d2.dtsi file and observe the Parallel Input/Output (PIO) assignments:

667        pioA_clk: pioA_clk {
668            #clock-cells = <0>;
669            reg = <18>;
670            atmel,clk-output-range = <0 83000000>;
671        };

Line 669 sets the Peripheral Identification (PID) of pioA to 18. This will be used to enable the pioA peripheral clock in the Power Management Controller (PMC).

Line 670 sets the pioA input clock to a maximum frequency of 83 MHz.

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 1494 specifies which driver will be used for the pioA device.

Line 1495 sets the pioA base address to 0xfc038000 and size 0x600

Line 1496-1499 sets each PIO bank (there are four total) with its own interrupt line. The file output/build/linux-linux4sam_6.0/include/dt-bindings/interrupt-controller/irq.h provides the definitions of TRQ_TYPE.

Line 1504 provides the definition for the pioA clock source.


Kernel

Objective: Observe how the peripheral I/O pins were configured as GPIO in the Linux kernel. No changes are required.

1

From the buildroot directory, run the Linux kernel menuconfig:

$ make linux-menuconfig

The top-level menu will be displayed:

Linux-menuconfig_top.png

Device Driver:

2

Select Device Drivers —->

Linux-menuconfig_device-drivers.png

Pin Controllers:

3

Next, select Pin controllers —->

Linux-menuconfig_pin-controllers.png

Observe that AT91 pinctrl driver and AT91 PIO4 pinctrl driver are selected as shown by the “-*-“. The drivers are accessed from the root filesystem in the device directory: /dev/gpiochip0

GPIO Support:

4

Type ESC-ESC to go back to the Device Driver menu page.

5

Select GPIO Support —->

Linux-menuconfig_gpio-support.png

6

Observe that the pseudo filesystem sysfs for GPIO from is selected.

The GPIO driver can be accessed from the root filesystem in the system directory: /sys/class/gpio/


Application Programming in C Language

Objective: Explain how GPIO can be accessed using a C Language program.

The GPIO drivers can be accessed by input/output control calls to ioctl(). The following C program will generate a 100 Hz square-wave on GPIO PB2 (J24 pin 2 of the mikroBUS 1).

1

Copy and paste the below C program using your favorite editor.

Name the file gpio.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/gpio.h>
#include <sys/ioctl.h>

#define DEV_GPIO  "/dev/gpiochip0"

int main(int argc, char *argv[])
{
    int fd;
    int ret;

    struct gpiochip_info cinfo;
    struct gpioline_info linfo;
    struct gpiohandle_request req;
    struct gpiohandle_data data;

    /* open gpio */
    fd = open(DEV_GPIO, 0);
    if (fd < 0) {
        printf("ERROR: open %s ret=%d\n", DEV_GPIO, fd);
        return -1;
    }

    /* get gpio chip info */
    ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
    if (ret < 0) {
        printf("ERROR get chip info ret=%d\n", ret);
        return -1;
    }
    printf("GPIO chip: %s, \"%s\", %u GPIO lines\n",
            cinfo.name, cinfo.label, cinfo.lines);
    ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo);
    if (ret < 0) {
        printf("ERROR get line info ret=%d\n", ret);
        return -1;
    }
    printf("line %2d: %s\n", linfo.line_offset,
                    linfo.name);

    /* set gpio_pb2 output */
    // 128 gpio in gpiochip0
    // 0  ~ 31    PA0 -> PA31
    // 32 ~ 63  PB0 -> PB31
    // 33 ~ 95  PC0 -> PC31
    // 96 ~ 127 PD0 -> PD31
    req.lineoffsets[0] = 34;
    req.lines = 1;
    req.flags = GPIOHANDLE_REQUEST_OUTPUT;
    strcpy(req.consumer_label, "RST_mBUS1");
    int lhfd = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
    if (lhfd < 0) {
        printf("ERROR get line handle lhdf=%d\n", lhfd);
        return -1;
    }
    data.values[0] = 1;
    ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
    if (ret < 0) {
        printf("ERROR set line value ret=%d\n", ret);
        return -1;
    }

    while (1) {
        // set gpio_pb2 low
        data.values[0] = 0;
        ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
        usleep(5*1000);

        // set gpio_pb2 high
        data.values[0] = 1;
        ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
                usleep(5*1000);
    }

    /* close gpio */
    close(fd);

    return 0;
}

2

To compile the program, type the command:

Call the gcc compiler that is installed on your machine.

$ /buildroot/output/host/bin/arm-buildroot-linux-gnueabihf-gcc gpio.c -o gpio_test

3

Make gpio_test executable:

$ sudo chmod +x gpio_test

4

Run gpio_test:

$ ./gpio_test

A 100 Hz square wave will output from GPIO PB2 (J24 pin 2 of the mikroBUS 1).


libgpiod – C library and tools

Objective: Explain how to interact with GPIO from the Shell using the libgpiod library and tools,

libgpiod (GPIO device library) is a C library and tools for interacting with the Linux GPIO character device. This library encapsulates the ioctl() calls and data structures using a straightforward API. For more information see: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about/

Prerequisite: Using Buildroot, select and build an image with the libgpiod library. See Buildroot Configuration section above.

APIs of libgpiod:

libgpiod provides a simple API to access the GPIO driver. When Buildroot completes its build, the C header file for these APIs are located at: /output/build/libgpiod-0.3.2/include/gpiod.h

The libgpiod tools are located in the following folder. These provide demonstration source code that shows you how to work with the libgpiod API.

From the buildroot directory:

$ cd output/build/libgpiod-0.3.2/src/tools/
$ ls *.c
gpiodetect.c  gpiofind.c  gpioget.c  gpioinfo.c  gpiomon.c  gpioset.c  tools-common.c

Tools of libgpiod:

There are some simple tools provided by libgpiod for accessing GPIO driver from the Shell.

In the past, GPIO was accessed by the Shell from the sysfs interface. As of Linux version 4.8, this use has been deprecated. The libgpiod was created a better way to access the GPIO driver.

There are six commands in libgpiod tools:

  • gpiodetect: list all gpiochips present on the system, their names, labels, and number of GPIO lines
  • gpioinfo: list all lines of specified gpiochips, their names, consumers, direction, active state, and additional flags
  • gpioget: read values of specified GPIO lines
  • gpioset: set values of specified GPIO lines, potentially keep the lines exported and wait until timeout, user input or signal
  • gpiofind: find the gpiochip name and line offset given the line name
  • gpiomon: wait for events on GPIO lines, specify which events to watch, how many events to process before exiting or if the events should be reported to the console

Using libgpiod tools on ATSAMA5D27-SOM1-EK1:

Detect GPIO on the target processor:

# gpiodetect
gpiochip0 [fc038000.pinctrl] (128 lines)

Print all lines information:

# gpioinfo 
gpiochip0 - 128 lines:
        line   0:        "PA0"       unused   input  active-high 
        line   1:        "PA1"       unused   input  active-high 
        line   2:        "PA2"       unused   input  active-high 
        line   3:        "PA3"       unused   input  active-high 
        line   4:        "PA4"       unused   input  active-high 
        line   5:        "PA5"       unused   input  active-high 
        line   6:        "PA6"       unused   input  active-high 
        line   7:        "PA7"       unused   input  active-high 
        line   8:        "PA8"       unused   input  active-high 
        line   9:        "PA9"       unused   input  active-high
[...]

Find the GPIO chip name and offset of GPIO PB2

# gpiofind PB2
gpiochip0 34

Set PB2 output high:

# gpioset gpiochip0 34=1

Set PB2 output low:

# gpioset gpiochip0 34=0

Toggle PB2 high for 1 second:

# gpioset —mode=time —sec=1 gpiochip0 34=0

Monitor PB2 pin status:

# gpiomon gpiochip0 34
event: FALLING EDGE offset: 34 timestamp: [1325983345.255958082]
event: RISING EDGE offset: 34 timestamp: [1325983345.256686960]
event: FALLING EDGE offset: 34 timestamp: [1325983348.205010375]
event: RISING EDGE offset: 34 timestamp: [1325983348.577229302]
event: FALLING EDGE offset: 34 timestamp: [1325983348.657488131]
event: RISING EDGE offset: 34 timestamp: [1325983348.695700717]
event: FALLING EDGE offset: 34 timestamp: [1325983348.830615058]
event: RISING EDGE offset: 34 timestamp: [1325983349.395371156]
event: FALLING EDGE offset: 34 timestamp: [1325983349.938427156]
event: RISING EDGE offset: 34 timestamp: [1325983349.938456229]

Summary

In this topic you used Buildroot to build an image with the libgpiod library and tools. You also wrote an application in C language and interacted via the Shell to read and write to GPIO pins of a SAMA5D2 Series ARM Cortex-A5 MPU. You walked through the device tree and kernel to observe how the embedded Linux system configures and controls GPIO pins.

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.