4.1 IOPORT简介
IOPORT 可以对引脚进行以下几个方面的配置:
-
配置引脚为普通 IO 功能,即输入或输出高电平或者低电平。
-
控制引脚的输入上拉电阻。
-
控制引脚的驱动能力。
-
控制引脚是否检测上升沿/下降沿/双边沿。
-
控制引脚是否作为中断输入引脚。
-
配置引脚为模拟输入功能或者将引脚在内部连接到其他外设模块。
4.2 IOPORT的框图分析
IOPORT 的功能结构框图,标有字母 A 处表示的是芯片实际引出的 IO 引脚。
接下来我们对 IOPORT 外设的结构框图进行分析,将不难得出 IOPORT 有如下几种工作模式:
-
通用输入输出(GPIO)模式
-
输入模式(浮空/上拉)
-
输出模式(推挽/开漏)
-
模拟输入功能模式
-
复用功能模式
4.2.1 IO端口方向
PDR (Port Direction Register) 是端口方向寄存器,它控制端口的 GPIO 方向。 当 IO 引脚需要控制输出高电平或者低电平时,可设置引脚的 GPIO 方向为 GPIO 输出; 而当需要读取 IO 引脚的电平时,可设置引脚的 GPIO 方向为 GPIO 输入。见图中标注 ① 处。
4.2.2 IO输入上拉控制
PCR (Pull-up Control Register) 是上拉控制寄存器,它控制 IO 引脚的 GPIO 输入是否使能上拉。 当设置为允许上拉时,实际上会使得图中字母 B 处的弱上拉电阻连接到VCC电源正极,从而使得引脚处于弱上拉输入模式。 需要注意的是,当引脚的 GPIO 方向被配置为“输入”时,才可以设置使用弱上拉电阻。 从上图还可以看出R7FA2L1AB3CFL 的 IO 端口是没有下拉电阻的。见图中标注 ② 处。
4.2.3 IO驱动能力和开漏输出控制
DSCR (Port Drive Capability Register) 是端口驱动能力寄存器,它控制 IO 引脚的驱动能力。 驱动能力指的是IO驱动的电流强度和IO的最大翻转速率。
NCODR (N-Channel Open-Drain Control Register) 是开漏输出控制寄存器,它控制 IO 引脚是否使能开漏模式。 当引脚的 GPIO 方向被配置为“输出”时,可以配置 IO 引脚输出的模式是推挽输出还是使能开漏输出。见图中标注 ③ 处。
8.2.4 IO端口输出数据
这部分看似比较复杂,但是实际上 EOSR、POSR、PORR、EORR 的箭头最终都指向 PODR, 这意味着操作 EOSR、POSR、PORR、EORR 这些寄存器,实际上将最终操作的是 PODR 寄存器。见图中标注 ④ 处。
-
图中 PODR (Port Output Data Register) 是端口输出数据寄存器,它控制 GPIO 引脚输出的电平。 当引脚的 GPIO 方向被配置为“输出”时,可以配置引脚输出高电平或者低电平。
-
图中 EOSR (Event Output Set Register) 是事件输出置位寄存器(该寄存器我们暂且忽略它)。
-
图中 POSR (Pmn Output Set Register) 是端口输出数据寄存器,它控制 GPIO 引脚输出为高电平,但却不能控制输出低电平。
-
图中 PORR (Pmn Output Reset Register) 是端口输出数据寄存器,它控制 GPIO 引脚输出为低电平,但却不能控制输出高电平。
-
图中 EORR (Event Output Reset Register) 是事件输出复位寄存器(该寄存器我们暂且忽略它)。
4.2.5 IO端口输入数据
PIDR (Port Input Data Register) 是端口输入数据寄存器,可以通过它读取 GPIO 引脚的电平状态。 当引脚的 GPIO 方向被配置为“输入”时,程序可以读出输入引脚的电平是高电平还是低电平。见图中标注 ⑤ 处。
4.2.6. 模拟输入模式
ASEL (Analog Input Enable) 是模拟输入选择控制位,可以通过它来将引脚配置为模拟输入模式。 当使用 ADC 功能时,需将引脚配置为模拟输入模式。见图中标注 ⑥ 处。
4.2.7. 端口模式控制和外设复用选择
PMR (Port Mode Control) 是端口模式控制位,可以通过它来将引脚配置为 GPIO 输入/输出模式,或者配置作为复用外设功能引脚。见图中标注 ⑦ 处。
PSEL (Peripheral Select) 是外设复用选择,可以通过它来选择将引脚连接到某一个外设功能上。
4.2.8. IO边沿检测与中断
EOFR (Event on Falling/Event on Rising) 是事件触发选择,可以通过它来让引脚检测边沿信号,如果检测到指定信号将触发一个事件。见图中标注 ⑧ 处。
ISEL (IRQ Input Enable) 是IRQ输入使能控制位,可以配置是否产生中断。
4.3. IOPORT的寄存器描述
IOPORT 模块由于功能相对简单,寄存器相对来说比较少,下面我们就来看看它的这几个寄存器。
4.3.1. 端口引脚功能选择寄存器
我们在前面说过,瑞萨 RA 系列芯片的 IO 端口从理论上被分成16个组、每组有16个引脚(实际上可能会更少), 而下图中所描述的端口引脚功能选择寄存器(PmnPFS)便是用来配置 IO 引脚的,一个这样的寄存器对应配置一个 IO 引脚。
注:上图中的 “Pmn”,“m = 0 to 9, A, B”表示的是 IO 端口 m 的范围,而“n = 00 to 15”表示的是 IO 引脚 n 的范围。
PmnPFS 寄存器的位域说明如下:
位 | 位域名 | 说明 |
---|---|---|
0 | PODR | 端口输出数据
|
1 | PIDR | 端口输入数据
|
2 | PDR | 端口方向
|
4 | PCR | 上拉控制
|
6 | NCODR | 输出开漏控制
|
[11:10] | DSCR | 端口驱动能力
|
[13:12] | EOFR | 上升沿/下降沿事件触发设置
|
14 | ISEL | IRQ 输入中断使能
|
15 | ASEL | 模拟输入使能
|
16 | PMR | 端口模式控制
|
[28:24] | PSEL | 端口引脚复用选择 需要查表选择该引脚的复用功能 |
4.3.2. 端口输出数据寄存器
上图所示为端口输出数据寄存器的相关描述。该寄存器的位域说明如下:
位 | 位域名 | 说明 |
---|---|---|
[15:0] | PDR | Pmn 引脚方向
|
[31:16] | PODR | Pmn 引脚输出数据
|
4.3.3. 端口输入数据寄存器
上图所示为端口输入数据寄存器的相关描述。该寄存器的位域说明如下:
位 | 位域名 | 说明 |
---|---|---|
[15:0] | PIDR | Pmn 引脚输入数据
|
[31:16] | EIDR | 端口事件输入数据
|
4.3.4. 端口输出置位/复位寄存器
上图所示为端口输出置位/复位寄存器的相关描述。该寄存器的位域说明如下:
位 | 位域名 | 说明 |
---|---|---|
[15:0] | POSR | Pmn 引脚输出置位
|
[31:16] | PORR | Pmn 引脚输出复位
|
4.3.5. 写保护寄存器
当我们要配置RA单片机的 I/O 引脚时,我们主要需要配置的是 PmnPFS 寄存器, 但是所有的 PmnPFS 寄存器默认是被保护的,因此要想写入引脚 Pmn 对应的 PmnPFS 寄存器,需要先通过写保护寄存器解除写保护。
上图所示为写保护寄存器的相关描述。该寄存器的位域说明如下:
位 | 位域名 | 说明 |
---|---|---|
6 | PFSWE | PmnPFS 寄存器写入使能
|
7 | B0WI | PFSWE 位写入禁止
|
4.4. 实验:使用寄存器点亮LED灯
4.4.1. 硬件设计
芯片的 P400、P403、P404 引脚分别通过一个 2.2 KΩ 的限流电阻连接到 LED1、LED2、LED3 这三个用户 LED 灯的阴极,LED 灯的阳极连接到 3.3V 电源。 而 LED4 是电源指示灯,只要开发板通电就会亮。
hal_entry.c文件
void hal_entry(void)
{
/* TODO: add your own code here */
/* 取消写保护 */
R_PMISC->PWPR = 0; ///< Clear BOWI bit - writing to PFSWE bit enabled
R_PMISC->PWPR = 1U << BSP_IO_PWPR_PFSWE_OFFSET; ///< Set PFSWE bit - writing to PFS register enabled
/* LED1:配置引脚 P400 对应的PFS寄存器 */
R_PFS->PORT[BSP_IO_PORT_04_PIN_00>>8].PIN[BSP_IO_PORT_04_PIN_00 & 0xFF].PmnPFS =
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_LOW;
/* LED2:配置引脚 P403 对应的PFS寄存器 */
R_PFS->PORT[BSP_IO_PORT_04_PIN_03>>8].PIN[BSP_IO_PORT_04_PIN_03 & 0xFF].PmnPFS =
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_LOW;
/* LED3:配置引脚 P404 对应的PFS寄存器 */
R_PFS->PORT[BSP_IO_PORT_04_PIN_04>>8].PIN[BSP_IO_PORT_04_PIN_04 & 0xFF].PmnPFS =
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_LOW;
/** 此时3个LED灯的引脚默认输出的是低电平
* 所以3个LED灯都会默认亮起来
* 我们在 while 循环里让 LED1 闪烁:每秒钟翻转一次状态
*/
while(1)
{
/* 翻转LED灯:LED1 */
//R_PORT4->PODR |= 1<<(BSP_IO_PORT_04_PIN_00 & 0xFF);
//R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS);
//R_PORT4->PODR &= (uint16_t)~(1 << (BSP_IO_PORT_04_PIN_00 & 0xFF));
//R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS);
/* 或者也可以这样用位异或操作来翻转LED1 */
R_PORT4->PODR ^= 1<<(BSP_IO_PORT_04_PIN_00 & 0xFF);
R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS);
}
//这后面的代码无需理会
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
4.4.3. 下载验证
编写好上述代码,然后将程序编译并下载到开发板之后,按下复位按键来复位开发板, 可以观察到开发板上面除了电源指示灯之外的3个 LED 灯当中有两个灯常亮,还有一个灯在缓慢闪烁。 闪烁着的 LED 灯为 LED1,它每秒钟(1000毫秒)便改变一次亮灭的状态。