1. 项目概述与背景
在工业控制和汽车电子领域,DSP28335作为TI公司经典的C2000系列数字信号处理器,因其强大的实时控制能力和丰富的外设接口被广泛应用。而CAN总线作为一种高可靠性的现场总线,特别适合工业环境下的设备间通信。将两者结合的固件升级方案,能够有效解决传统串口升级距离短、可靠性低的痛点。
这个方案的核心价值在于:
- 实现设备现场升级无需拆机,通过CAN总线完成固件传输
- 支持断点续传和校验机制,确保工业环境下升级可靠性
- 完整的工具链包括Bootloader、应用程序和上位机,形成闭环解决方案
2. 硬件架构设计要点
2.1 DSP28335与CAN接口配置
在硬件设计阶段,需要特别注意CAN控制器的电气特性。DSP28335内置的eCAN模块支持CAN2.0B协议,典型电路设计应包含:
- CAN收发器选型:推荐使用SN65HVD23x系列,其共模电压范围达±25V,适合工业环境
- 终端电阻匹配:必须在总线两端配置120Ω终端电阻
- 滤波电路设计:在CANH/CANL线上并联30pF电容可有效抑制高频干扰
重要提示:PCB布局时CAN信号线应保持差分对等长,与其他信号线间距至少3倍线宽
2.2 存储器分区规划
合理的Flash分区是Bootloader设计的基础,典型分配方案:
| 地址范围 | 大小 | 用途 |
|---|---|---|
| 0x3F8000-0x3F8FFF | 4KB | Bootloader代码区 |
| 0x3F9000-0x3FBFFF | 12KB | 升级缓冲区 |
| 0x3FC000-0x3FFFFF | 16KB | 应用程序区 |
这种分配保证了:
- Bootloader有足够空间实现完整功能
- 升级缓冲区可存储完整固件包
- 应用程序区与Bootloader物理隔离
3. Bootloader实现详解
3.1 启动流程设计
上电后Bootloader的执行逻辑:
- 初始化时钟和看门狗
- 配置GPIO和CAN外设
- 检查升级标志位
- 若需要升级则进入下载模式,否则跳转应用程序
关键代码片段:
c复制void main(void) {
InitSysCtrl(); // 系统时钟初始化
InitGpio(); // GPIO配置
InitCAN(); // CAN模块初始化
if(*(volatile Uint32 *)0x3F9000 == 0x55AA55AA) {
DownloadMode(); // 进入升级模式
} else {
JumpToApp(); // 跳转应用程序
}
}
3.2 CAN通信协议设计
自定义的升级协议帧格式:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| 帧头 | 2 | 固定为0xAA55 |
| 包序号 | 2 | 数据包顺序编号 |
| 数据长度 | 1 | 有效数据长度(0-8) |
| 数据 | 0-8 | 有效载荷 |
| CRC校验 | 1 | 从帧头到数据的累加和校验 |
数据传输采用分块机制,每包最大8字节,配合ACK/NACK确认机制保证可靠性。
4. 应用程序设计要点
4.1 与Bootloader的接口约定
应用程序需要遵守以下规范:
- 中断向量表重映射到应用程序区
- 保留0x3F9000-0x3FBFFF区域供Bootloader使用
- 实现特定的升级触发机制
跳转代码示例:
c复制#pragma CODE_SECTION(EnterBootloader, "secureRamFuncs")
void EnterBootloader(void) {
EALLOW;
*(volatile Uint32 *)0x3F9000 = 0x55AA55AA; // 设置升级标志
SysCtrlRegs.WDKEY = 0x55; // 触发看门狗复位
EDIS;
while(1);
}
4.2 双备份机制实现
为提高可靠性,建议实现A/B双备份系统:
- 将Flash分为两个独立的应用分区
- 每次升级写入非活动分区
- 升级完成后校验通过再切换分区
分区状态管理表:
| 地址 | 字段 | 说明 |
|---|---|---|
| 0x3FA000 | ActiveFlag | 当前活动分区标识 |
| 0x3FA004 | CRC32 | 固件校验值 |
| 0x3FA008 | Version | 固件版本号 |
5. 上位机开发关键点
5.1 通信协议实现
C#上位机使用PCAN-USB接口时的主要操作:
csharp复制// 初始化CAN接口
TPCANHandle channel = PCANBasic.PCAN_USBBUS1;
TPCANBaudrate baudrate = TPCANBaudrate.PCAN_BAUD_500K;
PCANBasic.Initialize(channel, baudrate);
// 发送数据帧
TPCANMsg msg = new TPCANMsg();
msg.ID = 0x100; // 目标节点ID
msg.LEN = 8; // 数据长度
msg.MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD;
Array.Copy(data, msg.DATA, 8); // 填充数据
PCANBasic.Write(channel, ref msg);
5.2 文件分块处理算法
固件文件处理流程:
- 计算文件CRC32校验值
- 按每包8字节分块
- 添加协议头尾信息
- 实现进度显示和断点续传
核心分块代码:
csharp复制int packetCount = (int)Math.Ceiling((double)fileBytes.Length / 8);
for(int i=0; i<packetCount; i++) {
int offset = i * 8;
int length = Math.Min(8, fileBytes.Length - offset);
byte[] packet = new byte[length + 5]; // 头尾+数据
// 填充协议头
packet[0] = 0xAA;
packet[1] = 0x55;
// 填充包序号
packet[2] = (byte)(i >> 8);
packet[3] = (byte)i;
// 填充数据
Array.Copy(fileBytes, offset, packet, 4, length);
// 计算CRC
packet[length+4] = CalculateCRC(packet, length+4);
SendPacket(packet); // 发送数据包
}
6. 实际部署中的经验总结
6.1 常见问题排查指南
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法进入Bootloader | 升级标志位被意外清除 | 检查看门狗复位逻辑 |
| 数据传输CRC错误 | CAN总线干扰 | 增加硬件滤波,降低波特率 |
| 跳转应用程序失败 | 中断向量表未正确重映射 | 检查应用程序链接文件配置 |
| 升级后功能异常 | Flash编程不完整 | 增加编程后的校验过程 |
6.2 性能优化建议
-
传输效率优化:
- 将波特率提升至1Mbps(需确保布线质量)
- 采用流控机制避免数据丢失
-
可靠性增强:
- 实现三重备份机制
- 增加数字签名验证
-
用户体验改进:
- 上位机增加自动重试机制
- 提供详细的错误日志记录
在实际项目中,我们发现当升级文件超过32KB时,建议将CAN波特率设置为500kbps以上,并启用分块校验机制。一个典型的优化后的传输过程如下:
- 上位机发送升级开始命令(包含文件大小和CRC)
- DSP28335准备接收缓冲区并回复确认
- 分块传输(每16个数据包后插入校验点)
- 传输完成后执行整体校验
- 校验通过后执行Flash编程
这种机制在工业现场测试中,即使存在偶尔的通信干扰,也能保证升级的成功率。我们曾在一个汽车ECU项目中实现了连续1000次升级零失败的记录。