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

【经验分享】STM32H7的Cache解读(非常重要)

[复制链接]
STMCU小助手 发布时间:2021-10-26 23:17
24.1 初学者重要提示2 c' ?; y! v( o5 r1 B  \# a
  学习本章节前,务必保证已经学习了第23章的MPU知识。
  X) E! N: h1 V$ X* z& H' m. n1 r  本章是半年的实践经验总结,非常具有参考价值,而且是入门STM32H7的必学章节。
. q  `) Q2 C' I+ g% T  Cache的熟练运用需要不断的经验积累。对于初学者来说,可能无法一下子理解所有知识点,但是一定要的花时间多读几遍,随着后面章节的不断运用,认识会不断的深入。
  p/ O* m! B- a" W! Z7 q, B24.2 引出问题
! ^( V  ?- c4 V6 [, f4 \- n; {$ i当前芯片厂商出的M7内核芯片基本都做了一级Cache支持,Cache又分数据缓存D-Cache和指令缓冲I-Cache,STM32H7的数据缓存和指令缓存大小都是16KB。对于指令缓冲,用户不用管,这里主要说的是数据缓存D-Cache。以STM32H7为例,主频是400MHz,除了TCM和Cache以400MHz工作,其它AXI SRAM,SRAM1,SRAM2等都是以200MHz工作。数据缓存D-Cache就是解决CPU加速访问SRAM。
1 E; u: Z) ~' Q1 D0 U) x, B: h7 l% }
如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了200MHz到400MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。
6 q5 q- i5 T' J3 N9 M  j, T
$ x+ ]+ q; A( B9 m4 d9 `: a8 I对于使能了Cache的SRAM区,要分读写两种情况考虑。
& \8 _* D8 I+ p& G
* |8 L: E0 E6 x- e1 |  读操作:- V6 A( h) [4 L5 L
如果CPU要读取的SRAM区数据在Cache中已经加载好,这就叫读命中(Cache hit),如果Cache里面没有怎么办,这就是所谓的读Cache Miss。
6 H5 Z4 S1 B' R# m
/ N# @2 c0 p& [. @" e3 {2 f# ?2 ~  写操作:' }$ K; l( w0 [: ^5 m
如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域(专业词汇叫Cache Line,以32字节为单位),这就叫写命中(Cache hit),如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。6 [# j& a$ Q! d( R! X; D
+ H6 z1 Z2 a4 c- K" H8 f/ v7 T
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDYvMTM3OTEwNy0yMDE5.png

% I' |7 C  z* }4 u2 G24.3 支持的Cache配置
7 S2 C  P' A6 o. L8 d, J7 i(这个知识点在上一章节进行了详细说明,这里再简述下核心内容)0 `5 m( R) N) |6 R
6 w% x' F: l5 o0 i) T" u; n! T* o
Cache的配置是通过MPU来设置的,通常只用到下几种方式。
: N, h. N( |5 ^6 e7 q' j, w7 b7 i
4 W" u# Y4 T; @, }( d7 s3 H- F8 W
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDYvMTM3OTEwNy0yMDE5.png

: k& t* e3 O/ k8 |( [, B2 J# |6 C, n* }7 R- z! ^' l
其中的TEX是用来设置Cache策略的,C是Cache,B是缓冲用来配合Cache设置的,而S是共享,用来解决多总线或者多核访问时的同步问题。MPU配置的时候,最主要的也是配置这几个参数。
* U  ^: Z% r7 y- @/ x& C% D- T) T3 ^; N$ W* ]- p
Cache支持的策略有如下四种:
1 f# J$ I% P8 l! N1 V
* A. w" o5 [0 i, L- C: ^0 e
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDYvMTM3OTEwNy0yMDE5.png

/ G/ M# J) j* }8 k3 a" q! L6 f; E! P2 ^$ e0 D* t0 J' z
有了这四种方式,就可以正式进入本章的主题,Cache的读写操作是如何工作的,下面分这四种情况做介绍。
4 q, s# _/ }: t6 b" \& [0 U( c
5 @/ Y  A( K+ c, o: V24.4 四种Cache(MPU)配置的读写操作流程4 l" v" O  q/ j
24.4.1 配置Non-cacheable9 A6 g0 s$ S. p* y$ f2 K% u
这个最好理解,就是正常的读写操作,无Cache。/ W% B' z8 K! g7 }- {; U

* E8 [8 c- A; x1 K; |对应四种MPU配置如下:; ?: y0 t5 {8 k9 \8 @  D: f

; F+ B( ]; s% z5 T5 V! r  TEX = 000  C=0  B=0  S=忽略此位,强制为共享2 {3 f4 _1 I  f! h- f6 I8 |
  TEX = 000  C=0  B=1  S=忽略此位,强制为共享
6 S0 `  |) |# y) t  TEX = 001  C=0  B=0  S=0
2 ?: @& ^  h0 _; @4 {  TEX = 001  C=0  B=0  S=1+ |% J9 r* ?6 q: t8 ?' g; }
24.4.2 配置Write through,read allocate,no write allocate9 i& E% m7 C  t2 y, M9 R7 ~% O' f
注意,M7内核只要开启了Cache,read allocate就是开启的。
, v' w3 o$ ?* j* `4 p; @2 Y. J* \* c+ T/ |7 \
  使能了此配置的SRAM缓冲区写操作
0 P/ E% }# ]/ h    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会同时写到Cache里面和SRAM里面;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。
" x- r8 b1 S4 r2 |9 C8 V8 \$ }. O8 v
    在写Cache命中的情况下,这个方式的优点是Cache和SRAM的数据同步更新了,没有多总线访问造成的数据一致性问题。缺点也明显,Cache在写操作上无法有效发挥性能。) y1 w0 A' H2 c4 W; v. y( }
' b7 b* Z3 K. d# ?9 V0 `5 {7 L/ A
  使能了此配置的SRAM缓冲区读操作0 x) G& r' ]4 A. F4 c
    如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。" e% F4 Q0 o3 v4 P" c

: e% P: N$ ~. ~$ E" M# G. M- n& C6 g+ p    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。
+ r! K) a$ d  y6 u  ~
% q( t# B3 ~# k  }  对应的两种MPU配置如下:
* Q3 Y0 N4 e$ R$ P0 c& z3 S, }TEX = 000 C=1 B=0  S=1
, r% y' X9 A6 }3 {4 A8 r. _8 p$ c) v- @9 p2 Z5 J
TEX = 000 C=1 B=0  S=0
$ |  u8 a7 t& q* W  ]4 R* P! K0 J6 z0 H9 T
24.4.3 配置Write back,read allocate,no write allocate
4 D4 G: X# R! E+ W注意,M7内核只要开启了Cache,read allocate就是开启的。8 V( L  v8 E$ z  U! o2 H

" i/ G: ?5 g/ k$ D# n6 ~# M  使能了此配置的SRAM缓冲区写操作
5 s  n- R  ]5 M( L    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。
% j7 M- b8 r% G4 r
% T- m% B. \  ?* V& \4 [    安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。# ]+ I' V. n. W; c7 y
6 Q7 o% ]2 P1 n9 c; t, O
  使能了此配置的SRAM缓冲区读操作
9 e9 m3 b  V' K   如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。
- i' A; n* y  @# i& v4 n4 P# q% ~+ j1 Y( O+ e1 |' B
    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。& p/ |: I) f+ {5 H1 s2 s8 X

  Y- P5 H2 T9 m% G  对应两种MPU配置如下:
* H, J0 _+ G8 F! zTEX = 000 C=1 B=1  S=1
  E  C" {7 A$ O* D3 m: v
& Z" G8 u* b! TTEX = 000 C=1 B=1  S=0: \% x* t3 T. f2 t2 U
( O6 T# W) w7 X1 a
24.4.4 配置Write back,read allocate,write allocate5 h' t8 h6 I5 d' ^) [) C+ b3 w% ^
注意,M7内核只要开启了Cache,read allocate就是开启的。
& m0 g, Z' M$ Y" [9 h8 J! I) ^) k7 D& p! X
  使能了此配置的SRAM缓冲区写操作
3 i. x( l  g/ h! u0 `, ?9 W4 K0 V$ E! b    如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置write allocate了,意思就是CPU写到往SRAM里面的数据,会同步在Cache里面开辟一个空间将SRAM中写入的数据加载进来,如果此时立即读此SRAM区,那么就会有很大的速度优势。
! @2 u/ c5 L. N, m. l$ \' p
3 y! L( i: l- X5 u% `/ f: y    安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。, C( h4 G7 G- r% g% N. F4 w3 }
' b: J+ o! g7 l" b
  使能了此配置的SRAM缓冲区读操作/ c# g+ q6 n1 y5 ?5 J* e$ X
    如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。
5 g/ U8 J2 c1 m9 V7 e; n. t9 N, S) _( L( G: f
    安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。8 u( \( q  F8 }& r6 H/ L

6 n6 Q, [/ l$ b% Z    这个配置被誉为可以最大程度发挥Cache性能,不过具体应用仍需具体分析。
# p  H8 _' |4 u3 X- u8 O; M# q# s; H8 n" l+ W- P
  对应两种MPU配置如下:
7 W6 r" J/ W: j7 nTEX = 001 C=1 B=1  S=13 N6 q* A3 x, ~
9 U9 `, ?* e! e" `$ w  a* I
TEX = 001 C=1 B=1  S=0, D9 \$ }5 V& {# ]* B! `3 m) D& Q( {

0 ?" V0 t& k2 w, O" V$ H24.4.5 共享配置是个隐形的大坑
6 w6 q1 o$ X0 L2 l) L, ^STM32H7编程手册对其的描述是多核共享。
/ [5 O$ t+ A5 G  r) K
* Y" y& X6 d: a$ V; M, A! }
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDYvMTM3OTEwNy0yMDE5.png
3 ]) \$ i7 s; }* v

0 j0 s4 d7 f5 r4 k/ s而H7的应用笔记对齐的描述是开启共享基本等同于关闭Cache。
, q. F, X: r. u3 k, p8 p
; z4 w2 l& T; a
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDE5MDYvMTM3OTEwNy0yMDE5.png

+ L6 ]3 N& _% |* P
* C+ _/ m( }  s. O实际测试下面四种开Cache的情况,开关共享对缓冲区的大批量数据的读操作影响很大,基本差出两倍,而写操作基本没有影响,也许这就是所谓的多总线同步读造成的。另外共享开关仅对开启了Cache的情况下有影响,而对于关闭了Cache的情况是没有影响的,开不开没关系。3 |4 c' e4 v  z! T6 M

+ [# g# g0 M- E# o24.4.6 总结这几种方式的几个关键知识点+ n" \9 `0 |& F! X! {0 `7 E
Cortex-M7内核的L1 Cache由多行内存区组成,每行有32字节,每行都配有一个地址标签。数据缓冲DCache是每4行为一组,称为4-way set associative。而指令缓冲区ICache是2行为一组,这样节省地址标签,不用每个行都标记一个地址。: U" b+ u( y2 R7 ^8 r! C
对于读操作,只有在第1次访问指定地址时才会加载到Cache,而写操作的话,可以直接写到内存中(write-through模式)或者放到Cache里面,后面再写入(write-back模式)。
! f' ^! q6 c) C; W如果采用的是Write back,Cache line会被标为dirty,等到此行被evicted时,才会执行实际的写操作,将Cache Line里面的数据写入到相应的存储区。! o- _. _9 g$ A% x& `
Cache命中是访问的地址落在了给定的Cache Line里面,所以硬件需要做少量的地址比较工作,以检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记新行,填充新的读写操作。如果所有行都分配完毕了,Cache控制器将支持eviction操作。根据Cache Line替换算法,一行将被清除Clean,无效化Invalid或者重新配置。数据缓存和指令缓存是采用的伪随机替换算法。
0 g9 [9 F! U9 CCache支持的4种基本操作,使能,禁止,清空和无效化。Clean清空操作是将Cache Line中标记为dirty的数据写入到内存里面,而无效化Invalid是将Cache Line标记为无效,即删除操作。
& v$ W5 w3 a7 C24.5 面对繁冗复杂的Cache配置,推荐方式和安全隐患解决办法
: Y! @3 w* H  S, o5 {% r  推荐使用128KB的TCM作为主RAM区,其它的专门用于大缓冲和DMA操作等。; u5 Z" y5 D( a+ d4 m" {  B  u
  Cache问题主要是CPU和DMA都操作这个缓冲区时容易出现,使用时要注意。
) h6 S7 A5 u2 M" h& G& ^  Cache配置的选择,优先考虑的是WB,然后是WT和关闭Cache,其中WB和WT的使用中可以配合ARM提供的函数解决上面说到的隐患问题(见本章24.6小节)。但不是万能的,在不起作用的时候,直接暴力选择函数SCB_CleanInvlaidateDCache解决。关于这个问题,在分别配置以太网MAC的描述符缓冲区,发送缓冲区和接收缓冲区时尤其突出。
, X& w. S) B, C; C  p: s: p; Q: j: v  y24.6 Cache的相关函数
. |/ s6 h% O% D8 L2 H0 y% NCMSIS软件包的core_cm7.h文件为Cache的配置提供了11个函数:5 J$ E8 K; n5 Y+ G: F' M$ K

2 o; E" V. N6 H% h( I  SCB_EnableICache
8 f/ I1 L3 b2 |, y- f  SCB_DisableICache
. k* Z4 X+ f' g$ B  SCB_InvalidateICache  f, x0 w) }, z  G% _1 y
  SCB_EnableDCache
' k* Z' L+ d1 r7 R' q  SCB_DisableDCache2 ~8 V3 V" d; h
  SCB_InvalidateDCache9 B9 [/ @( z: E3 }& c/ t% Y
  SCB_CleanDCache$ `) X5 w9 c$ K6 y
  SCB_CleanInvalidateDCache
2 N  R9 k+ e9 w9 |; ~  SCB_InvalidateDCache_by_Addr3 s* e0 X  N( p/ k- ~
  SCB_CleanDCache_by_Addr
5 u$ y% P2 I' `% p- B  SCB_CleanInvalidateDCache_by_Addr
) _7 N# w& _2 A! T3 Q/ q: C! T6 V. ^" t0 G+ F# T

4 [5 N) j+ W  u: R7 t下面将这几个函数依次做个讲解。其中前三个函数是指令Cache,比较容易掌握。重点是后面几个数据Cache函数。由于函数SCB_CleanInvalidateDCache,SCB_CleanDCache和SCB_InvalidateDCache是对整个Cache的操作,所以比最后的三个函数SCB_InvalidateDCache_by_Addr,SCB_CleanDCache_by_Addr和SCB_CleanInvalidateDCache_by_Addr要耗时,当然,如果用户操作的存储器超过了数据Cache的大小,即16KB,那么就跟前三个函数没有区别了。% Y6 x) \5 q( J

& o' H8 B" V2 O/ C: g24.6.1 函数SCB_EnableICache
- G: M* Z( V* v( p- y) z6 ^函数原型:
. `* U: R9 f5 f" p4 ^" ^+ }7 |9 q9 z  l4 {4 L
  1. __STATIC_INLINE void SCB_EnableICache (void); z5 f1 |8 B5 ^' J( G" Y1 [
  2. {
    7 f/ M1 u8 {  d; l5 s* [# ^
  3.   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)( v: d, k6 e5 U+ d) n+ a3 t, @
  4.     __DSB();; l# @' D* B( M1 A
  5.     __ISB();* R: n% N1 G  U6 a7 K( R  g
  6.     SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */# s+ |/ \+ j6 x
  7.     __DSB();
    $ R" K+ J/ X: t$ S' A' O6 t8 v$ k
  8.     __ISB();
    ) f, }; J0 g- T( ]2 }/ {! R
  9.     SCB->CCR |=  (uint32_t)SCB_CCR_IC_Msk;  /* enable I-Cache */
    + ~* |8 r0 z2 d7 c' L
  10.     __DSB();7 l2 ], S) m" Z& `3 e! A
  11.     __ISB();
    * P' B8 a) h" H8 H; G. F$ L
  12.   #endif
    / V; E" C1 a! ^4 C
  13. }
复制代码

) ^0 Q/ `- f% {; W( E3 K" c0 E函数描述:
0 T% Q, @! }" x& w1 O1 [
. A7 v5 Y, f+ O此函数用于使能指令Cache,系统上电后优先初始化即可。
# G, o) I7 T5 |: @; c# X, m. [; b9 A6 b4 @
注意事项:
8 S9 ]& ~0 y% r9 Y! T. a
9 N+ d. u/ y: y/ n8 }) o  __STATIC_INLINE:
7 A$ e  ?$ z* W9 b* p, b表示内联函数,这种类型函数的作用就是将函数直接嵌入到调用此函数的代码中,从而降低调用此函数所占用的时间。
' i' _, q7 o+ z! k
+ _, ]" ^' \, w* O& G- I  __DMB指令:/ N6 V: d* p+ w/ G& ?0 Z1 g% P
Data Memory Barrier(数据存储器隔离),DMB 指令保证所有在它前面的存储器访问操作都执行完毕后,才提交在它后面的存储器访问操作。
$ O  I/ s$ N5 Q/ c4 t! K& c! d+ M0 ]' j! W
  __DSB指令:
# g5 V/ {% x! u: |5 ?6 F! K, H+ xData Synchronization Barrier(数据同步隔离),比DMB严格,当所有在它前面的存储器访问操作都执行完毕后,才执行在它后面的指令。0 t0 J$ D8 J. E1 G
/ f. g5 X8 Z7 R+ Y1 k3 R1 q
  __ISB指令:
, \+ V, g2 ]0 Q7 `0 C  p  R$ ^Instruction Synchronization Barrier(指令同步隔离),它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。0 U" O5 @, o0 {6 {: k) `
" @& L9 c( v1 j- P5 q+ o9 n, T8 _, x
24.6.2 函数SCB_DisableICache: c: E  K, v  b0 |6 f
函数原型:, c  ?, M3 O0 R
' i1 \9 m' E5 B; N
  1. __STATIC_INLINE void SCB_DisableICache (void)- n' f) j- p' U0 X8 |3 r" O
  2. {
    1 l6 g" @6 d6 b% o
  3.   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    ' O. f5 b! U+ d- ~; k
  4.     __DSB();1 H+ B+ R" c" T) L6 a
  5.     __ISB();
    4 b& ^3 z7 C7 R0 x3 i9 [
  6.     SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk;  /* disable I-Cache */
    % ?7 |1 P' o- L+ F, U
  7.     SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */( {" I3 X7 c' `3 e/ P+ t# l1 u
  8.     __DSB();
    . b' n* e: N" {- I
  9.     __ISB();9 b4 `5 ?5 z- Z' q- y% P2 l6 }4 |
  10.   #endif  K4 k+ l3 C/ b5 G
  11. }
复制代码

+ H# _+ Q0 m" `( ^, I4 v函数描述:7 }. N8 o+ Y. u9 ]0 B# a

8 ]8 U1 g7 s8 @# l  ]! O9 w此函数用于禁止指令Cache。2 V* l' |% D' y+ F. P# Q; E; k! o/ a! G

0 S8 v& m- l# v2 |8 |注意事项:2 a+ ?2 t! w' V7 k
  Q5 [! f  h0 U
__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。# @6 ?, _  ^: P/ X

, U1 O# Q0 s6 _2 k8 |& {24.6.3 函数SCB_InvalidateICache, k5 \  J( A9 f. ^; N* ]
函数原型:% [: C7 m7 `* C/ w8 ?( h- D

( F( o" y, Q: j2 q" s/ t, j
  1. __STATIC_INLINE void SCB_InvalidateICache (void)% \% K( g2 ^. Y' n  k  j! O
  2. {5 v( |" ~3 Z7 ?' C4 u
  3.   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    8 ?( \4 V1 ?" n9 K( h" H) P
  4.     __DSB();
      j) a5 ]/ e/ C  `
  5.     __ISB();* j; j: M$ n* G- c
  6.     SCB->ICIALLU = 0UL;' b) x! _& v: d/ K
  7.     __DSB();
    % c- N4 z. E8 G* E- t+ f
  8.     __ISB();# q: C  V( s! v, L
  9.   #endif5 t. }8 u7 {* M+ s, L: X4 I  D
  10. }
复制代码
; u2 ~& w  r9 t  Z! _
函数描述:
- k9 {" v% I% r  P
9 m  r0 b( V( U0 D6 c4 v/ V' x此函数用于将指令Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的指令。9 U0 a, o8 [8 L$ w
5 p6 u/ s. s, ]; \: D
注意事项:* k/ s; m9 j0 q/ S+ N' w. V+ X

- s3 h" }* h* B2 T% b__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。" T4 w6 k8 l9 n2 v( a2 a6 J
; H: N, u3 E0 B/ z* q) `  x1 c
24.6.4 函数SCB_EnableDCache
, H7 c9 z$ z) M/ l) D+ t函数原型:
  R/ w# f) q# u/ t: [7 Z4 }! G( N
8 E: G6 ?1 ~* C' Q. m  r% b6 l7 a
  1. __STATIC_INLINE void SCB_EnableDCache (void)
    * {& T+ v- O" d2 M, h0 {* j
  2. {
    & n2 W! Y7 x' E1 V  W
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    : {/ [" S2 F+ W# R4 u
  4.     uint32_t ccsidr;+ _/ b: x. g( q6 q) D: {6 |) a7 S3 d4 Q
  5.     uint32_t sets;) N  n  {, Z3 n7 L
  6.     uint32_t ways;
    - h6 ^: s! ?, }$ d. p

  7. 0 ^8 m! n" R2 e* e1 c# q1 C2 V8 J& Z
  8.     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */* e4 a9 b7 n- p) g) N
  9.     __DSB();
    + H! p. u' u& H( Q# q

  10.   ?& S- w% S/ C6 l# j8 h* `% t
  11.     ccsidr = SCB->CCSIDR;
    8 n% G5 l! u- N; }4 X& x
  12. & q% L% F0 c; Q
  13.                                             /* invalidate D-Cache */: d4 }' g5 h" m/ u
  14.     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    3 B" r! m9 D" M3 n9 H
  15.     do {
    ( E& l: L, _- M1 b4 j4 r
  16.       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));/ o3 j" m; n; M: X2 p
  17.       do {
    / U, V7 ?1 L4 G: T8 g
  18.         SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
    0 w' F# N$ g+ f7 R7 \
  19.                       ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk)  );
    ! G! m2 q. ?- @( R* |1 k) u+ l$ ~
  20.         #if defined ( __CC_ARM )
    # C: l9 w* B. _# {5 C
  21.           __schedule_barrier();
    6 A4 ?# H' I  f. U( B. i7 I* s
  22.         #endif# X1 _3 m( H9 c) o0 W. ?
  23.       } while (ways-- != 0U);
    $ j% B3 D# o- k
  24.     } while(sets-- != 0U);
    ; T7 x. l" }9 ?- ^9 R
  25.     __DSB();* G. z, Q/ n- U9 [" I  O+ X
  26. * X6 I$ e; |% j% Z$ L  _9 `
  27.     SCB->CCR |=  (uint32_t)SCB_CCR_DC_Msk;  /* enable D-Cache */* B3 F! Y, o6 c: h$ e) ?4 Z& }% I; Z
  28. 0 T$ l- @4 y5 C' V
  29.     __DSB();. z: F. x& ]% s( Q7 i  B# t# k
  30.     __ISB();# k4 R' h) p: ?4 R( }
  31.   #endif8 |* {4 d4 ~5 I
  32. }
复制代码
* ^5 O& N' {+ M) }
函数描述:
- }# P: K! l: @( [$ @1 e
1 I* }) q5 n& A& v! ^3 H# F9 d. L此函数用于使能数据Cache,系统上电后优先初始化即可。$ I" I/ u2 V- k2 b0 h

+ G7 G& u+ q  v% k注意事项:
' @3 K* g/ E4 R. s
) s% _% u4 V, c' l+ B# D0 j__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。
$ b3 W$ G; R/ t. s) C. N4 q* n0 D" }$ H$ Q! b! A2 h
24.6.5 函数SCB_DisableDCache7 G* p! L. m4 Z. Y
函数原型:
' `# e' I0 s3 A8 j% |5 V3 x6 F" k6 M9 N1 c
  1. __STATIC_INLINE void SCB_DisableDCache (void)
      R% H: O2 W! S5 C
  2. {
    ) _6 p3 V( F' w# I5 [; |
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
      ]+ d6 k: n/ t. N; A2 l0 ^
  4.     register uint32_t ccsidr;
    3 A# M+ u4 a" X, [5 [
  5.     register uint32_t sets;/ s( V0 N* _- _# a' G
  6.     register uint32_t ways;  ~: r" b% M" o( ?

  7. + F, s3 K( r5 {1 t" e# O
  8.     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */, X7 Q0 A% S8 P! J+ z. T/ R
  9.     __DSB();# L$ _# h: n1 D9 J% U: I/ Y

  10. " t/ Q5 ]0 O0 D2 [
  11.     SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
    ! v, w4 Q& _( \7 d7 i7 B7 q8 y! u
  12.     __DSB();
    " F/ w) o/ |7 \

  13. ! n; r  E& o8 b
  14.     ccsidr = SCB->CCSIDR;
    2 D7 D/ O* `: \9 \$ }3 l* F; {

  15. & ]; l9 s3 X+ L+ s$ F; }8 z' d
  16.                                             /* clean & invalidate D-Cache */
    % N; d5 @1 \& N6 c
  17.     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    . C# n. d0 f2 E3 ]. u" ]
  18.     do {; G' N7 U) b& {& a( [
  19.       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
    # [" Z+ D/ e/ D# {* W1 F$ h' ?
  20.       do {, T$ ?# T8 A1 k- @
  21.         SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
    : _8 d0 j+ ?1 a3 ]( b
  22.                        ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
    6 k: `1 h7 v/ P( J" _; }8 `: x
  23.         #if defined ( __CC_ARM )! R6 R( b; I. n& s, _% R
  24.           __schedule_barrier();
    + X3 }- n8 q' b  }
  25.         #endif
    4 H3 z9 ~  ], s1 w6 _- K# }
  26.       } while (ways-- != 0U);" z" J5 L0 s$ U; r% a! B" S
  27.     } while(sets-- != 0U);
    9 w0 ?6 d1 t, W; o) F5 Y! ^
  28. + s) h7 z" W1 U5 H  k
  29.     __DSB();5 @" G% l, ~8 v
  30.     __ISB();
    ( \* d8 c) Q3 S1 t: e+ f3 S3 I% ^
  31.   #endif$ H" @- w3 T/ W& x
  32. }
复制代码

& y0 b. x3 L  v4 o/ j* R函数描述:
8 y( L5 z1 d, E. J
0 u2 B3 h" j. f. }此函数用于禁止数据Cache。  X" N& y  i; R! ]* l' l. m

  a1 q$ B5 Q  M, w/ i8 G: l注意事项:
; b4 P5 W3 K, C- T0 U5 e6 Q
' D* |/ R0 j; ?; |! G/ |8 z__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明" D8 a1 K5 q: P
4 y/ n3 v, o/ i- o5 ?0 U
24.6.6 函数SCB_InvalidateDCache
' r0 Q$ E$ p& d! Z- U! ?% V函数原型:. e. ^( ?0 i0 f

7 [2 b: n$ i- g5 d
  1. __STATIC_INLINE void SCB_CleanDCache (void)& b+ c( y+ V5 g0 t  K) a
  2. {1 A% t; d0 F$ _, y
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)8 t: i( H+ V8 o) z3 c- M  c! b
  4.     uint32_t ccsidr;0 J+ R2 v! _$ `3 [; @0 n/ M
  5.     uint32_t sets;
    # J2 a8 ^, h% a
  6.     uint32_t ways;
    8 O9 ?4 S" M% o  T9 `* L

  7. $ }* ^% }8 f" u8 [. \
  8.      SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    & N+ s! d; A9 o3 u0 q. u  D+ u
  9.    __DSB();
    : b8 O! M& t6 Y

  10. # q3 O6 i  a+ v7 h
  11.     ccsidr = SCB->CCSIDR;
    9 h4 O) t% C8 g" G8 O

  12. 3 U7 h" x9 c+ H' e7 @8 E- E
  13.                                             /* clean D-Cache */( m1 g. Q# n9 r7 l- @/ a6 `" ^
  14.     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    / v$ t$ K1 c' ~- s4 x
  15.     do {
    0 b$ w* x" ~# m
  16.       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
    ' z9 ?0 s. d8 X1 a
  17.       do {% u$ Z8 R9 {! w! k  c( |' m" Q6 Q
  18.         SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |. O; h# y) R7 ~( m: P
  19.                       ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );, e9 @, q% _1 }8 O
  20.         #if defined ( __CC_ARM )" b: b; c( p3 L/ t5 f
  21.           __schedule_barrier();. `! q  u( E+ E( k& q+ T/ C+ A
  22.         #endif) h" O' C; ~# O& P
  23.       } while (ways-- != 0U);
    ( H. d- _( }; I, B- I' P$ \- B1 Y
  24.     } while(sets-- != 0U);
    & D2 P) f7 v0 G) Y+ @
  25. - F2 Q6 R% g* ^2 o/ S, G
  26.     __DSB();
    $ `. v0 V1 m3 u& A" w" w1 O9 q
  27.     __ISB();- d7 X* Q3 E5 W' q: q
  28.   #endif  S1 P& H/ J$ {3 ^$ L
  29. }
复制代码
- v  n2 H' S; R- n1 C, b
函数描述:: X0 I/ h& Q$ |' v9 h8 A' {. ^
4 B  X2 ?8 `9 C( F5 [5 E
此函数用于将数据Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的数据。( m$ T2 p5 B- {' N

, m8 N7 H3 }: _; p9 {1 x! N注意事项:
! E; W8 |. Z+ V& ]" y: P% ?/ s/ z: q; |" u4 E, U
__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。; I. N( x) g+ m7 F! `

5 M; C0 Y/ H: L: y1 J) a+ E24.6.7 函数SCB_CleanDCache
5 B1 J: w1 a" d" x函数原型:' h# M; a) B4 R! o
7 n4 M5 G4 L2 E9 _' x8 U6 K
  1. __STATIC_INLINE void SCB_CleanDCache (void)# O1 Q  j5 C8 F& t. B. v, T' o
  2. {
    ! \- t& h# A+ P: w0 k
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)  u! g9 [) g+ r' Y8 P
  4.     uint32_t ccsidr;
    9 [9 g+ W3 g6 s% U0 I0 g3 p
  5.     uint32_t sets;2 K9 s8 c6 G+ O$ _) Z9 j
  6.     uint32_t ways;
    ' j& C1 a7 [9 w" H
  7.   @, W/ {( o) {  H1 R0 Z
  8.      SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    * Q- S0 ~+ R" b. t
  9.    __DSB();% I. M6 T2 g& v5 [$ u  O/ N- u, ?

  10. 8 ~) A: k  K" Q9 r( O& R
  11.     ccsidr = SCB->CCSIDR;
    ! Q" H6 l& Y, Y7 B3 i
  12. 2 J+ i6 P( Y' u6 _) _1 v, T
  13.                                             /* clean D-Cache */
    9 I3 E+ W6 g5 @$ P" w" A" D) y
  14.     sets = (uint32_t)(CCSIDR_SETS(ccsidr));9 a1 b5 M* l. G. t1 |- t) y
  15.     do {5 ]( d; R! c& x) Y" c
  16.       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));0 K5 D- V: v; Q  B& \1 @' L
  17.       do {
    ' Y& t0 ~1 x8 A% N
  18.         SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |. R4 q: a) ~: y
  19.                       ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );2 C0 a# j& K2 f3 b  ~& o  `5 p
  20.         #if defined ( __CC_ARM )# k/ _! R; r/ r( z4 X  ^
  21.           __schedule_barrier();
    7 H5 K4 R" t8 Z! X( T
  22.         #endif& w& c1 W7 C; g! S3 x
  23.       } while (ways-- != 0U);
      J# A% N' @* [4 N. u4 V
  24.     } while(sets-- != 0U);
    6 f2 E# O; _! g

  25. ( D  L) A8 R- b( d
  26.     __DSB();
    + g0 S3 W, s- d" ]; V
  27.     __ISB();
    . @- E; B/ y  ~3 e  k# t: y
  28.   #endif
    , a7 C$ w; U  N& T
  29. }
    : e- K# b& z" e5 }$ r: O% s
  30. 函数描述:
复制代码
2 y, ^/ Q7 a! e: w- d

) \2 H6 z; q8 z# l2 f此函数用于将数据Cache清除,清除的意思是将Cache Line中标记为dirty的数据写入到相应的存储区。
* C. b! w8 r& G8 |! g; f: A1 U( X* I7 T4 R2 i% [5 K* g3 d
注意事项:
" q1 [$ z6 K) g. \
7 h1 ?$ ^  h- x7 ]) }$ C" h__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。. U( y$ z1 _! E0 G  [+ {

7 ]1 }7 q; h; j% G+ i3 I3 o24.6.8 函数SCB_CleanInvalidateDCache. x: a% n/ v% K1 Y- ?& Z
函数原型:5 z  Y1 u5 Z3 q2 g) \

3 B$ Z' i( A2 J; N* d5 z
  1. __STATIC_INLINE void SCB_CleanInvalidateDCache (void)
    . O1 i) J  k+ D# L
  2. {
    # ?0 p0 Q. v" f* H2 ?4 ~- l6 G
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)0 }) B  l1 _6 y2 X% S" v$ D
  4.     uint32_t ccsidr;
    " h- @/ {$ @5 C& E' `
  5.     uint32_t sets;5 R# z- S5 D0 K) X4 p/ ?% Q- s
  6.     uint32_t ways;- x. D9 r6 K/ M+ M- f9 @

  7. $ t9 g) |" O7 _8 B
  8.     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    $ b% O/ |' f5 C( W
  9.     __DSB();
      q+ _# l# F7 k! f+ w1 h: b9 B

  10. . c% ]4 L+ h4 P2 f* a" f
  11.     ccsidr = SCB->CCSIDR;  G) I: y+ s! Q4 z3 {' m6 i
  12. 5 M# U! ~9 T9 o
  13.                                             /* clean & invalidate D-Cache */
    . Z' D; `: [% r- u5 t
  14.     sets = (uint32_t)(CCSIDR_SETS(ccsidr));+ n& c/ A7 E+ Q. p1 `: r
  15.     do {
    - d; }  ~0 `- U% T" P
  16.       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));6 Y4 j$ {" N# P: k- `$ ^
  17.       do {
    + d/ l3 F" z7 O& Q1 z1 e
  18.         SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |$ P5 J: J  C% }2 i
  19.                        ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );# P7 n  t0 A  f6 @
  20.         #if defined ( __CC_ARM )
    " A- r5 n) \3 K
  21.           __schedule_barrier();  l* n$ Y" v/ x4 h) L. N/ s: `
  22.         #endif
    $ P& d& R- j3 G. b
  23.       } while (ways-- != 0U);) D( O" ?( c) @1 P
  24.     } while(sets-- != 0U);( f( e6 E0 w. C2 G% i; H: S& X4 p

  25. 6 Z# D8 e) p% C: X
  26.     __DSB();
    $ |6 p. l1 G. c( V5 }' m
  27.     __ISB();* O: ~/ K4 Y: L% j
  28.   #endif  d9 T; I% a  [: r0 Y
  29. }
复制代码

% B! d  E# d, R& y$ z函数描述:
" c1 s3 H7 R# e  J
: Q$ C, j  t; n) q8 K/ E- g6 c3 l+ m此函数是前面两个函数SCB_InvalidateDCache和SCB_CleanDCache的二合一。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。
$ U5 j7 A& f5 F/ R! t: d& H
* G+ M2 f2 G, T5 m注意事项:
( f  @9 u( Q) [
, E* B3 {" ^" e4 U__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。& R- J3 o/ u: ?) Z1 R7 t2 U7 w
; j9 O, f7 a1 D  m
24.6.9 函数SCB_InvalidateDCache_by_Addr
$ u# ^3 M' O6 G8 r7 q函数原型:; p5 H* i# {/ d4 A- K% _: f" U

% ]' k% x2 b' @, A2 d6 R$ m5 P* A
  1. __STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
    * _$ T2 M! y2 V
  2. {* O4 g2 g& d  Z0 e$ q) t, p% _) a( l
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)) J% ^. F: T: V
  4.      int32_t op_size = dsize;8 {1 d# c! A) r* M& i1 ?$ T
  5.     uint32_t op_addr = (uint32_t)addr;
    - I# ^% ~' t# J8 K! F& \: @8 t7 C* d
  6.      int32_t linesize = 32;           /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */
    ; f! ^* {# a: v) g

  7. 3 z4 E' w& {, f, B1 v" O" f9 f
  8.     __DSB();1 a/ R: X: ~  e8 b
  9. - l; F: D" `  j; a- u! Z" p
  10.     while (op_size > 0) {6 N  p2 C9 L& x# N' P: J7 I6 \' x
  11.       SCB->DCIMVAC = op_addr;
    - Z) K! o, `7 F" M/ h; F2 O0 ?' |6 m
  12.       op_addr += (uint32_t)linesize;+ F4 ~$ T1 l: u- d8 Z
  13.       op_size -=           linesize;& ]( W% V* g6 P$ T( q/ N
  14.     }
    3 A4 G1 J5 S: J$ H, H, c/ ]
  15. * {$ C/ `$ M* t+ @4 q; a* G1 k- J8 l
  16.     __DSB();8 [8 Y" ~, `- Q' X6 M% Y7 q1 ]/ w) @
  17.     __ISB();
    6 G0 Q6 F5 {1 ?% W
  18.   #endif
    ) G" V  E$ f4 C9 k
  19. }
复制代码
8 ?2 j# ~9 f  J) ?" L! R! F
函数描述:7 x7 o, z. v( P- l* M% m0 M

8 q5 \) g8 l$ ^, m* j' Y4 M此函数与本章24.6.6小节中讲解的函数作用一样,区别是这里可以指定地址和存储区大小。用于将数据Cache无效化,无效化的意思是将Cache Line标记为无效,等同于删除操作。这样Cache空间就都腾出来了,可以加载新的数据。2 Z8 D) g5 v8 I; e

% \' z+ f1 m3 M# W6 o/ b: A& v注意事项:
! ?" M3 p" z; q- a: M% B1 i( V0 S/ H& e3 ^9 S
  __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。
2 G9 H6 h/ f9 A# P2 ^  第1个参数addr : 操作的地址一定要是32字节对齐的,即这个地址对32求余数等于0。
( @9 t+ N2 ]* F" z8 W* ]  第2个参数dsize :一定要是32字节的整数倍。
. F  e7 u6 s0 l24.6.10   函数SCB_CleanDCache_by_Addr
5 ^# |1 A: B# N' o函数原型:' b; c- V) s8 s0 }, K9 [6 W& W

+ z5 A( ^5 Z0 |( k" `! \! |
  1. __STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize)& t: }& q. G1 I
  2. {1 @; O8 Z) F" L4 ^; i
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)" g; T$ d0 [2 m! d* U7 x1 s
  4.      int32_t op_size = dsize;
    ( [" N& O( p" t( u
  5.     uint32_t op_addr = (uint32_t) addr;
    0 E! e7 i, e* O% d
  6.      int32_t linesize = 32;            /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */& p" O- }/ N1 R2 K8 f& n

  7. ; g" e5 O8 ?, Y, F* i$ T( S
  8.     __DSB();" ~8 O4 u0 q" B) C. [( I
  9. & ?8 p' j) i& E) K& w
  10.     while (op_size > 0) {9 }, |* G8 T, C2 t
  11.       SCB->DCCMVAC = op_addr;2 Z, {+ ~0 E9 f; l+ D8 j
  12.       op_addr += (uint32_t)linesize;" h1 e( ]3 q+ k' [# Y5 a
  13.       op_size -=           linesize;
    0 e* U3 T) u" h
  14.     }/ }% i: x* @/ `' [0 d

  15. 0 g, e: ?! g. ]  z' t
  16.     __DSB();
    9 i( V2 S! i1 T
  17.     __ISB();! j1 J/ l- J5 Y, O2 t
  18.   #endif
    5 {: J% Z0 N7 B0 k# J6 v# H6 @) g$ ]
  19. }
复制代码

, g! {0 v3 N6 G2 j: L# L函数描述:
6 d4 G3 C% h" a8 Q5 t0 M! F
6 F# G/ Z$ b, |( D此函数与本章24.6.7小节中讲解的函数作用一样,区别是这里可以指定地址和存储区大小。用于将数据Cache清除,清除的意思是将Cache Line中标记为dirty的数据写入到相应的存储区。
# `4 V" B' R1 p0 Y1 M. i  Z/ I" w0 I: M; z2 d4 W$ b% y
注意事项:! h0 W! `4 e2 S5 O0 z0 l0 n
  _! u1 T4 J0 t4 b2 ~: Q
  __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。
# h' g" I0 L' w; o/ n. j  第1个参数addr : 操作的地址一定要是32字节对齐的,即这个地址对32求余数等于0。
3 j) V+ j3 ~& c5 R1 O+ |# e4 N  第2个参数dsize :一定要是32字节的整数倍。
1 K6 X  @( Z% E' w( O  F24.6.11   函数SCB_CleanInvalidateDCache_by_Addr) P0 x9 S% {0 x1 a7 u/ O9 B1 z$ N
函数原型:
. [4 e: O- E+ W# ?" P1 m+ {  t# ?" u6 O
  1. __STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
    5 w$ U' E) E. m% T' i/ |
  2. {- J7 U" z6 Y6 i4 L9 r$ ]
  3.   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)# T/ Y1 `1 {, H- ~
  4.      int32_t op_size = dsize;: [* H1 \' O& w5 X* s0 p
  5.     uint32_t op_addr = (uint32_t) addr;
    2 e+ X& U0 G* G# t; N. R
  6.      int32_t linesize = 32;          /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */. S4 [6 V) {+ d  y5 T

  7.   Z% j# I+ ]0 [7 z
  8.     __DSB();. m$ B, X7 ^) G2 ]$ m' o
  9. ' l, a6 t, a& ~# M* Z5 k
  10.     while (op_size > 0) {/ }) T5 y7 C9 h1 E1 b; X9 J& M
  11.       SCB->DCCIMVAC = op_addr;
    % y5 L/ d( |2 H+ E' ^$ d3 |
  12.       op_addr += (uint32_t)linesize;' e" U! ?! A# m
  13.       op_size -=           linesize;
    6 `. f2 [0 R) d  M7 _$ Z
  14.     }
    ( X0 V! y) U7 r) \! {# Y% B( S

  15. * i8 }1 g( L& E5 w* l' n
  16.     __DSB();
    ) m) l9 e* q2 x% l
  17.     __ISB();( \7 G* u* {" z7 {* r+ }6 h, s0 A
  18.   #endif8 e$ M0 [1 K& @3 y
  19. }
复制代码

. R/ n: @' K( h/ j  J' L7 N函数描述:' o7 \. B+ `1 h; h
, y, T1 f4 o+ L1 ~( ?2 ^
此函数与本章24.6.8小节中讲解的函数作用一样,区别是这里可以指定地址和存储区大小。将Cache Line中标记为dirty的数据写入到相应的存储区后,再将Cache Line标记为无效,表示删除。这样Cache空间就都腾出来了,可以加载新的数据。
  ^2 J9 r$ Z. B, a- p- T0 v! B) u2 g+ h1 K. R
注意事项:* n5 S6 ]* {6 m# r; \1 O
9 K( V' X5 s9 J
  __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小节的说明。$ Q8 a( i. Y$ |1 e8 h
  第1个参数addr : 操作的地址一定要是32字节对齐的,即这个地址对32求余数等于0。, c$ W# l5 q& ~0 p1 k5 p& K
  第2个参数dsize :一定要是32字节的整数倍。0 r6 @/ [: |9 k
24.7 总结
  T3 `8 \  r! B本章节就为大家讲解这么多,务必要反复多读几遍,能理解多少算多少,随着后续章节的学习再回过头来再学习。
$ d+ c4 K3 c) b& w- J' z/ ?
8 v9 S" W& R" y- ]- f/ i3 ~
" j* H+ I" T: N& n& p5 l# B* r
赞 收藏 评论0 发布时间:2021-10-26 23:17

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版