全部例程

MPU - 内存保护单元

W55MH32

更新于 2026年8月13日

本篇总结

使用 MPU,配置内存区域访问权限,违规访问触发异常。

🔑 KEIL MDK、UART调试、MPU

本示例配置 MPU 保护 SRAM 区域并演示违规访问检测。

前置工具准备

开始本例程前,请确认以下工具已安装:

  • WIZ UartTool V1.0:串口收发测试工具:点击下载

硬件连接

本例程为纯软件功能,无需外部硬件连接。MPU 保护操作在芯片内部完成。USART1 用于输出调试信息。

引脚功能方向模式
PA9USART1_TX开发板 → PC复用推挽输出 (AF_PP)
PA10USART1_RXPC → 开发板浮空输入 (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_BaseAddressMPU_Size,如保护 Flash 区域 0x08000000
  • 设置只读权限 → 将 MPU_AccessPermission 改为 MPU_REGION_PRIV_RO,防止意外写入
  • 多区域保护 → 配置 Region 1~7 保护不同内存区域,各区域可重叠(高编号优先)

编译与下载

Keil MDK 中打开 MPU.uvprojxF7 编译,确认 0 Error(s)。连接 DEBUG USB 口到 PC,F8 下载。

运行验证

打开 WIZ UartTool V1.0,波特率 115200 / 8N1。下载固件并按 RESET 后,串口打印 "MPU configured. SRAM Region 0 protected."。如果程序尝试访问未授权的内存区域,将触发 HardFault,串口打印 "MPU Fault!" 和错误地址。

MPU内存保护测试串口输出
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 任务隔离等场景

下载本章例程

我们提供完整的工程文件以及配套开发板,方便你随时测试,快速完成产品开发:

开发环境: Keil MDK5 配套开发板

Andy

W5500 技术支持专家