Note

This is the documentation for the latest development branch and may refer to features that are not available in released versions. If you are looking for the documentation for a specific release, use the drop-down menu on the left and select the desired version.

GPIO#

Overview#

The K230 platform provides two GPIO controllers:

  • GPIO0: Controller base address 0x9140b000, provides 32 GPIO pins (0-31)

  • GPIO1: Controller base address 0x9140c000, provides 32 GPIO pins (0-31)

Device Tree Configuration#

IO pins have multiple functions. Refer to the following to configure a certain io (via IOMUX) as GPIO function:

&iomux {
    gpio21_pins: gpio21_pins {
        pins = K230_IO21;
        function = "alt0";
    };
    gpio52_pins: gpio52_pins {
        pins = K230_IO52;
        function = "alt0";
    };
};

If already configured as gpio function under uboot, it is not necessary to configure under linux The k230_iomux.py tool can also configure the related io as gpio function

Driver usage gpio reference

// Button configuration (GPIO21)
btn {
    compatible = "gpio-keys";
    pinctrl-names = "default";
    pinctrl-0 = <&gpio21_pins>;
    status = "okay";

    btn0: btn0 {
        label = "btn";
        linux,code = <KEY_VOLUMEUP>;
        gpios = <&gpio0_ports 21 GPIO_ACTIVE_LOW>;
    };
};

// LED configuration (GPIO52)
led {
    compatible = "gpio-leds";
    pinctrl-names = "default";
    pinctrl-0 = <&gpio52_pins>;
    status = "okay";

    led0:led0 {
        label = "led";
        gpios = <&gpio1_ports 20 GPIO_ACTIVE_HIGH>;
    };
};

k230 does not enable key and led framework by default (after enabling, libgpiod cannot be used to operate the corresponding pins). The above configuration is for reference only

libgpiod2 Tool Usage#

K230 Buildroot has integrated the libgpiod2 tool by default. Usage reference is as follows:

gpioget Reading Value#

# Read a single GPIO value gpio0 (GPIO0_0) - must use -c to specify chip
gpioget -c 0 0
# Read a single GPIO value GPIO52(GPIO1_20) - must use -c to specify chip
gpioget -c 1 20

gpioset Setting Value#

## Set GPIO52(GPIO1_20) to high level
gpioset -c 1 20=1
## Set GPIO52(GPIO1_20) to low level
gpioset -c 1 20=0
# Use -t to achieve automatic toggle (LED blinking, no need to write a loop)
# Toggle every 500ms, exit after 5 toggles
gpioset -c 1 -t 500ms,500ms  20=1

gpiomon Monitoring#

gpiomon - Monitor GPIO interrupt events

# Monitor both rising and falling edges of GPIO0_10
gpiomon -e both -c 0 21

# Monitor only falling edge (button press)
gpiomon -e falling -c 0 21

# Monitor only rising edge
gpiomon -e rising -c 0 21

# Exit after monitoring 5 events
gpiomon -e falling -n 5 -c 0 21

gpiodetect#

# List all GPIO controllers in the system
gpiodetect
# List all GPIO controllers and line information (recommended)
gpioinfo

C Language Programming Examples#

LED Blinking (C Language)#

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gpiod.h>

#define LED_GPIO_CHIP_PATH "/dev/gpiochip1"
#define LED_LINE_NUM       20

// 闪烁间隔(毫秒),可通过命令行参数指定
#define DEFAULT_INTERVAL_MS 500

int main(int argc, char *argv[]) {
    struct gpiod_chip *led_chip = NULL;
    struct gpiod_line_settings *settings = NULL;
    struct gpiod_line_config *line_cfg = NULL;
    struct gpiod_request_config *req_cfg = NULL;
    struct gpiod_line_request *led_request = NULL;
    unsigned int offsets[1];
    int interval_ms = DEFAULT_INTERVAL_MS;
    int ret = EXIT_FAILURE;

    // 解析命令行参数:led_blink [间隔毫秒]
    if (argc > 1) {
        interval_ms = atoi(argv[1]);
        if (interval_ms <= 0) {
            fprintf(stderr, "无效的间隔时间: %s\n", argv[1]);
            fprintf(stderr, "用法: %s [间隔毫秒]\n", argv[0]);
            return EXIT_FAILURE;
        }
    }

    printf("LED 闪烁测试 - 间隔: %d ms\n", interval_ms);

    // 1. 打开 LED GPIO 芯片控制器
    led_chip = gpiod_chip_open(LED_GPIO_CHIP_PATH);
    if (!led_chip) {
        perror("打开 LED gpiochip 失败");
        goto cleanup;
    }

    // 2. 创建并配置引脚设置
    settings = gpiod_line_settings_new();
    if (!settings) {
        perror("创建 line settings 失败");
        goto cleanup;
    }

    // 3. 创建引脚配置
    line_cfg = gpiod_line_config_new();
    if (!line_cfg) {
        perror("创建 line config 失败");
        goto cleanup;
    }

    // 配置 LED 引脚:设置为输出,初始值为 0(熄灭)
    gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT);
    gpiod_line_settings_set_output_value(settings, 0);
    offsets[0] = LED_LINE_NUM;
    if (gpiod_line_config_add_line_settings(line_cfg, &offsets[0], 1, settings) < 0) {
        perror("配置 LED 引脚失败");
        goto cleanup;
    }

    // 4. 创建请求配置
    req_cfg = gpiod_request_config_new();
    if (!req_cfg) {
        perror("创建 request config 失败");
        goto cleanup;
    }
    gpiod_request_config_set_consumer(req_cfg, "k230_led");

    // 5. 请求 LED GPIO 引脚
    led_request = gpiod_chip_request_lines(led_chip, req_cfg, line_cfg);
    if (!led_request) {
        perror("请求 LED GPIO 引脚失败");
        goto cleanup;
    }

    printf("LED 初始化成功!开始闪烁...\n");
    printf("LED: %s:%u\n", LED_GPIO_CHIP_PATH, LED_LINE_NUM);

    // 6. 主循环:LED 闪烁
    while (1) {
        // LED 点亮
        ret = gpiod_line_request_set_value(led_request, LED_LINE_NUM, 1);
        if (ret < 0) {
            perror("写入 LED 失败");
            break;
        }
        printf("LED ON\n");
        usleep(interval_ms * 1000);

        // LED 熄灭
        ret = gpiod_line_request_set_value(led_request, LED_LINE_NUM, 0);
        if (ret < 0) {
            perror("写入 LED 失败");
            break;
        }
        printf("LED OFF\n");
        usleep(interval_ms * 1000);
    }

    ret = EXIT_SUCCESS;

cleanup:
    // 释放资源
    if (led_request) gpiod_line_request_release(led_request);
    if (req_cfg) gpiod_request_config_free(req_cfg);
    if (line_cfg) gpiod_line_config_free(line_cfg);
    if (settings) gpiod_line_settings_free(settings);
    if (led_chip) gpiod_chip_close(led_chip);

    return ret;
}

Button Event Listening (C Language)#

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gpiod.h>
#include <poll.h>

// Modify according to your K230 board pins
#define BUTTON_GPIO_CHIP_PATH "/dev/gpiochip0"
#define BUTTON_LINE_NUM       21

// Helper function to print event type
static void print_edge_event_type(unsigned int event_type) {
    switch (event_type) {
        case GPIOD_EDGE_EVENT_RISING_EDGE:
            printf("[EVENT] Button released! (Event: RISING)\n");
            break;
        case GPIOD_EDGE_EVENT_FALLING_EDGE:
            printf("[EVENT] Button pressed! (Event: FALLING)\n");
            break;
        default:
            printf("[EVENT] Unknown event type: %u\n", event_type);
            break;
    }
}

int main(void) {
    struct gpiod_chip *button_chip = NULL;
    struct gpiod_line_settings *settings = NULL;
    struct gpiod_line_config *line_cfg = NULL;
    struct gpiod_request_config *req_cfg = NULL;
    struct gpiod_line_request *button_request = NULL;
    unsigned int offsets[1];
    int ret = EXIT_FAILURE;

    // 1. Open Button GPIO chip controller
    button_chip = gpiod_chip_open(BUTTON_GPIO_CHIP_PATH);
    if (!button_chip) {
        perror("Failed to open Button gpiochip");
        goto cleanup;
    }

    // 2. Create and configure pin settings
    settings = gpiod_line_settings_new();
    if (!settings) {
        perror("Failed to create line settings");
        goto cleanup;
    }

    // 3. Create pin configuration
    line_cfg = gpiod_line_config_new();
    if (!line_cfg) {
        perror("Failed to create line config");
        goto cleanup;
    }

    // Configure Button pin: set as input
    gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT);

    // Enable both-edge interrupt detection
    gpiod_line_settings_set_edge_detection(settings, GPIOD_LINE_EDGE_BOTH);

    offsets[0] = BUTTON_LINE_NUM;
    if (gpiod_line_config_add_line_settings(line_cfg, &offsets[0], 1, settings) < 0) {
        perror("Failed to configure Button pin");
        goto cleanup;
    }

    // 4. Create request configuration
    req_cfg = gpiod_request_config_new();
    if (!req_cfg) {
        perror("Failed to create request config");
        goto cleanup;
    }
    gpiod_request_config_set_consumer(req_cfg, "k230_button_irq");

    // 5. Request Button GPIO pin
    button_request = gpiod_chip_request_lines(button_chip, req_cfg, line_cfg);
    if (!button_request) {
        perror("Failed to request Button GPIO pin");
        goto cleanup;
    }

    // 6. Initialize event buffer (to clear kernel interrupt queue)
    // Capacity of 2 is sufficient for button debouncing and accumulated edge events
    struct gpiod_edge_event_buffer *event_buf = gpiod_edge_event_buffer_new(2);
    if (!event_buf) {
        perror("Failed to create event buffer");
        goto cleanup;
    }

    // 7. Get file descriptor for poll
    int fd = gpiod_line_request_get_fd(button_request);
    if (fd < 0) {
        perror("Failed to get poll file descriptor");
        goto cleanup;
    }

    printf("K230 Button interrupt detection initialized successfully!\n");
    printf("Button: %s, Line: %u\n", BUTTON_GPIO_CHIP_PATH, BUTTON_LINE_NUM);
    printf("Start using poll to wait for button events (CPU usage very low), press Ctrl+C to exit...\n\n");

    // 8. Main loop: wait for interrupts using poll
    while (1) {
        struct pollfd pfd = {
            .fd = fd,
            .events = POLLIN,
            .revents = 0
        };

        // Block indefinitely waiting for interrupt
        int poll_ret = poll(&pfd, 1, -1);
        if (poll_ret < 0) {
            perror("poll failed");
            break;
        }

        if (!(pfd.revents & POLLIN)) continue;

        size_t num_events = gpiod_line_request_read_edge_events(button_request, event_buf, 2);
        if (num_events == 0) continue;

        for (size_t i = 0; i < num_events; i++) {
            struct gpiod_edge_event *event = gpiod_edge_event_buffer_get_event(event_buf, i);
            if (!event) continue;

            unsigned int event_type = gpiod_edge_event_get_event_type(event);
            print_edge_event_type(event_type);
        }
    }

    ret = EXIT_SUCCESS;

cleanup:
    if (event_buf) gpiod_edge_event_buffer_free(event_buf);
    if (button_request) gpiod_line_request_release(button_request);
    if (req_cfg) gpiod_request_config_free(req_cfg);
    if (line_cfg) gpiod_line_config_free(line_cfg);
    if (settings) gpiod_line_settings_free(settings);
    if (button_chip) gpiod_chip_close(button_chip);

    return ret;
}


Python Examples#

LED Example (adafruit)#

import board
from digitalio import DigitalInOut, Direction
from time import sleep

# Initialize LED
led = DigitalInOut(board.LED)
led.direction = Direction.OUTPUT

# Blink LED in loop
while True:
    led.value = 1  # Output high level, turn on built-in blue LED
    sleep(1)
    led.value = 0  # Output low level, turn off built-in blue LED
    sleep(1)

Button Example (adafruit)#

'''
Experiment: Button Event Detection
Platform: 01studio
'''

import board
import time
from digitalio import DigitalInOut, Direction, Pull

# Initialize button
key = DigitalInOut(board.KEY)  # Define pin number
key.direction = Direction.INPUT  # Set as input
key.pull = Pull.UP  # Enable pull-up resistor

# Store previous state for edge detection
prev_state = 1

print("Button event detection started. Press Ctrl+C to exit.")

while True:
    current_state = key.value

    # Detect falling edge (pressed)
    if prev_state == 1 and current_state == 0:
        print("[EVENT] Button pressed!")

    # Detect rising edge (released)
    elif prev_state == 0 and current_state == 1:
        print("[EVENT] Button released!")

    prev_state = current_state
    time.sleep(0.2)  # 10ms sleep to reduce CPU usage

LED Example (periphery)#

from periphery import GPIO
import time

# Modify the chip path and pin number according to your K230 or other board
# Assuming LED is connected to line 20 of /dev/gpiochip1
LED_CHIP_PATH = "/dev/gpiochip1"
LED_LINE_NUM = 20

try:
    # Open GPIO and configure as output mode ("out")
    # New version of python-periphery no longer supports initial_value parameter
    led = GPIO(LED_CHIP_PATH, LED_LINE_NUM, "out")

    # Manually set initial value to low (LED off)
    led.write(False)

    print(f"Successfully initialized LED pin: {LED_CHIP_PATH} [Line {LED_LINE_NUM}]")
    print("Starting LED blink, press Ctrl+C to exit...")

    while True:
        # Output high level (True), turn on LED
        # Note: If your hardware is active-low, write(True) will turn it off,
        # and write(False) will turn it on
        print("LED ON")
        led.write(True)
        time.sleep(0.9)  # Keep on for 0.5 seconds

        # Output low level (False), turn off LED
        print("LED OFF")
        led.write(False)
        time.sleep(0.9)  # Keep off for 0.5 seconds

except KeyboardInterrupt:
    print("\nProgram terminated.")
except Exception as e:
    print(f"Error occurred: {e}")
finally:
    # Release GPIO resource properly and turn off LED before exiting
    if 'led' in locals():
        led.write(False)
        led.close()
        print("LED resource released.")

Button (periphery)#

from periphery import GPIO

try:
    # Open GPIO and configure: input with pull-up
    button = GPIO("/dev/gpiochip0", 21, "in", bias="pull_up")

    # [Core Magic]: Let Linux kernel handle debouncing, set debounce time to 20ms (20000us)
    # Note: periphery's debounce parameter unit is typically microseconds (us)
    button.debounce = 20000

    # Listen for both edges
    button.edge = "both"

    print("Starting button monitoring with kernel debouncing...")

    while True:
        # Block waiting for clean interrupts filtered by kernel
        if button.poll(timeout=None):
            # Read event to reset the flag
            try:
                _ = button.read_event()
            except Exception:
                pass

            # Read and print, no more bounce issues
            val = button.read()
            print(">>> Button Pressed <<<" if val == 0 else "=== Button Released ===")

except KeyboardInterrupt:
    print("\nProgram terminated.")
except Exception as e:
    print(f"Error: {e}")
finally:
    if 'button' in locals():
        button.close()

Comments list
Comments
Log in