A7:五路配置表 + 表驱动遍历 + 启动自检

六组编号(INA 地址 / DAC 片通道 / 三个按键位 / EDL 位 / 两根 EN 的 GPIO)拼成
一张 const 表 rail_cfg(1..5),没有一列是顺排的。开机 rail_selftest() 把它和
A3~A6 四个驱动的表逐格对账,再查全板引脚重复 / 越界,不过就 abort ——
那四个自检谓词至此全部有了调用点。

判据拎成 rail_selftest_table(t) 单独可调:真表是 const 的,不这么做就没法证明
「真有事的时候查得出来」。测试复制一张表出来逐样改坏,六种坏法都验过。

顺带修一个真 bug:HAL 两侧 GPIO 边界写的是 pin < 48,而 EFUSE_EN2 就在 IO48
上 —— CH2 的 eFuse 既开不了也关不掉。sim 与 ESP 两份都改成 0~48 含。

9 条 ctest(131 个用例)全绿,idf.py build 通过,16 条注错 15 条变红
(唯一没红的那条与原因记在 HANDOFF.md)。

Co-Authored-By: Claude Opus 5 <[email protected]>
这个提交包含在:
zhou yang
2026-09-07 07:13:04 +08:00
共同撰写人 Claude Opus 5
父节点 eb3df9ff49
当前提交 45de84ed3c
共修改 13 个文件,包含 1249 行新增和 63 行删除
@@ -9,9 +9,11 @@ typedef struct {
hal_gpio_mode_t mode;
int level;
uint32_t writes;
uint32_t seq; /* 最后一次被写时的全局序号,0 = 没写过 */
} pin_t;
static pin_t s_pin[SIM_GPIO_PINS];
static uint32_t s_seq; /* 全局写计数,从 1 开始发号 */
void sim_gpio_reset_internal(void); /* 只给 sim_hal_reset() 用 */
@@ -20,7 +22,11 @@ void sim_gpio_reset_internal(void); /* 只给 sim_hal_reset() 用 */
而 hal_gpio_write() 写同一个值也会计一次 writes。 */
void sim_sr595_gpio_hook(int pin, int level);
void sim_gpio_reset_internal(void) { memset(s_pin, 0, sizeof(s_pin)); }
void sim_gpio_reset_internal(void)
{
memset(s_pin, 0, sizeof(s_pin));
s_seq = 0;
}
static bool valid(int pin) { return pin >= 0 && pin < SIM_GPIO_PINS; }
@@ -51,6 +57,7 @@ hal_err_t hal_gpio_write(int pin, int level)
}
s_pin[pin].level = level ? 1 : 0;
s_pin[pin].writes++;
s_pin[pin].seq = ++s_seq;
sim_sr595_gpio_hook(pin, s_pin[pin].level);
return HAL_OK;
}
@@ -81,3 +88,5 @@ int sim_gpio_level(int pin)
}
uint32_t sim_gpio_writes(int pin) { return valid(pin) ? s_pin[pin].writes : 0; }
uint32_t sim_gpio_write_seq(int pin) { return valid(pin) ? s_pin[pin].seq : 0; }
@@ -66,7 +66,10 @@ void sim_i2c_set_present(uint8_t addr, bool present);
/* ---------------- GPIO ---------------- */
#define SIM_GPIO_PINS 48 /* ESP32-S3 的 GPIO 编号上限 */
/* ESP32-S3 的 GPIO 编号 **0~48**,所以数组要 49 个 —— `EFUSE_EN2` 就在 IO48 上。
A7 之前这里是 48,于是 CH2 的 eFuse 既开不了也**关不掉**(`hal_gpio_config()`
直接 HAL_ERR_ARG)。边界写成「个数」而不是「上限」,就是这么错的。 */
#define SIM_GPIO_PINS 49
/* 外部世界把某个**输入**脚拉成 level。对输出脚调用会 abort(那是总线打架)。 */
void sim_gpio_drive(int pin, int level);
@@ -77,6 +80,11 @@ int sim_gpio_level(int pin);
/* 被 hal_gpio_write() 写成功过几次。断言「改 CH1 没动 CH2~5」用得上(A5)。 */
uint32_t sim_gpio_writes(int pin);
/* 全局递增的写序号:每成功写一个脚 +1,本函数返回**该脚最后一次**被写时的序号
(从没被写过返回 0)。用来断言顺序 —— 「先断 VBUS 再关 eFuse」(A7)、
「17 ms 上电时序」(A9)这类事,光看每个脚的终值和次数是看不出来的。 */
uint32_t sim_gpio_write_seq(int pin);
/* ---------------- 74HC595 ×3 的 24 位链 ---------------- */
/* 按 datasheet 建模的假移位链,**只看线上真实发生的边**(SRCLK / RCLK 上升沿)。