1
0

存储访问协议.md 7.5 KB

存储访问协议

1. 协议目标

本协议用于上位机通过蓝牙透传链路按字节访问从机 MCU 的存储区域。协议为单主单从模型,不包含从机地址字段,不属于 Modbus RTU。

小程序中该协议与标准 Modbus、Bootloader 升级协议平级。标准 Modbus 继续使用原有从机地址、功能码和 Modbus CRC;存储访问协议统一使用本文定义的 CMD + ADDR + LEN + DATA + CRC 格式,0x0F info 也按只读区域处理。

2. 基本字节序

除 CRC 算法内部计算外,协议字段均为大端序。

16 位地址: ADDR_H ADDR_L
16 位长度: LEN_H  LEN_L
CRC 输出 : CRC_H  CRC_L

CRC 使用 CRC16-CCITT-FALSE

多项式: 0x1021
初值  : 0xFFFF
反转  : 输入不反转,输出不反转
异或  : 0x0000
顺序  : 高字节在前

3. CMD 定义

每帧第 1 字节为 CMD

bit7      ERR    异常标志
bit6      RW     读写标志
bit5~bit0 AREA   存储区域编号

含义如下:

含义
ERR 0 正常请求或正常响应
ERR 1 异常响应
RW 0 读操作
RW 1 写操作

命令生成规则:

读命令 CMD = AREA
写命令 CMD = 0x40 | AREA
异常 CMD_ERR = CMD | 0x80

4. AREA 定义

AREA 名称 用途
0x01 data 支持 支持 内部直接寻址 RAM 区
0x02 idata 支持 支持 内部间接寻址 RAM 区
0x03 xdata 支持 支持 外部数据空间或扩展 RAM
0x04 code 支持 禁止 程序存储区
0x0F info 支持 禁止 连接后同步 code 区关键数据地址与长度

0x0F info 是一个只读信息区域,不直接承载完整 Modbus_Code_Info_t。小程序连接设备后先通过 0x0F 按地址和长度读取 4 字节关键数据,再使用 AREA=0x04 code 读取真正的 Modbus_Code_Info_t

5. 帧格式

5.0 info 同步请求/响应

info 同步请求与普通读请求一致,地址和长度单位均为字节。当前定义固定读取 ADDR=0x0000LEN=0x0004

0F 00 00 00 04 CRC_H CRC_L

回复与普通读响应一致,仍包含本次读取的 ADDRLEN,随后 4 字节数据为 code 区内信息块的地址和长度:

0F 00 00 00 04 CODE_ADDR_H CODE_ADDR_L CODE_LEN_H CODE_LEN_L CRC_H CRC_L

响应中的前两个字节地址 00 00 和长度 00 04 是本次 info 区读取的地址与长度。CODE_ADDRCODE_LEN 是返回数据,表示 code 区内 Modbus_Code_Info_t 的字节地址和字节长度。

5.1 读请求

CMD ADDR_H ADDR_L LEN_H LEN_L CRC_H CRC_L

长度固定 7 字节。

5.2 写请求

CMD ADDR_H ADDR_L LEN_H LEN_L DATA... CRC_H CRC_L

长度为 7 + LEN 字节。

5.3 正常读响应

CMD ADDR_H ADDR_L LEN_H LEN_L DATA... CRC_H CRC_L

长度为 7 + LEN 字节。

5.4 正常写响应

CMD ADDR_H ADDR_L LEN_H LEN_L CRC_H CRC_L

长度固定 7 字节。

5.5 异常响应

CMD_ERR EXCEPTION_CODE CRC_H CRC_L

长度固定 4 字节。

6. 异常码

异常码 名称 说明
0x01 ILLEGAL_COMMAND 非法命令
0x02 ILLEGAL_AREA 非法区域
0x03 ILLEGAL_ADDRESS 非法地址
0x04 ILLEGAL_LENGTH 非法长度
0x05 WRITE_PROTECT 写保护
0x06 DEVICE_BUSY 设备忙
0x07 FORMAT_ERROR 格式错误
0x08 ACCESS_DENIED 访问拒绝
0x09 INTERNAL_ERROR 内部错误
0x0A ALIGNMENT_ERROR 对齐错误
0x0B RANGE_OVERFLOW 地址范围溢出
0x0C UNSUPPORTED_OPERATION 不支持的操作

7. info 同步流程

连接后同步 code 区关键数据时,上位机先读取 AREA=0x0F info 的只读 4 字节数据,再访问 AREA=0x04 code 读取真实数据。

7.1 读取 info 区关键数据

读请求:

0F 00 00 00 04 CRC_H CRC_L

从机返回:

0F 00 00 00 04 CODE_ADDR_H CODE_ADDR_L CODE_LEN_H CODE_LEN_L CRC_H CRC_L

返回数据字段含义:

字段 长度 说明
CODE_ADDR 2 字节 Modbus_Code_Info_t 在 code 区内的字节地址
CODE_LEN 2 字节 Modbus_Code_Info_t 的字节长度

7.2 使用 code 区读取完整信息块

上位机根据 info 返回数据继续读取:

AREA = 0x04
ADDR = CODE_ADDR
LEN  = CODE_LEN

如果 CODE_LEN 超过当前链路最大包长,小程序按字节地址自动分片。例如最大帧长为 64 字节时,单帧读响应可承载的数据长度为:

64 - 7 = 57 字节

小程序会依次读取:

CODE_ADDR + 0x0000 ~ CODE_ADDR + 0x0038
CODE_ADDR + 0x0039 ~ CODE_ADDR + 0x0071
...

每个分片均使用 AREA=0x04 code,地址为 code 区内真实字节地址。

8. Modbus_Code_Info_t 布局

Modbus_Code_Info_t 位于 info 返回数据给出的 code 区地址,布局如下:

typedef struct
{
    uint16_t byte_len;
    uint8_t cave_freq;
    uint8_t ref_volt;
    uint16_t amp_gain;
    uint16_t rs_shunt;
    float bus_div;
    float along_div;
    uint8_t chip_model[8];
    uint8_t model[16];

    uint16_t struct_count;
    uint16_t struct_entry_len;
    struct
    {
        uint16_t byte_addr;
        uint16_t byte_len;
        uint8_t mem_type;
        uint8_t type_name[MODBUS_CODE_INFO_STRUCT_NAME_BYTE_LEN];
    } struct_table[MODBUS_CODE_INFO_STRUCT_COUNT];
} Modbus_Code_Info_t;

固定头长度为 44 字节:

偏移 字段 长度
0 byte_len 2
2 cave_freq 1
3 ref_volt 1
4 amp_gain 2
6 rs_shunt 2
8 bus_div 4
12 along_div 4
16 chip_model 8
24 model 16
40 struct_count 2
42 struct_entry_len 2
44 struct_table struct_count * struct_entry_len

struct_tablemem_type 使用同一套 AREA 编号:

mem_type 结构体实例所在区域
0x01 data
0x02 idata
0x03 xdata
0x04 code

struct_table 不应把结构体实例标为 0x0F,因为 0x0F info 只用于同步 code 区信息块地址和长度,不作为普通变量读写区域。

9. 小程序同步后的处理

小程序读取完整 Modbus_Code_Info_t 后执行以下步骤:

  1. 解析硬件固定信息。
  2. 解析 struct_countstruct_entry_len
  3. 遍历 struct_table
  4. 根据每一项的 mem_typebyte_addrbyte_lentype_name 创建结构体组。
  5. 后续读取结构体实例时,改用对应的真实区域:
    • 0x01 data
    • 0x02 idata
    • 0x03 xdata
    • 0x04 code
  6. 如果导入了 C 结构体定义,小程序会根据 type_name 自动补全字段、位域、数组和数据类型。

示例:

struct_table[0]:
  byte_addr = 0x2000
  byte_len  = 64
  mem_type  = 0x03
  type_name = motor_runtime_t

则后续读取该结构体实例时发送:

03 20 00 00 40 CRC_H CRC_L

含义为读取 xdata0x2000 开始的 64 字节。

10. 实现约束

  1. codeinfo 区默认只读。
  2. LEN 单位始终为字节,不是 Modbus 寄存器。
  3. 上位机必须校验响应 CMD、ADDR、LEN 和 CRC。
  4. 异常响应固定 4 字节。
  5. 0x0F info 只用于连接同步信息块地址和长度,请求/回复均按普通只读帧处理,不作为普通变量读写区域。
  6. 如果固件更新了 Modbus_Code_Info_t 布局,应同步更新本文档和小程序解析器。