Photonicat 2 MCU 通讯协议
本页描述 Photonicat 2 主机(RK3576)与电源管理 MCU(Renesas RA2E1)之间的 串口通讯协议。协议同样适用于一代(RK3568),但一代的电压阈值是单节锂电语义, 详见下方"与一代的差异"。
相关页面:Photonicat 2 sysfs(内核已经把电源/RTC 数据导出成标准接口, 一般应用不需要自己解析本协议)、Photonicat 2 SOC 计算(状态帧里的 电量是怎么算出来的)、Photonicat 2 LED 指示灯、Photonicat 2 提示音说明。
先读这里:你可能不需要这个协议
绝大多数应用不应该直接收发本协议。主机侧已经有两层封装:
| 你想做的事 | 推荐用法 |
|---|---|
| 读电量/电压/电流/充电器状态 | /sys/class/power_supply/*,见 Photonicat 2 sysfs
|
| 读写时间 | hwclock / /dev/rtc(MCU 就是硬件 RTC)
|
| 风扇转速、温度 | /sys/class/hwmon/*、/sys/class/thermal/*
|
| 网页界面里的各种设置 | pcat-manager 的 REST API,见 Photonicat 2 开发者 API |
| 上面都覆盖不到的功能 | 才需要本页的协议 |
串口本身由内核驱动 photonicat-pm 和用户态守护进程
pcat-manager 占用。第三方程序直接抢串口会和它们冲突。
物理层
- 串口,115200 波特率,8 数据位,无校验,1 停止位(8N1)
- 主机侧设备:一代为
/dev/ttyS4;二代由设备树绑定给
photonicat-pm 驱动(serdev),不再以裸 tty 暴露
帧格式
| 字节 | 字段 | 说明 |
|---|---|---|
| 0 | 起始位 | 固定 0xA5 |
| 1 | 源地址 | 见地址表 |
| 2 | 目的地址 | 见地址表 |
| 3–4 | 帧序号 | 小端 uint16,主动发送方每发一帧加一,溢出回零;应答沿用请求的帧序号 |
| 5–6 | 数据长度 | 小端 uint16,指"命令号 + 命令内容 + 是否需要回复"三段的总字节数 |
| 7–8 | 命令号 | 小端 uint16 |
| 9… | 命令内容 | 变长,见各命令说明 |
| 倒数第 4 | 是否需要回复 | 1 = 需要应答,0 = 不需要 |
| 倒数第 3、2 | CRC16 | 对从字节 1 到"是否需要回复"为止的所有字节计算,小端 |
| 最后 1 | 结束位 | 固定 0x5A |
一帧总长 = 数据长度 + 10。接收方据此校验,长度对不上直接丢弃。
地址表
| 值 | 含义 |
|---|---|
| 0x01 | 第一块 CPU 板(目前只有一块,主机固定用 0x01) |
| 0x02 / 0x03 | 第二、三块 CPU 板(预留) |
| 0x80 | 广播给所有 CPU 板 |
| 0x81 | 电源管理 MCU(RA2E1) |
| 0xFE | 广播给所有 RA2E1 |
| 0xFF | 广播给系统内所有设备 |
命令号约定
奇数 = 请求,偶数 = 对应的应答(应答号 = 请求号 + 1)。这条规则贯穿整个
协议,MCU 内部就是按 命令号 % 2 来分发的。
命令一览
基础与版本
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 1 / 2 | CPU → MCU | 无 | 心跳。超过 1 分钟没有收到任何数据,MCU 会重启主机 |
| 3 / 4 | CPU → MCU | 应答含 8 字节字符串 | 读硬件版本,例如 NT2421A4
|
| 5 / 6 | CPU → MCU | 应答含 14 字节字符串 | 读软件版本,例如 RA2E1260726005
|
| 139 / 140 | CPU → MCU | —— | 读硬件 ID |
| 159 / 160 | CPU → MCU | —— | 读 bootloader 版本号 |
状态上报(7)
MCU → CPU,周期性主动上报,是整个协议里最重要的一帧。数据长度 56。 下表偏移量以命令内容首字节为 0(即整帧的字节 9):
| 偏移 | 长度 | 字段 | 单位 / 说明 |
|---|---|---|---|
| 0 | 2 | 电池电压 | mV,小端 |
| 2 | 2 | 充电器接口电压 | mV,小端 |
| 4 | 2 | 输入 GPIO 状态 | 位域 |
| 6 | 2 | 输出 GPIO 状态 | 位域 |
| 8 | 8 | 系统时间 | 年(2) 月 日 时 分 秒 星期,各 1 字节 |
| 16 | 1 | RTC 状态 | 0 正常,1 初始化异常,2 无秒中断,3 无分钟中断 |
| 17 | 1 | 板子温度 | 实际温度 = 本字节 − 100(℃) |
| 18 | 2 | 电池电流 | mA,有符号小端。正 = 放电,负 = 充电 |
| 20 | 2 | 剩余容量 | mAh |
| 22 | 1 | 电量 | %(1–100,算法见 Photonicat 2 SOC 计算) |
| 23 | 4 | 当前能量 | mWh,小端 |
| 27 | 4 | 满电能量 | mWh,小端(学习值,可与标称对比看老化) |
| 31 | 4 | 累计开机时长 | 秒,小端 |
| 35 | 4 | 加速度 X | 1/16384 g,有符号小端 |
| 39 | 4 | 加速度 Y | 同上 |
| 43 | 4 | 加速度 Z | 同上 |
| 47 | 1 | 加速度数据就绪 | 非 0 表示有效 |
| 48 | 4 | 风扇转速 | RPM,小端 |
| 52 | 1 | 充电状态 | 0 未充电,1 小电流充电,2 大电流充电,3 已充满 |
向后兼容:这一帧只在尾部追加字段,从不改动已有偏移。解析时应按 "长度至少为 N 才读第 N 个字段"的方式写,不要假设固定总长。
时间与定时开机
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 9 / 10 | CPU → MCU | 年(2) 月 日 时 分 秒,共 7 字节 | 设置 MCU 时间 |
| 11 / 12 | CPU → MCU | 见下 | 设置定时开机 |
定时开机每条 8 字节:年(2) 月 日 时 分 星期,再加 1 字节匹配掩码。
掩码 bit0 年、bit1 月、bit2 日、bit3 时、bit4 分、bit5 星期,
置 1 表示该项参与匹配。分匹配必须为 1,否则该条被忽略。
星期按位匹配,例如 0b00000101 表示周日和周二。
一次最多 6 条,覆盖之前的设置,故该段最长 48 字节。
关机与复位
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 13 / 14 | MCU → CPU | 1 字节关机事件 | MCU 通知主机即将关机 |
| 15 / 16 | CPU → MCU | 无 | 主机请求关机 |
| 17 / 18 | MCU → CPU | 无 | MCU 通知主机复位 |
关机事件取值:0 按键强制关机,1 电池低电压关机,2 升级前关机,3 其他。
开机原因(27)
CPU → MCU 查询,应答 1 字节:
| 值 | 含义 |
|---|---|
| 1 | 按键开机 |
| 2 | 定时开机 |
| 3 | 车载模式:插入充电器开机 |
| 4 | 低电压关机后,插入充电器且电压满足条件开机 |
| 5 | 无电池开机 |
| 6 | 家庭模式:充电器电压满足条件开机 |
看门狗与电源策略
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 19 / 20 | CPU → MCU | 3 字节:开机超时、关机超时、喂狗超时(秒) | 设置软件看门狗时间 |
| 21 / 22 | CPU → MCU | 1 字节 | 0 = 插充电器不自动开机,1 = 插充电器开机。(低电压关机的机器即使设 0 也会开机) |
| 157 / 158 | CPU → MCU | 1 字节 | 硬件看门狗开关 |
| 161 / 162 | CPU → MCU | 1 字节 | 设置设备模式(车载 / 家庭等) |
电压阈值(23)
CPU → MCU,18 字节,9 个 uint16 小端。二代为 2S 电池组,单位 mV, 数值是整包电压:
- 电压高指示阈值
- 电压中指示阈值
- 电压低指示阈值
- 插充电器开机电压
- 充电器在位判定电压
- 充电器不在时关机电池阈值
- 工作中低电压提示阈值
- 大电流充电电压阈值
- 开机后持续 15 分钟判定满电的电压阈值
超出默认值 ±1000 mV 的设置视为无效,MCU 会退回默认值。
注意:一代文档里的 3850 / 3700 / 3600 等是单节数值。二代是 2S, 默认值不同(例如低电告警 6500、强制关机 6300),不要照搬一代的数字。 各阈值的实际效果见 Photonicat 2 LED 指示灯。
温度阈值(145)
CPU → MCU,2 字节:
- 第 1 字节:主机断电温度(℃),有效范围 55–80,默认 75
- 第 2 字节:充电指示灯关闭温度(℃),有效范围 50–60,默认 53
超范围返回错误,不生效。温度过高触发断电时会播放提示音, 见 Photonicat 2 提示音说明。
风扇
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 147 / 148 | CPU → MCU | 1 字节占空比(0–100) | 主机直接接管风扇。一旦下发,MCU 内部的温控 PID 不再控制风扇;超过 100 返回错误 |
| 151 / 152 | CPU → MCU | 目标温度 | 设置风扇 PID 的目标温度,默认 47 ℃ |
| 153 / 154 | CPU → MCU | —— | 读取当前目标温度 |
未被主机接管时,MCU 用增量式 PID 控制风扇:目标温度 47 ℃, 充电时占空比上限 85 %,纯电池运行时上限 40 %。
指示灯与声音
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 25 / 26 | CPU → MCU | 6 字节 | 设置网络指示灯:高电平时长(2)、低电平时长(2)、变换次数(2),时长单位 10 ms,次数 0 表示一直闪 |
| 155 / 156 | CPU → MCU | 1 字节 | 声光模式:0x00 全关,0x01 关声音开灯光,0x02 开声音关灯光,0x03 全开;传 0xFF 为查询当前值 |
| 163 / 164 | CPU → MCU | 见下 | 播放自定义蜂鸣器序列 |
自定义蜂鸣器序列(163)载荷格式:
[步进 1][步进 2]…[步进 N][循环模式 1 字节]
每个步进 4 字节:频率 uint16 小端(Hz,0 = 休止)+ 时长 uint16 小端(ms)。 循环模式 0 = 播放一次,1 = 循环。时长为 0 会被当作 1 ms。 声音被关闭时该命令不执行。内置提示音见 Photonicat 2 提示音说明。
电池与充电
| 命令 | 方向 | 内容 | 说明 |
|---|---|---|---|
| 165 / 166 | CPU → MCU | 1 字节百分比 | 设置充电上限,有效范围 50–100,100 = 不限制。超范围返回错误 |
| 167 / 168 | CPU → MCU | 应答 1 字节 | 读取当前充电上限 |
| 169 / 170 | CPU → MCU | 应答见下 | 读取电池详细信息 |
| 141 / 142 | CPU → MCU | 1 字节 | 已废弃,保留解析以兼容老主机,行为等同空操作 |
充电上限自固件 RA2E1260726005 起持久化在 MCU 侧,复位和 OTA 后不丢失。 到达上限后 MCU 断开充电 MOSFET,回落约 2 % 后恢复充电。
电池信息(169)应答格式
应答是逐版本向尾部追加的结构,当前长度 59 字节。偏移以应答的命令内容 首字节为 0,全部小端:
| 偏移 | 长度 | 字段 | 说明 |
|---|---|---|---|
| 0 | 2 | 学习到的满容量 | mAh |
| 2 | 2 | 循环次数 | —— |
| 4 | 2 | 标称满容量 | mAh |
| 6 | 1 | 标志位 | bit0 = 容量为学习值,bit1 = 学习窗口进行中 |
| 7 | 2 | 内阻 | mΩ,整包串联值,归一到 25 ℃ |
| 9 | 4 | 累计开机秒数 | —— |
| 13 | 2 | 电池中点电压 | mV(2P2S 中心抽头) |
| 15 | 2 | 内部 SOC | ×10,显示修饰前 |
| 17 | 1 | 学习到的显示空点 | %,0 = 未学习 |
| 18 | 2 | 显示变换 a | ×1000 |
| 20 | 2 | 显示变换 b | ×100,有符号 |
| 22 | 2 | 充电电流增益 | ×1000 |
| 24 | 2 | 电流微调 a | ×1000 |
| 26 | 2 | 电流微调 b | mA,有符号 |
| 28 | 2 | 估算剩余容量 | mAh |
| 30 | 4 | 累计消耗能量 | mWh |
| 34 | 4 | 累计充入能量 | mWh |
| 38 | 1 | 协议版本号 | 当前 9 |
| 39 | 1 | 电池健康度 | %,0xFF = 尚未学习 |
| 40 | 2 | 预计可用时间 | 分钟,0xFFFF = 非稳定放电 |
| 42 | 2 | 预计充满时间 | 分钟,0xFFFF = 非稳定充电 |
| 44 | 1 | 库仑计在用温度 | ℃,有符号 |
| 45 | 1 | 低温空点上移 | ×10 %,常温 = 0 |
| 46 | 2 | 内阻温度倍率 k(T) | ×1000,25 ℃ = 1000 |
| 48 | 1 | 回路寄生电阻 | mΩ(线缆+接插件+MOSFET)。电芯本体内阻 = 偏移 7 的值 − 本值 |
| 49 | 4 | MCU 总运行秒数 | 自 MCU 复位起,看门狗/异常复位会清零 |
| 53 | 4 | 距上次休眠唤醒秒数 | 从未休眠则等于总运行秒数 |
| 57 | 2 | 进入待机次数 | 饱和计数 |
偏移 38 之前的版本靠应答长度区分(≥7、≥13、≥15、≥28、≥38…); 从版本 9 起有显式版本号字段,建议新代码优先读它。这些字段的物理含义见 Photonicat 2 SOC 计算。
抬腕唤醒(149)
MCU → CPU 主动上报抬腕/移动事件。对应 sysfs 的
/sys/kernel/photonicat-pm/movement_trigger。
MCU 固件升级
这一组命令由 pcat-manager 的升级工具使用,不建议手工调用—— 中断升级流程可能使 MCU 无法启动。正常升级方式见 Photonicat 2 MCU 手动更新。
| 命令 | 说明 |
|---|---|
| 129 / 130 | 请求进入升级模式 |
| 203 / 204 | 开始 OTA |
| 205 / 206 | 传送版本号 |
| 207 / 208 | OTA 结束 |
| 209 / 210 | 回报"已收到结束" |
| 211 / 212 | 传输 OTA 数据 |
| 213 / 214 | 接收就绪 |
| 215 / 216 | 长度校验正确 |
| 217 / 218、219 / 220 | 新区域拷贝到备份区 / 拷贝完成 |
| 221 / 222、223 / 224 | 擦除 SPI 最新区 / 备份区 |
错误上报(201)
MCU → CPU,用于上报解析或执行错误。
与一代的差异
- 一代主机是 RK3568,二代是 RK3576
- 一代是单节锂电,命令 23 的阈值是单节电压(3850 / 3700 / 3600 等);
二代是 2S 电池组,同样的字段是整包电压(约为一代的两倍)
- 一代只有命令 1–28;二代在 129 以上扩展了 ID、风扇、温度、声光、
电池信息、充电上限等
- 一代靠 pcat-manager 的 socket 对外提供数据;二代已集成进内核,
推荐直接读 sysfs,见 Photonicat 2 sysfs
参考实现
- 主机侧用户态:pcat-manager
src/pmu-manager.c - 主机侧内核:
photonicat-pm(power_supply + RTC) - 一代参考:rockchip_rk3568_pcat_manager