更新历史
日期 | 版本 | 作者 | 更新内容 |
---|---|---|---|
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
一个最简的烧录流程
- 0xFA 命令烧录,此时需要从APP跳入OTA程序
- 0xFA 再次命令烧录,作为ping功能,区别在于回复状态的头两个字节,跳转回复是00 01,而ping是00 02,表达已经在OTA程序中
- 0xF4 擦除指示,将固件需要的部分ROM全部擦掉
- 0xF7 首包指示
- 许多 0xF5 包,符合指示的长度,但是 OTA 会寄存最开始数个字节而不烧录,使得 APP 不完整。
- 反复进行 4、5 直到上位机认为完成
- 此时 OTA 程序自校验是否长度、校验都符合,写入最开始的数个字节,使得 APP 完整。
- 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 // 烧录上位机