文章目录
7.1 GPIO简介
GPIO 是通用输入输出端口的简称,简单来说就是 RT1052 可控制的引脚。
芯片一共 196 个引脚,其中 GPIO 就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
RT1052 的 IO 口总共分成 5 组:GPIO1~GPIO5
- 其中:GPIO1、GPIO2 和 GPIO4 每组 32个 IO,GPIO3 只有 28 个 IO,GPIO5 最少,只有 3 个 IO,这样总共是 127 个 IO 口
7.2 GPIO框图
该图从最右端看起:
①区域 中的就表示 RT1052 芯片引出的 GPIO 引脚,其余部件都位于芯片内部。
7.2.1 PAD引脚
PAD 代表了一个 RT1052 的 GPIO 引脚。
左侧是一系列信号通道及控制线
- input_on 控制输入开关
- Dir 控制引脚的输入输出方向
- Data_out 控制引脚输出高低电平
- Data_in 作为信号输入
注意:Dir、Data_out 和 Data_in 是由 IOMUXC 控制连接到具体哪个 Block 上面的,不一定是由 GIPO Block 控制,比如也可以由 SEMC Block 控制。
对于每个引脚都有很多关于属性的配置,这些配置是由下图的框架结构实现的:
1. 最右侧的 PAD 同样是代表一个 RT1052 的引脚。
2. 输出缓冲区, 当输出缓冲区使能时,引脚被配置为输出模式。
- DSE 驱动能力:DSE 可以调整芯片内部与引脚串联电阻 R0 的大小,从而改变引脚的驱动能力。通
过 DSE 可以把 R0 的值配置为原值的 1/2、1/3⋯1/7 等。(R0 的初始值为 260 欧姆,在 3.3V 电压下其电流驱动能力为 12.69mA) - SRE 压摆率配置:压摆率是指电压转换速率,可理解为电压由波谷升到波峰的时间。RT1052 的引脚通过 SRE 支持低速和高速压摆率这两种配置。
- SPEED 带宽配置: SPEED 可以设置 IO 的带宽,分别可设置为 50MHz、100MHz 以及 200MHz。即通过这个 IO 口最高的信号频率。通俗点讲就是方波不失真,如果超过这个频率方波就变正弦波。
- ODE 开漏输出配置: ODE 可以设置引脚是否工作在开漏输出模式。开漏输出模式常用在一些通讯总线中,如 I2C。没有输出高电平的能力,只能输出低电平或者高组态。
- 当输入缓冲区使能时,引脚被配置为输入模式。
- HYS 滞后使能:RT1052 的输入检测可以使用普通的 CMOS 检测或施密特触发器模式(滞后模式)。施密特触发器具有滞后效应,对正向和负向变化的输入信号有不同的阈值电压。
- Pull/Keeper 上下拉、保持器
- 芯片内部的上拉和下拉电阻可以将不确定的信号钳位在高、低电平,或小幅提高的电流输出能力,上拉提供输出电流,下拉提供输入电流。
- 注意:这些上下拉配置只是弱拉,对于类似 I2C 之类的总线,还是必须使用外部上拉电阻。
- PUS 上下拉配置
- PUS 可配置项可选为 100K 欧下拉以及 22K 欧、47K 欧及 100K 欧上拉。
- PUE 上下拉、保持器选择
- 上下拉功能和保持器功能是二选一的,可以通过 PUE 来选择。
- 当转换器停止工作时,保持器会保持输入输出电压。
- PKE 上下拉、保持器配置
- 上下拉功能和保持器还通过 PKE 来控制是否使能。
当引脚被配置为输出模式时,不管上下拉、保持器是什么配置,它们都会被关闭。
7.2.2 IOMUX复用选择器
IOMUX 译为 IO 复用选择器。RT1052 的芯片每个 GPIO都通过 IOMUX 支持多种功能。
- 如GPIO_AD_B0_03 是 LED0 使用的 IO的名字,这个 IO 有很多的功能,具体选择什么样的功能通过 IO 复用功能选择器(IOMUXC)来设置,这个就是前面说的第 34 章的内容
IOMUX 相当于增加了多根内部信号线与 IO 引脚相连,一个 IO 最多可支持 8 种可选的功能。
7.2.2.1 IOMUXC
IOMUX 由其左侧的 IOMUXC 控制(C 表示 Controler)。IOMUXC 提供寄存器给用户进行配置。分成 MUX Mode(IO 模式控制)以及 Pad Settings(Pad 配置):
- MUX Mode ,用来配置引脚的复用功能。
- Pad Settings , 用于配置引脚的属性。
IOMUXC寄存器的命名方式
XXXX 表示引脚的名字,例如本芯片中有一个名为GPIO_AD_B0_09的引脚,编号为GPIO1.9,IOMUXC_SW_MUX_CTL_PAD_ GPIO_AD_B0_09 以及 IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_09。
以下简称 MUX 寄存器及 PAD 寄存器。
IOMUXC_SW_MUX_CTL_PAD_XXXX 引脚模式寄存器
该寄存器主要有两个配置域,分别是 SION 和 MUX_MODE
- SION 用于设置引脚在输出模式下同时开启输入通道。
- 当引脚被配置成开漏模式的同时需要读取引脚的电平信号,那么必须开启 SION。
- MUX_MODE,它使用 3 个寄存器位表示可选的 ALT0~ALT7 这 8 个模式。
- 如 ALT2 模式就是用于 ENET 以太网外设的数据接收信号
- 若配置为 ALT4 则引脚会连接至 CSI 摄像头外设,作为数据信号
IOMUXC_SW_PAD_CTL_PAD_XXXX 引脚属性寄存器
PAD 寄存器的配置项比较丰富
- HYS 设置使用施密特模式的滞后功能
- PUS 配置上下拉电阻的阻值,其它的还包含 PUE、PKE、ODE、SPEED、DSE 及 SRE 的配置
7.2.3 Block 外设功能控制块
Block 是外设功能控制块。
- 具有 PWM 输出功能的引脚,它需要 PWM 外设的支持,这些外设在芯片内部会有独立的功能逻辑控制块,这些控制块通过 IOMUX 的复用信号与 IO 引脚相连。
- 使用时通过 IOMUX 选择具体哪个外设连接到 IO。
RT1052 的 IO 口可以有很多个 Block(控制块),每个 Block 其实就是一个复用功能,GPIO功能也属于这些 Block 里面的一个。
-
IO 口通过一个叫 IOMUXC 的 IO 复用选择器来选择具体的功能(具体连接到那个 Block 上面),看一下 RT1052 的 IO 复用功能框图
图中①处,是一个 PAD(标记为 PAD1),也就是 RT1052 的一个 IO 引脚,每个 PAD 有 5路信号:
-
input_on,是输入开关信号,用于控制是否开启强制输入功能(用 SW_MUX_CTL_PAD 寄存器的 SION 位设置)。如果开启强制输入,则不管 IO 口选择哪个复用模式(ALT0~7),总是可以通过 GPIO_PSR 读取这个 IO 口的状态。
-
Dir,是方向控制信号,控制 IO 的输入/输出方向。
-
Data_out,是数据输出信号,用于控制 IO 口输出高/低电平。
-
Data_in,是数据输入信号,用于读取 IO 口的高/低电平。
最后,下方的控制信号,来自 SW_PAD_CTL_PAD 寄存器(IO 引脚控制寄存器),它控制了这个 PAD 的具体属性(上拉/下拉/保持/速率/驱动能力等,在下一个知识点介绍)。
7.2.4 GPIO外设
GPIO 模块是每个 IO 都具有的外设,它具有 IO 控制最基本的功能,如输出高低电平、检测电平输入等。
7.2.4.1 GPIO.GDIR 方向寄存器
控制一个 GPIO 引脚时,要先用 GDIR 方向寄存器配置该引脚用于输出电平信号还是用作输入检测。
GDIR 寄存器的每一个数据位代表一个引脚的方向,对应的位被设置为 0 时该引脚为输入模式,被设置为 1 时该引脚为输出模式
对 GPIO1 的 GDIR 寄存器的 bit3 位被写入为 1,那么 GPIO1.3 引脚的模式即为输出。
7.2.4.2 GPIO.DR 数据寄存器
DR 数据寄存器直接代表了引脚的电平状态,它也使用 1 个数据位表示 1 个引脚的电平,每位用1 表示高电平,用 0 表示低电平。
- 当 GDIR 方向寄存器设置引脚为输出模式时,写入 DR 数据寄存器对应的位即可控制该引脚输出的电平状态
- 当 GDIR 方向寄存器设置引脚为输入模式时,读取 DR 数据寄存器对应的位即可获取该引脚当前的输入电平状态
7.2.4.3 GPIO.PSR 引脚状态寄存器
简化的 DR 寄存器。
仅在 GDIR 方向寄存器设置为输入模式时,它的每个位表示一个引脚当前的输入电平状态。PSR 寄存器的权限是只读的,对它进行写操作是无效的。
当引脚被配置成输出模式时,若 IOMUXC 中的 MUX 寄存器使能了 SION 功能(输出通道回环至输入),可以通过 PSR 寄存器读取回引脚的状态值。
7.2.4.4 与其它引脚的连接
第 5 项表示另一个引脚 PAD2,它与 PAD1 有一根信号线连接
- 表示部分引脚的输出可以作为另一个引脚的输入。
7.3 寄存器点亮LED灯
标号为 JTAG_TDI 的信号直接与芯片的 GPIO_AD_B0_09 引脚相连。
目标是把这个与 LED 灯相连的 GPIO_IO09(GPIO_AD_B0_09)引脚设置成输出模式并且输出低电平。
7.3.1 IOMUX复用模式
SW_MUX_CTL_PAD_GPIO_AD_B0_09 寄存器说明《IOMUX Controller(IOMUXC)》章节可以看到,寄存器的 MUX_MODE 域列出了这个引脚的 8 个可选功能。
- 把该域设置成 0b101 即十进制数 5 即可选中 ATL5 选项,表示 GPIO1_IO09
/* 设置 MUX 寄存器为 0x05 ,表示把引脚用于普通 GPIO */
2 IOMUXC_MUX_GPIO_AD_B0_09 = (unsigned int)0x05;
IOMUXC_ MUX _GPIO_AD_B0_09 是前面在 MIMXRT1052.h 头文件定义好的指针。
unsigned int 强制转换是确保它是一个 32 位的无符号数,与寄存器的数据类型对应。
7.3.2 PAD 属性配置
GPIO_AD_B0_09 对应的 PAD 寄存器 SW_PAD_CTL_PAD_GPIO_AD_B0_09。
由于控制 LED 灯时使用的是输出功能,所以只需要配置输出属性和上拉保持器即可。
- SRE 压摆率配置:LED 灯,对压摆率没什么要求。本实验中 PAD 寄存器的位设置为 SRE=0b0,即慢压摆率。
- DSE 驱动能力:随便选择一个即可,这里设置为 DSE=0b110,即阻值为 R0/6。
- SPEED 带宽配置:高低电平切换的最高频率,本实验控制 LED 灯对于带宽也没有要求,此处直接配置为 SPEED=0b10 即 100MHz。
- ODE 开漏输出配置:不使用
- PKE、PUE 及 PUS 上下拉、保持器配置:使用上下拉可以在没控制输出的时候引脚固定在高电平或低电平。在控制 DR 寄存器输出时,引脚会无视上下拉而根据 DR 寄存器的值输出电平。为简单起见,控制 LED 灯时我们直接关闭上下拉及保持器,即 PKE=0b0。
- PUE 用于在 PKE 使能的时候选择使用上下拉还是保持器,PUS 用于工作于上下拉模式时(PKE 使能,PUE 为上下拉时)选择使用上拉还是下拉以及对应的电阻。因为关闭了上下拉及保持器,所以 PUE 和 PUS为任意值都无影响,此处直接赋值为 PUE=0b0,PUS=0b00。
- HYS 滞后配置:是否使用施密特触发器,只对输入有效,所以这里配置HYS=0b0,不使用该功能。
得到二进制数 0b0000 0000 0000 1011 0000,化成十六进制数即为 0x000B0,也就是说,我们只要给 PAD 寄存器赋值为 0x000B0 即可得到以上配置
1 /* 设置 PAD 寄存器控制引脚的属性 */
2 IOMUXC_PAD_GPIO_AD_B0_09 = (unsigned int)0x000B0;
IOMUXC_PAD_GPIO_AD_B0_09 也 是 前 面 在 MIMXRT1052.h 头 文 件 定 义 好的 指 针, 它 指 向 GPIO_AD_B0_09(即 GPIO1_09) 引 脚 PAD 寄 存 器
7.3.3 控制引脚方向
把 GPIO 引脚设置为输出模式,这需要配置 GPIO 外设的 GDIR 方向寄存器
控制时把 GPIO1 对应的 GDIR 寄存器的 bit9 赋值为 1,即可把它设置为输出模式
1 /* 设置 GPIO1_09 引脚的方向,使用输出模式 */
2 GPIO1_GDIR |= (unsigned int)(1<<9);
7.3.4 控制引脚输出电平
通过 DR 数据寄存器控制引脚的电平
控制时把 GPIO1 对应的 DR 寄存器的 bit9 赋值为 1 可输出高电平,LED 灯灭,给 bit9 赋值为 0 可输出低电平,LED 灯亮
1 /* 控制引脚为高电平,关闭 LED 灯 */
2 GPIO1_DR |= (unsigned int)(1<<9);
3
4 /* 控制引脚为低电平,点亮 LED 灯 */
5 GPIO1_DR &=~ (unsigned int)(1<<9);
7.3.5 开启外设时钟
RT1052 外设很多,为了降低功耗,每个外设都对应着一个时钟,在芯片刚上电的时候这些时钟都是被关闭的,如果想要外设工作,必须把相应的时钟打开。
RT1052 的所有外设的时钟由一个专门的外设来管理,叫 CCM(Clock Controler Module),CCM 在《IMXRT1050RM》(参考手册)的第 18 章有详细的讲解。
开启 GPIO1 时钟,即要对 CCM_CCGR1 寄存器进行配置
bit28~bit29 配置 CSU 外设时钟,bit26~27 配置 GPIO1 外设时钟,每个配置域包含 2 位。
2 个位包含 3 个有效选择
- 0b00 表示该时钟关闭
- 0b01 和 0b11 表示在 RT1052 芯片的 RUN 模式下都开启该时钟。
- RUN模式指芯片的正常运行状态。
1 /* 开启 GPIO1 端口的时钟 */
2
3 /* 清空控制 GPIO1 端口时钟的 bit26 、 bit27 */
4 CCM_CCGR1 &= ~(unsigned int)(3<<26);
5
6 /* 把 bit26 、 bit27 设置为 0b01 ,即开启 GPIO1 时钟 */
7 CCM_CCGR1 |= (unsigned int)(1<<26);
7.4 GPIO函数使用
7.4.1 GPIO_PinWrite
1 /* 控制 GPIO1_IO09 输出低电平 */
2 GPIO_PinWrite(GPIO1,9,0);
3 /* 控制 GPIO1_IO09 输出高电平 */
4 GPIO_PinWrite(GPIO1,9,1);
7.4.2 GPIO_PinRead 函数
Reads the current input value of the GPIO port.
GPIO_PinRead(GPIO_Type * base, uint32_t pin)
GPIO_PinRead(GPIO1,5)
7.4.3 GPIO_WritePinOutput函数
Sets the output level of the individual GPIO pin to logic 1 or 0。
设置输出电平
GPIO_WritePinOutput(GPIO_Type * base, uint32_t pin, uint8_t output)
11.1 固件库点亮LED灯
11.1.4根据引脚名称查询具体功能信息
打开《IMXRT1050RM》(参考手册),在《Chapter 4 External Signals and Pin Multiplexing》章节的范围内依次搜索以上具体的引脚名,可以查询得到它们用作 GPIO 功能时具体的端口和引脚号
11.1.5 续行符
代码中的“”是 C 语言中的续行符语法,表示续行符的下一行与续行符所在的代码是同一行。
- 应用续行符的时候要注意,在“”后面不能有任何字符 (包括注释、空格),只能直接回车。
11.1.6 CPU 的空操作指令
16 void delay(uint32_t count)
17 {
18 volatile uint32_t i = 0;
19 for (i = 0; i < count; ++i) {
20 __asm("NOP"); /* 调用 nop 空指令 */
21 }
22 }
调用形式是“__asm(“NOP”)”。
根据它的输入参数算出具体的延时时间,此处我们只是简单地凭感觉使用。
11.2 板级基础组件
int main(void)
30 {
31 /************************ 第 3 部分 ****************************/
32 /* 初始化内存保护单元 */
33 BOARD_ConfigMPU();
34 /* 初始化开发板引脚 */
35 BOARD_InitPins();
36 /* 初始化开发板时钟 */
37 BOARD_BootClockRUN();
38 /* 初始化调试串口 */
39 BOARD_InitDebugConsole();
11.2.1 BOARD_ConfigMPU 函数
该函数在 board.c 文件中定义。它包含了内存保护单元的初始化
内存保护单元是内核的功能,使用该功能可以防止内存的非法访问导致系统崩溃。
11.2.2 BOARD_InitPins 函数
该函数在 pin_mux.c 文件中定义。
- 整个板子的所有引脚与 IOMUXC 相关的内容都放置在这个函数内
- 按我们程序的编写风格,每个外设的初始化配置都放置在独立的文件中
此处仍调用 BOARD_InitPins 函数主要是保留了官方对调试串口引脚 IOMUXC 部分的初始化,要使用第 4 部分的 PRINTF 函数,必须调用此函数。
11.2.3 BOARD_BootClockRUN 函数
该函数对整个芯片系统的时钟进行了初始化配置,具体的配置结果可以从后面的 PRINTF 函数打印到电脑串口调试助手的信息查看到。
11.2.4 BOARD_InitDebugConsole 函数
这部分初始化了调试用的串口外设,它如同我们初始化LED 灯时的 GPIO 外设部分。因此,要使用第 4 部分的 PRINTF 函数,也必须调用此函数。
11.3 SystemInit 函数
在 RT1052 标准库的“system_MIMXRT1052.c”文件中定义了。
- 在标准库中的 SystemInit 函数给芯片指定了中断向量表、关闭看门狗与 SysTick 定时器并且使能了代码加载缓冲功能。
- 当 RT1052 芯片上电后,执行启动文件中的指令后会调用该函数,完成以上配置。
11.4 防止头文件被重复包含
避免引起编译错误。
1 #ifndef __BSP_LED_H
2 #define __BSP_LED_H
3
4 /* 此处省略头文件的具体内容 */
5
6 #endif /* end of __BSP_LED_H */
为什么要用两个下划线来定义“__BSP_LED_H”标号,其实这只是防止它与其它普通宏定义重复
GPIO资源
- 图中 P2、P3 和 P6 为 MCU 主 IO 引出口,这三组排针共引出了 97 个 IO 口,另外,通过:P4(P112&P113)和 P8(P300&P301)等 2 组排针引出 4 个 IO 口
- P112 ,P113 之类的,是指:GPIO1_IO12 ,GPIO1_IO13 ,是 GPIO 的简化
叫法
- P112 ,P113 之类的,是指:GPIO1_IO12 ,GPIO1_IO13 ,是 GPIO 的简化
- 底板上总共引出了 101个 IO。RT1052 总共有 127 个 IO,剩下的 26 个 IO,主要用在了 SDRAM、FlexSPI 等外设上面。
GPIO输入
RT1052IO 有关知识的学习需要参考 RT1052 参考手册中的两章内容:《Chapter 34: IOMUXController(IOMUXC)》和《Chapter 32: General Purpose Controller(GPIO)》。
- 第 34 章讲解怎么将一个指定的 IO 设置为你想要的功能
- 第 32 章讲的是如果你要将一个 IO 用作 GPIO 的话该如何配置和使用。
GPIO配置
gpio_pin_config_t key_config;
//SNVS_WAKEUP 配置为 ALT5,即 GPIO5_00
IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,0);
//配置 KEY 相关 IO 的功能
//低转换速度,关闭输出驱动,速度为 100Mhz,关闭开路功能,使能 pull/keepr
//选择 pull 功能,上拉 22K Ohm,关闭 Hyst
IOMUXC_SetPinConfig(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,0xF080);
//KEY_UP 默认电平设置
key_config.direction=kGPIO_DigitalInput; //输入
key_config.interruptMode=kGPIO_NoIntmode; //不使用中断功能
key_config.outputLogic=1; //默认高电平
GPIO_PinInit(GPIO5,0,&key_config); //初始化 GPIO5_00
注意:当 IO 口初始化成 GPIO(ALT5 ),且 GPIO 设置成输入模式(GPIO_MODE_IN )时,输出缓冲器 失 能,相关配置(SPEED 、DSE 、SRE 、ODE 等)全部失效
宏定义的使用
这 4 个宏定义中的KEY0的值会跟随函数的变化而变化。
#define KEY0 GPIO_PinRead(GPIO1,5) //KEY0 按键 GPIO1_05
#define KEY1 GPIO_PinRead(GPIO5,1) //KEY1 按键 GPIO5_01
#define KEY2 GPIO_PinRead(GPIO3,26) //KEY2 按键 GPIO3_26
#define WK_UP GPIO_PinRead(GPIO5,0) //WK_UP 按键 GPIO5_00
一种485引脚定义的使用方法。
#define 485_DIR PCout(8);
485_DIR = 1;
这是跟上述用法相反的一种用法。
注意点
GPIO的5U在使用的时候万不可在前面加0,会别误以为八进制。