平台概述
SDK提供了示例应用程序,供开发人员在其开发套件上进行测试并验证设置是否正确。在完成这些测试后,开发人员可以使用这些示例作为开发自己应用程序的基础。
为了开始使用SDK,提供 快速入门,开发人员应首先熟悉该指南。
硬件架构
RTL87x2G的CPU为Real_M300V,可相当于ARM Cortex-M55, RTL87x2G硬件架构由以下部分组成:
丰富的外设
电源管理单元
时钟管理单元
RF模块
软件架构
系统架构
RTL87x2G软件架构包括几个主要的部分:
Platform:包括OTA,flash,FTL等。
IO Drivers:提供应用层访问RTL87x2G外设的接口。
OSIF:实时操作系统的抽象层。
GAP:应用程序和BLE协议栈交互的抽象层。
操作系统
RTL87x2G支持多种RTOS,默认使用FreeRTOS,版本为FreeRTOS V10.4.4,该系统运行在ROM上,包括以下几个模块:
任务管理
队列管理
中断管理
资源管理
内存管理
时间管理
OS接口
OSIF架构 如下图所示,OSIF层通过封装特定的RTOS接口来提供一层统一的接口。开发者可以基于OSIF层提供自定义的RTOS实现,而不需要在上层的软件做任何修改。所以,如果想要让APP可以跑在不同的RTOS,建议使用OSIF接口,而不是直接访问特定RTOS的接口。
任务和优先级
系统会默认创建Timer task,Idle task和Flash task;蓝牙协议栈会默认创建Bluetooth Controller task和Bluetooth Host task。应用程序可以根据实际的需求创建Task,其中APP Task优先级建议设定在1~4。
Task |
Description |
Priority |
---|---|---|
Timer |
FreeRTOS实现的软件定时器 |
6 |
Bluetooth Controller |
蓝牙HCI层以下的协议栈实现 |
6 |
Upper stack |
蓝牙HCI层以上的协议栈实现 |
5 |
APP |
应用层功能的实现 |
1~4 |
Flash |
flash suspend操作和FTL garbage collect |
1 |
Idle |
后台空闲任务,包括低功耗的处理 |
0 |
备注
可以创建多个APP任务,同时内存资源也会被相应地分配。
Idle任务和Timer任务是FreeRTOS创建的。
任务是配置成根据优先级抢占式的。
硬件中断服务例程(ISR)是由Vendor来实现的。
TrustZone
TrustZone是ARMv8-M处理器的基石。它提供了硬件的访问控制代码、内存和I/O,同时保留嵌入式应用程序的需求:实时响应,最小切换开销,受限的片上资源,便于软件开发。
ARMv8-M添加了一个额外的处理器状态的操作:安全的和不安全的执行状态。这些安全状态是正交于现有的线程和处理模式,从而在安全的和非安全状态两种模式间运行。
TrustZone有如下特性:
允许用户将内存划分为安全和非安全区域。
允许在未经身份验证时阻止调试安全代码/数据。
NVIC、MPU、SYSTICK、内核控制寄存器等也被备份到两个区域中,安全代码和非安全代码可以独立访问自己的资源。
安全区和非安全区都有MSP和PSP堆栈指针。
提出了Secure Gateway的概念,非安全代码可以通过Secure Gateway访问特定的安全代码,这也是非安全代码访问安全代码的唯一方式。
提供了一个Stack Limit Checking(堆栈限制检查)功能,可以用于检测堆栈溢出的情况。在ARMv8.1-M架构中,每个堆栈指针都有相应的堆栈限制寄存器。
SAU(Security Attribution Unit)和IDAU(Implementation Defined Attribution Unit)的作用是将内存空间划分为安全和不安全的空间。CPU发出的指令都会通过SAU来判断是否符合安全规则,其余Bus Master例如DMA、GPU、USB等发出的指令都会通过IDAU来判断是否符合安全规则。如果违反安全规则,例如non-secure code访问secure region,就会触发secure fault/hard fault。
以下是SAU默认的secure,non-secure划分,以Single Bank(OTA升级方式之一)为例,共设定了7种Non-Secure或者Non-Secure Callable区域:
区域 |
说明 |
---|---|
Region0 |
ROM中Non-Secure Callable区域,存放供Non-Secure程序调用的API |
Region1, 2 |
部分ROM,ITCM1,DTCM0 |
Region3 |
Data SRAM,Buffer SRAM,以及Flash最开始的SOCV config和OEM config |
Region4, 5 |
Flash区域 |
Region6 |
PSRAM,Peripheral等区域 |
备注
SDK中默认不开启TrustZone,所有code的执行都在secure区域。如需开启TrustZone需要额外维护一个secure app,可以参考SDK中trustzone_demo:rtl87x2g_sdk_xxxx\samples\trustzone_demo
启动流程
系统上电或者重启,会执行启动流程,启动流程包括:
eFuse校验
根据eFuse进行安全控制
Flash image校验和执行
eFuse校验决定是否启用secure boot,如启用secure boot,image authentication会涉及签名、CMAC、secure version校验。
在 启动流程图中,“Flash Image Check and Execute”表示对各种Flash Image检查和执行,具体流程如下:
检查OEM Data(Flash layout包含在此文件中)。
检查是否存在有效的待升级文件。
检查OTA Bank Header文件。
检查OTA Bank中每一个Flash image。
执行image。
Flash Image校验和执行是以上流程的流程图。Image检查方式是SHA256完整性校验(关闭secure boot)或者签名验证(打开secure boot)。执行OTA bank内Flash image的顺序:Boot Patch,BT Stack Patch,Secure APP,System Patch,BT Host,APP。
Dual Bank启动流程图中的“Dual Bank Process”是针对切换Bank模式升级Image的处理,在一个旧版本上升级一个新版本,Bank0和Bank1中都会存在images,启动流程会优先校验版本号高的OTA Header,版本号相同则校验Bank0,如果校验和解密成功,则执行该Bank内images;如果校验不成功,会继续校验版本号低的OTA Header。
应用程序
SDK目录
└── SDK
├── bin 应用程序链接的二进制文件
├── bsp 板级和硬件相关的文件
├── doc 文档
├── include 提供接口定义的头文件
├── samples 配置好可直接使用的Keil和GCC实例工程
├── subsys 上层和硬件无关的软件协议
└── tools 工具集
示例工程
为了帮助创建应用程序,SDK中已经创建好了许多示例工程,例如ble_peripheral以及一些BLE相关的示例工程。通过学习示例工程,开发者可以很容易地熟悉SDK。所有的示例工程已经配置好,并且根据RTL87x2G SOC划分好内存,具体内存划分请参考 Memory。
下面以ble_peripheral为例,展示如何通过示例工程来开发客制化应用程序。
ble_peripheral工程中的文件分为以下几个类别:
Device目录:存放启动代码
CMSIS目录:存放CMSIS文件
CMSE Library:Non-secure callable library
Lib目录:应用程序使用的所有二进制文件
Peripheral目录:应用使用的所有外设驱动和模块代码
Profile目录:应用使用的BLE profiles或者服务
APP目录:ble peripheral应用的实现
RTL87x2G MCU基于ARMv8.1架构,支持 MVE 指令集,可高效处理单精度整数和浮点数运算。默认SDK中发布的lib和sample app project都是选用如下device。
应用中的一些公共文件说明如下:
File name |
Description |
---|---|
rom_uuid.h |
UUID头文件是SDK用来识别ROM的,无需更改 |
ROM_NS.lib |
ROM符号库,应用程序链接ROM中的符号 |
gap_utils.lib |
实现BLE功能的GAP库 |
startup_rtl.c |
RTL87x2G应用程序启动的C文件 |
system_rtl.c |
RTL87x2G应用程序系统的C文件 |
board.h |
配置引脚和DLPS的头文件 |
flash_map.h |
Flash layout文件,此文件由Flashmap Generate Tool工具生成 |
mem_config.h |
Memory配置相关的文件 |
示例工程可能会随着SDK一起更新。为了更好地使用最新的示例代码,建议把新增的用户代码组织起来模块化。每个示例工程的详细信息请参考对应示例工程的使用手册。
APP处理流程
Action |
Description |
---|---|
board init |
PINMUX和PAD初始化设置 |
gap init |
GAP相关参数的初始化 |
profile init |
BLE Profiles的初始化 |
power manager init |
电源管理相关的初始化 |
SW timer init |
软件定时器的初始化 |
app queue init |
APP Queue的初始化 |
driver init |
外设的初始化 |
系统是在main()函数中初始化,包括:Board、Peripherals、BT Stack、Profile、Power和Task等。
BT Stack、Profiles和外设驱动是在应用层任务中初始化,并且实现了IO消息机制。所有的功能都被封装成IO事件,这些事件是在相关的消息处理器中处理。
BT Stack消息也是被封装成BT IO事件,跟外设事件处理的方式一样。
消息和事件处理流程
原始消息的来源有通用IO Peripherals的ISR和BT Stack,处理流程如下:
来自通用IO Peripherals的MSG会被MSG分发器转发给IO MSG Handler处理。
来自蓝牙协议栈的MSG会被MSG分发器转发给BT状态机,BT状态机处理完MSG后,会封装成BT IO MSG发送,MSG分发器接收到BT IO MSG后再转发给IO MSG Handler处理。
IO MSG Handler收到MSG后再判断Event类别,进而调用对应的Event Handler处理。
用户程序负责以下事项:
实现IO Peripheral ISR,在ISR中完成初步处理,如果需要进一步处理则封装MSG发给APP。
维护IO MSG Handler,以便接收和处理用户定义的ISR MSG。
实现应用层相关的Event Handler。
GAP层通知APP层是通过MSG和Event机制,而APP层可以直接调用GAP层的APIs。
IO消息
消息格式
typedef struct { uint16_t type; uint16_t subtype; union { uint32_t param; void *buf; }u; }T_IO_MSG;
消息类型定义
typedef enum { IO_MSG_TYPE_BT_STATUS, IO_MSG_TYPE_KEYSCAN, IO_MSG_TYPE_QDECODE, IO_MSG_TYPE_UART, IO_MSG_TYPE_KEYPAD, IO_MSG_TYPE_IR, IO_MSG_TYPE_GDMA, IO_MSG_TYPE_ADC, ... }T_IO_MSG_TYPE;
消息子类型定义
以T_IO_MSG_UART为例,定义UART的子类型。
typedef enum { IO_MSG_UART_RX = 1, IO_MSG_UART_RX_TIMEOUT = 2, IO_MSG_UART_RX_OVERFLOW = 3, IO_MSG_UART_RX_TIMEOUT_OVERFLOW = 4, IO_MSG_UART_RX_EMPTY = 5, }T_IO_MSG_UART;
用户自定义消息
APP开发者可以根据需求扩充定义Message Type以及自定义Subtype Message。
Pin设置
引脚的定义在board.h中定义。
#define KEY_0 P4_0 #define BEEP P4_1 #define LED_0 P2_1 #define LED_1 P2_4
DLPS设置
详细请查阅 低功耗模式 。
存储
存储映射
RTL87x2G MCU内存包括ROM,RAM,Cache,Flash和eFuse,详情请查阅 Memory。
Flash APIs
Flash操作的APIs如下所列,详细请查阅 Flash。
FLASH_NOR_RET_TYPE flash_nor_read_locked( uint32_t addr, uint8_t* data, uint32_t len); FLASH_NOR_RET_TYPE flash_nor_write_locked( uint32_t addr, uint8_t* data, uint32_t len); FLASH_NOR_RET_TYPE flash_nor_erase_locked( uint32_t addr, FLASH_NOR_ERASE_MODE mode); FLASH_NOR_RET_TYPE flash_nor_try_high_speed_mode(FLASH_NOR_IDX_TYPE idx, FLASH_NOR_BIT_MODE bit_mode);
FTL
FTL(flash transport layer)是BT Stack和用户程序读写flash数据的抽象层,详情请查阅 Flash。
eFuse
eFuse是一种一次编程的存储体,用来存储重要且固定的信息,例如:UUID,security key以及其它只会配置一次的信息。eFuse中每一bit不能从0改成1,并且也没有擦除的操作,所以更新eFuse要十分小心。Realtek提供MPTool更新eFuse。
中断
Nested Vectored Interrupt Controller (NVIC)
NVIC特性
16个Real-M300V异常,96条可屏蔽的中断通道
8个可编程的中断优先级
支持Secure和Non-secure向量表的重映射
低延迟异常和中断处理
系统控制寄存器(System Control Registers)的实现
RTL87x2G支持两种方式来更新中断向量表:
RamVectorTableUpdate_ext()
API:允许在中断服务例程中运行XIP代码。但这将带来额外的4us入口和3.6us出口的CPU开销。
RamVectorTableUpdate()
API:需要确保中断服务例程运行RAM代码,没有额外的CPU开销。
RTL87x2G引入flash suspend和resume机制,该机制必须确保在中断服务例程中不访问Flash,为此需要在中断中添加一层封装(wrapper)。默认情况下建议使用 RamVectorTableUpdate_ext()
API,以确保系统的稳定性和兼容性。而在对中断响应时间有严格要求的特殊情况下,建议使用 RamVectorTableUpdate()
API以获得更快的中断响应时间。
中断向量表
Exception Number |
NVIC Number |
Exception Type |
Description |
---|---|---|---|
1 |
Reset |
Reset |
|
2 |
NMI |
Non-maskable interrupt The WDG is linked to the NMI vector |
|
3 |
Hard Fault |
All fault conditions if the corresponding fault handler is not enabled |
|
4 |
MemManage Fault |
||
5 |
Bus Fault |
||
6 |
Usage Fault |
||
7~10 |
RSVD |
||
11 |
SVC |
Supervisor Call |
|
12 |
Debug Monitor |
Debug monitor (breakpoints, watchpoints, or external debug requests) |
|
13 |
RSVD |
||
14 |
PendSV |
Pendable Service Call |
|
15 |
SYSTICK |
System Tick Timer |
|
16 |
[0] |
System_ISR |
Interrupt CPU when system wakeup by GPIO |
17 |
[1] |
WDT |
Watch Dog Timer interrupt |
18 |
[2] |
Internal use |
|
19 |
[3] |
Internal use |
|
20 |
[4] |
Zigbee_ISR |
Zigbee interrupt |
21 |
[5] |
BTMAC_ISR |
BTMAC interrupt |
22* |
[6] |
Peripheral_ISR |
See Below Table: Peripheral ISR (an Extension of interrupt) |
23 |
[7] |
RSVD |
|
24 |
[8] |
RTC |
Real-Time Counter interrupt |
25 |
[9] |
GPIO_A0 |
GPIO_A0 interrupt (GPIO_A corresponds to GPIO0 in Address Map sheet) |
26 |
[10] |
GPIO_A1 |
GPIO_A1 interrupt (GPIO_A corresponds to GPIO0 in Address Map sheet) |
27 |
[11] |
GPIO_A[2:7] |
GPIO_A[2:7] interrupt (GPIO_A corresponds to GPIO0 in Address Map sheet) |
28 |
[12] |
GPIO_A[8:15] |
GPIO_A[8:15] interrupt (GPIO_A corresponds to GPIO0 in Address Map sheet) |
29 |
[13] |
GPIO_A[16:23] |
GPIO_A[16:23] interrupt (GPIO_A corresponds to GPIO0 in Address Map sheet) |
30 |
[14] |
GPIO_A[24:31] |
GPIO_A[24:31] interrupt (GPIO_A corresponds to GPIO0 in Address Map sheet) |
31 |
[15] |
GPIO_B[0:7] |
GPIO_B[0:7] interrupt (GPIO_B corresponds to GPIO1 in Address Map sheet) |
32 |
[16] |
GPIO_B[8:15] |
GPIO_B[8:15] interrupt (GPIO_B corresponds to GPIO1 in Address Map sheet) |
33 |
[17] |
GPIO_B[16:23] |
GPIO_B[16:23] interrupt (GPIO_B corresponds to GPIO1 in Address Map sheet) |
34 |
[18] |
GPIO_B[24:31] |
GPIO_B[24:31] interrupt (GPIO_B corresponds to GPIO1 in Address Map sheet) |
35 |
[19] |
DMA_Channel0 |
RTK-DMA channel0 global interrupt |
36 |
[20] |
DMA_Channel1 |
RTK-DMA channel1 global interrupt |
37 |
[21] |
DMA_Channel2 |
RTK-DMA channel2 global interrupt |
38 |
[22] |
DMA_Channel3 |
RTK-DMA channel3 global interrupt |
39 |
[23] |
DMA_Channel4 |
RTK-DMA channel4 global interrupt |
40 |
[24] |
DMA_Channel5 |
RTK-DMA channel5 global interrupt |
41 |
[25] |
DMA_Channel6 |
RTK-DMA channel6 global interrupt |
42 |
[26] |
DMA_Channel7 |
RTK-DMA channel7 global interrupt |
43 |
[27] |
DMA_Channel8 |
RTK-DMA channel8 global interrupt |
44 |
[28] |
DMA_Channel9 |
RTK-DMA channel9 global interrupt |
45 |
[29] |
PPE |
pixel process engine interrupt |
46 |
[30] |
I2C0 |
I2C0 interrupt |
47 |
[31] |
I2C1 |
I2C1 interrupt |
48 |
[32] |
I2C2 |
I2C2 interrupt |
49 |
[33] |
I2C3 |
I2C3 interrupt |
50 |
[34] |
RTK UART0 |
normal interrupt |
51 |
[35] |
RTK UART1 |
normal UART interrupt |
52 |
[36] |
RTK UART2 |
normal UART interrupt |
53 |
[37] |
RTK UART3 |
normal UART interrupt |
54 |
[38] |
RTK UART4 |
normal UART interrupt |
55 |
[39] |
RTK UART5 |
normal UART interrupt |
56 |
[40] |
SPI 3Wire |
SPI 3Wire interrupt |
57 |
[41] |
SPI0 |
SPI0 interrupt |
58 |
[42] |
SPI1 |
SPI1 interrupt |
59 |
[43] |
SPI Slave |
SPI Slave interrupt |
60 |
[44] |
Timer_0 |
Timer interrupt |
61 |
[45] |
Timer_1 |
Timer interrupt |
62 |
[46] |
Timer_2 |
Timer interrupt |
63 |
[47] |
Timer_3 |
Timer interrupt |
64 |
[48] |
Timer_4 |
Timer interrupt |
65 |
[49] |
Timer_5 |
Timer interrupt |
66 |
[50] |
Timer_6 |
Timer interrupt |
67 |
[51] |
Timer_7 |
Timer interrupt |
68 |
[52] |
Enhanced_Timer_0 |
Enhanced timer interrupt |
69 |
[53] |
Enhanced_Timer_1 |
Enhanced timer interrupt |
70 |
[54] |
Enhanced_Timer_2 |
Enhanced timer interrupt |
71 |
[55] |
Enhanced_Timer_3 |
Enhanced timer interrupt |
72 |
[56] |
HR-ADC |
HR-ADC interrupt |
73 |
[57] |
ADC |
ADC interrupt |
74 |
[58] |
KEYSCAN |
keyscan interrupt |
75 |
[59] |
AON Q-decode |
Qdec in AON domain interrupt |
76 |
[60] |
IR |
IR module global interrupt |
77 |
[61] |
SDHC |
Secure Digital IO interrupt |
78 |
[62] |
ISO7816 |
ISO7816 (Smart Card Standards) interrupt |
79 |
[63] |
Display |
Display interrupt |
80 |
[64] |
I2S0 RX |
I2S0 RX interrupt |
81 |
[65] |
I2S0 TX |
I2S0 TX interrupt |
82 |
[66] |
I2S1 RX |
I2S1 RX interrupt |
83 |
[67] |
I2S1 TX |
I2S1 TX interrupt |
84 |
[68] |
SHA256 |
SHA256 family interrupt |
85 |
[69] |
Public_key_engine |
Public key engine interrupt |
86 |
[70] |
Internal use |
|
87 |
[71] |
SegCom_CTL |
SegCom_CTL interrupt |
88 |
[72] |
CAN |
CAN interrupt |
89 |
[73] |
ETHERNET |
Ethernet interrupt |
90 |
[74] |
IMDC |
IMDC interrupt |
91 |
[75] |
Internal use |
|
92 |
[76] |
Internal use |
|
93 |
[77] |
USB |
USB IP interrupt |
94 |
[78] |
USB_SUSPEND_N |
USB Suspend/Resume interrupt |
95 |
[79] |
USB_Endp_Muti_Proc |
USB_Endp_Muti_Proc interrupt |
96 |
[80] |
USB_IN_EP_0 |
USB IN End Point 0 interrupt |
97 |
[81] |
USB_IN_EP_1 |
USB IN End Point 1 interrupt |
98 |
[82] |
USB_IN_EP_2 |
USB IN End Point 2 interrupt |
99 |
[83] |
USB_IN_EP_3 |
USB IN End Point 3 interrupt |
100 |
[84] |
USB_IN_EP_4 |
USB IN End Point 4 interrupt |
101 |
[85] |
USB_IN_EP_5 |
USB IN End Point 5 interrupt |
102 |
[86] |
USB_OUT_EP_0 |
USB OUT End Point 0 interrupt |
103 |
[87] |
USB_OUT_EP_1 |
USB OUT End Point 1 interrupt |
104 |
[88] |
USB_OUT_EP_2 |
USB OUT End Point 2 interrupt |
105 |
[89] |
USB_OUT_EP_3 |
USB OUT End Point 3 interrupt |
106 |
[90] |
USB_OUT_EP_4 |
USB OUT End Point 4 interrupt |
107 |
[91] |
USB_OUT_EP_5 |
USB OUT End Point 5 interrupt |
108 |
[92] |
USB_Sof |
USB Start Of Frame interrupt |
109 |
[93] |
Internal use |
|
110 |
[94] |
Internal use |
|
111 |
[95] |
Internal use |
Exception Number |
NVIC Number |
Exception Type |
Description |
---|---|---|---|
0 |
[6] |
SPIC0 |
SPI device (flash) Controller 0 interrupt |
1 |
[6] |
SPIC1 |
SPI device (flash) Controller 1 interrupt |
2 |
[6] |
SPIC2 |
SPI device (flash) Controller 2 interrupt |
3 |
[6] |
TRNG |
True Random Number Generator interrupt |
4 |
[6] |
LPC |
Low Power Comparator interrupt |
5 |
[6] |
SPI_PHY1 |
SPI_PHY1 interrupt |
6 |
[6] |
RSVD |
中断优先级
RTL87x2G中断支持3个固定最高优先级和8个可编程优先级。优先级数字代表的优先级高低如下。
0 > 1 > 2 > 3 > 4 > 5 > 6 > 7
Priority |
Usage |
---|---|
-3 |
Reset Handler |
-2 |
NMI |
-1 |
Hard Fault |
0~1 |
用于实时性要求非常高的中断 (注意:此优先级的中断不会被FreeRTOS的临界区屏蔽,但是中断处理函数内不能调用任何FreeRTOS的API) |
2~6 |
通用的中断 |
7 |
SysTick和PendSV |
电源模式管理
RTL87x2G支持四种功耗模式。
CPU Active
在Power active的模式下,如果程序没有进入到idle task,CPU 处于Active状态,CPU Clock会处于高速状态,默认是40M Clock。
CPU Sleep
在Power active的模式下,程序进入idle task,CPU 进入sleep状态,此时CPU clock会自动降速。如果CPU工作模式下处于40M Clock,CPU sleep时clock降低至625KHz。如果有使用PLL clock,slow clock 与 PLL Clock source的选择有关。
DLPS (Deep Low Power State)
系统休眠模式,较低的功耗,以及较快的进出时间,同时RAM内容保持。
Power Down
极致低功耗模式。此模式下RAM内容不保持,从Power Down模式退出执行重启流程,较DLPS模式耗时更长。只有LPC和PAD(关闭debounce)可以唤醒Power Down。
RTL87x2G会在满足特定的条件时进入低功耗模式,并且可以通过PAD、BT中断、RTC中断和OS software timer到期唤醒,详情请查阅 低功耗模式。
调试
调试应用程序有以下两种方式,详情请查阅 调试指南。
使用log机制跟踪代码的执行和数据。
使用Keil MDK或J-Link Commander和SWD进行调试,增加/删除断点以及访问/追踪memory等。