当前位置: 首页 > article >正文

ARM学习(42)CortexM3/M4 MPU配置

笔者之前学习过CortexR5的MPU配置,现在学习一下CortexM3/M4 MPU配置

1、背景介绍

笔者在工作中遇到NXP MPU在访问异常地址时,就会出现总线挂死,所以需要MPU抓住异常,就需要配置MPU。具体背景情况可以参考ARM学习(41)NXP MCU总线挂死,CPU could not be halted以及无法连接Jink。笔者之前还研究了Cortex-R5的MPU配置。

比如经常出现如下场景:
在这里插入图片描述
NXP的MCU使用的是LPC64016系列,是有配置MPU的。功能特点如下:
在这里插入图片描述
然后笔者又搜索了一下ST的芯片,主要针对F1和F4系列,F1大部分MCU没有配置MPU,F4基本都配置了MPU。具体得可以去下载ST的MCU手册,ST官网MCU系列,STMCU文档下载地址。
STM32F1系列只有STM32F10xxF、10xxG的才有MPU,比如101xF、103xF或者105xF系列,这些系列有个共同的特点就是Flash大,从768K到1MB。
在这里插入图片描述

STM32F4基本都配置MPU,其属于中高端产品。
在这里插入图片描述

STM32的产品 性能以及内核架构如下图所示。

在这里插入图片描述

2、MPU配置介绍

CortexM3、M4的MPU配置主要是几个寄存器的配置,可以配置MPU的region、访问权限和地址大小等属性。
寄存器主要有如下几个:

寄存器名字访问权限地址说明
MPU_TypeRO(只读)0xE000ED90说明MPU的region个数,默认是8,不可修改
MPU_CTRLRW(读写)0xE000ED94主要是使能MPU
MPU_RNRRW(读写)0xE000ED98选择使能的MPU region,可选
MPU_RBARRW(读写)0xE000ED9CMPU 属性以及size配置
MPU_RASRRW(读写)0xE000EDA0MPU保护的基地址配置

接下来具体看一下其配置信息。

2.1 MPU Type

只读寄存器,中间8位有效,可以读出数据来。
在这里插入图片描述
实际测试如下:
在这里插入图片描述

printf("mpu region=%d\r\n",(MPU->TYPE >>8)&0xff);

2.2 MPU CTRL

可读可写寄存器,

  • 背景region的作用,如果不打开,默认都不可访问,可以少一个region
  • NMI以及hardfault中断对mpu的操作
  • 使能MPU的操作
    在这里插入图片描述
    笔者来测试一下BIT2,不打开背景region,然后把region 0的4G区域关闭,然后使能MPU,代码如下:
    /* Disable MPU */
    ARM_MPU_Disable();
	
	/**省略保护区域配置**/
	
     /* Enable MPU */
    ARM_MPU_Enable(0);

异常代码还一样

    int* test_data_ptr = ( int*)0xF0000000;
    *test_data_ptr = 0x1234;
    printf("*test_data_ptr=%d\r\n",*test_data_ptr);

测试结果如下:可以看到异常已经抓到,数据地址是0xF0000000,代码地址10000348A,可以在trace32上面看到,说明背景region起作用了,保护了非法地址。
在这里插入图片描述
在这里插入图片描述
再来看一下,打开region,使得可以全部可以访问,但是异常地址没有保护,代码如下:

    /* Disable MPU */
    ARM_MPU_Disable();
	
	/**省略保护区域配置**/

     /* Enable MPU */
    ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);

测试结果如下,总线直接挂死,然后没有任何反应。
在这里插入图片描述
结论:

  • 如果是裸机系统,该BIT位可以作为一个背景region,其他region可以保护更多的区域,相当于增加了一个全局region的处理。
  • 如果有操作系统的情况下,可以限制用户对特殊代码的访问。
    在这里插入图片描述

2.3 MPU RNR

选择对应的region,进行属性和地址配置,往往不用这个寄存器,通过其他方式处理。
在这里插入图片描述

2.4 MPU RASR

MPU属性配置寄存器,配置权限访问,以及cacheable,共享等属性。
在这里插入图片描述
主要是两个属性:

  • 一个是访问属性,如上图所示
  • 另外一个是cache等属性,如下表所示
TEXCBS存储器类型描述说明
000001严格顺序严格顺序,总是共享
000011设备共享的设备
000100/1普通片外或者片内写通cache,不写分配
000110/1普通片外或者片内写回cache,不写分配
001000/1普通None-Cacheable
001010/1N/AN/A
001100/1N/AN/A
001110/1普通片外或者片内写回cache,读写分配
0101x0/1设备不共享的设备
010010/1N/AN/A
0101x0/1N/AN/A
1BBAA0/1N/ACache Memory,BB是片外,AA是片内
AA and BBCache类型
00None-Cachelable(没有cache)
01write back,write and read allocate(写回,读写分配cache)
10write through,no write allocate(写通,不写分配)
11write back,no write allocate(写回,不写分配)

再来看一下一般的设备如何配置

Typememory Type配置信息
ROM/Flash/Normal memoryTEX=0,C=1,B=0,S=0,没有share,写通cache
01Normal memoryTEX=0,C=1,B=0,S=1,共享,写通cache
10Normal memoryTEX=0,C=1,B=1,S=1,共享,写回cache
11DeviceTEX=0,C=0,B=1,S=1,共享Devices

2.5 MPU RBAR

在这里插入图片描述
可以通过region字段覆盖 RNR寄存器的region配置,所以减少一个寄存器的操作。

  • 基地址要以容量的大小进行对齐(即基地址可以整除容量),这样设计会让硬件设计简单。
  • 容量的大小最低从32开始,都是2的次幂,用编码表示其大小。 容量=1<< (容量编码+1)
#define ARM_MPU_REGION_SIZE_32B      ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes
#define ARM_MPU_REGION_SIZE_64B      ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes
#define ARM_MPU_REGION_SIZE_128B     ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes
#define ARM_MPU_REGION_SIZE_256B     ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes
#define ARM_MPU_REGION_SIZE_512B     ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes
#define ARM_MPU_REGION_SIZE_1KB      ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte
#define ARM_MPU_REGION_SIZE_2KB      ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes
#define ARM_MPU_REGION_SIZE_4KB      ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes
#define ARM_MPU_REGION_SIZE_8KB      ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes
#define ARM_MPU_REGION_SIZE_16KB     ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes
#define ARM_MPU_REGION_SIZE_32KB     ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes
#define ARM_MPU_REGION_SIZE_64KB     ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes
#define ARM_MPU_REGION_SIZE_128KB    ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes
#define ARM_MPU_REGION_SIZE_256KB    ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes
#define ARM_MPU_REGION_SIZE_512KB    ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes
#define ARM_MPU_REGION_SIZE_1MB      ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte
#define ARM_MPU_REGION_SIZE_2MB      ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes
#define ARM_MPU_REGION_SIZE_4MB      ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes
#define ARM_MPU_REGION_SIZE_8MB      ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes
#define ARM_MPU_REGION_SIZE_16MB     ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes
#define ARM_MPU_REGION_SIZE_32MB     ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes
#define ARM_MPU_REGION_SIZE_64MB     ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes
#define ARM_MPU_REGION_SIZE_128MB    ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes
#define ARM_MPU_REGION_SIZE_256MB    ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes
#define ARM_MPU_REGION_SIZE_512MB    ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes
#define ARM_MPU_REGION_SIZE_1GB      ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte
#define ARM_MPU_REGION_SIZE_2GB      ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes
#define ARM_MPU_REGION_SIZE_4GB      ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes

3、实际例子测试

笔者来看一下MPU的配置代码。

region号基地址长度属性
00x000000004G不可访问,背景region,TEX=0,S=0,C=1,B=0,不共享,写通cache
10x00000000256KB可访问,TEX=0,S=0,C=1,B=0,不共享,片外或者片内写通cache,不写分配,普通memory
20x0300000064KB可访问,TEX=0,S=0,C=1,B=0,不共享,片外或者片内写通cache,不写分配,普通memory
30x100000008MB只读,TEX=0,S=0,C=1,B=0,不共享,片外或者片内写通cache,不写分配,普通memory
40x20000000128KB可访问,TEX=0,S=0,C=1,B=0,不共享,片外或者片内写通cache,不写分配,普通memory
50x40000000256MB可访问,TEX=0,S=1,C=0,B=1,共享Devices,没有cahce
60xE00000001MB可访问,EX=0,S=1,C=0,B=1,共享Devices,没有cahce
void mpu_config()
{
    /* Disable MPU */
    ARM_MPU_Disable();

    /* Region 0 setting: Memory with no access type, not shareable, write trough */
    MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_NONE, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_4GB);

    /* Region 1 setting: Memory with  full access type, not shareable, write trough */
    MPU->RBAR = ARM_MPU_RBAR(1, 0x00000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_256KB);

    /* Region 2 setting: Memory with  full  access type, shareable, none-cacheable */
    MPU->RBAR = ARM_MPU_RBAR(2, 0x03000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64KB);

    /* Region 3 setting: Memory with  read-only  access type, not shareable, write trough */
    MPU->RBAR = ARM_MPU_RBAR(3, 0x10000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_8MB);

    /* Region 4 setting: Memory with  full  access type, not shareable, write trough */
    MPU->RBAR = ARM_MPU_RBAR(4, 0x20000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_128KB);

    /* Region 5 setting: Memory with  full  access type, shareable, none-cacheable */
    MPU->RBAR = ARM_MPU_RBAR(5, 0x40000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 1, 0, 1, 0, ARM_MPU_REGION_SIZE_256MB);

    /* Region 6 setting: Memory with  full  access type, shareable, none-cacheable */
    MPU->RBAR = ARM_MPU_RBAR(6, 0xE0000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 1, 0, 1, 0, ARM_MPU_REGION_SIZE_1MB);

     /* Enable MPU */
    ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_HFNMIENA_Msk);
}

笔者是基于这款芯片的memory创立的,然后根据芯片的地址等情形,可以确认相关memory的MPU配置属性。
在这里插入图片描述
然后笔者还碰到一个问题,之前不了解FW会调用0x03000000 ROM Code 的函数,所以这个区域没有配置,结果就访问异常了。错误类型也是指令访问异常。
在这里插入图片描述
在这里插入图片描述
笔者尝试配置rom code为只读测试一下,之前配置的时候,可读可写。
结论:配置这样也可以访问。

    /* Region 2 setting: Memory with  full  access type, shareable, none-cacheable */
    MPU->RBAR = ARM_MPU_RBAR(2, 0x03000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64KB);

2.6 subregion

再介绍一下subregion,就是一个region区域比较大,会被等分成8份,每份区域可以由一个bit去禁止。
所以可以配置更大的region,然后通过subregion再去细分。

这样笔者再新增一个region,然后禁止某些subregion,来做一些测试。
如下图代码所示,笔者打开了一个异常区域,0xF0000000,但是该区域的前128KB禁止,意味着其受背景region保护,访问进异常,但是其他区域可以访问,会导致总线挂死。

    /* Region 7 setting: Memory with  full  access type, shareable, none-cacheable */
    MPU->RBAR = ARM_MPU_RBAR(7, 0xF0000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 1, 0, 1, 1, ARM_MPU_REGION_SIZE_1MB);

如下图所示,该区域访问被抓住现场,地址0x100034AE,数据地址:0xF0000000。
在这里插入图片描述
在这里插入图片描述
如果全部区域都访问,则总线挂死,无法调试。

    /* Region 6 setting: Memory with  full  access type, shareable, none-cacheable */
    MPU->RBAR = ARM_MPU_RBAR(7, 0xF0000000);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 1, 0, 1, 0, ARM_MPU_REGION_SIZE_1MB);

在这里插入图片描述

4、参考

1、STM32F1-F4参考手册以及下载
2、Cortex M3/CM4权威指南
3、Cortex M3权威指南中文版


http://www.kler.cn/a/508966.html

相关文章:

  • postcss插件-实现vw适配
  • Chrome谷歌浏览器如何能恢复到之前的旧版本
  • Vue2.0的安装
  • 单元测试与unittest框架
  • 第34天:Web开发-PHP应用鉴别修复AI算法流量检测PHP.INI通用过滤内置函数
  • 【服务治理中间件】consul介绍和基本原理
  • 如何升级node.js版本
  • o.h.engine.jdbc.spi.SqlExceptionHelper : Zero date value prohibited
  • Java 文件操作
  • 【蓝桥杯】43689.包子凑数
  • 【Vue】vue3 video 保存视频进度,每次进入加载上次的视频进度
  • Linux的几个基本指令
  • 【华为战报】2024年12月 HCIP考试战报!
  • PHP版接口调试工具(自定义GET|POST|COOKIE|HEADER|User Agent|来路Referer)
  • 【20】Word:小许-质量管理-论文❗
  • 免费送源码:Java+ssm+MySQL 图书借阅管理系统的设计与实现 计算机毕业设计原创定制
  • 云部署服务器
  • 【青海省乡镇界】面图层+shp格式arcgis数据+乡镇名称和编码+wgs84坐标无偏移下载内容测评
  • 【React】class组件extends继承原理
  • Android系统开发(六):从Linux到Android:模块化开发,GKI内核的硬核科普
  • 使用Python爬虫获取1688网站item_get_company API接口的公司档案信息
  • 自学SpringBoot笔记
  • AIGC与劳动力市场:技术进步与就业结构的重塑
  • LeetCode 热题 100_子集(56_78_中等_C++)(回溯)(ans.clear())
  • Linux操作命令之Nginx基本功能
  • 搜维尔科技:Haption遥操作解决方案特点和优势