RK3288开发板GPIO介绍
简介
GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。
RK3288 有 9 组 GPIO bank: GPIO0,GPIO1, ..., GPIO8。每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分(不是所有 bank 都有全部编号,例如 GPIO5 就只有 B0~B7, C0~C3)。
每个 GPIO 口除了通用输入输出功能外,还可能有其它复用功能,例如 GPIO5_B4,可以复用成以下功能之一:
- spi0_clk
- ts0_data4
- uart4exp_ctsn
每个 GPIO 口的驱动电流、上下拉和重置后的初始状态都不尽相同,详细情况请参考《RK3288 规格书》中的 "RK3288 function IO description" 一章。
RK3288 的 GPIO 驱动是在以下 pinctrl 文件中实现的:
kernel/drivers/pinctrl/pinctrl-rockchip.c
其核心是填充 GPIO bank 的方法和参数,并调用 gpiochip_add 注册到内核中。
使用
开发板有两个电源 LED 灯是 GPIO 口控制的,分别是:
从电路图上看,GPIO 口输出低电平时灯亮,高电平时灯灭。
另外,扩展槽上引出了几个空闲的 GPIO 口,分别是:
这几个 GPIO 口可以自定义作输入、输出使用。
输入输出
下面以电源 LED 灯的驱动为例,讲述如何在内核编写代码控制 GPIO 口的输出。
首先需要在 dts (Device Tree) 文件 firefly-rk3288.dts (0930版) 或 firefly-rk3288_beta.dts (0809版) 中增加驱动的资源描述:
firefly-led{
compatible = "firefly,led";
led-work = <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
led-power = <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
status = "okay";
};
这里定义了两颗 LED 灯的 GPIO 设置:
led-work GPIO8_A2 GPIO_ACTIVE_LOW led-power GPIO8_A1 GPIO_ACTIVE_LOW
GPIO_ACTIVE_LOW 表示低电平有效(灯亮),如果是高电平有效,需要替换为 GPIO_ACTIVE_HIGH 。
之后在驱动程序中加入对 GPIO 口的申请和控制则可:
#ifdef CONFIG_OF #include <linux/of.h> #include <linux/of_gpio.h> #endifstatic int firefly_led_probe(struct platform_device *pdev) {int ret = -1;int gpio, flag;struct device_node *led_node = pdev->dev.of_node;gpio = of_get_named_gpio_flags(led_node, "led-power", 0, &flag);if (!gpio_is_valid(gpio)){printk("invalid led-power: %d\n",gpio);return -1;} if (gpio_request(gpio, "led_power")) {printk("gpio %d request failed!\n",gpio);return ret;}led_info.power_gpio = gpio;led_info.power_enable_value = (flag == OF_GPIO_ACTIVE_LOW) ? 0 : 1;gpio_direction_output(led_info.power_gpio, !(led_info.power_enable_value)); ... on_error:gpio_free(gpio); }
of_get_named_gpio_flags 从设备树中读取 led-power 的 GPIO 配置编号和标志,gpio_is_valid 判断该 GPIO 编号是否有效,gpio_request 则申请占用该 GPIO。如果初始化过程出错,需要调用 gpio_free 来释放之前申请过且成功的 GPIO 。
调用 gpio_direction_output 就可以设置输出高还是低电平,因为是 GPIO_ACTIVE_LOW ,如果要灯亮,需要写入 0 。
实际中如果要读出 GPIO,需要先设置成输入模式,然后再读取值:
int val; gpio_direction_input(your_gpio); val = gpio_get_value(your_gpio);
下面是常用的 GPIO API 定义:
#include <linux/gpio.h> #include <linux/of_gpio.h>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 有哪些功能可以复用,在运行时又如何切换功能呢?以 I2C4 为例作简单的介绍。
查规格表可知,I2C4_SDA 与 I2C4_SCL 的功能定义如下:
Pad# | func0 | func1 |
---|---|---|
I2C4_SDA/GPIO7_C1 | gpio7c1 | i2c4tp_sda |
I2C4_SCL/GPIO7_C2 | gpio7c2 | i2c4tp_scl |
在 /kernel/arch/arm/boot/dts/rk3288.dtsi 里有:
i2c4: i2c@ff160000 {compatible = "rockchip,rk30-i2c";reg = <0xff160000 0x1000>;interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;#address-cells = <1>;#size-cells = <0>;pinctrl-names = "default", "gpio";pinctrl-0 = <&i2c4_sda &i2c4_scl>;pinctrl-1 = <&i2c4_gpio>;gpios = <&gpio7 GPIO_C1 GPIO_ACTIVE_LOW>, <&gpio7 GPIO_C2 GPIO_ACTIVE_LOW>;clocks = <&clk_gates6 15>;rockchip,check-idle = <1>;status = "disabled";};
此处,跟复用控制相关的是 pinctrl- 开头的属性:
- pinctrl-names 定义了状态名称列表: default (i2c 功能) 和 gpio 两种状态。
- pinctrl-0 定义了状态 0 (即 default)时需要设置的 pinctrl: i2c4_sda 和 i2c4_scl
- pinctrl-1 定义了状态 1 (即 gpio)时需要设置的 pinctrl: i2c4_gpio
这些 pinctrl 在 /kernel/arch/arm/boot/dts/rk3288-pinctrl.dtsi 中定义:
/ { pinctrl: pinctrl@ff770000 {compatible = "rockchip,rk3288-pinctrl";...gpio7_i2c4 {i2c4_sda:i2c4-sda {rockchip,pins = <I2C4TP_SDA>;rockchip,pull = <VALUE_PULL_DISABLE>;rockchip,drive = <VALUE_DRV_DEFAULT>;//rockchip,tristate = <VALUE_TRI_DEFAULT>;}; i2c4_scl:i2c4-scl {rockchip,pins = <I2C4TP_SCL>;rockchip,pull = <VALUE_PULL_DISABLE>;rockchip,drive = <VALUE_DRV_DEFAULT>;//rockchip,tristate = <VALUE_TRI_DEFAULT>;}; i2c4_gpio: i2c4-gpio {rockchip,pins = <FUNC_TO_GPIO(I2C4TP_SDA)>, <FUNC_TO_GPIO(I2C4TP_SCL)>;rockchip,drive = <VALUE_DRV_DEFAULT>;};};...}}
I2C4TP_SDA, I2C4TP_SCL 的定义在 /kernel/arch/arm/boot/dts/include/dt-bindings/pinctrl/rockchip-rk3288.h 中:
#define GPIO7_C1 0x7c10 #define I2C4TP_SDA 0x7c11#define GPIO7_C2 0x7c20 #define I2C4TP_SCL 0x7c21
FUN_TO_GPIO 的定义在 /kernel/arch/arm/boot/dts/include/dt-bindings/pinctrl/rockchip.h 中:
#define FUNC_TO_GPIO(m) ((m) & 0xfff0)
也就是说 FUNC_TO_GPIO(I2C4TP_SDA) == GPIO7_C1, FUNC_TO_GPIO(I2C4TP_SCL) == GPIO7_C2 。
像 0x7c11 这样的值是有编码规则的:
7 c1 1 | | `- func | `---- offset `------ bank 0x7c11 就表示 GPIO7_C1 func1, 即 i2c4tp_sda 。
在复用时,如果选择了 "default" (即 i2c 功能),系统会应用 i2c4_sda 和 i2c4_scl 这两个 pinctrl,最终得将 GPIO7_C1 和 GPIO7_C2 两个针脚切换成对应的 i2c 功能;而如果选择了 "gpio" ,系统会应用 i2c4_gpio 这个 pinctrl,将 GPIO7_C1 和 GPIO7_C2 两个针脚还原为 GPIO 功能。
我们看看 i2c 的驱动程序 /kernel/drivers/i2c/busses/i2c-rockchip.c 是如何切换复用功能的:
static int rockchip_i2c_probe(struct platform_device *pdev) {struct rockchip_i2c *i2c = NULL;struct resource *res;struct device_node *np = pdev->dev.of_node;int ret; // ...i2c->sda_gpio = of_get_gpio(np, 0);if (!gpio_is_valid(i2c->sda_gpio)) {dev_err(&pdev->dev, "sda gpio is invalid\n");return -EINVAL;}ret = devm_gpio_request(&pdev->dev, i2c->sda_gpio, dev_name(&i2c->adap.dev));if (ret) {dev_err(&pdev->dev, "failed to request sda gpio\n");return ret;}i2c->scl_gpio = of_get_gpio(np, 1);if (!gpio_is_valid(i2c->scl_gpio)) {dev_err(&pdev->dev, "scl gpio is invalid\n");return -EINVAL;}ret = devm_gpio_request(&pdev->dev, i2c->scl_gpio, dev_name(&i2c->adap.dev));if (ret) {dev_err(&pdev->dev, "failed to request scl gpio\n");return ret;}i2c->gpio_state = pinctrl_lookup_state(i2c->dev->pins->p, "gpio");if (IS_ERR(i2c->gpio_state)) {dev_err(&pdev->dev, "no gpio pinctrl state\n");return PTR_ERR(i2c->gpio_state);}pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state);gpio_direction_input(i2c->sda_gpio);gpio_direction_input(i2c->scl_gpio);pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state); // ... }
首先是调用 of_get_gpio 取出设备树中 i2c4 结点的 gpios 属于所定义的两个 gpio:
gpios = <&gpio7 GPIO_C1 GPIO_ACTIVE_LOW>, <&gpio7 GPIO_C2 GPIO_ACTIVE_LOW>;
然后是调用 devm_gpio_request 来申请 gpio,接着是调用 pinctrl_lookup_state 来查找 “gpio” 状态,而默认状态 "default" 已经由框架保存到 i2c->dev-pins->default_state 中了。
最后调用 pinctrl_select_state 来选择是 "default" 还是 "gpio" 功能。
下面是常用的复用 API 定义:
#include <linux/pinctrl/consumer.h>struct device {//... #ifdef CONFIG_PINCTRLstruct dev_pin_info *pins; #endif //... };struct dev_pin_info {struct pinctrl *p;struct pinctrl_state *default_state; #ifdef CONFIG_PMstruct pinctrl_state *sleep_state;struct pinctrl_state *idle_state; #endif };struct pinctrl_state * pinctrl_lookup_state(struct pinctrl *p, const char *name);int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
/**
*
* 此文转自链接:http://wiki.t-firefly.com/index.php/Firefly-RK3288/GPIO
* 谢谢作者的分享,我只是个搬运工
* 为避免文中下载链接失效《RK3288 规格书》,附csdn链接:http://download.csdn.net/detail/limin13215/9785457
*
**/
RK3288开发板GPIO介绍相关推荐
- STM32F4 | 最小系统设计 | 开发板资源介绍 | 开发环境搭建 | 程序下载
文章目录 一.STM32最小系统设计 1.什么叫MCU最小系统? 2.STM32最小系统 2.1 供电电路(电源部分) 2.2 复位电路 2.3 时钟电路 2.4 BOOT启动模式选择 2.5 下载电 ...
- 【北京迅为】瑞芯微系列RK3399六核服务器级开发板接口介绍
迅为 iTOP-RK3399 开发板基于瑞芯微公司的 RK3399 六核处理器设计,Cortex-A72 架构: GPU Mali-T860 MP4 支持 4K H.265/H.264 视频解码:An ...
- 51单片机 | 如何学习单片机 | 开发板功能介绍 | 开发板使用方法 | 51单片机介绍
文章目录 一.如何学习单片机 1.学习哪种类型的单片机 2.学习单片机的最佳方法 3.学习单片机的准备工作 4.学习单片机的常见疑问 二.开发板功能及使用介绍 1.开发板功能介绍 2.开发板使用方法 ...
- 导出RK3288开发板上的根文件系统,并打包img
整体操作一共三步: 一.将Rk3288的整个根文件系统的文件,通过ssh拷贝到PC系统(Ubuntu): 二.将此拷贝的全部文件,加载到虚拟光盘中,制作成img文件: 三.将img文件,再烧回RK32 ...
- RK3288 开发板 排插物理引脚对应图以及如何进入android6.0.1内核终端、uboot终端
主要讲述三个问题: (1)RK3288 排查的物理引脚对应图 (2)如何通过打印窗口进入内核终端 (3)如何进入u-boot 终端 1.下面是RK3288 开发板排插物理引脚对应图 2.将物理引脚37 ...
- 关于百问网_STM32F103_MINI开发板的介绍
STM32F103_MINI开发板的介绍 学习内容: 建立集成开发环境 调试或者下载 打印显示 1.如何建立集成开发环境: 主要通过步骤是编辑→编译→汇编→链接→调试和下载 2.调试和下载: 主机(电 ...
- stm32开发板能干什么?stm32开发板功能介绍
很多开发者对于STM32开发板还都不了解,具体哪一款好用?怎么选择?让很多工程师感到困惑,今天就给大家介绍一款DFRobot商城新品,适合有经验的STM32玩家使用的一款开发板-STM32F411开发 ...
- RK3288开发板PopMetal上的GPIO驱动实例
2019独角兽企业重金招聘Python工程师标准>>> 楼主在这边给大家介绍下如何使用PopMetal的GPIO.先讲过程,再讲原理吧, 该驱动需要涉及到的知识点:1,DTS设备树的 ...
- html抽奖源码_开源FPGA开发板OpenICE 介绍及抽奖
首先呢,先强调一遍,我做板子不是为了挣钱,因为国内目前的形式比较严峻,只是为了体验一下开源的工具和环境,也为了后人能对FPGA有个新的认识,所以不会触碰到任何人的蛋糕. 本来今天不准备发文了,还是熬夜 ...
最新文章
- 送书 | 深入浅出,一起学习贝叶斯!
- asp.net 的状态管理
- swift perfect mysql_服务端写Swift体验 (Perfect框架)
- 信息学奥赛一本通(C++)在线评测系统——基础(一)C++语言——1083:计算星期几
- rails中weill_paginate的paginate方法中不能使用额外参数的解决办法
- python画窗口_pyqt中图案如何画在子窗口上
- dairy-20110419-每日总结
- 从事7年前端开发,有些经验想对转行学习前端的伙伴说说!
- Spring中Bean管理操作基于XML配置文件方法实现
- 交换机集群管理(锐捷)
- 数学倒底有没有绝对的严格性和形式化?
- Service 中的 onStart 和 onStartCommand
- 【疾病分类】基于matlab LBP果实病害检测分类【含Matlab源码 1714期】
- fit文件用python画瀑布图
- 【Shiro第七篇】SpringBoot + Shiro实现会话管理
- PCS7 入门指南 v9.0 SP3 v9.1 中文版 学习资料 (官方公开可用资料)
- 支付宝对应APPID
- stm32的内存分布
- 10岁男童高考获566分或被大学破格录取(图)
- PDF转换成Word