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 行删除
+38 -1
查看文件
@@ -1,13 +1,50 @@
/* ESP32-S3 入口。只在 ESP-IDF 目标里编译,宿主机构建不包含本文件。 */
#include <stdlib.h>
#include "esp_log.h"
#include "hal_time.h"
#include "phonerail.h"
#include "rail_cfg.h"
static const char *TAG = "phonerail";
/* 启动自检(需求 §10.4):五路的地址 / 位号 / 引脚无重复、无越界,
而且那张五路表和四个驱动自己的表没有分家。
⚠️ **不过就 abort,不降级。** 这里查的全是编译进固件的常量表,
查不过 = 固件本身写错了,不是硬件坏了 —— §10.10 的降级矩阵管的是后者。
带着一张错表跑起来的样子是「命令发给了另一路」,五台手机全在跑、
一个错误码都不报,谁也不会去怀疑它。 */
static void selftest_or_die(void)
{
const uint32_t bad = rail_selftest();
if (bad == 0) {
ESP_LOGI(TAG, "五路配置表自检通过");
return;
}
for (uint32_t bit = 1; bit != 0; bit <<= 1) {
if ((bad & bit) != 0) {
ESP_LOGE(TAG, "自检失败:%s (0x%02x)", rail_selftest_str(bit), (unsigned)bit);
}
}
abort();
}
void app_main(void)
{
/* 引脚表与外设初始化留到 A7/A8;这里只确认 HAL 真的被链进来了。 */
ESP_LOGI(TAG, "PhoneRail %s boot, %d rails, t=%u ms", phonerail_version(),
PHONERAIL_RAIL_COUNT, (unsigned)hal_time_now_ms());
selftest_or_die();
/* 十根 EN 线配成输出并全部拉低。**先于一切外设**:DAC / eFuse 一上电就有
输出,这两根线这时必须已经确定是低的。 */
const hal_err_t err = rail_en_init();
if (err != HAL_OK) {
ESP_LOGE(TAG, "EN 引脚初始化失败:%s", hal_err_str(err));
abort();
}
ESP_LOGI(TAG, "五路输出与 VBUS 全部关闭,等待 A8 的任务骨架");
/* 器件初始化与五个任务留到 A8/A15。 */
}