3. STM32N6内存体系与图像缓冲区规划
STM32N6 的图像预处理链路能否跑满带宽,往往不取决于 CPU 主频,而取决于“数据放在哪块内存、谁在访问它、访问路径是否冲突”。STM32N6 内部包含多块用途不同的 SRAM,外部可挂 HyperRAM/PSRAM,再加上 Cache 与 DMA 的可见性问题,构成了一个必须提前规划的存储拓扑。本节围绕“把哪块缓冲区放在哪里、为什么、怎么验证”展开。
一、先看清各存储区的角色分工
STM32N6 的片上存储大致可分为三类角色:
- DTCM(Data Tightly-Coupled Memory):紧耦合数据内存,通常为 128KB 级别,直连内核,零等待、无 Cache 一致性问题,适合存放栈、频繁访问的标量变量、小型查找表、DMA 描述符等。它不经过系统总线矩阵,因此不适合作为大图像缓冲。
- ITCM(Instruction Tightly-Coupled Memory):紧耦合指令内存,用于存放对实时性要求极高的中断服务程序或热点代码,保证取指不被总线竞争拖慢。图像数据不应放在这里。
- AXI SRAM:挂在 AXI 总线矩阵上的通用 SRAM,容量较大(数百 KB 到 MB 级),可被 CPU、DMA、NPU、显示控制器等多主设备访问,是图像行缓冲、中间特征图、DMA 目标缓冲的主力区域。代价是访问需要经过总线仲裁,且若开启 D-Cache 就存在一致性维护成本。
- 外部 HyperRAM / PSRAM:通过 OCTOSPI/XSPI 接口扩展,容量可达几十 MB,适合存放整帧图像、多帧环形缓冲、模型权重等大块数据。带宽和延迟明显劣于片上 SRAM,且访问是串行的,随机小访问效率低,必须靠突发传输和 Cache 掩盖延迟。
一个常见的误区是把整帧图像直接放进 AXI SRAM,结果发现同时还要放模型中间层和显示缓冲,很快耗尽。正确做法是按“访问频率 × 数据量”分层:高频小数据进 DTCM,中频中等数据进 AXI SRAM,低频大数据进 HyperRAM。
二、Cache 与 DMA 可见性:最容易踩的坑
STM32N6 的 Cortex-M55 带 D-Cache。当 CPU 写图像缓冲、DMA 再去读同一块内存时,如果数据还停留在 Cache 里没写回,DMA 读到的是旧数据;反过来 DMA 写入新数据后,CPU 若命中旧 Cache 行,读到的也是旧值。这就是一致性问题。
处理方式有三种,按场景选择:
- 把 DMA 缓冲放在非 Cache 区或配置为 Write-Through/Non-Cacheable:最省心,适合小缓冲和描述符,但会牺牲 CPU 访问速度。
- 显式维护 Cache:CPU 写完后调用
SCB_CleanDCache_by_Addr()写回,DMA 写完后调用SCB_InvalidateDCache_by_Addr()失效,再让 CPU 读。注意地址和长度必须按 Cache 行(通常 32 字节)对齐,否则会误伤相邻数据。 - 利用 MPU 分区属性:把图像缓冲所在区域配置为 Normal Non-Cacheable 或 Device 属性,从根上避免一致性问题,代价是该区域 CPU 访问变慢。
三、多缓冲区分配策略
图像流水线通常需要至少三级缓冲:采集缓冲(DMA 写入)、处理缓冲(CPU/NPU 读取并处理)、输出缓冲(送显示或下一级)。若只有一块缓冲,采集和处理必须串行,帧率会被腰斩。因此推荐使用双缓冲或三缓冲 + 乒乓切换。
以 640×480、RGB565 为例,单帧约 600KB。若放在 HyperRAM,可开三块共 1.8MB 做环形队列;若放在 AXI SRAM,则通常只够放行缓冲或降分辨率后的中间图。下面这张图给出一个典型的分层缓冲拓扑与数据流向。
四、一个可落地的分配示例
假设系统需求为:OV5640 输出 640×480 RGB565,帧率 30fps,NPU 做轻量检测,同时送 LCD 显示。单帧 614400 字节,30fps 即约 18.4MB/s 的采集带宽。规划如下:
| 缓冲区 | 位置 | 大小 | 属性 | 用途 |
|---|---|---|---|---|
| Frame[3] | HyperRAM | 3×600KB | Non-Cacheable 或 Clean/Invalidate | DMA 采集环形缓冲 |
| LineBuf | AXI SRAM | 2×1280B | Cacheable | 逐行预处理输入 |
| TensorIn | AXI SRAM | 224×224×3 | Cacheable + Clean | NPU 输入张量 |
| DispBuf | AXI SRAM | 2×300KB | Non-Cacheable | LCD 双缓冲输出 |
| Desc/Param | DTCM | <8KB | — | DMA 描述符、标量 |
关键判断依据:HyperRAM 上的三帧缓冲必须保证 DMA 写入与 CPU 读取不在同一帧上,通过帧完成中断切换索引;AXI SRAM 上的 TensorIn 在交给 NPU 前执行一次 Clean,NPU 写回结果后执行 Invalidate;DispBuf 设为 Non-Cacheable,避免显示控制器持续读取时反复维护 Cache。
最后强调一个原则:先定访问模式,再定内存位置。凡是“DMA 写、CPU 读”的缓冲,优先考虑 Non-Cacheable 或严格对齐的 Clean/Invalidate;凡是“CPU 高频小访问”的数据,优先放 DTCM;凡是“大块、低频、可突发”的数据,放 HyperRAM 并用 Cache 掩盖延迟。按这个顺序规划,STM32N6 的图像流水线才能在有限的内存资源下稳定跑起来。