紧耦合内存 TCM:为什么实时/中断代码要放进 TCM 而非 Cache
更新时间:2026-09-19。前置:Cache 组织结构、存储器推断、SRAM 控制器。Cache 提升平均性能但最坏情况延迟不确定;电机控制、安全中断、DSP 关键循环要的是「每次都确定」,于是 MCU 提供 TCM。
本文要回答的问题
- TCM 和普通 cache、普通片上 SRAM 到底差在哪?
- ITCM/DTCM 为什么分开,和哈佛结构什么关系?
- 什么代码/数据该放 TCM,怎样在启动时把内容搬进去?
- DMA 能不能访问 TCM,容量和 ECC 有哪些坑?
一、TCM 是什么:确定延迟的本地 SRAM
TCM(Tightly-Coupled Memory)是直接连到 CPU 内核、映射到固定地址空间的高速 SRAM,其关键不在「快」而在确定:
| 维度 | Cache | TCM |
|---|---|---|
| 内容管理 | 硬件按命中率自动替换,软件不可控 | 软件/链接脚本精确决定放什么 |
| 访问延迟 | hit 快;miss 时要去主存,延迟数十~数百周期且不固定 | 固定(常 0/1 等待),每次都一样 |
| 地址 | 透明缓存主存副本 | 独立固定地址,软件直接寻址 |
| 一致性问题 | 有多核/DMA 一致性问题 | 内容软件可控,基本无意外失效 |
| 用途 | 通用平均性能 | 中断处理、实时循环、关键数据 |
实时系统要算最坏执行时间(WCET):一段中断代码若跑在 cache 里,可能这次 hit、下次被其他代码挤出而 miss,响应时间无法保证。放进 TCM 后,取指和读数据的延迟被钉死,中断到执行首条指令、到产出结果的时间可严格预算(配合 中断/PLIC 的固定延迟)。
二、ITCM 与 DTCM、哈佛总线
典型 Cortex-M/RISC-V MCU 分两块:
- ITCM(Instruction TCM):放代码,接内核指令总线(I 总线)。
- DTCM(Data TCM):放数据/栈,接数据总线(D 总线)。
- 因为是哈佛结构,CPU 可在同一拍同时取指(ITCM)+ 读写数据(DTCM),互不阻塞,关键循环可达到每周期一条指令的吞吐。
- 有的 TCM 端口还接到系统总线矩阵(slave 口),允许 DMA/其他主设备/调试器在 CPU 不访问或经仲裁时访问它(见 AHB 总线矩阵)。
- 物理上 TCM 常由编译 SRAM 宏构成(见 SRAM 控制器、存储分块),可配等待状态(高频时插 1 wait state),但一旦配置,延迟对软件仍是固定的。
三、什么放 TCM、什么不放
适合放 TCM:
- 最高优先级中断 ISR、故障处理(电机 FOC、电源保护、汽车安全例程)。
- 确定性要求的紧循环(DSP 滤波、控制律、加解密时序敏感部分,见 ADC 过采样、AES 硬件)。
- ISR 用的数据、栈、关键查找表、描述符。
不适合:
- 大体积通用代码/数据——TCM 容量小(几十 KB~1MB 级),是稀缺资源。
- 需要大容量缓冲的内容(帧缓冲、大块 DMA 缓冲)——放外部 SRAM/DRAM,经 cache(见 HyperRAM)。
- 随机、低频访问的代码——放 cache 让其自动利用即可。
工程上用链接脚本 section(如 .itcm.text、.dtcm.data)加函数/变量属性(__attribute__((section(...))))精确放置,并做 WCET/占用分析。
四、内容从哪来:启动加载
TCM 是 SRAM,掉电丢失。代码常量初值通常存 Flash,启动时搬入:
复位 → BootROM/startup 代码(从 Flash 执行)
把 .itcm.text 段从 Flash 拷贝到 ITCM 地址
把 .dtcm.data 初值拷贝到 DTCM、.dtcm.bss 清零
配置 TCM 等待状态/ECC(见系统初始化)
之后跳到 ITCM 执行关键代码- 高性能 MCU 也支持「Flash→TCM」影子映射或上电 DMA 批量加载(见 DMA 微架构)。
- 有的器件支持 TCM ECC:上电需初始化(写已知模式)以免假 ECC 错误,见 SRAM ECC、Hamming ECC。
五、TCM 与 DMA/多核
- DMA 访问 DTCM:并非所有 TCM 都对 DMA 开放或随时可达。有的 DTCM 只在核的私有总线,DMA 访问要走「系统 slave 口 + 仲裁」,且当 CPU 高频占 D 总线时带宽受限;常见 bug 是以为 DMA 一定能零等待读写 DTCM。
- cache 一致性:TCM 本身不是 cache、通常不被 data cache 缓存(直连地址),所以 DMA 缓冲放 DTCM 反而免去 clean/invalidate,这是把 DMA 描述符放 TCM 的一个理由(见 DMA 与 cache)。但前提是 DMA 主设备物理上能到该地址。
- 多核时每核可有私有 TCM;他核要访问需经系统总线映射,不能假设单周期。
六、常见的坑
- 把 TCM 当「更快的 cache」乱放:塞满无关代码,关键 ISR 放不下;要按 WCET 需求精确分区。
- 以为 TCM 非易失:代码不搬运直接期望在 ITCM 执行,上电是随机内容;必须 startup 拷贝。
- 链接地址与加载地址混淆:运行地址在 TCM、存储地址在 Flash,链接脚本和拷贝表没对应,跳进去跑飞。
- DMA 访问不到/慢:DTCM slave 口未使能或总线仲裁导致 DMA 取数延迟,实时缓冲失效。
- 等待状态配置变化:高时钟下 TCM 也需 wait state,时序预算仍按 0 等待算,WCET 错。
- ITCM/DTCM 越界:链接脚本段大小超过物理 TCM,启动或运行时溢出到无效地址。
- ECC 未初始化:上电随机校验位导致假错误中断。
- 栈位置错:把系统栈放普通 SRAM,最深中断链上 cache miss 打破确定性;关键栈应在 DTCM。
- 函数指针/回调在 Flash:ITCM 代码调用的回调仍在 cache/Flash,确定性被打断却没注意。
- 调试时被断点/重映射影响:某些 TCM 在调试态/睡眠态的访问行为不同(见 低功耗、调试模块)。
- 常量与可写数据混放:只读表放 DTCM 浪费可写空间,可放 ITCM/专用只读区。
- 频率变化后未重配等待状态:DVFS 升频时 TCM wait state 没跟上导致取指错误(见 时钟控制器)。
相关与延伸
对照 cache 的非确定性见 Cache 组织与替换;存储物理见 SRAM 控制器、存储器推断、存储分块;DMA 缓冲一致性见 DMA 与 cache。
总结
TCM 是直接挂在内核 I/D 总线上、映射到固定地址、访问等待状态由配置钉死的本地 SRAM,与「靠硬件自动替换、miss 时延迟数十到数百周期且不固定」的 cache 相反,它用可预测的单周期/固定延迟换确定性:ITCM 放实时中断和控制律代码、DTCM 放 ISR 数据和关键栈,哈佛总线允许同一拍同时取指和读数,掉电后由启动代码把对应段从 Flash 拷贝进来;它容量小、需正确设置等待状态和 ECC 初始化,DMA 访问要确认有系统 slave 口——把 TCM 当大 cache 乱填、忘记启动搬运、链接/加载地址错配和假设 DMA 必能零等待访问 DTCM 是四大常见坑。