GPIO 应该是每个嵌入式设备都避免不了的。最近在做项目的时候,也遇到这方面的问题,所以简单总结一下:现在内核里面多了gpiod的来控制gpio口,相对于原来的形式,使用gpiod的好处是我们申请后不进行free也没有什么问题。但是你要是使用原来的方式后,一定要记得释放。不释放的话可能会有问题。
#旧的GPIO使用实例
DTS文件
驱动文件调用
# 新的GPIOD文档
#头文件
我们需要包含头文件
#include <linux/gpio/consumer.h>
看头文件里面包含的函数列表
desc_to_gpio
devm_get_gpiod_from_chi
devm_gpiod_get
devm_gpiod_get_array
devm_gpiod_get_array_op
devm_gpiod_get_index
devm_gpiod_get_index_op
devm_gpiod_get_optional
devm_get_gpiod_from_chi
devm_gpiod_get
devm_gpiod_get_array
devm_gpiod_get_array_op
devm_gpiod_get_index
devm_gpiod_get_index_op
devm_gpiod_get_optional
devm_gpiod_put
devm_gpiod_put_array
fwnode_get_named_gpiod
gpio_to_desc
gpiod_cansleep
gpiod_count
gpiod_direction_input
gpiod_direction_output
gpiod_direction_output_
gpiod_export
gpiod_export_link
gpiod_get
gpiod_get_array
gpiod_get_array_optiona
gpiod_get_direction
devm_gpiod_put_array
fwnode_get_named_gpiod
gpio_to_desc
gpiod_cansleep
gpiod_count
gpiod_direction_input
gpiod_direction_output
gpiod_direction_output_
gpiod_export
gpiod_export_link
gpiod_get
gpiod_get_array
gpiod_get_array_optiona
gpiod_get_direction
gpiod_get_index
gpiod_get_index_optiona
gpiod_get_optional
gpiod_get_raw_value
gpiod_get_raw_value_can
gpiod_get_value
gpiod_get_value_canslee
gpiod_is_active_low
gpiod_put
gpiod_put_array
gpiod_set_array_value
gpiod_set_array_value_c
gpiod_set_debounce
gpiod_set_raw_array_val
gpiod_set_raw_array_val
gpiod_get_index_optiona
gpiod_get_optional
gpiod_get_raw_value
gpiod_get_raw_value_can
gpiod_get_value
gpiod_get_value_canslee
gpiod_is_active_low
gpiod_put
gpiod_put_array
gpiod_set_array_value
gpiod_set_array_value_c
gpiod_set_debounce
gpiod_set_raw_array_val
gpiod_set_raw_array_val
gpiod_set_raw_value
gpiod_set_raw_value_can
gpiod_set_value
gpiod_set_value_canslee
gpiod_to_irq
gpiod_unexport
gpiod_set_raw_value_can
gpiod_set_value
gpiod_set_value_canslee
gpiod_to_irq
gpiod_unexport
#获取gpio描述符和释放
使用一下两个函数获取GPIO设备,多个设备时需要附带index参数。函数返回一个GPIO描述符,或一个错误编码,可以使用IS_ERR()进行检查:
或者也可以使用如下两个函数获取可用设备:
使用如下函数同时获取多个设备:
该函数返回一个GPIO描述结构体:
一个GPIO描述符可以使用如下函数释放:
需要注意GPIO描述符被释放后不可再使用,而且不允许使用第一个函数来释放通过序列获取得到GPIO描述符。
#举个例子
#dts文件
驱动文件调用:
#GPIO使用
#设置GPIO口方向
#检查GPIO口是方向
int gpiod_get_direction(const struct gpio_desc *desc)
函数返回GPIOF_DIR_IN或者GPIOF_DIR_OUT
#读取GPIO口电平
访问分为两种,一种是通过储存器读写实现的,这种操作属于原子操作,不需要等待,所以可以在中断处理程序中使用:
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
void gpiod_set_value(struct gpio_desc *desc, int value);
还有一种访问必须通过消息总线比如I2C或者SPI,这种访问需要在总线访问队列中等待,所以可能进入睡眠,此类访问不能出现在IRQ handler。可以使用如下函数分辨这些设备:
int gpiod_cansleep(const struct gpio_desc *desc)
使用如下函数读写:
linux下的sleep函数int gpiod_get_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
#active-low和raw-value
active-low & raw value有些设备采用低电平有效的方式输出逻辑信号。此时低电平输出1,高电平输出0。此时可以通过访问raw_value的方式来访问实际电路上的值,与逻辑处理无关:假设我们在DTS里面这样设置
reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;
然后我们这样调用
gpiod_set_value_cansleep(gc5025->reset_gpio, 1);
因为DTS里面的active 状态是 GPIO_ACTIVE_LOW,所以这个代码输出的是 低电平
gpiod_set_value_cansleep(gc5025->reset_gpio, 0);
输出的是高电平
这几个函数如下:
int gpiod_get_raw_value(const struct gpio_desc *desc)
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
raw-value 的意思就是不在乎DTS里面的ACTIVE,我set 高电平,就是高电平。逻辑关系汇总如下:
Function (example) active-low property physical line
gpiod_set_raw_value(desc, 0); don’t care low
gpiod_set_raw_value(desc, 1); don’t care high
gpiod_set_value(desc, 0); default (active-high) low
gpiod_set_value(desc, 1); default (active-high) high
gpiod_set_value(desc, 0); active-low high
gpiod_set_value(desc, 1); active-low low
gpiod_set_raw_value(desc, 0); don’t care low
gpiod_set_raw_value(desc, 1); don’t care high
gpiod_set_value(desc, 0); default (active-high) low
gpiod_set_value(desc, 1); default (active-high) high
gpiod_set_value(desc, 0); active-low high
gpiod_set_value(desc, 1); active-low low
可以使用如下函数判断一个设备是否是低电平有效的设备。
int gpiod_is_active_low(const struct gpio_desc *desc)
#设置多个输出
这个没使用过 使用如下函数设置一组设备的输出值
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
#兼容旧版本
旧的GPIO系统使用基于标号的结构而不是基于描述符。可以使用如下两个函数进行相互转换:
int desc_to_gpio(const struct gpio_desc *desc)
struct gpio_desc *gpio_to_desc(unsigned gpio)
struct gpio_desc *gpio_to_desc(unsigned gpio)
注意不能使用一套API的方法释放另一套API获取的设备
#和中断IRQ相关
使用如下函数获取一个GPIO设备对应的IRQ中断号
int gpiod_to_irq(const struct gpio_desc *desc)
返回值时一个IRQ number,或者一个负数的错误代码。得到的中断号可以传递给函数request_irq(),free_irq().
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论