A6:PCA9555 驱动 + 「接地脚永远是输入」的硬约束

U23 @ 0x20,16 个脚全部是输入:5×EFUSE_FLT# + 5×EFUSE_PGOOD + BUCK_PG
+ INA_ALERT + 4 个焊死在地上的备用脚(P0_7 / P1_5~7)。位表与地址从
.claude/pcb1-parts.json 的真实焊盘网络逐脚核回来,与设计文档 §17.2 一致。

驱动根本不提供「把某个脚配成输出」的接口(和 sr595.h 不提供「抬 OE#」同一条
规矩),方向字一律过 pca9555_dir_safe(),不安全直接 abort。原因是 PCA9555 的
Output Port 寄存器复位值是 0xFF —— 把接地脚配成输出的那一刻它就输出高电平,
而真器件既不报错也不 NAK,只是发烫。

三种极性(FLT# 低有效 / PGOOD 高有效 / INA_ALERT 低有效)各自只在一个函数里
出现一次;上层问「有没有故障」,不许自己去 & 位。

sim 侧新增按 datasheet 建模的假 PCA9555:Output 复位 0xFF、输入按位合成、
接地脚被驱动时记短路、INT# 只被「读输入端口」清除。为此给假 I²C 总线加了一个
窃听钩子(POST_WRITE / PRE_READ)—— 通用寄存器表模拟不了「配成输出就对地
短路」这类事,以后再有这种器件照这个挂。

验收:8 条 ctest(81 用例)全绿;idf.py build 通过,pca9555.c.obj 在。
12 个「一定会被写出来的错」逐个注进去跑过,全部变红。

Co-Authored-By: Claude Opus 5 <[email protected]>
这个提交包含在:
zhou yang
2026-09-07 06:28:11 +08:00
共同撰写人 Claude Opus 5
父节点 ab37f9dc49
当前提交 eb3df9ff49
共修改 12 个文件,包含 962 行新增和 59 行删除
+20
查看文件
@@ -413,6 +413,26 @@ typedef struct {
同理,**PCA9555 的方向寄存器只能配成全输入**:备用脚 Port0[7] / Port1[7:5] 在硬件上
直接接地,配成输出并写 1 就是对地短路(设计文档 §17.2 已在图纸上注明)。
> **A6 已落地**:驱动在 `firmware/components/drv/include/pca9555.h`,
> **根本不提供「把某个脚配成输出」的接口**(和 sr595.h 不提供「抬 OE#」同一条规矩)。
> 方向字一律过 `pca9555_dir_safe()`,不安全直接 abort。
> 同处还记了四条这一片的实现约定:
> ① ⚠️ **Output Port 寄存器的复位值是 0xFF** —— 所以把接地脚配成输出的那一刻它就
> 输出高电平,中间没有「先写个 0 再说」的余地,这比「配错方向」本身更急;
> ② **极性反转寄存器必须无条件清零**,不能赌复位值:看门狗只复位 ESP32,
> PCA9555 不掉电,上一条命的残留值原样留着,而写错的现象是「五路同时报故障」
> 或者更糟的「五路故障全都看不见」,I²C 一切正常;
> ③ **三种极性**(FLT# 低有效 / PGOOD 高有效 / INA_ALERT 低有效)各自只在
> `pca9555_rail_fault()` 等四个函数里出现一次,上层不许自己去 & 位;
> ④ **INT# 是加速路径不是主路径**:它要读走输入端口才释放,漏读一次就再也等不到
> 下一个沿,所以 `t_safety` 必须无条件轮询(§10.3 的 20 ms 就是按这个排的)。
>
> ⚠️ **FLT 与 PG 两张位表这次确实是顺排的**(都是 `bit = rail - 1`),
> 和 INA226 地址、595 位号那两张表不一样。所以这里最容易写出来的错不是「算式」,
> 而是**把 Port0 和 Port1 搞反** —— 两个端口的 bit0~4 长得一模一样,搞反之后
> 「有故障」会被读成「电源良好」,方向正好相反,而且**静息态两个端口读回来都是
> 全 1,单看一帧完全看不出来**。`test_one_rail_at_a_time` 专门拦这一手。
### 10.5 电压通道:DAC 只做微调,而且是反向的
| 事实 | 含义 |