# 九号控制器OTA工程 **Repository Path**: paceycn/controller-no.-9--ota-project ## Basic Information - **Project Name**: 九号控制器OTA工程 - **Description**: 九号控制器的OTA工程,详情可见 https://www.bilibili.com/video/BV1BLKD6dEW3/ - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 5 - **Created**: 2026-07-04 - **Last Updated**: 2026-07-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # CAN Bootloader OTA 固件升级系统 > **⚠️ 声明:本 README 由 AI(GitHub Copilot, DeepSeek V4 Pro)自动生成,仅供参考。** --- ## 🎬 演示视频 【九号控制器-二次开发之OTA(看简介)】 https://www.bilibili.com/video/BV1BLKD6dEW3/?share_source=copy_web&vd_source=ac307c82f7616dd4fbbfdda9db97ba8f --- ## ☕ 打赏支持 如果这个项目对你有帮助,欢迎请作者喝杯咖啡~
![微信收款码](微信收款码.jpg)
--- ## 项目概述 本项目是一个基于 **CAN 总线** 的 MCU 固件在线升级(OTA / IAP)系统,适用于 **AT32F415** 系列微控制器。系统由三部分组成: | 部分 | 路径 | 说明 | |------|------|------| | **Bootloader(下位机)** | `bootloader/` | 运行在 MCU 上的引导程序,负责固件接收、Flash 烧写与校验 | | **APP(下位机)** | `app/` | 运行在 MCU 上的应用程序,可响应 CAN 命令跳回 Bootloader | | **上位机(PC 工具)** | `上位机/` | Python GUI 工具,通过 CANable 适配器发送固件到 MCU | --- ## 硬件环境 | 项目 | 规格 | |------|------| | **MCU** | AT32F415(ARM Cortex-M4, 256KB Flash, 32KB SRAM) | | **CAN 适配器** | CANable 2.0(SLCAN 固件) | | **CAN 波特率** | 1 Mbps | | **系统时钟** | HEXT 外部晶振,PCLK = 70 MHz | --- ## 内存布局 ``` Flash (256KB) ┌──────────────────────┐ 0x08000000 │ Bootloader │ ~16 KB ├──────────────────────┤ 0x08004000 │ APP 固件 │ 最大 ~240 KB │ │ └──────────────────────┘ 0x08040000 SRAM (32KB) ┌──────────────────────┐ 0x20000000 │ 栈 / 堆 / 数据 │ │ ... │ ├──────────────────────┤ 0x20007FF0 │ Magic Word (4B) │ ← Bootloader 跳转标记 └──────────────────────┘ 0x20008000 ``` - **Bootloader** 占用 Flash 低 16 KB(`0x08000000 ~ 0x08003FFF`) - **APP** 起始地址为 `0x08004000`,最大可用约 240 KB - **Magic 标记** 驻留在 SRAM 末尾(`0x20007FF0`),软复位不丢失 --- ## 通信协议 ### CAN ID 分配 | CAN ID | 方向 | 说明 | |--------|------|------| | `0x100` | Host → Device | 命令帧 | | `0x101` | Device → Host | 应答帧 | | `0x102` | Host → Device | 数据帧 | | `0x103` | Device → Host | Bootloader 日志 / Banner | ### 命令码 | 命令码 | 功能 | |--------|------| | `0x00` | **PING** — 检测设备在线 | | `0x01` | **GET_INFO** — 获取设备信息(版本、Flash 容量等) | | `0x02` | **ERASE** — 擦除 APP 区域 | | `0x03` | **WRITE_PREPARE** — 准备接收数据块(附带总长度) | | `0x04` | **WRITE_FINALIZE** — 数据块写入完成,触发 CRC32 校验 | | `0x05` | **GO** — 校验通过后跳转 APP | | `0x06` | **RESET** — 软复位设备 | | `0x07` | **ENTER_BL** — APP 中收到此命令后跳回 Bootloader | ### 数据传输格式 - **块大小**: 256 字节 / Block - **每帧数据**: 6 字节(CAN 标准帧 8 字节中,2 字节为 Block 索引 + 序列号) - **每块帧数**: 约 43 帧(`ceil(256/6)`) - **CRC32**: 多项式 `0xEDB88320`(与 Ethernet / ZIP 一致),对整个固件计算 --- ## 目录结构 ``` 九号外发/ ├── README.md ← 本文件 │ ├── bootloader/ ← Bootloader 下位机工程 (Keil MDK) │ ├── BL/ │ │ ├── bootloader.c/h Bootloader 主逻辑 │ ├── APP/ │ │ ├── main.c Bootloader 入口 │ │ ├── interrupt.c/h ISR(CAN RX0 等) │ ├── BSP/ │ │ ├── BSP_can.c/h CAN 初始化与收发 │ │ ├── BSP_flash.c/h Flash 擦写操作 │ │ ├── BSP_crc32.c/h CRC32 计算 │ │ ├── BSP_iic.c/h I2C EEPROM 驱动 │ │ ├── BSP_eeprom_map.c/h EEPROM 数据布局 │ │ └── ... 其他 BSP 驱动 │ ├── FWLib/ AT32F415 标准外设库 │ ├── CORE/ CMSIS 及 DSP 库 │ ├── RTT/ SEGGER RTT 日志输出 │ ├── Project/ Keil 工程文件 │ └── bin/ 编译产物 │ ├── app/ ← APP 下位机工程 (Keil MDK) │ ├── APP/ │ │ ├── main.c APP 入口 │ │ ├── interrupt.c/h ISR(含 ENTER_BL 命令检测) │ ├── BSP/ BSP 驱动(同 bootloader) │ ├── FWLib/ AT32F415 标准外设库 │ ├── CORE/ CMSIS 及 DSP 库 │ ├── Project/ Keil 工程文件 │ └── bin/ 编译产物 │ └── 上位机/ ← PC 上位机工具 (Python) ├── can_bl_gui.py 主程序(Tkinter GUI) ├── requirements.txt Python 依赖 └── APP_Bootloader_接入指南.txt APP 接入说明 ``` --- ## 快速开始 ### 1. 编译下位机固件 使用 **Keil MDK** 分别打开以下工程并编译: - `bootloader/Project/Temperature_Reading.uvprojx` → 生成 Bootloader 固件 - `app/Project/Temperature_Reading.uvprojx` → 生成 APP 固件 编译产物位于各自的 `bin/` 目录。 > 注意:APP 工程的链接脚本需将起始地址设为 `0x08004000`,并且 `SCB->VTOR` 必须指向 APP 的向量表。 ### 2. 烧录 Bootloader 使用 J-Link 或其他调试器将 Bootloader 固件烧录到 `0x08000000`。 ### 3. 安装上位机依赖 ```bash cd 上位机 pip install -r requirements.txt ``` 依赖包: - `python-can >= 4.4.0` - `pyserial >= 3.5` ### 4. 启动上位机 ```bash python can_bl_gui.py ``` 操作流程: 1. 选择 CANable 串口并设置波特率(默认 1 Mbps) 2. 点击 **连接** 3. 点击 **PING** 确认设备在线 4. 点击 **选择固件**,加载 `.bin` 文件 5. 点击 **开始烧录**,等待进度完成 6. 点击 **GO** 跳转到新固件运行 ### 5. APP 跳回 Bootloader APP 运行时,上位机点击 **进入BL** 按钮发送 `0x100 0x07` 命令,MCU 会在 CAN RX 中断中检测该命令,写入 Magic 标记后软复位,回到 Bootloader。 --- ## 工作流程 ```mermaid sequenceDiagram participant PC as 上位机 (PC) participant BL as Bootloader (MCU) participant APP as APP (MCU) Note over BL: 上电 / 复位 BL->>BL: 检查 Magic 标记 alt Magic 有效 (BLMG) BL->>BL: 清除 Magic,留在 BL else Magic 无效 BL->>APP: 跳转到 0x08004000 end Note over PC,BL: ─── OTA 升级流程 ─── PC->>BL: PING (0x100, CMD=0x00) BL->>PC: 应答 (0x101, OK) PC->>BL: GET_INFO (0x100, CMD=0x01) BL->>PC: 版本号 / Flash 容量 PC->>BL: ERASE (0x100, CMD=0x02) BL->>PC: 擦除完成 PC->>BL: WRITE_PREPARE (0x100, CMD=0x03) loop 逐块传输 (256B/Block) PC->>BL: 数据帧 (0x102) BL->>PC: 应答 (CRC OK / ERR) end PC->>BL: WRITE_FINALIZE (0x100, CMD=0x04) BL->>PC: CRC32 校验结果 PC->>BL: GO (0x100, CMD=0x05) BL->>APP: 跳转到新固件 Note over PC,APP: ─── 运行时回退 BL ─── APP->>APP: 正常运行 PC->>APP: ENTER_BL (0x100, CMD=0x07) APP->>APP: 写 Magic + 软复位 Note over BL: 重新进入 Bootloader ``` --- ## 关键设计说明 ### Magic 标记机制 | 地址 | 值 | 含义 | |------|------|------| | `0x20007FF0` | `0x424C4D47` ("BLMG") | 下次复位后停留在 Bootloader | | `0x20007FF0` | 其他值 | 正常启动,自动跳转 APP | Magic 标记位于 SRAM 末尾,由 APP 写入后调用 `NVIC_SystemReset()`。软复位不擦除 SRAM,因此 Bootloader 启动时仍能读到该标记。 ### Flash 写入策略 - 接收在 CAN ISR 中完成(数据放入 `data_buf[256]`) - 实际的 Flash 擦写操作在 `main()` 主循环的 `bl_process()` 中执行 - 避免了在中断上下文中擦写 Flash 导致的其他中断延迟问题 ### CRC32 校验 - **传输阶段**: 每 256 字节块附带块级 CRC - **完成阶段**: WRITE_FINALIZE 命令触发全固件 CRC32 校验 - **启动阶段**: Bootloader 通过 I2C EEPROM 中保存的 CRC 值校验现有 APP 固件 --- ## 注意事项 1. **CAN 时钟精度**:CAN 协议要求时钟精度 ≤1.58%,必须使用 HEXT 外部晶振,不可使用 HICK 内部 RC 2. **向量表偏移**:APP 的 `VTOR` 必须设为 `0x08004000`,否则中断无法正确响应 3. **SRAM 末尾**:Magic 标记地址 `0x20007FF0` 不可被栈或堆覆盖,请在链接脚本中预留 4. **APP 中断向量**:APP 的 `startup` 文件中的向量表也是从 `0x08004000` 偏移,需链接器正确设置 --- ## 许可证 内部项目,仅供团队使用。 --- > *README generated by GitHub Copilot (DeepSeek V4 Pro) — 2026-06-29* --- > *README generated by GitHub Copilot (DeepSeek V4 Pro) — 2026-06-29*