Other uses of GPIO pins

Bela provides 16 digital I/O channels, which are sampled synchronously to the audio and can be easily written, read or tri-stated with a precision of ~22microseconds. However, for some uses you may want to access some of the GPIO pins directly from your program, without having them sampled automatically by the Bela real-time core.

Table of contents

  1. Example use cases
  2. Finding an available pin
  3. Accessing a pin

Example use cases

  • accurate, minimally invasive measurements of CPU time for specific blocks of code: simply toggle a pin before and after the section you want to measure and monitor it with an external oscilloscope
  • performing non-time-critical digital I/O (e.g.: reading buttons or driving LEDs) when you need more than the 16 I/Os provided by the Bela core.
  • manually driving the on-board LEDs for BelaMini (requires running with --disable-led).

Finding an available pin

Most pins of the BeagleBone or the PocketBeagle can perform different functions. The one function that is currently enabled depends on the pinmuxer (pin-multiplexer) controller. In order for a pin to work as a GPIO, you will have to make sure that the pinmuxer settings for the corresponding pin are in mode 7 (GPIO). Note that any of the pins normally used by Bela for digital I/O are already correctly configured as GPIO, but you will not be able to use them with the method below while Bela is running with digital enabled. However, you can disable the digital I/O in Bela (this is achieved by unticking the tickbox “Use digital” in the IDE, or equivalently, if you are using the command line, use the -G 0 flag) and safely access those pins for your own use while a Bela program is running (so you can skip the steps below and jump to “Using a GPIO pin” below). Whatever you do, make sure you do not use any of the other pins used by Bela. Here is a list of the pins on the BeagleBone and the pins used by Bela. diagram (P8, P9). And these are for BelaMini.

The procedure to set the pinmuxer is simpler when using config-pin. If you use config-pin, jump to Accessing a pin below. Alternatively, follow the instructions below for setting the pinmuxer, which are more generic. You will need the pinmuxer address (ADDR) and the GPIO number. How to retrieve these varies depending on the board you have:

Bela (BeagleBone)

Here is a list of the pins on the BeagleBone and the pins used by Bela. diagram (P8, P9). Pick a pin that is not in use by Bela and look up the GPIO number in the corresponding column and the pinmuxer address in the ADDR/OFFSET column. The ADDR value starts with 8 or 9 (remove the leading 0x when using this value below).

BelaMini (PocketBeagle)

The PocketBeagle does not have a nice and exhaustive list as the BeagleBone. You will first have to look at the BelaMini pinout and identify an available pin that can work as a GPIO. Once you identify your desired pin, search for the pin name(e.g.: P1.31) in this (hard to parse) page. From the column containing the pin name, look for the value of the “Control register” and “Mux mode 7” lines. We will call the “Control register” value “ADDR” from now on. The “Mux mode 7” line should look something like gpio x.yy. To find out the GPIO number(in order to access it with your code), you will need to get the value of the expression x * 32 + yy. For instance, P1.31 has ADDR = 9A0 and the Mux mode 7 value is gpio 3.18, therefore the gpio number is 3 * 32 + 18, that is 114 (this should match the number in the BelaMini pinout).

Pinmuxer setting

Once you have the ADDR value you can check what is the current pinmuxer setting for that pin (e.g.: for P9_11 on the BeagleBone, it is 0x870) and then running on the board:

grep 870 $PINS

this will return a line like the following

pin 28 (44e10870.0) 00000027 pinctrl-single

which denotes that the pin is in mode 27, which corresponds to GPIO, receiver enabled, pulldown (see notes at the bottom of the pin diagram files above), so you are good to go. If the pin is not set as a GPIO (and it is not used by Bela), then you can set it to GPIO by loading an appropriate device tree overlay. Again, you can use the config-pin utility, which makes everything easier.

Accessing a pin

From the command line

The Linux driver makes the GPIO chip available at /sys/class/gpio/. Here you can use commands such as:

echo $GPIO_NUMBER > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio$GPIO_NUMBER/direction
echo 1 > /sys/class/gpio/gpio$GPIO_NUMBER/value

There are plenty of tutorials available online for using the sysfs interface.

From C++

For proper, safe (and slow!!), access through the kernel you can use the kernel drivers sysfs interface, using the functions declared in https://github.com/BelaPlatform/Bela/blob/master/include/GPIOcontrol.h and implemented in https://github.com/BelaPlatform/Bela/blob/master/core/GPIOcontrol.cpp. You may want to use these in case yo have multiple processes accessing the same GPIO pins.

For accurate, fast, real-time safe access, you will instead want to use the methods of the Gpio class. Just #include Gpio.h and go for it. This class uses memory-mapped Gpios for real-time performance, without going through the Linux kernel. For en examples of its use, check out Digital/synchronous-gpio.