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
5.5 KiB
5.5 KiB
交接
更新:2026-09-06 完成任务包 A5(74HC595 24 位链 + 影子寄存器单一写入点)
一句话现状
15 路侧键 + 5 路 EDL_EN + HUB_RST 全在一条 24 位链上,内存里只有一份影子,
唯一写入点是 sr595_flush()。位表从 PCB 的真实焊盘网络逐脚核回来(不是照文档抄),
上电顺序按「先锁存安全值、再使能 OE#」写死。7 条 ctest(61 个用例)全绿,
idf.py build 通过。
下一步
A6:PCA9555 驱动(需求 §10.4 末段)。验收断言:方向寄存器永远不会把 Port0[7] / Port1[7:5] 配成输出(配错直接 abort)—— 那 4 个备用脚在板上直接接地 (设计文档 §17.2 的注),配成输出并输出高就是对地短路。 A3/A4/A5/A6 四个驱动包彼此独立,做完 A6 就能进 A7(通道配置表)。
本次新增/修改的文件
components/drv/include/sr595.h— 24 位链的位表、引脚、影子契约(唯一对外契约)components/drv/sr595.c— 驱动本体(≈200 行,只经hal_gpio_*)components/phonerail_hal/sim/sim_sr595.c— 按 datasheet 建模的假移位链 (SRCLK 上升沿移一格、RCLK 上升沿锁存),加上sim_hal.h的一节声明components/phonerail_hal/sim/hal_gpio_sim.c— 加了一个窃听钩子给上面那个模型;hal_gpio_config(OUTPUT)也会触发(真芯片配成输出就开始驱动,OE#靠这一条)test/test_sr595.c(15 个用例)- 三处 CMakeLists +
main/phonerail.h(版本0.1.0-a5) ../需求文档.md§10.6、../五路直供电源板设计.md§17.2 — 记落地 + 修掉过期的位表 (§8.2 那行过期的 DAC 通道分配也顺手改了)
验收命令与结果
$ bash host/test.sh
100% tests passed, 0 tests failed out of 7 # +test_sr595(15)
$ .\build_idf.ps1 # PowerShell
phonerail.bin binary size 0x32550 bytes. ... 0xcdab0 bytes (80%) free.
Project build complete. # sr595.c.obj 在;bin 与 A4 同样大是正常的(还没人调它)
# 四个「一定会被写出来的错」逐个改进去跑过,确认测试拦得住:
# 字节顺序发反(U21 先发) -> test_byte_order 红
# 先使能 OE# 再锁存安全值 -> test_outputs_are_enabled_only_after_a_safe_latch 红
# 安全影子写成 0(HUB_RST 摁死) -> 三条红,其中一条直接说「上电后 Hub 不能被摁在复位里」
# 位表改成 3(rail−1)+key 的算式 -> sr595_modify 的 assert 当场 abort(碰到空脚 bit4)
踩到的坑(只写会再犯的)
- 位表不能照 §17.2 抄 —— 那张表是 09-04 的两片版,§26.18 重排之后 15 路里
12 路对不上。这次是从
.claude/pcb1-parts.json的真实焊盘网络逐脚核出来的 (顺手把 §17.2 和 §8.2 里过期的两张表都改了)。和 A4 的 DAC 通道分配同一类坑。 - ⚠️ CH4 的三个键碰巧就是 bit 9/10/11,和「顺排公式
3(rail−1)+key」一模一样。 所以「断言位表不是公式」只能整体断言(15 位里只有 3 位重合), 逐路写NOT_EQUAL到 CH4 就自己红了 —— 第一版正是这么写的。 HUB_RST是低有效(USB2517I 的RESET_N,§21.7)。全 0 的上电影子会把 Hub 一直摁在复位里,而五路手机的电压电流全都正常 —— 看起来跟固件一点关系都没有。- 上电顺序不能换:三片
MR#接死在 +3V3,没有复位线 ⇒ 上电时移位寄存器内容 不确定。所以KEY_OE#在安全值锁存完之前根本不配成输出(ESP-IDF 一配成输出 就开始驱动,输出寄存器复位值 0,等于当场使能)。板上 R609 100 kΩ 上拉扛着这一段。 - 假移位链值得写:A5 的两条验收断言如果只对着驱动自己的影子变量断言,那是自己
证明自己 —— 字节顺序发反、每帧多打一个时钟、RCLK 打早了,影子变量一律看不出来。
sim_sr595_*按 datasheet 建模,attach 时把移位寄存器塞成0xA5A5A5(真板子上电 就是不确定值),四个注错进去的 bug 全被它照出来了。 - cygwin 的偶发
Subprocess aborted又来了一次:这次是三条测试同时在 0.03 s 里挂, 其中两条根本不碰 595。重跑就正常。别去查代码。
这个驱动 / 这一层的几条约定(写 A9 / A12 之前看一眼)
- 除
sr595.c外,任何地方都不许自己去打 SER/SRCLK/RCLK。 改按键或 EDL 一律是 「sr595_modify()改影子 →sr595_flush()」。多处直接操作移位链的症状是 另一台手机的按键被顺手清掉,而且要两个动作正好撞在一起才复现。 - 组合键必须
sr595_write(mask, value)一次给两位(VOL− + PWR 落在同一帧)。 分两次写会先单按一个键。RCLK之前输出不变,所以整帧是原子的。 - 不许拿
OE#当「临时全松开」用(需求 §10.6):那是复位路径不是控制路径, 所以sr595.h根本没提供抬OE#的接口。 - rail 是 1~5,
sr595_key_bit()/sr595_edl_bit()越界 abort;sr595_modify()的 mask 碰到三个空脚(bit 4/8/12)也 abort —— 悄悄忽略的话那一位永远是 0,而「按键没反应」要到接上真手机才发现。 sr595_map_ok()还没人调:A7 的启动自检要把它和dac63204_map_ok()一起调上。- 按键的保持时长(100 ms / 2 s / 10 s)与序列互斥还没做,那是 A9 的活。 A5 只保证「写下去的那一帧是对的」。