Linux下的gpio,gpiod

GPIO 应该是每个嵌入式设备都避免不了的。最近在做项目的时候,也遇到这方面的问题,所以简单总结一下

现在内核里面多了gpiod的来控制gpio口,相对于原来的形式,使用gpiod的好处是我们申请后不进行free也没有什么问题。但是你要是使用原来的方式后,一定要记得释放。不释放的话可能会有问题。

#旧的GPIO使用实例

DTS文件

det-gpios = <&gpio3 RK_PA6 IRQ_TYPE_EDGE_BOTH>;

驱动文件调用

    gc5025->det_pin = of_get_named_gpio_flags(node, "det-gpios", 0, &det_flags);camera_det_irq = gpio_to_irq(gc5025->det_pin);gc5025->det_value = gpio_get_value(gc5025->det_pin);/*判断注册终端*/if(camera_det_irq){if (gpio_request(gc5025->det_pin, "camera-irq-gpio")) {printk("gpio %d request failed!\n", gc5025->det_pin);gpio_free(gc5025->det_pin);return IRQ_NONE;}ret = request_irq(camera_det_irq, camera_det_irq_handler, IRQ_TYPE_EDGE_BOTH, "det-gpio", NULL);if (ret != 0) {free_irq(camera_det_irq, NULL);dev_err(dev, "Failed to request IRQ: %d\n", ret);return ret;}}

# 新的GPIOD文档

Linux 内核文档

https://www.kernel.org/doc/Documentation/gpio/consumer.txt

#头文件

我们需要包含头文件

#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_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
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_set_raw_value
gpiod_set_raw_value_can
gpiod_set_value
gpiod_set_value_canslee
gpiod_to_irq
gpiod_unexport

#获取gpio描述符和释放

使用一下两个函数获取GPIO设备,多个设备时需要附带index参数。函数返回一个GPIO描述符,或一个错误编码,可以使用IS_ERR()进行检查:

struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,enum gpiod_flags flags)struct gpio_desc *gpiod_get_index(struct device *dev,const char *con_id, unsigned int idx,enum gpiod_flags flags)

或者也可以使用如下两个函数获取可用设备:

struct gpio_desc *gpiod_get_optional(struct device *dev,const char *con_id,enum gpiod_flags flags)struct gpio_desc *gpiod_get_index_optional(struct device *dev,const char *con_id,unsigned int index,enum gpiod_flags flags)

使用如下函数同时获取多个设备:

struct gpio_descs *gpiod_get_array(struct device *dev,const char *con_id,enum gpiod_flags flags)

该函数返回一个GPIO描述结构体:

struct gpio_descs {unsigned int ndescs;struct gpio_desc *desc[];
}

一个GPIO描述符可以使用如下函数释放:

void gpiod_put(struct gpio_desc *desc)
void gpiod_put_array(struct gpio_descs *descs)

需要注意GPIO描述符被释放后不可再使用,而且不允许使用第一个函数来释放通过序列获取得到GPIO描述符。

#举个例子

#dts文件

gc5025: gc5025@37 {status = "okay";compatible = "galaxycore,gc5025";reg = <0x37>;clock-frequency = <400000>;pinctrl-names = "default";pinctrl-0 = <&cif_clkout_m0>;clocks = <&cru SCLK_CIF_OUT>;clock-names = "xvclk";avdd-supply = <&vcc2v8_dvp>;dovdd-supply = <&vcc1v8_dvp>;dvdd-supply = <&vdd1v2_dvp>;reset-gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>;pwdn-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;det-gpios = <&gpio3 RK_PA6 IRQ_TYPE_EDGE_BOTH>;rockchip,camera-module-index = <0>;rockchip,camera-module-facing = "front";rockchip,camera-module-name = "CMK-CW4191-FG1";rockchip,camera-module-lens-name = "CK5502";port {ucam_out: endpoint {remote-endpoint = <&mipi_in_ucam>;data-lanes = <1 2>;};};};

驱动文件调用:

    gc5025->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);if (IS_ERR(gc5025->reset_gpio))dev_warn(dev, "Failed to get reset-gpios\n");gc5025->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);if (IS_ERR(gc5025->pwdn_gpio))dev_warn(dev, "Failed to get pwdn-gpios\n");/*新的GPIO子系统方式,这种方式不需要手动释放资源*/gc5025->det_gpio = devm_gpiod_get(dev, "det", GPIOD_OUT_LOW);if (IS_ERR(gc5025->det_gpio))

#GPIO使用

#设置GPIO口方向

int gpiod_direction_input(struct gpio_desc *desc)
int gpiod_direction_output(struct gpio_desc *desc, int value)

#检查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);

还有一种访问必须通过消息总线比如I2C或者SPI,这种访问需要在总线访问队列中等待,所以可能进入睡眠,此类访问不能出现在IRQ handler。可以使用如下函数分辨这些设备:

int gpiod_cansleep(const struct gpio_desc *desc)

使用如下函数读写:

int gpiod_get_value_cansleep(const struct gpio_desc *desc)
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)

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

可以使用如下函数判断一个设备是否是低电平有效的设备。

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,
int *value_array)

#兼容旧版本

旧的GPIO系统使用基于标号的结构而不是基于描述符。可以使用如下两个函数进行相互转换:

int desc_to_gpio(const struct gpio_desc *desc)
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().

#举例子

    /*新的GPIO子系统方式,这种方式不需要手动释放资源*/gc5025->det_gpio = devm_gpiod_get(dev, "det", GPIOD_OUT_LOW);if (IS_ERR(gc5025->det_gpio))dev_warn(dev, "Failed to get det-gpios\n");camera_det_irq = gpiod_to_irq(gc5025->det_gpio);/*新gpio子系统转成旧gpio子系统*/gc5025->det_pin = desc_to_gpio(gc5025->det_gpio);/*读取上电gpio电平*/gc5025->det_value = gpio_get_value(gc5025->det_pin);/*判断注册终端*/if(camera_det_irq){ret = request_irq(camera_det_irq, camera_det_irq_handler, IRQ_TYPE_EDGE_BOTH, "det-gpio", NULL);if (ret != 0) {free_irq(camera_det_irq, NULL);dev_err(dev, "Failed to request IRQ: %d\n", ret);return ret;}}

#调试

移植驱动阶段或者调试阶段的工程中,难免想知道当前gpio的电平状态。当然很easy。万用表戳上去不就行了。是啊!硬件工程师的思维。作为软件工程师自然是要软件的方法。下面介绍两个api接口。自己摸索使用吧。点到为止。

static inline int gpio_export(unsigned gpio, bool direction_may_change);
static inline int gpio_export_link(struct device *dev, const char *name, unsigned gpio);

在你的driver中调用以上api后,编译下载。去/sys/class/gpio目录看看有什么发现。

  回复「 篮球的大肚子」进入技术群聊

回复「1024」获取1000G学习资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

剖析大神代码,计算整型里面1的个数

昨天的文章&#xff0c;可能很多人看了不知道怎么回事&#xff0c;确实&#xff0c;我也是看了之后一头雾水。先给出个简单的例子#include "stdio.h"int count_bits4(char x) {x (x&0x55) ((x>>1)&0x55);x (x&0x33) ((x>>2)&0x33);x…

android 复制u盘文件到手机本地_如何导出Android中的文件(把Android当做U盘)

方法一&#xff1a;1. 连接USB,插入电脑2.用手在手机上方往下滑动&#xff0c;会出现几个菜单&#xff0c;其中有一个"choose a connection type". 选择 Disk Drive.你看到的也许是&#xff0c;Charge only, 点击切换到Disk Drive.3.这时你的电脑上就会出现USB标志的…

机器学习导论 与数学分析

文章目录机器学习定义说人话例子专家系统 定义好&#xff0c; 应招&#xff0c;速度快机器学习 实验 奖惩 调参对象任务 TASK T一个或多个经验 EXPERIENCE性能PERFORMANCE类比人类学习监督学习半监督学习无监督学习增强学习可解决问题不可解决问题举例f&#xff08;x&#xff0…

聊聊、Highcharts 动态数据

最近项目中需要用到图表&#xff0c;找了几个开源框架&#xff0c;最后选择 Highcharts&#xff0c;原因是 Highcharts 功能强大&#xff0c;稳定&#xff0c;方便&#xff0c;而且开源&#xff0c;社区比较成熟。 首先下载 Highcharts&#xff0c;导入项目。 在 HTML 页面引入…

你知道用git打补丁吗?

#常规操作一个常规的使用git 生成补丁的方式git diff ./ > xxx.patch patch -p1 < xxx.patch但是这样生成的补丁有一个问题&#xff0c;这个是差分形式的diff --git a/kernel-4.4/drivers/input/touchscreen/goodix.c b/kernel-4.4/drivers/input/touchscreen/goodix.c i…

windows 禁用ipv6服务_Win10如何关闭IPV6?Win10禁用IPv6的方法

在Win10系统中默认开启IPV6&#xff0c;不过这个协议暂时我们还用不到。而且开启该协议有时对系统运行有一定的影响&#xff0c;一些网卡还会因为IPv6出现系统未响应&#xff0c;假死等情况&#xff0c;那么Win10系统怎么关闭IPV6&#xff1f;下面小编就给大家带来Win10禁用IPv…

概率论与贝叶斯先验

文章目录概率论与贝叶斯先验概率论基础问题代码图像本福特定律应用&#xff1a;公路堵车模型代码模型初速不同&#xff1a;影响不大减速概率&#xff1a;影响大应用&#xff1a;商品推荐解答概率公式应用样本贝叶斯公式分布两点分布二项分布泊松分布期望和方差表示强度应用均匀…

vue项目导入外部css样式和js文件

转自&#xff1a;http://blog.csdn.net/xiejunna/article/details/54943957 css文件放入static文件夹下。 转载于:https://www.cnblogs.com/ourLifes/p/7444074.html

Linux内核0.12完全注释

推荐一本书 Linux 0.12内核完全注释 先把麻雀解剖了&#xff0c;再去研究老鹰和飞机可能会更好。现在市面的很多书籍都是基于比较新的内核讲解的&#xff0c;2.6的内核或者4.4的内核&#xff0c;因为内核版本越高&#xff0c;里面的东西就越多&#xff0c;想要讲解明白就需要花…

iangularjs 模板,AngularJS模板中的三元运算符

How do you do a ternary with AngularJS (in the templates)?It would be nice to use some in html attributes (classes and style) instead of creating and calling a function of the controller.解决方案Update: Angular 1.1.5 added a ternary operator, so now we ca…

矩阵和线性代数

文章目录矩阵和线性代数矩阵SVD提法举例推导代码分解效果方阵行列式范德蒙行列式作用代数余子式伴随矩阵方阵的逆矩阵乘法模型举例概率转移矩阵平稳分布&#xff1a;向量乘法矩阵的秩秩与方程组的解推论向量组等价系数矩阵对CAB重认识正交阵特征值和特征向量性质不同特征值对应…

对比一段ADC键值读取的代码

最近接触到的一个代码&#xff0c;这个代码看起来很简单&#xff0c;但是却蕴藏了人类的智慧与结晶。正是这些不断产生的智慧与结晶&#xff0c;让我们的电子产品越来越稳定&#xff0c;越来越智能。周五了&#xff0c;评论文章&#xff0c;选两个同学赠送书籍《Linux内核完全剖…

HTML5权威指南 11.通信API

1 <!DOCTYPE html>2 <html>3 4 <head>5 <meta charset"UTF-8">6 <title></title>7 <script type"text/javascript">8 //&#xff08;1&#xff09;监听message事件9 window.addEve…

在线登记系统代码 php_PHP框架实现WebSocket在线聊天通讯系统

ThinkPHP使用Swoole需要安装think-swooleComposer包&#xff0c;前提系统已经安装好了SwoolePECL拓展tp5的项目根目录下执行composer命令安装think-swoole&#xff1a;composerrequiretopthink/think-swoole话不多说&#xff0c;直接上代码&#xff1a;新建WebSocket.php控制器…

Java:抽象类笔记

抽象类&#xff1a;类中没有包含足够的信息来描绘一个具体的对象。 为什么要创建抽象类&#xff1f; 为了更好的继承&#xff0c;以后能更好的扩展&#xff0c;减少类与类之间的耦合。 什么时候需要创建一个抽象类&#xff1f; &#xff08;简单粗暴的理解&#xff09;某个方法…

ios触摸超出_iOS开发笔记之多点触控(一)处理触摸的4个方法

多点触控乃苹果公司带给世界的创新之首&#xff0c;作为移动开发者&#xff0c;熟练掌握多点触控开发技能很有必要。处理触摸的四个方法&#xff1a;-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event //首次在屏幕上检测到触摸时调用{NSLog("touchesBega…

机器学习数据包之numpy

numpy 属性 import numpy as np#矩阵运算arraynp.array([[1,2,3],[2,3,4]])print (array)[[1 2 3][2 3 4]]维度 print(number of dim,array.ndim)number of dim 2形状 print(shape,array.shape)shape (2, 3)大小 print(size,array.size)size 6创建 创建类型 anp.array([…

RK 利用SARADC 来做多个按键

#DTS配置#配置DTS节点#驱动文件中匹配 DTS 节点#驱动说明#获取ADC通道#获取ADC值#计算采集到的电压#接口说明#调试方法#节点ADC值RK3399开发板上的 AD 接口有两种&#xff0c;分别为&#xff1a;温度传感器 (Temperature Sensor)、逐次逼近ADC (Successive Approximation Regis…

vslabel隐藏了怎么找_vscode菜单栏与工具栏隐藏之后怎么找回来

vscode菜单栏与工具栏隐藏之后怎么找回来,命令行,菜单栏,教程,相关文章,设置为vscode菜单栏与工具栏隐藏之后怎么找回来易采站长站&#xff0c;站长之家为您整理了vscode菜单栏与工具栏隐藏之后怎么找回来的相关内容。找回菜单栏1、按alt可以显示菜单栏&#xff1b;2、可以在命…

概率论之pandas

快速入门 1 import numpy as npspd.series([1,3,5,np.nan,8,4])Series spd.Series([1,3,5,np.nan,8,4])sOut[6]: 0 1.01 3.02 5.03 NaN4 8.05 4.0dtype: float64date_range datespd.date_range(20190301,periods6)datesOut[10]: DatetimeIndex([2019-03-…