三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

CCS7.3实战:给TI DSP的片上Flash分区,同时烧录两个独立工程(附完整CMD文件配置)

CCS7.3实战:给TI DSP的片上Flash分区,同时烧录两个独立工程(附完整CMD文件配置)

CCS7.3实战:TI DSP片上Flash分区与双工程烧录全解析

在嵌入式系统开发中,有时我们需要在单个DSP芯片上部署多个独立工程,比如Bootloader与应用程序分离、双备份系统设计,或是功能模块的独立升级。这种需求对Flash存储的管理提出了更高要求。本文将深入探讨如何在TI CCS7.3开发环境中,通过精细的Flash分区和链接器配置,实现两个工程的独立烧录与运行。

1. 理解TI DSP Flash架构基础

以TMS320F28377D为例,其片上Flash通常被划分为多个扇区(Sector),每个扇区有独立的擦除和编程能力。这是实现多工程共存的基础。Flash的物理特性决定了:

  • 擦除单位:最小擦除单位是一个扇区,无法单独擦除某个地址
  • 编程单位:可以按字(Word)或页(Page)进行编程
  • 寿命限制:Flash有擦写次数限制,通常为10万次左右

典型的Flash扇区划分如下表所示:

扇区名称起始地址结束地址大小
SectorA0x800000x81FFF8KB
SectorB0x820000x83FFF8KB
SectorC0x840000x85FFF8KB
SectorD0x860000x87FFF8KB

提示:实际扇区划分请参考具体芯片的数据手册,不同型号DSP的Flash配置可能不同。

2. CCS7.3工程配置关键步骤

2.1 创建基础工程模板

首先在CCS7.3中创建两个独立工程,比如Bootloader和Application。为每个工程设置正确的设备型号和编译器版本:

# 创建新工程的典型命令(CCS CLI方式) ccs --create_project --name=Bootloader --device=TMS320F28377D --output=output_folder ccs --create_project --name=Application --device=TMS320F28377D --output=output_folder

2.2 配置工程内存映射

在工程属性中设置正确的内存映射:

  1. 右键工程 → Properties → CCS Build → Memory Model
  2. 确保选择"Large Memory Model"以适应Flash使用
  3. 设置正确的运行时支持库(RTS)位置

2.3 修改链接器命令文件(.cmd)

这是最关键的步骤。我们需要为每个工程创建独立的链接器脚本,确保它们的代码和数据段不会重叠。以下是Bootloader工程的CMD文件示例:

MEMORY { FLASH_A : origin = 0x80000, length = 0x02000 /* SectorA */ FLASH_B : origin = 0x82000, length = 0x02000 /* SectorB */ RAM : origin = 0x00000, length = 0x10000 /* 数据RAM */ } SECTIONS { .codestart : > FLASH_A .text : > FLASH_A | FLASH_B .cinit : > FLASH_B .stack : > RAM .ebss : > RAM /* 其他段... */ }

而Application工程的CMD文件则应该使用不同的Flash扇区:

MEMORY { FLASH_C : origin = 0x84000, length = 0x02000 /* SectorC */ FLASH_D : origin = 0x86000, length = 0x02000 /* SectorD */ RAM : origin = 0x00000, length = 0x10000 /* 数据RAM */ } SECTIONS { .codestart : > FLASH_C .text : > FLASH_C | FLASH_D .cinit : > FLASH_D .stack : > RAM .ebss : > RAM /* 其他段... */ }

3. 实现工程间的跳转机制

3.1 Bootloader中的跳转代码

在Bootloader工程的main函数中,需要添加跳转到Application的代码。这通常通过汇编指令实现:

void main(void) { // Bootloader初始化代码... // 跳转到Application的入口点 asm(" LB #0x84000"); // 跳转到Application的codestart地址 // 以下代码理论上不会执行 while(1); }

3.2 Application中的返回机制

同样,Application工程中也可以实现返回到Bootloader的功能:

void main(void) { // Application主循环 while(1) { if(need_reboot()) { asm(" LB #0x80000"); // 跳转回Bootloader } // 正常应用代码... } }

4. Flash烧录的高级技巧

4.1 分次烧录策略

在CCS7.3中烧录两个工程时,需要注意:

  1. 先烧录Bootloader工程,选择仅擦除SectorA和SectorB
  2. 再烧录Application工程,选择仅擦除SectorC和SectorD

这样可避免全片擦除导致已烧录的内容丢失。

4.2 使用CCS脚本自动化

可以创建烧录脚本自动化这一过程:

// Bootloader烧录脚本 var params = { program: "Bootloader.out", config: "F2837xD_FLASH.cmd", sectors: "A,B", // 仅擦除A,B扇区 verify: true }; CCS.program(params); // Application烧录脚本 var params = { program: "Application.out", config: "F2837xD_FLASH.cmd", sectors: "C,D", // 仅擦除C,D扇区 verify: true }; CCS.program(params);

4.3 调试技巧

调试多工程系统时,可能会遇到以下问题:

  • 断点异常:两个工程都在运行时,断点可能会被意外触发
  • 符号表冲突:需要正确加载对应工程的符号表
  • 复位行为:理解硬件复位后的执行流程

建议调试时:

  1. 先单独调试每个工程,确保基本功能正常
  2. 使用CCS的"Advanced Restart"功能控制PC指针
  3. 在跳转点前后添加标志变量,便于跟踪执行流程

5. 实际应用场景扩展

5.1 Bootloader设计进阶

一个完整的Bootloader通常还需要:

  • 校验机制(CRC或数字签名)
  • 安全升级流程
  • 版本回滚功能
  • 状态标志存储

可以在Flash中保留一个专用的小扇区用于存储这些元数据:

MEMORY { CONFIG : origin = 0x7F800, length = 0x00800 /* 配置扇区 */ /* 其他扇区... */ } SECTIONS { .bootconfig : > CONFIG /* 其他段... */ }

5.2 双备份系统实现

利用Flash分区技术可以实现固件的双备份:

  1. 主备两个Application分区(如SectorC-D和SectorE-F)
  2. Bootloader根据校验结果决定启动哪个副本
  3. 升级时先更新备用副本,验证成功后再切换

这种设计提高了系统可靠性,特别适合关键应用场景。

5.3 动态加载模块

更高级的应用可以实现模块的动态加载:

  1. 将功能模块编译为独立可加载单元
  2. 在Flash中预留模块存储区
  3. 运行时从Flash加载模块到RAM执行

这需要更复杂的内存管理和链接脚本配置,但能实现高度灵活的架构。

← 返回列表