第三章 TC3xx内存布局详解
做嵌入式开发,特别是搞OTA升级,内存布局是绕不开的坎。我常说一句话:搞不清内存布局,就像开车不看仪表盘——迟早要出事。
TC3xx的内存体系其实挺有意思的。它不像有些MCU那样简单粗暴地划几个区就完事,而是把Flash、RAM、OTP这些资源安排得明明白白。今天我就带大家把这块硬骨头啃下来。
3.1 Flash分区:你的代码住哪儿
TC3xx的Flash,说白了就是程序存储的大本营。它分为几个关键区域,每个区域都有自己的脾气。
| 区域名称 | 起始地址 | 大小 | 用途 |
|---|---|---|---|
| PFlash0 | 0x80000000 | 2MB | 主程序代码存储 |
| PFlash1 | 0x80200000 | 2MB | 备用程序或Bootloader |
| DFlash0 | 0xAF000000 | 64KB | 数据存储,比如校准参数 |
| DFlash1 | 0xAF010000 | 64KB | EEPROM模拟区 |
这里有个坑,我必须要说。PFlash0和PFlash1虽然大小一样,但它们的擦写寿命和访问速度其实有细微差别。我在做OTA方案时,曾经因为没注意这个差异,导致升级过程中出现奇怪的超时问题。
关键点:PFlash的擦除单位是16KB,而DFlash是4KB。这意味着如果你要频繁更新小数据,用DFlash更划算。
3.2 RAM区域:你的数据在哪儿跑
RAM这块,TC3xx做得挺讲究。它把RAM分成了好几个独立的小区,每个小区都有专门的用途。
- DSPR(Data Scratch Pad RAM):每个核独享的,速度最快。我习惯把关键变量和堆栈放这里。
- PSPR(Program Scratch Pad RAM):也是每个核独享,但专门给程序用的。放一些时间敏感的函数,比如中断服务程序。
- LMU(Local Memory Unit):所有核共享的,容量最大。适合放全局变量和缓冲区。
- DLMU(Data Local Memory Unit):也是共享的,但访问路径更短,速度比LMU快一点。
你想想看,如果OTA升级时把下载的固件包放在DSPR里,那肯定不行——空间不够,而且会影响其他任务的运行。我一般把下载缓冲区放在LMU,解压和校验时再用DSPR加速。
我的习惯:OTA升级的临时缓冲区放在LMU,大小建议至少256KB。这样即使网络波动导致数据重传,也不会把RAM撑爆。
3.3 OTP区域:一次写入,终身受用
OTP,全称是One-Time Programmable。说白了就是只能写一次,写错了就废了。TC3xx的OTP区域不大,但作用很关键。
它主要用来存这些东西:
- 芯片唯一ID:每颗芯片出厂时就烧录好了,不能改。
- 安全密钥:用于固件签名验证的根密钥。我建议把公钥哈希放这里。
- 配置字:比如启动模式、Flash保护位等。
我曾经见过一个项目,工程师把调试接口的解锁密码写到了OTP里,结果密码设错了,芯片直接变砖。嗯,那场面,真是欲哭无泪。
警告:OTP区域一旦写入,无法擦除。在量产前一定要反复确认配置值。建议先在开发板上验证无误后,再写入正式产品。
3.4 内存映射与访问权限
TC3xx的内存映射不是简单的线性排列。它用了多层映射和权限控制,目的是保证安全。
举个例子,PFlash在CPU看来是0x80000000开始的地址,但在DMA控制器看来,可能是另一个地址。这种设计是为了隔离不同主设备的访问路径。
权限控制这块,TC3xx引入了MPU(内存保护单元)。你可以给每个任务分配不同的内存访问权限。比如OTA升级任务只能写DFlash,不能碰PFlash0里的主程序。
// 配置MPU保护PFlash0区域
// 只允许读,不允许写
IfxMpu_setRegion(0, // 区域编号
0x80000000, // 起始地址
0x200000, // 大小2MB
IfxMpu_Access_readOnly); // 只读权限
这个机制在OTA升级时特别有用。你可以把正在运行的程序区域设为只读,防止意外篡改。等升级完成、系统重启后,再切换保护策略。
3.5 实战中的内存布局规划
好了,理论说完了,咱们来点实际的。我一般做OTA方案时,内存布局是这样规划的:
| 区域 | 内容 | 大小 | 说明 |
|---|---|---|---|
| PFlash0 | Bootloader | 128KB | 负责启动和升级引导 |
| PFlash0剩余 | App主程序 | ~1.8MB | 正常运行时执行 |
| PFlash1 | 升级备份区 | 2MB | 存放新固件 |
| DFlash0 | 升级状态标志 | 4KB | 记录升级进度 |
| DFlash1 | 用户参数 | 64KB | 校准数据、配置等 |
为什么要这么分?原因很简单:
- Bootloader放在PFlash0开头,上电就能执行。
- 升级备份区放在PFlash1,这样升级时不会覆盖正在运行的程序。
- 升级状态标志用DFlash,因为擦写次数多,而且数据量小。
我记得有一次,客户要求升级过程中断电后能恢复。我就在DFlash0里存了一个升级状态机,每次擦写前先更新状态。这样即使断电,重启后也能从断点继续。
避坑指南:千万不要把升级状态标志和用户参数放在同一个DFlash扇区。否则每次升级都会擦除用户参数,客户会找你算账的。我曾经就吃过这个亏,后来学乖了,分开存放。
3.6 小结
TC3xx的内存布局,说白了就是一套精心设计的资源分配方案。Flash管存储,RAM管运行,OTP管安全。搞懂了这些,你就能像搭积木一样,把OTA升级方案安排得明明白白。
下一章,我会带大家深入Bootloader的设计,看看怎么在TC3xx上实现一个可靠的启动引导程序。到时候咱们再细聊。