- warm_esp.{h,c}:warm_restart() 记下开着的路(RTC_NOINIT,魔数 + 掩码 + 反码)→ gpio_hold 锁五根 EN → 重启;
目标镜像没有能力标记(第 288 字节 PRCAPS1,.rodata_custom_desc)就不锁 —— 老固件写不动锁住的 EN。
warm_take():软件复位 + 标记对得上才接管,一次性;再读 EN 真电平核对
- bringup:adopt 掩码;rail_en_init_keep() 接管的路写高、五根一律放开 hold(崩溃时旧锁可能还在);
刀片不在 / mux 失联的接管路立刻关(SLOT_EMPTY arg 1);第二段已开着的路不重开、不等 PG
- pca9555_init_keep():方向寄存器是本固件写的才留 VBUS(掉过电的片子锁存器是 0xFF),键 / EDL 清零
- HAL:hal_gpio_hold();ESP 输出脚配 INPUT_OUTPUT(读得到真电平);sim 给 hold 建模
- 事件 LOG_EV_OTA arg 7 = 接管;兜底定时器回滚故意不走接管
- 顶层 CMake:phonerail.h 进 CMAKE_CONFIGURE_DEPENDS(否则镜像头版本停在旧值);-u g_phonerail_caps 防 gc
- test_bringup 加 6 例(接管 / 非计划复位全关 / 空槽 / mux 失联 / PCA 掉过电 / hold 冻结),全工程 448 例全绿
- rack:固件库识别能力标记,推送对话框按「支持 / 不支持重启不断电」给不同提示(已部署)
- 需求文档:SR-6 改为「非计划复位全关」+ 计划内重启例外;§10.9 新增「重启不断电」
- 板 B:台架镜像(空槽强制 CH1 在位,未提交)开 CH1 → OTA 带重启 → 事件 18/7 mv=1,CH1 一直开着;
现跑 0.1.0-c3。未测:示波器看重启期间 EN / 输出毛刺(要插刀片)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
141 行
8.5 KiB
C
141 行
8.5 KiB
C
/* `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;
|
||
|
||
/* 「重启不断电」(warm_esp.c):计划内重启前开着的路,bit0 = CH1。0 = 普通启动。
|
||
这几路 EN 起来就是高(上一条命 hold 住的),第一段直接认领、不关;VBUS 也留着。
|
||
刀片不在 / mux 失联的,第一段里立刻关掉(`adopt_dropped`)—— 看不见的路不许带电(§5.8)。
|
||
⚠️ 只有软件复位 + RTC 里的标记对得上才会非 0;崩溃 / 看门狗 / 上电一律 0(SR-6)。 */
|
||
uint8_t adopt;
|
||
} 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 adopted; /* 接管了、一直开着没断过的路 */
|
||
uint8_t adopt_dropped;/* 想接管、但刀片不在 / mux 失联,已关掉 */
|
||
|
||
/* 第二段填。 */
|
||
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);
|
||
/* ↑ 已经开着的路(第一段接管的)不再上电、不等 PG,直接算进 `on` —— 不管 `want` 里有没有它:
|
||
接管的是「重启前的真实状态」,意图与之不符的那种(一路正在硬重启的断电阶段)本来就不会被接管。 */
|
||
|
||
/* 「意图」掩码的更新(`power` 命令改它,app_main 把结果存 NVS)。纯函数。 */
|
||
uint8_t bringup_want_update(uint8_t want, int rail, bool on);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* BRINGUP_H */
|