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

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

[复制链接]
STMCU小助手 发布时间:2021-12-13 23:02
3. Cache 一致性问题
2 y+ j) @( d; ]$ @$ W3.1 什么是 cache 一致性问题
$ `9 o/ D) u( j' ?$ T; o+ W所谓的 Cache 一致性问题, 主要指的是由于 D-cache 存在时,表现在有多个 Host(典型的如 MCU 的 Core, DMA 等)访问同一块内存时, 由于数据会缓存在 D-cache 中而没有更新实际的物理内存。
1 x: C! X  W( p7 ^  B; U$ s
7 F1 q- G7 r0 n, Y在实际应用中,有以下两种情况:
' y/ d( q; D3 G+ I# G9 V4 B
- u' l7 n8 H1 T2 |: r$ G, a% _第一种情况是当有写物理内存的指令时,Core 会先去更新相应的 cache-line(Write-back 策略),在没有 clean 的情况下,会导致其对应的实际物理内存中的数据并没有被更新,如果这个时候有其它的 Host(如 DMA)访问这段内存时,就会出现问题(由于实际物理内存并未被更新,和 D-cache 中的不一致),这就是所谓的 cache 一致性的问题。
' v# o& a8 g" T$ @) S6 F) i1 y* D  v  E+ l! w( d
516a4fcb212a09183f4c3f3efa77d170.png
& I! U$ N' d, V7 ^" C

4 b9 G8 v9 a  D% t  Q7 K4 O
图3.1 Cache 一致性问题 第1种情况

# F: P! i; _" r1 R  [6 N6 P# S: S- F# ]
第二种情况是 DMA 更新了某段物理内存(DMA 和 cache 直接没有直接通道),而这个时候 Core 再读取这段内存的时候,由于相对应地址的 cache-line 没有被 invalidate,导致 Core 读到的是 cache-line 中的数据,而非被 DMA 更新过的实际物理内存的数据。
3 d* \8 W* C& c& w& m' t# l. G& o8 F" O1 Q, D2 i' u7 F; k
ba3341c9a0e0ddc198b5fe0466a465dc.png
" d0 }: D6 b" k% K" H. S

% @* V8 B3 A3 z$ H0 D: q3 \6 Z$ q
图3.2 Cache 一致性问题 第2种情况
5 `) e% t, y* s/ e, u; ~; r, M
& S; z( U# |- }6 v3 f4 D; y( X+ X" S
3.2 如何处理 cache 一致性问题

- g" p- ~1 }6 |' x我们知道,Cache 机制是为了提高存储系统的平均读写性能而设计的,但是这种机制带来了数据一致性问题,然而,却没有对一致性的硬件支持。
% A6 L/ F/ Z3 i  C  W* `4 _# S
. c8 _2 e$ P2 b6 z4 v) e- T因此为了解决一致性问题,一个办法就是禁用 Cache(cache 都禁用了,肯定不会有 cache 一致性的问题啦~)。但是如果你选择使用 STM32F7 这样高性能的微控制器,又不使用其带来的高性能特性,那你为什么要用 F7 呢,用 F3、F4 不就得了么?所以为了提高性能,还是使能 cache,并积极解决 cache 一致性问题吧。
' G' V0 @; v* K# f' J% V( ~, u0 E2 P2 R6 g  Q1 M6 a$ i) y! q" k
好吧,解决 STM32F7 的 cache 一致性问题,有两种可选方案:
8 F2 [. O1 K& A0 D( L5 l8 h( o- s+ ~5 B
所有的共享存储器都定义为共享属性. e' i8 c1 p' n2 \4 q* K0 O
, H) p% F5 t5 A2 y# u0 `
这些区域将默认不被缓存到 D-Cache。
8 H8 ^9 u* p; D0 U4 n, Q所有的操作都直接针对二级存储器(内部Flash,外部存储器),性能降低。
! t# E" ]* `% S因为缓存对这些区域是透明的,写软件更容易。/ F/ J; q) K/ c6 W- R4 X  r
6 \* l5 ^$ z  t0 w2 ^
通过软件进行cache的维护7 G; _8 j, g( v9 t+ l3 |
(1)Cortex-M7 的写操作要是全局可见的
" o/ [" Q( H! R! N* S6 d) e% M1 |; {. W5 A
使用透写属性(通过 MPU 设置)。
7 y- H! r4 T+ l; [8 k使用 SIWT@CACR(Shared = Write Through)。
' F$ u. e; d3 f- u通过指令清 D-cache,然后所有更新位置禁止 D-Cache操作。: O4 I8 b3 l" w/ l( p
(2)其他主设备的写操作要对 Cortex-M7 可见
9 c) Z0 D9 P" f7 q! m% p
7 J* j2 e. A- u" |6 d; J" K2 o比如作废 Cortex-M7 Dache 中数据。, J+ @- t( {9 C! s; r, M
3.3 示例
2 F* q+ ~3 z3 K3.3.1 程序描述/ Q) c  [9 l3 D/ n' i
(1)首先将地址 0x20020000(SRAM1)处开始的 128 字节初始化为 0x55。7 j' u7 j: a3 E+ Q/ M5 b2 Z
(2)将 Flash 中的 128 字节的常量数组 aSRC_Const_Buffer 拷贝到 SRAM1 地址 0x20020000(pBuffer)。
0 y) ^4 }9 L2 e, E6 I4 Y5 X(3)配置并使能 DMA,通过 DMA 将数据从 SRAM1 的地址 0x20020000 处拷贝到 DTCM RAM 中的数组 aDST_Buffer 中。% m  @, O, o- Q
(4)将 Flash 中的数组 aSRC_Const_Buffer 与 DMA 读出的数组 aDST_Buffer 进行比较。: I8 ?5 F' o: M  g9 \( ~2 h

) q' C$ `! Z. A4 Z3 @显然,这个例子中的 cache 一致性问题, 展示的是上面(图3.1)的第一种情况。也就是在 Write-back 策略下,CPU 先去更新相应的 cache-line,然后 DMA 去访问对应的内存,从而导致数据不一致的现象。
! g) P' h/ H- b* u0 L5 N, w+ @5 F" T! i9 x$ @
程数据的传输流程和路径如下图所示:8 W+ C9 R  [  b4 z4 D

# R; z& k% o) K/ v2 C+ v; }" U
d0db73574a58707717ae26695e9dc302.png

+ ~6 v- U6 Q% k; o0 x3 a
+ a& J  m. b/ R( a
图3.3 Cache 示例数据传输框图
% S/ @6 Q$ G6 ], L/ c7 x

# S6 ~2 `# m) E' w6 A% K+ l3.3.2 复现 cache 一致性问题& C; ~( ^4 ~, K$ O6 r, p
我们先来按照示例要求编写代码,复现 cache 一致性问题。有些人可能会疑惑,变量数据怎么放到 Flash、SRAM1、DTCM?实际上,可以通过一些相关的配置文件进行设置,比如 icf 文件、scatter 文件等,当然,这跟所使用开发环境和编译工具链有关。& w! T2 \3 M. H+ X+ p

. v* H/ Y2 M( B  z) K4 x本文所使用的环境是 IAR,其链接文件 *.icf 如下:
; ]( a) ~3 a; `1 U9 q
0 J& J; m2 ?% [! J3 s
5377967a69d8334b1bbd7b99f41c9e23.png

$ I5 H% l! X" ~. j) [. D" a. m7 \7 s& L! z& f9 L9 i4 Y
然后将 aSRC_Const_Buffer 数组定义为常量,即可分配到 RO 区域,aDST_Buffer 定义为普通的全局变量或静态变量即可,因为内存区域从 0x20000000 开始,也就是 DTCM RAM。
+ g' H, |& f8 {$ z# ^& P+ Y; v, }& p" F6 _- h
好了,代码主体部分如下:
+ I. k9 h) D+ l% Q0 a
* B+ s8 q2 @. u' |
  1. #define SRAM1_ADDRESS_START   (0x20020000UL)" P% R+ D, {/ {& C" M" I& Z

  2. + m5 _, c3 A/ Q5 H/ ?. i
  3. static const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] =( D3 e( k$ ], H- J9 t, O
  4. {
    . W( a# `7 e8 G+ q3 G
  5.   0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,/ [6 d8 T1 r' B* j5 v# f3 o1 X! ?
  6.   0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,
      A. G7 e5 I7 h% z- x
  7.   0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30,; [% _6 q$ {, H' q7 o7 H. q
  8.   0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40,2 W" X  f% |, Z1 u) N& ~
  9.   0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50,
    ' x7 C' k6 w5 ]# \( d
  10.   0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60,
    2 V7 P; \3 t. _5 C+ m" ]. G. A
  11.   0x61626364, 0x65666768, 0x696A6B6C, 0x6D6E6F70,
    8 g2 e% U+ _. K- c$ ~, O
  12.   0x71727374, 0x75767778, 0x797A7B7C, 0x7D7E7F80
    " w! ?* Q) b+ F# F: N
  13. };
    7 E& [" k) J! H+ ]9 K+ j
  14. & U  X  k- G9 i4 T, n1 u$ }( t
  15. static uint32_t aDST_Buffer[BUFFER_SIZE];. j* Q; h' P; g; }: v- y3 h

  16. " r6 x  l: y& Z5 V0 {% U4 {9 g8 I
  17. int main(void)" z  X9 ~2 w4 h5 P% y
  18. {
    * q! N! w) E) z# O0 p. s! @1 l# e
  19.   uint32_t counter = 0;1 a4 z5 B/ K' P
  20.   uint32_t *pBuffer = (uint32_t*)SRAM1_ADDRESS_START;
    - Q' y3 P2 L( F5 {0 K. [  M1 N
  21. 3 t) ]; K6 P: A1 `, S+ v' J% _+ S0 L
  22.   if (HAL_Init() != HAL_OK)
    # N. i2 k- L: N$ F( h
  23.   {
    2 y, y9 y- m+ d
  24.     Error_Handler();9 v  S! ^2 X' O( f5 Q( W" V; @, ?: c! j
  25.   }# y. F2 l( B# a6 S

  26. ! e2 k' Y# @+ f9 D* n, S' U6 M
  27.   /* Initialize LEDs */
    2 n9 t) f/ u8 E4 L  C7 z7 i
  28.   BSP_LED_Init(LED1);+ F; ^& r3 `6 d7 g, C- u( E

  29. 2 \! a! t% X, [: n3 u  e8 N; F
  30.   /* Configure the system clock to 216 MHz */6 K) y- }( b: J/ i5 ?. e
  31.   SystemClock_Config();
    % ?9 F! d2 {) R8 X* ]
  32.   BSP_LCD_Config();
    $ K1 [4 q0 ]7 n
  33. 1 C5 R+ j) f8 F5 c6 V/ x5 Y& ^, m
  34.   /* Set to 1 if an transfer error is detected */
    - ~0 ?+ B( ]" f7 |" Q- q. i9 y4 X
  35.   transferErrorDetected = 0;
    + F0 \8 P* P1 `4 `# N9 L1 ?
  36.         ' w. R* S' }* m! j3 S1 r# g5 N
  37.   /* Fill 128 bytes with 0x55 pattern */
    $ e7 e$ `% D& b0 s( ~1 R
  38.   memset((uint8_t*)SRAM1_ADDRESS_START, 0x55, sizeof(aSRC_Const_Buffer));* p5 D. T0 ~3 ^

  39. & k% ]6 B$ d3 d2 ]
  40.   /* TODO:Enable MPU and change SRAM region attribute 8 S( R. w4 t1 K8 s
  41.   * set write-back policy on SRAM */
    . B. A$ C% R& g1 [: x: L, c4 `1 x
  42.   MPU_Config();, O$ |6 Q  b" K: F: U6 E8 j  C
  43. ; u/ \- N- @( {9 o% G1 ^! K. k
  44.   /* Enable Data cache */
      O7 N6 A- @. |& ^) B$ H
  45.   SCB_EnableDCache();2 d. L5 f4 v; y$ Q5 o2 G

  46.   `5 a0 m. e/ L  h! U+ |: [5 e
  47.   /* Copy data from Flash to SRAM by CPU */
    + ~* b' ]; P- Y' I, D
  48.   for (counter = 0; counter < (sizeof(aSRC_Const_Buffer)/4); counter++)
    : T6 V8 z, t+ k- E6 Y+ s
  49.   {
    0 \+ X; i  w3 o3 A. X( S) F
  50.         *pBuffer++ = aSRC_Const_Buffer[counter];
    ( k' t, ]& S, g/ i( G# [
  51.   }
    6 i; H% \+ V& x1 k' c+ Y
  52.         1 u% L$ B! }2 J7 Q1 E7 ]7 l4 A% D
  53.   //* Configure and enable the DMA stream for Memory to Memory transfer */
    $ A) M' W% e. S* l% j4 }* ?; w
  54.   DMA_Config();
    , a1 v8 G9 ?5 \: |0 j
  55. 5 h  _' g: L9 G+ |0 K% s
  56.   /* Wait for DMA end-of-transfer */
    % h  I6 a7 H- ]+ ^$ m: \& u, T) D  s
  57. " E4 }4 k  t. p# x- P
  58.   while(TransferCompleteFlag == RESET)
    ! M6 t. P. ^: P/ l
  59.   {1 z0 S0 v$ [' c! s3 y+ g3 H( g
  60.   }( A, o2 n/ P1 y: c7 r6 s; T

  61. . n& r' @8 k$ Y" W' t/ \
  62.   /* Check data integrity*/
    1 r! m) `; r. D) j  H+ p  \, |0 t( J
  63.   pBuffer = (uint32_t*)&aDST_Buffer;
    % h6 N& W4 [; X: A
  64.   for(counter = 0; counter <(sizeof(aSRC_Const_Buffer)/4); counter++)
    ' A1 E; L6 O' S& O6 S+ Z
  65.   {1 y" D7 ?- J$ X( h
  66.                 ) H* Z/ M+ q6 |! D
  67.     if(aSRC_Const_Buffer[counter] != *pBuffer)$ S  ]. V3 B7 e/ j! |) f. V
  68.     {! p+ C( W; m6 V
  69.         compareErrorDetected++;
      J, G; j2 y4 N
  70.     }
    1 @; u2 V" [0 M+ i( B
  71.     pBuffer++;- s4 ?7 D" Y+ E4 W2 A5 I' |. g
  72.   }9 w% @  B$ v- u
  73.         
    5 X' [. b$ n. {9 D3 X- V& ~
  74.   if (compareErrorDetected != 0)
    & p7 D& D2 E/ Y
  75.   {+ J  Q7 c  ~  c1 h) |
  76.       /* Toggle LED1 */
    3 C' d7 b$ O+ }/ l% ^
  77.       BSP_LED_Off(LED1);* K" f+ M+ a$ h$ d* A
  78.       compareErrorDetected = 0;        
    % P4 F. f* v6 l2 w0 a/ H. N. n
  79.       BSP_LCD_DisplayStringAtLine(10, (uint8_t *)"       Data comparation failed!      ");: t2 S: g6 b9 E" X5 h& W1 y
  80.   }
    4 u. F% v* n1 ]) L% K, m3 N% \
  81.   else
    % n8 Z2 G" ^# T0 C
  82.   {4 i; W* P1 w$ O
  83.       /* Turn LED1 on */5 ?) A) r+ |' A( G) H2 k+ y
  84.       BSP_LED_On(LED1);. Y" t: A2 H' H6 t3 ]$ f
  85.       BSP_LCD_DisplayStringAtLine(10, (uint8_t *)"       Data comparation success!      ");2 a: g$ ~# A8 ~( {- v
  86.   }: l' ?! D/ r& E9 N8 b/ \

  87. + {; F7 Q! F, j! e/ [+ C; J: x6 }* T
  88.   while (1)
    $ t9 I$ |4 A9 k: r7 `$ u  |. ^
  89.   {
    7 Y! s- R7 N% `7 ]  M- @" P

  90. , p+ X* e& h9 I# T6 P
  91.   }& V! Y. ?/ P; e/ D/ M4 a
  92. }
      w5 R$ E! D* ~" g
  93.   V8 l; N, c1 j7 H  G; o9 U# h: v, L
  94. static void MPU_Config(void)# E" S; f3 `0 `4 h! |! F& B
  95. {
    " e. H2 e" p" y7 h  a/ r
  96.   /* Disable MPU */
    4 g, ~! o; o) d0 E: q
  97.   MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;! G1 P( |8 w" H0 r4 X& @! @3 {
  98. - V1 {) s3 Y/ r6 X5 ?$ a2 }  a2 W& N
  99.   /* Configure RAM region as Region N°0, 256kB of size and R/W region */
    + R" M+ y7 p4 w! B
  100.   MPU->RNR  = SRAM1_REGION_NUMBER;
    . @9 M& l% e- ~
  101.   MPU->RBAR = SRAM1_ADDRESS_START;
    / y# B% H! Y' R' a/ h+ t3 q  Q& e
  102.          
    0 d& x7 x8 p+ ?) e7 j- l
  103.    /* Write-Back policy */! ^# W8 K: S9 e5 ^+ n
  104.   MPU->RASR = SRAM1_SIZE | MPU_RASR_C_Msk | MPU_RASR_B_Msk | SRAM1_ACCESS_PERMISSION | 1<<MPU_RASR_TEX_Pos;
    8 T% j1 z# m$ ?3 v

  105. # _- o* e8 L: g9 S5 q2 {& F
  106.   /* Enable MPU */& Z7 o3 G0 p, G3 E
  107.   MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;9 ]/ s5 y  U' T1 }( l
  108. }
    6 @8 {/ y6 Y8 M: E
复制代码
; J) s4 P& O8 P" g2 f/ F
为了确保 aSRC_Const_Buffer 在 Flash,aDST_Buffer 在 DTCM,我们可以在编译完之后查看 *.map 文件,如下:
) V7 E- e2 S* P8 H: I5 N  ?5 y1 j7 b: p: e8 m# \9 ~
d4c481b36d81bb11f17b07a56ac1f054.png
) F, x; g* z# J

) B" }# G1 h. u* R: _" [+ l
图3.4 检查常量和变量分配情况
& X& A( b9 h6 V* z8 E# ]

4 E5 M# {0 ~0 N下载到 STM32F769I-DISCO 板子上,显然,由于此时开启了 D-Cache,会出现数据不一致的现象,执行结果如下所示:: r2 s# a3 @$ J8 [

3 V  \% V# ^8 f' ]$ a2 e9 q
bd661d50dcd8f45abeeabdd2ac3c0289.jpg

6 q% Z# T/ s$ d5 O& K2 D8 p" G/ q% w3 _" \
图3.5 Cache 数据不一致
% I6 {# C( [- d7 n3 Z' _
9 _9 A' M) ^  T' d& l$ ^. O9 W0 o+ ?! ]
3.3.3 解决方案
" n& p# i/ t6 O- B  A% T  Z2 D' Q  w(1)不启动 D-Cache
9 k" _( k' c( n' f( w* I; J1 o; {/ @- ?- O
注释掉 SCB_EnableDCache();
' V% o1 O: j' S1 G8 W+ p8 x& Q3 X9 }( G' B5 @# p% n
不启动 D-Cache,当然也就没有了 Cache 数据不一致的问题啦~4 Y0 b9 {) C5 C1 Y5 O% _: ]. O+ w

& x) R- i5 G: g' G6 i(2)将 SRAM1 相应区域设置为 shareable
. o3 M4 e& m- u& K) p4 T0 K, n& x: E0 P/ _
通过 MPU 将 SRAM1 相应区域设置为 shareable,MPU_Config() 函数处理如下:
! K* W+ s0 |2 `4 M7 A
  1. static void MPU_Config(void)
    / D* g% e# _. s% j  c0 I
  2. {; h% Q' Y3 c' T( w: n! x
  3.   /* Disable MPU */; T' h1 X* R2 ?9 F( S; m% Z
  4.   MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
    ! A  B4 r) F8 b/ X* x5 K# q

  5. 2 b& I; ]" y9 i. ]2 B5 I* }
  6.   /* Configure RAM region as Region N°0, 256kB of size and R/W region */
      g7 w% y: B5 U
  7.   MPU->RNR  = SRAM1_REGION_NUMBER;
    3 y! ^: V# `6 O1 K+ q1 Y
  8.   MPU->RBAR = SRAM1_ADDRESS_START;' P2 t/ P1 u; |6 ~" r
  9. : O1 |! U$ c: x9 U
  10.   /* Shareable */* \. u& j6 d# I0 `& ~( C3 V
  11.   MPU->RASR = SRAM1_SIZE | MPU_RASR_S_Msk | SRAM1_ACCESS_PERMISSION;
    ; l. i7 h  G$ v8 ], \4 s% c

  12. $ A7 b" V9 `' N# |  Y  B
  13.   /* Enable MPU */6 z+ j) ~. m5 L* B6 w
  14.   MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
    ! ?; W4 s. a1 E; s
  15. }
复制代码

" g; v  q4 V+ _0 I(3)DMA 访问 SRAM1 前先 Clean cache# f5 N& Q' I  G' |( F
% }' b6 F0 F! C! ]% ^" N! q
在启动 DMA 访问之前,程序员需要在合适的地方将 D-Cache 数据回写到主内存中,也就是 Clean 的操作。
) [) ?/ K. T; J; w# ?6 I' v( E7 t8 A! H2 B$ c
在本示例中,可以在 DMA_Config(); 前调用:9 N. M7 n  U5 `0 I% m9 w, ?
  1. SCB_CleanDCache();
复制代码
或者. {3 c8 U1 P2 A( }
  1. SCB_CleanDCache_by_Addr((uint32_t*)SRAM1_ADDRESS_START, sizeof(aSRC_Const_Buffer));
复制代码
0 C1 l1 b. y: b  ^4 ^8 ^$ [
(4)将 SRAM1 相应区域设置为 Write-through 策略3 [; M6 J# W* Q: s2 {* V7 ]
4 L, i7 B! b  g! X# e4 s' o
通过 MPU 将 SRAM1 相应区域设置为透写模式(Write-through),MPU_Config() 函数处理如下:
  ?2 v: r% G( T0 M* }9 ^, p
/ [% s- O* k7 |8 F1 v, v1 z& u
  1. static void MPU_Config(void); a/ g# ^; |( L6 [" _2 u5 c; u% a
  2. {0 @) y7 T% P: W8 v# w; @% O
  3.   /* Disable MPU */8 I* a- R$ F# n) x5 j2 H- \0 T
  4.   MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
    5 t) }6 m0 d# l5 F6 _& x
  5. $ Y: A8 t: q- R2 P6 F1 d% l' ]
  6.   /* Configure RAM region as Region N°0, 256kB of size and R/W region */7 ]  i& u( l  u$ u! W, R
  7.   MPU->RNR  = SRAM1_REGION_NUMBER;5 a% \9 j1 z# K6 m# w- _
  8.   MPU->RBAR = SRAM1_ADDRESS_START;
    ; I# A* o% b$ }" U1 w4 q+ B
  9. , z' Q5 D9 i) F" w2 f
  10.   /*Write Through policy*/& g5 X9 Q8 E# V; a1 l
  11.   MPU->RASR = SRAM1_SIZE | MPU_RASR_C_Msk | SRAM1_ACCESS_PERMISSION;
    * q9 ]) d/ G/ w5 z) X9 F

  12. . V! B: L( ^' h2 \7 ?* K! ]2 t
  13.   /* Enable MPU */- C  @( r5 `1 l9 {7 g
  14.   MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;8 d  u* h2 u) f+ y% \
  15. }
复制代码
7 q7 o) d: B- ~8 @) A6 A/ w
(5)将所有 cacheable 的空间全部强制 Write-though
9 |9 _; G4 E) A/ v, y( f# h$ x, d2 r( F( z( O/ b
通过 cache 控制寄存器,将所有 cacheable 的空间全部强制 Write-though 模式。- o8 K8 w$ }8 ]) x
* T/ `" ~4 W3 h! p! M5 b+ D
e131d05081f8e30ba2296e50f3e9f392.png
2 l/ ?; @1 C* j0 c$ h6 o

; R% B1 G, ^. |; t0 G
图3.6 CACR 寄存器(来自 PM0253)
- a" a  G" C, _0 N0 V

5 f: s7 }8 C4 l: E  }在初始化的时候进行设置:
3 E' c) d' u( ?6 C
  1. __FORCE_WRITE_THROUGH();
复制代码
% p: n9 k, K! b$ j
宏定义为:1 v# h8 z: S5 x5 c5 H
  1. #define __FORCE_WRITE_THROUGH()    *(__IO uint32_t *)0xE000EF9C = 1UL<<2
复制代码

% h0 O5 E3 i2 C& }6 q以上这是都是较为常用的方法,在实际的开发过程中,为了提高性能,一般都会开启 cache,同时将其配置为 WB 策略,这就需要开发者在使用时特别小心!
- ~4 A: E0 g1 O- P9 {( ?& Q
4 v; \+ j- e6 h; a1 U. m值得一提的是:对于第二种情况(图3.2),就不是 clean 操作了,而是 invalidate。需要先调用 SCB_InvalidateDCache() 或 SCB_InvalidateDCache_by_Addr() 去 invalidate 相应的 cache-line, 这样当 CPU 在读取时,会忽略 D-cache 中的内容,去真实的物理地址读取对应的数据。
  ^% \5 {  v) ?$ y; |( r7 a5 h" v1 T& {* x8 `+ N8 ^! H( p
9dffde7b310ed170c1b45f9dd7f75abe.jpg

* p' a5 d3 w: c( ^1 y" F  v7 F: O+ n6 P6 b. O/ T
图3.7 Cache 数据一致
; G) B9 f5 P7 M. {5 v* ~. M9 D  m
, z9 w/ V1 w2 g$ L6 I/ V! t9 A
好啦,通过上述几种方法,就可以解决 cache 数据一致性问题。当然,除了我这里提供的,还有其他方案,各种方案各有利弊,要根据实际应用场景去衡量,这就是嵌入式程序员展示才华的时候啦~
" ~( J0 J5 ~- D: z* ?( g
. ~; z1 {) Q! ^6 {% }6 A' Q! c9 v5 f0 `/ |9 {

8 X% U* {$ _4 p/ l8 J
收藏 评论0 发布时间:2021-12-13 23:02

举报

0个回答

所属标签

相似技术帖

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