# 九号控制器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
---
## ☕ 打赏支持
如果这个项目对你有帮助,欢迎请作者喝杯咖啡~

---
## 项目概述
本项目是一个基于 **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*