This repository contains GPIO library for Pine A64/A64+ single board computers based on Allwinner A64 CPU. Currently, it only supports programmed input-output without interrupts. It was tested on Pine A64+ running Armbian 22.11.1 Jammy with Linux 5.15.80-sunxi64 kernel.
The image below shows the position of connectors on Pine A64/A64+ board.
Source (accessed 13.02.2023): wiki link, PINE A64 Connector Layout @courtesy of norm24 (PNG link)
Allwinner A64 user manual (PDF link, accessed 13.02.2023) on page 376 states that the CPU has 7 GPIO ports, each containing a number of configurable 1-bit input/output lines.
- Port B (PB): 10 i/o
- Port C (PC): 17 i/o
- Port D (PD): 25 i/o
- Port E (PE): 18 i/o
- Port F (PF): 7 i/o
- Port G (PG): 14 i/o
- Port H (PH): 12 i/o
According to file 'PINE A64 Pi-2/Eular/Ext Bus/Wifi Bus Connector Pin Assignment (Updated 15/Feb/2016)' (PDF link, accessed 13.02.2023) from Pine A64 wiki, the listed above i/o lines are available through four goldpin connectors located on the board. The following tables show goldpin indexes and their corresponding i/o lines, e.g. i/o line PC6 can be accessed through 36-th goldpin of Pi-2 Connector.
GPIO library only uses Linux system calls and C standard library functions without any external dependencies. To build it, firstly clone this repository to a Pine A64/A64+ board running Linux. Make sure you have gcc (GNU Compiler Collection) and ar (Archiver) available. Then you have two options:
- If
make(GNU Make) is available, build the library using the following command:make libgpio
or
- Permit execution of build.sh Bash script and run it:
chmod 755 build.sh ./build.sh
Either way, compiled static library archive libgpio.a is placed in ./build directory.
To delete ./build, use:
-
make clean
or
-
rm -r ./build
-
In your code, create
gpio_context_tstruct instance and initialize it withint gpio_init(gpio_context_t *ctx). -
Using the tables in PDF link, select a GPIO pin and check which i/o line symbol corresponds to the pin.
E.g. pin 38 of Pi-2 Connector and i/o line PC10.
-
Set the i/o line's function with
void gpio_set_function(gpio_context_t *ctx, uint8_t gpio, uint8_t function).gpioparameter contains GPIO port index in 3 more significant bits
and i/o line index in 5 less significant bits.port index port symbol number of i/o lines 0 PB 10 1 PC 17 2 PD 25 3 PE 18 4 PF 7 5 PG 14 6 PH 12 E.g. for i/o line PC10,
gpio= 001 01010According to Allwinner A64 user manual, i/o line's basic function options are represented by the following bit sequences:
- 000: Input
- 001: Output
- 111: IO Disable
Various GPIO i/o lines can have different special functions (e.g. for hardware SPI protocol, UART, etc.) but three basic ones listed above should remain the same for all i/o lines.
Pass the selected option in 3 least significant bits of
functionparameter.Example
gpio_set_functioncall for setting PC10 i/o line as output.
gpio_set_function(&ctx, 0b00101010, 0b001) -
(Optional, do it only with input i/o line function) Set the i/o line's internal pull-up/down resistor with
void gpio_set_pull_up_down(gpio_context_t *ctx, uint8_t gpio, uint8_t pull_up_down).For
gpioparameter look up to paragraph 3.According to Allwinner A64 user manual, i/o line's pull-up/down resistor options are represented by the following bit sequences:
- 00: Pull-up/down disable
- 01: Pull-up
- 10: Pull-down
- 11: Reserved
Pass the selected option in 2 least significant bits of
pull_up_downparameter.Example
gpio_set_pull_up_downcall for enabling PD6 i/o line's pull-up resistor.
gpio_set_pull_up_down(&ctx, 0b01000110, 0b01) -
-
Only with output i/o line function
Set i/o line's value with
void gpio_set_value(gpio_context_t *ctx, uint8_t gpio, uint8_t value).Example
gpio_set_valuecall for writing bit value 0 to PC10 i/o line.
gpio_set_value(&ctx, 0b00101010, 0b0) -
Only with input i/o line function
Get i/o line's value with
uint8_t gpio_get_value(gpio_context_t *ctx, uint8_t gpio).Example
gpio_get_valuecall for reading bit value from PE6 i/o line.
gpio_get_value(&ctx, 0b01000110)The read bit value is placed in the least significant bit of 8-bit variable returned by
gpio_get_value.
-
-
Release resources used by
gpio_context_tstruct instance withint gpio_cleanup(gpio_context_t *ctx).
-
Compile your program with
gccwithout linkinggcc program.c -c -o program.o -
Link your program's object file
program.oagainst compiled GPIO static library archivelibgpio.a. After-Lparameter, pass the name of the directory where you havelibgpio.a.gcc program.o -L[directory] -l:libgpio.a -o program -
Run the executable.
sudo ./programIt must be run with root's permissions because GPIO library operates on low-level registers accessible by CPU's address space. Otherwise
mmapfails andgpio_context_tstruct instance can not be initialized.
Code for examples shown below is located in examples directory.
To build this example, use make
make button
In this example, a button acts as SPST (Single Pole Single Throw) switch. When the button is pressed, it shorts GPIO pin 38 (i/o line PC10) to ground and gpio_get_value returns 0. Due to enabled pull-up resistor mode, when the button is released, the i/o line PC10 is charged up to high logic level electric potential and gpio_get_value returns 1.
(Click the image to watch the presentation on YouTube.)
This example uses SegDisp library dependent on GPIO library. SegDisp library can be used to drive a 4-digit 8-segment LED display module based on two 75HC595 shift registers connected in series (images below).
To build SegDisp, use
make libsegdisp
or (the same as for GPIO library in Building paragraph)
chmod 755 build.sh
./build.sh
Either way, compiled static library archive libsegdisp.a is placed in ./build directory.
To build and run a program using SegDisp, use
gcc program.c -c -o program.o
gcc program.o -L[directory containing libsegdisp.a] -l:libsegdisp.a -o program
sudo ./program
You can also build display example with make
make display
This example presents how SegDisp library drives a display module. For details on data format accepted by the module, see segdisp_display_digit function definition in segdisp.c file.
The counter can be slowed down but refresh rate must be preserved to avoid flickering.
base parameter value passed to segdisp_display_number determines the numeral system in which the counter value is expressed.










