在嵌入式系统开发中,内存保护和缓存维护是确保系统稳定性和性能的关键机制。Cortex-M7作为ARMv7-M架构的高性能微控制器核心,其内存保护单元(MPU)和缓存子系统为开发者提供了强大的硬件支持。
MPU通过划分内存区域并设置访问权限,实现了关键代码与数据的隔离保护。典型应用场景包括:
缓存系统则通过减少内存访问延迟显著提升性能,但同时也带来了数据一致性的挑战。Cortex-M7的缓存维护操作主要解决以下问题:
关键提示:在操作MPU或缓存前,必须充分理解内存屏障指令(DSB/ISB)的作用。DSB确保之前的存储器访问完成,ISB清空处理器流水线,这对避免竞态条件至关重要。
Cortex-M7的MPU通过TEX、C、B、S四个位域定义内存区域的行为特征:
| TEX[2:0] | C | B | S | 内存类型 | 共享性 | 其他属性 |
|---|---|---|---|---|---|---|
| 0b000 | 0 | 0 | x | 强序设备 | 由S位决定 | - |
| 0b000 | 0 | 1 | x | 外设 | 由S位决定 | - |
| 0b000 | 1 | 0 | x | 普通内存 | 由S位决定 | 非缓存 |
| 0b000 | 1 | 1 | x | 普通内存 | 由S位决定 | 写回、写分配、读分配 |
| 0b001 | 0 | 1 | x | 普通内存 | 由S位决定 | 非缓存 |
| 0b010 | 0 | 0 | 0 | 设备 | 非共享 | 非共享设备 |
| 0b1BB | A | A | 0 | 普通内存 | 非共享 | 缓存策略由BB(外部)和AA(内部)决定 |
缓存策略编码(AA/BB位):
AP[2:0]字段定义了特权和非特权模式的访问权限:
| AP[2:0] | 特权权限 | 非特权权限 | 描述 |
|---|---|---|---|
| 000 | 无访问 | 无访问 | 所有访问产生权限错误 |
| 001 | RW | 无访问 | 仅特权软件可访问 |
| 010 | RW | RO | 非特权写操作产生权限错误 |
| 011 | RW | RW | 完全访问 |
| 100 | 不可预测 | 不可预测 | 保留 |
| 101 | RO | 无访问 | 仅特权软件可读 |
| 110 | RO | RO | 特权/非特权均可读 |
| 111 | RO | RO | 特权/非特权均可读(与110行为相同) |
更新MPU区域的标准操作序列:
assembly复制; R1 = 区域编号
; R2 = 大小/启用
; R3 = 属性
; R4 = 基地址
LDR R0,=MPU_RNR ; 0xE000ED98
STR R1, [R0, #0x0] ; 设置区域编号
LDR R5, [R0, #0x8] ; 读取MPU_RASR
BIC R5, R5, #1 ; 清除启用位
STR R5, [R0, #0x8] ; 禁用区域
STR R4, [R0, #0x4] ; 设置基地址
LSL R3, R3, #16 ; 属性移到字的高半部分
ORR R2, R2, R3 ; 合并属性和大小/启用
STR R2, [R0, #0x8] ; 更新MPU_RASR
DSB ; 数据同步屏障
ISB ; 指令同步屏障
优化技巧:使用STM指令可一次性更新多个寄存器:
assembly复制LDR R0, =MPU_RNR
STM R0, {R1-R3} ; 一次性写入区域号、基地址、属性和大小
Cortex-M7支持三种基本缓存操作:
关键缓存维护寄存器:
| 地址 | 名称 | 类型 | 描述 |
|---|---|---|---|
| 0xE000EF50 | ICIALLU | WO | 指令缓存全部无效化 |
| 0xE000EF58 | ICIMVAU | WO | 按地址无效化指令缓存(到PoU) |
| 0xE000EF5C | DCIMVAC | WO | 按地址无效化数据缓存(到PoC) |
| 0xE000EF60 | DCISW | WO | 按set/way无效化数据缓存 |
| 0xE000EF68 | DCCMVAC | WO | 按地址清理数据缓存(到PoC) |
| 0xE000EF6C | DCCSW | WO | 按set/way清理数据缓存 |
| 0xE000EF70 | DCCIMVAC | WO | 按地址清理并无效化数据缓存(到PoC) |
| 0xE000EF74 | DCCISW | WO | 按set/way清理并无效化数据缓存 |
assembly复制STR <指令数据>, <地址> ; 写入新指令
DSB ; 确保写入完成
DCCMVAU <地址> ; 清理数据缓存到PoU
ICIMVAU <地址> ; 无效化指令缓存
DSB ; 确保维护操作完成
ISB ; 同步指令流
c复制// DMA传输前
SCB_CleanDCache_by_Addr(buffer, size);
// DMA传输后
SCB_InvalidateDCache_by_Addr(buffer, size);
assembly复制; 无效化整个数据缓存
MOV r0, #0x0
LDR r11, =CSSELR
STR r0, [r11] ; 选择L1数据缓存
DSB
LDR r11, =CCSIDR
LDR r2, [r11] ; 读取缓存大小信息
... ; 计算set/way参数
LDR r11, =DCISW
STR r3, [r11] ; 无效化缓存行
DSB
ISB
; 无效化指令缓存
MOV r0, #0x0
LDR r11, =ICIALLU
STR r0, [r11]
DSB
ISB
MPU配置后系统崩溃
缓存一致性问题
性能下降
MPU区域规划
缓存策略选择
代码优化
CMSIS提供标准化的缓存和MPU操作接口:
c复制// MPU配置示例
void MPU_Config(void) {
MPU_Region_InitTypeDef MPU_InitStruct = {0};
// 禁用MPU
HAL_MPU_Disable();
// 配置区域0:Flash(只读,特权访问)
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x08000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
// 启用MPU
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
// 缓存操作示例
void Cache_Operations(void) {
// 启用缓存
SCB_EnableICache();
SCB_EnableDCache();
// DMA传输前清理缓存
SCB_CleanDCache_by_Addr((uint32_t*)buffer, size);
// 执行DMA传输...
// DMA传输后无效化缓存
SCB_InvalidateDCache_by_Addr((uint32_t*)buffer, size);
}
实际项目中,建议将MPU配置封装为独立的初始化模块,并根据应用需求划分不同的内存区域。对于RTOS环境,还需要考虑任务切换时的MPU上下文保存与恢复。