升级校验、启动信息与复位流程
本页文档覆盖 AC63 系列 MCU(以 AC635N 为代表)从 uboot 引导结束到用户应用启动之间的完整 boot 流程,包括升级模式校验(check_upgrade())、启动信息(BOOT_INFO)的传递与初始化,以及复位(cpu_reset() / power_reset_source_dump())相关的实现机制。
Purpose and Scope
本页面向需要理解芯片上电后"谁先执行、按什么顺序执行、如何进入升级模式、如何复位"的固件开发与维护工程师,系统性地讲解 boot 阶段的三大能力:
- 升级校验:boot 早期通过驻留内存中的 magic 数据判断是否需要进入 USB/UART 升级模式,涉及
sdk/bsp/AC635N/src/hwi.c中的check_upgrade()、chip_reboot_entry_usb_upgrade_mode()、chip_reboot_entry_uboot_uart_upgrade_mode()等接口。 - 启动信息:uboot 通过
BOOT_DEVICE_INFO向 app 传递 flash/VM/时钟裁剪等信息,boot 侧将其拷贝到全局boot_info(BOOT_INFO),供vm_init_app()等后续模块使用,结构定义见sdk/bsp/AC635N/include/asm/boot.h。 - 复位流程:
cpu_reset()硬件复位、power_reset_source_dump()复位源打印、看门狗初始化wdt_init(WDT_4S),以及"写 magic → 复位 → 新固件检测 magic → 进入升级模式"这一闭环机制。
以下主题属于相邻能力,本页不做展开,请参考各自页面:
- OTA 升级数据下载与校验(app 侧升级协议、固件镜像校验)——属于升级应用层,不在 boot 阶段。
- VM 参数存储——本页只说明
vm_init_app()如何消费boot_info.vm完成初始化,不展开 VM 读写 API。 - 电源管理与低功耗——本页只涉及复位源信息打印,不展开电源模式配置。
Overview
AC63 系列 MCU 的启动链分为三段:uboot(引导)→ boot(本代码,sdk/bsp/AC635N/src/boot.c)→ user app(user_main())。uboot 负责最底层的 flash 搬运与硬件初始化,之后跳转到 boot 的 main();boot 完成看门狗、升级校验、eFuse、时钟、内存、VM 等基础初始化后,最终将控制权交给用户应用。
整个 boot 阶段的设计核心是一个**"魔法数(magic)+ 复位"机制**:
- 应用或工具需要进入升级模式时,先在特定内存地址写入一串特征字节(magic),然后调用
cpu_reset()复位; - 复位后芯片重新走 boot 流程,
main()在非常早期(efuse_init()之前)调用check_upgrade()检查 magic; - 若 magic 匹配,则清除 magic 并进入对应的升级模式(USB 升级或 uboot UART 升级);否则继续正常启动。
这一机制的优势在于:升级入口不依赖任何持久化标志位,天然支持"掉电复位后仍能进入升级模式"的可靠性要求,同时 magic 校验失败时(内存被破坏)自动回退到正常启动路径。
关键术语:
| 术语 | 含义 |
|---|---|
BOOT_INFO | boot 全局启动信息结构,存放于 .boot_info 段,由 boot_info_init() 填充 |
BOOT_DEVICE_INFO | uboot 传入的原始设备信息结构(含 flash_head 指针) |
ISR_ENTRY | 中断向量表入口地址,USB 升级 magic 的驻留位置 |
NV_RAM_LIST_ADDR | 不掉电 RAM 列表地址(nvram_list),UART 升级 magic 的驻留位置 |
cpu_reset() | 硬件看门狗复位接口,触发整机复位 |
power_reset_source_dump() | 打印本次复位的来源(上电/看门狗/软复位等) |
Architecture
flowchart TD
subgraph sg_Uboot["uboot 引导阶段"]
UBoot["uboot"]
DevInfo["BOOT_DEVICE_INFO<br/>(flash_head / sfc / chip_id / trim)"]
end
subgraph sg_Boot["boot 启动阶段 (boot.c main)"]
Main["main()"]
Wdt["wdt_init(WDT_4S)"]
CheckUp["check_upgrade()"]
Efuse["efuse_init()"]
ResInit["resfile_init()"]
Clk["clk_voltage_init + clk_early_init"]
PortInit["port_init() + debug_uart_early_init()"]
ResetDump["power_reset_source_dump()"]
MemInit["memory_init()"]
VmInit["vm_init_app()"]
BoardInit["board_init()"]
UserMain["user_main()"]
end
subgraph sg_Upgrade["升级入口 (hwi.c)"]
UsbMagic["usb_upgrade_mode_magic @ ISR_ENTRY"]
UartMagic["uboot_uart_upgrade_magic @ NV_RAM_LIST_ADDR"]
UsbMode["usb_upgrade_mode()"]
UartMode["uboot UART 升级"]
Reset["cpu_reset()"]
BootInfo["全局 BOOT_INFO boot_info"]
end
UBoot -->|"传递"| DevInfo
DevInfo -->|"跳转"| Main
Main --> Wdt
Wdt --> CheckUp
CheckUp -->|"magic 匹配"| UsbMagic
CheckUp -->|"进入"| UsbMode
UsbMagic --> UsbMode
CheckUp -->|"magic 不匹配,继续启动"| Efuse
Efuse --> ResInit --> Clk --> PortInit --> ResetDump
ResetDump --> MemInit --> VmInit --> BoardInit --> UserMain
BootInfo -.->|"vm_init_app 消费"| VmInit
UsbMode --> Reset
UartMagic -.->|"写 magic + 复位"| Reset
Reset -.->|"重新走 boot"| Main
架构说明:uboot 通过 BOOT_DEVICE_INFO 结构向 boot 传递 flash 与芯片信息;main() 的顺序是经过精心安排的——看门狗最先开启以保证异常可恢复,check_upgrade() 紧跟其后以保证升级入口在一切复杂初始化(时钟、内存、VM)之前被检测到;power_reset_source_dump() 在串口初始化完成后打印复位来源,便于现场排查"为什么复位";vm_init_app() 依赖 boot_info.vm(由 uboot 的 sdfile 提供),因此必须排在 memory_init() 之后、board_init() 之前。升级闭环通过"写 magic → cpu_reset() → 重新进入 main() → check_upgrade() 匹配"完成,无需持久化标志位。
启动信息:BOOT_INFO 的传递与初始化
数据结构
boot.h 定义了从 uboot 到 boot 的信息传递契约。最上层是 BOOT_DEVICE_INFO(uboot 传入),boot 侧将其关键字段拷贝到全局 BOOT_INFO boot_info:
typedef struct _boot_info {
struct vm_info vm; //VM 参数:对齐方式、flash 地址、大小(来自 sdfile)
struct sfc_info sfc; //flash 基地址与 app 逻辑地址(来自 uboot)
u32 flash_size; //flash 总容量(来自 uboot)
u16 chip_id; //芯片 ID(来自 uboot)
u16 trim_value; //芯片裁剪值(来自 uboot)
struct bt_mac_addr mac; //蓝牙 MAC 地址及 CRC
} BOOT_INFO;
Source: boot.h
配套的 vm_info、sfc_info、flash_head 分别描述 VM 参数(align 表示按 n×256 对齐)、flash 地址映射以及 flash 文件系统头部(含 crc、vid、FlashSize、FsVersion、pid 等)。BOOT_DEVICE_INFO 则把 flash_head 以指针形式传入,boot 通过它读取 FlashSize 与 align。
boot_info 的填充:boot_info_init()
全局 boot_info 被放置在专用的 .boot_info 段(sec(.boot_info)),其内容由 boot_info_init() 从 uboot 传来的 BOOT_DEVICE_INFO 拷贝而来:
void boot_info_init(void *_info)
{
BOOT_DEVICE_INFO *info = (BOOT_DEVICE_INFO *)_info;
boot_info.flash_size = info->fs_info->FlashSize;
boot_info.vm.align = info->fs_info->align;
boot_info.chip_id = info->chip_id;
boot_info.trim_value = info->trim_value;
memcpy(&boot_info.sfc, &info->sfc, sizeof(struct sfc_info));
}
Source: boot.c
设计意图:uboot 与 boot 之间通过结构体拷贝 + 专用段解耦。.boot_info 段保证 boot_info 在链接时处于固定、可被后续模块引用的位置;拷贝而非直接复用 uboot 内存,使 boot 侧获得独立、可校验的视图,避免对 uboot 栈/堆的隐性依赖。
VM 参数消费:vm_init_app()
vm_init_app() 是 boot_info.vm 的主要消费者。它根据 vm.align 决定操作模式:按页(page,1)还是按扇区(sector,0),并对容量做上限保护(页模式 8KB、扇区模式 16KB),随后调用 vm_init():
void vm_init_app()
{
u32 saddr = 0;
u32 size = 0;
u8 mode = 0;
struct vm_info vm;
memcpy(&vm, &boot_info.vm, sizeof(struct vm_info));
saddr = vm.vm_saddr;
size = vm.vm_size;
if (vm.align == 1) {
mode = 1; //page operated
size = size > (8 * 1024) ? (8 * 1024) : size;
} else {
mode = 0; //sector operated
size = size > (16 * 1024) ? (16 * 1024) : size;
}
log_info("vm_info:addr:0x%x, len:0x%x, mode:0x%x", saddr, size, mode);
if (vm_init(NULL, saddr, size, mode) != VM_ERR_NONE) {
ASSERT(0, "vm init err");
}
log_info("vm init ok");
}
Source: boot.c
注意 vm_init_app() 中的容量上限是 boot 侧的防御性约束:即使 sdfile 配置了更大的 VM 区域,boot 也只按保守上限初始化,降低越界风险;初始化失败直接 ASSERT 停机,避免带病运行导致 VM 数据损坏。
升级校验:check_upgrade() 与 magic 机制
USB 升级模式
hwi.c 中定义了 16 字节的 USB 升级 magic,并驻留在中断向量表入口 ISR_ENTRY 偏移 IRQ_SOFT0_IDX * 4 处。选择这个位置的原因:它位于 RAM 固定区域,复位不掉电(cpu_reset() 属于软复位),且不占用普通数据区:
static const u8 usb_upgrade_mode_magic[16] = {
0x33, 0xEA, 0xBB, 0x74, 0x85, 0x71, 0x8F, 0x32, 0xA7, 0x3C, 0xF0, 0x18, 0x4D, 0x20, 0x08, 0xF7
};
void check_upgrade()
{
char *magic_str = (char *)ISR_ENTRY;
magic_str += IRQ_SOFT0_IDX * 4;
if (memcmp(magic_str, usb_upgrade_mode_magic, sizeof(usb_upgrade_mode_magic)) == 0) {
memset(magic_str, 0, sizeof(usb_upgrade_mode_magic));
void usb_upgrade_mode();
usb_upgrade_mode();
}
}
Source: hwi.c
关键点:
- 匹配即清:一旦确认 magic,立即
memset清零,防止下次复位重复进入升级模式造成死循环。 - 不匹配即放行:magic 被破坏(例如内存异常写)时
memcmp不匹配,自动走正常启动路径,系统仍可恢复。
请求进入升级模式:chip_reboot_entry_usb_upgrade_mode()
应用侧(或升级工具)通过写 magic + 复位来请求升级:
void chip_reboot_entry_usb_upgrade_mode()
{
char *magic_str = (char *)ISR_ENTRY;
magic_str += IRQ_SOFT0_IDX * 4;
memcpy(magic_str, usb_upgrade_mode_magic, sizeof(usb_upgrade_mode_magic));
cpu_reset();
}
Source: hwi.c
写 magic 与 cpu_reset() 之间没有屏障延迟——magic 写入后立即复位,避免窗口期内其他代码覆盖该区域。
uboot UART 升级模式
UART 升级走另一条 magic 通道:nvram_list(NV_RAM_LIST_ADDR)是掉电保持的 RAM 列表,其起始位置驻留 8 字节 magic:
static u8 uboot_uart_upgrade_mode_magic[8] = {
'u', 'b', 'o', 'o', 't', 0x5a, 's', 't',
};
static u8 uboot_uart_upgrade_succ_magic[8] = {
'u', 'b', 'o', 'o', 't', 0xa5, 'o', 'k',
};
//须在memory_init();前检测该标志
void check_uboot_uart_upgrade()
{
if (memcmp((char *)NV_RAM_LIST_ADDR, uboot_uart_upgrade_succ_magic, sizeof(uboot_uart_upgrade_succ_magic)) == 0) {
memset((char *)NV_RAM_LIST_ADDR, 0, sizeof(uboot_uart_upgrade_succ_magic));
log_info("++++++++++++++++++++++++uboot uart upgrade succ");
}
}
void hw_mmu_disable(void);
void chip_reboot_entry_uboot_uart_upgrade_mode()
{
hw_mmu_disable();
memcpy((char *)NV_RAM_LIST_ADDR, uboot_uart_upgrade_mode_magic, sizeof(uboot_uart_upgrade_mode_magic));
cpu_reset();
}
Source: hwi.c
设计要点:
- 进入 UART 升级前必须调用
hw_mmu_disable()关闭 MMU,因为 uboot 运行在无 MMU 环境下,直接写 RAM 地址需要在物理地址空间操作。 - 成功升级后 uboot 会写入
uboot_uart_upgrade_succ_magic('u','b','o','o','t',0xa5,'o','k'),boot 侧在memory_init()之前检测该标志并打印成功日志——注释明确强调时序约束,因为memory_init()会重建内存管理,可能破坏该区域内容。
复位流程
复位接口:cpu_reset()
cpu_reset() 是 boot/驱动层统一使用的硬件复位入口(实现于 sdk/bsp/AC635N/src/debug.c,亦被充电检测、升级入口等模块调用)。复位后芯片重新从 uboot/boot 引导,之前写入的 magic 数据(位于不掉电 RAM 区域)得以保留,从而构成"请求升级 → 复位 → 检测 magic → 进入升级模式"的闭环。check_upgrade() 相关代码见上文;debug.c 中典型的调用形如:
{
cpu_reset();
}
Source: debug.c
除升级外,cpu_reset() 也用于应用层软复位(如 chargestore_hw.c 中设置 nvram_set_boot_state(UPGRADE_UART_SOFT_KEY) 后复位进入 UART 升级状态)。
复位源打印:power_reset_source_dump()
main() 在串口初始化完成后调用 power_reset_source_dump(),将本次复位的来源(上电复位、看门狗复位、软复位等)打印到日志。该调用的位置(debug_uart_early_init() 之后、memory_init() 之前)保证复位原因信息在内存初始化前即可输出,便于现场定位"芯片为何反复复位"。
log_info("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log_info(" boot %s %s", __DATE__, __TIME__);
clk_dump();
log_info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
power_reset_source_dump();
Source: boot.c
看门狗:wdt_init(WDT_4S)
main() 的第一条有效语句就是 wdt_init(WDT_4S),将看门狗超时配置为 4 秒。这是整个 boot 流程的第一优先级:一旦后续任何初始化卡死(时钟、内存等),看门狗会在 4 秒内强制复位,保证系统可恢复。wdt_reset_mode()(sdk/bsp/AC635N/src/wdt.c)则用于配置复位模式(中断/复位),属于看门狗的高级用法。
核心启动流程(Core Flow)
sequenceDiagram
participant U as uboot
participant B as boot.c main()
participant H as hwi.c (升级校验)
participant P as power/debug
participant A as user app
U->>B: 跳转,携带 BOOT_DEVICE_INFO
B->>B: wdt_init(WDT_4S) 先开看门狗
B->>H: check_upgrade()
alt ISR_ENTRY 处 USB magic 匹配
H->>H: 清除 magic
H->>A: 进入 usb_upgrade_mode()(不再走正常启动)
else magic 不匹配
H-->>B: 正常继续
B->>B: efuse_init() / resfile_init()
B->>B: clk_voltage_init + clk_early_init(含 4×100ms 延时)
B->>B: port_init() + debug_uart_early_init()
B->>P: power_reset_source_dump() 打印复位源
B->>B: memory_init()
B->>B: vm_init_app()(消费 boot_info.vm)
B->>B: board_init() + debug_init()
B->>A: user_main() 移交控制权
end
Note over A,H: 需要升级时:写 magic + cpu_reset(),重新走上述流程
时序要点:
- 看门狗最先:
wdt_init(WDT_4S)为整个 boot 提供兜底恢复能力。 - 升级校验第二:
check_upgrade()必须在efuse_init()、时钟、内存初始化之前执行,因为升级模式(尤其 UART/uboot 场景)依赖早期干净的 RAM 状态。 - 时钟稳定等待:
clk_early_init()后连续 4 次mdelay(100),共约 400ms,等待 PLL/RC 时钟稳定,避免外设与 flash 在时钟不稳时访问出错。 - 复位源尽早打印:
power_reset_source_dump()在memory_init()之前,保证日志不依赖内存管理系统。 - VM 初始化位于内存初始化之后:
vm_init_app()需要boot_info.vm(uboot/sdfile 提供)与内存管理就绪。 - 最终移交:
board_init()完成板级外设配置后,main()调用user_main()进入应用主循环。
使用示例
以下示例全部提取自本仓库真实源码,展示三类典型用法。
示例 1:应用请求进入 USB 升级模式
固件在需要进入 USB 升级(例如按键组合、上位机指令)时,直接写入 magic 并复位,无需任何额外标志文件:
void chip_reboot_entry_usb_upgrade_mode()
{
char *magic_str = (char *)ISR_ENTRY;
magic_str += IRQ_SOFT0_IDX * 4;
memcpy(magic_str, usb_upgrade_mode_magic, sizeof(usb_upgrade_mode_magic));
cpu_reset();
}
Source: hwi.c
示例 2:应用请求进入 uboot UART 升级模式
与 USB 路径不同,UART 路径需要先关闭 MMU,再写 NV_RAM_LIST_ADDR 处的 magic:
void hw_mmu_disable(void);
void chip_reboot_entry_uboot_uart_upgrade_mode()
{
hw_mmu_disable();
memcpy((char *)NV_RAM_LIST_ADDR, uboot_uart_upgrade_mode_magic, sizeof(uboot_uart_upgrade_mode_magic));
cpu_reset();
}
Source: hwi.c
示例 3:boot 消费 uboot 传递的启动信息
boot_info_init() 从 BOOT_DEVICE_INFO 提取 flash 容量、VM 对齐方式、芯片 ID 与裁剪值,是后续 vm_init_app() 等模块的数据来源:
void boot_info_init(void *_info)
{
BOOT_DEVICE_INFO *info = (BOOT_DEVICE_INFO *)_info;
boot_info.flash_size = info->fs_info->FlashSize;
boot_info.vm.align = info->fs_info->align;
boot_info.chip_id = info->chip_id;
boot_info.trim_value = info->trim_value;
memcpy(&boot_info.sfc, &info->sfc, sizeof(struct sfc_info));
}
Source: boot.c
配置选项
boot 阶段的配置分散在 boot.c 的宏定义与初始化调用中,以下为源码中可直接确认的选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
WDT_4S(wdt_init 参数) | 枚举 | 4 秒超时 | 看门狗超时时间,boot 全程兜底复位 |
TCFG_CLOCK_MODE | 枚举 | CLOCK_MODE_ADAPTIVE | 自适应时钟模式,用于 clk_voltage_init |
SYSVDD_VOL_SEL_126V | 枚举 | 1.26V | 系统内核电压档位 |
TCFG_LOWPOWER_POWER_SEL | 枚举 | PWR_LDO15 | 低功耗电源选择(LDO 1.5V) |
VDC13_VOL_SEL_140V | 枚举 | 1.40V | 1.3V 域电压档位 |
SYS_CLOCK_INPUT_PLL_RCL | 枚举 | RC 32.768K + PLL 24M | 系统时钟输入源与频率(另有 SYS_CLOCK_INPUT_PLL_BT_OSC 备选) |
vm.align(来自 uboot) | u8 | 0(扇区模式) | VM 操作模式:1=按页(上限 8KB),0=按扇区(上限 16KB) |
配置出处:boot.c
API Reference
void check_upgrade(void)
Boot 早期升级模式检测。检查 ISR_ENTRY + IRQ_SOFT0_IDX * 4 处 16 字节是否等于 usb_upgrade_mode_magic;匹配则清零 magic 并进入 usb_upgrade_mode()。
- 调用时机:
main()中wdt_init()之后、efuse_init()之前。 - 无返回值;匹配时流程不再返回。
- 定义见 hwi.c#L278-L288。
void chip_reboot_entry_usb_upgrade_mode(void)
写入 USB 升级 magic 到 ISR_ENTRY + IRQ_SOFT0_IDX * 4 并调用 cpu_reset(),复位后由 check_upgrade() 捕获进入 USB 升级模式。
- 定义见 hwi.c#L289-L295。
void check_uboot_uart_upgrade(void)
检测 NV_RAM_LIST_ADDR 处的 uboot UART 升级成功标志('u','b','o','o','t',0xa5,'o','k'),匹配则清零并打印成功日志。
- 时序约束:必须在
memory_init()之前调用(源码注释明确要求)。 - 定义见 hwi.c#L310-L316。
void chip_reboot_entry_uboot_uart_upgrade_mode(void)
先 hw_mmu_disable() 关闭 MMU,再写 UART 升级 magic 到 NV_RAM_LIST_ADDR,最后 cpu_reset() 进入 uboot UART 升级。
- 前置条件:调用方需确保 MMU 关闭后仍可安全执行(该函数自身完成)。
- 定义见 hwi.c#L320-L325。
void boot_info_init(void *_info)
从 uboot 传入的 BOOT_DEVICE_INFO* 填充全局 boot_info(flash 容量、VM 对齐、chip_id、trim_value、sfc 映射)。
- 参数:
_info— uboot 传递的BOOT_DEVICE_INFO指针。 - 无返回值;假设
info->fs_info有效。 - 定义见 boot.c#L19-L29。
void vm_init_app(void)
依据 boot_info.vm(地址、大小、对齐)初始化 VM 子系统;按 align 选择页/扇区模式并施加容量上限;vm_init() 返回非 VM_ERR_NONE 时 ASSERT 停机。
- 调用位置:
memory_init()之后、board_init()之前。 - 定义见 boot.c#L31-L55。
void power_reset_source_dump(void)
打印本次复位的来源信息,用于现场定位异常复位。调用位置:debug_uart_early_init() 之后、memory_init() 之前(见 boot.c#L98)。
失败模式、边界情况与并发考量
magic 区域被破坏
- USB magic 驻留于
ISR_ENTRY + IRQ_SOFT0_IDX * 4,该区域同时也承载软中断向量。若应用侧误写该区域,check_upgrade()的memcmp不匹配,系统静默走正常启动路径——这是设计上的容错,代价是升级请求可能被忽略,需重新发起。 - 反向风险:若其他代码碰巧写入与 16 字节 magic 相同的数据,芯片会意外进入 USB 升级模式。magic 采用 128 位伪随机字节序列,碰撞概率可忽略,这是选择长随机 magic 的意图。
时序敏感点
check_uboot_uart_upgrade()必须在memory_init()之前调用:NV_RAM_LIST_ADDR(nvram_list)内容在内存管理系统重建后可能被覆盖,晚于该时机检测将丢失成功标志(源码注释//须在memory_init();前检测该标志明确警示)。chip_reboot_entry_uboot_uart_upgrade_mode()必须关闭 MMU:uboot 运行在无 MMU 的物理地址空间,若不hw_mmu_disable(),写入的 magic 地址可能经 MMU 映射后落点错误,导致复位后检测失败。- magic 写入与
cpu_reset()之间无延迟:避免窗口期内中断或其他任务覆盖 magic。
复位与看门狗
main()首行wdt_init(WDT_4S),若 boot 后续初始化(如时钟稳定等待的 4×100ms 延时)异常卡死,看门狗 4 秒内强制复位。任何将wdt_init延后的修改都会削弱整个启动链的故障恢复能力。cpu_reset()为软复位,不掉电 RAM(ISR_ENTRY 区域、nvram_list)内容保留,这是升级闭环成立的前提;若改为硬件断电重启,magic 将丢失。
并发与重入
- Boot 阶段为单线程顺序执行,
check_upgrade()无并发问题;但升级请求方(应用线程/中断)与 boot 检测之间不存在原子性保证——若写 magic 过程中被复位打断,可能留下部分 magic。缓解手段是 magic 长度固定且检测为整块memcmp,部分写入几乎必然导致不匹配,宁可放弃本次升级也不误入升级模式。 check_upgrade()匹配后立即memset清零,保证重复复位不会重复进入升级模式(一次性语义)。
VM 初始化失败
vm_init() 返回非 VM_ERR_NONE 时直接 ASSERT(0, "vm init err") 停机。这是有意为之的 fail-fast:VM 是参数持久化基础,带病运行可能导致用户配置丢失或 flash 数据损坏。
性能与运维注意事项
- 启动延时:
clk_early_init()之后连续 4 次mdelay(100)(共约 400ms)用于时钟稳定,这是 boot 阶段最大的固定耗时;若对启动时间敏感,可在确认时钟源稳定后缩减,但需评估 flash 访问可靠性。 - 日志窗口:
power_reset_source_dump()与 boot banner(__DATE__/__TIME__)在memory_init()前打印,串口工具抓取这些日志可快速判断复位来源与固件构建时间。 - 升级入口可观测性:UART 升级成功后
check_uboot_uart_upgrade()打印++++++++++++++++++++++++uboot uart upgrade succ,可作为产线/调试中确认升级落地的标志。
扩展点
- 新增升级模式:可仿照现有两条 magic 通道(USB:ISR_ENTRY 区域;UART:nvram_list),在任意不掉电 RAM 区域定义新的 magic 常量,配套"写 magic +
cpu_reset()"的入口函数,并在check_upgrade()或新增的早期检测函数中注册匹配分支。注意新 magic 的驻留区域必须避开memory_init()会重建/清零的内存。 usb_upgrade_mode()为外部实现:check_upgrade()内以void usb_upgrade_mode();声明并调用,实际升级协议(枚举 USB、接收固件、写 flash)由上层模块提供,boot 只负责入口仲裁——这使升级实现可替换而不影响启动链。- 复位源诊断:
power_reset_source_dump()是扩展复位原因上报(如写入专门日志字段、异常复位计数)的天然挂载点。
测试情况
仓库内未见针对 boot 阶段(check_upgrade()/boot_info_init())的独立单元测试文件;该部分代码依赖硬件环境(uboot 交互、eFuse、时钟)验证。升级 magic 机制的回归验证主要依赖产线/调试流程:触发 chip_reboot_entry_usb_upgrade_mode() 后确认复位进入升级模式、升级成功后确认正常启动且不再进入升级模式。
Related Links
- boot.h(BOOT_INFO / BOOT_DEVICE_INFO 结构定义)
- boot.c(main / boot_info_init / vm_init_app)
- hwi.c(check_upgrade 与升级 magic 机制)
- debug.c(cpu_reset 调用)
- wdt.c(看门狗复位模式配置)
- upgrade.S(升级入口汇编,AC635N)
- 其他芯片变体(AC632N / AC636N / AC638N)的 boot 实现路径一致,结构定义与 magic 机制可对照各自
sdk/bsp/ACxxxN/src/boot.c与include/asm/boot.h。