2、STM32H7内存架构概览:掌握Flash、SRAM、DTCM、ITCM、AXI SRAM等内存区域的特点与用途
STM32H7系列(特别是基于Cortex-M7内核的H743/H750等型号)之所以能在TinyML推理中表现出远超F4系列的性能,其根本原因之一在于它拥有一个极其复杂且精细的内存架构。Cortex-M7内核本身具备6级超标量流水线,并且支持指令和数据双发射,如果内存访问速度跟不上内核的消费速度,再强的算力也会被“饿死”。因此,STM32H7将内存划分为多个物理区域,每个区域通过不同的总线连接到内核,拥有不同的访问延迟、容量和用途。对于TinyML开发者而言,理解这些内存区域的区别,是进行算子优化、缓存命中率调优和DMA数据传输设计的前提。本章将逐一剖析Flash、ITCM、DTCM、AXI SRAM以及普通SRAM的特点,并给出在神经网络推理中的选型建议。
上图展示了STM32H7内存架构的核心模块及其与内核、DMA和外设的连接关系。从TinyML应用的角度来看,这张图揭示了几个关键点:ITCM和DTCM是内核的“私密快车道”,访问延迟为零,但容量有限;AXI SRAM是主数据交换区,容量大且支持DMA直接访问;Flash虽然容量最大,但访问延迟高,通常需要借助缓存或预取机制。下面我们将逐一深入分析每个内存区域。
2.1 核心原理:Cortex-M7的内存架构与总线矩阵
要理解STM32H7的内存架构,首先需要了解Cortex-M7内核的总线接口设计。与Cortex-M4(如STM32F4)仅有一条系统总线不同,Cortex-M7拥有多条独立的总线接口,每条总线可以并行访问不同的内存区域,从而实现真正的哈佛架构(指令和数据并行访问)。具体来说,Cortex-M7提供了以下主要总线接口:
- ITCM总线(Instruction Tightly Coupled Memory):专用于指令取指,连接到ITCM RAM。该总线不经过任何总线矩阵或仲裁器,因此CPU取指时没有任何额外延迟。
- DTCM总线(Data Tightly Coupled Memory):专用于数据读写,连接到DTCM RAM。同样不经过总线矩阵,适合存放栈指针、频繁访问的变量和中间计算结果。
- AXI总线(Advanced eXtensible Interface):这是主系统总线,连接到AXI SRAM、Flash以及通过总线桥连接到其他外设。AXI总线支持多主设备访问(如CPU、DMA、以太网MAC等),并且具备写合并和读分配等优化特性。
- AHB/APB总线:通过AXI到AHB的桥接,连接低速外设(如UART、SPI、ADC等)。这些外设的访问延迟较高,不适合高频数据交换。
在TinyML推理过程中,CPU需要同时执行指令(从ITCM或Flash读取)、读取权重(从Flash或AXI SRAM)、读写中间特征图(从DTCM或AXI SRAM)。如果这些访问都挤在同一条总线上,就会产生严重的瓶颈。而STM32H7的多总线设计允许这些操作并行进行,从而大幅提升有效计算吞吐量。
2.2 各内存区域详细解析
2.2.1 Flash(2MB)——模型与代码的“仓库”
STM32H7的Flash容量最大(H743为2MB,H750为128KB但可通过外部QSPI扩展),用于存储程序代码、只读数据和神经网络模型的权重。然而,Flash的访问速度远低于CPU主频:在480MHz主频下,Flash的等待状态(Wait States)通常需要7个周期左右。这意味着如果CPU直接从Flash取指或读取数据,性能将大打折扣。
为了解决这个问题,STM32H7内置了Flash预取缓冲区和指令缓存(I-Cache)。预取缓冲区会提前将连续指令读取到缓冲区中,而I-Cache则缓存最近访问的指令块。对于TinyML应用,模型权重通常存储在Flash中,但在推理时会被复制到SRAM中以提高访问速度。如果权重太大无法完全放入SRAM,则只能通过Flash读取,此时建议启用数据缓存(D-Cache)来减少重复访问的延迟。
2.2.2 ITCM(64KB)——指令执行的“快车道”
ITCM(Instruction Tightly Coupled Memory)是专门为指令取指设计的SRAM,容量为64KB。它通过独立的ITCM总线直接连接到CPU内核,没有任何总线仲裁和等待状态。这意味着CPU从ITCM取指时,每个时钟周期都能获取一条指令,实现零等待执行。
在TinyML场景中,ITCM最适合存放计算密集型的核心循环代码,例如CMSIS-NN的卷积内核函数、矩阵乘法函数等。将这些热点函数放置在ITCM中,可以显著减少指令取指延迟,提升整体推理速度。需要注意的是,ITCM只能存储指令,不能存储数据。
2.2.3 DTCM(128KB)——数据访问的“私密空间”
DTCM(Data Tightly Coupled Memory)是专门为数据访问设计的SRAM,容量为128KB。与ITCM类似,DTCM通过独立的DTCM总线连接到CPU,访问延迟为零。DTCM最适合存放:
- 栈空间(Stack):函数调用时的局部变量和返回地址。
- 频繁访问的全局变量:例如推理循环中的计数器、指针、临时缓冲区。
- 中间特征图(Feature Map):如果模型较小,可以将某一层的输入和输出特征图放在DTCM中,实现零等待读写。
但DTCM有一个重要限制:DMA控制器无法直接访问DTCM。这是因为DTCM总线只连接到CPU内核,没有连接到总线矩阵。因此,如果数据需要通过DMA从外设搬运到内存,不能直接写入DTCM,而必须先写入AXI SRAM,再由CPU拷贝到DTCM。
2.2.4 AXI SRAM(512KB)——主数据交换区
AXI SRAM是STM32H7中容量最大的SRAM,共512KB,通过AXI总线连接到内核和DMA控制器。AXI总线支持多主设备访问,并且具备写合并(Write Merging)和读分配(Read Allocating)等优化特性。对于TinyML应用,AXI SRAM是存放以下数据的主要区域:
- 模型权重:从Flash加载到AXI SRAM中,以便快速访问。
- 输入/输出特征图:特别是较大尺寸的特征图。
- DMA缓冲区:用于外设数据采集和传输。
- 中间计算结果:如池化层、激活函数的输出。
AXI SRAM的访问延迟取决于是否命中缓存。如果启用了D-Cache,CPU对AXI SRAM的访问会先经过缓存,命中时延迟为1个周期,未命中时需要从SRAM读取(约2-3个周期)。在TinyML中,建议对AXI SRAM启用D-Cache,但需要注意缓存一致性问题:当DMA写入AXI SRAM时,如果CPU缓存中已有旧数据,就会产生不一致。此时需要执行缓存清理(Clean)和失效(Invalidate)操作。
2.2.5 普通SRAM(SRAM1/2/3,共288KB)——外设与通用存储
除了AXI SRAM,STM32H7还提供了SRAM1(128KB)、SRAM2(128KB)和SRAM3(32KB),它们通过AHB总线连接。这些SRAM的访问速度略低于AXI SRAM,但功耗更低。在TinyML应用中,这些SRAM通常用于:
- 外设数据缓冲区:例如ADC采样数据、UART接收缓冲区。
- DMA描述符:用于配置DMA传输。
- 非关键数据存储:如日志缓冲区、调试信息。
需要注意的是,SRAM1/2/3与AXI SRAM在物理上是连续的地址空间,但通过不同的总线访问。在性能要求不高的场景下,可以灵活分配使用。
2.3 内存区域对比与选型策略
| 内存区域 | 容量 | 访问总线 | 等待周期 | DMA可访问 | TinyML典型用途 |
|---|---|---|---|---|---|
| Flash | 2MB (H743) | AXI (通过预取/缓存) | 7周期 (480MHz) | 是 | 模型权重存储、代码存储 |
| ITCM | 64KB | ITCM总线 (专用) | 0 | 否 | 核心计算函数(卷积/矩阵运算) |
| DTCM | 128KB | DTCM总线 (专用) | 0 | 否 | 栈、中间特征图、频繁访问变量 |
| AXI SRAM | 512KB | AXI总线 | 1-3周期 (可缓存) | 是 | 权重、特征图、DMA缓冲区 |
| SRAM1/2/3 | 288KB | AHB总线 | 2-4周期 | 是 | 外设缓冲、日志、非关键数据 |
在实际TinyML项目中,内存分配策略应遵循以下优先级:
- 核心计算函数(如arm_convolve_H7)放入ITCM。
- 栈和热数据(如循环计数器、指针)放入DTCM。
- 大块数据(权重、特征图)放入AXI SRAM,并启用D-Cache。
- 外设相关缓冲区放入SRAM1/2/3,避免占用AXI SRAM带宽。
2.4 案例拆解:一个图像分类模型的内存布局优化
假设我们使用STM32H743运行一个MobileNetV1图像分类模型(输入224x224x3,权重约4.2MB)。由于Flash容量为2MB,模型权重无法完全放入内部Flash,因此需要将权重存储在外部QSPI Flash中,并在推理时按需加载到AXI SRAM。以下是具体的内存布局方案:
初始现象与目标:模型推理时间约为850ms,远高于预期的300ms。通过性能分析发现,CPU在等待权重数据时浪费了大量周期。
关键参数分析:
- 模型权重总量:4.2MB(QSPI Flash中)
- AXI SRAM可用空间:512KB(需预留DMA缓冲区)
- DTCM可用空间:128KB(用于栈和中间特征图)
- ITCM可用空间:64KB(用于核心函数)
优化操作步骤:
- 将CMSIS-NN的卷积内核函数(约30KB)放入ITCM,通过修改链接脚本(.ld文件)实现。
- 将推理循环的栈空间(8KB)和第一层卷积的输入/输出特征图(约150KB)放入DTCM。注意DTCM容量有限,只放前几层的小特征图。
- 将模型权重按层分组,每次推理前通过DMA从QSPI Flash加载当前层权重到AXI SRAM(使用双缓冲机制,预加载下一层权重)。
- 启用D-Cache,并设置AXI SRAM区域为Cacheable。在DMA写入权重后,执行SCB_CleanDCache()和SCB_InvalidateDCache()确保缓存一致性。
- 将ADC采样数据缓冲区放入SRAM1,避免与权重加载冲突。
结果对比:优化后推理时间降至320ms,性能提升约2.6倍。主要收益来自:ITCM消除了指令取指延迟,DTCM加速了特征图访问,DMA双缓冲隐藏了QSPI Flash的加载延迟。
风险与代价:内存布局复杂度增加,需要仔细管理DTCM的容量分配;DMA与CPU的缓存一致性维护增加了代码复杂度;如果模型层数较多,双缓冲需要额外的SRAM空间。
2.5 常见误区与总结
在实际开发中,工程师经常陷入以下误区:
- 误区一:所有数据都放入DTCM。DTCM虽然快,但容量有限且DMA无法访问。如果数据需要DMA搬运,必须放在AXI SRAM中。
- 误区二:忽略缓存一致性。当DMA和CPU共享AXI SRAM时,如果不执行缓存清理/失效操作,会导致数据错乱。这是TinyML中最常见的隐蔽Bug。
- 误区三:将大数组定义在栈上。STM32H7的栈默认在DTCM中,如果定义大数组(如int8_t buf[10000]),会迅速耗尽DTCM空间,导致栈溢出。应将大数组定义为全局变量或静态变量,放在AXI SRAM中。
- 误区四:认为Flash访问速度足够快。虽然Flash有预取和缓存,但在随机访问权重时,缓存命中率低,实际延迟可能高达数十个周期。务必在推理前将权重加载到SRAM。