2019-04-24
关键字: rk平台控制GPIO功能、rk串口控制引脚电平
本篇文章介绍了如何通过串口来控制 RK3128、RK3288 平台的 GPIO 。
我们可以很便捷地通过串口命令来控制 RK 的 CPU 芯片的 GPIO。
首先通过串口进入到以下目录,注意要提升我们的权限到 root
cd /sys/class/gpio
通常在这个目录至少能看到 export 和 unexport 两个文件,笔者的开发板这个目录有如下文件
shell@rk312x:/sys/class/gpio # ll --w------- root root 4096 2016-01-21 16:50 export lrwxrwxrwx root root 2016-01-21 16:50 gpiochip0 -> .. lrwxrwxrwx root root 2016-01-21 16:50 gpiochip128 -> lrwxrwxrwx root root 2016-01-21 16:50 gpiochip32 -> . lrwxrwxrwx root root 2016-01-21 16:50 gpiochip64 -> . lrwxrwxrwx root root 2016-01-21 16:50 gpiochip96 -> . --w------- root root 4096 2016-01-21 16:50 unexport
然后映射我们需要操作的 GPIO 端口号出来
echo 33 > export
不知道对应的端口号是多少? 看这里
执行完后,可以看到能多出一个目录出来
--w------- root root 4096 2016-01-21 17:00 export lrwxrwxrwx root root 2016-01-21 17:00 gpio33 -> ../../devices/20008000.pinctrl/gpio/gpio33 ...
如果您发现您在执行完命令后并没有如期多出一个映射目录出来,请戳这里
然后我们就可以通过操作这个目录里面的文件来达到控制 GPIO 功能的目的了。
比如我们可以查询一下这个 GPIO 口当前的方向以及电平值
shell@rk312x:/sys/class/gpio # cat gpio33/direction in shell@rk312x:/sys/class/gpio # cat gpio33/value 0
如果要更改电平,可以有如下操作
shell@rk312x:/sys/class/gpio # echo out > gpio33/direction shell@rk312x:/sys/class/gpio # echo 1 > gpio33/value
这一套流程组合起来即为
echo xx > /sys/class/gpio/export echo out > /sys/class/gpio/gpioxx/direction echo 1 > /sys/class/gpio/gpioxx/value
各个 GPIO 的端口值是通过查表和计算得出来的。
我们知道 GPIO 通常分为好几组,如 GPIO1, GPIO2, GPIO3 ...
那我们的计算公式即为
num = 32 * GPIO_X + PORT
GPIO_X 即为 GPIO 的组号,其对应关系如下
GPIO0 --> 0 GPIO1 --> 1 GPIO2 --> 2 ...
而 PORT 的值如下表所示
#define GPIO_A0 0 #define GPIO_A1 1 #define GPIO_A2 2 #define GPIO_A3 3 #define GPIO_A4 4 #define GPIO_A5 5 #define GPIO_A6 6 #define GPIO_A7 7 #define GPIO_B0 8 #define GPIO_B1 9 #define GPIO_B2 10 #define GPIO_B3 11 #define GPIO_B4 12 #define GPIO_B5 13 #define GPIO_B6 14 #define GPIO_B7 15 #define GPIO_C0 16 #define GPIO_C1 17 #define GPIO_C2 18 #define GPIO_C3 19 #define GPIO_C4 20 #define GPIO_C5 21 #define GPIO_C6 22 #define GPIO_C7 23 #define GPIO_D0 24 #define GPIO_D1 25 #define GPIO_D2 26 #define GPIO_D3 27 #define GPIO_D4 28 #define GPIO_D5 29 #define GPIO_D6 30 #define GPIO_D7 31
举个例子,假如我们要控制 gpio2_d4 引脚,则其端口号为
2 * 32 + 28 = 92
假如我们要控制 gpio0_a1 引脚,则其端口号为
0 * 32 + 1 = 1
一个 GPIO 引脚必须要处于一种 “完全自由” 的状态下才能够在串口中对它进行控制。
换句话说就是如果您要操作的 GPIO 引脚在 dts 或 dtsi 文件中操作过它,那么就无法通过串口来控制了。通过这种特性也可以检测我们在配置文件中对某引脚的控制是否起到效果了。
关于这种设定可以参考下 rk 官方给出的关于 gpio 的说明文档,这里贴出一部分关键说明如下

Sysfs 中的路径 -------------- 在/sys/class/gpio 中有 3 类入口: - 用于在用户空间控制 GPIO 的控制接口; - GPIOs 本身;以及 - GPIO 控制器 ("gpio_chip" 实例)。 除了这些标准的文件,还包含“device”符号链接。 控制接口是只写的: /sys/class/gpio/ "export" ... 用户空间可以通过写其编号到这个文件,要求内核导出 一个 GPIO 的控制到用户空间。 例如: 如果内核代码没有申请 GPIO #19,"echo 19 > export" 将会为 GPIO #19 创建一个 "gpio19" 节点。 "unexport" ... 导出到用户空间的逆操作。 例如: "echo 19 > unexport" 将会移除使用"export"文件导出的 "gpio19" 节点。 GPIO 信号的路径类似 /sys/class/gpio/gpio42/ (对于 GPIO #42 来说), 并有如下的读/写属性: /sys/class/gpio/gpioN/ "direction" ... 读取得到 "in" 或 "out"。这个值通常运行写入。 写入"out" 时,其引脚的默认输出为低电平。为了确保无故障运行, "low" 或 "high" 的电平值应该写入 GPIO 的配置,作为初始输出值。 注意:如果内核不支持改变 GPIO 的方向,或者在导出时内核代码没有 明确允许用户空间可以重新配置 GPIO 方向,那么这个属性将不存在。 "value" ... 读取得到 0 (低电平) 或 1 (高电平)。如果 GPIO 配置为 输出,这个值允许写操作。任何非零值都以高电平看待。 如果引脚可以配置为中断信号,且如果已经配置了产生中断的模式 (见"edge"的描述),你可以对这个文件使用轮询操作(poll(2)), 且轮询操作会在任何中断触发时返回。如果你使用轮询操作(poll(2)), 请在 events 中设置 POLLPRI 和 POLLERR。如果你使用轮询操作 (select(2)),请在 exceptfds 设置你期望的文件描述符。在 轮询操作(poll(2))返回之后,既可以通过 lseek(2)操作读取 sysfs 文件的开始部分,也可以关闭这个文件并重新打开它来读取数据。 "edge" ... 读取得到“none”、“rising”、“falling”或者“both”。 将这些字符串写入这个文件可以选择沿触发模式,会使得轮询操作 (select(2))在"value"文件中返回。 这个文件仅有在这个引脚可以配置为可产生中断输入引脚时,才存在。 "active_low" ... 读取得到 0 (假) 或 1 (真)。写入任何非零值可以 翻转这个属性的(读写)值。已存在或之后通过"edge"属性设置了"rising" 和 "falling" 沿触发模式的轮询操作(poll(2))将会遵循这个设置。 GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO 开始实现控制的控制器),并有着以下只读属性: /sys/class/gpio/gpiochipN/ "base" ... 与以上的 N 相同,代表此芯片管理的第一个 GPIO 的编号 "label" ... 用于诊断 (并不总是只有唯一值) "ngpio" ... 此控制器所管理的 GPIO 数量(而 GPIO 编号从 N 到 N + ngpio - 1) 大多数情况下,电路板的文档应当标明每个 GPIO 的使用目的。但是那些编号并不总是 固定的,例如在扩展卡上的 GPIO会根据所使用的主板或所在堆叠架构中其他的板子而 有所不同。在这种情况下,你可能需要使用 gpiochip 节点(尽可能地结合电路图)来 确定给定信号所用的 GPIO 编号。
这份文档位于
./kernel/Documentation/zh_CN/gpio.txt
参考: RK3288 GPIO 输出问题