【STM32H7教程】第24章 STM32H7的Cache解讀(非常重要)


完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第24章       STM32H7的Cache解讀(非常重要)

本章教程為大家講解STM32H7初學過程中最重要的一個知識點Cache。Cache在STM32H7的高性能發揮中占着舉足輕重的作用。所以掌握好Cache是提升STM32H7性能的關鍵一步。

24.1 初學者重要提示

24.2 引出問題

24.3 支持的Cache配置

24.4 四種Cache(MPU)配置的讀寫操作流程

24.5 面對繁冗復雜的Cache配置,推薦方式和安全隱患解決辦法

24.6 Cache的相關函數

24.7 總結

 

 

24.1 初學者重要提示

  1.   學習本章節前,務必保證已經學習了第23章的MPU知識。
  2.   本章是半年的實踐經驗總結,非常具有參考價值,而且是入門STM32H7的必學章節。
  3.   Cache的熟練運用需要不斷的經驗積累。對於初學者來說,可能無法一下子理解所有知識點,但是一定要的花時間多讀幾遍,隨着后面章節的不斷運用,認識會不斷的深入。

24.2 引出問題

當前芯片廠商出的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。

如果每次CPU要讀寫SRAM區的數據,都能夠在Cache里面進行,自然是最好的,實現了200MHz到400MHz的飛躍,實際是做不到的,因為數據Cache只有16KB大小,總有用完的時候。

對於使能了Cache的SRAM區,要分讀寫兩種情況考慮。

  •   讀操作:

如果CPU要讀取的SRAM區數據在Cache中已經加載好,這就叫讀命中(Cache hit),如果Cache里面沒有怎么辦,這就是所謂的讀Cache Miss。

  •   寫操作:

如果CPU要寫的SRAM區數據在Cache中已經開辟了對應的區域(專業詞匯叫Cache Line,以32字節為單位),這就叫寫命中(Cache hit),如果Cache里面沒有開辟對應的區域怎么辦,這就是所謂的寫Cache Miss。

 

24.3 支持的Cache配置

這個知識點在上一章節進行了詳細說明,這里再簡述下核心內容

Cache的配置是通過MPU來設置的,通常只用到下幾種方式。

 

其中的TEX是用來設置Cache策略的,C是Cache,B是緩沖用來配合Cache設置的,而S是共享,用來解決多總線或者多核訪問時的同步問題。MPU配置的時候,最主要的也是配置這幾個參數。

Cache支持的策略有如下四種:

 

有了這四種方式,就可以正式進入本章的主題,Cache的讀寫操作是如何工作的,下面分這四種情況做介紹。

24.4 四種Cache(MPU)配置的讀寫操作流程

24.4.1 配置Non-cacheable

這個最好理解,就是正常的讀寫操作,無Cache。

對應四種MPU配置如下:

  •   TEX = 000  C=0  B=0  S=忽略此位,強制為共享
  •   TEX = 000  C=0  B=1  S=忽略此位,強制為共享
  •   TEX = 001  C=0  B=0  S=0
  •   TEX = 001  C=0  B=0  S=1

24.4.2 配置Write through,read allocate,no write allocate

注意,M7內核只要開啟了Cache,read allocate就是開啟的。

  •   使能了此配置的SRAM緩沖區寫操作

    如果CPU要寫的SRAM區數據在Cache中已經開辟了對應的區域,那么會同時寫到Cache里面和SRAM里面;如果沒有,就用到配置no write allocate了,意思就是CPU會直接往SRAM里面寫數據,而不再需要在Cache里面開辟空間了。

    在寫Cache命中的情況下,這個方式的優點是Cache和SRAM的數據同步更新了,沒有多總線訪問造成的數據一致性問題。缺點也明顯,Cache在寫操作上無法有效發揮性能。

  •   使能了此配置的SRAM緩沖區讀操作

    如果CPU要讀取的SRAM區數據在Cache中已經加載好,就可以直接從Cache里面讀取。如果沒有,就用到配置read allocate了,意思就是在Cache里面開辟區域,將SRAM區數據加載進來,后續的操作,CPU可以直接從Cache里面讀取,從而時間加速。

    安全隱患,如果Cache命中的情況下,DMA寫操作也更新了SRAM區的數據,CPU直接從Cache里面讀取的數據就是錯誤的。

  •   對應的兩種MPU配置如下:

TEX = 000 C=1 B=0  S=1

TEX = 000 C=1 B=0  S=0

24.4.3 配置Write back,read allocate,no write allocate

注意,M7內核只要開啟了Cache,read allocate就是開啟的。

  •   使能了此配置的SRAM緩沖區寫操作

    如果CPU要寫的SRAM區數據在Cache中已經開辟了對應的區域,那么會寫到Cache里面,而不會立即更新SRAM;如果沒有,就用到配置no write allocate了,意思就是CPU會直接往SRAM里面寫數據,而不再需要在Cache里面開辟空間了。

    安全隱患,如果Cache命中的情況下,此時僅Cache更新了,而SRAM沒有更新,那么DMA直接從SRAM里面讀出來的就是錯誤的。

  •   使能了此配置的SRAM緩沖區讀操作

   如果CPU要讀取的SRAM區數據在Cache中已經加載好,就可以直接從Cache里面讀取。如果沒有,就用到配置read allocate了,意思就是在Cache里面開辟區域,將SRAM區數據加載進來,后續的操作,CPU可以直接從Cache里面讀取,從而時間加速。

    安全隱患,如果Cache命中的情況下,DMA寫操作也更新了SRAM區的數據,CPU直接從Cache里面讀取的數據就是錯誤的。

  •   對應兩種MPU配置如下:

TEX = 000 C=1 B=1  S=1

TEX = 000 C=1 B=1  S=0

24.4.4 配置Write back,read allocate,write allocate

注意,M7內核只要開啟了Cache,read allocate就是開啟的。

  •   使能了此配置的SRAM緩沖區寫操作

    如果CPU要寫的SRAM區數據在Cache中已經開辟了對應的區域,那么會寫到Cache里面,而不會立即更新SRAM;如果沒有,就用到配置write allocate了,意思就是CPU寫到往SRAM里面的數據,會同步在Cache里面開辟一個空間將SRAM中寫入的數據加載進來,如果此時立即讀此SRAM區,那么就會有很大的速度優勢。

    安全隱患,如果Cache命中的情況下,此時僅Cache更新了,而SRAM沒有更新,那么DMA直接從SRAM里面讀出來的就是錯誤的。

  •   使能了此配置的SRAM緩沖區讀操作

    如果CPU要讀取的SRAM區數據在Cache中已經加載好,就可以直接從Cache里面讀取。如果沒有,就用到配置read allocate了,意思就是在Cache里面開辟區域,將SRAM區數據加載進來,后續的操作,CPU可以直接從Cache里面讀取,從而時間加速。

    安全隱患,如果Cache命中的情況下,DMA寫操作也更新了SRAM區的數據,CPU直接從Cache里面讀取的數據就是錯誤的。

    這個配置被譽為可以最大程度發揮Cache性能,不過具體應用仍需具體分析。

  •   對應兩種MPU配置如下:

TEX = 001 C=1 B=1  S=1

TEX = 001 C=1 B=1  S=0

24.4.5 共享配置是個隱形的大坑

STM32H7編程手冊對其的描述是多核共享。

 

而H7的應用筆記對齊的描述是開啟共享基本等同於關閉Cache。

 

實際測試下面四種開Cache的情況,開關共享對緩沖區的大批量數據的讀操作影響很大,基本差出兩倍,而寫操作基本沒有影響,也許這就是所謂的多總線同步讀造成的。另外共享開關僅對開啟了Cache的情況下有影響,而對於關閉了Cache的情況是沒有影響的,開不開沒關系。

24.4.6 總結這幾種方式的幾個關鍵知識點

  1. Cortex-M7內核的L1 Cache由多行內存區組成,每行有32字節,每行都配有一個地址標簽。數據緩沖DCache是每4行為一組,稱為4-way set associative。而指令緩沖區ICache是2行為一組,這樣節省地址標簽,不用每個行都標記一個地址。
  2. 對於讀操作,只有在第1次訪問指定地址時才會加載到Cache,而寫操作的話,可以直接寫到內存中(write-through模式)或者放到Cache里面,后面再寫入(write-back模式)。
  3. 如果采用的是Write back,Cache line會被標為dirty,等到此行被evicted時,才會執行實際的寫操作,將Cache Line里面的數據寫入到相應的存儲區。
  4. Cache命中是訪問的地址落在了給定的Cache Line里面,所以硬件需要做少量的地址比較工作,以檢查此地址是否被緩存。如果命中了,將用於緩存讀操作或者寫操作。如果沒有命中,則分配和標記新行,填充新的讀寫操作。如果所有行都分配完畢了,Cache控制器將支持eviction操作。根據Cache Line替換算法,一行將被清除Clean,無效化Invalid或者重新配置。數據緩存和指令緩存是采用的偽隨機替換算法。
  5. Cache支持的4種基本操作,使能,禁止,清空和無效化。Clean清空操作是將Cache Line中標記為dirty的數據寫入到內存里面,而無效化Invalid是將Cache Line標記為無效,即刪除操作。

24.5 面對繁冗復雜的Cache配置,推薦方式和安全隱患解決辦法

  •   推薦使用128KB的TCM作為主RAM區,其它的專門用於大緩沖和DMA操作等。
  •   Cache問題主要是CPU和DMA都操作這個緩沖區時容易出現,使用時要注意。
  •   Cache配置的選擇,優先考慮的是WB,然后是WT和關閉Cache,其中WB和WT的使用中可以配合ARM提供的函數解決上面說到的隱患問題(見本章24.6小節)。但不是萬能的,在不起作用的時候,直接暴力選擇函數SCB_CleanInvlaidateDCache解決。關於這個問題,在分別配置以太網MAC的描述符緩沖區,發送緩沖區和接收緩沖區時尤其突出。

24.6 Cache的相關函數

CMSIS軟件包的core_cm7.h文件為Cache的配置提供了11個函數:

  •   SCB_EnableICache
  •   SCB_DisableICache
  •   SCB_InvalidateICache
  •   SCB_EnableDCache
  •   SCB_DisableDCache
  •   SCB_InvalidateDCache
  •   SCB_CleanDCache
  •   SCB_CleanInvalidateDCache
  •   SCB_InvalidateDCache_by_Addr
  •   SCB_CleanDCache_by_Addr
  •   SCB_CleanInvalidateDCache_by_Addr

 

下面將這幾個函數依次做個講解。其中前三個函數是指令Cache,比較容易掌握。重點是后面幾個數據Cache函數。由於函數SCB_CleanInvalidateDCache,SCB_CleanDCache和SCB_InvalidateDCache是對整個Cache的操作,所以比最后的三個函數SCB_InvalidateDCache_by_Addr,SCB_CleanDCache_by_Addr和SCB_CleanInvalidateDCache_by_Addr要耗時,當然,如果用戶操作的存儲器超過了數據Cache的大小,即16KB,那么就跟前三個函數沒有區別了。

24.6.1 函數SCB_EnableICache

函數原型:

__STATIC_INLINE void SCB_EnableICache (void)
{
  #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    __DSB();
    __ISB();
    SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */
    __DSB();
    __ISB();
    SCB->CCR |=  (uint32_t)SCB_CCR_IC_Msk;  /* enable I-Cache */
    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於使能指令Cache,系統上電后優先初始化即可。

注意事項:

  •   __STATIC_INLINE:

表示內聯函數,這種類型函數的作用就是將函數直接嵌入到調用此函數的代碼中,從而降低調用此函數所占用的時間。

  •   __DMB指令:

Data Memory Barrier(數據存儲器隔離),DMB 指令保證所有在它前面的存儲器訪問操作都執行完畢后,才提交在它后面的存儲器訪問操作。

  •   __DSB指令:

Data Synchronization Barrier(數據同步隔離),比DMB嚴格,當所有在它前面的存儲器訪問操作都執行完畢后,才執行在它后面的指令。

  •   __ISB指令:

Instruction Synchronization Barrier(指令同步隔離),它會清洗流水線,以保證所有它前面的指令都執行完畢之后,才執行它后面的指令。

24.6.2 函數SCB_DisableICache

函數原型:

__STATIC_INLINE void SCB_DisableICache (void)
{
  #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    __DSB();
    __ISB();
    SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk;  /* disable I-Cache */
    SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */
    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於禁止指令Cache。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。

24.6.3 函數SCB_InvalidateICache

函數原型:

__STATIC_INLINE void SCB_InvalidateICache (void)
{
  #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
    __DSB();
    __ISB();
    SCB->ICIALLU = 0UL;
    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於將指令Cache無效化,無效化的意思是將Cache Line標記為無效,等同於刪除操作。這樣Cache空間就都騰出來了,可以加載新的指令。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。

24.6.4 函數SCB_EnableDCache

函數原型:

__STATIC_INLINE void SCB_EnableDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
                      ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);
    __DSB();

    SCB->CCR |=  (uint32_t)SCB_CCR_DC_Msk;  /* enable D-Cache */

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於使能數據Cache,系統上電后優先初始化即可。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。

24.6.5 函數SCB_DisableDCache

函數原型:

__STATIC_INLINE void SCB_DisableDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    register uint32_t ccsidr;
    register uint32_t sets;
    register uint32_t ways;

    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();

    SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean & invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
                       ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於禁止數據Cache。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明

24.6.6 函數SCB_InvalidateDCache

函數原型:

__STATIC_INLINE void SCB_CleanDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
   __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
                      ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於將數據Cache無效化,無效化的意思是將Cache Line標記為無效,等同於刪除操作。這樣Cache空間就都騰出來了,可以加載新的數據。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。

24.6.7 函數SCB_CleanDCache

函數原型:

__STATIC_INLINE void SCB_CleanDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

     SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
   __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
                      ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數用於將數據Cache清除,清除的意思是將Cache Line中標記為dirty的數據寫入到相應的存儲區。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。

24.6.8 函數SCB_CleanInvalidateDCache

函數原型:

__STATIC_INLINE void SCB_CleanInvalidateDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;

    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean & invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
                       ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數是前面兩個函數SCB_InvalidateDCache和SCB_CleanDCache的二合一。將Cache Line中標記為dirty的數據寫入到相應的存儲區后,再將Cache Line標記為無效,表示刪除。這樣Cache空間就都騰出來了,可以加載新的數據。

注意事項:

__STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。

24.6.9 函數SCB_InvalidateDCache_by_Addr

函數原型:

__STATIC_INLINE void SCB_InvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     int32_t op_size = dsize;
    uint32_t op_addr = (uint32_t)addr;
     int32_t linesize = 32;           /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

    __DSB();

    while (op_size > 0) {
      SCB->DCIMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=           linesize;
    }

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數與本章24.6.6小節中講解的函數作用一樣,區別是這里可以指定地址和存儲區大小。用於將數據Cache無效化,無效化的意思是將Cache Line標記為無效,等同於刪除操作。這樣Cache空間就都騰出來了,可以加載新的數據。

注意事項:

  •   __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。
  •   第1個參數addr : 操作的地址一定要是32字節對齊的,即這個地址對32求余數等於0。
  •   第2個參數dsize :一定要是32字節的整數倍。

24.6.10   函數SCB_CleanDCache_by_Addr

函數原型:

__STATIC_INLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     int32_t op_size = dsize;
    uint32_t op_addr = (uint32_t) addr;
     int32_t linesize = 32;            /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

    __DSB();

    while (op_size > 0) {
      SCB->DCCMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=           linesize;
    }

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數與本章24.6.7小節中講解的函數作用一樣,區別是這里可以指定地址和存儲區大小。用於將數據Cache清除,清除的意思是將Cache Line中標記為dirty的數據寫入到相應的存儲區。

注意事項:

  •   __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。
  •   第1個參數addr : 操作的地址一定要是32字節對齊的,即這個地址對32求余數等於0。
  •   第2個參數dsize :一定要是32字節的整數倍。

24.6.11   函數SCB_CleanInvalidateDCache_by_Addr

函數原型:

__STATIC_INLINE void SCB_CleanInvalidateDCache_by_Addr (uint32_t *addr, int32_t dsize)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     int32_t op_size = dsize;
    uint32_t op_addr = (uint32_t) addr;
     int32_t linesize = 32;          /* in Cortex-M7 size of cache line is fixed to 8 words (32 bytes) */

    __DSB();

    while (op_size > 0) {
      SCB->DCCIMVAC = op_addr;
      op_addr += (uint32_t)linesize;
      op_size -=           linesize;
    }

    __DSB();
    __ISB();
  #endif
}

函數描述:

此函數與本章24.6.8小節中講解的函數作用一樣,區別是這里可以指定地址和存儲區大小。將Cache Line中標記為dirty的數據寫入到相應的存儲區后,再將Cache Line標記為無效,表示刪除。這樣Cache空間就都騰出來了,可以加載新的數據。

注意事項:

  •   __STATIC_INLINE,__DMB,__DSB和__ISB的作用看本章24.6.1小節的說明。
  •   第1個參數addr : 操作的地址一定要是32字節對齊的,即這個地址對32求余數等於0。
  •   第2個參數dsize :一定要是32字節的整數倍。

24.7 總結

本章節就為大家講解這么多,務必要反復多讀幾遍,能理解多少算多少,隨着后續章節的學習再回過頭來再學習。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM