STM32--MPU内存保护单元(二)
Posted Z小旋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32--MPU内存保护单元(二)相关的知识,希望对你有一定的参考价值。
上一篇我们说了MPU内存保护单元的基本原理跟寄存器,这一篇我们来说下HAL库的函数及基本配置
本章说的一些HAL库参数,请参照上篇寄存器说明部分:
首先我们来看一下在stm32h7xx_hal_cortex.h中的MPU_Region_InitTypeDef
MPU初始化结构体
该结构体参数如下:
typedef struct
uint8_t Enable; //区域使能/禁止
uint8_t Number; //区域编号
uint32_t BaseAddress; //配置区域基地址
uint8_t Size; //区域容量
uint8_t SubRegionDisable; //子 region 除能位段设置
uint8_t TypeExtField; //类型扩展级别
uint8_t AccessPermission; //设置访问权限
uint8_t DisableExec; //允许/禁止取指
uint8_t IsShareable; //禁止/允许共享
uint8_t IsCacheable; //禁止/允许缓存
uint8_t IsBufferable; //禁止/允许缓冲
MPU_Region_InitTypeDef;
下面我们来对这个结构体的各个参数进行讲解:
1.Enable
- 对应 MPU 控制寄存器(CTRL)的第0位 ENABLE 用于控制是否使能 MPU
对应HAL库参数如下:
/** @defgroup CORTEX_MPU_Region_Enable CORTEX MPU Region Enable
* @
*/
#define MPU_REGION_ENABLE ((uint8_t)0x01) //mpu使能
#define MPU_REGION_DISABLE ((uint8_t)0x00) //mpu关闭
2.Number
- 对应MPU 区域编号寄存器(RNR)来设置内存区序号的,用户配置的时候,推荐从 Number0 开始配置,最多到 Number15
共计 16 个。对应的 HAL 库参数如下
/** @defgroup CORTEX_MPU_Region_Number CORTEX MPU Region Number
* @
*/
#define MPU_REGION_NUMBER0 ((uint8_t)0x00)
#define MPU_REGION_NUMBER1 ((uint8_t)0x01)
#define MPU_REGION_NUMBER2 ((uint8_t)0x02)
#define MPU_REGION_NUMBER3 ((uint8_t)0x03)
#define MPU_REGION_NUMBER4 ((uint8_t)0x04)
#define MPU_REGION_NUMBER5 ((uint8_t)0x05)
#define MPU_REGION_NUMBER6 ((uint8_t)0x06)
#define MPU_REGION_NUMBER7 ((uint8_t)0x07)
#define MPU_REGION_NUMBER8 ((uint8_t)0x08)
#define MPU_REGION_NUMBER9 ((uint8_t)0x09)
#define MPU_REGION_NUMBER10 ((uint8_t)0x0A)
#define MPU_REGION_NUMBER11 ((uint8_t)0x0B)
#define MPU_REGION_NUMBER12 ((uint8_t)0x0C)
#define MPU_REGION_NUMBER13 ((uint8_t)0x0D)
#define MPU_REGION_NUMBER14 ((uint8_t)0x0E)
#define MPU_REGION_NUMBER15 ((uint8_t)0x0F)
3.BaseAddress
- MPU 基地址寄存器(RBAR)的ADDR位 来设置内存区的首地址。
0x24000000
0x60000000
......
4.Size
- RASR 寄存器的 SIZE 位,设置MPU区域的大小,SIZE 位使用的是 bit[5:1],共计 5 个 bit,可以表示 2^5 = 32 种大小
HAL 库给出了可以配置的 28 个参数:
/** @defgroup CORTEX_MPU_Region_Size CORTEX MPU Region Size
* @
*/
#define MPU_REGION_SIZE_32B ((uint8_t)0x04)
#define MPU_REGION_SIZE_64B ((uint8_t)0x05)
#define MPU_REGION_SIZE_128B ((uint8_t)0x06)
#define MPU_REGION_SIZE_256B ((uint8_t)0x07)
#define MPU_REGION_SIZE_512B ((uint8_t)0x08)
#define MPU_REGION_SIZE_1KB ((uint8_t)0x09)
#define MPU_REGION_SIZE_2KB ((uint8_t)0x0A)
#define MPU_REGION_SIZE_4KB ((uint8_t)0x0B)
#define MPU_REGION_SIZE_8KB ((uint8_t)0x0C)
#define MPU_REGION_SIZE_16KB ((uint8_t)0x0D)
#define MPU_REGION_SIZE_32KB ((uint8_t)0x0E)
#define MPU_REGION_SIZE_64KB ((uint8_t)0x0F)
#define MPU_REGION_SIZE_128KB ((uint8_t)0x10)
#define MPU_REGION_SIZE_256KB ((uint8_t)0x11)
#define MPU_REGION_SIZE_512KB ((uint8_t)0x12)
#define MPU_REGION_SIZE_1MB ((uint8_t)0x13)
#define MPU_REGION_SIZE_2MB ((uint8_t)0x14)
#define MPU_REGION_SIZE_4MB ((uint8_t)0x15)
#define MPU_REGION_SIZE_8MB ((uint8_t)0x16)
#define MPU_REGION_SIZE_16MB ((uint8_t)0x17)
#define MPU_REGION_SIZE_32MB ((uint8_t)0x18)
#define MPU_REGION_SIZE_64MB ((uint8_t)0x19)
#define MPU_REGION_SIZE_128MB ((uint8_t)0x1A)
#define MPU_REGION_SIZE_256MB ((uint8_t)0x1B)
#define MPU_REGION_SIZE_512MB ((uint8_t)0x1C)
#define MPU_REGION_SIZE_1GB ((uint8_t)0x1D)
#define MPU_REGION_SIZE_2GB ((uint8_t)0x1E)
#define MPU_REGION_SIZE_4GB ((uint8_t)0x1F)
5.SubRegionDisable
- MPU 区域属性和容量寄存器(RASR)的SRD位,关闭对应子区域使能
SRD 中的 8 个位,每个位控制一个 sub region 是否被除能。如 SRD.4=0,则 4 号 sub region
被除能。如果某个 sub region 被除能,且其对应的地址范围又没有落在其它 region 中,则对该
区的访问将引发 fault。
正常我们直接写0就行,就是Region的每个子区域都有效
6.TypeExtField
- MPU 区域属性和容量寄存器(RASR)的TEX位 Cache的扩展功能使能位
TEX 对应的 HAL 库 MPU 参数给了三个,实际应用中仅用到前两个 MPU_TEX_LEVEL0 和
MPU_TEX_LEVEL1
/** @defgroup CORTEX_MPU_TEX_Levels MPU TEX Levels
* @
*/
#define MPU_TEX_LEVEL0 ((uint8_t)0x00)
#define MPU_TEX_LEVEL1 ((uint8_t)0x01)
#define MPU_TEX_LEVEL2 ((uint8_t)0x02)
7.AccessPermission
- MPU 区域属性和容量寄存器(RASR)的AP 位 设置region内存区的权限
正常设置为MPU_REGION_FULL_ACCESS
全访问,都可以读写就可以
/** @defgroup CORTEX_MPU_Region_Permission_Attributes CORTEX MPU Region Permission Attributes
* @
*/
#define MPU_REGION_NO_ACCESS ((uint8_t)0x00)
#define MPU_REGION_PRIV_RW ((uint8_t)0x01)
#define MPU_REGION_PRIV_RW_URO ((uint8_t)0x02)
#define MPU_REGION_FULL_ACCESS ((uint8_t)0x03)
#define MPU_REGION_PRIV_RO ((uint8_t)0x05)
#define MPU_REGION_PRIV_RO_URO ((uint8_t)0x06)
//MPU_REGION_NO_ACCESS,无访问(特权&用户都不可访问)
//MPU_REGION_PRIV_RW,仅支持特权读写访问
//MPU_REGION_PRIV_RW_URO,禁止用户写访问(特权可读写访问)
//MPU_REGION_FULL_ACCESS,全访问(特权&用户都可访问)
//MPU_REGION_PRIV_RO,仅支持特权读访问
//MPU_REGION_PRIV_RO_URO,只读(特权&用户都不可以写)
8.DisableExec
- RASR 寄存器的 XN 位,XN=0 表示使能指令提取,即这块内存区可以执行程序代码,XN=1 表示禁止指令提取,即这块内存区禁止执行程序代码
/** @defgroup CORTEX_MPU_Instruction_Access CORTEX MPU Instruction Access
* @
*/
#define MPU_INSTRUCTION_ACCESS_ENABLE ((uint8_t)0x00)
#define MPU_INSTRUCTION_ACCESS_DISABLE ((uint8_t)0x01)
8.IsShareable
-RASR 寄存器的 S 位,用于位用于控制存储器的共享特性,S=1,则二级存储器不可以缓存(Cache),如果设置 S=0,则可以缓存(Cache),一般我们设置该位为 0 即可。
/** @defgroup CORTEX_MPU_Access_Shareable CORTEX MPU Instruction Access Shareable
* @
*/
#define MPU_ACCESS_SHAREABLE ((uint8_t)0x01)
#define MPU_ACCESS_NOT_SHAREABLE ((uint8_t)0x00)
9.IsCacheable
- RASR 寄存器的 C位,用于使能或者禁止Cache
/** @defgroup CORTEX_MPU_Access_Cacheable CORTEX MPU Instruction Access Cacheable
* @
*/
#define MPU_ACCESS_CACHEABLE ((uint8_t)0x01)
#define MPU_ACCESS_NOT_CACHEABLE ((uint8_t)0x00)
10.IsBufferable
- RASR 寄存器的 B位,用于配合C位实现Cache下是否使用缓冲
/** @defgroup CORTEX_MPU_Access_Bufferable CORTEX MPU Instruction Access Bufferable
* @
*/
#define MPU_ACCESS_BUFFERABLE ((uint8_t)0x01)
#define MPU_ACCESS_NOT_BUFFERABLE ((uint8_t)0x00)
关于MPU还有几个函数:
禁止和使能 MPU 以及 MemManage 中断。
HAL 库中使能 MPU 以及 MemManage 中断函数:
__STATIC_INLINE void HAL_MPU_Enable(uint32_t MPU_Control);
参数:MPU_Control
MPU_HFNMI_PRIVDEF_NONE ((uint32_t)0x00000000)
- 此参数设置 MPU 的 CTL 控制寄存器的 PRIVDEFENA 位为 0。
- 表示禁止了背景区,访问任何未使能 MPU 的区域均会造成内存异常 MemFault。
- 此参数设置 MPU 的 CTL 控制寄存器的 HFNMIENA 位为 0。
- 表示 NMI 不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会关闭 MPU。
MPU_HARDFAULT_NMI ((uint32_t)0x00000002)
- 此参数设置 MPU 的 CTL 控制寄存器的 PRIVDEFENA 位为 0。
- 表示使能了背景区,访问任何未使能 MPU 的区域均会造成内存异常 MemFault。
- 此参数设置 MPU 的 CTL 控制寄存器的 HFNMIENA 位为 1。
- 表示 NMI 不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会保持继续开启 MPU。
MPU_PRIVILEGED_DEFAULT ((uint32_t)0x00000004)
- 此参数设置 MPU 的 CTL 控制寄存器的 PRIVDEFENA 位为 1。
- 表示使能了背景区,特权级模式可以正常访问任何未使能 MPU 的区域。
- 此参数设置 MPU 的 CTL 控制寄存器的 HFNMIENA 位为 0。
- 表示 NMI 不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会关闭 MPU。
MPU_HFNMI_PRIVDEF ((uint32_t)0x00000006)
- 此参数设置 MPU 的 CTL 控制寄存器的 PRIVDEFENA 位为 1。
- 表示禁止了背景区,访问任何未使能 MPU 的区域均会造成内存异常 MemFault。
- 此参数设置 MPU 的 CTL 控制寄存器的 HFNMIENA 位为 1。
- 表示 NMI 不可屏蔽中断服务程序和硬件异常中断服务程序执行期间会保持继续开启 MPU。
正常我们使用的是 MPU_PRIVILEGED_DEFAULT
即使能背景区,异常中断关闭MPU
禁止函数为:
__STATIC_INLINE void HAL_MPU_Disable(void);
下面我们设置下H7的FMC区域保护
//保护 MCU的FMC块1 区域,,共 64M 字节
//BaseAddress:MPU 保护区域的基址(首地址)
//Size:MPU 保护区域的大小(必须是 32 的倍数,单位为字节)
//可设置的值参考:CORTEX_MPU_Region_Size
//Number:MPU 保护区编号,范围:0~15,最大支持 16个保护区域
//可设置的值参考:CORTEX_MPU_Region_Number
//AccessPermission:访问权限,访问关系如下:
//可设置的值参考:CORTEX_MPU_Region_Permission_Attributes
//MPU_REGION_NO_ACCESS,无访问(特权&用户都不可访问)
//MPU_REGION_PRIV_RW,仅支持特权读写访问
//MPU_REGION_PRIV_RW_URO,禁止用户写访问(特权可读写访问)
//MPU_REGION_FULL_ACCESS,全访问(特权&用户都可访问)
//MPU_REGION_PRIV_RO,仅支持特权读访问
//MPU_REGION_PRIV_RO_URO,只读(特权&用户都不可以写)
//详见:STM32H7 Series Cortex-M7 processor programming manual.pdf,4.6 节,Table 89.
void MPU_Set_Protection()
MPU_Region_InitTypeDef MPU_Initure;
HAL_MPU_Disable(); //配置 MPU 之前先关闭 MPU,配置完成以后在使能 MPU
MPU_Initure.Enable=MPU_REGION_ENABLE; //使能该保护区域
MPU_Initure.Number=MPU_REGION_NUMBER0; //设置保护区域编号
MPU_Initure.BaseAddress=0x60000000; //设置基址
MPU_Initure.Size=MPU_REGION_SIZE_64MB; //设置保护区域大小
MPU_Initure.SubRegionDisable=0X00; //禁止子区域
MPU_Initure.TypeExtField=MPU_TEX_LEVEL0; //设置类型扩展域为 level0
MPU_Initure.AccessPermission=MPU_REGION_FULL_ACCESS; //设置访问权限,
MPU_Initure.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE; //允许指令访问
MPU_Initure.IsShareable=MPU_ACCESS_NOT_SHAREABLE; //禁止共用
MPU_Initure.IsCacheable=MPU_ACCESS_CACHEABLE; //使能 cache
MPU_Initure.IsBufferable=MPU_ACCESS_BUFFERABLE; //允许缓冲
HAL_MPU_ConfigRegion(&MPU_Initure); //配置 MPU
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); //开启 MPU
从 0x60000000 地址开始的 64MB 地址空间,禁止共用,禁止 cache,禁止缓冲。保证FMC数据的正常传输。可以提高代码的稳定性(其实就是减少使用 cache 导致的各种莫名奇妙的问题)
因为STM32H7的FMC是从0x60000000
开始的,然后分成了4个块,我们保护块1 所以起始地址为0x60000000
保护区域大小为MPU_REGION_SIZE_64MB
如果发生异常,则进入MemManage 中断,中断内容用户可自行编写
//MemManage 错误处理中断
//进入此中断以后,将无法恢复程序运行!!
void MemManage_Handler(void)
以上是关于STM32--MPU内存保护单元(二)的主要内容,如果未能解决你的问题,请参考以下文章
STM32+MPU6050设计便携式Mini桌面时钟(自动调整时间显示方向)