335 lines
9.9 KiB
Markdown
335 lines
9.9 KiB
Markdown
# STM8 Mesh 继电器 OTA、Flash 分区与业务协议设计
|
||
|
||
本文档记录当前已经确认的外部 W25Q80BV存储规划、Bootloader启动策略、主程序OTA职责以及业务命令规则。
|
||
|
||
## 1. 硬件资源与程序分区
|
||
|
||
### 1.1 STM8S003F3P6TR 内部 Flash
|
||
|
||
STM8S003F3P6TR 内部程序 Flash 总容量为 8KiB,地址范围为 `0x8000~0x9FFF`。
|
||
|
||
当前 Bootloader 规划如下:
|
||
|
||
| 地址范围 | 容量 | 用途 |
|
||
|---|---:|---|
|
||
| `0x8000~0x84FF` | 1.25KiB | Bootloader |
|
||
| `0x8500~0x9FFF` | 6.75KiB | Application 主程序 |
|
||
|
||
应用程序必须按照 `0x8500` 重新链接,不能使用默认的 `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片选。
|
||
|
||
蓝牙状态/故障指示灯连接到 `PB4`,低电平点亮;继电器状态指示灯连接到 `PD3`,高电平点亮。
|
||
|
||
程序运行/OTA状态灯连接到 `PB5`,低电平点亮:正常运行时按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;
|
||
- 写入升级结果;
|
||
- 清除升级请求;
|
||
- 检查内部应用程序是否有效;
|
||
- 应用损坏时恢复出厂固件;
|
||
- 跳转到 `0x8500` 启动主程序。
|
||
|
||
升级安全顺序必须是:
|
||
|
||
```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
|
||
CMD | LEN | DATA | CRC16_H | CRC16_L
|
||
```
|
||
|
||
说明:
|
||
|
||
- JDY-28M 外层地址:发送方和接收方 Mesh 短地址均由外层提供,高字节在前;
|
||
设备应答时将外层发送方地址作为目标地址;
|
||
- `CMD`:命令;
|
||
- `LEN`:DATA长度;
|
||
- `DATA`:命令数据;
|
||
- `CRC16`:CRC-16/MODBUS,计算范围为 CMD、LEN、DATA,高字节在前;
|
||
- 发送方和接收方 Mesh 短地址由 JDY-28M 外层帧携带,业务帧不重复添加地址;
|
||
- CRC错误时静默丢弃,不执行继电器动作,不返回错误帧。
|
||
|
||
JDY-28M的Mesh外层帧负责目标地址、源地址、Mesh头和帧尾,业务帧本身不重复添加地址。
|
||
|
||
## 7. 已确定的业务命令
|
||
|
||
| CMD | 名称 | 方向 | DATA说明 |
|
||
|---:|---|---|---|
|
||
| `0x01` | 继电器控制 | 主机→设备 | `0x00`断开,`0x01`吸合 |
|
||
| `0x02` | 查询继电器状态 | 主机→设备 | 返回`0x00`断开或`0x01`吸合 |
|
||
| `0x03` | 查询实际电流 | 主机→设备 | 返回无符号mA,高字节在前 |
|
||
| `0x04` | 故障/恢复上报 | 设备→主机 | DATA为故障码或恢复码 |
|
||
| `0x05` | 查询设备短地址 | 主机→设备 | 返回2字节短地址 |
|
||
| `0x06` | 配置电流阈值 | 主机→设备 | 2字节,单位mA,低字节在前,保存到EEPROM |
|
||
|
||
当前汇编主程序已经完成并通过实物验证的命令为:`0x01`、`0x02`和`0x05`。
|
||
`0x03`、`0x04`、`0x06`、`0x07`以及`0x08~0x0E`属于已确定的协议设计,
|
||
在当前汇编主程序中尚未全部完成或尚未完成实物验证,上位机不应据此判断当前
|
||
固件已经支持这些命令。
|
||
| `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`后清除待上报结果记录。
|