完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。 所有的 GPIO 在上电后的初始状态都是输入模式,可以通过软件设为上拉或下拉,也可以设置为中断脚,驱动强度都是可编程的,其核心是填充 GPIO bank 的方法和参数,并调用 gpiochip_add 注册到内核中。
本文以 GPIO0_B4 和 GPIO4_D5 这两个 GPIO 口为例写了一份简单操作 GPIO 口的驱动,以下就以该驱动为例介绍 GPIO 的操作。 常用的 GPIO API 定义 #include #include enum of_gpio_flags { OF_GPIO_ACTIVE_LOW = 0x1, }; int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags); int gpio_is_valid(int gpio); int gpio_request(unsigned gpio, const char *label); void gpio_free(unsigned gpio); int gpio_direction_input(int gpio); int gpio_direction_output(int gpio, int v); GPIO引脚计算 RK3568 有 5 组 GPIO bank:GPIO0~GPIO4,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分,常用以下公式计算引脚: GPIO pin脚计算公式:pin = bank * 32 + number GPIO 小组编号计算公式:number = group * 8 + X 下面演示GPIO4_D5 pin脚计算方法: bank = 4; //GPIO4_D5 => 4, bank ∈ [0,4] group = 3; //GPIO4_D5 => 3, group ∈ {(A=0), (B=1), (C=2), (D=3)} X = 5; //GPIO4_D5 => 5, X ∈ [0,7] number = group * 8 + X = 3 * 8 + 5 = 29 pin = bank*32 + number= 4 * 32 + 29 = 157; GPIO4_D5 对应的设备树属性描述为:<&gpio4 29 IRQ_TYPE_EDGE_RISING>,由kernel/include/dt-bindings/pinctrl/rockchip.h的宏定义可知,也可以将GPIO4_D5描述为<&gpio4 RK_PD5 IRQ_TYPE_EDGE_RISING>。 // kernel/include/dt-bindings/pinctrl/rockchip.h #define RK_PA0 0 #define RK_PA1 1 #define RK_PA2 2 #define RK_PA3 3 #define RK_PA4 4 #define RK_PA5 5 #define RK_PA6 6 #define RK_PA7 7 #define RK_PB0 8 #define RK_PB1 9 #define RK_PB2 10 #define RK_PB3 11 ...... 当GPIO4_D5脚没有被其它外设复用时, 我们可以通过export导出该引脚去使用 :/ # ls /sys/class/gpio/ export gpiochip128 gpiochip32 gpiochip64 unexport gpiochip0 gpiochip255 gpiochip500 gpiochip96 :/ # echo 157 > /sys/class/gpio/export :/ # ls /sys/class/gpio/ export gpiochip0 gpiochip255 gpiochip500 gpiochip96 gpio157 gpiochip128 gpiochip32 gpiochip64 unexport :/ # ls /sys/class/gpio/gpio157 active_low device direction edge power subsystem uevent value :/ # cat /sys/class/gpio/gpio157/direction in :/ # cat /sys/class/gpio/gpio157/value 0 DTS配置 首先在 DTS 文件中增加驱动的资源描述: kernel/arch/arm64/boot/dts/rockchip/rk356x-demo.dtsi gpio_demo: gpio_demo { status = "okay"; compatible = "demo,rk356x-gpio"; demo-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; /* GPIO0_B4 */ demo-irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>; /* GPIO4_D5 */ }; 这里定义了一个脚作为一般的输出输入口:demo-gpio GPIO0_B4 , 定义了一个脚作为中断,其中 GPIO_ACTIVE_HIGH 表示高电平有效,如果想要低电平有效,可以改为:GPIO_ACTIVE_LOW,而 IRQ_TYPE_EDGE_FALLING和IRQ_TYPE_EDGE_RISING:用于边沿触发方式的中断,指示上升沿还是下降沿, IRQ_TYPE_LOW和IRQ_TYPE_HIGH:用于电平触发方式的中断,指示中断是高电平还是低电平;这个属性将被驱动所读取。 然后在 probe 函数中对 DTS 所添加的资源进行解析,代码如下: static int demo_gpio_probe(struct platform_device *pdev) { int ret; int gpio; enum of_gpio_flags flag; struct demo_gpio_info *gpio_info; struct device_node *demo_gpio_node = pdev->dev.of_node; printk("demo GPIO Test Program Proben"); gpio_info = devm_kzalloc(&pdev->dev,sizeof(struct demo_gpio_info *), GFP_KERNEL); if (!gpio_info) { return -ENOMEM; } gpio = of_get_named_gpio_flags(demo_gpio_node, "demo-gpio", 0, &flag); if (!gpio_is_valid(gpio)) { printk("demo-gpio: %d is invalidn", gpio); return -ENODEV; } if (gpio_request(gpio, "demo-gpio")) { printk("gpio %d request failed!n", gpio); gpio_free(gpio); return -ENODEV; } gpio_info->demo_gpio = gpio; gpio_info->gpio_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0:1; gpio_direction_output(gpio_info->demo_gpio, gpio_info->gpio_enable_value); printk("demo gpio putoutn"); ... } of_get_named_gpio_flags 从设备树中读取 demo-gpio 和 demo-irq-gpio 的 GPIO 配置编号和标志,gpio_is_valid 判断该 GPIO 编号是否有效,gpio_request 则申请占用该 GPIO。如果初始化过程出错,需要调用 gpio_free 来释放之前申请过且成功的 GPIO 。在驱动中调用 gpio_direction_output 就可以设置输出高还是低电平,这里默认输出从 DTSI 获取得到的有效电平 GPIO_ACTIVE_HIGH,即为高电平,如果驱动正常工作,可以用万用表测得对应的引脚应该为高电平。实际中如果要读出 GPIO,需要先设置成输入模式,然后再读取值 int val; gpio_direction_input(gpio); val = gpio_get_value(gpio); 中断 在示例程序中还包含了一个中断引脚,GPIO 口的中断使用与 GPIO 的输入输出类似,首先在 DTS 文件中增加驱动的资源描述: kernel/arch/arm64/boot/dts/rockchip/rk356x-demo.dtsi gpio { compatible = "demo-gpio"; demo-irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>; /* GPIO4_D5 */ }; IRQ_TYPE_EDGE_RISING 表示中断由上升沿触发,当该引脚接收到上升沿信号时可以触发中断函数。 这里还可以配置成如下: IRQ_TYPE_NONE //默认值,无定义中断触发类型 IRQ_TYPE_EDGE_RISING //上升沿触发 IRQ_TYPE_EDGE_FALLING //下降沿触发 IRQ_TYPE_EDGE_BOTH //上升沿和下降沿都触发 IRQ_TYPE_LEVEL_HIGH //高电平触发 IRQ_TYPE_LEVEL_LOW //低电平触发 然后在 .probe 函数中对 DTS 所添加的资源进行解析,再做中断的注册申请,代码如下: static irqreturn_t demo_gpio_irq(int irq, void *dev_id) //中断函数 { printk("Enter demo gpio irq test program!n"); return IRQ_HANDLED; } static int demo_gpio_probe(struct platform_device *pdev) { int ret; int gpio; enum of_gpio_flags flag; struct demo_gpio_info *gpio_info; struct device_node *demo_gpio_node = pdev->dev.of_node; ... gpio_info->demo_irq_gpio = gpio; gpio_info->demo_irq_mode = flag; gpio_info->demo_irq = gpio_to_irq(gpio_info->demo_irq_gpio); if (gpio_info->demo_irq) { if (gpio_request(gpio, "demo-irq-gpio")) { printk("gpio %d request failed!n", gpio); gpio_free(gpio); return IRQ_NONE; } ret = request_irq(gpio_info->demo_irq, demo_gpio_irq, flag, "demo-gpio", gpio_info); if (ret != 0) free_irq(gpio_info->demo_irq, gpio_info); dev_err(&pdev->dev, "Failed to request IRQ: %dn", ret); } return 0; } 调用 gpio_to_irq 把 GPIO 的 PIN 值转换为相应的 IRQ 值,调用 gpio_request 申请占用该 IO 口,调用 request_irq 申请中断,如果失败要调用 free_irq 释放,该函数中 gpio_info-demo_irq 是要申请的硬件中断号,demo_gpio_irq 是中断函数,gpio_info->demo_irq_mode 是中断处理的属性,demo-gpio 是设备驱动程序名称,gpio_info 是该设备的 device 结构,在注册共享中断时会用到。 GPIO复用 GPIO 口除了通用输入输出、中断功能外,还可能有其它复用功能,如GPIO0_B4, 就有如下几个功能: 那么在使用作GPIO口时,就需要注意是否被复用为其他功能了,这里可以用io命令查看iomux来判断是否复用,假如通过io命令发现GPIO0_B4有复用作I2C1_SDA,使用GPIO0_B4作gpio或者其他功能时就需要将I2C1 disabled掉。 &i2c1 { status = "disabled"; }; gpio_demo: gpio_demo { status = "okay"; compatible = "demo,rk356x-gpio"; demo-gpio = <&gpio0 12 GPIO_ACTIVE_HIGH>; /* GPIO0_B4 */ demo-irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>; /* GPIO4_D5 */ }; // Note: 此处GPIO0_B4仅作示例,实际使用中不推荐如此修改 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
569 浏览 0 评论
839 浏览 1 评论
737 浏览 1 评论
1957 浏览 1 评论
3204 浏览 1 评论
浏览过的版块 |
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 06:54 , Processed in 0.591929 second(s), Total 71, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号