操作寄存器来控制GPIO-点亮LED灯


前言

通过io 操作实现点亮LED灯操作。 但是IO操作的都是寄存器地址,所以先搞清楚寄存器知识点。

难点

  • 对于部分嵌入式同学来说,都是很基础的家常便饭,但是对于上层应用转嵌入式、驱动工程师来说,比较难。
  • 不理解寄存器基本知识点、看操作手册比较困难,无法理解基础知识点等 。

参考资料

GPIO 控制和操作-使用命令通过sysfs文件系统控制GPIO
RK3568驱动指南|第十二篇 GPIO子系统-第129章 GPIO控制和操作实验
使用C程序通过sysfs文件系统控制gpio
rk3588写入寄存器
linux IO指令 读写GPIO口电平实例

  • 这里目标是LED灯点亮实验,核心知识点是认识寄存器地址并进行操作。
  • 了解、学习, 寄存器相关知识点、IO指令操作。

一、寄存器知识点-复用寄存器-方向寄存器-数据寄存器

需求是通过寄存器地址,直接控制LED亮灭! 那么复用、方向、数据这些其实我们之前就已经了解过。 GPIO 来实现外设LED灯的亮灭,那么几个基本知识点:

  • 复用配置:配置pin脚给GPIO功能【本身pin脚复用中有很多功能可以复用,如果实现LED灯亮灭,那么你这个pin脚第一步要实现 复用给GPIO口来用】
  • 方向配置:方向就是极性、输入输出一说。如果控制外设,那么就是输出 out;如果是接收信号 来实现事件监听,比如判断高低电平变化、按键是否被按下,那么就是输入 in。
  • 数据:切实就是配置高低电平,配置的底层逻辑就是配置寄存器的值。

上面分析下其实就是不同阶段对应的不同寄存器。

区别和联系

寄存器比喻作用在点亮LED实验中的操作
复用寄存器选择水龙头出口的模式配置引脚的基本功能(GPIO?UART?)设置为 GPIO 功能
方向寄存器决定水流方向(流出/吸入)配置GPIO引脚为输入或输出设置为 输出 模式
数据寄存器拧开水龙头开关设置输出电平的高低 写入 ‘1’ 或 ‘0’来点亮或熄灭

实现LED灯亮灭步骤-操作寄存器步骤

它们之间的联系和工作流程(点亮LED的编程步骤):

这是一个严格的、有逻辑依赖关系的配置顺序:

  • 1、先配置【复用寄存器】:告诉芯片:“这个引脚我要用来做普通的GPIO,请不要把它用作其他用途(比如串口)。”

  • 2、再配置【方向寄存器】:告诉GPIO:“你现在处于输出模式,你要去驱动外部设备(LED),而不是读取外部信号。”

  • 3、最后操作【数据寄存器】:给GPIO一个明确的指令:“输出高电平(1)”或者“输出低电平(0)”,从而控制LED的亮灭。

简单来说:

复用寄存器决定了引脚是不是一个GPIO。
方向寄存器决定了这个GPIO是输出还是输入。
数据寄存器决定了这个输出型GPIO的电平状态。

二、查找复用寄存器

查找复用寄存器的方法

为什么要查找,就是要看一下默认的复用值是不是目前需求需要的,当然 也可以通过寄存器地址 来更改为复用需要的值。

简要思路

要确定一个Pin脚(例如GPIO2_A2)的复用寄存器地址,你需要查阅官方文档《Rockchip RK3568 TRM Part1》 或者比如 Rockchip RK3568 TRM Part1 V1.1-20210301.pdf。具体步骤如下:

找到寄存器偏移地址:在TRM手册中搜索该Pin脚的名字(如"GPIO2_A2"),你会找到其IOMUX控制寄存器的偏移地址。例如,GPIO2_A2的偏移地址可能是0xE020。

确定寄存器基地址:RK3568的GPIO控制器分为多个BANK(GPIO0-GPIO4),它们位于不同的基地址上:

  • PMUGRF:负责GPIO0,基地址一般为 0xFDC20000。

  • GRF:负责GPIO1, GPIO2, GPIO3, GPIO4,基地址一般为 0xFDC60000。

计算完整寄存器地址:将基地址与偏移地址相加,得到完整的物理地址。例如,GPIO2_A2的完整地址就是 0xFDC60000 + 0xE020 = 0xFDC6E020

根据pin脚名字找对应偏移地址

比如:我们用到的pin脚标号 GPIO0B7 ,那就在 参考数据手册 Rockchip RK3568 TRM Part1 V1.1-20210301.pdf 中找偏移地址。

看 第三章 PMU_GRF_Register_Description-Registers Summary
在这里插入图片描述

PMU_GRF、PMU_GRF_GPIO0B7_IOMUX_L 和 PMU_GRF_GPIO0B7_IOMUX_H 名词理解

术语名称全称/解释主要作用在 RK3568 中的补充说明
PMU_GRFPower Management Unit General Register Files电源管理单元通用寄存器文件:包含与电源管理、时钟、复位及部分GPIO(如GPIO0)控制相关的寄存器。基地址通常为 0xFDC20000。GPIO0 Bank 属于 PMU分组,因此其配置寄存器位于 PMU_GRF 内。
PMU_GRF_GPIO0B7_IOMUX_LPMU_GRF GPIO0B IOMUX Low for pin 7配置 GPIO0_B7 引脚 低两位 的复用功能。具体控制引脚功能的低位部分,例如选择功能0、1、2等。
PMU_GRF_GPIO0B7_IOMUX_HPMU_GRF GPIO0B IOMUX High for pin 7配置 GPIO0_B7 引脚 高两位 的复用功能。具体控制引脚功能的高位部分,与低位组合形成完整的4位功能选择码。

GPIO 分组与 IOMUX 概念

理解上述寄存器,还需要了解 RK3568 的 GPIO 组织方式和 IOMUX 概念:

GPIO 分组结构:RK3568 的 GPIO 分为 5 个 Bank (GPIO0~GPIO4),GPIO0 属于 PMU 分组。每个 Bank 内部分为 4 个 Group (A, B, C, D),每个 Group 有 8 个引脚。因此,GPIO0B7 指的就是 GPIO0 Bank, Group B, pin 7。

引脚复用(IOMUX):芯片引脚有限,一个物理引脚往往可以复用为多种不同功能(如 GPIO、UART、I2C 等)。通过配置 IOMUX 寄存器,你可以选择这些引脚在当前场景下的具体角色。这种配置也常被称为 管脚功能选择 或 Pin multiplexing。

问题-为什么GPIO0B7 对应的偏移地址在PMU_GRF_GPIO0B_IOMUX_H

在Rockchip(RK)平台的开发中,区分GPIO控制寄存器是使用 PMU_GRF_GPIO0B7_IOMUX_H 还是 PMU_GRF_GPIO0B7_IOMUX_L,关键在于理解Rockchip的寄存器组织方式。下面这个表格清晰地展示了GPIO0B组引脚与寄存器位的对应关系:

GPIO 引脚所属寄存器位对应寄存器宏后缀
GPIO0B0低16位_L
GPIO0B1低16位_L
GPIO0B2低16位_L
GPIO0B3低16位_L
GPIO0B4高16位_H
GPIO0B5高16位_H
GPIO0B6高16位_H
GPIO0B7高16位_H
_L和_H 区分规则与原理

PMU_GRF_GPIO0B7_IOMUX_H 和 PMU_GRF_GPIO0B7_IOMUX_L,其区分依据主要来自Rockchip芯片的以下设计:

  • 32位寄存器与高低位分配:Rockchip的GRF(通用寄存器文件)和PMU_GRF(电源管理单元GRF)中的IOMUX(输入输出复用)寄存器通常是32位的。为了高效利用地址空间,一个32位的IOMUX寄存器会被划分为两部分:
16位:用于控制某个特定的GPIO引脚(例如GPIO0B7)。

低16位:用于控制与该引脚在同一个Bank内的另一个GPIO引脚。
因此,通过 _H 和 _L 后缀,就能明确指定当前操作的是寄存器的高16位还是低16位。
  • 引脚编号与寄存器位的关联:在一个GPIO Bank内部,引脚的编号顺序决定了它在复合寄存器中的位置。以GPIO0B组为例,它包含8个引脚(B0到B7)。根据这个规则,通常是较低的引脚编号(如B0-B3)对应寄存器的低16位(使用 _L 后缀),较高的引脚编号(如B4-B7)对应寄存器的高16位(使用 _H 后缀)。你提到的 GPIO0B7 正处于较高的编号,因此它由 PMU_GRF_GPIO0B7_IOMUX_H 的高16位控制。

如何查找复用寄存器

如上,已经找到了偏移量地址:
在这里插入图片描述

继续找一下高位的相关信息描述:PMU_GRF_GPIO0B_IOMUX_H

在这里插入图片描述
现在偏移量地址已经找到了,偏移量地址高位 数据单元功能也已经知道了,为了获取到寄存器复用地址 还需要的就是复用基地址:
在这里插入图片描述
哈哈哈,寄存器文件中都有描述的,那么得到的PMU_GRF复用寄存器基地址就是:0xFDC20000

所以复用寄存器地址=基地址+偏移地址=0xFDC2000C 。 使用 io 命令查看此寄存器的地址:

就是:复用寄存器地址=0xFDC20000+0x000C

基础知识点:十六进制格式表示

复用寄存器地址=0xFDC20000+0x000C,你会发现基地址和偏移地址 格式其实不一样的,如下分析:

案例分析0xFDC20000 0x000C

0xFDC20000

  • 这是一个完整的8位十六进制数,代表一个32位的值。

  • 它很可能是一个内存地址、一个较大的常量值或者一个硬件寄存器的配置值。它的高字节(FD, C2)都是有意义的数字,所以不能省略。

    0x000C

  • 这是一个4位十六进制数。在32位的上下文中,它等同于 0x0000000C。

  • 它通常表示一个较小的数值,或者在一个16位系统/语境中(16位用4个十六进制数表示)。在32位语境下写成 0x000C 而不是 0xC,可能是为了:

在代码或文档中与其他32位数值对齐,保持美观。

明确指示这个值将被放入一个16位或32位的存储空间中。

在数据手册或协议中,这个值可能对应一个16位的字段。
使用 io 命令查看此寄存器的地址

如上:复用寄存器地址=0xFDC20000+0x000C= 0xFDC2000C

[root@topeet:/]# io -r -4 0xFDC2000C
fdc2000c:  00000001
[root@topeet:/]#

所以得到的GPIO0B7 口的复用寄存值是 00000001
在这里插入图片描述
这里侧重于查找gpio口寄存器复用默认功能,设置功能暂不讲解,通过io 口设置一次而已。

二、查找方向寄存器

GPIO_SWPORT_DDR-GPIO_SWPORT_DDR_L-GPIO_SWPORT_DDR_H 是什么

在Rockchip(RK)平台的芯片中,GPIO_SWPORT_DDR 是一个关键的寄存器,用于控制GPIO的输入/输出方向。为了更高效地管理,这个寄存器在硬件上被分成了 GPIO_SWPORT_DDR_L 和 GPIO_SWPORT_DDR_H 两部分。

下面这个表格能帮你快速了解它们的核心区别:

特性GPIO_SWPORT_DDR_LGPIO_SWPORT_DDR_H
控制范围GPIO Bank的低16位引脚GPIO Bank的高16位引脚
具体引脚位0 ~ 位15 (例如 Pin 0 - Pin 15)位16 ~ 位31 (例如 Pin 16 - Pin 31)
寄存器位宽16位16位
共同构成32位方向寄存器的低半部分32位方向寄存器的高半部分

详解RK的GPIO方向寄存器

要理解上面的划分,我们需要先了解一些RK平台GPIO的基本结构:

  • Bank分组:RK平台的GPIO通常被组织成多个Bank(例如RK3568有GPIO0~GPIO4)

  • 32位宽度:每个Bank最多可以控制32个引脚。因此,用于设置引脚方向的寄存器(GPIO_SWPORT_DDR)在硬件上本身就是一个32位的寄存器

  • 软件分拆访问:GPIO_SWPORT_DDR_L 和 GPIO_SWPORT_DDR_H 很可能是为了软件编程方便,将这个完整的32位方向寄存器在地址空间上分拆成的两个16位寄存器。

在驱动代码中,我们通常看到的是对 swport_ddr 这个整体寄存器进行操作,这背后可能就是通过操作 GPIO_SWPORT_DDR_L 和 GPIO_SWPORT_DDR_H 来实现的。

为何GPIO0_B7方向在GPIO_SWPORT_DDR_L

首先,我们需要了解RK平台GPIO的引脚编号规则。根据搜索结果,RK3568的GPIO引脚号计算方式如下:
引脚号 = 32 * bank_num + 8 * group + x
其中:

bank_num:0 ~ 4,对应GPIO0~GPIO4。

group:0 ~ 3,对应A~D(即GPIOA~GPIOD)。

x:0 ~ 7,对应组内的具体引脚。

对于 GPIO0_B7:

  • 它属于 GPIO0 (bank_num = 0)。
  • 它属于B组 (group = 1,因为A=0, B=1, C=2, D=3)。
  • 它是B组内的第7个引脚 (x = 7)。

我们来计算一下:
引脚号 = 32 * 0 + 8 * 1 + 7 = 15

计算得出,GPIO0_B7在该Bank内部的引脚编号是15。根据之前的介绍,编号0~15的引脚正是由 GPIO_SWPORT_DDR_L 这个低16位寄存器控制的。因此,GPIO0_B7的方向确实由 GPIO_SWPORT_DDR_L 寄存器中相应的位来控制。

特别提醒: 判断是否在GPIO_SWPORT_DDR_L 还是 GPIO_SWPORT_DDR_H,实际并不是通过引脚号来判断的, 务必根据目标引脚在Bank中的具体编号(0-15还是16-31)来选择合适的寄存器。 也就是group+X 值来判断的。

GPIO_SWPORT_DDR_L 与 GPIO_SWPORT_DDR_H总结与注意事项

简单来说,GPIO_SWPORT_DDR_L管一个GPIO Bank里编号小的那一半引脚是输入还是输出,而GPIO_SWPORT_DDR_H则管编号大的那一半。

在实际编程中,需要注意:

  • 务必根据目标引脚在Bank中的具体编号(0-15还是16-31)来选择合适的寄存器。

  • 在配置寄存器时,请务必参考你所使用的具体RK芯片型号的官方技术参考手册,因为不同型号的地址偏移量可能会有差异

查找方向寄存器的值

根据上面基础知识和 上面复用查表基础,找到GPIO_SWPORT_DDR_L ,如下: 偏移地址:0x0008

找到GPIO_SWPORT_DDR_L 描述
在这里插入图片描述

找到GPIO_SWPORT_DDR_L 具体描述信息,位控制逻辑。

在这里插入图片描述
同样,如寄存器复用功能找基地址一样,在地址映射表中找到GPIO映射基地址,如下:GPIO基地址 0xFDD60000
在这里插入图片描述
所以:方向寄存器的地址=基地址+偏移地址=0xFDD60000+0x0008=0xFDD60008

使用 IO 命令查看该寄存器的值:如下,

[root@topeet:/]# io -r -4 0xFDD60008
fdd60008:  00000044
[root@topeet:/]#

用计算器看一下十六进制的 0x00000044 的32位值,验证15位值 代表的是输入还是输出,如下:

在这里插入图片描述

不是1 而是0 ,那么应该就是输入 in 了, 那么改变一下输入值,用以前的知识点:GPIO 控制和操作-使用命令通过sysfs文件系统控制GPIO 来查看一下 direction 方向到底是输入还是输出,如下:
在这里插入图片描述
果然是输入模式,那么就用命令改变成输出吧,再继续看看寄存器值:

在这里插入图片描述
现在验证到了,就是输出out 模式了。 现在已经把 GPIO口复用给GPIO使用,把方向设置为输出,剩下的就是通过设置寄存器值来实现高低电平来控制 LED灯亮灭了。

三、查找方向寄存器

在上面方向寄存器的时候,已经找到了GPIO 基地址:0xFDD60000

知识点 GPIO_SWPORT_DR、GPIO_SWPORT_DR_L和GPIO_SWPORT_DR_H 是什么

在Rockchip(RK)平台的芯片中,GPIO_SWPORT_DR、GPIO_SWPORT_DR_L和GPIO_SWPORT_DR_H是与GPIO数据值相关的寄存器,用于控制GPIO的输出电平或读取输入电平

如上面分析 方向 输入输出一样,的到了, GPIO0B7 用的高低电平控制就是 GPIO_SWPORT_DR_L 了

查找方向寄存器的值

根据上面基础知识和 上面复用查表基础,找到GPIO_SWPORT_DR_L,如下: 偏移地址:0x0000

找到GPIO_SWPORT_DR_L描述,如下:
在这里插入图片描述

首先看一下,数据寄存器地址值多少:

数据寄存器的地址为基地址+偏移地址=0xFDD60000

io 命令查看一次:

[root@topeet:/]# io -r -4 0xFDD60008
fdd60008:  00008044

在这里插入图片描述
设置使能打开,处于高电平情况下: 得到十六进制值 80008044

在这里插入图片描述

在这里插入图片描述

io 命令设置高低电平、使能开关实现LED亮灭

如上分析,这里直接使用命令控制即可:实现灯的亮灭

[root@topeet:/]# io -w -4 0xFDD60000 0x80008044
[root@topeet:/]# io -w -4 0xFDD60000 0x80000044

总结

  • 很遗憾的是 这种偏底层io 控制寄存器值很少很少用了,基本上都是通过设备树来配置好GPIO 输入、输出模式,默认高低电平等。 但是对于理解寄存器相关知识点绝对有很大的好处和意义。
  • 最大的收获是:学会了看参考手册,基础知识的扩充。熟悉了很多专业术语:PMU_GRF、PMU_GRF_GPIO0B7_IOMUX_L 、PMU_GRF_GPIO0B7_IOMUX_H、GPIO_SWPORT_DDR-GPIO_SWPORT_DDR_L-GPIO_SWPORT_DDR_H、GPIO_SWPORT_DR、GPIO_SWPORT_DR_L、GPIO_SWPORT_DR_H
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值