/* 假的 74HC595 ×3 移位链 —— 挂在 GPIO sim 上,只看**线上真实发生的边**。 为什么要这么一个东西:A5 的两条验收断言(改一路不动别路、字节顺序 U33→U22→U21) 如果只对着驱动自己的影子变量断言,那是**自己证明自己** —— 字节顺序发反了、 每帧多打一个时钟、RCLK 在数据发完之前就打了,影子变量一律看不出来。 所以这里按 datasheet 建模:SRCLK 上升沿移一格,RCLK 上升沿把移位寄存器抄进输出锁存器。 24 级的编号与 sr595.h 一致:0 = U21.QA(DS 进来的第一级),23 = U33.QH(链尾)。 */ #include #include #include "sim_hal.h" typedef struct { bool attached; int ser_pin, srclk_pin, rclk_pin, oe_pin; int ser, srclk, rclk, oe; /* 当前电平;oe 初值 1 = 板上 R609 拉着 */ uint32_t shift; /* 移位寄存器(未锁存) */ uint32_t out; /* 输出锁存器 */ uint32_t clocks; /* SRCLK 上升沿总数 */ uint32_t latches; /* RCLK 上升沿总数 */ bool enabled_once; uint32_t enable_latches; /* OE# 第一次被拉低时,已经锁存过几次 */ uint32_t enable_out; /* OE# 第一次被拉低那一刻,输出锁存器里是什么 */ } chain_t; static chain_t s_ch; void sim_sr595_reset_internal(void); /* 只给 sim_hal_reset() 用 */ void sim_sr595_gpio_hook(int pin, int level); void sim_sr595_reset_internal(void) { memset(&s_ch, 0, sizeof(s_ch)); } void sim_sr595_attach(int ser_pin, int srclk_pin, int rclk_pin, int oe_pin) { memset(&s_ch, 0, sizeof(s_ch)); s_ch.attached = true; s_ch.ser_pin = ser_pin; s_ch.srclk_pin = srclk_pin; s_ch.rclk_pin = rclk_pin; s_ch.oe_pin = oe_pin; /* `OE#` 上电就被 R609 拉高 —— 高阻,不是 0。 */ s_ch.oe = 1; /* 上电后移位寄存器与输出锁存器的内容**不确定**(`MR#` 接死在 +3V3,没有复位线)。 这里塞一个显眼的非零值:驱动要是先使能 OE# 再锁存安全值, `sim_sr595_enable_outputs()` 就会把这坨脏东西原样报出来。 */ s_ch.shift = 0x00A5A5A5u & 0x00FFFFFFu; s_ch.out = s_ch.shift; } void sim_sr595_gpio_hook(int pin, int level) { if (!s_ch.attached) { return; } level = level ? 1 : 0; if (pin == s_ch.ser_pin) { s_ch.ser = level; } else if (pin == s_ch.srclk_pin) { if (level == 1 && s_ch.srclk == 0) { /* 上升沿:整条链往编号大的方向挪一格 */ s_ch.shift = ((s_ch.shift << 1) | (uint32_t)s_ch.ser) & 0x00FFFFFFu; s_ch.clocks++; } s_ch.srclk = level; } else if (pin == s_ch.rclk_pin) { if (level == 1 && s_ch.rclk == 0) { s_ch.out = s_ch.shift; s_ch.latches++; } s_ch.rclk = level; } else if (pin == s_ch.oe_pin) { if (level == 0 && s_ch.oe != 0 && !s_ch.enabled_once) { s_ch.enabled_once = true; s_ch.enable_latches = s_ch.latches; s_ch.enable_out = s_ch.out; } s_ch.oe = level; } } uint32_t sim_sr595_outputs(void) { return s_ch.out; } uint32_t sim_sr595_shift(void) { return s_ch.shift; } uint32_t sim_sr595_clocks(void) { return s_ch.clocks; } uint32_t sim_sr595_latches(void) { return s_ch.latches; } int sim_sr595_oe(void) { return s_ch.oe; } bool sim_sr595_enabled(void) { return s_ch.enabled_once; } uint32_t sim_sr595_enable_latches(void) { return s_ch.enable_latches; } uint32_t sim_sr595_enable_outputs(void) { return s_ch.enable_out; } int sim_sr595_pin(int bit) { assert(bit >= 0 && bit < 24); if (s_ch.oe) { return -1; /* 高阻。栅极侧靠自己的 100 kΩ 下拉,HUB_RST 侧靠 R716 上拉 */ } return (int)((s_ch.out >> bit) & 1u); }