固件 A15:启动顺序 + 降级矩阵(bringup.{h,c},已上板)
- 启动序列从 app_main.c 拆进 main/bringup.{h,c},宿主机可测:
bringup_devices()(§10.9 第 1~4 步)→ 起 t_safety → bringup_power_restore()(第 5~6 步)
- 六片 INA226 写 Config/Calibration(之前没做,电流恒 0);输入侧 0x43 登记对调接
- 按「意图」逐路上电、错开 100 ms、每路等 PG 500 ms,等不到关回去并记 LOG_EV_PG_TIMEOUT(17)
- 意图只由 power 命令改(cmd_env_t.intent → NVS phonerail/rail_want)
- §10.10 逐行降级:INA/DAC/PCA9555/mux/PRSNT#/CH224A;mux 失联时不碰主干
- BOOT 事件 arg = 复位原因;HUB_RST# 仍只在上电复位时脉冲
- rail_volt_init() 一片失败不再放弃另一片;CH224A 主干 / 通道 5 两处都找
- sim:sim_gpio_rise_us / sim_gpio_set_hook,sim_gpio_drive 可在配置前调
- test_bringup.c 24 例 + test_cmd 意图 1 例,共 425 例全绿;版本 0.1.0-a15
- rack:事件表加 17 PG_TIMEOUT(已部署)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -0,0 +1,130 @@
|
||||
/* `bringup` —— 启动顺序 + 降级矩阵(A15,需求 §10.9 / §10.10)。
|
||||
|
||||
A14 之前这一段整个写在 `app_main.c` 里,而 `app_main.c` 只进 IDF 目标 ——
|
||||
于是像 `ina226_set_reversed(INA226_ADDR_INPUT, true)` 这种「漏了就把正常供电
|
||||
判成反灌」的单行,**唯一的拦网是人眼**(计划 A15 那一行的 ⭐)。
|
||||
现在整段都在这里,宿主机上逐个「拔掉」器件跑得到。
|
||||
|
||||
---- 分两段,中间让 `t_safety` 起来 --------------------------------------
|
||||
|
||||
bringup_devices() §10.9 第 1~4 步:引脚安全态 → 总线 → 认件 / 初始化
|
||||
(缺件按 §10.10 降级,**不 abort**)
|
||||
── app_main 在这里 spawn(TASK_SAFETY) ──
|
||||
bringup_power_restore() §10.9 第 5~6 步:按上次的意图逐路上电、错开 100 ms、等 PG
|
||||
|
||||
拆开的理由:上电那一刻巡检必须已经在跑。§10.9 原文把「起链路任务」放在第 7 步,
|
||||
但没说巡检什么时候起;若等五路全开完(最坏 0.4 s 错开 + 0.5 s 等 PG)才起,
|
||||
这将近一秒里 SR-5 / SW-8 是瞎的。两段之间锁是通的(一切都经 `i2cbus_xact`),
|
||||
所以巡检与上电序列并发没有问题。
|
||||
|
||||
---- 分界线:什么 abort、什么降级 -----------------------------------------
|
||||
与 `selftest_or_die()` 同一条线:**固件自己错了 = 返回错误码(app_main abort),
|
||||
器件不在 = 降级、记事件、接着起**。前者只有三种:EN 脚配不上、I²C 外设起不来、
|
||||
`PRSNT#` 脚配不上 —— 全是引脚号 / 配置常量的问题,换块板子也一样。
|
||||
|
||||
---- §10.10 各行在这里怎么落地 -----------------------------------------
|
||||
某片 INA226 无应答 → 该路照常上电,`blind` 置位,记 I2C_LOST;
|
||||
判据自己会因为 `rail_ok` 为假而不武装(t_safety.c 的三道闸)
|
||||
DAC 无应答 → 不关输出,设定值影子回到 NVM 默认(3.90 V),记 I2C_LOST
|
||||
某片 PCA9555 无应答 → 不关输出(照常上电),`io_lost` 置位,记 I2C_LOST;
|
||||
等 PG 改按 INA226 电压判
|
||||
mux 连续选不中 → 先脉冲一次 `MUX_RST#`;仍不通 ⇒ 五路一路都不上电,记 MUX_LOST
|
||||
`PRSNT#` 为高 → 不初始化、不上电;只在「上次是开着的」时记 SLOT_EMPTY
|
||||
CH224A 读不到 / 偏低 → 不关输出,按读到的档位(读不到按 60 W)定上限,记 PD_LIMIT
|
||||
看门狗复位 → app_main 把复位原因填进 BOOT 事件的 arg(evlog_init_ex)
|
||||
I²C 总线挂死 → ⚠️ **本包没做**(9 个时钟的总线恢复在 HAL 层,见 HANDOFF) */
|
||||
#ifndef BRINGUP_H
|
||||
#define BRINGUP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal_err.h"
|
||||
#include "phonerail.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* §10.9 第 5 步:路与路之间错开多久。单路缓启动涌流 0.8 A,五路同开是 4 A 叠在
|
||||
12 V 输入上;错开 100 ms 后各路 11.5 ms 的斜坡完全不重叠。**是必须,不是讲究**。 */
|
||||
#define BRINGUP_STAGGER_MS 100
|
||||
|
||||
/* §10.9 第 6 步:开了电之后等 PG 最多等多久。与硬重启的 `ACT_HR_PG_TIMEOUT_MS`
|
||||
同一个数(PG 在斜坡中段就该来,~30 倍余量)。⚠️ 与硬重启**处理不同**:
|
||||
硬重启等不到 PG 不断电(那是运行中的手机),启动时等不到就关回去(§10.9 原文)。
|
||||
—— 但「PCA9555 读不到」不算「等不到」,那是看不见,见 `BRINGUP_ARG_BY_VOLT`。 */
|
||||
#define BRINGUP_PG_TIMEOUT_MS 500
|
||||
|
||||
/* 等 PG 期间多久看一眼。ESP 上 `hal_time_delay_ms()` 至少一个 tick(10 ms),
|
||||
所以实际是 10 ms;错开的 100 ms 因此会落在 100~110 ms 之间。 */
|
||||
#define BRINGUP_PG_POLL_MS 5
|
||||
|
||||
/* PCA9555 读不到时的 PG 替身:INA226 母线电压到了「设定值 − 这个数」就算好了。
|
||||
与 SR-5 的 ±100 mV 同一个数 —— 到了这个电压判据就不会再判它欠压。 */
|
||||
#define BRINGUP_PG_VOLT_MARGIN_MV 100
|
||||
|
||||
/* CH224A 读不到 / 读到 0 时按这个电流算上限(20 V × 3 A = 60 W,§10.10「最保守的 60 W」)。 */
|
||||
#define BRINGUP_PD_FALLBACK_MA 3000
|
||||
|
||||
/* `LOG_EV_PG_TIMEOUT` 的 arg 位。 */
|
||||
#define BRINGUP_ARG_FLT 0x01u /* 超时那一刻 FLT# 在报 */
|
||||
#define BRINGUP_ARG_BY_VOLT 0x02u /* 这一路 PCA9555 读不到,是按 INA226 电压判的 */
|
||||
|
||||
/* 整板级降级位(`bringup_report_t.deg`)。 */
|
||||
typedef enum {
|
||||
BRINGUP_DEG_MUX = 1u << 0, /* mux 复位后仍选不中:五路不上电 */
|
||||
BRINGUP_DEG_DAC_U6 = 1u << 1, /* 0x4A 不应答:CH1/2/4 停在 NVM 默认 */
|
||||
BRINGUP_DEG_DAC_U7 = 1u << 2, /* 0x4B 不应答:CH3/5 停在 NVM 默认 */
|
||||
BRINGUP_DEG_DAC_NVM = 1u << 3, /* 上电复位时读回的码不是 3.90 V(NVM 被改过) */
|
||||
BRINGUP_DEG_INPUT_INA = 1u << 4, /* 输入侧 0x43 不应答:整板功率看不见 */
|
||||
BRINGUP_DEG_PD = 1u << 5, /* CH224A 读不到:按 60 W */
|
||||
BRINGUP_DEG_PD_LOW = 1u << 6, /* CH224A 读到了,但低于 60 W */
|
||||
} bringup_deg_t;
|
||||
|
||||
typedef struct {
|
||||
/* 这次复位是不是上电复位。只有它为真才脉冲 `HUB_RST#`(app_main 的那一大段理由:
|
||||
其余复位原因下脉冲 = 自己把自己的 USB 控制台拔了),也只有它为真才核对
|
||||
DAC 的 NVM 默认值(热重启时 DAC 没断过电,里面是上一次命令设的值)。 */
|
||||
bool power_on_reset;
|
||||
} bringup_in_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t deg; /* bringup_deg_t 的或 */
|
||||
|
||||
/* 每路一位,bit0 = CH1。 */
|
||||
uint8_t empty; /* `PRSNT#` 高:刀片不在位 */
|
||||
uint8_t blind; /* 刀片 INA226 不应答:失去遥测、判据不武装(「盲跑」) */
|
||||
uint8_t io_lost; /* 刀片 PCA9555 不应答:FAULT/PG 看不见,VBUS 关不掉 */
|
||||
|
||||
/* 第二段填。 */
|
||||
uint8_t want; /* 请求恢复的(上次的意图) */
|
||||
uint8_t on; /* 最后真的开着的 */
|
||||
uint8_t pg_fail; /* 等不到 PG、已关回去 */
|
||||
uint8_t unverified; /* PCA9555 与 INA226 都读不到:开着,但确认不了 */
|
||||
uint32_t on_ms[PHONERAIL_RAIL_COUNT]; /* 每路 EN 抬高的时刻(没开是 0) */
|
||||
|
||||
uint32_t pd_ma; /* CH224A 读到的档位电流(读不到是 0) */
|
||||
uint32_t pd_limit_mw; /* 整板功率上限(读不到按 60 W) */
|
||||
uint16_t dac_nvm_mv[PHONERAIL_RAIL_COUNT]; /* 上电复位时读回的每路设定(没读是 0) */
|
||||
} bringup_report_t;
|
||||
|
||||
/* §10.9 第 1~4 步。返回非 HAL_OK **只**表示固件 / 引脚配置本身错了(见文件头),
|
||||
调用方应当 abort;器件缺失一律 HAL_OK + `r` 里的降级位 + 事件。
|
||||
⚠️ 调之前 `evlog_init_ex()` 要已经跑过:这里产生的事件要排在 BOOT 那一条之后。 */
|
||||
hal_err_t bringup_devices(const bringup_in_t *in, bringup_report_t *r);
|
||||
|
||||
/* §10.9 第 5~6 步。`want` 是上次的每路意图(bit0 = CH1,来自 NVS;新板是 0 = 全不开)。
|
||||
逐路:能开的开、错开 `BRINGUP_STAGGER_MS`、各自等 PG(`BRINGUP_PG_TIMEOUT_MS`),
|
||||
等不到就关回去并记 `LOG_EV_PG_TIMEOUT`。阻塞,最坏约 0.4 + 0.5 s。
|
||||
不能开的(空槽 / mux 失联)直接跳过,空槽且想开的记一条 SLOT_EMPTY。 */
|
||||
void bringup_power_restore(uint8_t want, bringup_report_t *r);
|
||||
|
||||
/* 「意图」掩码的更新(`power` 命令改它,app_main 把结果存 NVS)。纯函数。 */
|
||||
uint8_t bringup_want_update(uint8_t want, int rail, bool on);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BRINGUP_H */
|
||||
在新工单中引用
屏蔽一个用户