瑞萨RA系列MCU简介

开发板官网(https://www.edevkit.com/)
本系列教程目录:
- 瑞萨单片机开发教程[一] e2-studio + DAP LINK开发环境搭建
- 瑞萨单片机开发教程[二] Keil/RASC开发环境搭建
- 瑞萨单片机开发教程[三] 新建RASC工程
- 瑞萨单片机开发教程[四] GPIO输出——led实验
- 瑞萨单片机开发教程[五] GPIO输入——按键key实验
- 瑞萨单片机开发教程[六] ICU外部中断实验
- 瑞萨单片机开发教程[七] SCI UART串口通信实验
- 瑞萨单片机开发教程[八] DMAC 串口数据传输实验
- 瑞萨单片机开发教程[九] ADC 电压采集实验
瑞萨RA系列芯片介绍
2.1 RA系列MCU介绍
瑞萨电子的 RA 系列 32 位微控制器(MCU)凭借采用高性能 Arm® Cortex®-M 处理器内核的多架构设计,在行业中处于领先地位。具有卓越的安全性、出色的 CoreMark® 性能、低功耗运行以及出色的无线连接能力。
瑞萨 RA 系列产品包括:
- RA0 系列,高性价比系列 32 位 MCU,提供超低功耗,运行频率最高可达 32MHz,配备 128KB 闪存。
- RA2 系列,入门级 32 位 MCU,兼具强劲性能与超低功耗,运行频率最高可达 64MHz,配备 512KB 闪存,且具有出色的成本优势。
- RA4 系列,运行频率最高可达 100MHz,既能满足合理的低功耗需求,又集成了丰富的外设功能。
- RA6 系列,运行频率最高可达 240MHz,且集成了各种通信接口。
- RA8 系列,高性能 32 位 MCU,搭载 Arm Cortex-M85 内核,运行频率最高可达 1GHz。部分产品搭载了 Ethos™-U55 NPU。

RA0 系列 – 入门级:RA0 系列入门系列中的基础,简单的 MCU,具有出色的成本效益和超低功耗。它使用 Arm Cortex-M23 内核提供高达 32MHz 的 CPU 性能,具有高达 64KB 的嵌入式闪存和 1.6V 至 5.5V 的宽电源电压范围。RA0 系列是成本敏感型应用的理想选择,如低功耗和低成本的消费电子产品、小家电系统控制、工业系统控制和楼宇自动化。
RA2 系列 – 低功耗:基于 Arm Cortex-M23 内核,最高频率 48 MHz,拥有高达 512 KB 的闪存和 64 KB 的 SRAM。电源电压范围为 1.6 V 到 5.5 V。外设包括全速 USB、CAN、24 位 ∑-△ 模数转换器 (ADC)、16 位数模转换器 (DAC)、电容式触摸感应以及安全功能。
RA4 系列 – 高性能和出色的功耗:基于支持 TrustZone 的 Arm Cortex-M33F 内核或 Arm Cortex-M4F 内核构建,最高频率 100 MHz。高达 1 MB 的闪存和 128 KB 的 SRAM。电压范围为 1.6 V 到 5.5 V。外设包括电容式触摸感应、段码式 LCD 控制器、全速 USB、CAN、安全功能以及数据转换器和定时器。RA4W1 系列器件还额外配备了 Bluetooth ® 低功耗 (BLE) 5.0。
RA6 系列 – 高性能:基于支持 TrustZone 的 Arm Cortex-M33F 内核或 Arm Cortex-M4F 内核。最高频率 200 MHz。高达 2 MB 的闪存和 640 KB 的 SRAM。电压范围为 2.7 V 到 3.6 V。外设包括数据转换器、定时器、外部存储总线、以太网、全速和高速 USB、CAN、安全功能、电容式触摸感应和用于 TFT 显示的图形 LCD 控制器,以及一个 2D 图形引擎。RA6T1 系列器件带有用于电机控制的增强型外设,如高分辨率 PWM 定时器或高级模拟模块。
RA8 系列 – 更高性能、人机界面、物联网和边缘计算:RA8 系列在瑞萨 RA MCU 系列产品组合中提供最高性能和最先进的功能集,采用行业领先的技术 Arm Cortex-M85 CPU 内核与 Helium™ M-profile 矢量扩展提供前所未有的性能,具有完全确定性、低延迟、实时操作,能够满足客户最苛刻的应用需求。

RA 系列产品特点及主要功能如上,选型时可根据需求选择适合型号 MCU。
2.2 RA产品系列型号命名含义

以 RA 的 MCU R7FA6M5BH2CBG 型号为例:

① R:表示瑞萨(Renesas)的意思。
②③ 7F:表示 MCU,内部包含 Flash 存储器。
④⑤ A6:表示 RA6 产品系列。
⑥⑦ M5:“M”表示主流产品,“5”表示产品组号。
⑧ B:表示功能特性集,这里的“B”表示带 CAN-FD,如果是“A”则表示不带。
⑨ H:表示内部 FLASH 容量,“H”为 2MB。
⑩ 2:表示工作温度范围,“2”为 -40°C ~ 85°C,“3”为 -40°C ~ 105°C。
⑪⑫⑬ 无 :第 11、12、13 位表示工厂编程号。这三位是可选的,对于该型号没有这三位。
⑭ C:第 14 位表示质量等级为工业级。
⑮⑯ BG:第 15、16 位,“BG”表示封装为 FBGA 176 pins 封装,而“FC”则表示封装为 LQFP 176 pins 封装。
2.3 RA系列芯片寄存器介绍
2.3.1 模块与资源
MCU 芯片里面主要有两大部分,一是 CPU 内核,二是片上外设。以 RA6M5 芯片为例,RA6M5 所采用的 CPU 内核是 Cortex-M33(简称 CM33)。该 CPU 内核由 ARM 公司设计,但其实 ARM 公司并不生产芯片,而是出售其芯片技术授权。芯片生产厂商,比如 Renesas、ST、NXP、TI 等等,他们负责在 CPU 内核之外设计各个模块并生产整个芯片,这些内核之外的模块被称为“核外设备”或“片上外设”(Peripheral)。例如,RA6M5 芯片内部的外设模块:I/O Ports(GPIO)、SCI(串口)、I2C、SPI 等等,这些都叫做片上外设。
实际上,既然有“核外设备”,那必然也有“核内设备”,即 CPU 内核(Cortex-M33)内部也是具有一定的设备模块的结构的。例如,CPU 内部有 NVIC(嵌套向量中断控制器)、FPU(浮点计算单元)等等。

标着 “Arm Cortex-M33” 的方框,其所表示的便是 CPU 内核,其中包含的小方框(DSP、FPU、MPU、NVIC 等)属于内核的设备。
除了 “Arm Cortex-M33” 的方框以外,还有很多个大方框,它们对片上的全部外设模块进行了一个分类,大方框当中的小方框表示的是外设模块。
| 存储器模块(Memory) | Flash、SRAM |
|---|---|
| 直接内存访问(DMA) | DTC、DMAC |
| 总线(Bus) | CSC、MPU |
| 系统(System) | POR/LVD、Reset、Mode control、Power control、 ICU、Clocks、CAC、 Battery backup、Register write protection |
| 定时器(Timers) | GPT、AGT、RTC、WDT/IWDT |
| 通讯接口(Communication interfaces) | SCI、IIC、SPI、QSPI、OSPI、SDHI、ETHERC、 CAN-FD、USBHS、USBFS、CEC |
| 人机交互接口(Human machine interface) | CTSU |
| 模拟(Analog) | ADC、DAC、TSN |
| 数据处理(Data processing) | CRC、DOC |
| 事件链接(Event link) | ELC |
| 安全(Security) | SCE9 |
RA6M5 芯片 Cortex-M33 CPU 内核结构如图。

2.3.2 存储器映射
给存储器分配地址的过程叫存储器映射,寄存器是一类特殊的存储器,它的每个位都有特定的功能,可以实现对外设/功能的控制,给寄存器的地址命名的过程就叫寄存器映射。
1.存储器映射表

RA6M5 芯片内部的存储器被映射到这一整块 4G(0 ~ 0xFFFF FFFF)的地址空间中。除了寄存器和 SRAM、Flash 的地址空间区域以外,还存在着其他类型的地址空间区域,比如 QSPI area 和 OSPI area。Reserved area 表示的是保留区域。
2.存储器区域划分
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射。
| 区域地址范围 | 区域用途 |
|---|---|
| 0x0000_0000 ~ 0x002F_FFFF | On-chip flash (code flash):片上 Flash(代码) |
| 0x0100_80F0 ~ 0x0100_81B3 | On-chip flash (Factory flash):片上 Flash(出厂保留) |
| 0x0100_A100 ~ 0x0100_A2FF | On-chip flash (option-setting flash):片上 Flash(选项设置) |
| 0x0800_0000 ~ 0x0800_1FFF | On-chip flash (data flash):片上 Flash(数据) |
| 0x2000_0000 ~ 0x2007_FFFF | SRAM0 |
| 0x2800_0000 ~ 0x2800_03FF | Standby SRAM |
| 0x4000_0000 ~ 0x4017_FFFF | Peripheral I/O registers:外设寄存器 |
| 0x407E_0000 ~ 0x407E_FFFF | Flash I/O registers:Flash 寄存器 |
| 0x407F_C000 ~ 0x407F_FFFF | Flash I/O registers:Flash 寄存器 |
| 0x6000_0000 ~ 0x67FF_FFFF | External address space (Quad SPI area):外部 QSPI 存储器地址 |
| 0x6800_0000 ~ 0x7FFF_FFFF | External address space (Octa SPI area):外部 OSPI 存储器地址 |
| 0x8000_0000 ~ 0x87FF_FFFF | External address space (CS area):外部存储器地址 |
| 0xE000_0000 ~ 0xFFFF_FFFF | System for Cortex-M33:处理器内核设备寄存器 |
表格中的 “0x4000_0000 ~ 0x4017_FFFF ” 区域,它映射到了绝大部分外设模块的寄存器。
2.3.3 外设基地址和外设寄存器地址

在芯片手册第 19 章“I/O Ports”当中的第 2 小节为“Register Descriptions”,此小节详细描述了外设模块 IOPORT(即 GPIO)的寄存器。

Base address 为该外设的基地址,也就是 IO 端口的基地址。因为 RA6M5 的 IO 端口不止有一个,而是有 16 个端口(用 PORTm 表示,m = 0~9, A, B),所以每一个端口都有一个基地址,每个端口的基地址都可以用图中的公式来计算出来。
Offset address 为该外设寄存器的地址偏移,图中的寄存器为 PCNTR1/PODR/PDR 寄存器,而“Offset address: 0x000”表示的是该寄存器相对于基地址的偏移量。
要读取 PORT1 的 PCNTR1/PODR/PDR 寄存器的值时,先计算出该寄存器的地址为 (0x40080000 + 0x0020*1),然后再把该地址值转换为 C 语言的指针 (uint32_t *)(0x40080000 + 0x0020*1),最后再取值即可读出该寄存器的值 *( (uint32_t *)(0x40080000 + 0x0020*1) )。
每一种外设模块下面都会有多个寄存器,每个寄存器都有特定的功能。对于一些功能相对复杂的外设来说,它们的寄存器数量可以达到十几个甚至几十个。以 IOPORT1 为例,它的基地址为:0x40080020,下表则展示了它部分的寄存器名称、寄存器地址以及相对于基地址的偏移。
| 寄存器名称 | 寄存器地址 | 相对于基地址的偏移 |
|---|---|---|
| PCNTR1/PODR/PDR | 0x40080020 | 0x000 |
| PCNTR2/EIDR/PIDR | 0x40080024 | 0x004 |
| PCNTR3/PORR/POSR | 0x40080028 | 0x008 |
| PCNTR4/EORR/EOSR | 0x4008002C | 0x00C |
外设基地址

①该基地址包含的寄存器名称。
②PORTm 外设模块基地址,从 0x40080000 开始,每个 port 占用 0x20 字节大小地址,PORTm 包含 PORT0~PORTB。
③寄存器偏移地址。
④地址 bit 位说明,一个寄存器 32bit,“Bit position”为位号,指示该位处于该寄存器中的位置;“Bit field”为位域,一般不同的位域有不同的作用;“Value after reset”为复位值,指示该位的复位值。
⑤位域功能说明。这部分为对每一个位域的功能的详细说明。
⑥说明提示,有些寄存器操作需要注意。
2.3.4 C 语言操作寄存器
通过查看芯片数据手册,知道外设端口的寄存器地址,想要操作寄存器,就可以通过 C 语言取地址,这样就可以读写寄存器地址的数据。
定义 PORT 外设基地址
/* 外设基地址 */
#define R_PORT0_BASE 0x40080000
#define R_PORT1_BASE 0x40080020
#define R_PORT2_BASE 0x40080040
#define R_PORT3_BASE 0x40080060
#define R_PORT4_BASE 0x40080080
#define R_PORT5_BASE 0x400800A0
#define R_PORT6_BASE 0x400800C0
#define R_PORT7_BASE 0x400800E0
#define R_PORT8_BASE 0x40080100
#define R_PORT9_BASE 0x40080120
#define R_PORT10_BASE 0x40080140
#define R_PORT11_BASE 0x40080160
#define R_PFS_BASE 0x40080800
#define R_PMISC_BASE 0x40080D00
定义寄存器结构体
外设有很多,每个外设又包含很多寄存器,一个寄存器又包含多个寄存器位域,如上述 PCNTR1 包含 PDR 和 PODR 两个位域功能,015 位属于 PDR,1631 位属于 PODR。而 PORT0 一个外设地址包含 PCNTR1、PCNTR2、PCNTR3、PCNTR4 这 4 个寄存器,这样可以利用 C 语言的结构体和联合体的特性定义寄存器和位域。
/**
* @brief I/O Ports (R_PORT0)
*/
typedef struct /*!< (@ 0x40040000) R_PORT0 Structure */
{
union
{
__IOM uint32_t PCNTR1; /*!< (@ 0x00000000) Port Control Register 1 */
struct
{
__IOM uint32_t PDR : 16; /*!< [15..0] Pmn Direction(引脚Pmn 方向)*/
__IOM uint32_t PODR : 16; /*!< [31..16] Pmn Output Data(引脚Pmn 输出数据)*/
} PCNTR1_b;
};
union
{
__IM uint32_t PCNTR2; /*!< (@ 0x00000004) Port Control Register 2 */
struct
{
__IM uint32_t PIDR : 16; /*!< [15..0] Pmn Input Data(引脚Pmn 输入数据)*/
__IM uint32_t EIDR : 16; /*!< [31..16] Pmn Event Input Data(引脚Pmn 事件输入数据)*/
} PCNTR2_b;
};
union
{
__OM uint32_t PCNTR3; /*!< (@ 0x00000008) Port Control Register 3 */
struct
{
__OM uint32_t POSR : 16; /*!< [15..0] Pmn Output Set(引脚Pmn 输出置位)*/
__OM uint32_t PORR : 16; /*!< [31..16] Pmn Output Reset(引脚Pmn 输出复位)*/
} PCNTR3_b;
};
union
{
__IOM uint32_t PCNTR4; /*!< (@ 0x0000000C) Port Control Register 4 */
struct
{
__IOM uint32_t EOSR : 16; /*!< [15..0] Pmn Event Output Set(引脚Pmn 事件输出置位)*/
__IOM uint32_t EORR : 16; /*!< [31..16] Pmn Event Output Reset(引脚Pmn 事件输出复位)*/
} PCNTR4_b;
};
} R_PORT0_Type; /*!< Size = 16 (0x10) */
定义外设寄存器
定义了基地址和 R_PORT0_Type 寄存器结构体之后,通过 (R_PORT0_Type *) 指针类型指向基地址,这样就把基地址转换成结构体类型指针,这样定义的外设寄存器可以方便地通过结构体变量去读写数据。
#define R_PORT0 ((R_PORT0_Type *) R_PORT0_BASE)
#define R_PORT1 ((R_PORT0_Type *) R_PORT1_BASE)
#define R_PORT2 ((R_PORT0_Type *) R_PORT2_BASE)
#define R_PORT3 ((R_PORT0_Type *) R_PORT3_BASE)
#define R_PORT4 ((R_PORT0_Type *) R_PORT4_BASE)
#define R_PORT5 ((R_PORT0_Type *) R_PORT5_BASE)
#define R_PORT6 ((R_PORT0_Type *) R_PORT6_BASE)
#define R_PORT7 ((R_PORT0_Type *) R_PORT7_BASE)
#define R_PORT8 ((R_PORT0_Type *) R_PORT8_BASE)
#define R_PORT9 ((R_PORT0_Type *) R_PORT9_BASE)
#define R_PORT10 ((R_PORT0_Type *) R_PORT10_BASE)
寄存器读写
对寄存器的操作就是对寄存器位的操作,C 语言对位的操作就是利用位运算符&、|、~、<<、>>。
- 清零寄存器某一位
清零操作使用按位与“&”运算符。
//清零某个位
R_PORT0->PODR &= ~(1u<<0); //清零PODR寄存器的第0位
R_PORT0->PODR &= ~(1u<<6); //清零PODR寄存器的第6位
//清零多个位
R_PORT0->PODR &= ~(3u<<0); //清零PODR寄存器的第0,1位
R_PORT0->PODR &= ~(3u<<6); //清零PODR寄存器的第6,7位
- 置1寄存器某一位
置1操作使用按位或“|”运算符。
//置位某个位
R_PORT0->PODR |= 1u<<0; //PODR寄存器的第0位置1
R_PORT0->PODR |= 1u<<6; //PODR寄存器的第6位置1
//置位多个位
R_PORT0->PODR |= 3u<<0; //PODR寄存器的第0,1位置1
R_PORT0->PODR |= 3u<<6; //PODR寄存器的第6,7位置1
- 取反寄存器某一位
取反操作使用按位异或“^”运算符。
//取反某个位
R_PORT0->PODR ^= 1u<<0; //取反PODR寄存器的第0位
R_PORT0->PODR ^= 1u<<6; //取反PODR寄存器的第6位
//取反多个位
R_PORT0->PODR ^= 3u<<0; //取反PODR寄存器的第0,1位
R_PORT0->PODR ^= 3u<<6; //取反PODR寄存器的第6,7位