你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的Cache和MPU

[复制链接]
STMCU小助手 发布时间:2021-12-18 17:42
一、Cache
& C; g" \7 A; A" Y: @4 Q, U- h  [2 A. \7 p9 L) R! \; ]7 |
1、介绍
7 X& l) r( c5 t+ s6 e& W. V5 a4 T( M: W& [( U! @, `  h' U: S4 c. ^) \
        Cache又分数据缓存D-Cache和指令缓冲I-Cache,STM32H7的数据缓存和指令缓存大小都是16KB。STM32H7主频是400MHz,除了TCM和Cache以400MHz工作,其它AXI SRAM,SRAM1,SRAM2等都是以200MHz工作。数据缓存D-Cache就是解决CPU加速访问SRAM。
: E$ C. P( p4 j1 v2 q& l3 @7 V! m1 F
        如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了200MHz到400MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。: D0 c$ y$ b1 r. C

0 W; A0 p6 r, b) t" A2、操作,分为读操作和写操作
" \& _! J! \5 J4 W- J! @) O* v8 f7 s9 U& F& x
        读操作: 如果CPU要读取的SRAM区数据在Cache中已经加载好,这就叫读命中(Cache hit),如果Cache里面没有怎么办,这就是所谓的读Cache Miss。
9 h, T# Y, q) o, X$ r$ Z: ^$ U5 o8 Q7 b$ t
       写操作: 如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域(专业词汇叫Cache Line,以32字节为单位),这就叫写命中(Cache hit),如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。
4 d8 t3 s3 h& d9 l" s
  h- f( ?) M- ~2 z$ Y& M3、H7支持的Cache策略,共4种
4 Q6 A+ ~8 J: f+ n
: D: s) P- Y- O2 X2 t/ M, X  ]
20191118102334153.png
; d$ F: Q! P* T5 E
" @6 g6 i( s0 \4 M3 s
<回写:如果Cache中有,写数据只写到Cache,不写到RAM。>5 U( b- j8 a; F

* i: T% [4 E) E& _<透写:如果Cache中有,写数据也要同时写到Cache和RAM。>
  b# j2 }, q" u1 N9 F  a1 y& \1 m/ M' |2 U. v
<write allocate:写数据时,如果Cache中没有,那么就要在Cache中开辟一个空间,把数据写入Cache,同时把RAM中的相邻数据加载进来填充Cache。>
9 @  Q  |+ w9 G; e! t/ d1 H
2 [- t- h7 M  ]<no write allocate:写数据时,如果Cache中没有,那么把数据直接写入RAM。>
+ W' q! ~  X! F% w2 E6 s, ~
( J' Y- }0 L9 n% Y5 z<read allocate:读数据时,如果Cache中没有,那么就要在Cache中开辟一个空间,把数据从RAM中加载进来,后续的读操作,就可以直接从Cache中读取了。>
6 @2 V; l+ L; P- f, v) H9 w4 G; j; K9 v( i6 Y* z' Q1 O
<no read allocate:读数据时,如果Cache中没有,那么直接从RAM中读。>
. `+ Z! J% U& ^, W& G
' E! Y% p+ Z( n5 p  l4、风险
5 Q; q4 i0 p' v' r; d& d: u/ t/ S
- G7 `+ ~" q0 `+ t  h- y$ i
20191118112913153.png
( X8 N. P8 ]9 d' }  {! c

  f2 Z% v) Q' \. V; S        从上面的图就看出来使用Cache的风险,因为DMA是直接与SRAM交换数据的,而CPU与SRAM之间隔了一个Cache,如果DMA更新了某个数据到SRAM,CPU要去访问,而恰好Cache中有,那么CPU就不会去SRAM中拿,就会拿到Cache中已经过时的数据。因此使用了DMA的内存区要配置为无Cache或者拿数据前清一次Cache。
3 N* R1 H) k2 I/ ]  y
9 i6 C# @8 I: G- y5 b# ]' j5、相关函数
7 Q" |' W9 {/ V4 c- c( w# p' Q4 Z1 g# e# z
        SCB_EnableICache(void) :用于使能指令Cache,系统上电后优先初始化即可。
8 \6 V' }$ o* s* j, K0 I4 t; a- d
        SCB_DisableICache(void) :用于禁止指令Cache。) J7 ]/ J) K& Z7 W+ d1 i+ F8 C
8 c' I9 O3 d) B6 }: t, a
        SCB_InvalidateICache(void) :用于将指令Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的指令。7 [4 c% U7 ~  k, N

( b/ N0 A) n' {4 x        SCB_EnableDCache(void) :用于使能数据Cache,系统上电后优先初始化即可。2 W8 U, d+ u) _/ W% l* F

1 u) B. A' q: x  h/ O        SCB_DisableDCache(void) :用于禁止数据Cache。
  |! b7 e" M& a; R- G/ {# \9 i
        SCB_InvalidateDCache(void) :用于将数据Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的数据。
$ q4 s# E: Q" a. w
# f% ^! f( Z, k, f- z, [, J( |6 w$ z9 v        SCB_CleanDCache(void):用于将数据Cache清除,清除的意思是将Cache Line中标记为dirty的数据写入到相应的存储区。
- T" [5 `0 B2 H0 t( F0 u# p) a* D2 q% K8 X! J6 W4 R- v
        SCB_CleanInvalidateDCache(void) :此函数是前面两个函数SCB_InvalidateDCache和SCB_CleanDCache的二合一。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。4 k! s: }2 ?* k; P( ]8 b/ i
5 @4 H. ]- V9 s. u. j
        SCB_InvalidateDCache_by_Addr(uint32_t *addr,int32_t dsize):可以指定地址和存储区大小,地址要32字节对齐,大小要是32字节的整数倍。用于将数据Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的数据。( b4 U( q) O5 P; W/ R/ \

% O. |) q  ~* P3 }. y        SCB_CleanDCache_by_Addr(uint32_t *addr,int32_t dsize):可以指定地址和存储区大小,地址要32字节对齐,大小要是32字节的整数倍。用于将数据Cache清除,清除的意思是将Cache Line中标记为dirty的数据写入到相应的存储区。
# \- y& V& |2 U: X
3 W1 f. J1 w& V: J6 n5 v        SCB_CleanInvalidateDCache_by_Addr(uint32_t *addr,int32_t dsize):可以指定地址和存储区大小,地址要32字节对齐,大小要是32字节的整数倍。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。
$ G" v7 d* T) s3 K: s' Z
. \( d4 A- b9 t/ t  N5 r2 p- b) `. C+ X7 B" i# @
" M; c( S4 i8 B" V7 o3 [
二、MPU- E: Y; g$ i# o$ h

' g8 V: |4 ]; v; `0 J. M1、作用) T1 p& \3 k, U8 k6 \4 \

* Y5 q! G, ~) Y; [4 P3 {7 X        防止不受信任的应用程序访问受保护的内存区域; 防止用户应用程序破坏操作系统使用的数据;通过阻止任务访问其它任务的数据区;允许将内存区域定义为只读,以便保护重要数据;检测意外的内存访问。 简单的说就是内存保护、外设保护和代码访问保护。0 n* L& C4 T4 h& H0 }' a
  k5 @1 W- N. }' u
2、MPU可以配置的三种内存类型
  i( ?6 A6 p& s0 O1 r6 N6 ^' n% I
. o: k: y& E: _. n+ L" D. g1)、Normal memory
* p/ R/ t: v. C, w  U3 f
5 L( Y/ |8 j: X! V$ A) z        CPU以最高效的方式加载和存储字节、半字和字,对于这种内存区,CPU的加载或存储不一定要按照程序列出的顺序执行。
1 \, {  L9 A7 V" n$ ^& D
& I. l% F" e" l, J  `& ~2)、Device memory# N7 L& K& B9 m! P/ K

5 E/ H- A/ \7 w3 H1 U- ]3 ?* n7 v        对于这种类型的内存区,加载和存储要严格按照次序进行,这样是为了确保寄存器按照正确顺序设置。
; T% u4 U8 r3 b  e" }8 f/ o' i$ g
  i" _6 `' Z0 ]: N3)、Strongly ordered memory
" g/ O+ Q% p9 T/ P: E
7 D0 ^7 F# s  }$ [/ h, B        程序完全按照代码顺序执行,CPU需要等待当前的加载/存储指令执行完毕后才执行下一条指令。这样会导致性能下降。" L  Z# D1 `, h
4 U8 U% p/ |7 L1 _
3、MPU的使用" s: ^7 A# g$ h. H7 q: L8 e

! g2 T6 k' c  {# g! O        MPU可以配置保护16个内存区域(这16个内存域是独立配置的),每个区域最小要求256字节,每个区域还可以配置为8个子区域。由于子区域一般都相同大小,这样每个子区域的大小就是32字节,正好跟Cache的Cache Line大小一样。) H" E! d4 q% F! l1 \
# S# E. d1 M5 ^1 R
        使用时把一段连续的内存区配置为一个MPU保护区域,然后再配置这个MPU保护区域的特性。比如128KB的DTCM、64KB的SRAM4、32MB的SDRAM。MPU保护区域的特性使用MPU_RASR寄存器来配置,描述如下:
. H% y- }2 C6 N2 m( @; z( J7 n7 l4 u! N
20191118111700740.png

: y0 F" M. ]+ b6 D% U5 ]9 R! i6 H# `7 o' z  K! r
1)、XN:用于控制这个MPU保护区域能否执行程序代码。
9 d  Z- @: t0 Z5 j2 c) v$ A
' `7 ?% h' Q5 ~6 J2)、AP:用于控制这个MPU保护区域的特权级和非特权级的读写访问权限。7 |5 E+ l* F3 z

/ ?0 \* K2 y& X2 P& l* |1 K
20191118111401294.png
! @6 U& m7 E8 I7 O  j

/ L$ c8 q  D5 ^2 r5 m3)、TEX、C、B、S:H7支持4种Cache策略,这几位就是用来控制这个MPU保护区域使用哪一种。
( R; i" M7 a. T  _6 b2 ?/ c6 S
+ [" R, x5 L: {" l/ n9 s
2019111811214681.png

( X) `0 y$ ~" W& C5 t0 Q5 M/ a! {9 w; C
S位用于解决多总线或者多核访问的共享问题,一般不要开启。
5 ?- k$ V% P: ~9 v2 W+ u6 q8 v. |4 y4 I  {  i1 S
4)、SRD:这个位用于控制内存区的子区域 ,使用的是bit[15:8],共计8个bit,一个bit控制一个子区域, 0表示使能此子区域, 1表示禁止。一般情况下,取值0x00,表示8个子区域都使能。& p8 X; {, e& Q9 c. C6 m0 y! N- H/ ^

( D3 e% K  I1 A4 ~* T; j5)、SIZE:配置这个MPU保护区域的大小。
$ N: C( V/ u6 m" ^' p" O# ^+ W4 Y& C, z. K9 \. _) ?( N
三、HAL配置例程7 f5 K" K& d* P; F
+ g- L0 L8 k$ h6 v
  1. //设置某个区域的MPU保护
    . m+ A& W: m. X, N) X/ P8 d  @
  2. //baseaddr:MPU保护区域的基址(首地址)6 L8 C4 d7 u6 _6 L5 c  m( p: E
  3. //size:MPU保护区域的大小(必须是32的倍数,单位为字节),可设置的值参考:CORTEX_MPU_Region_Size
    ( a4 l; g( K" d. z* ]
  4. //rnum:MPU保护区编号,范围:0~7,最大支持8个保护区域,可设置的值参考:CORTEX_MPU_Region_Number. A1 H) @" ~/ j  B8 ^+ a6 i$ G& @
  5. //ap:访问权限,访问关系如下:可设置的值参考:CORTEX_MPU_Region_Permission_Attributes
    . i+ r1 N' d  ^1 S& g$ l( e
  6. //0,无访问(特权&用户都不可访问)5 A- K0 d6 ~3 E9 d3 b5 j6 ~9 V( |
  7. //1,仅支持特权读写访问1 w) z, g, |- Z6 }' ]; y
  8. //2,禁止用户写访问(特权可读写访问)
    & Z& h  ~8 M& y* `! o) w
  9. //3,全访问(特权&用户都可访问)
    0 }6 E; D/ ^0 }" f0 g7 l  R4 E1 o5 E
  10. //4,无法预测(禁止设置为4!!!)" ]# Q+ A% y" a$ p+ c  [6 s: J# i
  11. //5,仅支持特权读访问
    ; X* R& A3 D5 F# e
  12. //6,只读(特权&用户都不可以写)
    - V! X! ]" N! c! e3 p+ S0 [, S3 [
  13. //详见:STM32F7 Series Cortex-M7 processor programming manual.pdf,4.6节,Table 89.  q5 {8 `, T: W& {4 e# ^
  14. //sen:是否允许共用;0,不允许;1,允许& ?3 l+ S- P1 t+ [% |4 ]; t! [
  15. //cen:是否允许catch;0,不允许;1,允许* [; b8 ]. [3 r) n5 g3 a4 c" d$ I
  16. //返回值;0,成功.1 ?$ j+ R( |# e, P. H: K
  17. //    其他,错误.
    ; S, A; B; O: Y8 R+ x7 w) ~& b
  18. u8 MPU_Set_Protection(u32 baseaddr,u32 size,u32 rnum,u32 ap,u8 sen,u8 cen,u8 ben,u8 Tex)
    7 o/ a. |: Q3 q! z& }
  19. {
    9 Q* g  b3 \; W$ `' w& D
  20.         MPU_Region_InitTypeDef MPU_Initure;
    ) \8 O0 O" v4 Q: {' z- F  F/ T
  21.         HAL_MPU_Disable();                                                                        //配置MPU之前先关闭MPU,配置完成以后在使能MPU+ V; r+ a9 {: G2 N, ^
  22. 9 e- R3 u7 B- I% Q5 ?
  23.         MPU_Initure.Enable=MPU_REGION_ENABLE;                                //使能该保护区域 % l6 N' ~7 [$ T( [: z
  24.         MPU_Initure.Number=rnum;                                            //设置保护区域/ h' m, q6 Z' m7 v& f' q7 ~
  25.         MPU_Initure.BaseAddress=baseaddr;                            //设置基址
    + b& q  d; g7 Q, M2 Q8 S
  26.         MPU_Initure.Size=size;                                                    //设置保护区域大小# x1 {5 M4 b! S2 j4 X. ?% C
  27.         MPU_Initure.SubRegionDisable=0X00;                      //禁止子区域
    2 {8 V% U& J! y  ^8 d/ s
  28.         MPU_Initure.TypeExtField=Tex;                           //设置类型扩展域& @( a4 d- d- u1 z
  29.         MPU_Initure.AccessPermission=(u8)ap;                            //设置访问权限,* |6 \% \# q7 _( s6 b) O' D
  30.         MPU_Initure.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;        //允许指令访问(允许读取指令): U7 b2 A) m: W8 [
  31.         MPU_Initure.IsShareable=sen;                            //是否允许共用
    + f9 Q! V7 l0 p& W1 [: I; i4 S
  32.         MPU_Initure.IsCacheable=cen;                            //是否允许cache5 s/ x1 \' }* J2 X  I2 m% r
  33.         MPU_Initure.IsBufferable=ben;                           //是否允许缓冲* j1 Q" f  n" p. B8 ?! W
  34.         HAL_MPU_ConfigRegion(&MPU_Initure);                     //配置MPU6 h1 I. g, s  P9 E/ u7 _
  35.         HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);                                //开启MPU+ e" _& X$ V" T- s
  36.     return 0;* T1 _- z, R( f3 F- H( K% C
  37. }
    & S0 {0 U9 @1 w+ c, U1 W% I  |) ?
  38. ) }: k* m7 Z/ ^0 N2 H+ r
  39. //设置需要保护的存储块
    3 L- O' A- @3 C  Z
  40. //必须对部分存储区域进行MPU保护,否则可能导致程序运行异常
    7 d5 ?$ J' N2 o, O7 T' w# L
  41. //比如MCU屏不显示,摄像头采集数据出错等等问题...
    ' [1 y) L9 L! [- F! Y
  42. void MPU_Memory_Protection(void)   //特意把SRAM4设置为不允许cache,使用DMA的变量可以放在这里。但要注意相应DMA能否访问SRAM4$ u8 Z* ~$ k9 @, c7 I
  43. {! I/ i( `: E8 n9 `4 Y
  44.         MPU_Set_Protection(0x20000000,MPU_REGION_SIZE_128KB,MPU_REGION_NUMBER1,MPU_REGION_FULL_ACCESS,0,1,1,MPU_TEX_LEVEL0);        //保护整个DTCM,共128K字节,禁止共用,允许cache,允许缓冲
    % C& r8 e. E$ h7 u3 i
  45.         MPU_Set_Protection(0x24000000,MPU_REGION_SIZE_512KB,MPU_REGION_NUMBER2,MPU_REGION_FULL_ACCESS,0,1,1,MPU_TEX_LEVEL0);        //保护整个内部SRAM,包括SRAM1,SRAM2和DTCM,共512K字节9 e: i, _; i- p' ~! C* F8 o) _- o. {' G
  46.         MPU_Set_Protection(0x30000000,MPU_REGION_SIZE_512KB,MPU_REGION_NUMBER3,MPU_REGION_FULL_ACCESS,0,1,1,MPU_TEX_LEVEL0);        //保护整个SRAM1~SRAM3,共288K字节,禁止共用,允许cache,允许缓冲
    0 B: c5 J  ~( B0 q
  47.         MPU_Set_Protection(0x38000000,MPU_REGION_SIZE_64KB ,MPU_REGION_NUMBER4,MPU_REGION_FULL_ACCESS,0,0,1,MPU_TEX_LEVEL0);        //保护整个SRAM4,共64K字节,禁止共用,不允许cache,允许缓冲
    5 M% U' g. f0 v% l$ X8 F
  48.         MPU_Set_Protection(0x60000000,MPU_REGION_SIZE_64MB ,MPU_REGION_NUMBER5,MPU_REGION_FULL_ACCESS,0,0,0,MPU_TEX_LEVEL0);        //保护MCU LCD屏所在的FMC区域,,共64M字节,禁止共用,禁止cache,禁止缓冲
    & A  Q' X* u5 c+ `
  49.         MPU_Set_Protection(0xC0000000,MPU_REGION_SIZE_64MB ,MPU_REGION_NUMBER6,MPU_REGION_FULL_ACCESS,0,1,1,MPU_TEX_LEVEL0);        //保护SDRAM区域,共32M字节,禁止共用,允许cache,允许缓冲
    0 }6 _9 k$ h) i* D6 i* s. M/ Q
  50. }
复制代码

6 a, ~# _6 m  E1 e: r/ a, J四、其他0 g9 p! H" u' M6 o

( H7 ~6 i. ?& Q1 P" O  E1 X% q        值得一提的是,LTDC也是直接从RAM拿数据的,如果你使用了GUI(比如EMWIN),你的显示数据可能会暂存在Cache,而LTDC直接从RAM拿数据,就可能造成画面撕裂、重影、斑点之类的问题。解决方法是,把显存设置成透写。  a0 J: G5 Y0 p  z: X9 {4 X# ?: O

6 ~7 o$ e- d6 g9 n        从下面的图可以看到,Cache是在M7那个框里面的。而框外面的外设都可以直接与RAM交换数据,因此使用外设操作数据时都要考虑一下Cache的影响,不然异常可能难以预料。2 a, D' p2 W. p6 J9 T
7 @2 x- {( B$ b* Z5 J% M( n
20191119145451828.png
5 V$ E8 h7 n3 J# e

0 t/ D6 r* Z. J/ k2 ~1 F: B
) [, K  k' x: S6 g7 A
收藏 评论0 发布时间:2021-12-18 17:42

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版