BeagleBone Green GPIO

This post details how to control the BeagleBone Green (BBG) via GPIO.

1. GPIO

Since Linux v4.8, the standard way of using Linux GPIO has been via libgpiod. Prior to the introduction of libgpiod, the sysfs interface was used, but sysfs is depreciated and was removed from the mainline Linux kernel in 2020. The best source of information on libgpiod comes with the library and the (libgpiod manual).

The library comes with a number of command line tools to manipulate GPIOs:

  • 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.

Examples:

    # Read the value of a single GPIO line.
    $ gpioget gpiochip1 23
    0

    # Read two values at the same time. Set the active state of the lines
    # to low.
    $ gpioget --active-low gpiochip1 23 24
    1 1

    # Set values of two lines, then daemonize and wait for a signal (SIGINT or
    # SIGTERM) before releasing them.
    $ gpioset --mode=signal --background gpiochip1 23=1 24=0

    # Set the value of a single line, then exit immediately. This is useful
    # for floating pins.
    $ gpioset gpiochip1 23=1

    # Find a GPIO line by name.
    $ gpiofind "USR-LED-2" gpiochip1 23

    # Toggle a GPIO by name, then wait for the user to press ENTER.
    $ gpioset --mode=wait `gpiofind "USR-LED-2"`=1

    # Wait for three rising edge events on a single GPIO line, then exit.
    $ gpiomon --num-events=3 --rising-edge gpiochip2 3
    event:  RISING EDGE offset: 3 timestamp: [    1151.814356387]
    event:  RISING EDGE offset: 3 timestamp: [    1151.815449803]
    event:  RISING EDGE offset: 3 timestamp: [    1152.091556803]

    # Wait for a single falling edge event. Specify a custom output format.
    $ gpiomon --format="%e %o %s %n" --falling-edge gpiochip1 4 0 4 1156 615459801

    # Pause execution until a single event of any type occurs. Don't print
    # anything. Find the line by name.
    $ gpiomon --num-events=1 --silent `gpiofind "USR-IN"`

    # Monitor multiple lines, exit after the first event.
    $ gpiomon --silent --num-events=1 gpiochip0 2 3 5

To use it on the BBG, one must first download the library and include files.

sudo apt update
sudo apt install libgpiod-dev

You can check everything is working by detecting the GPIO chips and printing their labels and state.

debian@beaglebone:~$ gpiodetect
gpiochip0 [gpio] (32 lines)
gpiochip1 [gpio] (32 lines)
gpiochip2 [gpio] (32 lines)
gpiochip3 [gpio] (32 lines)
debian@beaglebone:~$ gpioinfo
gpiochip0 - 32 lines:
	line   0:  "MDIO_DATA"       unused   input  active-high 
	line   1:   "MDIO_CLK"       unused   input  active-high 
...

Now turn on the D5 LED for 10 seconds using

debian@beaglebone:~$ gpioset -m time -s 10 gpiochip1 24=1

and turn it off for 10 seconds

debian@beaglebone:~$ gpioset -m time -s 10 gpiochip1 24=0

Note that after gpioset exits, the data of the output is undefined.

2. Setting pinmux values via the Device Tree

The pins of the BBG P9 header have different operations depending on the pinmum mode chosen. Looking at the P9 header, Mode 7 connects the GPIO line to the pin of the AM335X chip. To do so, we need to specify this configuration via the Linux Device Tree (DT). How the DT works will be covered as a later topic, but this (admittedly complicated) configuration below will set

First make the following dts file:

$ cat PHWL-GPIO.dts 
/*  
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Purpose License Version 2 as
* published by the Free Software Foundation
*
* Original from: github.com/jadonk/validation-scripts/blob/master/test-capemgr/ 
*
* Modified by Derek Molloy for the example on www.derekmolloy.ie
* that maps GPIO pins for the example
*
* Modified by Philip Leong for SSD exercise
*
*/

/dts-v1/;
/plugin/;

/{
       compatible = "ti,beaglebone", "ti,beaglebone-black";
       part-number = "PHWL-GPIO";
       version = "00A0";

       fragment@0 {
             target = <&am33xx_pinmux>;
            
             __overlay__ {
                  pinctrl_test: PHWL_GPIO_Pins {
			pinctrl-single,pins = <

				0x150 0x07  /* P9_22 60 OUTPUT MODE7 - The LED Output */
				0x154 0x07  /* P9_21 60 OUTPUT MODE7 - The LED Output */
				0x178 0x07  /* P9_20 60 OUTPUT MODE7 - The LED Output */
				0x17c 0x07  /* P9_19 60 OUTPUT MODE7 - The LED Output */
				0x158 0x07  /* P9_18 60 OUTPUT MODE7 - The LED Output */
				0x15c 0x07  /* P9_17 60 OUTPUT MODE7 - The LED Output */
				0x074 0x07  /* P9_13 60 OUTPUT MODE7 - The LED Output */
                       
                               /* OUTPUT  GPIO(mode7) 0x07 pulldown, 0x17 pullup
, 0x?f no pullup/down */
			       /* INPUT   GPIO(mode7) 0x27 pulldown, 0x37 pullup
, 0x?f no pullup/down */

			>;
		  };
             };
       };

       fragment@1 {
		target = <&ocp>;
		__overlay__ {
			test_helper: helper {
				compatible = "bone-pinmux-helper";
				pinctrl-names = "default";
				pinctrl-0 = <&pinctrl_test>;
				status = "okay";
			};
		};
	};
};
$ sudo cp PHWL-GPIO-00A0.dtbo /lib/firmware/

to build

$ dtc -O dtb -o PHWL-GPIO-00A0.dtbo -b 0 -@ PHWL-GPIO.dts

Modify /boot/uEnv.txt to be:

$ cat /boot/uEnv.txt 
#Docs: http://elinux.org/Beagleboard:U-boot_partitioning_layout_2.0

uname_r=4.14.108-ti-r131
#uuid=
#dtb=
cmdline=coherent_pool=1M net.ifnames=0 rng_core.default_quality=100 quiet
enable_uboot_overlays=1
uboot_overlay_addr0=/lib/firmware/PHWL-GPIO-00A0.dtbo

#In the event of edid real failures, uncomment this next line:
#cmdline=coherent_pool=1M net.ifnames=0 rng_core.default_quality=100 quiet video=HDMI-A-1:1024x768@60e

##enable x15: eMMC Flasher:
##make sure, these tools are installed: dosfstools rsync
#cmdline=init=/opt/scripts/tools/eMMC/init-eMMC-flasher-v3-no-eeprom.sh

reboot (shutdown -r now) and the modes should have changed to 007

$ grep 007 /sys/kernel/debug/pinctrl/44e10800.pinmux/pins
pin 21 (PIN21) 44e10854 00000007 pinctrl-single 
pin 23 (PIN23) 44e1085c 00000007 pinctrl-single 
pin 29 (PIN29) 44e10874 00000007 pinctrl-single 
pin 84 (PIN84) 44e10950 00000007 pinctrl-single 
pin 85 (PIN85) 44e10954 00000007 pinctrl-single 
pin 86 (PIN86) 44e10958 00000007 pinctrl-single 
pin 87 (PIN87) 44e1095c 00000007 pinctrl-single 
pin 94 (PIN94) 44e10978 00000007 pinctrl-single 
pin 95 (PIN95) 44e1097c 00000007 pinctrl-single 

3. Laboratory Experiment

Part 1 - S2 Button Input (40%)

Download, compile and execute the blink program which flashes the D5 LED as follows

phwl@PHWL-MBP ~ % ssh debian@beaglebone.local
Debian GNU/Linux 10

BeagleBoard.org Debian Buster IoT TIDL Image 2020-04-06

Support: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian

default username:password is [debian:temppwd]

debian@beaglebone.local password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Feb 22 08:49:57 2021 from fe80::8b4:5a85:cfb2:5eb%eth0

debian@beaglebone:~$ git clone https://github.com/phwl/elec3607-labquestions
Cloning into 'elec3607-labquestions'...
remote: Enumerating objects: 22, done.
remote: Counting objects: 100% (22/22), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 22 (delta 5), reused 17 (delta 3), pack-reused 0
Unpacking objects: 100% (22/22), done.
debian@beaglebone:~$ cd elec3607-labquestions/labs/lab1-gpio/
debian@beaglebone:~/elec3607-labquestions/labs/lab1-gpio$ gcc -o blink blink.c -lgpiod
debian@beaglebone:~/elec3607-labquestions/labs/lab1-gpio$ ./blink

Here is a listing of blink.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
 * **    blink.c -    blink with 1s delay 
 * */

#include <stdio.h>
#include <unistd.h>
#include <gpiod.h>

#define GPIOCHIP        1
#define GPIOLINE        24

int 
main(int argc, char *argv[])
{
        struct gpiod_chip *output_chip;
        struct gpiod_line *output_line;
        int line_value;

        /* open chip and get line */
        output_chip = gpiod_chip_open_by_number(GPIOCHIP);
        output_line = gpiod_chip_get_line(output_chip, GPIOLINE);

        /* config as output and set a description */
        gpiod_line_request_output(output_line, "blink", GPIOD_LINE_ACTIVE_STATE_HIGH);

        for (;;)
        {
                line_value = !line_value;
                gpiod_line_set_value(output_line, line_value);
                sleep(1);
        }

        return 0;
}

Referring to the libgpiod manual, we obtain a descriptor for the chip specified by GPIOCHIP in line 20. Using that descriptor we obtain one for the line in line 21. In line 24, we configure the pin as an output, and give it the name “blink” (this is called a consumer in libgpiod). Line 28 toggles line_value between a true and false value, which is written to the line in line 29. We then sleep for 1 second before returning to the top of the infinite loop. You can press control-C to exit the program.

Modify the program so that, in addition to blinking the LED, it will print the status of the S2 button once a second as below.

debian@beaglebone:~$ ./blink 
S2=1
...
S2=0

Part 2 - Seven Segment Display (60%)

The data sheet for a seven segment display (SSD) is available here.

  • Each segment should be driven by a BBG output which supports 6mA drive. Select 6 such pins on the P8 connector that meet this requirement.
  • Calculate the resistor value so that the current to drive the LED (voltage is 3.3V-Vf where Vf=the diode forward voltage drop) doesn’t exceed 4mA.
  • Connect up the SSD to the BBG via a breadboard.
  • Program the SSD so the value changes in value 0 to 9 every second then goes back to 0. When S2 is pressed it should count backwards.