STM32H743的MPU和Cache

本文介绍了MPU(MemoryProtectionUnit)的基本概念、作用、内存类型以及配置方法,如内存块设置、寄存器和配置函数。此外,还详细讨论了Cache的功能,包括不同Cache策略如Writeback和Writethrough的影响,以及如何在STM32H7中管理数据一致性。提供了配置示例和推荐的Cache使用策略,包括启用、禁用、清空和无效化Cache的库函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、MPU相关知识

1、什么是MPU

        MPU的全称是“Memory Protection Unit”,内存保护单元。MPU可以将内存设置成多个具有一定访问规则的内存块。最多可以设置16个内存块,序号分别是0至15,序号越大,访问规则的优先级越高,当两个内存块重叠时执行优先级高的规则。未设置MPU的内存区域是默认区(default region),也叫背景区,他的序号是-1,优先级最低。

        MPU设置的内存块的最小区域为256字节,每一个内存块又可以分成8个子域,一般都是平分,即每个子域的最小大小为32字节,其大小正好和 Cache的最小单位一致。

2、MPU有什么作用?

        a.防止用户应用程序破坏操作系统使用的数据。

        b.防止不受信任的应用程序访问受保护的内存区域。

        c.允许将内存区域定义为只读,以便保护重要数据。

 

简单的说就是内存保护、外设保护和代码访问保护。

3、MPU可以配置的三种内存类型

        Normal memory  正常操作内存空间

                CPU 以最高效的方式加载和存储字节、半字和字,对于这种内存区,CPU 的加载或存储不一定要按照程序列出的顺序执行。

         Device memory

                对于这种类型的内存区,加载和存储要严格按照次序进行,这样是为了确保寄存器按照正确顺序设置。

        Strongly ordered memory

                程序完全按照代码顺序执行,CPU 需要等待当前的加载/存储指令执行完毕后才执行下一条指令。这样会导致性能下降。

4、MPU的寄存器

 5、MPU的配置函数:

         HAL_MPU_Disable(void) :此函数用于禁止 MPU。配置 MPU 前要优先调用此函数禁止 MPU,然后才可以配置。

         HAL_MPU_Enable(uint32_t MPU_Control):此函数用于使能 MPU,一般情况使用参数                 MPU_PRIVILEGED_DEFAULT,可选参数如下:

                        ◆ 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。

         HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init):此函数用于配置 MPU。结构体成员变量如下:

typedef struct

{

         uint8_t     Enable;                     REGION是否使能

         uint8_t     Number;                   内存块序号

         uint32_t   BaseAddress;            内存块首地址

         uint8_t     Size;                          内存块大小

         uint8_t     SubRegionDisable;   是否使能内存区的子域

         uint8_t     TypeExtField;            设置Cache策略

         uint8_t     AccessPermission;   设置区域特权级和非特权级的读写权限

         uint8_t     DisableExec;             XN使能位

         uint8_t     IsShareable;             是否开共享

         uint8_t     IsCacheable;            是否使能Cache

         uint8_t     IsBufferable;            是否使用缓冲区

}MPU_Region_InitTypeDef;

6、MPU配置范例

static void MPU_Config(void)

{

  MPU_Region_InitTypeDef MPU_InitStruct;

 

  /* Disable the MPU */

  HAL_MPU_Disable();

  /* Configure the MPU attributes as Device not cacheable

     for ETH DMA descriptors */

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;

  MPU_InitStruct.BaseAddress = 0x30040000;

  MPU_InitStruct.Size = MPU_REGION_SIZE_256B;

  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;

  MPU_InitStruct.Number = MPU_REGION_NUMBER0;

  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;

  MPU_InitStruct.SubRegionDisable = 0x00;

  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

 

  /* Configure the MPU attributes as Normal Non Cacheable

     for LwIP RAM heap which contains the Tx buffers

对于包含Tx缓冲区的LwIP RAM堆,配置MPU属性为Normal Non - Cacheable */

  MPU_InitStruct.Enable = MPU_REGION_ENABLE;

  MPU_InitStruct.BaseAddress = 0x30044000;

  MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;

  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;

  MPU_InitStruct.Number = MPU_REGION_NUMBER1;

  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;

  MPU_InitStruct.SubRegionDisable = 0x00;

  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enable the MPU */

  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

二、Cache相关知识

1、什么是Cache

        Cache是一个读写速度和CPU运行速度保持一致的内存区域,也叫缓存。当前芯片厂商出的 M7 内核芯片基本都做了一级 Cache 支持,Cache 又分数据缓存 D-Cache 和指令缓冲 I-Cache,STM32H7 的数据缓存和指令缓存大小都是 16KB,这里主要说的是数据缓存 D-Cache。

2、 Cache的作用:在高速内核(最高480M)和低速外设(最高240M)之间进行一个缓冲以提高CPU的运行速度。

3、 Cache 策略

名词解释:

Write through:直写:同时将数据写到flash和 Cache。如果写MISS,则根据是否开启Write allocate决定是否在cache中开辟空间并将数据写入。

Write back:回写:如果写命中将不再写入到flash,如果写MISS,则根据是否开启Write allocate决定是否在cache中开辟空间并将数据写入。

allocate:使能了以后如果MISS,则会在Cache中重新开辟空间以方便后续读写。

具体策略:

        注意,M7内核只要开启了Cache,read allocate就是开启的。

Non-cacheable:正常的读写操作,无Cache。

Write back, write and read allocate:

(1)使能了此配置的SRAM缓冲区写操作

        如果写命中就不再更新flash;如果写MISS,CPU会将数据先写到flash,然后再在Cache中开辟区域,将SRAM区数据加载进来,以后直接从Cache里面读取,从而时间加速。

劣势:如果写命中,Cache的数据和flash的数据不一致

(2)使能了此配置的SRAM缓冲区读操作

        如果读命中,将不会再读flash。如果读MISS,就用到配置read allocate了,CPU会在Cache里面开辟区域,将SRAM区数据加载进来,以后直接从Cache里面读取,从而时间加速。

劣势:如果读命中之前DMA写操作也更新了flash的数据,那就造成了数据不一致的问题。

这个配置被誉可以最大程度发挥Cache性能,不过具体应用仍需具体分析。

(3)对应两种MPU配置如下:

        TEX = 001 C=1 B=1  S=1

        TEX = 001 C=1 B=1  S=0

Write through,no write allocate:

(1)使能了此配置的SRAM缓冲区写操作

        如果写命中,那么会同时写到Cache里面和SRAM里面;如果写MISS,就用到配置no write allocate了,CPU以后将不再往Cache里面写数据,将直接往flash里面写。

优势:在写命中时,Cache和SRAM的数据同步更新,没有多总线访问造成的数据一致性问题。

劣势:Cache在写操作上无法有效发挥性能。

(2)使能了此配置的SRAM缓冲区读操作

        如果读命中,将不会再读flash。如果读MISS,就用到配置read allocate了,CPU会在Cache里面开辟区域,将SRAM区数据加载进来,以后直接从Cache里面读取,从而时间加速。

劣势:如果读命中之前DMA写操作也更新了flash的数据,那就造成了数据不一致的问题。

(3)对应两种MPU配置如下:

        TEX = 000 C=1 B=0  S=1

        TEX = 000 C=1 B=0  S=0

Write back, no write allocate:

(1)使能了此配置的SRAM缓冲区写操作

        如果写命中就不再更新flash;如果写MISS,就用到配置no write allocate了,CPU以后将不再往Cache里面写数据,将直接往flash里面写。

劣势:如果写命中,Cache和flash的数据将不一致。

(2)使能了此配置的SRAM缓冲区读操作

        如果读命中,将不会再读flash。如果读MISS,就用到配置read allocate了,CPU会在Cache里面开辟区域,将SRAM区数据加载进来,以后直接从Cache里面读取,从而时间加速。

劣势:如果读命中之前DMA写操作也更新了flash的数据,那就造成了数据不一致的问题。

(3)对应两种MPU配置如下:

        TEX = 000 C=1 B=1  S=1

        TEX = 000 C=1 B=1  S=0

注意:

由于开了共享会严重降低读Cache的速度,基本等同于关闭 读Cache。而对写Cache基本没有影响。

共享开关仅在开启Cache的情况下有影响,而对于关闭了Cache的情况是没有影响的,开不开没关系。

4、总结4种 Cache 策略的几个关键知识点

(1)对于读操作,只有在第1次访问指定地址时才会加载到Cache,而写操作的话,可以直接写到内存中(write-through模式)或者放到Cache里面,后面再写入(write-back模式)。

(2)如果采用的是Write back,CPU会先将数据更新到Cache,然后再将Cache line被标为dirty,等到此行被evicted时,才会执行实际的写操作,将Cache Line里面的数据写入到flash。

(3)Cache命中是访问的地址落在了给定的Cache Line里面,所以硬件需要做少量的地址比较工作,以检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记新行,填充新的读写操作。如果所有行都分配完毕了,Cache控制器将支持eviction操作。根据Cache Line替换算法,一行将被清除Clean,无效化Invalid或者重新配置。数据缓存和指令缓存是采用的伪随机替换算法。

(4)Cache支持的4种基本操作,使能,禁止,清空和无效化。Clean清空操作是将Cache Line中标记为dirty的数据写入到内存里面,而无效化Invalid是将Cache Line标记为无效,即删除操作,之后再将flash的数据重新加载到Cache,以保持数据的一致性问题。

5、面对这种繁冗复杂的Cache配置,推荐方式和安全隐患解决如下(以H7为例):

(1)推荐使用128KB的TCM作为主RAM区,其它的专门用于大缓冲和DMA操作等。

(2)Cache问题主要是CPU和DMA都操作这个缓冲区时容易出现,使用时要注意。

(3)Cache配置的选择,优先考虑的是WB,然后是WT和关闭Cache,其中WB和WT的使用中可以配合ARM提供的如下几个函数解决上面说到的隐患问题。但不是万能的,在不起作用的时候,直接暴力选择函数SCB_CleanInvlaidateDCache解决。关于这个问题,在分别配置以太网MAC的描述符缓冲区,发送缓冲区和接收缓冲区时尤其突出。

6、Cache配置库函数

◆ SCB_EnableICache:使能指令 Cache。

◆ SCB_DisableICache:禁止指令 Cache。

◆ SCB_InvalidateICache:将指令 Cache 无效化,无效化的意思是将 Cache Line 标记为无效,等同于删除操作,腾出空间。

◆ SCB_EnableDCache:使能数据 Cache。

◆ SCB_DisableDCache:禁止数据 Cache。

◆ SCB_InvalidateDCache:将数据 Cache 无效化,无效化的意思是将 Cache Line 标记为无效,等同于删除操作,腾出空间。

◆ SCB_CleanDCache:用于将数据 Cache 清除,清除的意思是将 Cache Line 中标记为 dirty 的数据写入到相应的存储区。

◆ SCB_CleanInvalidateDCache:将 Cache Line 中标记为 dirty 的数据写入到相应的存储区后,再将 Cache Line 标记为无效进行删除,腾出空间。

◆ SCB_InvalidateDCache_by_Addr(uint32_t *addr, int32_t dsize):将自指定地址开始指定大小的内存区域进行无效化,无效化的意思是将 Cache Line 标记为无效,等同于删除操作,腾出空间。

◆ SCB_CleanDCache_by_Addr(uint32_t *addr, int32_t dsize):将自指定地址开始指定大小的内存区域标记为 dirty 的数据写入到相应的存储区。

◆ SCB_CleanInvalidateDCache_by_Addr(uint32_t *addr, int32_t dsize):将自指定地址开始指定大小的内存区域中标记为 dirty 的数据写入到相应的存储区后,再将 Cache Line 标记为无效进行删除,腾出空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值