目录
[1 STM32H743 RAM简介.... 1](#1 STM32H743 RAM简介.... 1)
[1.1 ITCM.. 1](#1.1 ITCM.. 1)
[1.2 DTCM.. 2](#1.2 DTCM.. 2)
[1.3 AXI SRAM... 2](#1.3 AXI SRAM... 2)
[1.4 SRAM1、SRAM2、SRAM3. 2](#1.4 SRAM1、SRAM2、SRAM3. 2)
[1.5 SRAM4.. 5](#1.5 SRAM4.. 5)
[1.6 Backup SRAM... 5](#1.6 Backup SRAM... 5)
[2 各部分内存实际使用方式.... 5](#2 各部分内存实际使用方式.... 5)
[2.1 通过sct文件配置各部分内存段.... 5](#2.1 通过sct文件配置各部分内存段.... 5)
[2.2 使用不同内存段定义变量.... 8](#2.2 使用不同内存段定义变量.... 8)
- STM32H743 MPU简介
MPU 即内存保护单元,F1和F4系列也有,但是基本不用,H7为什么要使用MPU了呢?因为要使用Cache来提高性能,使用Cache的前提是必须配置MPU,所以H7的MPU基本上是用来支持Cache来使用的。
MPU 的主要功能是定义一些存储区域的访问规则, 简单的说就是内存保护、外设保护和代码访问保护,STM32H7 整个4GB存储映射空间都可以配置,但是归根结底MPU配置主要是配合Cache使用,所以后面也主要以这个为重点讲解。
-
- MPU功能实现,区域划分
MPU可以配置保护16个内存区域,每个内存区域叫做一个region(这16个内存域是独立配置的),region号范围是0-15,还有默认区 default region,也叫作背景区,序号-1。由于这些内存区可以嵌套和重叠,所以这些区域在嵌套或者重叠的时候有个优先级的问题。序号15的优先级最高,以此递减,序号-1,即背景区的优先级最低。这些优先级是固定的。

上共有7个区,背景区和序号0-5的区。内存区4跟内存区0和1有重叠部分,那么重叠部分将按照内存区4的配置规则执行;内存区5被完全包含在内存区3里面,那么这部分内存区将按照内存区5的配置规则执行。
每个区域最小要求256字节,每个区域还可以配置为8个子区域。由于子区域一般都相同大小,这样每个子区域的大小就是32字节,正好跟Cache的Cache Line大小一样。
特别解释:背景区在所有region中的优先级最低,是在4GB空间内除去所有定义好的region区域以外的区域,背景区不单独配置时,其内存类型和Cache的策略与所处区域的功能相关,每个区域会有不同的MPU属性和cache策略,如下:

特别注意:可以看到表中AXI SRAM、SRAM1-4等若没有配置MPU,Cache策略默认都是cacheable,write back,此时如果使能了cache,但是MPU没有配置,作为背景区,具有write back的cache的策略,就会出现cache与RAM数据一致性的问题,会导致数据错乱,因此如果使用Cache,建议将整个RAM区域中使用到的内存块,全部进行MPU配置,确定好是否使用cache,使用什么样的cache策略。
-
- MPU支持的三种内存类型:
- Normal(普通内存):用于存放代码和数据(如 Flash、SRAM),允许缓存,可以开启 Cache 来加速访问,可能乱序执行。常见的SRAM (DTCM, SRAM1/2/3/4) 中的变量、堆栈、缓冲区,Flash 中的代码段等。
- Device(设备内存):用于访问外设寄存器(如 UART、GPIO、TIM 的寄存器),不允许缓存,强制关掉 D-Cache,不会乱序执行,可缓存。包括所有外设寄存器区域(地址 0x40000000 开始)
- Strongly-Ordered(强顺序内存):最为严格的内存类型,通常用于系统控制区域,不允许缓存,强制关掉 D-Cache,不会乱序执行,不可缓存。包括系统控制寄存器(SCB、MPU 本身、NVIC等,地址 0xE0000000 开始)
其中前两种实际开发中用户最常用,第三种不常用,几乎不需要用户配置,这里需要注意的是,MPU的内存类型和Cache的策略类型不是一回事儿,Normal类型内存可能支持write back和write through类型的cache策略。
- MPU配置方法
- MPU参数详解
下面对MPU配置的各个参数进行说明,下图所示:

- Enable:表示该区域是否使能MPU的配置,这个肯定是配置成MPU_REGION_ENABLE,不然MPU的配置不生效没有意义;
- Number:该参数为当前配置区域的region号,范围是0-15,因为MPU支持16个区域的配置,并且区域号越大,不同区域地址重叠时优先级权限越高,有相应的宏定义,可直接使用,例如:MPU_REGION_NUMBER1;
- BaseAddress:MPU配置区域的起始地址,要求32字节对齐;
- Size:MPU配置区域的长度,要求32字节对齐,有相应的宏定义,可直接使用,例如:MPU_REGION_SIZE_512KB;
- SubRegionDisable:用于配置是否禁用特定的子区域。每个MPU配置的region区域可以再划分为8个子区域(固定划分为8个长度相等的子区域),每个子区域大小 = 区域总大小 / 8,每个子区域用一个 bit 来控制是否被禁用(即从该 MPU 区域中排除出去)。
Bit0-Bit7分别对应子区域0-子区域7
当bit值为0时,表示当前子区域可用,当bit值为1时,表示当前子区域禁用。
默认情况下该字段都填0,不禁用任何子区域。
- TypeExtField:简写为TEX,该字段配合C/B/S三个字段,共同用于设置MPU内存类型和Cache策略,该字段共三个值:MPU_TEX_LEVEL0、MPU_TEX_LEVEL1、MPU_TEX_LEVEL2,常用的只有前两个,第三个用不上;
- AccessPermission:表示当前区域的访问权限,一般配置MPU都是用来使用cache,所以该字段默认都赋值全部可访问:MPU_REGION_FULL_ACCESS
- DisableExec:表示该内存区域是否允许指令执行,一般存放数据的区域(如 SRAM、DMA Buffer)、栈空间(Stack)、堆(Heap)设置为禁止执行:MPU_INSTRUCTION_ACCESS_DISABLE;存放程序代码的区域(Flash)、用于跳转表的 RAM(如 BootLoader 跳转代码)设置为允许执行:MPU_INSTRUCTION_ACCESS_ENABLE
我们使用Cache基本都在RAM上,因此该字段直接设置成禁止执行 MPU_INSTRUCTION_ACCESS_DISABLE;
- IsShareable:简写为S,该字段需要配合TEX/C/B三个字段来使用,共同决定MPU内存类型和Cache策略。该字段指示当前内存区域是否可以多主控共享操作,手册中解释为多处理器之间是否可以共享一片内存的操作,例如双核CPU,两个CPU之间的共享,但是实际测试发现,如果单核CPU,在使用cache功能时使能了该字段的共享,虽然无多核操作,但是会影响cache的性能,甚至类似于no cache的情况,因此该区域配置MPU如果是为了使用cache提升性能,一定要把共享禁用,即配置为:MPU_ACCESS_NOT_SHAREABLE;
特别说明:该字段的共享指的是多处理器之间,CPU和DMA之间虽然可能都操作内存,但是不属于该字段控制的范畴,因此用于DMA数据处理的存储空间,该字段也要配置为禁止共享,禁止共享不会影响CPU和DMA都操作该部分空间的数据;
- IsCacheable:简写为C,指示该区域是否使用cache,该字段需要配合TEX/B/S三个字段来使用,共同决定MPU内存类型和Cache策略,有相应的宏定义,可直接使用,例如:MPU_ACCESS_CACHEABLE;
- IsBufferable:简写为B,指示该区域是否使用缓存,该字段需要配合TEX/C/S三个字段来使用,共同决定MPU内存类型和Cache策略,有相应的宏定义,可直接使用,例如:MPU_ACCESS_CACHEABLE;
参数设置完毕后,使用HAL_MPU_ConfigRegion()函数初始化相应区域的MPU配置
在使用HAL_MPU_Enable()函数来使能MPU功能
其中HAL_MPU_Enable()的形参有四种类型,分别是:
cpp
#define MPU_HFNMI_PRIVDEF_NONE ((uint32_t)0x00000000)
#define MPU_HARDFAULT_NMI ((uint32_t)0x00000002)
#define MPU_PRIVILEGED_DEFAULT ((uint32_t)0x00000004)
#define MPU_HFNMI_PRIVDEF ((uint32_t)0x00000006)
这四个宏定义是用于配置MPU控制寄存器(MPU_CTRL)的参数,主要控制MPU在异常(HardFault、NMI)和特权模式下的行为,MPU_CTRL寄存器中两个相关控制位含义如下:

下面详细介绍这几个参数含义:
- MPU_HFNMI_PRIVDEF_NONE:
背景区:特权模式下禁用背景区,地址未命中任何 MPU 区域会触发 MemManage Fault
HardFault/NMI:MPU 在异常发生时关闭(防止异常处理程序因 MPU 而无法执行)。
- MPU_HARDFAULT_NMI:
背景区:特权模式下禁用背景区,地址未命中任何 MPU 区域会触发 MemManage Fault
HardFault/NMI:MPU 仍然生效(异常处理程序也受 MPU 约束,如果访问未配置区域,会陷入死循环无法恢复)。
- MPU_PRIVILEGED_DEFAULT:
背景区:特权模式下启用背景区,未命中区域可访问,使用默认属性
HardFault/NMI:MPU 关闭(异常处理程序不受 MPU 约束,保证异常能正常处理)。
- MPU_HFNMI_PRIVDEF:
背景区:特权模式下禁用背景区,地址未命中任何 MPU 区域会触发 MemManage Fault
HardFault/NMI:MPU 仍然生效(异常处理程序也受 MPU 约束)。
差异对照表:

最常用的是第三种类型:MPU_PRIVILEGED_DEFAULT
-
- MPU设置与内存类型和Cache策略的对应关系
MPU配置内存类型和Cache策略与TEX、C、B、S几个参数相关,不同参数设置对应的不同内存类型和Cache策略具体如下:

关键说明:
Write-Back 分为两种:Write-Allocate (TEX=001, C=1, B=1) 和 No-Allocate (TEX=000, C=1, B=1)。
STM32H7 的算法计算区应使用 TEX=001, C=1, B=1 (Write-Allocate) 以获得最高性能。
外设寄存器 必须使用 Device 类型 (TEX=000, C=0, B=1),不允许缓存。
对于S位的设置如下:

对于常见的应用场景可配置如下:

-
- MPU配置代码实例
cpp
void MPU_Config(void)
{
////↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓MPU配置实例↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓////
/*
* 1.DTCM:不进行MPU和Cache的策略配置,直接使用,用于存放程序启动的栈、.bss、.data以及程序中使用的各种全局、静态变量
* 2.AXI SRAM:MPU内存类型全部配置为Normal,允许Cache,Cache策略全部配置为Write back,来获取最高性能,用于存放算法和程序过程中
* 使用的各种全局、静态变量,DMA读写的变量不要放在该区域,否则会存在数据一致性的问题,那样就需要手动维护Cache的数据
* 一致性,比较容易出错,风险高,如果只有CPU操作Cache和RAM,则不需要手动维护Cache数据的一致性问题
* 3.SRAM1-SRAM3:设置与AXI SRAM一致
* 4.SRAM4:MPU内存类型全部配置为Normal,不允许Cache,设置为No Cache,用于外设DMA的数据读写使用,因为没有使能Cache,
* 因此DMA和CPU都是直接操作内存数据,无数据一致性问题,但是性能比启用cache稍慢,如果DMA数据区只是拷贝数据,
* 不直接参与算法计算,则性能损耗几乎无影响
*/
//MPU初始化结构体
MPU_Region_InitTypeDef MPU_InitStruct;
//初始化前先禁止MPU
HAL_MPU_Disable();
//AXI SRAM区域的MPU设置
MPU_InitStruct.Enable = MPU_REGION_ENABLE; //配置的该内存区域是否使能
MPU_InitStruct.Number = MPU_REGION_NUMBER1; //配置的该内存区域的region编号(0-15)
MPU_InitStruct.BaseAddress = 0x24000000; //配置的该内存区域的起始地址(要求32字节对齐)
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; //配置的该内存区域的长度(要求32字节对齐)
MPU_InitStruct.SubRegionDisable = 0x0; //配置的该内存区域是否要有禁用的子区域
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; //TEX,与C/B位共同决定内存类型和缓存策略
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; //配置的该内存区域访问权限
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;//配置的该内存区域是否允许指令执行
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; //配置的该内存区域是否允许多主控共享
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; //配置的该内存区域是否允许Cache,与TEX/B位共同决定内存类型和缓存策略
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; //配置的该内存区域是否允许缓存,与TEX/C位共同决定内存类型和缓存策略
//初始化MPU配置
HAL_MPU_ConfigRegion(&MPU_InitStruct);
//SRAM1区域的MPU设置
MPU_InitStruct.Number = MPU_REGION_NUMBER2; //配置的该内存区域的region编号(0-15)
MPU_InitStruct.BaseAddress = 0x30000000; //配置的该内存区域的起始地址(要求32字节对齐)
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB; //配置的该内存区域的长度(要求32字节对齐)
//初始化MPU配置
HAL_MPU_ConfigRegion(&MPU_InitStruct);
//SRAM2区域的MPU设置
MPU_InitStruct.Number = MPU_REGION_NUMBER3; //配置的该内存区域的region编号(0-15)
MPU_InitStruct.BaseAddress = 0x30020000; //配置的该内存区域的起始地址(要求32字节对齐)
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB; //配置的该内存区域的长度(要求32字节对齐)
//初始化MPU配置
HAL_MPU_ConfigRegion(&MPU_InitStruct);
//SRAM3区域的MPU设置
MPU_InitStruct.Number = MPU_REGION_NUMBER4; //配置的该内存区域的region编号(0-15)
MPU_InitStruct.BaseAddress = 0x30040000; //配置的该内存区域的起始地址(要求32字节对齐)
MPU_InitStruct.Size = MPU_REGION_SIZE_32KB; //配置的该内存区域的长度(要求32字节对齐)
//初始化MPU配置
HAL_MPU_ConfigRegion(&MPU_InitStruct);
//SRAM4区域的MPU设置-DMA数据区,不可cache,不可缓存,no cache策略
MPU_InitStruct.Enable = MPU_REGION_ENABLE; //配置的该内存区域是否使能
MPU_InitStruct.Number = MPU_REGION_NUMBER5; //配置的该内存区域的region编号(0-15)
MPU_InitStruct.BaseAddress = 0x38000000; //配置的该内存区域的起始地址(要求32字节对齐)
MPU_InitStruct.Size = MPU_REGION_SIZE_64KB; //配置的该内存区域的长度(要求32字节对齐)
MPU_InitStruct.SubRegionDisable = 0x0; //配置的该内存区域是否要有禁用的子区域
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; //TEX,与C/B位共同决定内存类型和缓存策略
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; //配置的该内存区域访问权限
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;//配置的该内存区域是否允许指令执行
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; //配置的该内存区域是否允许多主控共享
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; //配置的该内存区域是否允许Cache,与TEX/B位共同决定内存类型和缓存策略
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; //配置的该内存区域是否允许缓存,与TEX/C位共同决定内存类型和缓存策略
//初始化MPU配置
HAL_MPU_ConfigRegion(&MPU_InitStruct);
//使能MPU配置
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}