STM32H743的Cache(缓存)是提升高速内核访问低速内存/外设效率的硬件模块,核心是把常用的数据/指令临时存在“高速缓存区”,减少CPU等待时间。

        cache也属于ARM内核。

一、Cache的核心基础

1. Cache的本质:CPU的“高速临时仓库”

        STM32H743基于Cortex-M7内核,主频最高480MHz,但它访问的外部Flash(通常几十MHz)、甚至部分SRAM的速度远低于内核。如果CPU每次都直接访问这些低速存储,会大量“空等”(浪费时钟周期)。

        Cache可以访问外部FLASH或者SRAM进行提速。

        注:如果是ITCM,已经是480MHZ的访问速率,那么无需配置MPU和cache。

2. STM32H743的Cache配置(核心参数)

缓存类型

大小

核心作用

适用场景

I-Cache

64KB

缓存指令(程序代码)

从Flash/低速SRAM运行程序

D-Cache

64KB

缓存数据(变量/外设数据)

频繁读写SRAM/外设数据

Cache行

32字节

缓存的最小单位(每次读写按行操作)

3. 关键概念(通俗解释)

术语

大白话解释

命中(Hit)

CPU要访问的内容在Cache里,直接取→速度快

未命中(Miss)

CPU要访问的内容不在Cache里,需先从低速存储加载到Cache→短暂等待

写穿(Write-Through)

写数据时,同时写Cache和原始内存→数据绝对一致,但写速度稍慢

写回(Write-Back)

写数据时只写Cache,等Cache行被替换时再写回原始内存→写速度快,但数据可能不一致

缓存失效(Invalidate)

清空Cache中指定内容,强制CPU重新从原始内存加载最新数据

缓存回写(Clean)

把Cache中修改过的数据写回原始内存(仅写回模式需要)

二、STM32H743 Cache使用意义

        新手可能会问:“我不用Cache行不行?”——可以,但会浪费H743的性能,甚至导致功能异常:

  1. 性能损失:如果禁用Cache,480MHz的内核访问Flash(比如运行程序)时,会因为速度不匹配频繁等待,实际运行效率可能只有原本的1/5;
  2. 数据一致性问题:如果开启Cache但不做正确配置,CPU从Cache读到“旧数据”,而外设/DMA已经修改了原始内存的数据,导致程序逻辑出错;
  3. H743的内存架构特殊:H743有多层内存(ITCM/DTCM/AXI SRAM/外部SDRAM),不同内存的Cache策略不同,必须针对性配置。

三、Cache的核心使用规则

1. 不同内存/外设,Cache策略不同(核心!)

Cache不是“开了就万事大吉”,必须根据访问对象调整:

访问对象

I-Cache

D-Cache

推荐模式

关键注意点

Flash(程序代码)

开启

关闭

-

指令缓存提升程序运行速度

ITCM SRAM(指令)

关闭

关闭

-

ITCM本身是高速RAM,无需Cache

DTCM SRAM(数据)

关闭

关闭

-

DTCM直接连内核,速度比Cache还快

AXI SRAM(数据)

关闭

开启

写回+分配

频繁读写的数据,Cache收益最大

外设寄存器

关闭

关闭

-

外设数据实时变化,Cache会导致读旧值

外部SDRAM

关闭

开启

写回+分配

低速外部内存,Cache提升明显

2. Cache的基本操作(HAL库示例)

Cache的核心操作是“使能/禁用”“失效(Invalidate)”“回写(Clean)”:

步骤1:开启I-Cache和D-Cache(系统初始化时)
// 开启I-Cache(指令缓存)
SCB_EnableICache();
// 开启D-Cache(数据缓存),默认用写回模式
SCB_EnableDCache();
步骤2:针对不同内存配置Cache(结合MPU)

Cache的策略不是单独配置的,而是通过MPU(内存保护单元) 给不同内存区域标记“是否可缓存”——这是新手最容易忽略的点!

示例:配置AXI SRAM为“可缓存(D-Cache)”

MPU_Region_InitTypeDef MPU_InitStruct = {0};
MPU_Disable(); // 配置前禁用MPU

// AXI SRAM(0x24000000,1MB)
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_UNPRIV_RO;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
// 关键:设置为可缓存、可缓冲(写回模式)
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;    // 开启D-Cache
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;  // 开启写回
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;         // Normal内存(SRAM)

HAL_MPU_ConfigRegion(&MPU_InitStruct);
MPU_Enable(MPU_PRIVILEGED_DEFAULT); // 使能MPU

示例:配置外设寄存器为“不可缓存”

// 外设寄存器区(0x40000000,16MB)
MPU_InitStruct.BaseAddress = 0x40000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; // 禁用D-Cache
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; // 禁用缓冲
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; // Device内存(外设)
HAL_MPU_ConfigRegion(&MPU_InitStruct);
步骤3:数据一致性处理

如果CPU和DMA/外设同时访问一块开启D-Cache的内存(比如AXI SRAM),会出现“CPU读Cache旧数据,DMA写了原始内存新数据”的问题,必须手动处理

// 场景:DMA要往AXI SRAM(0x24000000)写数据,先失效Cache(清空旧数据)
SCB_InvalidateDCache_by_Addr((uint32_t *)0x24000000, 1024); // 失效1024字节
HAL_UART_Receive_DMA(&huart1, (uint8_t *)0x24000000, 1024); // DMA接收数据

// 场景:CPU修改了Cache中的数据,要让DMA读取最新值,先回写Cache
SCB_CleanDCache_by_Addr((uint32_t *)0x24000000, 1024); // 回写1024字节
HAL_SPI_Transmit_DMA(&hspi2, (uint8_t *)0x24000000, 1024); // DMA发送数据

四、常见问题

1. 开启Cache后外设数据读错

        原因:给外设寄存器区域开了D-Cache,CPU读的是Cache里的旧值;

        解决:所有外设地址段(0x40000000开始)必须配置为MPU_ACCESS_NOT_CACHEABLE

2. DMA和CPU共享内存数据不一致

        原因:CPU写数据到Cache但没回写,DMA读原始内存还是旧值;

        解决:DMA发送前执行SCB_CleanDCache_by_Addr(回写),DMA接收前执行SCB_InvalidateDCache_by_Addr(失效)。

3. 开启Cache后程序跑飞

        原因:给ITCM/DTCM(高速RAM)开了Cache,反而导致冲突;

        解决:ITCM/DTCM本身速度比Cache快,直接禁用其Cache(配置为NOT_CACHEABLE)。

4. 只开Cache不配置MPU

        原因:以为“开启SCB_EnableDCache()就够了”,但MPU没给内存区域标记“可缓存”,Cache实际没生效

        解决:Cache的策略是通过MPU的IsCacheable位控制的,必须配套配置MPU。

五、建议

阶段1:基础配置

  1. 开启I-Cache(提升Flash运行程序的速度);
  2. 开启D-Cache,但仅给AXI SRAM/外部SDRAM配置“可缓存”;
  3. 所有外设区域配置为“不可缓存”;
  4. 暂时不用DMA的话,先不处理数据一致性(减少复杂度)。

阶段2:进阶处理

  1. 记住“DMA发送前Clean、接收前Invalidate”的规则;
  2. 用HAL库的SCB_CleanDCache_by_Addr/SCB_InvalidateDCache_by_Addr函数,参数是“内存起始地址+长度”;
  3. 长度必须是32字节的整数倍(Cache行大小),比如要处理100字节,就填128字节。

阶段3:优化配置

  1. 区分“写穿”和“写回”:对数据一致性要求高的场景(如实时控制)用写穿,对速度要求高的场景用写回;
  2. 针对不同任务的内存区域,通过MPU配置不同的Cache策略(比如任务私有数据开Cache,共享数据关Cache)。

六、总结

  1. Cache目的是让480MHz的内核不用等低速存储;
  2. Cache必须配合MPU使用,不同内存/外设要配不同的缓存策略;
  3. 只要涉及DMA/外设,必须处理“Cache数据一致性”(Clean/Invalidate)。

 

七、代码及寄存器

SCB_EnableICache();
SCB_EnableDCache();
SCB->CACR |= 1 << 2; /* 强制 D-Cache 透写,如不开启透写,实际使用中可能遇到各种问题 */

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐