GPIO

The General-Purpose Input/Output interfaces provides pins that can be configured as either inputs or outputs. Many of the signals available at the phyCORE-Connector can be multiplexed as GPIOs. The phyCORE-AM64x processor supports seven independent GPIO modules. To learn more information about the phyCORE-AM64x GPIO interface, please see section 9.3 in the Hardware Manual.

Requirements

  • M/M Jumper Wire Optional for Advanced Steps

    Note

    The expansion header was designed for 2mm pins. It is acceptable to use 2.54mm jumper pins during the development and verification of interfaces. The only issue arises when you switch back to plugging in a 2mm male header for an expansion board you created.

Using LEDs and Push buttons

This section of the guide will go over the use of the LEDs and Push buttons populated on the phyBOARD-Electra carrier board, see the User Interface section of the schematic for more information.

The GPIOs used here serve a dual purpose; before Linux is fully booted these GPIO signals are sampled at initial power-on and used to configure the behavior of the boot ROM (ie these signals boot strap the AM64x processor). In order to ensure that the push buttons do not interfere with the boot configuration, these signals are enabled via the OR gate (reference designator U79) automatically by the AM64x processor once the initial boot process is over.

These User Interface signals are all assigned to kernel drivers within the arch/arm64/boot/dts/ti/k3-am64xx-phyboard-electra.dtsi.

Toggling the User LED (D30)

The development kit has a user-configurable LED (D30) that is hooked up to the processor’s GPIO0_15.

GPIO0_15 is represented as gpio-438 in software. In the next section “GPIO Signal Naming” you’ll see that these GPIO signals are already allocated to name red:disk. This indicates that a driver has claimed this gpio, and this can be confirmed by checking the linux device tree. The driver is gpio-leds.

phyCORE-AM64x LED 1 Location Close View
  • Let’s take a look at the sysfs interface that the gpio-leds driver are located in.

Target (Linux)
ls /sys/class/leds/
Target (Linux)
root@phyboard-electra-am64xx-2:~# ls /sys/class/leds
blue:user@  green:disk@  green:heartbeat@  green:user@  mmc0::@  mmc1::@  red:disk@  red:user@
  • Let’s first turn ON the LED (it should be OFF by default):

Target (Linux)
echo 1 > /sys/class/leds/red\:disk/brightness

When the gpio-leds driver is attached to a PWM enabled pin, the brightness file will actually control the physical brightness of the pin and allow you to write values from 0 to 255 to do so. In this case, GPIO0_15 is not PWM capable pin and thus 0 corresponds to the LED being OFF and any other value sets the LED to ON.

  • Turn OFF the LED

Target (Linux)
echo 0 > /sys/class/leds/red\:disk/brightness
  • We can also leverage the driver to do more interesting things with the LED. Let’s configure the GPIO as a Linux heartbeat for example:

Target (Linux)
echo "heartbeat" > /sys/class/leds/red\:disk/trigger
  • The heartbeat trigger can be turned OFF like so:

Target (Linux)
echo "none" > /sys/class/leds/red\:disk/trigger

The other LEDs on the development kit, LED2 (green:disk) and RGB (red:user, green:user, blue:user), can be controlled in the same way.

Reading the User Button (S7)

We can see in both the development kit schematic and in /sys/kernel/debug/gpio that GPIO0_17 is connected to the user button S7 and is represented in software as gpio-440 with the name “home”. We can see in the device tree that this GPIO is assigned to the gpio-keys driver.

phyCORE-AM64x S7 & S8 Button
  • We can poll the state of this input GPIO just by reading /sys/kernel/debug/gpio like we already did above:

Target (Linux)
cat /sys/kernel/debug/gpio | grep home
Example Output
root@phyboard-electra-am64xx-2:~# cat /sys/kernel/debug/gpio | grep home
gpio-442 (                    |home                ) in  lo
  • Now try running that command again while holding down the S7 button:

Example Output
root@phyboard-electra-am64xx-2:~# cat /sys/kernel/debug/gpio | grep home
gpio-442 (                    |home                ) in  hi

We can see that the pin goes from “lo” to “hi” when the button is pressed (note that the push button pulls the pin down… BUT the GPIO is configured as a ACTIVE_HIGH within the linux device tree which explains the seemingly reverse behavior).

  • Another option for viewing button presses is to leverage the gpio-keys driver and the input events that it generates:

Target (Linux)
cat /dev/input/event0 | hexdump

With that above command running as an active process, try pushing the User buttons S7 and S8. You should see a large block of hexadecimal data printed to the screen for each button press.

Note

These blocks of data are input_event structures that identify the key code assigned to the GPIO (see the linux device tree), when the button press occurred, and the type of button press event that was generated (long press, single press, button release, etc). See Documentation/input/input.rst within the kernel source for more information.

  • Enter Ctrl + C to end the process and resume control of the console.

GPIO Signal Naming

The GPIO pin numbering of the phyCORE-AM64x schematic is represented differently from the device identifier used by the kernel. Therefore in GPIO hardware signal naming convention looks very different from the software GPIO naming convention. This section will walk through how to calcualte the GPIO signals and shoe how to identify which GPIO signals are in use on the developmeny kit.

Active GPIO Signals

  • See which GPIO signals have been allocated by running the following command.

Target (Linux)
cat /sys/kernel/debug/gpio
Example Output
root@phyboard-electra-am64xx-2:~# cat /sys/kernel/debug/gpio
gpiochip1: GPIOs 337-424, parent: platform/601000.gpio, 601000.gpio:
gpio-355 (                    |PHY reset           ) out lo ACTIVE LOW
gpio-356 (                    |PHY reset           ) out lo ACTIVE LOW
gpio-379 (                    |wp                  ) out lo
gpio-380 (                    |spi1 CS1            ) out lo ACTIVE LOW

gpiochip0: GPIOs 425-511, parent: platform/600000.gpio, 600000.gpio:
gpio-437 (                    |green:heartbeat     ) out lo
gpio-440 (                    |red:disk            ) out lo
gpio-441 (                    |green:disk          ) out lo
gpio-442 (                    |home                ) in  lo
gpio-446 (                    |menu                ) in  lo
gpio-451 (                    |sysfs               ) out lo
gpio-453 (                    |gpio-fan            ) out lo ACTIVE LOW
gpio-457 (                    |standby             ) out lo
gpio-460 (                    |standby             ) out lo
gpio-488 (                    |PHY reset           ) out lo ACTIVE LOW
GPIO and gpiochip

GPIO SOC Modules

GPIO Hardware Signal

Section

gpiochip1

GPIO1

337-424

gpiochip0

GPIO0

425-511

Note

If a gpio instance is listed in that above /sys/kernel/debug/gpio file it means that it is tied to an active kernel driver. If this is the case, you shouldn’t not attempt to control the gpio unless using the appropriate userspace tools, provided by the hardware driver. This guide will outline the control of gpios both tied to a kernel driver and those that are unused, left in reset.

Note gpio-453 will appear when the fan device tree overlay is active. Please see the Fan guide for more information.

Calculating GPIO Signal Names

This section of the guide will walk through how to figure out the hardware signal name and the corresponding SOC GPIO signal name.

Hardware to Software

  • Using the development kit’s carrier board and SOM schematics the hardware GPIO signal GPIO0_15 (LED1) at SOM connector D3 pin.

  • See which GPIO signals have been allocated by running the following command.

Target (Linux)
cat /sys/kernel/debug/gpio
Expected Output
 root@phyboard-electra-am64xx-2:~# cat /sys/kernel/debug/gpio
 gpiochip1: GPIOs 337-424, parent: platform/601000.gpio, 601000.gpio:
 gpio-355 (                    |PHY reset           ) out lo ACTIVE LOW
 gpio-356 (                    |PHY reset           ) out lo ACTIVE LOW
 gpio-379 (                    |wp                  ) out lo
 gpio-380 (                    |spi1 CS1            ) out lo ACTIVE LOW

 gpiochip0: GPIOs 425-511, parent: platform/600000.gpio, 600000.gpio:
 gpio-437 (                    |green:heartbeat     ) out lo
 gpio-440 (                    |red:disk            ) out lo
 gpio-441 (                    |green:disk          ) out lo
 gpio-442 (                    |home                ) in  lo
 gpio-446 (                    |menu                ) in  lo
 gpio-451 (                    |sysfs               ) out lo
 gpio-453 (                    |sysfs               ) in  lo
 gpio-457 (                    |standby             ) out lo
 gpio-460 (                    |standby             ) out lo
 gpio-488 (                    |PHY reset           ) out lo ACTIVE LOW
  • Looking at the section “gpiochip0”, since it translates to GPIO0, you can see the first software GPIO signal is gpio-425 for GPIO0. By adding 425 and the hardware signal(GPIO0_15) together the proper software singal name can be found.

    425+15 = 440

  • Now you know that gpio-440 (software) is GPIO0_15 (hardware).

Software to Hardware

  • In order to figure out which hardware GPIO signals are already allocated simply subtract the software GPIO singal from the GPIO bank starting section.

    • Find the GPIO bank section by running the following command on the development kit.

      Target (Linux)
      cat /sys/kernel/debug/gpio
      
  • The GPIO0 bank correlates gpiochip1 which starts at gpio-425. To find which hardware GPIO signal led1 corresponds to gpio-440, subtract gpio-440 from the start of the GPIO bank (gpio-425).

    440-425 = 15

  • Now you know that gpio-440 (software) is GPIO0_15 (hardware).

Advanced GPIO Control

Export and Control a Input GPIO

Thus far in this guide we have gone over the control of GPIOs assigned to specific gpio-X drivers within the kernel, now let’s look into exporting and controlling unused GPIOs. For this guide we will target GPIO0_18 which is brought out to pin 8 of the X27 expansion connector.

phyCORE-AM64x x27 Expansion Connector
  • First, convert the hardware resource GPIO0_18 into it’s software representation. We should come up with GPIO0_18 = gpio-443 in Linux.

  • Export this GPIO in the kernel:

Target (Linux)
echo 443 > /sys/class/gpio/export

This will create a new sysfs directory /sys/class/gpio/gpio443 (note that this step will not work for GPIOs already reserved by a driver).

  • Let’s navigate into the new directory and take a look around:

Target (Linux)
cd /sys/class/gpio/gpio443
ls
Expected Output
root@phyboard-electra-am64xx-2:gpio443# ls
device@  power/  subsystem@  active_low  direction  edge  uevent  value
  • Similar to the features exposed by the gpio-leds driver outlined above in this guide, exporting GPIOs within sysfs creates a directory full of files that enable us to control the GPIO from userspace. We can check the current configuration of the GPIO interface by reading some of these files:

Target (Linux)
cat direction
cat value
cat active_low
Expected Output
root@phyboard-electra-am64xx-2:gpio443# cat direction
in
root@phyboard-electra-am64xx-2:gpio443# cat value
1
root@phyboard-electra-am64xx-2:gpio443# cat active_low
0

We can see that by default, the GPIO is exported as an active_high input.

  • You could go ahead and short GPIO0_18 (pin 8 of X27) to GND (pin 4 of X27) to simulate a button press and at the same time read the value file to see it go from 1 to 0.

Export and Control a Output GPIO

Let’s take a closer look at this GPIO:

  • In order to fully control GPIOs, we will need to have a understanding of the way the AM64x processor is designed at the silicon level. The AM64x processor has many subsystems within it while having a limited number of processor pads to bring out signals to and enable hardware interfaces on (such as USB, mPCIe, GPIOs, etc). These various hardware subsystems share processor pins and the processor pins have to be configured for the signal you want to access. This is a process called pin multiplexing (or just pin muxing) and is the reason that you won’t ever be able to bring out every feature the AM64x processor has to offer all at the same time (you have to make decisions regarding which interfaces are critical to your application and design and ensure they can all come out, without conflicting).

  • Since we are ultimately trying to control the GPMC0_AD3 processor pad (this is the processor pin that brings out GPIO0_18 in the phyCORE-AM64x development kit schematic) lets look this up in the processor datasheet:

    phyCORE-AM64x Processor Datasheet

    Here we can confirm the processor pin (often referred to as a processor ball, or pad as well) is number U20 (which should agree with the SOM schematic), the pad’s config register’s name is PADCONFIG18, the pad config register address is 0x000F4048, and the mux mode we want for GPIO0_18 is 7.

  • Let’s take a look at the pad config on the development kit:

Target (Linux)
devmem2 0x000F4048
Expected Output
root@phyboard-electra-am64xx-2:gpio443# devmem2 0x000F4048
/dev/mem opened.
Memory mapped at address 0xffffaed22000.
Read at address  0x000F4048 (0xffffaed22048): 0x00254007
The 0x000F4048 memory address contained the data 0x00254007.
  • A handy trick to decode that hexadecimal output is to use your Windows Host Machine’s Calculator App and setting it to Programmer mode.

phyCORE-AM64x GPIO Calculator

We can use the bit toggling keypad to view the individual bits that are set, as well as change them easily.

  • Next, lookup PADCONFIG18 within the AM64x processor Technical Reference Manual (TRM) from Texas Instruments. You should find the following table breaking down what each bit within the pad config register means:

Texas Instrument's AM64x Pad Configuration
  • Looking at the data stored in 0x000F4048 alongside the TRM’s Table 5-77, we can see that the processor pin is in its reset state (or default state) 0x00254007. This can be interpreted as follows:

    • TX (transmit) Driver Disabled

    • RX (receiver) Driver Enabled

    • Internal Pull Down Selected

    • Internal Pull Down Enabled

    • Schmitt Trigger Input Enabled

    • Mux Mode 7

  • We can see that the processor pin by default is sitting in a state that makes it very convenient for us to export the GPIO and use it as an input in Linux.

    In order for us to configure GPIO0_18 as an output, we’ll need to modify the GPIO in the kernel AND modify the processor’s pad config!

  • First, let’s mux the processor pad to function as a output GPIO0_18. We’ll want to set 0x000F4048 to reflect the following to do this (other options such as the internal pull up/down resistors could be optionally enabled depending on your needs):

    • Tx (transmit) Driver Enabled

    • Rx (receiver) Driver Disabled

    • Mux Mode 7: This will correspond to the value 0x00010007.

  • Write the value 0x00010007 to PADCONFIG18:

Target (Linux)
devmem2 0x000F4048 w 0x00010007

Now our pin is properly configured to function as an output (for driving an LED for example).

  • Next, we need to configure the kernel to use this pin as a output:

Target (Linux)
echo out > direction
  • With both the kernel and hardware interface properly configured as an output, we can now successfully drive the pin:

Target (Linux)
echo 1 > value
echo 0 > value