.. _driver_gpio: GPIO 驱动模型与中断接口 ############################################################ 本页依据 :doc:`/maintenance` 中记录的 Zephyr ``main`` 快照更新。 GPIO 公共接口位于 ````。应用通常在 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 与按键节点: .. code-block:: devicetree #include / { 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`` 自动转换为对应的物理高低电平。 输出控制与输入读取 ================== .. code-block:: c #include #include 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`` 或全局变量,不能是栈上临时变量): .. code-block:: c 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 上下文中执行,耗时去抖或总线操作应通过 :doc:`../kernel/workq` 延后到线程上下文处理。结合 ``zephyr,gpio-emul`` 的完整可运行中断示例见 :doc:`/tutorial/step2_gpio_and_workqueue`。 上游依据 ======== * `官方文档:hardware/peripherals/gpio `_ * `固定提交:include/zephyr/drivers/gpio.h `_