1. 项目概述与核心价值
对于任何一位嵌入式开发者而言,微控制器上电后执行的第一行代码——启动流程,其重要性再怎么强调都不为过。它不仅是系统从“沉睡”到“苏醒”的起点,更是整个应用稳定、安全运行的基石。如果启动流程设计不当或理解不透彻,轻则导致程序无法运行,调试困难;重则可能引发安全漏洞,让未经授权的代码得以执行,这在工业控制、汽车电子等领域是绝对不可接受的。
德州仪器(TI)的C2000™系列微控制器,尤其是TMS320F28003x,因其强大的实时控制能力和丰富的外设,在电机驱动、数字电源、可再生能源等高性能控制领域占据着重要地位。其内置的Boot ROM(启动只读存储器)提供了一套复杂而精密的启动机制,远不止是“从Flash跑起来”那么简单。它像一位经验丰富的系统引导员,能够根据硬件配置、引脚状态甚至安全策略,智能地决定从哪里、以何种方式加载并执行用户的应用程序代码。
我接触过不少项目,初期都曾在启动环节“踩坑”。比如,调试时程序莫名其妙跑飞,最后发现是启动模式配置错误;又或者,产品需要现场升级固件,却因为对FWU(固件更新)启动模式理解不深,导致升级流程复杂且不可靠。更棘手的是安全需求,如何确保产线烧录的代码在终端产品上不被篡改?这就需要深入理解安全启动(Secure Flash Boot)背后的CMAC认证机制。
本文将深入剖析TMS320F28003x的Boot ROM机制,不仅解读官方手册中的关键表格和流程,更会结合我多年的实战经验,拆解从最基础的Flash/RAM启动,到用于调试的等待模式,再到关乎产品生命周期的安全启动与固件更新模式。我会重点解释每个模式背后的“为什么”,分享配置时的注意事项和避坑指南,并提供可直接参考的链接器命令文件(CMD)片段和实操思路。无论你是正在评估F28003x的新手,还是希望优化现有系统启动流程的资深工程师,这篇文章都将为你提供一份从原理到实践的详细地图。
2. Boot ROM机制深度解析
在深入具体模式之前,我们必须先建立对TMS320F28003x Boot ROM的整体认知。它不是一段简单的跳转代码,而是一个小型但功能完备的引导加载程序(Bootloader),固化在芯片内部ROM中,无法被用户修改。上电或复位后,CPU首先从这里开始执行。
2.1 启动流程总览与决策逻辑
Boot ROM的初始任务,是进行一系列的“侦探工作”,以决定最终的启动路径。这个决策过程主要依据以下几个关键因素,其逻辑顺序通常如下:
- 检查仿真器连接:Boot ROM会首先探测是否有调试器(如TI的XDS系列)通过JTAG接口连接。如果检测到仿真器,并且满足特定条件(如
BOOTPIN_CONFIG密钥匹配),设备可能会进入一种特殊的“仿真启动模式”,优先响应调试器的控制,这对于开发和调试至关重要。 - 读取启动模式引脚:这是最经典的启动方式。F28003x提供了一组专用的GPIO引脚(例如
GPIO72/GPIO84等,具体请查阅芯片数据手册),在上电复位时,这些引脚的状态会被锁存到特定的寄存器中(如BOOTDEFx)。Boot ROM读取这些寄存器的值,将其解码为对应的启动模式选项。 - 解析
BOOTDEFx寄存器:该寄存器是启动模式的“指令集”。其值不仅由硬件引脚状态决定,在某些情况下(如等待模式、安全启动)也可能由OTP(一次性可编程存储器)或Flash中的配置字决定。Boot ROM根据BOOTDEFx的值,查询内部的一个“跳转表”,决定下一步是跳转到Flash的某个地址、RAM的某个地址,还是执行某个外设(如SCI、SPI)的引导加载程序。
这个决策过程的精妙之处在于其容错和调试友好性。例如,如果Boot ROM检测到启动模式引脚配置了一个无法识别的值(即不在有效模式列表内),且此时有调试器连接,它会自动进入“等待模式”(Wait Boot),而不是盲目地跳转到一个可能无效的地址导致系统死锁。这为开发者提供了一个安全的恢复入口。
2.2 关键内存映射与保留区域
理解Boot ROM,必须清楚它占用了哪些资源,以及用户程序需要避开哪些“禁区”。官方手册中的Table 4-29. Reserved RAM Memory Map明确指出了Boot ROM需要使用的RAM区域。
Memory Description Origin Address Length (Words) RAM Boot Status, Boot Mode, 0x0000 0002 0x0126 MPOST Status, Boot Stack为什么这个区域如此重要?
- 地址
0x0000 0002开始:这个区域位于RAM的开头,Boot ROM用它来存储关键的状态信息,例如检测到的最终启动模式(Boot Mode)、上电自检状态(MPOST Status)以及一个临时使用的栈空间(Boot Stack)。 - 用户程序必须避开:在你的链接器命令文件(
.cmd)中,绝对不能将任何代码或数据分配到0x00000000至0x00000127(长度0x0126个字,每个字16位,换算成字节地址范围约为0x00000000-0x0000024E)这个区域。否则,Boot ROM运行时会破坏你的数据,或者你的程序会覆盖Boot ROM的状态变量,导致不可预知的后果。 - 实战心得:我习惯在CMD文件的
MEMORY部分明确将这个区域排除在可用RAM之外,或者用一个不被使用的伪内存段(UNUSED_RAM)覆盖它,从源头避免链接器误分配。MEMORY { ... /* 必须保留给Boot ROM使用的区域 */ BOOT_RESERVED : origin = 0x00000000, length = 0x00000250 /* 略大于0x0126字,按字节计 */ RAMLS0 : origin = 0x00000250, length = 0x0000FDB0 /* 用户可用RAM从0x250开始 */ ... }
2.3 等待模式(Wait Boot):开发者的“安全港”
等待模式(Wait Boot)是一种特殊的启动模式,Boot ROM不会跳转到任何用户应用程序,而是进入一个特定的循环等待状态。根据手册Table 4-19,CPU的程序计数器(PC)会停留在几个特定的地址范围内,例如0x3FB8B9 – 0x3FB8C0。
什么情况下会进入等待模式?手册Section 4.8.3列出了几种情况:
- 主动设置:用户通过配置启动模式引脚,明确选择进入等待模式(
BOOTDEFx = 0x04或0x24)。 - 无法识别的启动模式:当启动模式引脚被解码为一个无效值时,且有调试器连接。
- 仿真配置密钥错误:当
BOOTPIN_CONFIG密钥不等于0xA5或0x5A时。 - 仿真启动过程中发生错误。
为什么说它是“安全港”?
- 避免JTAG冲突:手册明确指出,在使用调试器时,推荐使用等待模式。这是因为如果Boot ROM直接跳转到Flash中的用户程序,而用户程序可能初始化了某些外设或改变了时钟配置,这可能会干扰调试器通过JTAG与芯片的通信,导致连接不稳定甚至断开。等待模式让CPU“暂停”在Boot ROM的已知状态,调试器可以安全地连接、初始化并接管控制权。
- 提供明确的调试入口:当你的程序在Flash中跑飞,或者因配置错误无法启动时,将板子设置为等待模式再上电,可以确保调试器每次都能稳定地连接到芯片,然后你可以手动将程序加载到RAM进行调试,或者擦除/重编程Flash。
- 操作要点:进入等待模式后,你需要通过调试器(如Code Composer Studio)手动执行一个“Go Main”或从复位向量重启的操作,才能让CPU跳��循环,开始执行你的代码。
3. 核心启动模式详解与配置
3.1 Flash启动与RAM启动:基础与调试
这是两种最直接的模式,Boot ROM简单地跳转到一个预设的存储器地址开始执行。
Flash启动:Boot ROM跳转到Flash中的指定入口地址。这是产品发布时的标准模式,代码非易失,上电即运行。入口地址由BOOTDEFx的值决定,手册Table 4-17(虽然标题是RAM,但同节有Flash入口表)和Section 4.8.2列出了多个选项,例如从Bank 0 Sector 0 (0x00080000) 或 Sector 8 (0x00088000) 开始。关键点:你需要确保你的.out文件的代码段(通常是.text)的起始地址与这里选择的入口地址严格匹配。这通常在链接器CMD文件中通过BEGIN段指定。
RAM启动:Boot ROM跳转到RAM中的指定入口地址(通常是0x00000000)。这种模式主要用于调试。因为向RAM加载程序的速度远快于烧写Flash,可以极大提高调试效率。重要警告:如前所述,0x00000000开始的区域是Boot ROM的保留区。因此,真正的“RAM启动”入口地址通常需要偏移,或者你需要先通过调试器将程序加载到RAM的其他位置(如0x00008000),然后修改PC指针跳转过去。更常见的做法是使用“Flash启动”但将代码链接到RAM中执行(即ramfuncs),但这需要Boot ROM跳转到Flash中的一个引导程序,再由该引导程序将代码从Flash拷贝到RAM执行。
配置心得:
- 在CCS工程中,
Boot Mode的选择(通过GEL文件或目标配置文件设置)必须与硬件引脚的上拉/下拉电阻配置一致。不一致是导致“程序烧进去但没反应”的常见原因。 - 对于RAM调试,我强烈推荐使用CCS的“RAM Launch”配置。它自动处理了将程序加载到RAM、设置入口点等一系列复杂步骤。
3.2 安全Flash启动:基于CMAC的代码认证
安全启动是保障嵌入式系统固件完整性和真实性的核心机制。F28003x的安全Flash启动模式在普通Flash启动的基础上,增加了一个关键的认证环节:CMAC(Cipher-based Message Authentication Code)。
核心流程:
- 选择模式:通过
BOOTDEFx配置为安全Flash启动模式。 - 计算与存储“金标”:在编译链接后,你需要对计划存放代码的Flash起始区域(例如前16KB)计算一个128位的CMAC哈希值,这就是“金标”(Golden Tag)。这个金标必须存储在Flash中一个固定的偏移地址(
Flash Entry Point Address + 0x2)。同时,用于计算CMAC的128位密钥(CMAC Key)需要预先编程到芯片的OTP(一次性可编程)存储器的特定区域(DCSM Z1 OTP CMACKEY0-3)。 - 上电认证:芯片上电进入安全启动模式后,Boot ROM会使用OTP中的密钥,对Flash中指定的16KB区域重新计算CMAC值。
- 比对与决策:将计算得到的CMAC值与Flash中存储的“金标”进行比对。如果完全一致,认证通过,Boot ROM跳转到Flash入口点执行程序。如果不一致,认证失败,根据手册
Table 4-22,设备会触发看门狗复位或进入调试停止状态。
技术细节与实操难点:
- 密钥与金标的格式:手册
Table 4-21的示例非常关键。密钥和金标在存储时,整体是“大端序”(MSB在前),但每个32位字内部是“小端序”(Little-Endian)。这是最容易出错的地方。例如,一个密钥0x00112233445566778899AABBCCDDEEFF,在OTP中应存储为:CMACKEY0 = 0x00112233CMACKEY1 = 0x44556677CMACKEY2 = 0x8899AABBCMACKEY3 = 0xCCDDEEFF而在Flash中的金标存储也遵循类似规则,但地址偏移是+0x2(两个字)。
- 链接器配置:你必须修改链接器命令文件,为金标预留空间。手册
Example 4-1给出了范例:
然后,你需要一个后处理工具(如TI提供的MEMORY { BEGIN : origin = 0x80000, length = 0x0002 /* 跳转到_c_int00的指令 */ GOLDEN_CMAC_TAG : origin = 0x80002, length = 0x0008 /* 预留8个字(128位)给金标 */ FLASH_SECTOR_0 : origin = 0x8000A, length = 0x1FF6 /* 实际应用代码从0x8000A开始 */ }secureFlashBooter工具或自定义脚本),在生成最终的二进制文件(.bin或.hex)前,计算正确的CMAC值并填充到GOLDEN_CMAC_TAG区域。 - 分区要求:用于安全启动的Flash扇区(包含入口点和前16KB代码)必须被分配到DCSM的Zone 1。这需要在代码中或通过编程工具配置DCSM相关寄存器。
- 启用JTAG锁:手册建议在使用安全启动时启用
JTAGLOCK。这是一把双刃剑:它能在一定程度上防止通过JTAG端口读取内存内容,增强安全性,但一旦锁定,调试将变得极其困难(通常需要全擦除才能解锁)。务必在产品量产前才启用此功能。
3.3 固件更新启动:多Bank版本管理
固件更新(FWU)启动模式为解决产品现场升级提供了一个优雅的解决方案。它支持在多个Flash Bank中存储不同版本的应用镜像,Boot ROM会自动选择版本号最新的一个来启动。
镜像格式:每个Bank中的镜像必须遵循一个特定的头部格式,如手册Table 4-24所示:
- 偏移
0x0:32位应用程序入口地址。 - 偏移
0xA:32位密钥(Key),有效值必须为0x5A5A5A5A。这是一个简单的有效性标识。 - 偏移
0xC:32位固件版本号。这是核心:版本号采用递减计数。0xFFFFFFFF是初始值,每次更新固件,版本号应减小(例如,V2.0版本号比V1.0小)。Boot ROM会扫描所有Bank,找出密钥有效且版本号最小(即数值上最小,代表版本最新)的镜像来启动。
工作流程:
- 假设产品出厂时,Bank 0烧录了V1.0固件(版本号=
0xFFFFFFFE)。 - 需要升级时,通过通信接口(如CAN、SCI)将V2.0固件(版本号=
0xFFFFFFFD)下载到空闲的Bank 1中。 - 系统重启。Boot ROM在FWU模式下,检查Bank 0和Bank 1。
- 两者密钥均有效(
0x5A5A5A5A)。 - 比较版本号:
0xFFFFFFFD(Bank 1) <0xFFFFFFFE(Bank 0)。 - 因此,Boot ROM选择从Bank 1启动V2.0固件。
- 两者密钥均有效(
- V2.0固件启动后,可以擦除Bank 0中的旧版本,为下一次更新做准备,实现“滚动更新”。
优势与注意事项:
- 高可靠性:即使新版本固件(Bank 1)有问题,重启后Boot ROM会发现其启动失败(或密钥无效),并自动回退到旧版本(Bank 0)启动,实现“双备份”保护。
- 设计考量:你需要合理规划Flash Bank的用途。通常,需要至少两个完整的Bank来存放应用程序。这意味着你的应用程序代码大小不能超过单个Bank的容量。
- 版本号管理:版本号的生成和管理必须非常严谨,通常由构建服务器自动分配递减的版本号,并嵌入到镜像头中。手动操作极易出错。
- 入口地址多样性:手册
Table 4-25显示,FWU模式支持多个入口地址选项(如0x00080000,0x00088000等),这为链接代码提供了灵活性。
4. 外设引导加载程序实战指南
除了直接从内部存储器启动,F28003x的Boot ROM还集成了通过外部接口加载程序的能力,这对于工厂量产烧录、系统自举升级至关重要。这些引导加载程序(Bootloader)遵循一个通用的数据流协议��
4.1 通用数据流协议解析
所有外设引导加载程序(SCI, SPI, I2C, Parallel, CAN)都期望主机(Host)发送一个特定格式的8位数据流。理解这个协议是编写上位机加载程序的关键。其通用结构如下表所示:
| 字节序号 | 内容 (LSB在前) | 描述 |
|---|---|---|
| 1, 2 | 0xAA, 0x08 | 密钥值:固定为0x08AA,用于同步和验证数据流。 |
| 3, 4 | LOSPCP | 低速外设时钟预分频器:用于配置SPI等外设时钟(SPI模式特有)。 |
| 5, 6 | SPIBRR | SPI波特率寄存器:用于配置SPI通信速率(SPI模式特有)。 |
| ... | ... | 保留字:通常为0x0000,为未来功能预留,共8个保留字(16字节)。 |
| 19,20,21,22 | PC[31:0] | 32位入口点地址:程序加载完成后,CPU跳转执行的地址。 |
| 23,24 | Block Size | 第一个数据块的大小(以字为单位)。 |
| 25,26,27,28 | Dest Addr[31:0] | 第一个数据块的目的地址。 |
| 29,30... | Data Word 1... | 第一个数据块的实际数据。 |
| ... | ... | 重复块大小、目的地址、数据的格式,用于后续数据块。 |
| n, n+1 | 0x00, 0x00 | 结束标志:块大小为0x0000,表示数据流结束。 |
协议核心思想:这是一个非常灵活的“块搬运”协议。主机告诉引导程序:“接下来有N个字的数据,请放到内存地址A处。” 放完后,再告诉它下一块的数据。所有数据块传输完毕后,发送一个零长度的块作为结束信号,随后Boot ROM便会跳转到之前指定的入口点地址开始执行刚加载的程序。
4.2 各外设引导模式特点与选型
SCI(串口)引导:
- 特点:最常用、最简单的引导方式。利用SCI-A的自动波特率检测功能,无需主机与设备预先约定波特率,兼容性极好。
- 实战技巧:手册提到,在高波特率(>100kbps)下,信号边沿可能影响自动波特率检测。可靠的做法是:先用一个较低的、稳定的波特率(如9600)建立连接并完成引导程序加载。待用户程序运行后,再由用户程序与主机协商切换到更高的通信波特率。
- 数据流:遵循通用协议,无特殊保留字配置。
SPI引导:
- 特点:从外接SPI EEPROM或Flash芯片启动。常用于需要脱机存储启动代码的场景。
- 连接:主机需模拟一个SPI从设备,或者直接使用SPI存储器。数据必须从存储器的
0x0000地址开始存放。 - 关键步骤:SPI引导程序在读取密钥
0x08AA后,会接着读取LOSPCP和SPIBRR字节,允许主机在加载过程中动态调整SPI通信速率。这对于先低速建立连接,后高速传输大数据量很有用。 - 流程图解读:手册中的
Figure 4-7清晰地展示了从EEPROM读取数据的“突发模式”流程:初始化SPI -> 拉低片选 -> 发送读命令和地址0x0000-> 连续读取数据流。
I2C引导:
- 特点:从外接I2C EEPROM启动,器件地址固定为
0x50。 - 协议细节:I2C引导需要严格的协议时序,如
Figure 4-10和Figure 4-11所示的“随机读”和“顺序读”。主机(或EEPROM)必须遵循此时序。 - 速率配置:数据流中的第3-8字节用于配置I2C时钟预分频器(
I2CPSC)和高/低电平计数寄存器(I2CCLKH/L),允许在引导过程中切换标准模式(100kHz)和快速模式(400kHz)。
Parallel GPIO引导:
- 特点:通过一组GPIO引脚并行传输数据,速度最快,但占用引脚多。通常用于有专用编程接口的工装。
- 握手协议:这是最复杂的部分,见
Figure 4-13。它使用两根控制线(Host Control和C28x Control)进行严格的“四步握手”来传输每个字节,从而完美适配不同速度的主机和从机,无需担心时序同步问题。 - 数据组织:虽然是8位数据流,但每次读取两个字节组成一个16位字。主机需要按照
Table 4-35的格式组织数据,特别注意地址和数据的字节序(LSB先发送)。
CAN / CAN-FD引导:
- 特点:适用于汽车或工业网络环境,可通过总线进行程序更新。
- 配置:使用CAN-A邮箱1,标准ID为
0x1。默认配置为100kbps(CAN)或1Mbps/2Mbps(CAN-FD)。 - CAN-FD增强:CAN-FD模式的数据流(
Table 4-38)前几个字节可用于配置自定义的位时序寄存器(NBTR,DBTR),提供了更灵活的通信速率配置能力。
选型建议:
- 产品量产烧录:优先考虑Parallel GPIO(速度快)或SCI(接口简单)。
- 现场网络升级:CAN或CAN-FD是不二之选。
- 小批量或需要存储启动镜像:SPI或I2C引导配合外部存储器很方便。
- 开发和调试:SCI引导最为常用,因为几乎所有电脑都有串口。
5. 工程实践:从配置到问题排查
5.1 链接器命令文件配置精要
链接器命令文件是连接硬件启动地址与软件编译输出的桥梁。配置错误是导致启动失败的最常见原因之一。以下是一个综合了安全启动和常规启动考虑的CMD文件核心片段:
MEMORY { /* 1. Boot ROM保留区 - 绝对禁止使用 */ BOOT_RESERVED : origin = 0x00000000, length = 0x00000250 /* 2. 安全启动相关段 */ BEGIN : origin = 0x00080000, length = 0x00000002 /* 跳转指令 */ GOLDEN_CMAC_TAG : origin = 0x00080002, length = 0x00000008 /* 128位CMAC金标 */ APP_FLASH : origin = 0x0008000A, length = 0x0007FFF6 /* 应用程序Flash区 */ /* 3. 应用程序RAM区 */ RAMLS0 : origin = 0x00000250, length = 0x0000FDB0 RAMLS1 : origin = 0x00010000, length = 0x00008000 /* ... 其他RAM区域 */ } SECTIONS { /* 安全启动的BEGIN段,包含跳转到_c_int00的指令 */ .begin : > BEGIN, PAGE = 0 /* 安全启动的金标段,由后处理工具填充 */ .goldenCmacTag : > GOLDEN_CMAC_TAG, PAGE = 0 /* 应用程序代码段 */ .text : > APP_FLASH, PAGE = 0 .cinit : > APP_FLASH, PAGE = 0 .switch : > APP_FLASH, PAGE = 0 /* 需要加载到RAM中运行的函数(如中断服务程序)*/ .ramfuncs : LOAD = APP_FLASH, RUN = RAMLS0, PAGE = 0 LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart) /* 全局和静态变量 */ .bss : > RAMLS0, PAGE = 1 .data : > RAMLS0, PAGE = 1 .stack : > RAMLS1, PAGE = 1 /* ... 其他段 */ }关键点说明:
.begin段:通常由运行时支持库(RTS)提供,里面就是一条跳转到_c_int00(C环境初始化函数)的指令。它的起源地址必须与你在Boot模式中配置的Flash入口地址完全一致。.goldenCmacTag段:仅在启用安全启动时需要。它是一个填充段,链接时不包含有效数据,需要在生成最终二进制文件前,通过工具计算并填入CMAC值。LOAD与RUN地址:对于性能要求高的函数(如中断服务例程),可以将其链接到Flash(LOAD地址),但在运行时拷贝到RAM(RUN地址)中执行,以加速运行。这需要你在C代码中使用#pragma CODE_SECTION或在CMD文件中指定,并在系统初始化时手动完成拷贝(或由MemCopy函数完成)。
5.2 常见启动问题排查实录
即使理解了所有原理,在实际操作中依然会遇到各种问题。下面是我总结的一些典型故障场景和排查思路:
问题1:程序编译烧录后,上电无任何反应,调试器也无法连接。
- 可能原因1:启动模式引脚配置错误。这是头号杀手。用万用表测量
GPIO72/84等启动引脚在上电瞬间的电平,确认其与你在CCS中或硬件设���中选择的模式匹配(例如,内部上拉为1,下拉为0)。 - 可能原因2:时钟配置错误导致Boot ROM运行异常。检查你的晶体振荡器电路是否正常,PLL配置是否超出了芯片允许的范围。Boot ROM在初始化阶段会配置一个基本的系统时钟,但如果外部时钟源失效,它可能无法正确运行。
- 可能原因3:电源或复位电路不稳定。用示波器观察芯片的电源引脚和复位引脚,确保上电时序正确,无毛刺,电压稳定。
- 排查步骤:
- 断开所有可能影响启动引脚的电路,仅保留上拉/下拉电阻。
- 尝试配置为最简化的等待模式。如果此时调试器可以稳定连接,说明Boot ROM基本运行正常,问题可能出在跳转后的用户代码或地址映射上。
- 如果等待模式也不行,重点检查电源、复位和时钟。
问题2:调试器可以连接,但一运行程序就跑飞或硬件错误。
- 可能原因1:链接器CMD文件配置错误,代码/数据段覆盖了Boot ROM保留区或非法区域。仔细检查
.map文件,确认所有段的起始地址和长度没有与0x00000000~0x00000250区域重叠。 - 可能原因2:中断向量表(PIE VECTTABLE)地址设置错误。在F28003x中,中断向量表需要被重映射到RAM中。确保在系统初始化代码中正确设置了
PIE控制寄存器和向量表地址。 - 可能原因3:C环境初始化失败。检查
.cinit段是否被正确加载和解析。可以单步调试_c_int00函数,看在哪里出错。 - 排查步骤:
- 在CCS中查看反汇编,确认程序计数器(PC)是否跳转到了预期的入口地址(如
0x80000)。 - 单步执行最初的几条汇编指令,看是否在访问非法内存地址。
- 检查栈指针(SP)是否指向了一个有效的RAM区域。
- 在CCS中查看反汇编,确认程序计数器(PC)是否跳转到了预期的入口地址(如
问题3:安全启动模式启用后,认证一直失败。
- 可能原因1:CMAC金标计算或填充错误。这是最常见的原因。确认:
- 用于计算CMAC的Flash区域范围是否正确(从入口点开始,连续16KB)。
- 计算金标时使用的密钥是否与编程到OTP中的密钥完全一致(注意字节序!)。
- 金标是否填充到了Flash中正确的偏移地址(入口点+2)。
- 填充的金标格式是否符合“整体大端,字内小端”的规则。
- 可能原因2:Flash分区(DCSM Zone)配置错误。确保包含入口点和前16KB代码的Flash扇区被分配给了Zone 1,并且Zone 1的配置是有效的。
- 可能原因3:OTP密钥编程错误或物理损坏。OTP是一次性的,一旦编程错误无法修改。使用TI的编程工具(如Uniflash)仔细核对密钥值,并在编程前进行验证读回。
- 排查步骤:
- 暂时关闭安全启动,改用普通Flash启动,确认基础功能正常。
- 使用TI提供的安全启动工具链,严格按照流程生成和烧录镜像。手动操作极易出错。
- 在安全启动失败后,通过调试器(如果JTAG未锁)读取OTP密钥区和Flash中的金标区,与原始数据进行逐字节比对。
问题4:使用SCI引导加载时,主机发送数据后设备无回应。
- 可能原因1:波特率不匹配或自动波特率失败。尽管SCI引导支持自动波特率,但在高波特率或信号质量差时容易失败。尝试将主机波特率降至9600或19200。
- 可能原因2:数据流格式错误。严格检查发送的数据流:第一个字必须是
0x08AA,后续的保留字、入口地址、块大小等都必须符合协议,并且每个字节发送后,必须等待设备回显该字节,这是SCI引导的握手机制。 - 可能原因3:硬件连接问题。检查TX/RX线是否接反,电平是否匹配(通常是3.3V TTL),地线是否连接良好。
- 排查步骤:
- 使用示波器或逻辑分析仪,抓取SCI-A引脚(
GPIO84/85)的波形,确认主机数据已发出,且波形清晰。 - 在主机端,实现严格的超时和重试机制。如果发送一个字节后未收到回显,应重发或重置整个引导流程。
- 参考TI官方示例代码(通常在
C2000Ware的boot_rom示例中)来编写上位机程序,确保协议实现的正确性。
- 使用示波器或逻辑分析仪,抓取SCI-A引脚(
启动问题的排查往往需要耐心和系统性思维。从最底层的电源、时钟、引脚,到中间的Boot ROM配置,再到上层的软件链接和代码逻辑,逐层剥离,利用调试器、示波器和万用表等工具,总能定位到问题的根源。记住,等待模式是你的好朋友,它总能给你一个稳定的起点。