Files
STM8_Mesh_Control/docs/OTA_STORAGE_AND_PROTOCOL.md
T

329 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# STM8 Mesh 继电器 OTA、Flash 分区与业务协议设计
本文档记录当前已经确认的外部 W25Q80BV存储规划、Bootloader启动策略、主程序OTA职责以及业务命令规则。
## 1. 硬件资源与程序分区
### 1.1 STM8S003F3P6TR 内部 Flash
STM8S003F3P6TR 内部程序 Flash 总容量为 8KiB,地址范围为 `0x8000~0x9FFF`。
当前 Bootloader 规划如下:
| 地址范围 | 容量 | 用途 |
|---|---:|---|
| `0x8000~0x87FF` | 2KiB | Bootloader |
| `0x8800~0x9FFF` | 6KiB | Application 主程序 |
应用程序必须按照 `0x8800` 重新链接,不能使用默认的 `0x8000` 起始地址。
### 1.2 W25Q80BV 外部 Flash
W25Q80BV总容量为128KiB。当前固定分区如下:
| 地址范围 | 容量 | 用途 |
|---|---:|---|
| `0x000000~0x001FFF` | 8KiB | 出厂固件镜像 |
| `0x002000~0x002FFF` | 4KiB | 出厂固件元数据 |
| `0x003000~0x004FFF` | 8KiB | OTA升级固件镜像 |
| `0x005000~0x005FFF` | 4KiB | OTA升级元数据 |
| `0x006000~0x01FFFF` | 104KiB | 后续日志、运行记录、故障记录等 |
元数据区域均独占一个4KiB扇区,避免擦除元数据时影响固件镜像。
### 1.3 SPI连接
| STM8引脚 | W25Q80BV信号 |
|---|---|
| `PC5` | `SCK` |
| `PC6` | `MOSI/DI` |
| `PC7` | `MISO/DO` |
| `PD4` | `CS#` |
| `3.3V` | `VCC` |
| `GND` | `GND` |
恢复/继电器按键连接到 `PA3`,按键另一端接地,使用内部上拉:
```text
PA3 = 1:按键释放
PA3 = 0:按键按下
```
JDY-28M 控制脚当前分配为:`PA2=PWRC`、`PD2=RESET`。`PA2` 不再作为Flash片选。
蓝牙状态/故障指示灯连接到 `PB5`,低电平点亮;继电器状态指示灯连接到 `PD3`,高电平点亮。
程序运行/OTA状态灯连接到 `PB4`,低电平点亮:正常运行时按500ms节奏闪烁,OTA接收或校验时按约100ms节奏快速闪烁。
## 2. 元数据格式
出厂元数据和OTA元数据使用相同字段布局,只是存储区域不同。
### 2.1 元数据字段
相对于元数据区域起始地址的固定偏移如下:
| 偏移 | 字段 | 长度 | 说明 |
|---:|---|---:|---|
| `0x00` | 魔数 | 4字节 | 识别元数据类型 |
| `0x04` | 固件长度 | 4字节 | 实际固件字节数 |
| `0x08` | 固件版本 | 2字节 | 版本号,高低字节规则由打包工具固定 |
| `0x0A` | CRC16 | 2字节 | 完整固件镜像CRC-16/MODBUS |
| `0x0E` | 镜像有效标志 | 1字节 | `0xA5`表示有效 |
| `0x0F` | 升级请求 | 1字节 | 非0表示请求Bootloader处理 |
| `0x10` | 升级结果 | 1字节 | Bootloader执行结果 |
| `0x11` | 保留 | 1字节 | 后续扩展 |
### 2.2 元数据绝对地址
OTA元数据区域起始地址为 `0x005000`,因此:
```text
魔数: 0x005000~0x005003
固件长度: 0x005004~0x005007
固件版本: 0x005008~0x005009
CRC16: 0x00500A~0x00500B
有效标志: 0x00500E
升级请求: 0x00500F
升级结果: 0x005010
```
出厂元数据区域起始地址为 `0x002000`,字段偏移相同,因此出厂镜像升级结果地址为 `0x002010`。
### 2.3 魔数
魔数是固定识别值,不是密码。当前约定:
```c
FACTORY_METADATA_MAGIC = 0x46414331 /* FAC1,出厂镜像 */
OTA_METADATA_MAGIC = 0x4F544131 /* OTA1,升级镜像 */
```
Bootloader只有在魔数正确、有效标志正确、升级请求有效、固件长度合法且CRC16正确时,才允许使用镜像。
### 2.4 元数据写入规则
下载过程中不能提前写入有效标志。正确顺序为:
```text
1. 擦除OTA固件区域;
2. 接收并写入固件分包;
3. 计算完整固件CRC16/MODBUS;
4. 写入魔数、长度、版本和CRC16;
5. 校验元数据;
6. 最后写入image_valid = 0xA5;
7. 设置upgrade_request;
8. 软件复位进入Bootloader。
```
这样可以避免断电时把不完整固件误判为有效镜像。
## 3. Bootloader职责
Bootloader不处理JDY-28M Mesh通信,也不接收OTA分包。
Bootloader负责:
- 上电检测PA3上电恢复按键;
- 读取OTA元数据;
- 校验OTA固件CRC16/MODBUS;
- 擦除STM8内部应用区;
- 从W25Q80BV搬运固件到内部Flash;
- 回读校验内部Flash;
- 写入升级结果;
- 清除升级请求;
- 检查内部应用程序是否有效;
- 应用损坏时恢复出厂固件;
- 跳转到 `0x8800` 启动主程序。
升级安全顺序必须是:
```text
先完整校验W25Q80BV固件
↓
CRC正确
↓
擦除内部应用区
↓
写入应用程序
↓
回读校验
↓
记录升级成功
↓
清除升级请求
```
### 3.1 出厂固件恢复
以下任一情况出现时,Bootloader使用 `0x000000` 开始的出厂镜像:
- 内部应用程序为空;
- 内部应用程序入口无效;
- OTA固件CRC16错误;
- 内部Flash写入失败;
- 内部Flash写入后校验失败;
- 应用程序损坏导致无法正常启动。
出厂镜像必须预先写入W25Q80BV,并且出厂元数据中的镜像有效标志和CRC16必须正确。
## 4. PA3上电恢复按键
### 4.1 Bootloader阶段
上电后首先运行Bootloader:
```text
检测PA3
├── 未按下:执行正常Bootloader流程
└── 已按下:开始计时,此期间不跳转主程序
├── 5秒内释放:继续正常Bootloader流程
└── 持续按住超过5秒:恢复出厂固件
```
主程序不会参与本次上电按键判断,因此不存在Bootloader长按和主程序恢复参数重复触发的问题。
### 4.2 主程序阶段
主程序只处理正常运行期间的新按键:
```text
短按:按下时间小于5秒,控制继电器
长按:按下时间大于5秒,恢复主程序参数
```
## 5. 主程序OTA职责
主程序负责:
- 通过JDY-28M接收OTA业务帧;
- 校验业务帧CRC16/MODBUS;
- 擦除OTA固件区域;
- 将固件分包写入 `0x003000`;
- 计算完整固件CRC16/MODBUS;
- 写入OTA元数据;
- 设置有效标志和升级请求;
- 软件复位进入Bootloader;
- 启动后读取Bootloader升级结果;
- 通过Mesh主动上报升级结果;
- 收到主机确认后清除升级结果。
## 6. 主程序业务帧格式
业务数据帧格式:
```text
SRC_H | SRC_L | CMD | LEN | DATA | CRC16_L | CRC16_H
```
说明:
- `SRC_H SRC_L`:发送方 Mesh 短地址,高字节在前;设备应答时将该地址作为
JDY-28M 外层目标地址,业务帧中的 SRC 改为设备自身短地址;
- `CMD`:命令;
- `LEN`:DATA长度;
- `DATA`:命令数据;
- `CRC16`:CRC-16/MODBUS,计算范围为 SRC、CMD、LEN、DATA,低字节在前;
- CRC错误时静默丢弃,不执行继电器动作,不返回错误帧。
JDY-28M的Mesh外层帧负责目标地址、源地址、Mesh头和帧尾,业务帧本身不重复添加地址。
## 7. 已确定的业务命令
| CMD | 名称 | 方向 | DATA说明 |
|---:|---|---|---|
| `0x01` | 继电器控制 | 主机→设备 | `0x00`断开,`0x01`吸合 |
| `0x02` | 查询继电器状态 | 主机→设备 | 返回`0x00`断开或`0x01`吸合 |
| `0x03` | 查询实际电流 | 主机→设备 | 返回无符号mA,高字节在前 |
| `0x04` | 故障/恢复上报 | 设备→主机 | DATA为故障码或恢复码 |
| `0x05` | 查询设备短地址 | 主机→设备 | 返回2字节短地址 |
| `0x06` | 配置电流阈值 | 主机→设备 | 2字节,单位mA,低字节在前,保存到EEPROM |
| `0x0E` | 查询当前固件版本 | 主机→设备 | 无DATA |
| `0x0D` | OTA升级结果上报 | 设备→主机 | DATA为升级结果码 |
应答命令使用请求命令加 `0x80`:
```text
0x81:继电器控制应答
0x82:继电器状态应答
0x83:电流查询应答
0x85:短地址查询应答
0x86:阈值配置应答
```
OTA内部控制命令建议保留:
```text
0x08:进入OTA模式
0x09:固件数据分包
0x0A:固件发送完成并校验
0x0B:查询OTA状态
0x0C:取消OTA
0x0E:查询当前固件版本
```
## 8. 故障码和升级结果码
### 8.1 故障码
```text
0x02:ACS712采样异常
0x03:蓝牙初始化异常
0x04:电流故障恢复
0x05:蓝牙故障恢复
0x06:采样异常恢复
0x07:继电器控制失败预留码
```
电流故障需要持续至少10秒确认,恢复也需要持续至少10秒确认。默认电流阈值为100mA,支持动态配置并保存到EEPROM。
故障恢复上报需要等待主机确认;未收到确认时每10秒重复上报,直到收到确认。
### 8.2 OTA升级结果码
```text
0x00:无结果
0x01:升级成功
0x02:固件CRC错误
0x03:内部Flash写入失败
0x04:写入后校验失败
0x05:固件长度非法
0x06:W25Q80BV读取失败
```
主程序启动后读取升级结果,并使用:
```text
CMD = 0x0D
LEN = 0x01
DATA = 升级结果码
```
发送给主机。主机确认后,主程序清除结果字段。
### 8.3 主机侧最终确认流程
`CMD=0x8B`仅表示应用程序已经完成外部Flash固件的整包CRC16校验,并且
已经成功写入OTA元数据。校验成功后,设备先发送`0x8B=00`,再主动触发
MCU复位;Bootloader随后负责把OTA镜像搬运到内部Flash。
主机不能在收到`0x8B=00`后立即认为升级完成,而应继续等待设备重新启动并
主动上报:
```text
CMD = 0x0D
LEN = 0x01
DATA[0] = 0x01:Bootloader搬运并校验成功
```
主机默认等待20秒。超时未收到`0x0D`,或者收到的结果码不是`0x01`,均应
判定本次升级失败。收到结果后,主机向上报帧的设备短地址发送:
```text
CMD = 0x8D
LEN = 0x01
DATA[0] = 原样返回设备上报的升级结果码
```
设备收到`0x8D`后清除待上报结果记录。