第三十二章 MPU——内存保护单元

第三十二章 MPU——内存保护单元

目录

第三十二章 MPU——内存保护单元

1 MPU功能概述

1.1 基本概念

1.2 关键术语

2 MPU核心功能

2.1 内存区域划分

2.2 访问权限控制

2.3 内存属性配置

3 应用场景

4 注意事项

5 程序设计

5.1 内存区域大小宏(SIZE字段)

5.2 内存类型与缓存策略宏(C和S字段)

5.3 访问权限宏(AP字段)

5.4 设置内存保护规则

5.5 主函数main()

6 下载验证

7 总结


MPUMemory Protection Unit,内存保护单元)是W55MH32中用于管理内存区域访问权限与属性的关键模块。它通过划分内存区域并设置访问规则(如读//执行权限、缓存策略),增强系统的安全性和稳定性,尤其适用于多任务系统(如RTOS)或需要隔离关键资源的场景。

1 MPU功能概述

1.1 基本概念

MPUW55MH32内置的硬件模块,不支持虚拟内存(与MMU不同),但能通过物理内存区域划分实现以下功能:

  • 限制任务/程序对特定内存区域的访问(如禁止写、禁止执行)。
  • 定义内存区域的属性(如缓存策略、共享性),优化系统性能。
  • 检测非法内存访问(如越界、权限违规),触发异常(如 MemManage Fault),避免系统崩溃。

1.2 关键术语

  • 内存区域(RegionMPU 将内存划分为多个独立区域,每个区域需配置基地址、大小、权限等参数。
  • 访问权限(Access Permission:定义区域的读(R)、写(W)、执行(X)权限(如仅读、可读可写、不可执行)。
  • 内存属性(Memory Attribute:包括缓存策略(如无缓存、写通、写回)、共享性(是否被多处理器共享)等,影响数据访问效率。

2 MPU核心功能

2.1 内存区域划分

MPU通过配置区域基地址(Base Address)和区域大小(Size),将物理内存划分为多个独立区域。

  • 大小限制:区域大小必须是2的幂次(如32B64B1KB64KB等),且基地址需对齐到区域大小(例如 64KB 区域的基地址必须是 64KB 的整数倍)。
  • 区域重叠:若多个区域重叠,编号大的区域优先级更高(覆盖小编号区域的配置)。

2.2 访问权限控制

每个区域可独立设置特权级(Privileged)和用户级(Unprivileged)的访问权限(如 RTOS 中内核运行在特权级,任务运行在用户级)。常见权限组合如下:

权限类型

说明

PRIV_RW

特权级可读可写,用户级无权限

PRIV_RW_USER_RO

特权级可读可写,用户级仅可读

PRIV_RO

特权级仅可读,用户级无权限

NO_ACCESS

任何级别均不可访问(用于标记非法区域)

2.3 内存属性配置

通过设置内存类型(Memory Type)和缓存策略(Cache Policy),优化数据访问效率:

  • 内存类型:如普通内存(Normal)、设备内存(Device)。
    • 普通内存:支持缓存(如SRAM中的变量)。
    • 设备内存:通常为外设寄存器(如 GPIOUART),需禁用缓存(避免缓存导致的读写延迟)。
  • 缓存策略:
    • 无缓存(Non-Cacheable):直接访问物理内存(如设备寄存器)。
    • 写通(Write-Through):写数据时同时更新缓存和内存(适合需要实时性的场景)。
    • 写回(Write-Back):写数据时仅更新缓存,后续统一写入内存(适合高频读写场景,提升效率)。

3 应用场景

MPU的核心价值在于内存安全防护和资源隔离,以下是其典型应用场景,结合核心功能说明其实际意义:

  • RTOS任务隔离(多任务系统核心需求):在RTOS(实时操作系统)中,多个任务共享同一内存空间,若未隔离可能因任务异常(如栈溢出、野指针)导致系统崩溃。MPU通过区域划分与权限控制实现任务隔离。
  • 关键数据/代码保护(防篡改与误操作):系统中某些数据或代码(如固件、校准参数、加密密钥)一旦被修改,可能导致功能失效或安全漏洞。MPU通过只读或禁止访问权限保护这些资源。
  • 外设寄存器访问控制(防止误操作外设):外设寄存器(如GPIOUART的控制寄存器)的错误修改可能导致外设异常。MPU限制仅特权级代码(如内核)可修改关键寄存器。
  • 内存越界检测(开发调试辅助):开发阶段,程序可能因数组越界、野指针等错误访问未分配内存。MPU将未使用的内存区域配置为NO_ACCESS(无访问权限),触发异常以快速定位问题。
  • 安全启动与固件保护(系统级安全需求):在需要安全启动的系统中(如医疗设备、工业控制),MPU保护启动代码和安全配置区域,确保系统从可信代码启动。

4 注意事项

引脚驱动能力MCO输出频率不宜过高(需低于GPIO的最大可靠频率,通常建议不超过50MHz),高频时需考虑信号完整性(如阻抗匹配)。

时钟源使能顺序:配置MCO前需确保时钟源已稳定(如HSE起振完成),避免输出无效信号。

5 程序设计

MPU的核心配置通过RASRRegion Attribute and Size Register,区域属性与大小寄存器)实现,具体配置步骤如下:

5.1 内存区域大小宏(SIZE字段)

#define MPU_DEFS_RASR_SIZE_1KB       (0x09 << MPU_RASR_SIZE_Pos)
#define MPU_DEFS_RASR_SIZE_16KB      (0x0D << MPU_RASR_SIZE_Pos)
#define MPU_DEFS_RASR_SIZE_64KB      (0x0F << MPU_RASR_SIZE_Pos)

作用:设置内存区域的大小。

原理:RASRSIZE字段(位 [5:0])用于定义区域大小,实际大小为2(SIZE+1)字节。

  • 0x09对应SIZE=9,计算得210=1024字节(1KB);
  • 0x0D对应SIZE=13,计算得214=16384字节(16KB);
  • 0x0F对应SIZE=15,计算得216=65536字节(64KB)。

5.2 内存类型与缓存策略宏(CS字段)

#define MPU_DEFS_NORMAL_MEMORY_WT    (MPU_RASR_C_Msk | MPU_RASR_S_Msk)

作用:定义普通内存的直写(Write-Through, WT)缓存策略。

原理:

  • C_Msk(位 [16]):使能缓存(Cacheable);
  • S_Msk(位 [18]):标记为共享内存(Sharable),用于多主设备(如 CPU DMA)访问时的一致性;
  • 组合后表示 “可缓存、共享的直写内存”(写操作直接更新内存,不经过缓存)。

5.3 访问权限宏(AP字段)

#define MPU_DEFS_RASE_AP_FULL_ACCESS (0x3 << MPU_RASR_AP_Pos)

作用:设置内存区域的完全访问权限(无限制)。

原理:RASRAP字段(位 [23:21])定义访问权限,0x3表示:

  • 特权模式(Privileged)允许读/写;
  • 用户模式(User)允许读/写(无限制访问)。

5.4 设置内存保护规则

内存保护规则由MPU_Set()函数实现,函数内容如下:

{
    SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
 
    mpu_disable();
    mpu_region_config(0, 0x8000000, MPU_DEFS_RASR_SIZE_64KB,
                      MPU_DEFS_NORMAL_MEMORY_WT | MPU_DEFS_RASE_AP_FULL_ACCESS | MPU_RASR_ENABLE_Msk);
    mpu_region_config(1, 0x20000000, MPU_DEFS_RASR_SIZE_16KB,
                      MPU_DEFS_NORMAL_MEMORY_WT | MPU_DEFS_RASE_AP_FULL_ACCESS | MPU_RASR_ENABLE_Msk);
    mpu_region_config(2, USART1_BASE, MPU_DEFS_RASR_SIZE_1KB,
                      MPU_DEFS_NORMAL_MEMORY_WT | MPU_DEFS_RASE_AP_FULL_ACCESS | MPU_RASR_ENABLE_Msk);
    mpu_region_disable(3);
    mpu_region_disable(4);
    mpu_region_disable(5);
    mpu_region_disable(6);
    mpu_region_disable(7);
 
    mpu_enable();
}

该函数首先使能了内存错误(MemFault)异常,以便检测非法内存访问;随后禁用MPU(配置前需禁用以避免冲突),依次配置3个内存区域:

  • 区域0(起始地址0x800000064KB,对应Flash
  • 区域1(起始地址0x2000000016KB,对应RAM
  • 区域2(起始地址USART1_BASE1KB,对应串口1外设寄存器)

3个区域均设置为“直写缓存+完全访问权限”并启用;接着禁用未使用的区域3~7MPU通常支持8个区域,未使用的需禁用以防意外访问);最后启用MPU,使所有配置的内存保护规则生效,确保FlashRAM及串口外设的访问受限于预设的大小、权限和缓存策略,提升系统内存访问的安全性与稳定性。

5.5 主函数main()

主函数main()的内容如下:

int main(void)
{
    RCC_ClocksTypeDef clocks;
 
    delay_init();
    UART_Configuration(115200);
    RCC_GetClocksFreq(&clocks);
 
    printf("\n");
    printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhz\n",
           (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000,
           (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000);
    printf("MPU Test.\n");
 
    printf("MPU->TYPE, Value: 0x%x\n", MPU->TYPE);
    printf("MPU->CTRL, Value: 0x%x\n", MPU->CTRL);
    printf("MPU->RNR, Value: 0x%x\n", MPU->RNR);
    printf("MPU->RBAR, Value: 0x%x\n", MPU->RBAR);
    printf("MPU->RASR, Value: 0x%x\n", MPU->RASR);
    printf("MPU->RBAR_A1;, Value: 0x%x\n", MPU->RBAR_A1);
    printf("MPU->RASR_A1, Value: 0x%x\n", MPU->RASR_A1);
    printf("MPU->RBAR_A2, Value: 0x%x\n", MPU->RBAR_A2);
    printf("MPU->RASR_A2, Value: 0x%x\n", MPU->RASR_A2);
    printf("MPU->RBAR_A3, Value: 0x%x\n", MPU->RBAR_A3);
    printf("MPU->RASR_A3, Value: 0x%x\n\n", MPU->RASR_A3);
 
    printf("LimiteToPrivilege Access\n");
    SHOW_PrintFlash(0x08000000, 64);
 
    MPU_Set();
 
    printf("LimiteToUser Access\n");
    SHOW_PrintFlash(0x08000000, 64);
    while (1);
}

main()函数是MPU功能测试的主程序:首先初始化延时函数和串口(波特率115200),调用标准库获取系统各时钟域频率(SYSCLKHCLK等)并打印;接着打印MPU核心寄存器(TYPECTRL等)的初始状态用于调试;

随后调用MPU_Set配置内存保护规则,对比配置前后对Flash起始地址(0x08000000)前64字节的访问结果(特权模式与用户模式),验证MPU对内存访问权限的限制效果;最后进入无限循环保持运行。

6 下载验证

程序下载运行之后,首先打印了时钟信息,接着是MPU的相关寄存器初始状态信息,然后用特权限制访问内存成功,之后设置为用户访问,再次访问则无法读取内容:

7 总结

MCO功能通过灵活配置时钟源和分频系数,为W55MH32提供了对外输出时钟的能力,简化了系统设计中的时钟同步问题。先理解其应用场景(如多芯片同步、调试测量),再掌握配置步骤(时钟源选择、GPIO设置、分频配置),可更高效地应用于实际项目中。

### 关于ESP32MPU9255传感器的连接及使用 对于希望了解如何将ESP32MPU9255传感器相连以及具体应用方式的开发者而言,存在多个有价值的资源可以参考。一个全面的驱动程序库被提供给ESP32来支持不同类型的MPU传感器,其中包括了MPU9255,并且此库兼容SPI和I2C两种通信协议[^1]。 为了简化开发流程,官方提供了详细的指南说明怎样通过下载特定版本的ZIP包(例如针对MPU6050的设计)获取必要的源码文件,尽管这里提到的是MPU6050,但对于其他型号如MPU9255同样适用类似的步骤[^2]。这些资料通常会包含初始化过程、配置动态内存管理单元(DMP)的相关设置以及其他实用的例子演示如何解析来自IMU的数据以获得角度信息等重要参数。 另外,在某些情况下,当涉及到更复杂的特性实现时——比如DMP的支持,则可能需要额外注意一些细节上的差异或者做出适当修改才能使原有代码适应新的硬件环境[^5]。值得注意的是,虽然上述参考资料主要围绕着MPU6050展开讨论,但是由于两者之间存在着高度相似之处,因此大部分概念和技术要点可以直接迁移过来应用于MPU9255之上。 下面给出一段基于Arduino框架下的简单示例代码片段用于展示基本操作: ```cpp #include <Wire.h> #include "MPU9255.h" MPU9255 mySensor; void setup() { Serial.begin(115200); Wire.begin(); if (!mySensor.init()) { Serial.println("Failed to initialize sensor!"); while (true); // Stop everything. } } void loop() { sensors_event_t a, g, m; mySensor.getEvent(&a, &g, &m); Serial.print("Accel X: "); Serial.print(a.acceleration.x); Serial.print(", "); Serial.print("Y: "); Serial.print(a.acceleration.y); Serial.print(", "); Serial.print("Z: "); Serial.print(a.acceleration.z); Serial.println(" m/s^2"); delay(500); } ``` 这段代码实现了对加速度计数据的基本读取功能,其中`MPU9255.h`是假设已经安装好的第三方库的一部分,它负责处理底层通讯逻辑并向上层应用程序暴露易于使用的API接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值