GPIO 驱动模型与中断接口
本页依据 文档基线与后续更新 中记录的 Zephyr main 快照更新。
GPIO 公共接口位于 <zephyr/drivers/gpio.h>。应用通常在 Devicetree 中使用
gpio-leds 或 gpio-keys 绑定描述引脚与极性,并在 C 代码中通过
struct gpio_dt_spec 和 *_dt 系列函数访问引脚。
配置与设备树描述
启用 CONFIG_GPIO=y 以及目标平台对应的控制器驱动(在 QEMU 仿真环境中可启用
CONFIG_GPIO_EMUL=y 并使用 zephyr,gpio-emul)。
在设备树或 app.overlay 中定义 LED 与按键节点:
#include <zephyr/dt-bindings/gpio/gpio.h>
/ {
aliases {
led0 = &status_led;
sw0 = &user_key;
};
leds {
compatible = "gpio-leds";
status_led: led_0 {
gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
};
};
buttons {
compatible = "gpio-keys";
user_key: button_0 {
gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
};
};
};
GPIO_ACTIVE_LOW 与 GPIO_ACTIVE_HIGH 定义引脚的**逻辑有效电平(Active Level)**。
使用 gpio_pin_set_dt(&spec, 1) 时,1 始终表示“设为逻辑有效状态”,驱动内部会根据
dt_flags 自动转换为对应的物理高低电平。
输出控制与输入读取
#include <zephyr/drivers/gpio.h>
#include <errno.h>
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static const struct gpio_dt_spec key = GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios);
int io_init_and_poll(void)
{
int ret;
if (!gpio_is_ready_dt(&led) || !gpio_is_ready_dt(&key)) {
return -ENODEV;
}
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE);
if (ret != 0) {
return ret;
}
ret = gpio_pin_configure_dt(&key, GPIO_INPUT);
if (ret != 0) {
return ret;
}
/* 读取按键逻辑状态:1 表示按下(有效),0 表示未按下 */
int pressed = gpio_pin_get_dt(&key);
if (pressed > 0) {
gpio_pin_toggle_dt(&led);
}
return 0;
}
中断回调配置
GPIO 中断通过 struct gpio_callback 注册。该结构体必须在中断启用期间保持有效(通常声明为
static 或全局变量,不能是栈上临时变量):
static struct gpio_callback key_cb_data;
static void key_isr(const struct device *port, struct gpio_callback *cb,
gpio_port_pins_t pins)
{
ARG_UNUSED(port);
ARG_UNUSED(cb);
ARG_UNUSED(pins);
/* 运行在 ISR 上下文:仅执行非阻塞操作或提交 k_work */
}
int key_interrupt_enable(void)
{
int ret = gpio_pin_interrupt_configure_dt(&key, GPIO_INT_EDGE_TO_ACTIVE);
if (ret != 0) {
return ret;
}
gpio_init_callback(&key_cb_data, key_isr, BIT(key.pin));
return gpio_add_callback_dt(&key, &key_cb_data);
}
GPIO_INT_EDGE_TO_ACTIVE/GPIO_INT_EDGE_TO_INACTIVE基于逻辑有效状态触发,推荐搭配gpio_dt_spec使用。GPIO_INT_EDGE_RISING/GPIO_INT_EDGE_FALLING基于物理电平跳变触发。中断回调在 ISR 上下文中执行,耗时去抖或总线操作应通过 工作队列 延后到线程上下文处理。结合
zephyr,gpio-emul的完整可运行中断示例见 实战二:外设中断与下半部处理——GPIO 仿真、按键中断与工作队列。