前言#
最近希望將 ADC 性能跑到盡可能的極限,所以研究了一下相關的外設功能。
其中 cache 和 MPU 屬性適配的部分我以前一直沒搞太懂,這次總算弄得比較清楚了。在具有 cache 功能的 arm 晶片中,一定要配合 MPU 外設功能配置才可以使用 cache 功能。
- cache:緩衝區主要是為了處理器內核可以更連續地操作內存,畢竟一些內存操作涉及到跨總線,cache 可以在讀取時對命中的內存附近進行預取,以及寫入時一定程度的延遲湊連續,最主要的是可以減少內部總線的衝突以加速數據的處理。
- MPU(Memory Protection Unit):內存保護單元是 arm 晶片的內存保護機制,主要用於配置某段內存區的 cache 屬性。
當然可以有其他用途但是恕我直言沒有其他用途,例如在不同的任務線程加載中,對內存區的配置可以精細化不同,實現類似 MMU 的功能但是正常人不會做這麼複雜的應用的。 - DMA(Direct Memory Access):直接寄存器訪問,可以以沒有處理器算力參與的形式,將外設寄存器中的數值拷貝到內存中,在拷貝一定數量 (例如 1024 個) 後產生中斷通知,供我們對這段數據進行處理。
MPU 與 MMU 的主要區別
MPU | MMU | |
---|---|---|
緩衝命中周期 | 固定 1 指令周期 | 1~20 周期不等 |
管理精細度 | 有限的區域 (十數個) 管理 | 可以 RAM 逐頁精細化 |
多任務支持 | 劃分物理區域進行有限隔離 | 虛擬地址進程完全隔離 |
說白了 | 做即時性應用的 | 搞 linux 的 |
其他很多晶片當然都有類似的 cache 和 MPU 功能,但是這裡主要討論的 arm 晶片,他們的功能都是類似的,只是管理粒度、劃區數量、或者不可管理固定屬性,其中的屬性和對應功能都是類似的。
總線的理解#
MCU 晶片的外設分布在不同總線上,而同總線的外設和內存間讀寫相對會快。我們僅就 ADC 、DMA、以及內存的配合,理解總線。
在我的這個應用中,因為 DMA 只能操作同總線上的外設和內存,所以使用到了 ADC1/2/3、DMA1/2、BDMA1。
結合以下的總線示意圖理解。ADC1 結合 DMA1 采樣同時占用部分 D2 域內存、ADC3 結合 BDMA 采樣同時占用部分 D3 域內存,並最終將數據初期處理後將采樣值放在 D1 域內存供 CPU 後續計算。這樣分配盡可能減少跨域的性能損耗。
cache 屬性的配置#
MPU 配置控制 cache 屬性,有最重要的 3 個配置項如下,我有一些自己的簡單總結
- IsCacheable 決定是否開啟 cache。
- IsBufferable 決定是否將寫入指令也使用 cache 緩衝後統一寫入內存。如果不开啟 IsCache 那麼沒有意義
- IsShareable 決定是否採用嚴格的時序控制,這在外設的外設,例如 FMC 訪問外部內存時非常重要,因為資源跨晶片了,需要開啟嚴格時序。
以及對應的 chat GPT 解釋,比我說的清楚詳細。
- IsCacheable 控制是否使用 D-Cache,以及在 M7 上配合 TEX/C/B 決定緩存策略。
- IsBufferable 允許寫緩衝(write buffering/combining),可能延後對外可見時間,以換取更高吞吐。
- IsShareable 標記該區 “可被多個主機共享”,在 M7 上還會改變緩存策略:Cacheable+Shareable 會強制為 Write-Through/No-Write-Allocate。
詳細說明
- IsCacheable
- 關心點:是否走 D-Cache;配合 TEX/C/B 決定是 Write-Back/Write-Allocate 還是 Write-Through/No-Allocate。
- 影響:CPU 訪問延遲與帶寬、總線流量;不直接改變外設采樣速率,但影響 CPU 處理速度。
- IsBufferable
- 含義:允許將寫入先進入寫緩衝並可能合併,再異步刷到內存 / 總線,減少總線事務、提高吞吐。
- 影響:
- 性能:連續寫(memcpy、流式寫)更快。
- 可見性 / 順序:寫入對其他主機(DMA / 外設)的 “可見時刻” 可能延後;必要時用屏障指令保證順序。
- 典型用法:Normal 內存常設為 BUFFERABLE;Device/MMIO 通常不設以避免重排 / 合併。
- IsShareable
- 含義:該區域可能被多個主機共享(CPU、DMA 等)。在 Cortex-M7 上對 Cacheable 的 Normal 區有特別影響:
- Cacheable + Shareable = 寫直達(Write-Through)、不寫分配(No-Write-Allocate),減少其他主機看到舊數據的窗口,但 CPU 側性能較 WB/WA 略降。
- Cacheable + Non-shareable = 通常為 Write-Back/Write-Allocate(配合 TEX=1,C=1,B=1),CPU 性能最佳。
- 影響:
- 順序與可見性語義更保守,有利於與其他主機協作。
- 不等於 “硬件緩存一致性”,但改變了緩存寫策略與內存屏障語義範圍。
常見組合速覽(Normal 內存)
- B=1, C=1, Shareable=0, TEX=1 → Write-Back, Write-Allocate(CPU 最快,適合大多數計算緩衝)
- B=1, C=1, Shareable=1, TEX=1 → Write-Through, No-Write-Allocate(更保守的共享語義)
- B=0/1, C=0 → Non-cacheable(可選擇是否允許寫緩衝;B=0 更嚴格時序)
見此前的總線示意,由於 cache 實際屬於 CPU 的一部分,所以 DMA 獲得的內存數據 (D2/D3 域內存區) 是必然跨域的。在跨域的應用中,必須解決內存一致性問題,這需要一個內存區大小的 while 循環來強制命中解決一致性問題,反而引起不必要的消耗。
所以在 MPU 配置中,D2、D3 域對應的地址範圍不開啟 Cache,對應上述的第三個組合。D1 域的常用內存區則可以開啟 IsCache、開啟 IsBuffer、關閉 IsShare 以獲得最大的性能,對應上述的第一個組合。
而上述的第二個組合,我暫時沒有遇到過使用場景,也想像不出來。
以下是上述配置的匹配代碼,可供參考以及我自己回檔。
/**
* @brief MPU配置
* @param None
* @retval None
*/
static void MPUInit(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* 禁止 MPU */
HAL_MPU_Disable( );
/* 配置AXI SRAM的MPU屬性為Write back, Read allocate,Write allocate
最佳性能,用於CPU處理計算 */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置D2域MPU
D2域外設的DMA使用 禁止cache */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置以太網收發描述符部分為Strongly Ordered */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.SubRegionDisable = 0x0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置D3域MPU
D3域外設的DMA使用 禁止cache */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x38000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER3;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置FMC 片選3 的支持*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x68000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; // 此外設需配置為無cache,否則會重複片選和讀寫使能
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER4;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/*使能 MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
此文由 Mix Space 同步更新至 xLog
原始鏈接為 https://www.yono233.cn/posts/novel/25_10_13_arm-cache_mpu