目录

Motor_Bootloader

基于 STM32G474 的独立 Bootloader 工程,通过 CAN 总线 (FDCAN1) 实现固件远程 OTA 升级。上电先于 APP 运行,负责校验 APP 完整性并跳转,或进入 CAN 升级模式接收新固件。


架构概览

采用 独立 Bootloader + APP 双区 架构:

上电 → Bootloader (0x08000000)
         │
         ├─ APP 有效 → 跳转 APP (0x08004000)
         │
         └─ 需升级 / APP 无效 → CAN 升级循环
                                  │
                                  └─ 升级完成 → 写控制块 → 跳转 APP
  • Bootloader:位于 Flash 起始 16 KB,负责跳转决策与升级。
  • APP(Motor_Driver):重定位到 0x08004000,向量表偏移 VECT_TAB_OFFSET = 0x4000。
  • 升级触发:APP 侧 ota_trigger.c 收到 ENTER_BL 命令 → 写控制块 update_requested → 复位交给 Bootloader。

Flash 布局

STM32G474RBTx:128 KB Flash,每页 2 KB,共 64 页。

0x08000000 ─ 0x08003FFF  (16 KB,  Page  0–7)   Bootloader (独立工程, 上电先运行)
0x08004000 ─ 0x0801EFFF  (108 KB, Page  8–61)  APP (应用固件, 向量表重定位)
0x0801F000 ─ 0x0801F7FF  (2 KB,   Page 62)     Bootloader 控制块
0x0801F800 ─ 0x0801FFFF  (2 KB,   Page 63)     参数存储区 (MotorParams_t, 升级不变)

Bootloader 控制块 (Page 62)

升级完成后由 Bootloader 写入校验信息,APP 侧 ota_trigger 写入升级请求。断电/复位后据此决策。

typedef struct {
    uint32_t magic;              // 有效标志 0x424C4442 ("BLDB")
    uint32_t update_requested;   // 1 = APP 请求进入升级模式
    uint32_t app_valid;          // 1 = APP 已通过完整性校验
    uint32_t app_size;           // APP 固件大小 [字节]
    uint32_t app_crc;            // APP 区 CRC32 (IEEE 802.3)
    uint32_t app_version;        // APP 版本号 (上位机下发)
    uint32_t node_id;            // CAN node_id (接收过滤)
    uint32_t master_id;          // CAN master_id (应答目标)
} BootloaderControlBlock_t;      // 共 32 字节

上电决策流程 (Bootloader_Start)

  1. 读取控制块,解析 node_id / master_id(控制块无效时用默认值 0x01 / 0x10)。
  2. 决定是否进入升级模式:
    • 控制块有效且 update_requested == 1 → 升级(APP 主动请求)
    • app_valid != 1 → 升级(APP 未通过校验)
    • APP 区 CRC 与控制块记录不符 → 通过向量表有效性区分:
      • 向量表有效 → 视为 ST-Link 外部烧录,直接跳转 APP
      • 向量表无效 → APP 已损坏,进入升级模式
    • 无控制块 → APP 区全空则升级,否则直接跳转(ST-Link 首次烧录场景)
  3. 无需升级则直接跳转 APP;否则初始化 CAN 进入升级循环。

CAN 升级协议

与上位机 Motor_Studio(yiyou_bootloader.py)配套。

参数

参数 默认值 说明
node_id 0x01 接收过滤 ID(控制块无效时)
master_id 0x10 应答目标 ID
广播 ID 0x00 升级循环中忽略广播,避免多节点误触发
解锁密钥 0x59495559 (“YIUY”) 进入升级前校验
单帧数据量 7 字节 顺序寻址,无地址字段,尾帧可短

命令字

命令 值 说明
ENTER 0x06 进入 Bootloader(需解锁密钥,ACK 返回版本号)
ERASE 0x07 擦除 APP 区 (Page 8–61)
DATA 0x08 顺序写入数据(每帧 ≤ 7 字节,ACK 返回已写入偏移)
CRC 0x09 计算已写入 APP 区 CRC32,ACK 返回 CRC
RESET 0x0A 收尾:校验 size → 写控制块 → 跳转 APP
STATUS 0x0B 查询当前写入偏移(DATA 帧 ACK 丢失后的恢复用)

应答 (ACK) 帧格式

[CMD][STATUS][VALUE_B3][VALUE_B2][VALUE_B1][VALUE_B0][00][00]
状态码 值 含义
BL_OK 0x01 操作成功
BL_ERR_BUSY 0x02 设备忙
BL_ERR_ADDR 0x03 地址错误 (越界 / 未对齐)
BL_ERR_DATA 0x04 数据错误 (长度 / 校验)
BL_ERR_FLASH 0x05 Flash 操作失败
BL_ERR_CRC 0x06 CRC 校验不匹配
BL_ERR_STATE 0x07 状态错误
BL_ERR_LOCKED 0x08 解锁密钥错误

Flash 细分错误通过 value = (err << 16) | (detail & 0xFFFF) 上报,detail 通常为 FLASH->SR 寄存器原始值。

升级流程

1. ENTER  (密钥 "YIUY")        → 解锁, ACK 返回 BL_VERSION
2. ERASE                        → 擦除 APP 区
3. DATA  × N (顺序寻址)         → 逐帧写入, ACK 返回已写入偏移
4. CRC                          → 校验已写入固件 CRC32
5. RESET (size + version)       → 写控制块 (app_valid=1, app_crc) → 跳转 APP

写入采用 STM32G4 双字编程(8 字节对齐),尾块不足 8 字节时在 CRC/RESET 阶段由 bl_write_flush() 补齐。


项目结构

Motor_Bootloader/
├── Core/                          # CubeMX 生成 (HAL 初始化)
│   ├── Inc/                       # main.h, fdcan.h, stm32g4xx_it.h ...
│   └── Src/                       # main.c, fdcan.c, gpio.c, system_stm32g4xx.c ...
├── Drivers/
│   ├── Bootloader/                # Bootloader 核心逻辑
│   │   ├── bootloader.c/h         # 主流程 / 决策 / 升级循环 / 命令分发
│   │   ├── bootloader_can.c/h     # FDCAN1 轮询收发 (无 RTOS / 无中断)
│   │   └── bootloader_flash.c/h   # Flash 擦除/双字编程/CRC32/控制块读写
│   ├── CMSIS/                     # CMSIS 内核
│   └── STM32G4xx_HAL_Driver/      # HAL 库
└── MDK-ARM/                       # Keil uVision 工程
    ├── Motor_Bootloader.uvprojx   # Bootloader 工程 (0x08000000)
    └── stm32g474xx_flash.sct      # 链接脚本 (Flash 起始)

构建与烧录

  • IDE: Keil MDK-ARM v5 (uVision)
  • 工程文件: MDK-ARM/Motor_Bootloader.uvprojx
  • 目标地址: 0x08000000(Flash 起始)
  1. 在 Keil 打开 MDK-ARM/Motor_Bootloader.uvprojx
  2. Build → Rebuild (F7),确保 0 error 0 warning
  3. Flash → Download (F8) 通过 ST-Link 烧录

完整升级链路需配合 APP(Motor_Driver,烧录到 0x08004000)与上位机(Motor_Studio)。首次烧录顺序:先 Bootloader,再 APP。


子模块说明

本仓库是总工程 Motor_Project 的一个 git submodule(目录 Motor_Bootloader/)。总工程只记录指向本仓库某个 commit 的指针,修改后需分两步提交,否则总工程不会指向新版本:

# 第一步:本仓库内提交并推送
git checkout master            # 避免在 detached HEAD 上提交
git add .
git commit -m "feat: xxx"
git push origin master

# 第二步:回总工程更新指针并提交
cd ..
git add Motor_Bootloader       # 更新总工程记录的子模块 commit
git commit -m "chore: 更新 Motor_Bootloader 子模块"
git push origin master

⚠️ 只提交本仓库而不更新总工程指针,他人克隆总工程得到的仍是旧版本代码。

关于
11.1 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号