GPIO
1. GPIO Subsystem
GPIO (General-Purpose Input/Output) is a versatile pin that can be controlled by a microcontroller (MCU) or CPU. It serves various functions, such as detecting high and low signal levels and controlling output. In Linux, GPIO pins can be exported to user space and controlled via the sysfs filesystem. This allows GPIO pins to be used for multiple purposes, including serial communication, I2C, network communication, and voltage detection.
Linux provides a dedicated GPIO subsystem driver framework to handle GPIO devices. Through this framework, users can easily interact with the CPU’s GPIO pins. The driver framework supports basic input and output functionality, including interrupt detection for inputs. This flexibility makes it easy for developers to repurpose GPIO pins for various tasks. For more detailed information on the GPIO subsystem, refer to <Linux kernel source>/Documentation/gpio.
2.GPIO Control (Shell)
2.1 Pin Layout
To export GPIO pins to user space, the pin number is often required, which can be identified from the interface diagram. Detailed pin functions can be found in the "Data Download" section, including the 40-pin layout or Datasheet manual.Luckfox Omni3576 Pin Diagram:
2.2 GPIO Number Calculation
GPIO pin numbers are labeled in the pin diagram, which can be directly used or calculated using the method below.
GPIO has 5 banks: GPIO0~GPIO4, each bank is divided into 4 groups, with a total of 32 pins: A0~A7, B0~B7, C0~C7, D0~D7
GPIO Naming Convention: GPIO pins are named as GPIO{bank}_{group}{X}, such as:
GPIO0_A0 ~ A7
GPIO0_B0 ~ B7
GPIO0_C0 ~ C7
GPIO0_D0 ~ D7
GPIO1_A0 ~ A7
....
GPIO1_D0 ~ D7
....
GPIO4_D0 ~ D7GPIO Number Calculation Formula:
pin = bank * 32 + number
number = group * 8 + X
pin = bank * 32 + (group * 8 + X)For example, calculating the pin number for GPIO2_D7_d:
bank:2group:3 (A=0, B=1, C=2, D=3)X:7
Pin number: 2 x 32 + ( 3x 8 + 7) = 95
2.3 Controlling GPIO via Sysfs
Export GPIO to User Space:
sudo su
echo 95 > /sys/class/gpio/exportUnexport GPIO from User Space:
echo 95 > /sys/class/gpio/unexport
2.3.1 Device Directory and Attributes
When you write a GPIO number to
/sys/class/gpio/export, the kernel exports this GPIO to user space, making it accessible through the/sys/class/gpio/gpio<N>directory for subsequent operations (e.g., setting direction, setting or reading level).root@luckfox:/home/luckfox# ls /sys/class/gpio
export gpio95 gpiochip0 gpiochip128 gpiochip32 gpiochip509 gpiochip64 gpiochip96 unexportThe
/sys/class/gpio/gpioN(N = 1, 2, 3, 5, ...) directory contains various attributes for GPIO control.cd /sys/class/gpio/gpio95
root@luckfox:/sys/class/gpio/gpio95# ls
active_low device direction edge power subsystem uevent valuedirection: Configure GPIO as input (in) or output (out).value: Read input level or control output level. Writing/reading1sets/reads a high level, while0sets/reads a low level.edge: Configure interrupt trigger type (used only for GPIO set as interrupts):- Rising edge:
rising - Falling edge:
falling - Both edges:
both - Disable interrupt:
none
- Rising edge:
2.3.2 Controlling GPIO Levels
Set Direction
root@luckfox:/sys/class/gpio/gpio95# pwd # Ensure you're in the target GPIO directory
/sys/class/gpio/gpio95
echo out > direction # Set GPIO as output
echo in > direction # Set GPIO as inputControl GPIO Level Using the
valueAttribute# Output
echo 1 > value
echo 0 > value
# Input
cat valuePossible Errors
root@luckfox:~# echo 72 > /sys/class/gpio/export
bash: echo: write error: Device or resource busy- This error may occur if the GPIO is already claimed by a driver. Use the following command to check:
mount -t debugfs none /media
cat /media/gpio
root@luckfox:/# cat /media/gpio
gpiochip0: GPIOs 0-31, parent: platform/27320000.gpio, gpio0:
gpio-9 ( |bt_default_wake_host) in lo IRQ
gpio-14 ( |reset ) out lo ACTIVE LOW
gpiochip1: GPIOs 32-63, parent: platform/2ae10000.gpio, gpio1:
gpio-50 ( |bt_default_rts ) out lo
gpio-55 ( |vcc5v0-host ) out hi
gpio-60 ( |bt_default_wake ) out hi
gpio-61 ( |work ) out hi
gpiochip2: GPIOs 64-95, parent: platform/2ae20000.gpio, gpio2:
gpiochip3: GPIOs 96-127, parent: platform/2ae30000.gpio, gpio3:
gpio-104 ( |GTP RST PORT ) in hi
gpio-118 ( |led ) out hi ACTIVE LOW
gpio-120 ( |led ) out hi ACTIVE LOW
gpio-125 ( |vbus5v0-typec ) out lo
gpio-127 ( |reset ) out lo ACTIVE LOW
gpiochip4: GPIOs 128-159, parent: platform/2ae40000.gpio, gpio4:
gpio-128 ( |vcc3v3-m2 ) out hi
gpio-148 ( |sbu1-dc ) out lo
gpio-149 ( |sbu2-dc ) out hi
gpiochip5: GPIOs 509-511, parent: platform/rk806-pinctrl.1.auto, rk806-gpio, can sleep:
3. Controlling I/O with Python
Toggle an LED Using Python
#!/usr/bin/python3
from periphery import GPIO
import time
LED_Pin = 95
LED_GPIO = GPIO(LED_Pin, "out")
while True:
try:
LED_GPIO.write(True)
time.sleep(0.5)
LED_GPIO.write(False)
time.sleep(0.5)
except KeyboardInterrupt:
LED_GPIO.write(False)
break
except IOError:
print ("Error")
LED_GPIO.close()Run the Program
chmod 777 gpio.py
./gpio.py
4. Controlling I/O with C
Download and extract the C code archive, and upload it to the Omni3576 board.
Enter the project folder. There are four files in the project: sysfs_gpio.c, sysfs_gpio.h, main.c and Makefile:
linaro@linaro-alip:~$ cd Luckfox_GPIO_C && ls
main.c Makefile sysfs_gpio.c sysfs_gpio.h
linaro@linaro-alip:~/Luckfox_GPIO_C$The physical code of the Omni3576 pins is defined in the sysfs_gpio.h file and called in the main function main.c. You can modify it according to your needs:
#sysfs_gpio.h
....
#define I2C0_SDA 18 // 3,18
#define I2C0_SCL 17 // 5,17
#define UART8_TX 70 // 7,70
#define GPIO17 98 //11,98
#define GPIO27 99 //13,99
#define GPIO22 13 //15.13
#define SPI0_MOSI 24 //19,24
#define SPI0_MISO 25 //21,25
#define SPI0_CLK 23 //23,23
#define I2C8_SDA 79 //27,79
#define UART8_RX 71 //29,71
#define GPIO6 151 //31,151
#define GPIO13 97 //33,97
#define SPI4_MISO 138 //35,138
#define GPIO26 72 //37,72
#define UART2_TX 141 //8,141
#define UART2_RX 140 //10,140
#define PWM2 27 //12,27
#define GPIO23 12 //16,12
#define GPIO24 21 //18,21
#define GPIO25 77 //22,77
#define SPI0_CS0 22 //24,22
#define SPI0_CS1 19 //26,19
#define I2C8_SCL 78 //28,78
#define GPIO12 96 //32,96
#define GPIO16 95 //36,95
#define SPI4_MOSI 137 //38,137
#define SPI4_CLK 136 //40,136
....
#main.c
....
int x[28] = {I2C0_SDA, I2C0_SCL, UART8_TX, GPIO17, GPIO27,
GPIO22, SPI0_MOSI, SPI0_MISO, SPI0_CLK, I2C8_SDA,UART8_RX,
GPIO6, GPIO13, SPI4_MISO, GPIO26,UART2_TX, UART2_RX, PWM2,
GPIO23, GPIO24, GPIO25, SPI0_CS0, SPI0_CS1, I2C8_SCL, GPIO12,
GPIO16, SPI4_MOSI, SPI4_CLK};
....Compile the program:
root@luckfox:/home/luckfox/Luckfox_GPIO_C# make
cc -c sysfs_gpio.c -o sysfs_gpio.o
cc -c main.c -o main.o
cc sysfs_gpio.o main.o -o sysfs_gpioRun the program to toggle LEDs and debug GPIO states:
root@luckfox:/home/luckfox/Luckfox_GPIO_C# ./sysfs_gpio
Debug: Export: Pin18
Debug: Pin18:Output
Debug: Export: Pin17
Debug: Pin17:Output
Debug: Export: Pin70
Debug: Pin70:Output
Debug: Export: Pin98
Debug: Pin98:Output
Debug: Export: Pin99
Debug: Pin99:Output
Debug: Export: Pin13
Debug: Pin13:Output
Debug: Export: Pin24
Debug: Pin24:Output
Debug: Export: Pin25
Debug: Pin25:Output
Debug: Export: Pin23
Debug: Pin23:Output
Debug: Export: Pin79
Debug: Pin79:Output
Debug: Export: Pin71
Debug: Pin71:Output
....
5. Device Tree Overview
The GPIO DTS source file is already defined in
kernel-6.10/arch/arm64/boot/dts/rockchip/rk3576.dtsi, and we can use it directly.gpio2: gpio@2ae20000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0x2ae20000 0x0 0x200>;
interrupts = <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 64 32>;
interrupt-controller;
#interrupt-cells = <2>;
};If you want to configure
GPIOfor input and output, take controlling an LED as an example. You can define it in the device filekernel-6.1/arch/arm64/boot/dts/rockchip/luckfox-omni3576.dts:/ {
model = "Luckfox Omni3576";
compatible = "luckfox,omni3576", "rockchip,rk3576";
gpio2pb0:gpio2pb0 {
pinctrl-names = "default";
pinctrl-0 = <&gpio2_pb0>;
gpios = <&gpio2 RK_PB0 GPIO_ACTIVE_HIGH>;
};
};
&pinctrl {
gpio2-pb0 {
gpio2_pb0:gpio2-pb0 {
rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};To configure
GPIOinterrupts, you can define them in the device filekernel-6.1/arch/arm64/boot/dts/rockchip/luckfox-omni3576.dtsas follows:/ {
model = "Luckfox Omni3576";
compatible = "luckfox,omni3576", "rockchip,rk3576";
gpio2pb0:gpio2pb0 {
compatible = "rockchip,gpio-bank";
pinctrl-names = "default";
pinctrl-0 = <&gpio2_pb0>;
interrupt-parent = <&gpio2>;
interrupts = <RK_PB0 IRQ_TYPE_EDGE_RISING>;
};
};
&pinctrl {
gpio2-pb0 {
gpio2_pb0:gpio2-pb0 {
rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};IRQ_TYPE_NONE: No defined interrupt trigger typeIRQ_TYPE_EDGE_RISING: Triggered on rising edgeIRQ_TYPE_EDGE_FALLING: Triggered on falling edgeIRQ_TYPE_EDGE_BOTH: Triggered on both rising and falling edgesIRQ_TYPE_LEVEL_HIGH: Triggered on high levelIRQ_TYPE_LEVEL_LOW: Triggered on low level