电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
【i.MX6ULL】驱动开发3——GPIO寄存器配置原理
分 享
扫描二维码分享
【i.MX6ULL】驱动开发3——GPIO寄存器配置原理
嵌入式
linux
驱动
码农爱学习
关注
发布时间: 2021-09-23
丨
阅读: 1397
前面的两篇Linux驱动文章,介绍了字符设备驱动的两种新旧开发方式,并使用一个虚拟的字符驱动来学习字符设备的开发的流程。 本篇起,就要来操作Linux开发板的硬件,首先当然是通过经典的点亮LED灯程序,来学习Linux IO口操作的字符设备开发流程。 对比STM32的点灯程序,有寄存器操作与库函数操作两种,但其本质都是在配置寄存器。 同样,i.MX6ULL也有多种点灯方式: - **裸机系统**:汇编操作寄存器点灯、C语言操作寄存器点灯 - **跑Linux系统**:字符驱动LED点灯、设备树驱动LED点灯 究其本质,最终都是要操作i.MX6ULL的寄存器。比如,在控制GPIO引脚实现LED亮灭时,会进行类似如下的寄存器配置: ```c /@@* 寄存器物理地址 */ #define CCM_CCGR1_BASE (0X020C406C) #define SW_MUX_SNVS_TAMPER3_BASE (0X02290014) #define SW_PAD_SNVS_TAMPER3_BASE (0X02290058) #define GPIO5_DR_BASE (0X020AC000) #define GPIO5_GDIR_BASE (0X020AC004) ``` 那这些寄存器都是什么作用呢?这些地址是怎么确定的呢? 所以,在学习GPIO控制LED点灯之前,需要先了解清楚有关GPIO的寄存器配置。 [TOC] 既然是要操作硬件,首先就来看一下i.MX6ULL这个芯片的IO口基本信息。 # 1 认识Linux开发板的GPIO口 首先要明确:IO与GPIO是两个概念,GPIO是属于IO的一部分。 - IO: Input Output,用于**CPU与外界进行信息交互**。例如CPU 读内存数据需要 I/O 系统,CPU 输出数据到屏幕显示出来也需要 I/O 系统,信息在 I/O 系统上传输有串行或并行。 - GPIO: General-Purpose IO ports,即**通用I/O口**,在微控制器芯片上一般都会提供一个“通用可编程I/O接口”。接口至少有两个寄存器——**数据寄存器**与**控制寄存器**。数据寄存器的各位直接引到芯片外部,控制寄存器则是对数据寄存器中每一位进行独立的设置。 ## 1.1 板子LED硬件原理图 在开始介绍i.MX6ULL的GPIO之前,先来看一下板子的原理中对于LED的标注。 我这块板子(野火EBF6ULL S1 Pro)的原理图中关于LED电路的部分,如下图所示。 这里出现了两种标注:**SNVS_TAMPER3**与**GPIO5_IO03**,先对这两个名称有个印象,下面就来介绍其含义。 另外,从原理图可以看出,低电平时LED灯会亮起。 ![](https://cf04.ickimg.com/bbsimages/202109/292497e811a60e0fe45aea6e024cd277.png) ## 1.2 GPIO逻辑结构 下图为i.MX6ULL的GPIO硬件结构框图,其中①和⑤的PAD表示i.MX6ULL芯片引出的GPIO引脚,其余部件都位于芯片内部。 ① **PAD**:它代表了i.MX6ULL芯片的一个GPIO引脚。 ② **IOMUX复用选择器**:与STM32的引脚复用功能类似,i.MX6ULL芯片的**每个IO**通过**IOMUXC中的MUX寄存器和PAD寄存器设置,可以支持多种功能(如GPIO、IIC、USART...)**。 ③ **Block外设功能控制块**:例如具有PWM输出功能的引脚,它需要PWM外设的支持。 ④ **GPIO外设**:GPIO模块是每个IO都具有的外设, 它是IO控制的基本功能, 如输出高低电平、 检测电平输入等。**当需要使用引脚的GPIO功能时,就要配置GPIO外设中的各个寄存器(DR、GDIR、PSR...)**。 ⑤ **与其它引脚的连接**:这里是另一个引脚PAD2,它与PAD1有一根信号线连接,表示部分引脚的输出可以作为另一个引脚的输入。 ![](https://cf04.ickimg.com/bbsimages/202109/2ec4b2e9eba895982a99038fd1e4c303.png) ### 1.2.1 PAD配置 PAD代表示i.MX6ULL 的**GPIO引脚**。其左侧是一系列**信号通道**及**控制线**: - input_on控制输入开关 - Dir 控制引脚的输入输出方向 - Data_out 控制引脚输出高低电平 - Data_in 作为信号输入 这些信号都经过一个**IOMUX**器件连接到左侧的寄存器。 ![](https://cf04.ickimg.com/bbsimages/202109/899a6264839529afce5a01161bf17972.png) 另外,对于每个引脚都有很多关于属性的配置: ![](https://cf04.ickimg.com/bbsimages/202109/c75d865dcd289248a6f7da1c65438f4e.png) - ① PAD引脚 框图最右侧的PAD同样是代表一个i.MX6ULL引脚。 - ② 输出缓冲区(**OBE**,output buffer enable) 当输出缓冲区使能时,引脚被配置为**输出模式**。该模式又包含了如下的属性配置: - **DSE 驱动能力配置**:通过**调整芯片内部与引脚串联电阻 R0 的大小**,从而改变引脚的驱动能力。可以把R0的值配置为原值的1/2、1/3⋯1/7 等。 - **SRE 压摆率配置**:指电压转换速率,即电压由波谷升到波峰的时间。**增大压摆率**可减少输出电压的上升时间。 - **SPEED 带宽配置**:带宽的意思是能通过这个IO口最高的信号频率,可设置为50MHz、100MHz以及200MHz。 - **ODE 开漏输出配置**:开漏输出模式常用在一些通讯总线中,如I2C。 - ③ 输入缓冲区(**IBE**,input buffer enable) 当输入缓冲区使能时,引脚被配置为**输入模式**。该模式又包含了如下的属性配置: - **HYS 滞后使能**:i.MX6ULL的输入检测可以使用普通的 CMOS 检测或施密特触发器模式(滞后模式)。 - ④ **Pull/Keeper上下拉、保持器** 引脚的控制中还包含了上下拉、保持器的功能。 - PUS 上下拉配置:可选为100K欧下拉以及22K欧、47K欧及100K欧上拉。 - PUE 上下拉、保持器选择:上下拉功能和保持器功能是二选一的,可以通过PUE来选择。 - PKE 上下拉、保持器配置:上下拉功能和保持器还通过PKE来控制是否使能。 ### 1.2.2 IOMUX复用选择器 与STM32的引脚复用功能类似,i.MX6ULL芯片的每个GPIO通过IOMUX设置,可以支持多种功能。 ![](https://cf04.ickimg.com/bbsimages/202109/0d2085930b677543c9a2e38a86c407b5.png) IOMUX由其左侧的**IOMUXC**提供寄存器给用户进行配置,它又分成**MUX_Mode**(IO 模式控制)以及**Pad Settings**(Pad 配置)两个部分: ① **MUX_Mode配置**:用来配置引脚的复用功能 ② **Pad Settings 配置**:配置引脚的属性,例如驱动能力,是否使用上下拉电阻,是否使用保持器,是否使用开漏模式以及使用施密特模式还是CMOS模式等 在IOMUXC外设中关于MUX_Mode和Pad Settings寄存器命名格式如下: | IOMUXC 控制类型 | 寄存器名称 | | --------------- | -------------------------- | | MUX_Mode | IOMUXC_SW_MUX_CTL_PAD_XXXX | | Pad Settings | IOMUXC_SW_PAD_CTL_PAD_XXXX | ## 1.3 GPIO命名 ### 1.3.1 按照GPIO分组 i.MX6ULL芯片的GPIO被分成 5 组, 并且每组GPIO的数量不尽相同,例如GPIO1有32个引脚,GPIO2有22个引脚等等: | GPIO组 | 引脚数 | 名称 | | ------ | ------ | -------------------- | | GPIO1 | 32 | GPIO1_IO0~GPIO1_IO31 | | GPIO2 | 22 | GPIO2_IO0~GPIO2_IO21 | | GPIO3 | 29 | GPIO3_IO0~GPIO3_IO28 | | GPIO4 | 29 | GPIO4_IO0~GPIO4_IO28 | | GPIO5 | 12 | GPIO5_IO0~GPIO5_IO11 | 具体可查阅数据手册: ![](https://cf04.ickimg.com/bbsimages/202109/1e4a22b15b30a098998b5f82ca444455.png) ### 1.3.2 按照IO分组 此外,还有另一种命名方式,因为GPIO是属于IO的一种,因此按照I.MX6ULL的IO分类,可以分为两大类:**SNVS域的IO和通用的IO**,这两类IO本质上是一样的。 | IO类别 | 命名类型 | | ---------- | -------------------------------- | | SNVS域的IO | IOMUXC_SNVS_SW_MUX_CTL_PAD_XX_XX | | 通用的IO | IOMUXC_SW_MUX_CTL_PAD_XX_XX | - SNVS域的IO: 命名形式为`IOMUXC_SNVS_SW_MUX_CTL_PAD_XX_XX` `XX_XX`可以是如: BOOT_MODE0、SNVS_TAMPER0、TEST_MODE等。 ![](https://cf04.ickimg.com/bbsimages/202109/2ed39929ac5e1893243d360190e33f0b.png) - 通用的IO: 命名形式为`IOMUXC_SW_MUX_CTL_PAD_XX_XX` `XX_XX`可以是如: GPIO1_IO01、UART1_TX_DATA、JTAG_MOD等。 ![](https://cf04.ickimg.com/bbsimages/202109/13418e740a4b10e84460aaa9a1e59c4c.png) 所以,从IO名称上,基本就可以看出该管脚的基本用途。 # 2 板子LED引脚配置 ![](https://cf04.ickimg.com/bbsimages/202109/23a8d2e14afa6ec5bc35b41e0c2ca7fc.png) 下面以 GPIO5_IO03引脚为例,也就是这次要控制的LED引脚,进行配置: ## 2.1 IO配置 ### 2.1.1 配置MUX寄存器 从下图可以看出,**IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3**的MUX寄存器,其**地址为0X2290014H**。 这个**寄存器是32位的,但只用到了低5位**,其中**bit0~bit3**(MUX_MODE)就是设置SNVS_TAMPER3的复用功能的。 SNVS_TAMPER3只能复用为 种功能 IO,即**ALT5作为 GPIO5_IO03**。 ![](https://cf04.ickimg.com/bbsimages/202109/6ed1e2e4e4151f6017419871568c0c91.png) ### 2.1.2 配置PAD寄存器 PAD 寄存器的配置项相对于MUX寄存器就更加丰富了。 从下图可以看出,**IOMUXC_SNVS_SW_PAD_CTL_PAD_SNVS_TAMPER3**的PAD寄存器,其**地址为0X2290058H**。 这**也是个32位寄存器,但是只用到了其中的低17位**。 ![](https://cf04.ickimg.com/bbsimages/202109/b02ec362202dbe5f6aaf4803b2e3b3f9.png) ## 2.2 GPIO配置 上面的MUX和PAD这两种寄存器都是配置IO的,当把IO配置为了GPIO功能后,还有继续对GPIO外设的各种寄存器进行配置: ![](https://cf04.ickimg.com/bbsimages/202109/e45f81f1ecd7854077b88383e712e057.png) ### 2.2.1 配置DR寄存器 **DR(data register)**,即数据寄存器,它是32位的,一个GPIO组最大只有32个IO,因此DR寄存器中的每个位都对应一个 GPIO。 - 当GPIO被配置为**输出模式**后,向指定的位写入数据那么相应的IO就会输出相应的高低电平,例如,要设置GPIO5_IO03输出低电平,那么就应该设置 GPIO5.DR=0x08。 - 当 GPIO被配置为**输入模式**后,此寄存器就保存着对应IO的电平值,每个位对对应一个GPIO,例如,当GPIO5_IO03这个引脚接地的话,那么 GPIO5.DR 的bit3就是0。 ![](https://cf04.ickimg.com/bbsimages/202109/33e21656c06d6b8c3d709daf836f101d.png) ### 2.2.2 配置GDIR寄存器 **GDIR(GPIO direction register)**,即方向寄存器,也是32位的,用来设置某个GPIO的工作方向的,即输入/输出。 同样的,每个IO对应一个位,如果要设置GPIO为输入,就设置相应的位为0,如果要设置为输出,就设置为 1。 比如要设置 GPIO5_IO03 为输出,那么 GPIO5.GDIR=0x00; ![](https://cf04.ickimg.com/bbsimages/202109/b99982f46c881ac510bdfb1fface33e9.png) ### 2.2.3 配置PSR寄存器 **PSR(Pad Status Register)**,即状态寄存器,也是32位的。 注意它是一个**只读寄存器**,每个IO对应一个位,读取相应的位即可获取对应的GPIO的状(高低电平值),功能和输入状态下的DR寄存器一样。 这个寄存器使用**ipg_clk_s时钟**,这意味着只有在访问这个位时才对输入信号进行采样。所以,为了同步访问这个寄存器都需要两个等待状态。 ![](https://cf04.ickimg.com/bbsimages/202109/0678ff52427b96422a76a017413e9f72.png) ### 2.2.4 配置ICR1寄存器 **ICR1(interrupt configuration register1)和ICR2**,都是中断控制寄存器, ICR1用于配置低16个GPIO,ICR2 用于配置高16 个GPIO。 ICR1寄存器中一个GPIO用两个位,这两个位用来配置中断的触发方式: | 位设置 | 中断触发方式 | | ------ | ------------ | | 00 | 低电平触发 | | 01 | 高电平触发 | | 10 | 上升沿触发 | | 11 | 下降沿触发 | 以GPIO1_IO15为例, 若要设置该引脚为上升沿触发中断, 需要配置为:GPIO1.ICR1=2<<30。 ![](https://cf04.ickimg.com/bbsimages/202109/d68b5652f6166d7370d0d9da879deb8c.png) ### 2.2.5 配置ICR2寄存器 **ICR1和ICR2(interrupt configuration register2)**,都是中断控制寄存器, ICR1用于配置低16个GPIO,ICR2 用于配置高16 个GPIO。 若要设置GPIO1的IO16~31的话就需要设置ICR2寄存器了,设置方式参考上面的ICR1。下面这个图与ICR1类似,只截取部分显示。 ![](https://cf04.ickimg.com/bbsimages/202109/ecfd7421df03634bac50cefcffa637ae.png) ### 2.2.6 配置IMR寄存器 **IMR(interrupt mask register)**,即中断屏蔽寄存器,也是32位,每个IO对应一个位。 IMR寄存器用来控制GPIO的中断禁止和使能,如果使能某个GPIO的中断,那么设置相应的位为1即可,反之,如果要禁止中断,那么就设 置相应的位为0即可。 例如,要使能GPIO1_IO00的中断,需要配置为GPIO1.MIR=1。 ![](https://cf04.ickimg.com/bbsimages/202109/38af9c749e9afa09abca496e1a2bc97e.png) ### 2.2.7 配置ISR寄存器 **ISR(interrupt status register)**,即中断状态寄存器,也是32位,每个IO对应一个位。 只要某个GPIO的中断发生,则ISR中相应的位就会被置1。所以通过读取ISR寄存器来判断是否发生了中断,类似于学习STM32用到的中断标志位。 当中断处理完以后,必须清除中断标志位,清除方法就是向ISR中相应的位写1,也就是写1清零。 为了同步,读访问需要两个等待状态,复位需要一个等待状态。 ![](https://cf04.ickimg.com/bbsimages/202109/f849c9ebb865c02646e67611e7a4dc2d.png) ### 2.2.8 配置EDGE_SEL寄存器 **EDGE_SEL(edge select register)**,即边沿选择寄存器,也是32位,每个IO对应一个位。 它用来设置边沿中断, 并会覆盖ICR1和ICR2的设置。 如果相应的位被置1,则相当于设置了对应的GPIO是双边沿(上升沿和下降沿)触发。例如,设置GPIO1.EDGE_SEL=1,则表示 GPIO1_IO01是双边沿触发中断,无论 GFPIO1_CR1的设置为多少。 ![](https://cf04.ickimg.com/bbsimages/202109/02fd0f7dff1249df908ac804eb76a2b0.png) ## 2.3 GPIO各寄存器地址查询表 上面介绍的有关GPIO的7种寄存器,为了方便查询各个寄存器的地址,这里列出一张表: ![](https://cf04.ickimg.com/bbsimages/202109/d82b6cd387b493b6b4110faf1bf6b931.png) ## 2.4 时钟配置 与ST32类似,I.MX6ULL每个外设都有一个外设时钟,使用GPIO时,也必须先使能对应的时钟。 ### 2.4.1 配置CCM寄存器 **CCM(Clock Controller Module)**时钟控制模块寄存器用来使能外设时钟。 CMM一共有**CCM_CCGR0~CCM_CCGR6**这 7 个寄存器,控制着I.MX6U的所有外设时钟开关。 | GPIOx | CCGRx(addr) | CGx | | ---------------- | ------------------- | ---- | | GPIO1_CLK_ENABLE | CCGR1(0X020C406C) | CG13 | | GPIO2_CLK_ENABLE | CCGR0(0X020C4068) | CG15 | | GPIO3_CLK_ENABLE | CCGR2(0X020C4070) | CG13 | | GPIO4_CLK_ENABLE | CCGR3(0X020C4074) | CG6 | | GPIO5_CLK_ENABLE | CCGR1(0X020C406C) | CG15 | 以CCM_CCGR0为例,它是个32位寄存器,每2位控制一个外设的时钟,比如 bit31:30 控制着GPIO2 的外设时钟,两个位就有 4 种操作方式: | 位设置 | 时钟控制 | | ------ | ------------------------------------------------------------ | | 00 | 所有模式下都关闭外设时钟 | | 01 | 只有在运行模式下打开外设时钟,等待模式和停止模式下均关闭外设时钟 | | 10 | 未使用(保留) | | 11 | 除了停止模式以外,其他所有模式下时钟都打开 | 若要打开GPIO2的外设时钟,只需要设置CCM_CCGR0的bit31和bit30为1即可,即 CCM_CCGR0=3 << 30。 ![](https://cf04.ickimg.com/bbsimages/202109/cc174d9582c5485e921a45362613a102.png) ## 2.5 配置总结 使用i.MX6ULL的GPIO时,需要如下几步配置: - 使能 GPIO 对应的时钟 - 配置MUX寄存器,设置IO的复用功能,使其复用为GPIO功能 - 配置PAD寄存器,设置 IO 的上下拉、速度等 - 配置GPIO的各种寄存器(DR、GDIR、...),设置输入/输出、是否使用中断、默认输出电平等 通过上面对各种寄存器的介绍,现在再来看本篇开头提到的那几个寄存器地址,如果理解了本篇的介绍,应该就知道这些地址大概的含义了: ```c /@@* 寄存器物理地址 */ #define CCM_CCGR1_BASE (0X020C406C) #define SW_MUX_SNVS_TAMPER3_BASE (0X02290014) #define SW_PAD_SNVS_TAMPER3_BASE (0X02290058) #define GPIO5_DR_BASE (0X020AC000) #define GPIO5_GDIR_BASE (0X020AC004) ``` # 3 总结 本篇主要介绍了i.MX6ULL有关GPIO的寄存器配置原理,本篇是i.MX6ULL操作硬件电路的基础,了解了这些寄存器的配置原理,后续的LED输出控制、按键输入控制、IIC、SPI通信控制才能更加容易理解。 本文用到的i.MX6ULL数据手册PDF已上传至我的gitee仓库
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
码农爱学习
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交