arm cache 属性的影响

前言

最近希望将 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 以获得最大的性能，对应上述的第一个组合。

而上述的第二个组合，我暂时没有遇到过使用场景，也想象不出来。

以下是上述配置的匹配代码，可供参考以及我自己回档。

Copy
/**
* @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