更新历史
日期 版本 作者 更新内容
2025-08-14 0.1.0 yono 定义基础消息结构

概述

这是一个简单的 MCU-OTA 基础协议,采用短帧形式发送和接收,适合极小资源的实现,同时对不同的物理链路保证了基本的纠错,并便于更复杂纠错的拓展开发。

基础消息结构

对于不同的物理接口,例如 UART、CAN、LAN ,各有自己不同的校验机制。但基础的有价值消息是统一的,在此定义基础的消息结构。因为其他的接口消息是完全流式可定义的,无需兼容,所以此消息结构更多的是对 CAN 消息的兼容

通常采用烧录上位机与被烧录设备一发一收的形式,在广播多机烧录中采用一发多收(此部分库不方便全兼容,需要定制)。

[!NOTE]

整个文档中涉及的数字均为 16 进制,可能不添加 0x 或 h 提示。

请求单帧结构

控制消息(4字节) 额外消息(n字节)

请求通常由烧录机,例如上位机软件发出。

其中控制消息表达了:

  • 向谁发送
  • 做什么
  • 由谁发送
/* 具体位含义 */
typedef struct
{
    uint16_t bParaID:6; //BIT0-BIT5,模块ID(0-63)
    uint16_t bCabID :4; //BIT6-BIT9,机柜ID(0-15)
    uint16_t bRX_Mes:6; //BIT10-BIT15,收件方信息
    uint16_t bKind  :8; //BIT16-BIT23,Command/Event的Kind
    uint16_t bTX_Mes:3; //BIT24-BIT26,寄件人信息
    uint16_t bBITs  :5; //BIT27-BIT31通常无实际意义 在CAN总线中可用于优先级仲裁
} BOOT_PARSE_MSG_BIT;

额外消息则表达了一些拓展信息,例如在指示烧录flash地址时包含地址信息,在烧录过程中传输固件。

一个经典的握手发送帧示例

/* 控制信息 */
05 // 高8位,指示寄件人是0x05意味着烧录上位机,后续会介绍寄件人定义
FA // kind指示,表示对模块类型1进行烧录,后续会介绍更多定义
04 01 // 收件人是0x01意味着模块类型1,机柜ID是0代表机柜广播,模块ID是1代表对模块1烧录

/* 额外消息,无实际意义,握手时控制信息已经可以表达所有有效信息 */
00
01
00
00
00
00
00
00

回复单帧结构

对于任意请求都需要回复,指示对请求的处理情况

控制消息(4字节) 回复状态(8字节)

控制消息与请求的结构和定义是统一的。

回复状态的第一第二字节应该复制请求部分,用于辅助校验,第四字节是实际的状态指示

对上面握手消息的回复为

/* 控制信息 */
00 // 高8位,指示寄件人是0x00意味着模块类型1
FA // 与握手相同kind
80 41 // 收件人是0x20意味着上位机,机柜ID是自己0x01一号机柜,模块ID是1代表自己模块号1

/* 回复状态 */
00
01 // 头两个字节复制了消息
00
06 // 这是实际状态位 0x06表示ACK默认的成功
00 // 其他字节都属于预留部分
00
00
00

控制消息各位域详解

bParaID:6

BIT0-BIT5,模块ID(0-63)

在一个机柜中可能存在多个板卡模块,或者机器模块,那么在总线上他们应该有唯一ID,这就是在机柜层的唯一ID。指示了应该由谁解析请求,也指示了是谁回复的。

bCabID :4

BIT6-BIT9,机柜ID(0-15)

同上,在一个大的总线上可能具有多个机柜,那么总线上应该有唯一ID,这个部分进行了指示。

bRX_Mes:6

BIT10-BIT15,收件方信息

可能的值有以下这些,通常库中会做枚举或宏定义

0x01 // 被烧录模块类型1
0x02 // 被烧录模块类型2
0x04 // 被烧录模块类型3
0x08 // 被烧录模块类型4
0x10 // 被烧录模块类型5
0x20 // 烧录上位机

这个存在的意义是:假设某个机器,其中有一片 stm32、一片 GD32,由于他们在同一台机器中,对外认为是同一机器 ID;但两个芯片负责不同的功能,具有不同的程序固件。那么我们可以对 stm32 定义为模块类型1,对 GD32 定义为模块类型2,以此在 OTA 时进行有区分的升级。

bKind:8

BIT16-BIT23,Command/Event的Kind

可能的值有以下这些

0xFA // 命令烧录模块类型1 同时兼容ping功能
0xFB // 命令烧录模块类型2 同时兼容ping功能
0xFC // 命令烧录模块类型3 同时兼容ping功能
0xFD // 命令烧录模块类型4 同时兼容ping功能
0xFF // 命令烧录模块类型5 同时兼容ping功能

0xF3 // 统计烧录台数
0xF4 // 擦除数据命令
0xF5 // 烧录数据
0xF6 // 应答烧录台数
0xF7 // 烧录指示信息,包含地址、长度、校验
0xF8 // 结束重启,跳转APP

一个最简的烧录流程

  1. 0xFA 命令烧录,此时需要从APP跳入OTA程序
  2. 0xFA 再次命令烧录,作为ping功能,区别在于回复状态的头两个字节,跳转回复是00 01,而ping是00 02,表达已经在OTA程序中
  3. 0xF4 擦除指示,将固件需要的部分ROM全部擦掉
  4. 0xF7 首包指示
  5. 许多 0xF5 包,符合指示的长度,但是 OTA 会寄存最开始数个字节而不烧录,使得 APP 不完整。
  6. 反复进行 4、5 直到上位机认为完成
  7. 此时 OTA 程序自校验是否长度、校验都符合,写入最开始的数个字节,使得 APP 完整。
  8. 0xF8 上位机发起重启跳转,接收到确认回复,完成烧录

烧录请求帧的回复都是完全统一的,可见前面的帧结构,以下对流程中不同的kind需要携带怎样的额外信息作说明。

0xFA~0xFF :ping/跳转包,额外消息无所谓,只要有两个字节供回复校验即可

0xF3:统计包,额外消息无所谓,只要有两个字节供回复校验即可

0xF4:擦除包,额外消息8字节,前4个字节从低到高指示了擦除起始地址,后四个字节从低到高指示了总长度。例如起始地址为0x11223344,擦除总长0x55667788,那么额外消息为 44 33 22 11 88 77 66 55

0xF5:烧录数据包,此前已经进行过指示,这里额外消息将固件十六进制发送即可。在CAN中共8字节,而其他通信则视实际情况加长,在达到指示长度前,被烧录设备不会回复

0xF6:与统计包配合的回复,避免多次统计所以kind错开

0xF7:接下来固件的烧录提示,额外消息8字节,前4个字节从低到高指示了起始地址,随后2个字节从第到高指示了连续包的和校验,最后2个字节从低到高指示了连续固件的长度。例如连续烧录从0x11224455开始,这些固件十六进制的和校验为0x3456,总长度0x200,那么额外信息为 55 44 22 11 56 34 00 02

0xF8:完成的跳转/重启包,额外消息无所谓,只要有两个字节供回复校验即可

bTX_Mes:3

BIT24-BIT26,寄件人信息

可能的值有以下这些,通常库中会做枚举或宏定义

0x00 // 被烧录模块类型1
0x01 // 被烧录模块类型2
0x02 // 被烧录模块类型3
0x03 // 被烧录模块类型4
0x04 // 被烧录模块类型5
0x05 // 烧录上位机