STM32F4的CAN升级方案 bootloader源代码,对应测试用app源代码,都是keil工程,代码有备注,也有使用说明。 带对应上位机可执行文件。 上位机vs2013开发(默认exe,源代码需要额外拿)
STM32F4 系列 MCU 的在线升级(In-Application Programming,简称 IAP)方案,本质上是在产品的整个生命周期内,通过现场总线(本文为 CAN)把新的固件安全、可靠地写入内部 Flash,并在下次上电或复位后自动运行。
附件源码是一套基于STM32F407 + Keil5 + ZLG-USBCAN-II的“CAN-Bootloader + PC 升级工具”完整参考实现。
本文将从方案架构、Bootloader 启动流程、协议设计、Flash 自举映射、上位机交互、常见坑点与调试技巧六个维度,深度拆解这套代码,帮助读者快速吃透并迁移到实际项目。
------------------------------------------------
一、方案全景图
------------------------------------------------
- 物理链路
PC ↔(USB-CAN 适配器) ↔ CAN 总线 ↔ MCU(STM32F407,CAN1,引脚 PA11/PA12,经典 500 kbps)。
- 软件角色
• PC 端:C# 上位机(Release/can在线升级上位机.exe)
• 适配器驱动:ControlCAN.dll(ZLG 原厂,向下兼容国产克隆狗)
• MCU 端:
‑ Bootloader(0x0800 0000 ~ 0x0800 7FFF,32 KB)
‑ Application(0x0800 8000 起,最大到 1 MB 末尾)
- 升级触发条件
• 上电或 RESET 后,Bootloader 首先运行,检查“APP 有效标志”——位于 0x0800 7800 的 uint32_t 变量:
‑ 值 == 0x7856 4312 → 跳转到 APP
‑ 值 != 0x7856 4312 → 停在 Bootloader,等待 PC 下发升级流
------------------------------------------------
二、Bootloader 启动流程(代码级)
------------------------------------------------
以下流程全部在 bootloader\Src\main.c 中实现,为了便于阅读,笔者把关键片段抽出来并加中文注释。
- 关中断 + 设置时钟
HAL_Init(); SystemClock_Config(); // 沿用 ST 库默认 168 MHz- 初始化 CAN 驱动
MX_CAN1_Init(); // 500 kbps,经典采样点 87.5 % HAL_CAN_Start(&hcan1); __HAL_CAN_ENABLE_IT(&hcan1, CAN_IT_FMP0); // 打开 FIFO0 消息 pending 中断- 读取“APP 有效标志”
#define APP_EXE_FLAG_ADDR ((uint32_t *)0x08007800) if ((*APP_EXE_FLAG_ADDR) == 0x78564312) { JumpToApp(); // 见下一节 }- 若标志无效 → 进入升级循环
while (1) { if (rxMsg.Flag == NEW) // CAN 中断里收到完整帧 ParseAndProgram(); // 协议解析 + Flash 烧写 }------------------------------------------------
三、从 Bootloader 到 APP 的“跳转”细节
------------------------------------------------
ARM Cortex-M4 的跳转不能简单((void (*)(void))addr)(),必须恢复中断向量表、MSP、主栈指针,否则 APP 一跑就 HardFault。
typedef void (*pFunction)(void); static void JumpToApp(void) { uint32_t JumpAddr = *(__IO uint32_t *)(APP_START_ADDR + 4); // 复位向量 pFunction JumpToApplication = (pFunction)JumpAddr; /* 1. 关全局中断 */ __disable_irq(); /* 2. 复位所有外设,避免 Bootloader 残留 */ HAL_RCC_DeInit(); HAL_DeInit(); /* 3. 把向量表重定位到 APP 区 */ SCB->VTOR = APP_START_ADDR; /* 4. 设置主栈指针 */ __set_MSP(*(__IO uint32_t *)APP_START_ADDR); /* 5. 跳转 */ JumpToApplication(); }------------------------------------------------
四、CAN 升级协议(极简但够用)
------------------------------------------------
作者采用“扩展帧 ID = 0x1FFFFFFF 的高 11bit 作为命令,低 18bit 作为地址/序号”的极简思路,省掉复杂握手,实测单帧 8 字节 payload 在 500 kbps 下稳定 2 kB/s。
| 命令宏 | 扩展帧 ID 高 11bit | 数据区格式 | 说明 |
|---|---|---|---|
| CMDWRITEREQ | 0x100 | 8 字节 payload | 携带 4 字节目标地址 + 4 字节数据 |
| CMDWRITEACK | 0x101 | 同上 | Bootloader 烧完返回,上位机收到才发下一包 |
| CMD_JUMP2APP | 0x102 | 任意 | 写标志 0x78564312 后软复位 |
| CMD_ERASE | 0x103 | 4 字节扇区号 | 一次擦 16 KB(STM32F4 页大小) |
所有命令均一问一答,超时 300 ms 重发 3 次;若仍无应答则终止升级。
------------------------------------------------
五、Flash 自举映射与擦写策略
------------------------------------------------
STM32F407 内部 Flash 共 1 MB,分为 12 个 16 KB 的 Sector + 4 个 64 KB + 1 个 128 KB。
Bootloader 代码本身占用 Sector 0(0x0800 0000 ~ 0x0800 3FFF)和 Sector 1 前 8 KB,因此:
•0x0800 0000 ~ 0x0800 7FFF:Bootloader 私有,永不擦除
STM32F4的CAN升级方案 bootloader源代码,对应测试用app源代码,都是keil工程,代码有备注,也有使用说明。 带对应上位机可执行文件。 上位机vs2013开发(默认exe,源代码需要额外拿)
•0x0800 8000 起:APP 区,升级时按 16 KB 粒度擦除
擦除函数直接调用 HAL 库HALFLASHUnlock() / HALFLASHExErase(),注意:
- 解锁后必须关中断,防止擦除期间 CAN 中断触发导致 HardFault。
- 写 Flash 时,MCU 工作频率需 ≤ 24 MHz,因此代码里会临时把 HCLK 降到 24 M,写完再恢复 168 M。
------------------------------------------------
六、PC 端上位机实现要点
------------------------------------------------
- 采用 VS2013 + .NET 4.5,调用周立功
ControlCAN.dll的 VCI 接口:VCIOpenDevice / VCIStartCAN / VCITransmit / VCIReceive
- 升级文件格式
仅支持纯二进制(.bin),上位机自动计算 CRC16,最后一包下发 CRC 供 Bootloader 校验。
- 流程 UI
① 选择 bin → ② 扫描 USB-CAN 狗 → ③ 点击“连接” → ④ “开始升级” → ⑤ 实时进度条 + 速率显示 → ⑥ 自动跳转运行。
------------------------------------------------
七、APP 工程需要做的 3 件事
------------------------------------------------
- 链接脚本把中断向量表搬到 0x0800 8000
在stm32f407xg.ld中修改:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 1024K - 32K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
}
- 生成 bin
Keil → Options → User → After Build 添加:fromelf --bin --output=@L.bin !L
- 上电检查升级请求(可选)
如果希望 APP 运行时也能“软复位回 Bootloader”,可在串口/按键/CAN 收到特定命令后:
*APPEXEFLAGADDR = 0xFFFFFFFF;
NVICSystemReset();
------------------------------------------------
八、常见坑点与调试技巧
------------------------------------------------
- CAN 总线终端电阻
单节点调试时,一定在 CANH-CANL 并 120 Ω,否则一帧都收不到。
- 时钟回退忘了恢复
擦除 Flash 后若忘记SystemClock_Config()恢复 168 M,会导致 CAN 波特率跑偏,通信全丢。
- 中断向量表没重定位
APP 里如果直接用 0x0800 0000 的向量表,SVC/HardFault 一进就飞。
- 写 Flash 时踩了自身的 .text
Bootloader 代码如果超过 32 KB,擦除 Sector 1 会把自己“抹脖子”,务必保证擦除范围不包含自身。
- 国产 CAN 狗兼容性
部分克隆狗只支持标准帧,需要把上位机帧类型改成CANIDSTD,或替换官方 ControlCAN.dll。
------------------------------------------------
九、性能数据与扩展思路
------------------------------------------------
• 实测 256 KB APP,波特率 500 kbps,整包升级约 2 min,丢包率 0 %(办公室环境,1 m 双绞线)。
• 若升级到 1 Mbps,可把包间隔压缩到 5 ms,理论速度 4 kB/s,整包 < 70 s。
• 协议里再加 8 字节 CRC32 可容忍 3 % 丢帧,适合长距离现场。
• 若希望“差分升级”,可把协议换成 Ymodem/Xmodem,或移植开源tiny-dfu,Bootloader 端代码改动 < 300 行。
------------------------------------------------
十、一句话总结
------------------------------------------------
这套 STM32F4-CAN-IAP 方案代码量精简、协议直白、工具链成熟,“能直接用在量产”——
只要牢记:
“标志位 + 向量表 + 时钟回退 + 擦除范围”四大铁律,
就能在 1 天内把在线升级功能无缝嫁接到任何 STM32F4 项目。