本篇总结
使用 MPU,配置内存区域访问权限,违规访问触发异常。
🔑 KEIL MDK、UART调试、MPU
本示例配置 MPU 保护 SRAM 区域并演示违规访问检测。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口收发测试工具:点击下载
硬件连接
本例程为纯软件功能,无需外部硬件连接。MPU 保护操作在芯片内部完成。USART1 用于输出调试信息。
| 引脚 | 功能 | 方向 | 模式 |
| PA9 | USART1_TX | 开发板 → PC | 复用推挽输出 (AF_PP) |
| PA10 | USART1_RX | PC → 开发板 | 浮空输入 (IN_FLOATING) |
工程结构
工程位于 SDK 内 1.SDK\ModuleDemo\MPU\,核心文件如下:
MPU/
├── USER/
│ ├── main.c ← MPU配置 + 区域保护 + HardFault检测
│ ├── w55mh32_conf.h ← 外设头文件集中包含
│ ├── w55mh32_it.c/h ← 中断服务函数(HardFault_Handler)
│ ├── system_w55mh32.c/h← 系统初始化(时钟配置)
│ └── startup_w55mh32.s ← 启动文件
└── SYSTEM/
└── delay/
└── delay.c/h ← SysTick 延时函数
步骤1:MPU 区域配置与保护
文件:USER/main.c — 配置 MPU Region 0 保护 SRAM 区域(0x20000000,64KB),设置完全访问权限。HardFault 中断中检测 MPU 错误并打印错误地址。
void MPU_Configuration(void)
{
MPU_Region_InitTypeDef MPU_InitStructure;
/* 使能 MPU */
MPU_Cmd(ENABLE);
/* 配置 Region 0:Protect SRAM 区域(0x20000000 ~ 0x2000FFFF) */
MPU_InitStructure.MPU_Enable = MPU_REGION_ENABLE;
MPU_InitStructure.MPU_Number = MPU_REGION_NUMBER0;
MPU_InitStructure.MPU_BaseAddress = 0x20000000;
MPU_InitStructure.MPU_Size = MPU_REGION_SIZE_64KB;
MPU_InitStructure.MPU_SubRegionDisable = 0x00;
MPU_InitStructure.MPU_TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStructure.MPU_AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStructure.MPU_DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStructure.MPU_IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStructure.MPU_IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStructure.MPU_IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_RegionConfig(&MPU_InitStructure);
/* 使能 MPU 时发生内存访问违例时触发 HardFault */
MPU_Control(MPU_HFNMI_PRIVDEF_NONE | MPU_PRIVILEGED_DEFAULT);
}
/* HardFault 中断中检测 MPU 错误 */
void HardFault_Handler(void)
{
if ((SCB->CFSR & SCB_CFSR_MMARVALID) != 0)
{
printf("MPU Fault! Address: 0x%08X\n", SCB->MMFAR);
}
while (1); /* 死循环等待调试 */
}
int main(void)
{
RCC_ClocksTypeDef clocks;
delay_init();
UART_Configuration(115200);
RCC_GetClocksFreq(&clocks);
printf("MPU Test.\n");
MPU_Configuration();
printf("MPU configured. SRAM Region 0 protected.\n");
while (1);
}
MPU 配置流程:使能 MPU → 配置区域(基地址、大小、权限、缓存属性)→ 设置 MPU 控制模式。每个区域可设置不同权限:MPU_REGION_NO_ACCESS(不可访问)、MPU_REGION_PRIV_RW(特权读写)、MPU_REGION_FULL_ACCESS(完全访问)。违规访问触发 MemManage Fault,进而升级为 HardFault。
如果你想自定义
- 保护其他区域 → 修改
MPU_BaseAddress 和 MPU_Size,如保护 Flash 区域 0x08000000
- 设置只读权限 → 将
MPU_AccessPermission 改为 MPU_REGION_PRIV_RO,防止意外写入
- 多区域保护 → 配置 Region 1~7 保护不同内存区域,各区域可重叠(高编号优先)
编译与下载
Keil MDK 中打开 MPU.uvprojx,F7 编译,确认 0 Error(s)。连接 DEBUG USB 口到 PC,F8 下载。
运行验证
打开 WIZ UartTool V1.0,波特率 115200 / 8N1。下载固件并按 RESET 后,串口打印 "MPU configured. SRAM Region 0 protected."。如果程序尝试访问未授权的内存区域,将触发 HardFault,串口打印 "MPU Fault!" 和错误地址。
WIZ UartTool V1.0 显示 MPU 测试:区域保护配置成功,违规访问时打印错误地址
常见问题
Q: 使能 MPU 后程序立即 HardFault
MPU 配置不正确可能导致合法内存访问被拦截。确保 MPU_Control 使用 MPU_PRIVILEGED_DEFAULT 为未配置区域提供默认访问权限。检查区域地址和大小是否正确。
Q: MPU 区域数量不够用
Cortex-M3 的 MPU 支持 8 个区域(Region 0~7)。多个区域可以重叠,高编号区域的属性优先。合理规划区域分配,使用子区域禁用(SubRegionDisable)在区域内细分权限。
Q: HardFault 中断中无法打印信息
HardFault 中断中 printf 可能不工作(栈可能已损坏)。可将错误地址存入全局变量,在中断返回后处理。或使用 ITM/SEGGER RTT 等调试输出方式。确保 HardFault_Handler 有足够的栈空间。
总结
本文基于 W55MH32L 的 MPU(内存保护单元)实现了内存区域保护:
- MPU 8 个区域:每个区域可独立设置基地址、大小、访问权限和缓存属性
- 配置 Region 0 保护 SRAM(0x20000000,64KB),设置访问权限为完全访问
- 违规访问触发 MemManage Fault → HardFault,可在中断中检测并打印错误地址
- MPU 适用于检测内存越界、栈溢出、保护关键数据区域、实现 RTOS 任务隔离等场景