GPIO
Pat Beirne edited this page 1 year ago

2. GPIO

The currently shipping u-boot+kernel boots up with the microcontroller (RDA8810) in a strange state, with some GPIO pins set to operate in special-function mode, and some set into GPIO mode, and the mix doesn't seem to match the intended functions described in the i96 spec.

This table describes the state of the 40 pin bus. Column 'mode' is the mode setting of the pin after boot; some of these agree with the i96 spec, some do not. The '(rda)' column is the pin name according to the RDA data sheet. The 'kernel' column is the GPIO numbering system used by the Linux kernel. And the 'verified' column indicates that I verified(measured) the function of the pin in gpio mode. The 'alt' column indicates the special function available on this pin, using the Linux naming scheme.

If there are 'special function' groups that you don't need for your project, you may use these pins as GPIO pins. For example, if you're not using sound on the PCM group, you can recover pins 15, 17, 19 & 21 for use as general purpose pins.

verified gpio(kernel) gpio(rda) alt mode° i96 name pin pin i96 name mode° alt gpio (rda) gpio (kernel) verified
GND 1 2 GND
yes gpio40 gpio_b8 ttyS0 gpio UART0_CTS 3 4 PWR_BTN_N note 2
yes gpio104 gpio_c8 ttyS0 ttyS0 UART0_TX 5 6 v_rtc 1.4V
yes gpio103 gpio_c7 ttyS0 ttyS0 UART0_RX 7 8 SPI0_CLK gpio spi2 gpio_a2 gpio2 yes
yes gpio41 gpio_b9 ttyS0 gpio UART0_RTS 9 10 SPI0_DI gpio spi2 gpio_a4 gpio4 yes
yes gpio14 gpio_a14 ttyS1 ttyS1 UART1_TX 11 12 SPI0_CS gpio spi2 gpio_a6 gpio6 yes
yes gpio102 gpio_c6 ttyS1 ttyS1 UART1_RX 13 14 SPI0_DO gpio spi2 gpio_a3 gpio3 yes
yes gpio0 gpio_a0 i2c-1 i2c-1 I2C0_SCL 15 16 PCM_FS pcm pcm gpio_a10 gpio10 yes
yes gpio1 gpio_a1 i2c-1 i2c-1 I2C0_SDA 17 18 PCM_CLK pcm pcm gpio_a9 gpio9 yes
yes gpio38 gpio_b6 i2c-2 i2c-2 I2C1_SCL 19 20 PCM_D0 pcm pcm gpio_a13 gpio13 yes
yes gpio39 gpio_b7 i2c-2 i2c-2 I2C1_SDA 21 22 PCM_DI pcm pcm gpio_a11 gpio11 yes
yes gpio15 gpio_a15 ttyS1 ttyS1 GPIO_A 23 24 GPIO_B lcd lcd gpio_a20 gpio20 yes
yes gpio56 gpio_b24 gpio GPIO_C 25 26 GPIO_D ttyS2 ttyS2 gpio_d2 gpio66 yes
yes gpio67 gpio_d3 ttyS2 ttyS2 GPIO_E 27 28 GPIO_F lcd lcd gpio_a22 gpio22 yes
yes gpio30 gpio_a30 lcd lcd GPIO_G 29 30 GPIO_H lcd lcd gpio_a29 gpio29 yes
yes gpio28 gpio_a28 lcd lcd GPIO_I 31 32 GPIO_J lcd lcd gpio_a27 gpio27 yes
yes gpio26 gpio_a26 lcd lcd GPIO_K 33 34 GPIO_L lcd lcd gpio_a25 gpio25 yes
2.9V v_pad +1v8 35 36 SYS_DCIN n/c
5V(usb) +5v 37 38 SYS_DCIN n/c
GND 39 40 GND

° NOTE: these are the default modes with this software:

function version
u-boot U-Boot 2012.04.442-rel5.0.2-g5ee06c1-dirty (Mar 18 2020 - 18:51:54)
kernel Linux version 3.10.62-rel5.0.2+ (Linaro)
distribution Ubuntu 16.04

NOTE 2: this pin measures 0v normally, rises to 3.8V when the power button is pushed; this appears to be the opposite of the i96 spec. The schematic indicates that it's used as an interrupt, so this inversion probably doesn't matter.

In order to align the bus pins with the intended function of the i96 bus, we need to make some changes. The UART1, I2C and I2S/PCM pins are configured correctly. Pins 3, 9 (uart), 8, 10,12 and 14 (spi) need to be set to 'special-function'. And all the pins between 23 and 34 need to be set to 'gpio' mode. At the bottom of this file you can find a Python3 utility to restore the pins of the microproccesor to the states intended by the i96 bus.

The existing linux kernel does not give access to the pin-function control registers, but there are a couple of ways to access those registers from the linux environment:

  • the excellent devmem2 utility written by Jan-Derk Bakker; use apt install devmem2
  • C code using mmap()
  • Python3 code using mmap()

This document was written using devmem2 to locate and test the control registers.

Here are the relevant registers:

Register Name Register Address Usage Existing State Desired State
IOMUX 0x11a0.9008 special-function/gpio select for group C 0x7fe0.003f 0x7fe0.003f
IOMUX-A 0x11a0.900c ibid, group A 0x0002.10fc 0x7e52.90a0
IOMUX-B 0x11a0.9010 ibid, group B 0x3f00.033f 0x3f00.003f
IOMUX-D 0x11a0.9014 ibid, group D 0x0000.0010 0x0000.001c
GPIO-DIR 0x11a0.8000 direction register for group C
GPIO-DATA 0x11a0.800c data register for group C
GPIO-A-DIR 0x2093.0000 direction register for group A
GPIO-A-DATA 0x2093.000c data register for group A
GPIO-B-DIR 0x2093.1000 direction register for group B
GPIO-B-DATA 0x2093.100c data register for group B
GPIO-D-DIR 0x2093.2000 direction register for group D
GPIO-D-DATA 0x2093.200c data register for group D

The patterns shown on the first 4 lines of this table will set the GPIO pins to align with the i96 bus specifications. And give you access to 12 general purpose GPIO pins (23-34). Note: a '1' written into this register will select a pin for GPIO; a '0' selects the special-function mode.

The last 8 entries are for information only. The Linux GPIO device driver /sys/class/gpio works perfectly; there's no need to bypass it. (The linux /dev/gpiochip does not exist in this kernel, since it's 3.10)

For example, after the GPIO correction, to toggle pin 26 (i96-name: GPIO-D, linux-name: gpio66), simply:

cd /sys/class/gpio  
echo 66 > export
cd gpio66
echo out > direction
echo 1 > value
echo 0 > value

## alternatively, use gpio or opio
opio mode 66 out    
# this will also do the 'export' function and create /sys/class/gpio/gpio66
opio write 66 1
opio write 66 0

The code to restore the GPIO pins to the i96 standard is in the file gpio_fixup.py. I recommend you install it at /usr/local/bin/gpio_fixup.py and add it to /etc/rc.local near the end of the boot sequence.

GPIO State at Boot Time

Be aware that if you connect 'output' hardware to the 40pin connector, the GPIO's may not be set properly in the 5-20 seconds between U-Boot and running the gpio-correction code. This time can stretch even longer if the Wifi module takes time to stabilize.

If you want to be sure about the state of an output, use one of these:

  • GPIOC (pin 25 on the i96 connector, gpio56 in the linux driver)
  • UART2_CTS as a GPIO (pin 3 on the i96 connector, gpio40 in the linux driver)
  • UART2_RTS as a GPIO (pin 9 on the i96 connector, gpio41 in the linux driver)

Prior to setting the gpio pin as an output, these pin will be hi-impedance. Design your hardware that it operates properly in the absence of a drive-voltage.

Once the system has booted, you can set the GPIO mode on pins 3 and 9 using the opio program: opio mode 40 out and opio mode 41 out.

Of course, all of the above comments apply to the current uboot. A modified version could set the other i96 pins properly, but modifying uboot is beyond my skill level.

2G-IOT board

The 2G-IOT board is very similar, except that the GPIO bits are mostly set correctly. Here is the state of the pins at power-on (using the currently shipping uboot/kernel)

opio -2 status

+-----+-----+----------+------+-+ OrgPi 2G-iot +-+------+----------+-----+-----+
| gpio| alt | i96 Name | Mode | V | Physical | V | Mode | i96 Name | alt | gpio|
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
|     | 2.8v| V_PAD    |      |   |  1 || 2  |   |      | VDD_IN   | 5V  |     |
| 63  | SDA | I2C1.SDA | alt  | ? |  3 || 4  |   |      | VDD_IN   | 5V  |     |
| 62  | SCL | I2C1.SCL | alt  | ? |  5 || 6  |   |      | GND      |     |     |
| 56  |     | GPIO.B24 | out  | 0 |  7 || 8  | ? | alt  | UART2.TX |     | 104 |
|     |     | GND      |      |   |  9 || 10 | ? | alt  | UART2.RX |     | 103 |
| 102 | RX  | UART1.RX | alt  | ? | 11 || 12 | 1 | out* | GPIO.B5  |     | 37  |
| 14  | TX  | UART1.TX | alt  | ? | 13 || 14 |   |      | GND      |     |     |
| 15  | CTS | UART1.CT | alt  | ? | 15 || 16 | 0 | in*  | GPIO.C5  |     | 101 |
|     | 2.8v| V_PAD    |      |   | 17 || 18 | 0 | in*  | GPIO.C25 | SIM | 121 |
| 4   | DI  | SPI2.DI  | in*  | 0 | 19 || 20 |   |      | GND      |     |     |
| 3   | DIO | SPI2.DIO | in*  | 0 | 21 || 22 | ? | alt  | UART1.RT | RTS | 16  |
| 2   | CLK | SPI2.CLK | in*  | 0 | 23 || 24 | 1 | in*  | SPI2.CS0 | CS0 | 5   |
|     |     | GND      |      |   | 25 || 26 | 0 | in*  | SPI2.CS1 | CS1 | 6   |
| 1   |     | I2C2.SDA | alt  | ? | 27 || 28 | ? | alt  | I2C2.SCL | SCL | 0   |
| 122 | SIM | GPIO.C26 | in*  | 0 | 29 || 30 |   |      | GND      |     |     |
| 123 | SIM | GPIO.C27 | in*  | 1 | 31 || 32 | 0 | out* | UART2.RT | RTS | 41  |
| 124 | LCD | GPIO.C28 | in*  | 0 | 33 || 34 |   |      | GND      |     |     |
| 125 | LCD | GPIO.C29 | in*  | 0 | 35 || 36 | 0 | out* | UART2.CT | CTS | 40  |
| 126 | LCD | GPIO.C30 | in*  | 0 | 37 || 38 | ? | alt  | I2C3.SCL | SCL | 38  |
|     |     | GND      |      |   | 39 || 40 | ? | alt  | I2C3.SDA | SDA | 39  |
+-----+-----+----------+------+---+----++----+---+------+----------+-----+-----+
Note: *these pins are set to GPIO mode but do NOT have exports in /sys/class/gpioNote: *these pins are set to GPIO mode but do NOT have exports in /sys/class/gpio

If you wish to use SPI2, you will have to set the mode pins to 'alt'; if not, you have 5 extra gpio pins already set up as inputs. Gpio pins 40 and 41 are set to outputs. I2C1, UART1, I2C2 and UART2 (tx+rx) are already set up and ready to use.

GPIO/OPIO program

You can control the state of the pins using the opio command line tool, documented here in this file, or here if you want to download it.