A5:74HC595 24 位链 + 影子寄存器单一写入点

15 路侧键 + 5 路 EDL_EN + HUB_RST 在一条 24 位链上,内存里只有一份影子,
唯一写入点是 sr595_flush()。发送顺序 U33 → U22 → U21,每字节 QH 先发。

位表是从 .claude/pcb1-parts.json 的真实焊盘网络逐脚核回来的,不是照文档抄 ——
设计文档 §17.2 那张是 09-04 的两片版,§26.18 重排后 15 路里有 12 路对不上。
顺手把 §17.2 与 §8.2 里过期的两张表都改了。

sim 侧新增按 datasheet 建模的假移位链(SRCLK 上升沿移一格、RCLK 上升沿锁存),
只看线上真实发生的边 —— 对着驱动自己的影子变量断言等于自己证明自己。
四个注错进去的 bug(字节序反、OE# 先使能、安全影子写 0、位表写成算式)全被拦住。

上电顺序按「先锁存安全值、再使能 OE#」写死:三片 MR# 接死在 +3V3,
上电时移位寄存器内容不确定,先拉低 OE# 就是把随机值放到 15 个栅极上。

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
这个提交包含在:
zhou yang
2026-09-06 19:33:51 +08:00
共同撰写人 Claude Opus 5
父节点 9eb1b39da6
当前提交 ab37f9dc49
共修改 13 个文件,包含 7895 行新增和 6869 行删除
+16
查看文件
@@ -475,6 +475,22 @@ ESP32.KEY_SER → U21 → U22 → U33 (先移入的字节落在链尾 U
> 的方式「临时全松开」——那会让 15 个栅极同时进高阻,靠的是每个栅极自己的 100 kΩ 下拉,
> 是复位路径,不是正常控制路径。
> **2026-09-06 A5 落地**:`components/drv/sr595.{h,c}`。影子是一个 24 位整数
> (bit0 = U21.QA 链首 … bit23 = U33.QH 链尾),唯一写入点是 `sr595_flush()`;
> 别处只准 `sr595_modify()` 改影子,组合键走 `sr595_write(mask, value)` 一帧发完。
> 位表见设计文档 §17.2(§26.18 重排后的那张,**不是 09-04 那张**)。
>
> 同处记下三条这一层的实现约定:
> - **上电顺序是「先锁存安全值,再使能 `OE#`」,不能换。** 三片的 `MR#` 接死在 +3V3,
> 没有复位线 ⇒ 上电时移位寄存器内容**不确定**。先拉低 `OE#` 就是把那坨随机值
> 放到 15 个栅极上 —— 五台手机的电源键可能一起被按下去。所以 `sr595_init()` 里
> `KEY_OE#` 在安全值锁存完之前**根本不配成输出**,靠板上 R609 上拉着。
> (ESP-IDF 的 `gpio_config()` 一配成输出就开始驱动,输出寄存器复位值是 0。)
> - **`HUB_RST` 低有效**,所以上电安全影子是 `1 << 23` 而不是 0。写成 0 的现象是
> 「Hub 插上枚举不出来」,而五路电压电流全都正常,看不出跟固件有关。
> - **发送失败要留着脏**(`sr595_flush()` 失败不清 dirty,下次重发整帧)。
> 丢了脏标志 = 链上和影子永久对不上,而后面每一次 flush 都会「成功」。
### 10.7 事件记录与存储
事件是 SW-3 的交付物,也是排查排线接触不良的唯一线索,所以**记录路径不能依赖上位机在线**。