md
Orange Pi PC 2 Input/Output with Armbian Bionic
March 9, 2020
<-ALSA and Bluetooth on the Orange Pi PC 2 with Armbian Bionic --
<-A Second Look at the Orange Pi PC 2

The Orange Pi PC 2, which is slightly bigger than the Raspberry Pi model B, has a similar 40 pin general purpose input output header in approximately the same location. The absence of a UART on physical pins 8 and 10 is one notable difference which is easily overlooked because the dedicated 3 pin UART header on the OPiPC2. There are other differences. We have already seen that the I2C controllers connected to the I2C pins are not assigned the same bus number.

Table of Contents

  1. H5 SoC General Purpose Input/Output
  2. GPIO Header
  3. Access Through the sysfs Interface
  4. Access Through the GPIO Character Device

H5 SoC General Purpose Input/Output toc

There are 106 I/0 pins on the Allwinner H5 arranged in 7 banks called GPIOA, GPIOC to GPIOG and GPIOL (what happened to B, H, I, J, K?). Thankfully, the numbering of pins within a bank is consecutive and starts at 0.

BankFirst PinLast PinPin
Count
NameNumberNameNumber
GPIOAPA00PA212122
GPIOCPC064PC168017
GPIODPD096PD1711318
GPIOEPE0128PE15 14316
GPIOFPF0160PF61667
GPIOGPG0192PG1320514
GPIOLPL0352PL1136312
total106

Pin numbers are calculated from the pin name. As an example, here is the calculation to obtain the pin number of pin 12 in GPIO bank D.

The ordinal number of a letter is it's position in the latin alphabet: ord(A) = 1, ord(B) = 2 and so on. Pin numbers (or GPIO numbers) are not consecutive but they do give a unique number to each pin which simplifies access to them as will be seen below.

Descriptions of all these pins can be found in Chapter 4 Pin Description of the Allwinner H5 Datasheet V1.0. SUNXI provides a succint description of the pins and their functions for the H3 SoC which is bacically the same as the H5 SoC except for the ARM cores. The kernel debug interface also lists the available I/O pins, including their pin number, their name, function, drive capabilities and so on.

opipc@orangepipc2:~$ sudo -i root@orangepipc2:~# cd /sys/kernel/debug/pinctrl root@orangepipc2:/sys/kernel/debug/pinctrl# ls -l total 0 drwxr-xr-x 2 root root 0 Dec 31 1969 1c20800.pinctrl drwxr-xr-x 2 root root 0 Dec 31 1969 1f02c00.pinctrl -r--r--r-- 1 root root 0 Dec 31 1969 pinctrl-devices -r--r--r-- 1 root root 0 Dec 31 1969 pinctrl-handles -r--r--r-- 1 root root 0 Dec 31 1969 pinctrl-maps

Have a look at the content of the three pinctrl-* files, it is instructive but not quite essential for the purpose at hand. Also look at the content of the two controllers. It's worthwhile to look at all the files that describe the I/O pins from differnt point of views. Here is a partial listing.

root@orangepipc2:/sys/kernel/debug/pinctrl# ls -l 1c20800.pinctrl/ total 0 -r--r--r-- 1 root root 0 Dec 31 1969 gpio-ranges -r--r--r-- 1 root root 0 Dec 31 1969 pinconf-groups -r--r--r-- 1 root root 0 Dec 31 1969 pinconf-pins -r--r--r-- 1 root root 0 Dec 31 1969 pingroups -r--r--r-- 1 root root 0 Dec 31 1969 pinmux-functions -r--r--r-- 1 root root 0 Dec 31 1969 pinmux-pins -r--r--r-- 1 root root 0 Dec 31 1969 pins root@orangepipc2:/sys/kernel/debug/pinctrl# cat 1c20800.pinctrl/pinconf-pins Pin config settings per pin Format: pin (name): configs pin 0 (PA0): input bias disabled, output drive strength (20 mA) pin 1 (PA1): input bias disabled, output drive strength (20 mA) pin 2 (PA2): input bias disabled, output drive strength (20 mA) ... pin 5 (PA5): input bias pull up, output drive strength (20 mA) ... pin 67 (PC3): input bias pull up, output drive strength (20 mA) pin 68 (PC4): input bias pull up, output drive strength (20 mA) ... pin 204 (PG12): input bias disabled, output drive strength (20 mA) pin 205 (PG13): input bias disabled, output drive strength (20 mA) root@orangepipc2:/sys/kernel/debug/pinctrl# cat 1c20800.pinctrl/pinmux-functions function: gpio_in, groups = [ PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PA8 PA9 PA10 PA11 PA12 PA13 PA14 PA15 PA16 PA17 PA18 PA19 PA20 PA21 PC0 PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 PD0 PD1 PD2 PD3 PD4 PD5 PD6 PD7 PD8 PD9 PD10 PD11 PD12 PD13 PD14 PD15 PD16 PD17 PE0 PE1 PE2 PE3 PE4 PE5 PE6 PE7 PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 PF0 PF1 PF2 PF3 PF4 PF5 PF6 PG0 PG1 PG2 PG3 PG4 PG5 PG6 PG7 PG8 PG9 PG10 PG11 PG12 PG13 ] function: gpio_out, groups = [ PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PA8 PA9 PA10 PA11 PA12 PA13 PA14 PA15 PA16 PA17 PA18 PA19 PA20 PA21 PC0 PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 PD0 PD1 PD2 PD3 PD4 PD5 PD6 PD7 PD8 PD9 PD10 PD11 PD12 PD13 PD14 PD15 PD16 PD17 PE0 PE1 PE2 PE3 PE4 PE5 PE6 PE7 PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 PF0 PF1 PF2 PF3 PF4 PF5 PF6 PG0 PG1 PG2 PG3 PG4 PG5 PG6 PG7 PG8 PG9 PG10 PG11 PG12 PG13 ] function: uart2, groups = [ PA0 PA1 PA2 PA3 ] function: jtag, groups = [ PA0 PA1 PA2 PA3 PF0 PF1 PF3 PF5 ] function: irq, groups = [ PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PA8 PA9 PA10 PA11 PA12 PA13 PA14 PA15 PA16 PA17 PA18 PA19 PA20 PA21 PF0 PF1 PF2 PF3 PF4 PF5 PF6 PG0 PG1 PG2 PG3 PG4 PG5 PG6 PG7 PG8 PG9 PG10 PG11 PG12 PG13 ] function: uart0, groups = [ PA4 PA5 PF2 PF4 ] function: pwm0, groups = [ PA5 ] function: sim, groups = [ PA6 PA7 PA8 PA9 PA10 PA20 PA21 PD12 PD13 PD14 PD15 PD16 PE14 PE15 ] function: i2c0, groups = [ PA11 PA12 ] function: di, groups = [ PA11 PA12 PD0 PD1 ] function: spi1, groups = [ PA13 PA14 PA15 PA16 ] function: uart3, groups = [ PA13 PA14 PA15 PA16 ] function: spdif, groups = [ PA17 ] function: i2s0, groups = [ PA18 PA19 PA20 PA21 ] function: i2c1, groups = [ PA18 PA19 ] function: nand0, groups = [ PC0 PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 ] function: spi0, groups = [ PC0 PC1 PC2 PC3 PC4 ] function: mmc2, groups = [ PC1 PC5 PC6 PC8 PC9 PC10 PC11 PC12 PC13 PC14 PC15 PC16 ] function: emac, groups = [ PD0 PD1 PD2 PD3 PD4 PD5 PD6 PD7 PD8 PD9 PD10 PD11 PD12 PD13 PD14 PD15 PD16 PD17 ] function: ts2, groups = [ PD0 PD1 PD2 PD3 PD4 PD5 PD6 PD7 PD8 PD9 PD10 PD11 ] function: ts3, groups = [ PD7 PD8 PD9 PD10 PD11 ] function: csi, groups = [ PE0 PE1 PE2 PE3 PE4 PE5 PE6 PE7 PE8 PE9 PE10 PE11 PE12 PE13 ] function: ts0, groups = [ PE0 PE1 PE2 PE3 PE4 PE5 PE6 PE7 PE8 PE9 PE10 ] function: ts1, groups = [ PE7 PE8 PE9 PE10 PE11 ] function: ts, groups = [ PE11 ] function: i2c2, groups = [ PE12 PE13 ] function: mmc0, groups = [ PF0 PF1 PF2 PF3 PF4 PF5 ] function: mmc1, groups = [ PG0 PG1 PG2 PG3 PG4 PG5 ] function: uart1, groups = [ PG6 PG7 PG8 PG9 ] function: i2s1, groups = [ PG10 PG11 PG12 PG13 ] root@orangepipc2:/sys/kernel/debug/pinctrl# cat 1c20800.pinctrl/pinmux-pins Pinmux settings per pin Format: pin (name): mux_owner gpio_owner hog? pin 0 (PA0): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 1 (PA1): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 2 (PA2): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 3 (PA3): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 4 (PA4): 1c28000.serial (GPIO UNCLAIMED) function uart0 group PA4 pin 5 (PA5): 1c28000.serial (GPIO UNCLAIMED) function uart0 group PA5 pin 6 (PA6): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 7 (PA7): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 8 (PA8): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 9 (PA9): (MUX UNCLAIMED) (GPIO UNCLAIMED) ... pin 203 (PG11): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 204 (PG12): (MUX UNCLAIMED) 1c20800.pinctrl:204 pin 205 (PG13): (MUX UNCLAIMED) (GPIO UNCLAIMED) root@orangepipc2:/sys/kernel/debug/pinctrl# exit logout opipc@orangepipc2:~$ cd ~ opipc@orangepipc2:~$

GPIO Header toc

Only 28 of the I/O pins are brought out to the 40 pin header of the OPiPC2. Here is the map of the 40 pin header on the Orange Pi PC 2. The pin numbers, calculated as shown above, are in the GPIO columns.

Orange Pi PC 2 GPIO Header
GPIOFunctionPinFunctionGPIO
3.3V 125V
12PA12 (TWI0_SDA/DI_RX/PA_EINT12) 345V
11PA11 (TWI0_SCK/DI_TX/PA_EINT11) 56GND
6PA6 (SIM_PWREN/PWM1/PA_EINT6) 78PC5 (NAND_RE/SDC2_CLK) 69
GND 910PC6 (NAND_RB0/SDC2_CMD) 70
1PA1 (UART2_RX/JTAG_CK0/PA_EINT1) 1112PD14 (RGMII_NULL/MII_TXERR/RMII_NULL) 110
0PA0 (UART2_TX/JTAG_MS0/PA_EINT0) 1314GND
3PA3 (UART2_CTS/JTAG_DI0/PA_EINT3) 1516PC4 (NAND_CE0) 68
3.3V 1718PC7 (NAND_RB1) 71
15PA15 (SPI1_MOSI/UART3_RTS/PA_EINT15) 1920GND
16PA16 (SPI1_MISO/UART3_CTS/PA_EINT16) 2122PA2 (UART2_RTS/JTAG_DO0/PA_EINT2) 2
14PA14 (SPI1_CLK/UART3_RX/PA_EINT14) 2324PA13 (SPI1_CS/UART3_TX/PA_EINT13) 13
GND 2526PA21 (PCM0_DIN/SIM_VPPPP/PA_EINT21) 21
19PA19 (PCM0_CLK/TWI1_SDA/PA_EINT19) 2728PA18 (PCM0_SYNC/TWI1_SCK/PA_EINT18) 18
7PA7 (SIM_CLK/PA_EINT7) 2930GND
8PA8 (SIM_DATA/PA_EINT8) 3132PG8 (UART1_RTS/PG_EINT8) 200
9PA9 (SIM_RST/PA_EINT9) 3334GND
10PA10 (SIM_DET/PA_EINT10) 3536PG9 (UART1_CTS/PG_EINT9) 201
107PD11 (RGMII_NULL/MII_CRS/RMII_NULL) 3738PG6 (UART1_TX/PG_EINT6) 198
GND 3940PG7 (UART1_RX/PG_EINT7)199

These pins are there for us to play with, but access to them is not quite as simple as on an ESP or an AVR device in the Arduino framework. For one thing, pin numbering is slightly more complicated as seen above and, for another thing, adminitrator privileges are needed because I/O pins belong to root. Just to complicate things, thre are more than one way to access the I/0 pins as shown below.

Access Through the sysfs Interface toc

The old way of accessing I/O pins in Linux is through the sysfs interface. The interface is a "filesystem for exporting kernel objects", as is often the case is Linux. This approach, now deprecated, still works. SUNXI has a page entitled GPIO that provides detailed instructions on this topic. There's also a reference to a well written article, Access GPIO from Linux user space by Fabio Falsini, which goes into greater detail.

It's a simple matter to verify that the GPIO pins are available in sysfs.

opipc@orangepipc2:~$ ls -l /sys/class/gpio total 0 --w------- 1 root root 4096 Dec 31 1969 export lrwxrwxrwx 1 root root 0 Dec 31 1969 gpiochip0 -> ../../devices/platform/soc/1c20800.pinctrl/gpio/gpiochip0 lrwxrwxrwx 1 root root 0 Dec 31 1969 gpiochip352 -> ../../devices/platform/soc/1f02c00.pinctrl/gpio/gpiochip352 --w------- 1 root root 4096 Dec 31 1969 unexport

The following text by Linus Walleij succinctly documents the interface.

What: /sys/class/gpio/ Date: July 2008 KernelVersion: 2.6.27 Contact: Linus Walleij Description: As a Kconfig option, individual GPIO signals may be accessed from userspace. GPIOs are only made available to userspace by an explicit "export" operation. If a given GPIO is not claimed for use by kernel code, it may be exported by userspace (and unexported later). Kernel code may export it for complete or partial access. GPIOs are identified as they are inside the kernel, using integers in the range 0..INT_MAX. See Documentation/admin-guide/gpio for more information. /sys/class/gpio /export ... asks the kernel to export a GPIO to userspace /unexport ... to return a GPIO to the kernel /gpioN ... for each exported GPIO #N OR /<LINE-NAME> ... for a properly named GPIO line /value ... always readable, writes fail for input GPIOs /direction ... r/w as: in, out (default low); write: high, low /edge ... r/w as: none, falling, rising, both /gpiochipN ... for each gpiochip; #N is its first GPIO /base ... (r/o) same as N /label ... (r/o) descriptive, not necessarily unique /ngpio ... (r/o) number of GPIOs; numbered N to N + (ngpio - 1) This ABI is deprecated and will be removed after 2020. It is replaced with the GPIO character device.

Let's toggle pin PA11 (GPIO pin number 11, physical pin 5) high and low using the sysfs interface. First access to the pin must be gained which is done by writting the pin number to the export file in the gpio sysfs directory. Once that is done, a new directory, called gpio11 is created.

root@orangepipc2:/home/opipc# echo 11 > /sys/class/gpio/export root@orangepipc2:/home/opipc# ls -l /sys/class/gpio total 0 --w------- 1 root root 4096 Mar 10 19:15 export lrwxrwxrwx 1 root root 0 Mar 10 19:15 gpio11 -> ../../devices/platform/soc/1c20800.pinctrl/gpiochip1/gpio/gpio11 lrwxrwxrwx 1 root root 0 Mar 10 19:05 gpiochip0 -> ../../devices/platform/soc/1c20800.pinctrl/gpio/gpiochip0 lrwxrwxrwx 1 root root 0 Mar 10 19:05 gpiochip352 -> ../../devices/platform/soc/1f02c00.pinctrl/gpio/gpiochip352 --w------- 1 root root 4096 Mar 10 19:05 unexport root@orangepipc2:/home/opipc# ls -l /sys/class/gpio/gpio11/ total 0 -rw-r--r-- 1 root root 4096 Mar 10 19:15 active_low lrwxrwxrwx 1 root root 0 Mar 10 19:15 device -> ../../../gpiochip1 -rw-r--r-- 1 root root 4096 Mar 10 19:15 direction -rw-r--r-- 1 root root 4096 Mar 10 19:15 edge drwxr-xr-x 2 root root 0 Mar 10 19:15 power lrwxrwxrwx 1 root root 0 Mar 10 19:15 subsystem -> ../../../../../../../class/gpio -rw-r--r-- 1 root root 4096 Mar 10 19:15 uevent -rw-r--r-- 1 root root 4096 Mar 10 19:15 value

Two files are of importance for us right now (details about files). The pin mode is changed to input or output by writing in or out respectively to the direction file. When in input mode, reading the value file will return a "0" or "1" (a single ASCII character) depending on the signal present on the pin. If the pin is in output mode, writing "0" or "1" to the value file sets the pin's voltage to 0 or, nominally 3.3 volts respectively.

root@orangepipc2:/home/opipc# cd /sys/class/gpio/gpio11 ... root@orangepipc2:/sys/class/gpio/gpio11# echo "out" > direction root@orangepipc2:/sys/class/gpio/gpio11# cat value 0 root@orangepipc2:/sys/class/gpio/gpio11# echo "1" > value root@orangepipc2:/sys/class/gpio/gpio11# cat value 1 root@orangepipc2:/sys/class/gpio/gpio11# echo "0" > value root@orangepipc2:/sys/class/gpio/gpio11# cat value 0

Since it is hard to show the transition from off to on or vice versa of a LED on a static page, here is what was recorded by PulseView used with a clone of Salea logic analyzer connected to pin PA11. There is some additional annotation on screen captures shown below.

To release the pin, unexport its number. The gpio11 tree will be deleted by the system.

root@orangepipc2:/sys/class/gpio/gpio11# cd .. root@orangepipc2:/sys/class/gpio# echo 11 > unexport root@orangepipc2:/sys/class/gpio# ls -l total 0 --w------- 1 root root 4096 Mar 10 19:15 export lrwxrwxrwx 1 root root 0 Mar 10 19:05 gpiochip0 -> ../../devices/platform/soc/1c20800.pinctrl/gpio/gpiochip0 lrwxrwxrwx 1 root root 0 Mar 10 19:05 gpiochip352 -> ../../devices/platform/soc/1f02c00.pinctrl/gpio/gpiochip352 --w------- 1 root root 4096 Mar 10 21:28 unexport

Here is a short Bash script to toggle the pin on and off as quickly as possible.

#!/bin/bash # Toggle GPIO pin PA11 on and off for 5 000 cycles # # Must run as root # gpio=11 echo $gpio > /sys/class/gpio/export cd /sys/class/gpio/gpio$gpio echo "out" > direction x=1 while [ $x -le 5000 ] do echo "1" > value echo "0" > value x=$(( $x + 1 )) done

As can be seen below, a frequency of 7.8 kHz was achieved.

As one would expect because Linux is not a real-time OS, the toggling was not done at a constant rate. Even though the script ran for a short time (about 767 milliseconds), there were visible "gaps", one lasting 4 ms, while background tasks were being performed. With a compiled C program, it was possible to achieve a rather more impressive frequency of 166 kHz. Still, for a system running at 1.2 GHz, this is not all that fast.

#include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #define MAX_BUF 256 int gpio = 11; void openGpioOutput(void) { int fd; char buf[MAX_BUF]; fd = open("/sys/class/gpio/export", O_WRONLY); sprintf(buf, "%d", gpio); write(fd, buf, strlen(buf)); close(fd); printf("Exported %d to /sys/class/gpio\n", gpio); sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio); fd = open(buf, O_WRONLY); // Set out direction write(fd, "out", 3); // Set in direction //write(fd, "in", 2); close(fd); printf("Set pin %d to output mode\n", gpio); } void toggle(void) { int fd; char buf[MAX_BUF]; printf("Starting to toggle pin %d\n", gpio); sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio); fd = open(buf, O_WRONLY); for (int i=0; i < 5000; i++) { // Set GPIO high status write(fd, "1", 1); // Set GPIO low status write(fd, "0", 1); } close(fd); printf("Finished\n"); } void closeGpio(void) { int fd; char buf[MAX_BUF]; fd = open("/sys/class/gpio/unexport", O_WRONLY); sprintf(buf, "%d", gpio); write(fd, buf, strlen(buf)); close(fd); printf("GPIO pin %d released", gpio); } int main() { openGpioOutput(); toggle(); closeGpio(); }

Compile and run this program borrowed from Fabio Falsini's article

opipc@orangepipc2:~$ cc -o toggle toggle.c opipc@orangepipc2:~$ sudo ./toggle Exported 11 to /sys/class/gpio Set pin 11 to output mode Starting to toggle pin 11 Finished GPIO pin 11 released
opipc@orangepipc2:~$ sudo -i root@orangepipc2:~# echo 11 > /sys/class/gpio/export root@orangepipc2:~# cd /sys/class/gpio/gpio11 root@orangepipc2:/sys/class/gpio/gpio11# echo "in" > direction physical pin 5 grounded: root@orangepipc2:/sys/class/gpio/gpio11# cat value 0 physical pin 5 connected to 3.3 volts: root@orangepipc2:/sys/class/gpio/gpio11# cat value 1 root@orangepipc2:/sys/class/gpio/gpio11# cd .. root@orangepipc2:/sys/class/gpio# echo 11 > unexport root@orangepipc2:/sys/class/gpio# exit logout opipc@orangepipc2:~$ cd ~

Quite a bit more could be done

After setting up a switch between an I/0 pin and ground, it quickly became apparent that there is no obvious way to enable any internal pull up resistor with the sysfs interface. it worked


Access Through the GPIO Character Device toc

GPIO access using the sysfs interface has been deprecated since version 4.8 of the Linux kernel. So, in Armbian Bionic with a 5.4.20 Linux kernel, we should be using the "new" method to access the I/O pins, the character based GPIO device gpiod. references An Introduction to chardev GPIO and Libgpiod on the Raspberry PI by Craig Peacock in BeyondLogic (October 16, 2018) Pilotage de GPIO avec l’API Libgpiod (partie 1) Pilotage de GPIO avec l’API Libgpiod (partie 2) Pilotage de GPIO avec l’API Libgpiod (partie 3) de Christophe Blaess datant d'octobre 2018. https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/about/

Installing libgpiod toc

In typical Debian fashion, the six command-line tools included with the gpiod library are in a seperate package.

Manpages of gpiod in Debian experimental
opipc@orangepipc2:~$ sudo apt install gpiod Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: libgpiod1 The following NEW packages will be installed: gpiod libgpiod1 0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded. Need to get 24.4 kB of archives. After this operation, 124 kB of additional disk space will be used. Do you want to continue? [Y/n] y Get:1 http://ports.ubuntu.com bionic/universe arm64 libgpiod1 arm64 1.0-1 [10.9 kB] Get:2 http://ports.ubuntu.com bionic/universe arm64 gpiod arm64 1.0-1 [13.5 kB] Fetched 24.4 kB in 2s (12.9 kB/s) Selecting previously unselected package libgpiod1:arm64. (Reading database ... 32119 files and directories currently installed.) Preparing to unpack .../libgpiod1_1.0-1_arm64.deb ... Unpacking libgpiod1:arm64 (1.0-1) ... Selecting previously unselected package gpiod. Preparing to unpack .../archives/gpiod_1.0-1_arm64.deb ... Unpacking gpiod (1.0-1) ... Setting up libgpiod1:arm64 (1.0-1) ... Setting up gpiod (1.0-1) ... Processing triggers for libc-bin (2.27-3ubuntu1) ... opipc@orangepipc2:~$ which gpioget /usr/bin/gpioget opipc@orangepipc2:~$ sudo gpiodetect gpiochip0 [1f02c00.pinctrl] (32 lines) gpiochip1 [1c20800.pinctrl] (224 lines) opipc@orangepipc2:~$ sudo apt-cache policy libgpiod* libgpiod0: Installed: (none) Candidate: (none) Version table: libgpiod1: Installed: (none) Candidate: 1.0-1 Version table: 1.0-1 500 500 http://ports.ubuntu.com bionic/universe arm64 Packages libgpiod-dev: Installed: (none) Candidate: 1.0-1 Version table: 1.0-1 500 500 http://ports.ubuntu.com bionic/universe arm64 Packages libgpiod-doc: Installed: (none) Candidate: 1.0-1 Version table: 1.0-1 500 500 http://ports.ubuntu.com bionic/universe arm64 Packages 500 http://ports.ubuntu.com bionic/universe armhf Packages opipc@orangepipc2:~$ sudo apt install libgpiod1: Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: libgpiod1 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Need to get 10.9 kB of archives. After this operation, 39.9 kB of additional disk space will be used. Get:1 http://ports.ubuntu.com bionic/universe arm64 libgpiod1 arm64 1.0-1 [10.9 kB] Fetched 10.9 kB in 0s (25.5 kB/s) Selecting previously unselected package libgpiod1:arm64. (Reading database ... 32119 files and directories currently installed.) Preparing to unpack .../libgpiod1_1.0-1_arm64.deb ... Unpacking libgpiod1:arm64 (1.0-1) ... Setting up libgpiod1:arm64 (1.0-1) ... Processing triggers for libc-bin (2.27-3ubuntu1) ...

Using ioctl

opipc@orangepipc2:~/gpio$ nano gpio.c

// Applications - Pin Control and GPIO // https://microchipdeveloper.com/32mpu:apps-gpio // #include #include #include #include #include #include #define DEV_GPIO "/dev/gpiochip1" #define GPIO_PIN 11 // GPIO PA11 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); // this does not work in Armbian for Allwinner H5 ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo); if (ret < 0) { printf("WARNING get line info returned=%d\n", ret); } else { printf("line %2d: %s\n", linfo.line_offset, linfo.name); } */ req.lineoffsets[0] = GPIO_PIN; 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; } else { printf("Square wave generated on line %d, ^C to exit.\n", GPIO_PIN); } while (1) { // set GPIO_PIN low data.values[0] = 0; ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); //usleep(5*1000); // set GPIO_PIN high data.values[0] = 1; ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); //usleep(5*1000); } /* close gpio */ close(fd); return 0; }
opipc@orangepipc2:~/gpio$ cc -o gpio-test gpio.c opipc@orangepipc2:~/gpio$ sudo ./gpio-test Square wave generated on line 11, ^C to exit. ^C

Python

opipc@orangepipc2:~$ sudo apt install pkg-config Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: pkg-config 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Need to get 42.8 kB of archives. After this operation, 169 kB of additional disk space will be used. Get:1 http://ports.ubuntu.com bionic/main arm64 pkg-config arm64 0.29.1-0ubuntu2 [42.8 kB] Fetched 42.8 kB in 1s (41.7 kB/s) Selecting previously unselected package pkg-config. (Reading database ... 32203 files and directories currently installed.) Preparing to unpack .../pkg-config_0.29.1-0ubuntu2_arm64.deb ... Unpacking pkg-config (0.29.1-0ubuntu2) ... Setting up pkg-config (0.29.1-0ubuntu2) ... Processing triggers for man-db (2.8.3-2ubuntu0.1) ... opipc@orangepipc2:~$ mkvenv gpiod creating virtual environment /home/opipc/gpiod updating virtual environment /home/opipc/gpiod Cache entry deserialization failed, entry ignored opipc@orangepipc2:~$ ve gpiod (gpiod) opipc@orangepipc2:~$ pip install libgpiod

  https://stackoverflow.com/questions/46463724/accessing-gpio-on-orangepi-pc-plus-h3-on-armbian-3-4-113-and-newer#46464496



  https://github.com/brgl/libgpiod


  https://diyprojects.io/orange-pi-onelite-tutorial-use-gpio-python-pinouts/
  Orange Pi One/Lite (Tutorial): use the GPIO in Python, pinouts

  https://diyprojects.io/orange-pi-review-opi-gpio-package-node-red-node-red-contrib-opi-gpio/
  Orange Pi: test of the OPI.GPIO package for Node-Red (node-red-contrib-opi-gpio)



UART: yes probably! Orange Pi Zero 2+ H5 can't communicate on UART1 https://forum.armbian.com/topic/5938-orange-pi-zero-2-h5-cant-communicate-on-uart1/?tab=comments#comment-46116

https://opi-gpio.readthedocs.io/en/latest/ OPi-GPIO is a drop-in replacement library for RPi.GPIO for the Orange Pi Zero. Only the basic GPIO functions are replicated, using sysfs: this allows the GPIO pins to be accessed from user space. RPi.GPIO replacement for Orange Pi Zero and Nano Pi Duo By sgjava, January 1, 2018 https://forum.armbian.com/topic/6069-rpigpio-replacement-for-orange-pi-zero-and-nano-pi-duo/ however sysfs is depricated

https://github.com/bitbank2/ArmbianIO ArmbianIO is a C library for accessing I2C, SPI and GPIO ports in a consistent way across all of the SBCs that Armbian supports.

https://github.com/bitbank2/armbian_oled A C library for SSD1306 displays (I2C+SPI) which uses my ArmbianIO library

https://forum.armbian.com/topic/7980-wiringpi-cant-work-for-h5-cpu-orangepi-pc-2/ WiringPi can't work for H5 CPU (OrangePi PC 2)

https://github.com/bitbank2/ir_receiver C code to receive NEC codes from a GPIO connected to a IR demodulator

https://forum.armbian.com/topic/5655-armbianio-api-proposal/ ArmbianIO API proposal

https://forum.armbian.com/topic/5662-pygpio-a-more-general-python-gpio-library/ pyGPIO - A 'more general' python GPIO library

Allwinner H5 & A64 https://forum.armbian.com/forum/27-allwinner-h5-a64/page/18/

https://forum.armbian.com/profile/1032-lopau/

RPi Low-level peripherals https://elinux.org/RPi_Low-level_peripherals#General_Purpose_Input.2FOutput_.28GPIO.29

CEC (Consumer Electronics Control) over HDMI https://elinux.org/CEC_(Consumer_Electronics_Control)_over_HDMI

Bootable SPI flash https://linux-sunxi.org/Bootable_SPI_flash#Macronix_MX25L1606E

WiringPI / WiringOP

http://wiringpi.com/ Wiring Pi GPIO Interface library for the Raspberry Pi http://www.orangepi.org/Docs/WiringPi.html https://github.com/zhaolei/WiringOP https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md SPI https://elinux.org/RPi_SPI RPi SPI http://abyz.me.uk/rpi/pigpio/index.html The pigpio library