C/C++ GPIO Development

lgpio Introduction

lgpio is a GPIO control library for Linux systems, providing a simple and easy-to-use C language interface 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 library interface

Supported Features

Feature Description
GPIO General purpose input/output control
I2C I²C bus communication
SPI SPI bus communication
PWM Pulse width modulation output
Notify GPIO interrupts and event notifications

Installing lgpio

Install from Source

# Install dependency tools
apt update
apt install -y git build-essential

# Clone lgpio source code
git clone https://github.com/joan2937/lg.git
cd lg

# Compile and install
make
make install

# Update dynamic library 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 exist
ls -l /usr/local/lib/liblgpio.*

# Check if header files exist
ls -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 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 level
    int 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)");

    // Maintain state for 5 seconds
    sleep(5);

    // Release GPIO resources
    lgGpioFree(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 GPIO pin status.

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 GPIO status
    while (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 resources
    lgGpioFree(h, gpio_num);
    lgGpiochipClose(h);

    return 0;
}

Compile and Run

# Compile
gcc -o gpio_input gpio_input.c -llgpio

# Run
sudo ./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 - GPIO36
    int 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 input
    int 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 level
        lgGpioWrite(h, gpio_out, 1);
        usleep(100000);  // 100ms
        int val_high = lgGpioRead(h, gpio_in);
        printf("Output: HIGH | Input: %s\n", val_high ? "HIGH" : "LOW");

        sleep(1);

        // Set low level
        lgGpioWrite(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 resources
    lgGpioFree(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: 40Pin Function Testing

lgpio API Reference

GPIO Chip Operations

// Open GPIO chip
int lgGpiochipOpen(int chip_num);

// Close GPIO chip
int lgGpiochipClose(int handle);

GPIO Configuration

// Claim GPIO as output mode
int lgGpioClaimOutput(int handle, int flags, int gpio, int level);

// Claim GPIO as input mode
int lgGpioClaimInput(int handle, int flags, int gpio);

// Release GPIO
int lgGpioFree(int handle, int gpio);

GPIO Read/Write

// Read GPIO level
int lgGpioRead(int handle, int gpio);

// Write GPIO level
int lgGpioWrite(int handle, int gpio, int level);

PWM Control

// Output PWM signal
int 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 lgpio library is installed
  2. Check header file path: ls /usr/local/include/lgpio.h
  3. If in other path, specify during compilation: gcc -I/path/to/include ...

Runtime Errors

Issue: Permission denied

Solution:
Run program with sudo:

sudo ./gpio_output 36 1

Issue: Cannot find shared library

error while loading shared libraries: liblgpio.so

Solution:

# Update dynamic library cache
sudo ldconfig

# Or set LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

Pin Occupied Issue

If you encounter GPIO already occupied error, use the following command to check:

# View GPIO status
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