杰理 SDK 文档中心
首页
首页
  • 概述与入门

    • 项目概览
    • 快速开始与开发环境
  • 应用与运行时

    • 应用入口与主循环
    • 按键驱动与用户消息处理
    • 消息系统
  • 固件升级

    • 双备份升级机制与状态机
    • UART 升级传输
    • 升级校验、启动信息与复位流程
  • 芯片与硬件支持

    • AC63 系列芯片 BSP 结构
    • 外设接口与驱动
    • 低功耗、RTC 与时基唤醒
  • 构建与工具

    • 构建系统与工作区
    • 烧写与量产工具
  • 参考资源

    • 数据手册与原理图
    • 双备份升级文档

升级校验、启动信息与复位流程

本页文档覆盖 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)+ 复位"机制**:

  1. 应用或工具需要进入升级模式时,先在特定内存地址写入一串特征字节(magic),然后调用 cpu_reset() 复位;
  2. 复位后芯片重新走 boot 流程,main() 在非常早期(efuse_init() 之前)调用 check_upgrade() 检查 magic;
  3. 若 magic 匹配,则清除 magic 并进入对应的升级模式(USB 升级或 uboot UART 升级);否则继续正常启动。

这一机制的优势在于:升级入口不依赖任何持久化标志位,天然支持"掉电复位后仍能进入升级模式"的可靠性要求,同时 magic 校验失败时(内存被破坏)自动回退到正常启动路径。

关键术语:

术语含义
BOOT_INFOboot 全局启动信息结构,存放于 .boot_info 段,由 boot_info_init() 填充
BOOT_DEVICE_INFOuboot 传入的原始设备信息结构(含 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(),重新走上述流程

时序要点:

  1. 看门狗最先:wdt_init(WDT_4S) 为整个 boot 提供兜底恢复能力。
  2. 升级校验第二:check_upgrade() 必须在 efuse_init()、时钟、内存初始化之前执行,因为升级模式(尤其 UART/uboot 场景)依赖早期干净的 RAM 状态。
  3. 时钟稳定等待:clk_early_init() 后连续 4 次 mdelay(100),共约 400ms,等待 PLL/RC 时钟稳定,避免外设与 flash 在时钟不稳时访问出错。
  4. 复位源尽早打印:power_reset_source_dump() 在 memory_init() 之前,保证日志不依赖内存管理系统。
  5. VM 初始化位于内存初始化之后:vm_init_app() 需要 boot_info.vm(uboot/sdfile 提供)与内存管理就绪。
  6. 最终移交: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.40V1.3V 域电压档位
SYS_CLOCK_INPUT_PLL_RCL枚举RC 32.768K + PLL 24M系统时钟输入源与频率(另有 SYS_CLOCK_INPUT_PLL_BT_OSC 备选)
vm.align(来自 uboot)u80(扇区模式)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 的意图。

时序敏感点

  1. check_uboot_uart_upgrade() 必须在 memory_init() 之前调用:NV_RAM_LIST_ADDR(nvram_list)内容在内存管理系统重建后可能被覆盖,晚于该时机检测将丢失成功标志(源码注释 //须在memory_init();前检测该标志 明确警示)。
  2. chip_reboot_entry_uboot_uart_upgrade_mode() 必须关闭 MMU:uboot 运行在无 MMU 的物理地址空间,若不 hw_mmu_disable(),写入的 magic 地址可能经 MMU 映射后落点错误,导致复位后检测失败。
  3. 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。
Prev
UART 升级传输