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:

  1. Confirm that lgpio library is installed

  2. Check header file path: ls /usr/local/include/lgpio.h

  3. If 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.

Reference resources