C/C++ GPIO development¶
Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.
lgpio introduction¶
lgpio is a GPIO control library for Linux system, providing a simple and easy-to-use C API to operate GPIO, I2C, SPI and other peripherals.
Main features¶
High performance: C language implementation with high execution efficiency
Cross-platform compatibility: Supports various Linux single-board computers
Rich features: Supports GPIO, I2C, SPI, PWM and other peripherals
Easy integration: Provides standard C API
Supported features¶
Feature |
Description |
|---|---|
GPIO |
General purpose input/output |
I2C |
I²C bus communication |
SPI |
Serial peripheral interface |
PWM |
Pulse width modulation |
Notification |
GPIO interruptions and event notifications |
Install lgpio¶
Install from source code¶
# Install dependency toolsapt update
apt install -y git build-essential
# Clone lgpio source codegit clone https://github.com/joan2937/lg.git
cd lg
# Compile and installmakemake install# Update dynamic linker cache
ldconfig
Verify installation¶
After installation, you can verify with the following commands:
# Check dynamic library
ldconfig -p | grep lgpio
You should see output similar to liblgpio.so.
Other verification methods:
# Check if library files existls -l /usr/local/lib/liblgpio.*
# Check if header file existsls -l /usr/local/include/lgpio.h
GPIO control¶
Hardware preparation¶
Main board
Jumper wires
Multimeter (optional, for measuring voltage)
GPIO output control¶
The following example demonstrates how to use lgpio to control GPIO pin to output high and low levels.
Example code¶
Create gpio_output.c file:
#include <stdio.h>#include <stdlib.h>#include <lgpio.h>#include <unistd.h>int main(int argc, char **argv){if (argc < 3) {printf("Usage: %s <gpio_num> <pin_level>\n", argv[0]);printf("Example: %s 36 1 # Set GPIO36 to HIGH\n", argv[0]);return 1;}int gpio_num = atoi(argv[1]);int pin_level = atoi(argv[2]);int h;// Open GPIO chip 4
h = lgGpiochipOpen(4);if (h < 0) {printf("ERROR: %s (%d)\n", lguErrorText(h), h);return 1;}// Set GPIO to output mode and set initial levelint e = lgGpioClaimOutput(h, 0, gpio_num, pin_level);if (e < 0) {printf("ERROR: %s (%d)\n", lguErrorText(e), e);lgGpiochipClose(h);return 1;}printf("GPIO %d set to %s\n", gpio_num, pin_level ? "HIGH (3.3V)" : "LOW (0V)");// Keep the state for 5 secondssleep(5);// Release GPIO resourceslgGpioFree(h, gpio_num);lgGpiochipClose(h);return 0;}
Compile program¶
gcc -o gpio_output gpio_output.c -llgpio
Run test¶
Test low level:
sudo ./gpio_output 36 0
Output: GPIO 36 set to LOW (0V)
Test high level:
sudo ./gpio_output 36 1
Output: GPIO 36 set to HIGH (3.3V)
Tip: GPIO36 corresponds to Pin3 of 40Pin.
GPIO input reading¶
The following example demonstrates how to read the state of a GPIO pin.
Example code¶
Create gpio_input.c file:
#include <stdio.h>#include <stdlib.h>#include <lgpio.h>#include <unistd.h>int main(int argc, char **argv){if (argc < 2) {printf("Usage: %s <gpio_num>\n", argv[0]);printf("Example: %s 36 # Read GPIO36 state\n", argv[0]);return 1;}int gpio_num = atoi(argv[1]);int h, e, value;// Open GPIO chip 4
h = lgGpiochipOpen(4);if (h < 0) {printf("ERROR: %s (%d)\n", lguErrorText(h), h);return 1;}// Set GPIO to input mode
e = lgGpioClaimInput(h, 0, gpio_num);if (e < 0) {printf("ERROR: %s (%d)\n", lguErrorText(e), e);lgGpiochipClose(h);return 1;}printf("Reading GPIO %d state (press Ctrl+C to exit)...\n", gpio_num);// Loop to read the GPIO statewhile (1) {
value = lgGpioRead(h, gpio_num);if (value < 0) {printf("ERROR: %s (%d)\n", lguErrorText(value), value);break;}printf("GPIO %d: %s\n", gpio_num, value ? "HIGH" : "LOW");sleep(1);}// Release resourceslgGpioFree(h, gpio_num);lgGpiochipClose(h);return 0;}
Compile and run¶
# Compile
gcc -o gpio_input gpio_input.c -llgpio
# Runsudo ./gpio_input 36
GPIO output feedback test¶
The following example demonstrates how to verify functionality by outputting from one pin and reading from another pin.
Example code¶
Create gpio_feedback.c file:
#include <stdio.h>#include <lgpio.h>#include <unistd.h>int main(){int h;int gpio_out = 36; // Pin3 - GPIO36int gpio_in = 37; // Pin5 - GPIO37// Open GPIO chip 4
h = lgGpiochipOpen(4);if (h < 0) {printf("ERROR: %s (%d)\n", lguErrorText(h), h);return 1;}// Set GPIO36 as output, GPIO37 as inputint e1 = lgGpioClaimOutput(h, 0, gpio_out, 0);int e2 = lgGpioClaimInput(h, 0, gpio_in);if (e1 < 0 || e2 < 0) {printf("ERROR: Failed to claim GPIO\n");lgGpiochipClose(h);return 1;}printf("=== GPIO Feedback Test ===\n");printf("Output: GPIO%d (Pin3)\n", gpio_out);printf("Input: GPIO%d (Pin5)\n", gpio_in);printf("Please connect Pin3 and Pin5 together\n\n");for (int i = 0; i < 5; i++) {// Set high levellgGpioWrite(h, gpio_out, 1);usleep(100000); // 100msint val_high = lgGpioRead(h, gpio_in);printf("Output: HIGH | Input: %s\n", val_high ? "HIGH" : "LOW");sleep(1);// Set low levellgGpioWrite(h, gpio_out, 0);usleep(100000);int val_low = lgGpioRead(h, gpio_in);printf("Output: LOW | Input: %s\n", val_low ? "HIGH" : "LOW");sleep(1);}// Release resourceslgGpioFree(h, gpio_out);lgGpioFree(h, gpio_in);lgGpiochipClose(h);printf("\nTest completed\n");return 0;}
Compile and run¶
# Compile
gcc -o gpio_feedback gpio_feedback.c -llgpio
# Run (need to short Pin3 and Pin5 first)sudo ./gpio_feedback
Expected output:
=== GPIO Feedback Test ===
Output: GPIO36 (Pin3)
Input: GPIO37 (Pin5)
Please connect Pin3 and Pin5 together
Output: HIGH | Input: HIGH
Output: LOW | Input: LOW
Output: HIGH | Input: HIGH
Output: LOW | Input: LOW
...
GPIO pin mapping¶
Quectel Pi H1 primarily uses /dev/gpiochip4 for GPIO control.
Common pin mapping¶
Physical pin |
Pin name |
GPIO number |
GPIO chip |
Default function |
|---|---|---|---|---|
Pin3 |
NFC_I2C_SDA |
36 |
/dev/gpiochip4 |
I2C09_SDA |
Pin5 |
NFC_I2C_SCL |
37 |
/dev/gpiochip4 |
I2C09_SCL |
Pin7 |
CAM2_RST |
77 |
/dev/gpiochip4 |
GPIO |
Pin11 |
GPIO_16 |
16 |
/dev/gpiochip4 |
GPIO/SPI/UART/I2C |
Pin13 |
GPIO_17 |
17 |
/dev/gpiochip4 |
GPIO/SPI/UART/I2C |
Note: Pin3 and Pin5 are configured as I2C9 interface by default. If you need to use them as GPIO, please ensure no other devices are occupying them.
For complete pin mapping, please refer to: 40-Pin expansion
lgpio API reference¶
GPIO chip operations¶
// Open GPIO chipint lgGpiochipOpen(int chip_num);// Close GPIO chipint lgGpiochipClose(int handle);
GPIO configuration¶
// Claim GPIO as output modeint lgGpioClaimOutput(int handle, int flags, int gpio, int level);// Claim GPIO as input modeint lgGpioClaimInput(int handle, int flags, int gpio);// Release GPIOint lgGpioFree(int handle, int gpio);
GPIO read/write¶
// Read GPIO levelint lgGpioRead(int handle, int gpio);// Write GPIO levelint lgGpioWrite(int handle, int gpio, int level);
PWM control¶
// Output PWM signalint lgTxPwm(int handle, int gpio, float freq, float duty, int offset, int cycles);
Common issues¶
Compilation errors¶
Issue: Cannot find lgpio.h
fatal error: lgpio.h: No such file or directory
Solution:
Confirm that lgpio library is installed
Check header file path:
ls /usr/local/include/lgpio.hIf the header file is in other path, specify the path during compilation:
gcc -I/path/to/include ...
Runtime errors¶
Issue: Permission denied
Solution:
Run the program with sudo:
sudo ./gpio_output 36 1
Issue: Cannot find shared library
error while loading shared libraries: liblgpio.so
Solution:
# Update dynamic linker cachesudo ldconfig
# Or set LD_LIBRARY_PATHexport LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
Pin occupancy issue¶
If you encounter an error indicating that the GPIO is already occupied, use the following command to check:
# View GPIO state
gpioinfo | grep -A 180 "gpiochip4" | grep -E "(line 36|line 37|consumer)"
If the pin is occupied, you need to release it first or select another unoccupied pin.