docs: 添加子模块说明并移除许可
基于 STM32G474 的独立 Bootloader 工程,通过 CAN 总线 (FDCAN1) 实现固件远程 OTA 升级。上电先于 APP 运行,负责校验 APP 完整性并跳转,或进入 CAN 升级模式接收新固件。
采用 独立 Bootloader + APP 双区 架构:
上电 → Bootloader (0x08000000) │ ├─ APP 有效 → 跳转 APP (0x08004000) │ └─ 需升级 / APP 无效 → CAN 升级循环 │ └─ 升级完成 → 写控制块 → 跳转 APP
0x08004000
VECT_TAB_OFFSET = 0x4000
ota_trigger.c
ENTER_BL
update_requested
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 写入校验信息,APP 侧 ota_trigger 写入升级请求。断电/复位后据此决策。
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
node_id
master_id
0x01
0x10
update_requested == 1
app_valid != 1
与上位机 Motor_Studio(yiyou_bootloader.py)配套。
yiyou_bootloader.py
0x00
0x59495559
0x06
0x07
0x08
0x09
0x0A
0x0B
[CMD][STATUS][VALUE_B3][VALUE_B2][VALUE_B1][VALUE_B0][00][00]
0x02
0x03
0x04
0x05
Flash 细分错误通过 value = (err << 16) | (detail & 0xFFFF) 上报,detail 通常为 FLASH->SR 寄存器原始值。
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() 补齐。
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 起始)
MDK-ARM/Motor_Bootloader.uvprojx
0x08000000
完整升级链路需配合 APP(Motor_Driver,烧录到 0x08004000)与上位机(Motor_Studio)。首次烧录顺序:先 Bootloader,再 APP。
本仓库是总工程 Motor_Project 的一个 git submodule(目录 Motor_Bootloader/)。总工程只记录指向本仓库某个 commit 的指针,修改后需分两步提交,否则总工程不会指向新版本:
Motor_Bootloader/
# 第一步:本仓库内提交并推送 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
⚠️ 只提交本仓库而不更新总工程指针,他人克隆总工程得到的仍是旧版本代码。
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
Motor_Bootloader
基于 STM32G474 的独立 Bootloader 工程,通过 CAN 总线 (FDCAN1) 实现固件远程 OTA 升级。上电先于 APP 运行,负责校验 APP 完整性并跳转,或进入 CAN 升级模式接收新固件。
架构概览
采用 独立 Bootloader + APP 双区 架构:
0x08004000,向量表偏移VECT_TAB_OFFSET = 0x4000。ota_trigger.c收到ENTER_BL命令 → 写控制块update_requested→ 复位交给 Bootloader。Flash 布局
STM32G474RBTx:128 KB Flash,每页 2 KB,共 64 页。
Bootloader 控制块 (Page 62)
升级完成后由 Bootloader 写入校验信息,APP 侧
ota_trigger写入升级请求。断电/复位后据此决策。上电决策流程 (
Bootloader_Start)node_id/master_id(控制块无效时用默认值0x01/0x10)。update_requested == 1→ 升级(APP 主动请求)app_valid != 1→ 升级(APP 未通过校验)CAN 升级协议
与上位机 Motor_Studio(
yiyou_bootloader.py)配套。参数
0x010x100x000x59495559(“YIUY”)命令字
0x060x070x080x090x0A0x0B应答 (ACK) 帧格式
0x010x020x030x040x050x060x070x08升级流程
写入采用 STM32G4 双字编程(8 字节对齐),尾块不足 8 字节时在 CRC/RESET 阶段由
bl_write_flush()补齐。项目结构
构建与烧录
MDK-ARM/Motor_Bootloader.uvprojx0x08000000(Flash 起始)MDK-ARM/Motor_Bootloader.uvprojx子模块说明
本仓库是总工程 Motor_Project 的一个 git submodule(目录
Motor_Bootloader/)。总工程只记录指向本仓库某个 commit 的指针,修改后需分两步提交,否则总工程不会指向新版本: