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

【经验分享】例说STM32F7高速缓存——Cache一致性问题(三)

[复制链接]
STMCU小助手 发布时间:2021-12-13 23:02
3. Cache 一致性问题
1 v! ]: J, p: C9 T/ {0 j; X3.1 什么是 cache 一致性问题
, D; u9 F1 p+ C所谓的 Cache 一致性问题, 主要指的是由于 D-cache 存在时,表现在有多个 Host(典型的如 MCU 的 Core, DMA 等)访问同一块内存时, 由于数据会缓存在 D-cache 中而没有更新实际的物理内存。
) e" h9 h( x1 F( \2 C& _
6 v/ M& j' X* j* U+ \在实际应用中,有以下两种情况:
! p6 O4 M* l. O( X
9 l* n: c5 I; N5 a" u第一种情况是当有写物理内存的指令时,Core 会先去更新相应的 cache-line(Write-back 策略),在没有 clean 的情况下,会导致其对应的实际物理内存中的数据并没有被更新,如果这个时候有其它的 Host(如 DMA)访问这段内存时,就会出现问题(由于实际物理内存并未被更新,和 D-cache 中的不一致),这就是所谓的 cache 一致性的问题。
7 x  ^6 G8 I0 u
* `0 |; }+ {& O" q2 h2 U
516a4fcb212a09183f4c3f3efa77d170.png

7 E; R7 @  t# M4 k& g) g9 O! s
8 Q% ]' P* B2 n
图3.1 Cache 一致性问题 第1种情况
( F+ M+ E* z* N# _* p& V$ V/ e
+ {" d- T# ?8 P$ g( n# [$ @/ j
第二种情况是 DMA 更新了某段物理内存(DMA 和 cache 直接没有直接通道),而这个时候 Core 再读取这段内存的时候,由于相对应地址的 cache-line 没有被 invalidate,导致 Core 读到的是 cache-line 中的数据,而非被 DMA 更新过的实际物理内存的数据。
  P$ I2 ]8 b3 c; ?4 I* Y! d6 K* M
, \6 j  i! i/ v" N+ C& i
ba3341c9a0e0ddc198b5fe0466a465dc.png

- |( y1 p, P" n4 C; p* E& r* Z( _: ?8 E7 ^7 Q
图3.2 Cache 一致性问题 第2种情况
+ P5 N0 p, C4 {# ^

# ]9 Q, N% Q8 L5 T: T# c% h: d5 N3.2 如何处理 cache 一致性问题
. j" }# q" v- W; N
我们知道,Cache 机制是为了提高存储系统的平均读写性能而设计的,但是这种机制带来了数据一致性问题,然而,却没有对一致性的硬件支持。
; E9 Q$ |) U% n5 Y, W, Y( d# O
% {% E+ ~1 M2 Z; J% A( c3 K因此为了解决一致性问题,一个办法就是禁用 Cache(cache 都禁用了,肯定不会有 cache 一致性的问题啦~)。但是如果你选择使用 STM32F7 这样高性能的微控制器,又不使用其带来的高性能特性,那你为什么要用 F7 呢,用 F3、F4 不就得了么?所以为了提高性能,还是使能 cache,并积极解决 cache 一致性问题吧。3 u: m! x. }7 N3 J: _8 a3 o

: Y) s+ L$ [" c5 ]  n) |$ N好吧,解决 STM32F7 的 cache 一致性问题,有两种可选方案:
* k2 A( _3 W  {# p" {: I
9 O* S5 U, v3 V# F9 w7 |所有的共享存储器都定义为共享属性
# ]' x1 G, Y  `0 n/ D, [2 M, ]* j1 x6 `, D" g" }) Q
这些区域将默认不被缓存到 D-Cache。
/ ~+ g! x1 n4 a9 \' s* X% Q6 `所有的操作都直接针对二级存储器(内部Flash,外部存储器),性能降低。
6 t! g& I5 q1 E$ s1 d# e# ~6 B因为缓存对这些区域是透明的,写软件更容易。3 k3 N5 p1 ]) I+ c
6 c0 M; b+ a# U/ e4 g
通过软件进行cache的维护5 y* b1 r7 {8 J; M7 X0 a
(1)Cortex-M7 的写操作要是全局可见的
& y; b2 R% m6 ^' S
7 C# ^) i# i9 o8 O3 r* {使用透写属性(通过 MPU 设置)。) f  b, P' j3 j! u: h- Q
使用 SIWT@CACR(Shared = Write Through)。1 g5 O) O$ F  Z( w& X& X
通过指令清 D-cache,然后所有更新位置禁止 D-Cache操作。7 M, q: ?+ E& A3 W
(2)其他主设备的写操作要对 Cortex-M7 可见/ D7 }+ C; G% \  |  @# G

3 X6 d  J  Y# B比如作废 Cortex-M7 Dache 中数据。5 ], l* R: K; U. Q& t' q# E
3.3 示例4 X& J0 I2 T% _8 V" n
3.3.1 程序描述
9 v1 \0 X* X; H: u% r% p(1)首先将地址 0x20020000(SRAM1)处开始的 128 字节初始化为 0x55。6 a2 `. S* F' ^/ b0 D8 V
(2)将 Flash 中的 128 字节的常量数组 aSRC_Const_Buffer 拷贝到 SRAM1 地址 0x20020000(pBuffer)。
5 ^/ V- T8 I0 {  T0 k& a. ^(3)配置并使能 DMA,通过 DMA 将数据从 SRAM1 的地址 0x20020000 处拷贝到 DTCM RAM 中的数组 aDST_Buffer 中。: v1 G$ t* W1 L3 u, `: j
(4)将 Flash 中的数组 aSRC_Const_Buffer 与 DMA 读出的数组 aDST_Buffer 进行比较。# {1 m1 H4 D; C6 |& k- Z9 v4 l, y

& }0 B5 ~  e7 y- [. q9 u, |显然,这个例子中的 cache 一致性问题, 展示的是上面(图3.1)的第一种情况。也就是在 Write-back 策略下,CPU 先去更新相应的 cache-line,然后 DMA 去访问对应的内存,从而导致数据不一致的现象。
- E* e% [% G. q, W8 {6 h
  J1 P$ }$ a4 @) n7 F程数据的传输流程和路径如下图所示:
6 V# I6 w$ p; E% {# b. ]) Z0 |9 e& i  H3 r3 |
d0db73574a58707717ae26695e9dc302.png

# N3 b& \+ ^: \( y( H( v' i9 N' M; W: A  t$ q) Y5 Z9 N5 w4 h
图3.3 Cache 示例数据传输框图

8 `* W7 h/ N0 A0 s. _& ^' V4 p9 @1 V) a8 E0 n3 ?$ b# q- l
3.3.2 复现 cache 一致性问题
1 G; K& \3 ~5 ]. ?3 w: |我们先来按照示例要求编写代码,复现 cache 一致性问题。有些人可能会疑惑,变量数据怎么放到 Flash、SRAM1、DTCM?实际上,可以通过一些相关的配置文件进行设置,比如 icf 文件、scatter 文件等,当然,这跟所使用开发环境和编译工具链有关。. H% t7 ?$ P8 w$ j# n

+ i* h4 Y4 |# |6 V/ _) b0 b& v4 m本文所使用的环境是 IAR,其链接文件 *.icf 如下:& _3 Q; A9 s: W

' _1 Z4 o+ X4 K8 }, {. K& _
5377967a69d8334b1bbd7b99f41c9e23.png
* k' L5 u) M4 p7 A' R7 X% J: R

; V0 c) w3 \3 U6 n6 f- E然后将 aSRC_Const_Buffer 数组定义为常量,即可分配到 RO 区域,aDST_Buffer 定义为普通的全局变量或静态变量即可,因为内存区域从 0x20000000 开始,也就是 DTCM RAM。' }/ z2 n8 F9 P" ^) `; w

: m( R$ z/ X- F/ K$ M好了,代码主体部分如下:
' B# b0 c' B' M' g
8 V; k9 W) b* }, V( T2 ~+ I
  1. #define SRAM1_ADDRESS_START   (0x20020000UL)
    5 N; a; N$ f2 y! I( i

  2. 1 T8 v9 ?4 O. k! V$ J( F" P! ~, }
  3. static const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] =
    : [1 ^% d2 b! q, t& d) H# {
  4. {, n9 s5 @4 v  ?* |! B. \
  5.   0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,
    8 p7 L  e  _, w# N7 O" h" R
  6.   0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,2 i: L, U. W% L4 i
  7.   0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30,. V9 E" n  o4 I8 }, e' C1 p; ?4 D. P$ z
  8.   0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40,
    # Z/ w3 P7 A) X
  9.   0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50,
    ' U/ ^+ e% P/ Q) S+ j7 `
  10.   0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60,0 T! `0 C! j/ V6 A8 \" o
  11.   0x61626364, 0x65666768, 0x696A6B6C, 0x6D6E6F70,, c) e4 n0 m( g. |
  12.   0x71727374, 0x75767778, 0x797A7B7C, 0x7D7E7F80* W1 Z5 U7 e* z+ z
  13. };& e1 @& \# R7 x/ i! A) p4 x
  14.   X/ Y6 A& \& P. Y9 L! Y3 N
  15. static uint32_t aDST_Buffer[BUFFER_SIZE];
    . }+ K8 s* v- C- J( |0 G

  16. 2 b' g0 H' q2 ?# c# q( I
  17. int main(void)
    9 n* }! ^# Z5 l! p% h: Y
  18. {
    ! R# `* }4 T2 L+ W' q8 M- C
  19.   uint32_t counter = 0;
    - _; q% ]/ B% K7 k" u# {' F( `
  20.   uint32_t *pBuffer = (uint32_t*)SRAM1_ADDRESS_START;' ~0 j8 G+ N1 w- p5 D$ m- z
  21. $ S1 X9 j: ^, ~, U) g) X
  22.   if (HAL_Init() != HAL_OK), I& g4 G& a# I
  23.   {! H5 f2 Y, z: E9 m2 ^8 y' F; P8 ^
  24.     Error_Handler();, [  n/ p! h  n, b8 \' s9 {
  25.   }
      A5 V, U: I' Q1 _) K! x' K" O

  26. . I5 U+ s: K: F
  27.   /* Initialize LEDs */8 N, L4 q1 T# J) v& C
  28.   BSP_LED_Init(LED1);, T% P1 y& N  ?* ~! A/ W; X. E

  29. , V3 R- F: ]& t" g2 }! j. H
  30.   /* Configure the system clock to 216 MHz */0 `* g5 I" \' E8 z+ j7 H$ {
  31.   SystemClock_Config();
    4 b8 O' I7 C, A
  32.   BSP_LCD_Config();& y- L$ W. _3 u: C3 K

  33. - O2 a# |$ z9 l6 h0 w0 ~# X
  34.   /* Set to 1 if an transfer error is detected */( H- y7 R; j" m; I' [1 |( l4 e
  35.   transferErrorDetected = 0;- f7 F- I5 X) y% |8 Y" y
  36.         % C* ^6 L2 N% [5 h  i) ^1 p" a
  37.   /* Fill 128 bytes with 0x55 pattern */' j6 Z( h8 p1 n) }7 c2 Q
  38.   memset((uint8_t*)SRAM1_ADDRESS_START, 0x55, sizeof(aSRC_Const_Buffer));, \2 q. B6 |1 ^1 o! p: t

  39. " J0 Z2 [# ~1 t! W; }
  40.   /* TODO:Enable MPU and change SRAM region attribute ( {7 }; r' i3 v2 E0 m5 W  y
  41.   * set write-back policy on SRAM */
    # U+ _/ p* C8 S1 n5 k2 [
  42.   MPU_Config();
    8 {2 `+ M+ x9 c  v

  43. 2 p' @2 h3 P$ L. R) W
  44.   /* Enable Data cache */- B* k+ F" @; I
  45.   SCB_EnableDCache();
    - a; y- O) Q. J9 t- p; n2 o, `# S4 u" m; q
  46. 1 B# }! V) N+ e  K2 F- {
  47.   /* Copy data from Flash to SRAM by CPU */, E; {. S& B# p! x8 V/ p
  48.   for (counter = 0; counter < (sizeof(aSRC_Const_Buffer)/4); counter++)
    ; Y" |9 B! \3 O
  49.   {
    8 B* K# U0 Y: V
  50.         *pBuffer++ = aSRC_Const_Buffer[counter];: e5 ?& x7 n5 U
  51.   }/ m8 a& H0 m8 n, a: Y; E) ^
  52.         
    1 r5 a) t  {5 W" K$ s8 Z
  53.   //* Configure and enable the DMA stream for Memory to Memory transfer */! N2 i& C  W% _+ ^1 I* j
  54.   DMA_Config();3 c* z; d. i; H" |+ N

  55. & U0 _* ~, M5 M- b  P1 O! f2 p
  56.   /* Wait for DMA end-of-transfer */3 g! h0 E4 R* S  X7 `% S6 u; I
  57. . S# S& Z. ~4 B4 I; t" \
  58.   while(TransferCompleteFlag == RESET)' c& {# ^$ A/ D* g! a
  59.   {
    0 W+ B" l( M4 @5 Y2 h
  60.   }
    $ `% R$ {# O+ K" v( j# q

  61. % Y7 A. A: w3 m# R9 R, h
  62.   /* Check data integrity*/
    + W  r, H8 U* I7 w, |& f+ L9 n: c
  63.   pBuffer = (uint32_t*)&aDST_Buffer;6 ]9 D# w" D& t
  64.   for(counter = 0; counter <(sizeof(aSRC_Const_Buffer)/4); counter++)
    + o  ^8 ~! C$ M' N  I% T/ y
  65.   {# D2 s, s7 T+ C9 B( i2 j+ e
  66.                
    ' i! A2 D( e* w2 U% r' E
  67.     if(aSRC_Const_Buffer[counter] != *pBuffer)" J. L+ _& P9 c: h$ T
  68.     {4 d# w! \$ a7 D( N* f, C/ @
  69.         compareErrorDetected++;$ y7 t: P  t6 p) z- m( U: c
  70.     }0 f  W; ]( ?- x( |1 G' q2 D
  71.     pBuffer++;( M; D+ |( D8 h& L" ?  M. c) d# P3 V0 b
  72.   }4 w. V' K$ E0 F) N, D  u; P
  73.         . |/ C4 I1 q$ B9 h1 f; o8 J7 q
  74.   if (compareErrorDetected != 0)1 }3 b; x/ P* e% L& M8 s3 F
  75.   {4 p3 c) H) {/ z$ g( W. L
  76.       /* Toggle LED1 */  ^3 P# O2 F% r
  77.       BSP_LED_Off(LED1);
    5 B2 b. @, J: y/ E- _
  78.       compareErrorDetected = 0;        ' K" d$ d+ \/ B2 E) @* c0 m
  79.       BSP_LCD_DisplayStringAtLine(10, (uint8_t *)"       Data comparation failed!      ");
    ' M7 Y0 z/ |+ C- g6 H  e8 I2 r/ i/ r
  80.   }& x! l; M' l% G3 z4 k* j; Y2 r
  81.   else/ l) x4 @4 F7 D
  82.   {
    % E: j1 F6 q! W# O2 W
  83.       /* Turn LED1 on */
    2 h2 E" z0 Z+ Y+ F6 x( v# ]4 W
  84.       BSP_LED_On(LED1);6 F; z" N# U+ `
  85.       BSP_LCD_DisplayStringAtLine(10, (uint8_t *)"       Data comparation success!      ");# u8 }6 p8 X; e( l% ~4 Z& X2 e3 d) X
  86.   }4 u' T8 k8 F  q: Y4 K

  87. 6 J5 n* x( `7 T* W- Q, V
  88.   while (1)
    4 \" @0 a, X. C! Y" \
  89.   {
    - v8 @" R: F5 _$ t. d5 _

  90. 5 c! D& |- q: n+ p6 a2 A% M
  91.   }
      R" L( _+ C% g
  92. }
    ! f6 s% y! n! E

  93. / S5 Z5 x  U) |1 L8 P
  94. static void MPU_Config(void)& E$ O. V6 }! c/ }0 T
  95. {! K+ p- e+ X6 k3 ]5 i5 \; a2 g3 C
  96.   /* Disable MPU */
    5 J) e; o" I% W. n% I8 x5 c
  97.   MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;6 K; I) m  K8 W' y; i/ c2 c* o8 {  p

  98. + N2 l3 A8 }+ U' e, n  b7 F8 G, K
  99.   /* Configure RAM region as Region N°0, 256kB of size and R/W region */
    6 ^$ w7 K. ]: M& U7 u
  100.   MPU->RNR  = SRAM1_REGION_NUMBER;. z$ D: i& I! e' e+ v" J9 R* W
  101.   MPU->RBAR = SRAM1_ADDRESS_START;4 E# J/ c" V# D
  102.          ) O. K* o! y6 L. H$ l
  103.    /* Write-Back policy */
    1 o$ F& h4 C5 r
  104.   MPU->RASR = SRAM1_SIZE | MPU_RASR_C_Msk | MPU_RASR_B_Msk | SRAM1_ACCESS_PERMISSION | 1<<MPU_RASR_TEX_Pos;* L( k1 {7 \; q

  105. ) ?- p6 ~; C  h9 ^+ g. r' \( E
  106.   /* Enable MPU */
    6 L. P  h4 v2 V/ e
  107.   MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
    8 R$ y$ S! I" S9 O
  108. }
    3 Y5 i4 o( v: j4 O" p& w
复制代码
- ?9 q" r( B, W8 g6 l( i! x6 g; E
为了确保 aSRC_Const_Buffer 在 Flash,aDST_Buffer 在 DTCM,我们可以在编译完之后查看 *.map 文件,如下:% i  r% `2 |9 W% e6 d6 M( z8 u1 K

7 |* A* O! V2 S7 J
d4c481b36d81bb11f17b07a56ac1f054.png
7 R8 S+ f, x' @/ r  V2 S) G
, f: F0 O2 t0 R% }
图3.4 检查常量和变量分配情况

  y. r/ s+ N- R0 x) x3 u/ R% E$ `) W4 x
下载到 STM32F769I-DISCO 板子上,显然,由于此时开启了 D-Cache,会出现数据不一致的现象,执行结果如下所示:
# m/ ^3 s: ?7 r% ~9 ]) j4 n2 }. C5 f
bd661d50dcd8f45abeeabdd2ac3c0289.jpg

1 Y" d* M6 X8 h" Z: X
& l: _/ _5 n; ~! M
图3.5 Cache 数据不一致
  r( T2 c) t- |

  R3 Y# \5 D  M2 @' k3.3.3 解决方案2 w4 ]& ?! K, @- `
(1)不启动 D-Cache. n" H; h) Z: A) u' X
2 @7 U' @3 k4 o2 G4 U4 n  Z8 v
注释掉 SCB_EnableDCache();
* S2 k9 |: O' l. h" u/ _7 J3 o0 B8 B# \( U$ O* @
不启动 D-Cache,当然也就没有了 Cache 数据不一致的问题啦~7 N9 P: k5 o# R# k
1 G9 N8 i2 F* M* o1 O( t4 F
(2)将 SRAM1 相应区域设置为 shareable
$ j) C3 F- s5 c
. o6 |( Y6 Y/ j通过 MPU 将 SRAM1 相应区域设置为 shareable,MPU_Config() 函数处理如下:5 _9 ^+ W+ c/ \) R4 h* U+ {
  1. static void MPU_Config(void)
    1 L, C' L6 Q; r6 i  Y
  2. {
    5 v& t6 J! S" i
  3.   /* Disable MPU */
    , p5 K, i1 P  @; l0 G! ~5 a' l
  4.   MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
    - T1 x' n, @. A4 \

  5. 3 L$ J, Z$ _6 N1 i1 \9 ^& K& N0 E
  6.   /* Configure RAM region as Region N°0, 256kB of size and R/W region */* Z5 j- L9 h' u6 y
  7.   MPU->RNR  = SRAM1_REGION_NUMBER;
    ) Y% U9 Y6 F% w8 G; Z) {9 w
  8.   MPU->RBAR = SRAM1_ADDRESS_START;
    9 e! E* f& f; B6 i
  9. # F  ^+ [! U- l! m: m% p$ l
  10.   /* Shareable */7 B2 _$ N7 W3 F% w& U
  11.   MPU->RASR = SRAM1_SIZE | MPU_RASR_S_Msk | SRAM1_ACCESS_PERMISSION;1 ?- y" \1 d" H1 ~

  12. ( X( W+ f7 J  k4 S
  13.   /* Enable MPU */
    * d1 W  y# R/ M5 o
  14.   MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;: c" D; p; y, O. Q# R: s
  15. }
复制代码

0 S$ X( x+ n0 y$ S6 h8 m(3)DMA 访问 SRAM1 前先 Clean cache" n1 H. h  k. ?* M8 C+ Y6 u$ x& u

& X( ]) E0 X6 ^/ H% H: Q* H, ^在启动 DMA 访问之前,程序员需要在合适的地方将 D-Cache 数据回写到主内存中,也就是 Clean 的操作。
" S) G/ ]9 y. o
  k* l. `- z- P& f* R在本示例中,可以在 DMA_Config(); 前调用:/ d* m- K& U* D7 g" _) T
  1. SCB_CleanDCache();
复制代码
或者
7 z/ D, W" u, v& Z5 {: H0 `
  1. SCB_CleanDCache_by_Addr((uint32_t*)SRAM1_ADDRESS_START, sizeof(aSRC_Const_Buffer));
复制代码

" B! {+ A% U0 s. e' l/ c(4)将 SRAM1 相应区域设置为 Write-through 策略
- j4 Z  h' S5 n" @& u; q8 ^, a/ o1 Q5 e) C& }
通过 MPU 将 SRAM1 相应区域设置为透写模式(Write-through),MPU_Config() 函数处理如下:
) z7 h+ C  X! m& ^/ |0 t0 M  `
$ _) S4 g+ S; M. _" p
  1. static void MPU_Config(void)5 O, F' r: Q) L2 y8 Y
  2. {1 F" g* d, W# Z! g* d- D
  3.   /* Disable MPU */
    ) _/ g# u7 w, z* m
  4.   MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
    6 o. g5 [" {) h: @( N' x& g

  5. ) }4 V3 n: F# M  h
  6.   /* Configure RAM region as Region N°0, 256kB of size and R/W region */
    4 W5 x7 c8 b5 J7 {
  7.   MPU->RNR  = SRAM1_REGION_NUMBER;
    1 x4 w# k: F/ \
  8.   MPU->RBAR = SRAM1_ADDRESS_START;
    " G& Z) \8 U, v8 ^9 k' K  ~8 Q
  9. 5 R3 i8 Y0 _! s6 c, P
  10.   /*Write Through policy*/
    5 x) P' E& X; d& w/ K
  11.   MPU->RASR = SRAM1_SIZE | MPU_RASR_C_Msk | SRAM1_ACCESS_PERMISSION;( q' c3 c$ e7 Z
  12. 2 Y4 @/ V( K( K6 x. `6 g5 U
  13.   /* Enable MPU */
    # N  r' k" ^0 ~9 U7 L
  14.   MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;# x' R, F: i1 `. Q1 u. {) ^
  15. }
复制代码

+ S3 @* W7 l& J1 F1 ], S, a(5)将所有 cacheable 的空间全部强制 Write-though
' |% I# R/ ~; @
9 B% y9 \. U/ P9 t# U+ U+ j通过 cache 控制寄存器,将所有 cacheable 的空间全部强制 Write-though 模式。
( M6 [6 }# {- C, I) k7 ]! O
# ~2 H5 K- v6 J/ C4 g! A! Q
e131d05081f8e30ba2296e50f3e9f392.png

. ~5 w" i) p7 D+ J% |' c% s- B
0 H4 ?/ z7 g  C  e, z: V/ H
图3.6 CACR 寄存器(来自 PM0253)
0 E, d* ?" l! Y
  I7 `3 R) @. o5 u& k# K
在初始化的时候进行设置:& f2 v* \# E- f$ I* Q
  1. __FORCE_WRITE_THROUGH();
复制代码

0 B$ I* o) G  ~宏定义为:: P% Y+ }' E. z" S/ q0 H2 F4 q
  1. #define __FORCE_WRITE_THROUGH()    *(__IO uint32_t *)0xE000EF9C = 1UL<<2
复制代码

4 ^6 q/ q8 A: H9 X/ \以上这是都是较为常用的方法,在实际的开发过程中,为了提高性能,一般都会开启 cache,同时将其配置为 WB 策略,这就需要开发者在使用时特别小心!' H! U! f& q& S# d4 H0 a
- z/ O0 T) d* j' |; @6 C( N
值得一提的是:对于第二种情况(图3.2),就不是 clean 操作了,而是 invalidate。需要先调用 SCB_InvalidateDCache() 或 SCB_InvalidateDCache_by_Addr() 去 invalidate 相应的 cache-line, 这样当 CPU 在读取时,会忽略 D-cache 中的内容,去真实的物理地址读取对应的数据。6 ?: s. Z1 l9 H' U- K. d

: X- W8 W2 z* t7 d, [5 F
9dffde7b310ed170c1b45f9dd7f75abe.jpg

! k3 ?/ J" f3 ^7 I+ k
) e; ]4 |/ @) [8 S: d
图3.7 Cache 数据一致
, v' S7 l5 {, I& M, U- @6 O( J

4 I1 ^! j7 s9 y' p9 ~; t, G  h好啦,通过上述几种方法,就可以解决 cache 数据一致性问题。当然,除了我这里提供的,还有其他方案,各种方案各有利弊,要根据实际应用场景去衡量,这就是嵌入式程序员展示才华的时候啦~  ]# S5 Z& s+ ~; d

0 Q7 o) v* J6 E# [3 v: C4 P# K7 g5 V# p
7 d& R* [1 w/ @7 w  c  y8 y
收藏 评论0 发布时间:2021-12-13 23:02

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版