本文简要介绍zephyr GPIO的驱动logic level的原理和实现
Zephyr大约在2019年底merge了对disk_access_usdhc.c的改写,其中detect gpio使用了gpio logic level,由于mm_swiftio的dts还是沿用原来的无logic level设置,导致检测卡失败。借此契机顺便分析了一下gpio logic level的实现机制。
原理
一般情况下我们将0当做gpio的低电平,1当做gpio的高电平,这是物理世界的对应。在软件上由于逻辑实现上的可移植或是代码的易读性我们会引入logic level。例如对于A型的SD Card检测电路,被设计插卡后detect GPIO低电平, 而对于B型的SD Card检测电路,被设计插卡后detect GPIO高电平,反映到软件流程上将会对于不同的gpio level判断。
但对于插卡检测的软件来说,只希望得到的是gpio反映卡有插入或者没有插入。于是zephyr gpio引入了gpio logic level的做法,针对具体的某一个gpio可以被配置为logic level 1是对应物理的低电平或者是物理高电平,这样对于插卡检测软件来说只需要检测到逻辑电平为高就可以判断是有卡插入。
使用
在gpio.h中用下面两个宏flag表示logic 1对应的物理电平
1 | #define GPIO_ACTIVE_LOW (1 << 0) |
当gpio_config(struct device *port, gpio_pin_t pin, gpio_flags_t flags);通过flags设置logic level的模式
包含GPIO_ACTIVE_LOW 时:gpio上出现低电平时表示逻辑1
gpio level | gpio logic level |
---|---|
0 | 1 |
1 | 0 |
包含GPIO_ACTIVE_HIGH 时:gpio上出现高电平时表示逻辑1
gpio level | gpio logic level |
---|---|
0 | 0 |
1 | 1 |
配置logic level完成后,gpio_port_get,gpio_pin_get读出的就是逻辑电平。
通过gpio_port_clear_bits,gpio_port_set_bits,gpio_port_set_clr_bits,gpio_port_set_masked写入逻辑电平。
gpio也有下面的api直接读写物理电平:
gpio_pin_get_raw,gpio_port_get_raw,gpio_pin_set_raw,gpio_port_clear_bits_raw,gpio_port_set_bits_raw,gpio_port_set_clr_bits_raw,gpio_port_set_masked_raw
对于中断level来说定义有flag
1 | #define GPIO_INT_LEVELS_LOGICAL (1U << 15) |
当gpio_pin_interrupt_configure传入的flags中有GPIO_INT_LEVELS_LOGICAL,时,中断配置时会将传入的高低电平触发做为逻辑电平处理。
注:如果在gpio_config时GPIO_ACTIVE_LOW 和GPIO_ACTIVE_HIGH都没设置,将会使用GPIO_ACTIVE_HIGH,也就是物理电平和逻辑电平一致。
实现
配置时
只要flags当中带有GPIO_ACTIVE_LOW,所以低物理电平对应高逻辑电平,两者是取反的关系,关键代码如下
1 | static inline int gpio_pin_configure(struct device *port, gpio_pin_t pin, |
读
gpio_pin_get其实就是包装gpio_port_get,这里只分析gpio_port_get
1 | static inline int gpio_port_get(struct device *port, gpio_port_value_t *value) |
写
写逻辑电平的api都是包装gpio_port_set_masked和gpio_pin_set,只分析这两个API的代码
1 | static inline int gpio_pin_set(struct device *port, gpio_pin_t pin, int value) |
中断配置
只摘取逻辑电平相关的代码
1 | static inline int z_impl_gpio_pin_interrupt_configure(struct device *port, |