diff --git a/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/RTT_Viewer.png b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/RTT_Viewer.png new file mode 100644 index 0000000000000000000000000000000000000000..adf98da7868cdeca213f00e65a804cd433d66400 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/RTT_Viewer.png differ diff --git a/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/jlink.png b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/jlink.png new file mode 100644 index 0000000000000000000000000000000000000000..37286d1381892df5d5fbeb86bb8ff7b38eba0df6 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/jlink.png differ diff --git a/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/menuconfig.png b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/menuconfig.png new file mode 100644 index 0000000000000000000000000000000000000000..a4202c19c24cb7ba98267d3764876f00fd3fc427 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/menuconfig.png differ diff --git a/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/seggerRTT_console.png b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/seggerRTT_console.png new file mode 100644 index 0000000000000000000000000000000000000000..a91fe1010c3a053e205fa7e4220810ea8ebda8cc Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/images/seggerRTT_console.png differ diff --git a/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/segger_rtt.md b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/segger_rtt.md new file mode 100644 index 0000000000000000000000000000000000000000..bd8aea280533fd28698c54494a7db656f73a5bba --- /dev/null +++ b/rt-thread-version/rt-thread-standard/application-note/debug/seggerRTT/segger_rtt.md @@ -0,0 +1,86 @@ +# SEGGER_RTT + +## 本文目标人群 + +本文受益人: + +- 开发的时候经常采用 jlink 的硬件调试器进行调试([ST-LINK]([https://www.segger.com/jlink-st-link.html](https://www.segger.com/jlink-st-link.html))) 也可以刷成 JLINK)。 +- 有时候想要在中断中打印一些信息的,但是 printf 在中断中不能打印。 +- 在移植 RT-THREAD 前期,UART 驱动没有完全 ready,想要用 rt_kprintf 进行打印的。 +- 正在开发的 MCU 不希望 console 独占一个 UART。 + +## 简介 + +[SEGGER_RTT](https://github.com/supperthomas/RTTHREAD_SEGGER_TOOL.git) 软件包是一款基于 SEGGER 的 [J-Link RTT ](https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/) 来开发,把 RT-THREAD 的 console 口通过 `J-Link RTT` 进行传输,从而实现 console 口进行一个比较方便的交互,可以完全用来替代 UART 口。这里的 RTT 是 `Real Time Transfer` 的缩写。 + +SEGGER_RTT 的工作原理如下图所示: + +![jlink](images/jlink.png) + + + +J-LINK 可以通过查询变量的方法来查看特定变量的值,SEGGER_RTT 的工具也是利用这一原理。 + +SEGGER_RTT 软件包的特点总结如下: + +- 可以在中断中打印 +- 可以缓存开机的 log +- 可以接收 finsh 命令 +- 多平台支持 +- 不依赖操作系统,单机裸机都可以运行 SEGGER_printf +- 可以支持多种 terminal 端口使用,打印不同的 log +- 可以不用初始化就可以直接使用 + + +## 如何使用 + +1. 在 menuconfig 中选中对应的软件包即可下载该软件包 + +![menuconfig](images/menuconfig.png) + +2. 需要注意的是,选中软件包之后,drv_rtt.c 相当于多了一个类似于 UART 的串型 device 设备,名称为 `jlinkRtt` + +如果想要替换为 console 口的话,需要找到如下两处代码进行修改: + +- rt_hw_jlink_rtt_init 初始化必须在 `rt_console_set_device(RT_CONSOLE_DEVICE_NAME);` 之前调用 +- menuconfig 中的 `RT-Thread Kernel → Kernel Device Object` 中的 console 也要设置为 `jlinkRtt` + +``` +#define RT_CONSOLE_DEVICE_NAME "jlinkRtt" +rt_hw_jlink_rtt_init(); +rt_console_set_device(RT_CONSOLE_DEVICE_NAME); +``` +3. 安装 [JLINK](https://www.segger.com/downloads/jlink/) 的一套工具,安装之后,打开 `J-Link RTT Viewer` 工具,进行如下设置选择对应的 device + +![RTT_Viewer](images/RTT_Viewer.png) + +这边需要注意的是最下面的选项,指的是代码中变量 &_SEGGER_RTT 的地址,有些芯片支持自动识别地址,有些芯片不支持自动识别地址。可以通过 debug 来查看该变量的地址,也可以根据你的 MCU 设置 RAM 的 search 范围,让 JLINK 轮询 RAM 中的地址, 例如 STM32 可以设置 RAM 地址搜索范围 + +``` +0x20000000 0x1000 +``` + +## 运行效果 + +![seggerRTT_console](images/seggerRTT_console.png) + +## 注意事项 + +1. 你需要有 JLINK 连接。 在 STM32 或者 Nordic 开发板上测试都是可以用的。其他的 JLINK 应该也是通用的,这个省去了调试的 UART 串口的占用。可以用这个口打印 log 或者 console 调试。 + +2. 只要你的开发板可以用 JLINK 来调试查看变量,就可以用这个软件包。 RTT 本质上,就是一直轮询_SEGGER_RTT 这个全局变量。所以对架构不是特别敏感,只要你的板子 JLINK 可以 debug 即可。 + +3. 如果你手上有 STLINK, 可以选择刷成 JLINK 参考连接 [segger st-link](https://www.segger.com/products/debug-probes/j-link/models/other-j-links/st-link-on-board/) 当然刷成 JLINK 之后,你的 JLINK 也只能操作 STM32 授权的设备,其他厂商设备是不支持的。 + +## 总结 + +我觉得在开发可以用 JLINK 调试芯片的时候,前期可以通过 segger_rtt 进行 console 调试,是一件比较快速上手的事情,比如在制作新的 BSP 的时候,可以先采用 RTT 的方式进行 console 调试,同样这种 console 可以在中断中打印相应的 log,也是一件比较方便的事情。总之,我感觉需要用到的地方还是挺多的,所以推荐给大家使用。当然 SEGGER_RTT 的功能不仅限于此,其实还有很多功能还未完全开发,比如一些彩色打印和 terminal 复用,欢迎对软件包提意见和需求,如果有什么建议都可以在软件包的 issue 里面提。如果对 SEGGER_RTT 软件包感兴趣的,可以参考 [SEGGER_RTT 探索](https://supperthomas-wiki.readthedocs.io/en/latest/DEBUG/01_SEGGER_RTT/SEGGER_RTT.html#id1) 和 [SEGGER_RTT TOOL](https://github.com/supperthomas/RTTHREAD_SEGGER_TOOL)。 + + + + +## 特别感谢 + +本软件包参考了软件包 [SystemView](https://github.com/RT-Thread-packages/SEGGER_SystemView),以及一些 BLE 社区小伙伴的指导建议。 + + diff --git a/rt-thread-version/rt-thread-standard/application-note/system/mpu/MPU.md b/rt-thread-version/rt-thread-standard/application-note/system/mpu/MPU.md new file mode 100644 index 0000000000000000000000000000000000000000..1b17c7f7b86cc64983df648118222623813c53b6 --- /dev/null +++ b/rt-thread-version/rt-thread-standard/application-note/system/mpu/MPU.md @@ -0,0 +1,198 @@ +# ARM-MPU 详解 + +## 简介 + +​ MPU(Memory Protection Unit) 内存保护单元。 本文主要讲 armv7-m 架构 架构下的 MPU。在 armv7-m 架构下,Cortex-M3 和 Cortex-M4 处理器对 MPU 都是选配的,不是必须的。 + +​ MPU 是一个可以编程的 device 设备,可以用来定义内存空间的属性,比如特权指令和非特权指令以及 cache 是否可访问。armv7-m 通常支持 8 个 region。一个 region 就代表一段连续的区域。 + +​ MPU 可以让嵌入式系统更加健壮,以及保护一些加密区域,可以用来防止黑客攻击。 + +​ MPU 有以下能力可以增加系统的健壮性: + +- 可以阻止用户去破坏操作系统需要使用的数据 +- 可以防止一个任务去非法访问其他任务的数据,将任务完全隔离开 +- 可以把关键数据区设为只读,从而不被破坏 +- 检测其他意外访问,比如,堆栈溢出,数组越界等。 + +## 原理讲解 + +​ 通常 MPU 功能这个是由操作系统提供的服务。在嵌入式调试的时候,我们经常会遇到 hardfault,这个时候一般情况可能是某个指针指到未知的地方,然后对该地址进行修改赋值,会触发 hardfault。MPU 的功能其实和这个功能基本类似。 + +​ 首先理解以下两点,基本上可以大概理解 MPU: + +1. MPU 可以定义某些特定的地址区域的属性,这个属性可以定义成很多类型,比如定义成非特权状态下不可以赋值 +2. 如果非特权指针不小心访问到这个地址区域并且尝试给该区域赋值修改,这个时候会触发 MemManage fault 或者 hardfault 中断,代表你的程序不被允许修改该区域。 + +MPU 本质上就是为了保护某一段地址区域不被非授权状态的程序进行访问。 + +比如,RTOS中的一些特殊的变量,用户线程是不被允许访问和修改的,这个时候如果你启用了 MPU,并且保护了这些变量,那用户即使知道这里的实际的物理地址,也是不被允许访问和修改的。 + +## MPU 寄存器模组 + +MPU 主要有以下寄存器 + +| 名称 | 地址偏移 | +| -------------------------------- | ---------- | +| MPU 类型寄存器 TYPER | 0xE000ED90 | +| MPU 控制寄存器 CTRL | 0xE000ED94 | +| MPU region 号寄存器 RNR | 0xE000ED98 | +| MPU region 基地址寄存器 RBAR | 0xE000ED9C | +| MPU region 属性寄存器 RASR | 0xE000EDA0 | + +### MPU_TYPER + +MPU 类型寄存器主要表示这个 MCU 有几个 region + +| bit 位 | 名称 | 类型 | 描述 | +| ----- | -------- | ---- | ------------------------------------ | +| 15:8 | DREGION | R | MPU 支持的 data region 数量 通常为 0x08 | +| 0 | SEPARATE | R | 分割标志,没有用,默认为 0 | + +### MPU_CTRL + +MPU 控制寄存器主要使能 MPU 等控制 + +| bit 位 | 名称 | 类型 | 描述 | +| ----- | ---------- | ---- | ------------------------------------------- | +| 2 | PRIVDEFENA | R/W | 是否为特权级打开缺省存储器映射 | +| 1 | HFNMIENA | R/W | 1: 在 hardfault 和 NMI 中默认使能 MPU(这个主要是在处理一些hardfault中断的时候,是否需要开启MPU保护对应的数据区域,默认是关闭的)。0: 在hardfault和NMI中默认不使能| +| 0 | ENABLE | R/W | 置 1,使能 MPU | + +PRIVDEFENA 这个 bit 参考一张图 + +如果 PRIVDEFENA=1 ,特权模式下打开背景 region。 + +如果 PRIVDEFENA = 0, 不打开背景 region。背景 region 如下图所示,就是 region 没有定义到的地方。 + +![image-20210822233929926](images/region.png) + + + +### MPU_RNR 和 MPU_RBAR + +MPU region 号寄存器 (MPU_RNR) 和 MPU 基址寄存器 (MPU_RBAR) 通常成对使用 + +MPU_RNR + +| bit 位 | 名称 | 类型 | 描述 | +| ----- | ------ | ---- | ------------------------------------------------------------ | +| 7:0 | region | R/W | 选择下一个需要配置的 region, 因为通常只有 8 个 region,所以 2:0 位有效 | + +MPU_RBAR + +| bit 位 | 名称 | 类型 | 描述 | +| ----- | ------ | ---- | ------------------------------------------ | +| 31:N | ADDR | R/W | REGION 的基地址。N>4 | +| 4 | VALID | R/W | 决定是否理会写入 REGION 字段的值 | +| 3:0 | ENABLE | R/W | MPU region 字段,valid=1 有效,valid=0 无效 | + +从寄存器定义可以看出 region 的基地址最小单位为 64KB。所以你的基地址必须是像 0x10000, 0x20000 这样的地址才是合法的地址。这里主要定义 region 的起始地址。 + +### MPU_RASR + +RASR 是 region 的属性和容量寄存器 +| bit 位 | 名称 | 类型 | 描述 | +| ----- | ---------- | ---- | ----------------------------------------------------- | +| 31:29 | 预留 | - | - | +| 28 | XN | R/W | | +| 26:24 | AP | R/W | ** 访问许可属性 ** | +| 21:19 | TEX | R/W | 类型拓展 | +| 18 | S | R/W | 是否可共享 (1= 可共享,0 = 不可共享) | +| 17 | C | R/W | 是否缓存(1 = 可缓存, 0 = 不可缓存) | +| 16 | B | R/W | buffable(可否缓冲) | +| 15:8 | SRD | R/W | 子 region 除能,每个 bit 代表子 region 是否需要除能 | +| 5:1 | REGIONSIZE | R/W | region 容量。 容量值为 1<<(REGIONSIZE+1) 最小为 32 字节 | +| 0 | SZENABLE | R/W | 1 = 使能此 region 0= 除能此 region | + +REGIONSIZE 的值参考下图 + +![image-20210823230728523](images/REGIONSIZE.png) + +AP(访问许可) 如下表所示 + +![image-20210823230912596](images/AP.png) + +RASR 寄存器中有个 SRD "子 region" 的概念。通常 8 个 region 可能不是很够,所以允许每个 REGION 再次细分更小的模块。但是子 region 必须是 8 等分的,每一份是一个子 region,而且子 region 的属性和父 region 必须是相同的. 每个子 region 可以单独的除能,SRD 中每一个 bit 代表一个 region 是否被除能。例如 SRD.3 = 0 , 则 3 号子 region 被除能。能被子 region 拆分的最小也要有 256 个字节(因为 region 大小最小为 32BYTE). 如果 128 就不能再分了。 + +其他属性的使用可以参考具体的架构文档。 + +## MPU Smple + +下面是 MPU 对应的 sample,这个测试是在 armv7 架构下的。这边我使用的是开发板 L496ZG-NUCLEO 开发板 + +其余的只要有 ARM MPU 的,都可以通过下面代码进行测试 + +``` +#include "mpu_armv7.h" +#define ARRAY_ADDRESS_START (0x20002000UL) +#define ARRAY_SIZE ARM_MPU_REGION_SIZE_32B +#define ARRAY_REGION_NUMBER 0 +#define REGION_PERMISSION ARM_MPU_AP_RO +uint8_t PrivilegedReadOnlyArray[32] __attribute__((at(ARRAY_ADDRESS_START))); + +void mpu_sample() +{ + uint32_t rbar; + uint32_t rasr; + ARM_MPU_Disable(); + rbar = ARM_MPU_RBAR(ARRAY_REGION_NUMBER, ARRAY_ADDRESS_START); + rasr = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 0, 0, 0, ARRAY_SIZE); + ARM_MPU_SetRegion(rbar, rasr); + ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); + (void)PrivilegedReadOnlyArray[0]; + PrivilegedReadOnlyArray[0] = 'e'; +} + +void MemManage_Handler(void) +{ + uint32_t lrValue = 0; + uint32_t cfsr = SCB->CFSR; + + rt_kprintf("MemManage_Handler:\n" + "\tcontrol 0x%x\n" + "\tmmfar 0x%x\n" + "\tLR 0x%x\n", + __get_CONTROL(), SCB->MMFAR, lrValue); + + if (cfsr & SCB_CFSR_MMARVALID_Msk) + { + rt_kprintf("Attempt to access address\n"); + } + + if (cfsr & SCB_CFSR_DACCVIOL_Msk) + { + rt_kprintf("Operation not permitted\n"); + } + + if (cfsr & SCB_CFSR_IACCVIOL_Msk) + { + rt_kprintf("Non-executable region\n"); + } + + if (cfsr & SCB_CFSR_MSTKERR_Msk) + { + rt_kprintf("Stacking error\n"); + } + + /* Disable MPU and restart instruction */ + ARM_MPU_Disable(); +} +``` + +执行了 mpu_sample() 之后,你就会发现 MCU 进入了 MemManage_Handler 中断,并且可以恢复。 + +**(请将mpu_armv7.h等文件更新到最新的[CMSIS](https://github.com/ARM-software/CMSIS_5/blob/develop/CMSIS/Core/Include/mpu_armv7.h))** + +## 参考文档: + +[1] ARM cortex-M3 权威指南 + +[2] [Arm® Cortex®-M4 Processor Technical Reference Manual](https://developer.arm.com/documentation/100166/0001) + +[3] [ARMv7-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0403/ee) + +[4] [Armv8-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0553/bo) + + + diff --git a/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/AP.png b/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/AP.png new file mode 100644 index 0000000000000000000000000000000000000000..ed5d032646488fad4ee9115384b48f660492acc5 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/AP.png differ diff --git a/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/REGIONSIZE.png b/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/REGIONSIZE.png new file mode 100644 index 0000000000000000000000000000000000000000..7bda86a9dac02ee7434e3a7fc5ed4e213a103fa5 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/REGIONSIZE.png differ diff --git a/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/region.png b/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/region.png new file mode 100644 index 0000000000000000000000000000000000000000..78b3271ee1e2d5b5cb9107c82e57f6fbc8f32f83 Binary files /dev/null and b/rt-thread-version/rt-thread-standard/application-note/system/mpu/images/region.png differ