
当我们阅读一些STM32F7或STM32H7系列芯片例程,或者基于这两类芯片通过cubeMx进行配置并用到MPU功能时,往往会在代码里看到下面这段MPU配置。 ' y/ w# j5 H: V+ Q6 i3 K5 ` ![]() 对这段代码可能有人有些疑问,这里重点一起聊聊其中的3个,供参考。 第一个疑问,那行做赋值0x87的代码是什么意思? 第二个疑问,这段代码的注释【绿色】是说将未定义的区域配置为Strongly Ordered存储属性,这个未定义到底如何理解?从代码看,这里清晰地对从0开始的整个4G空间做了配置,未定义区域到底指的哪里? 第三个疑问,这段代码往往并不是开发者自己配置的。如果使用CubeMx进行配置它会自动给我们加上这段,为什么要加这段?很多时候经测试,即使没这段代码似乎也没有什么问题。 这几个问题,涉及到MPU和Cortex M7内核芯片试探性访问的知识。我尽量通俗地加以介绍,知晓怎么回事即可。 我们知道,通过MPU可以配置特定地址空间的存储属性,给CPU约定访问权限。我们在对某块地址空间做MPU配置时,通常需要设置起始地址、空间大小、Cacheable、Bufferable、Shareable、子区属性、区块编号等。这里的地址空间,英文用Region来特指,后面都使用该词。 实际应用中我们往往会针对不同的Region做MPU配置,在做不同Region的MPU设置时,可能出现地址空间重叠的情况。比方像下面64KB空间内做了3个不同Region的MPU配置,而且发生了不同Region的地址重叠。 1 Z5 i! X B* `$ k* J# n ![]() 这个时候,对于地址重叠空间的MPU属性由Region编号大的决定。结合上图,N+2编号Region的MPU属性优先级最高,Region N的最低。 刚才我在前面提到了子区,它是什么意思呢? 子区也是个特定概念,英文用SubRegion。所谓Subregion,当我们对某地址空间不小于256B的Region进行MPU配置时,可以把该Region等分为8个子区【Subregion】,并把当前Region的MPU属性针对部分子区进行排除性或说例外性设置。啥意思呢?比方说,本来当前Region经MPU配置后为WriteThough支持共享的存储属性,同时呢,又将其中的2个子区做排除性设置,即这2个子区不适用当前的MPU配置。好比当前举国抗疫防新冠,要求全面强制核酸,但同时又可以做例外说明,那些基本足不出户的老人或小孩不适用该要求。 在MPU配置寄存器MPU_RASR里有个8位字段SRD专门用来配置子区的排除属性。每1位对应一个子区,高位对应高地址子区,低位对应低地址子区。某位为0表示该子区使用当前MPU配置,为1表示该子区不适用当前配置,即被排除在外。【更多细节可以参考下图】( X0 M J( E, M. r1 a/ a1 e 2 J$ ]+ L+ `$ b) m ![]() 不妨举例说一下,假设我们选择了某64KB区域进行MPU设置,其中有2个SubRegion被做了MPU排除处理,即其中2个8KB空间不适用当前的MPU配置。如下图所示: " u2 r" Y% I4 `9 I ![]() 此时,对应到MPU配置寄存器MPU_RASR里的SRD字段的内容就是0x48。 聊到这里,我们就可以回答开篇的部分疑问了。 ![]() 从上面这段代码不难看出,首先将从0开始的4GB空间做了MPU配置,Region编号为0,最终被配置为Strongly Ordered存储属性。那句赋值0x87的代码则是进一步针对当前Region里的SubRegion做属性排除设置。这里的0x87就是给前面提到的给SRD字段的赋值。【这里每个子区空间大小为512MB】 ![]() 也就是说,这4GB空间中有4个子区不适用目前配置的MPU属性,即下图中几个红色方框内区域。 ![]() 换句话说,这里并没有真正针对整个4GB空间做MPU配置,实际上只对上图中的绿色区域做了Strongly Order的存储属性设置。然而,代码的注释又说是针对未定义区域做MPU配置,怎么理解未定义区域呢? 这里说的未定义区域到底是上图中红色区域还是绿色区域呢? 显然不是指红色区域,因为这里特意对红色区域做了MPU属性排除处理,即当前MPU配置根本就不适用它。那是指绿色区域?似乎也不对!因为绿色区域的MPU配置不是很清晰吗?Region编号、地址空间、访问属性等一应俱全。何来未定义呢? 。。。。。。 我们可以进一步了解到,上图中绿色区域对应的是外部存储设备的地址空间。如果我们需要用到外部存储设备的话,往往还会针对外扩的存储单元再做MPU配置。比方我们基于STM32H7芯片外扩了一个32MB的SDRAM,然后做了如下的MPU配置。 ![]() 照样,先对整个4GB空间做了MPU初始配置,即前面一直在解说的内容。然后针对外扩的32MB的SDRAM做了特定MPU配置,此时的Region标号为1,访问属性为Write Through。此块Region空间属于前面初始配置中外部存储空间的一部分,即出现不同Region地址重叠,所以这块SDRAM所在Region的MPU访问属性就是Write Through,而不再是一开始配置的Strongly Ordered属性了。见下图中绿色区域中那部分黄色方块。 ![]() 当然,如果说你还外扩了其它的存储单元,比方扩个QSPI什么的,如果MPU属性依然不同于Strongly Ordered、且Region编号大于0,更多绿色区域将被新的黄色区域替换。比方变成下面图示的样子。 ![]() 也就是说,注释代码里提到的未定义区域,是指初始定义出来的绿色区域中没有被用户的实际外部存储器所占用的剩余空间。即上面图中抠除黄色区域以后剩下的绿色区域。 这里又衍生个问题,为什么要这样做呢? 这个问题又涉及到M7内核芯片的试探性访问特性。试探性访问可以提升芯片的性能,但有时可能也会导致些问题。比方,由于试探性访问,在CPU访问外部存储器时,可能发生越界访问。如果说它访问到一个本不存在存储设备的地址时,可能发生锁死异常。结合上面图形,黄色地址区域是实实在在的外部存储器件所占用的空间,如果因为试探性访问可能越界访问不存在物理存储单元的绿色区域而导致麻烦。 不过,由于CPU不会针对配置为Device 或Strongly Ordered存储属性的地址空间进行试探性访问。为了防止上面提到的问题,于是就有了前面谈到的一上来就把所有用于外部访问的存储空间配置为Strongly Ordered属性,显然这个配置是个粗框架性的。用户具体使用时根据实际存储器的特性、容量等再配置特定的MPU属性并覆盖原来初始设置,其它未用区域依然保持Strongly Ordered属性,正是为了防止在没有放置实际存储器的地方发生试探性访问。 最后一个问题,有人发现即使不要那段针对4GB空间的MPU初始代码,似乎也没遇到啥问题。 这也正常。因为你即使外扩了存储单元,并非一定会因为试探性访问导致异常。比方你外扩了32MB的存储单元,未必就一定会要用到最后一个位置,说不定还剩余很多,远不至于读到最后边界而让CPU试探到不存在存储器的空间。但是事先做那段初始配置,对系统是一个很好的未雨绸缪。就好像河边安置防护栏一样,没有,也不至于天天怎么样;有,肯定要安全保险得多。 |
【2025·STM32峰会】GUI解决方案实训分享1-对LVGL咖啡机例程的牛刀小试以及问题排查
OpenBLT移植到STM32F405开发板
为什么要先开启STM32外设时钟?
【STM32MP157】从ST官方例程中分析RPMsg-TTY/SDB核间通信的使用方法
【经验分享】STM32实例-RTC实时时钟实验④-获取RTC时间函数与中断服务函数
STM32 以太网 MAC Loopback 的实现
STM32功能安全设计包,助力产品功能安全认证
基于STM32启动过程startup_xxxx.s文件经验分享
HRTIM 指南
ST 微控制器电磁兼容性 (EMC) 设计指南