杰理 SDK 文档中心
首页
首页
  • 项目概览

    • AD16N 系列芯片与 SDK 能力总览
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建指南
    • 烧录与固件升级
  • SDK 工程架构

    • SDK 目录结构与模块分层
    • 构建系统与批处理工具
    • BSP 板级支持包
  • mbox_flash 小音箱应用

    • 应用初始化与启动流程
    • 应用配置系统
    • 按键、UI 与用户交互
  • 音频子系统

    • 音频解码框架与调度
    • 音频格式解码器实现
    • MIDI 合成与播放
    • 音频编码与录音
    • EQ/DRC 与音效处理
    • DAC/ADC 音频接口与采样
  • 存储与文件系统

    • 媒体 IO 抽象层 MIO
    • 存储设备驱动
    • 文件系统支持
  • 平台系统库

    • 系统基础服务
    • CPU 平台与运行库
    • 固件升级与更新机制
    • 蓝牙与扩展连接接口
  • 电源与低功耗管理

    • 电源管理与低功耗设计
    • 锂电池充电管理
  • 硬件与文档参考

    • SDK 文档中心与版本发布记录
    • 芯片数据手册与硬件设计参考

系统基础服务

系统基础服务是 AD16N 通用音频 MCU SDK 中支撑整个应用程序运行的底层服务集合,涵盖系统启动引导(c_main)、电源管理(sys_power_init/sys_power_down)、看门狗(wdt_init/wdt_clear)、系统定时器(sys_timer_init)、异常分析与掩码调试(mask_init)以及时钟/PLL 配置(pll_sel)等基础能力。

Purpose and Scope

本页面向 AD16N SDK 的系统基础服务层,说明这些服务在应用启动与运行生命周期中的职责、调用顺序、实现机制与配置方式。内容以 sdk/apps/app/bsp/start/uc03/main.c(启动入口)与 sdk/apps/app/bsp/cpu/uc03/power_api.c(电源管理)为骨架,结合各应用模块(如 idle_check.c、music_play.c、rtc_mode.c)对基础服务的实际调用展开。

以下相关主题由其他页面覆盖,本页不展开:

  • 音频解码/播放服务(bsp/common/decoder、bsp/common/audio)→ 参见音频服务相关页面。
  • 配置存储服务(bsp/common/config/cfg_tools.c)→ 参见配置服务页面。
  • 外设驱动(IO、UART、SD、LED 等)→ 参见外设驱动页面。

Overview

系统基础服务位于应用层与芯片硬件之间,是 app() 业务逻辑得以运行的先决条件。SDK 的启动入口 c_main(int cfg_addr) 在汇编启动代码之后被调用,它按严格的顺序完成:关闭并重新配置看门狗 → 初始化异常掩码与调试设施 → 中断系统初始化 → IO 初始化 → 日志(串口)初始化 → PLL/时钟配置 → 内存堆初始化 → 系统定时器初始化 → 电源管理初始化 → 业务系统初始化 → 进入应用主循环。

设计意图在于:让所有硬件级前置条件(时钟、电源、内存、中断、看门狗)在业务代码运行前被确定性地建立,从而保证 app() 中任意模块(播放、RTC、低功耗)都能直接使用这些服务而不必关心底层时序。同时,电源管理服务通过 sys_power_down(usec) 提供统一的低功耗入口,业务模块(如空闲检测、音乐暂停、RTC 模式)在关键路径上直接调用它以进入 powerdown。

Architecture

下图展示系统基础服务在启动流程与运行期中的位置及相互关系:

flowchart TD
    subgraph sg_Startup["启动阶段 (c_main)"]
        A["wdt_close / wdt_init(WDT_8S)"] --> B["mask_init_for_app<br/>(mask_init + sd_mask_init)"]
        B --> C["irq_init / port_init"]
        C --> D["log_init(TCFG_UART_BAUDRATE)"]
        D --> E["pll_sel(TCFG_PLL_SEL, TCFG_PLL_DIV, TCFG_HSB_DIV)"]
        E --> F["my_malloc_init"]
        F --> G["sys_timer_init (SYS_TIMER_EN)"]
        G --> H["sys_power_init"]
        H --> I["system_init"]
        I --> J["app() 业务主循环"]
    end

    subgraph sg_Runtime["运行期服务调用"]
        J --> K["wdt_clear 周期喂狗"]
        K --> L["sys_power_down(usec) 低功耗"]
    end

    subgraph sg_Modules["业务模块调用方"]
        M["idle_check.c 空闲检测"]
        N["music_play.c 音乐暂停"]
        O["rtc_mode.c RTC 模式"]
    end

    M --> L
    N --> L
    O --> L
    L --> P["power_api.c 电源管理"]

架构说明:

  • 启动链路是单向依赖链:每一步都以前一步为前置条件。例如 sys_timer_init() 依赖 my_malloc_init() 建立的堆,sys_power_init() 依赖时钟与中断就绪,而 system_init()/app() 依赖上述全部服务。
  • 看门狗在启动早期被关闭(wdt_close())以允许慢速初始化,随后以 wdt_init(WDT_8S) 重新开启,业务主循环 while(1) 中必须周期 wdt_clear(),否则系统复位。
  • 电源管理服务是运行期的公共低功耗出口,多个业务模块在关屏/暂停/待机场景下调用 sys_power_down(-2) 进入 powerdown,由 power_api.c 统一实现。
  • 异常分析服务(mask_init)在 config_exception_enable 使能时挂接 exception_analyze 回调,用于崩溃现场分析;SD 卡相关的 sd_mask_init 则为 SD 调试提供超时回调。

启动流程详解:c_main 引导序列

系统上电后,芯片复位向量跳转到汇编启动代码,最终调用应用入口 c_main(int cfg_addr)。它是系统基础服务在启动阶段的"总调度器",其实现位于 sdk/apps/app/bsp/start/uc03/main.c:

__attribute__((noreturn))
void c_main(int cfg_addr)
{
    wdt_close();

    mask_init_for_app();
    irq_init();
    local_irq_disable();
    local_irq_enable();

    //上电初始化所有IO
    port_init();

    log_init(TCFG_UART_BAUDRATE);

    pll_sel(TCFG_PLL_SEL, TCFG_PLL_DIV, TCFG_HSB_DIV);

    dump_clock_info();

    debug_init();

    wdt_init(WDT_8S);

    P3_PINR_CON &= ~BIT(0); //关闭长按复位

    /* gpio_clk_out(IO_PORTC_00, CLK_OUT_HSB); */

    log_info("time & date %s %s \n  OTP c_main\n", __TIME__, __DATE__);

    my_malloc_init();
#if SYS_TIMER_EN
    sys_timer_init();
#endif
    power_reset_source_dump();
    power_wakeup_reason_dump();
    sys_power_init();

    system_init();
    app();
    while (1) {
        wdt_clear();
    }
}

Source: main.c

逐步拆解该序列的设计意图:

  1. wdt_close() — 启动早期关闭看门狗。原因:复位后看门狗可能处于使能状态,而后续初始化(尤其时钟切换、内存初始化)耗时较长,若继续计数会导致启动过程被意外复位。
  2. mask_init_for_app() — 建立异常分析设施(见下文"异常处理与掩码调试")。它根据 config_exception_enable 决定是否挂接 exception_analyze 回调,使崩溃时可输出分析信息。
  3. irq_init() + local_irq_disable/enable() — 初始化中断控制器并做一次关/开中断的屏障操作,确保后续初始化期间中断状态确定。
  4. port_init() — 上电初始化所有 IO 引脚,避免悬空引脚造成漏电或误触发。
  5. log_init(TCFG_UART_BAUDRATE) — 以配置的波特率初始化串口日志,此后 log_info 等输出才可用。
  6. pll_sel(TCFG_PLL_SEL, TCFG_PLL_DIV, TCFG_HSB_DIV) + dump_clock_info() — 选择 PLL 并配置 HSB 分频,随后打印时钟信息。时钟是后续所有外设与定时器的基础,必须先于电源/定时器初始化。
  7. debug_init() — 初始化调试辅助设施。
  8. wdt_init(WDT_8S) — 以 8 秒超时重新开启看门狗,此后代码必须周期性喂狗。
  9. P3_PINR_CON &= ~BIT(0) — 关闭长按复位功能,避免用户长按 IO 触发复位。
  10. my_malloc_init() — 初始化内存堆分配器,为 sys_timer_init 等需要动态内存的服务做准备。
  11. sys_timer_init()(受 SYS_TIMER_EN 宏控制) — 初始化系统定时器服务。
  12. power_reset_source_dump() / power_wakeup_reason_dump() — 打印复位源与唤醒原因,用于排查异常复位和低功耗唤醒路径。
  13. sys_power_init() — 初始化电源管理服务(见下节)。
  14. system_init() — 初始化业务系统(设备、事件等)。
  15. app() — 进入业务应用主体;返回后进入 while(1) 死循环,仅做 wdt_clear() 喂狗,防止系统复位。

电源管理服务(power_api.c)

电源管理是系统基础服务的核心运行期能力。sdk/apps/app/bsp/cpu/uc03/power_api.c 提供了两个关键 API:

void sys_power_init()
{
    ...
}

void sys_power_down(u32 usec)
{
    ...
}

Source: power_api.c

  • sys_power_init():在启动阶段完成电源模块初始化,使后续低功耗请求可用。它在 c_main 中被调用,且在 power_reset_source_dump()/power_wakeup_reason_dump() 之后——这样可以在初始化电源前先记录复位/唤醒现场。
  • sys_power_down(u32 usec):统一的低功耗入口。参数 usec 为低功耗持续时间,业务代码以 -2 调用表示"进入 powerdown"(由调用方配合临界区使用,见下文示例)。

业务模块在关键低功耗路径上调用它,例如空闲检测模块:

UI_init();//关闭数码管
sys_power_down(-2);//进入powerdown
OS_EXIT_CRITICAL();

Source: idle_check.c

注意调用惯例:在临界区(OS_ENTER_CRITICAL)内执行 sys_power_down(-2),返回后调用 OS_EXIT_CRITICAL()。这是因为 powerdown 过程中系统时钟/中断被挂起,必须以临界区保护状态切换的原子性,防止唤醒瞬间的中断竞争。

看门狗服务

看门狗贯穿启动与运行期:

  • 启动早期 wdt_close() 关闭,避免初始化超时误复位;
  • 初始化完成前 wdt_init(WDT_8S) 以 8 秒超时开启;
  • 业务主循环与耗时任务中周期调用 wdt_clear() 喂狗。

在 c_main 中,主循环只做喂狗:

while (1) {
    wdt_clear();
}

Source: main.c

设计意图:看门狗是系统"最后一道防线"——当业务逻辑死锁或异常导致主循环停滞时,8 秒后系统自动复位,配合 power_reset_source_dump() 的复位源打印可定位故障。SD 卡调试中还通过 sd_debug 回调在 E_SD_RECEIVE_DATA_TIMEOUT/E_SD_SEND_ACMD41_TIMEOUT 时提前 wdt_clear(),避免 SD 超时路径误触发复位:

static void sd_debug(u32 idx)
{
    if (idx == E_SD_RECEIVE_DATA_TIMEOUT || idx == E_SD_SEND_ACMD41_TIMEOUT) {
        wdt_clear();
    }
    ...
}

Source: main.c

系统定时器服务

系统定时器由编译宏 SYS_TIMER_EN 控制,使能时在启动流程中调用:

#if SYS_TIMER_EN
    sys_timer_init();
#endif

Source: main.c

它必须在 my_malloc_init()(内存堆就绪)之后、sys_power_init()(电源服务)之前初始化,因为后续业务系统(system_init/app)依赖定时器提供时间基准与调度能力。

异常处理与掩码调试

mask_init_for_app() 是调试服务在启动期的装配点:

void mask_init_for_app(void)
{
    if (config_exception_enable) {
        mask_init(exception_analyze, putchar, clk_get, device_status_emit);
    } else {
        mask_init(NULL, putchar, clk_get, device_status_emit);
    }

//--------------------------
#if TFG_SD_EN
    sd_mask_init(5, NULL, NULL, NULL, NULL, sd_debug);
#endif
}

Source: main.c

要点:

  • config_exception_enable 使能时,mask_init 挂接 exception_analyze 作为异常分析回调;关闭时传入 NULL 以减小代码体积/开销(量产裁剪场景)。
  • putchar 作为日志输出函数、clk_get 提供时钟计数、device_status_emit 上报设备状态——这些回调把异常分析、时间戳与设备状态输出串联起来,使崩溃现场可复现。
  • sd_mask_init(5, NULL, NULL, NULL, NULL, sd_debug) 在 TFG_SD_EN 使能时为 SD 子系统注册调试掩码,sd_debug 负责超时场景下的喂狗与日志。

核心流程:启动与低功耗时序

sequenceDiagram
    participant HW as 芯片复位/汇编启动
    participant CM as c_main
    participant WDT as 看门狗
    participant PWR as power_api.c
    participant SYS as system_init/app

    HW->>CM: 跳转 c_main(cfg_addr)
    CM->>WDT: wdt_close()
    CM->>CM: mask_init_for_app() / irq_init() / port_init()
    CM->>CM: log_init(TCFG_UART_BAUDRATE)
    CM->>CM: pll_sel(...) + dump_clock_info()
    CM->>WDT: wdt_init(WDT_8S)
    CM->>CM: my_malloc_init() → sys_timer_init()
    CM->>PWR: power_reset_source_dump() / power_wakeup_reason_dump()
    CM->>PWR: sys_power_init()
    CM->>SYS: system_init()
    CM->>SYS: app() 业务主体
    SYS-->>CM: 返回(不应发生)
    CM->>WDT: while(1) wdt_clear() 周期喂狗

    Note over SYS,PWR: 运行期低功耗路径
    SYS->>PWR: sys_power_down(-2) [临界区内]
    PWR-->>SYS: powerdown 返回(唤醒)
    SYS->>SYS: OS_EXIT_CRITICAL()

时序要点:

  1. 启动阶段(上半部分)是确定性的线性序列,任何一步失败(如堆初始化失败、时钟配置错误)都会导致后续服务不可用;由于看门狗已开启,卡死会在 8 秒后触发复位。
  2. 运行期低功耗(下半部分)由业务模块主动触发:sys_power_down(-2) 必须在临界区内调用,唤醒返回后立即退出临界区。power_wakeup_reason_dump() 使下次启动能够打印本次唤醒原因,形成"低功耗 → 唤醒 → 诊断"的闭环。

使用示例

示例一:在业务空闲检测中进入低功耗

UI_init();//关闭数码管
sys_power_down(-2);//进入powerdown
OS_EXIT_CRITICAL();

Source: idle_check.c

说明:空闲检测模块先关闭数码管显示(关闭功耗大户),随后在临界区内进入 powerdown;OS_EXIT_CRITICAL() 前的代码均在关中断保护下执行,保证低功耗状态的原子进入。

示例二:音乐暂停时进入低功耗

LED5X7_init();
sys_power_down(-2);
OS_EXIT_CRITICAL();

Source: music_play.c

说明:音乐播放模块在暂停场景先初始化 LED 显示(LED5X7),随后同样以 sys_power_down(-2) 进入 powerdown,遵循"先关显示、再进低功耗"的顺序以最大化省电效果。

示例三:RTC 模式下的低功耗

sys_power_down(-2);//进入powerdown

Source: rtc_mode.c

说明:RTC 模式(时钟显示待机)依赖系统定时器维持时间,进入 powerdown 后由 RTC/唤醒源恢复,属于该模式的核心节能路径。

配置选项

系统基础服务的行为主要由编译期宏与配置项控制,汇总如下:

配置项类型默认值说明
SYS_TIMER_EN宏 (0/1)依工程配置是否使能系统定时器服务;使能时 c_main 调用 sys_timer_init()
TCFG_UART_BAUDRATE数值工程配置日志串口波特率,传入 log_init()
TCFG_PLL_SEL数值工程配置PLL 选择参数,传入 pll_sel()
TCFG_PLL_DIV数值工程配置PLL 分频参数,传入 pll_sel()
TCFG_HSB_DIV数值工程配置HSB 总线分频参数,传入 pll_sel()
WDT_8S枚举/宏8 秒看门狗超时周期,传入 wdt_init()
config_exception_enable全局变量依工程配置使能时 mask_init 挂接 exception_analyze 异常分析回调
TFG_SD_EN宏 (0/1)依工程配置使能 SD 子系统;使能时调用 sd_mask_init 注册调试掩码

其中时钟三项(TCFG_PLL_SEL/TCFG_PLL_DIV/TCFG_HSB_DIV)决定芯片工作频率,直接影响定时器精度与低功耗唤醒时序,属于"一次配置、全局生效"的关键项。

API 参考

c_main(int cfg_addr)

系统应用入口,由启动汇编代码调用,noreturn。负责按顺序装配全部系统基础服务后进入业务主循环。

参数:

  • cfg_addr (int):配置区地址,用于定位系统配置。

返回: 不返回(__attribute__((noreturn)))。

Source: main.c

mask_init_for_app(void)

装配异常分析与调试掩码服务。依据 config_exception_enable 决定是否注册 exception_analyze 回调;TFG_SD_EN 使能时注册 SD 调试掩码。

Source: main.c

sys_power_init(void)

初始化电源管理服务,使 sys_power_down 可用。在 c_main 的时钟/中断/内存初始化之后调用。

Source: power_api.c

sys_power_down(u32 usec)

进入低功耗状态。

参数:

  • usec (u32):低功耗持续时间;业务代码传入 -2 表示进入 powerdown。

调用约束: 应在临界区(OS_ENTER_CRITICAL)内调用,唤醒返回后调用 OS_EXIT_CRITICAL()。

Source: power_api.c

wdt_init(wdt_timeout_t timeout) / wdt_clear(void) / wdt_close(void)

看门狗三件套:wdt_init(WDT_8S) 以 8 秒超时开启;wdt_clear() 周期喂狗(主循环与 SD 超时路径);wdt_close() 启动早期关闭。

Source: main.c

sys_timer_init(void)

初始化系统定时器服务,仅在 SYS_TIMER_EN 使能时由 c_main 调用,需在 my_malloc_init() 之后。

Source: main.c

pll_sel(sel, div, hsb_div) / dump_clock_info(void)

配置系统时钟(PLL 选择与 HSB 分频)并打印时钟信息,必须在电源与定时器初始化之前完成。

Source: main.c

失败模式、边界情况与并发

基于源码证据,系统基础服务存在以下可观测的失败模式与边界行为:

看门狗复位

  • 主循环停滞复位:app() 返回后主循环仅执行 wdt_clear();任何阻塞超过 WDT_8S(8 秒)的路径都会触发看门狗复位。SD 卡超时(E_SD_RECEIVE_DATA_TIMEOUT、E_SD_SEND_ACMD41_TIMEOUT)是已知的长时间阻塞路径,因此 sd_debug 回调在这些事件中提前喂狗,防止误复位。
  • 诊断闭环:复位后下次启动通过 power_reset_source_dump() 打印复位源,开发者可据此区分看门狗复位、上电复位与长按复位(P3_PINR_CON 关闭了长按复位,因此该来源会被屏蔽)。

低功耗的并发/原子性约束

  • sys_power_down(-2) 必须在 OS_ENTER_CRITICAL/OS_EXIT_CRITICAL 临界区内调用(见 idle_check/music_play 示例)。这是硬性约定:powerdown 期间时钟与中断被挂起,若不在临界区内,唤醒瞬间的中断处理可能与低功耗状态切换竞争,导致状态不一致或漏唤醒。
  • 所有业务模块(空闲检测、音乐暂停、RTC)遵循同一调用模式,说明该约束由调用方负责而非库内强制,扩展新低功耗场景时必须沿用此模式。

配置宏一致性

  • SYS_TIMER_EN、TFG_SD_EN、config_exception_enable 等配置控制代码装配路径。若 SYS_TIMER_EN 关闭但业务代码仍依赖系统定时器,将出现未初始化服务的使用错误;同理 TFG_SD_EN 关闭时 sd_mask_init 分支被裁剪。修改配置后需全量重编译并回归验证启动序列。

启动序列的强顺序依赖

c_main 中各步骤顺序不可调换:log_init 先于 pll_sel 的日志输出、my_malloc_init 先于 sys_timer_init、时钟先于电源。任何新增基础服务都应在 system_init() 之前完成装配,否则业务代码可能在服务未就绪时访问它。

性能与运维要点

  • 启动时序敏感:wdt_close() → 慢速初始化 → wdt_init(WDT_8S) 的结构允许初始化阶段不受看门狗限制;但 8 秒窗口意味着 system_init()/app() 前的全部初始化必须在 8 秒内完成(正常情况下远小于此)。
  • 低功耗收益顺序:业务模块先关闭显示(数码管/LED5X7)再 sys_power_down,说明显示是待机功耗的主要来源,新增省电路径应遵循"先关外设、再进低功耗"的顺序。
  • 日志与诊断:dump_clock_info()、power_reset_source_dump()、power_wakeup_reason_dump() 在每次启动打印,是现场问题排查的第一手信息;量产裁剪时可关闭 config_exception_enable 以减小异常分析开销。

扩展点

系统基础服务通过以下方式支持扩展:

  1. 新增低功耗场景:复用 sys_power_down(-2) 入口,按"临界区进入 → 关显示 → powerdown → 退出临界区"的既有模式编写,例如新增按键待机、定时待机场景。
  2. 新增启动阶段服务:在 c_main 中 system_init() 之前插入初始化调用,并遵守依赖顺序(内存 → 时钟 → 定时器 → 电源)。
  3. 异常分析定制:通过 mask_init 的回调参数(exception_analyze、putchar、clk_get、device_status_emit)替换日志输出、时钟计数与设备状态上报实现。
  4. SD/外设调试掩码:仿照 sd_mask_init(5, NULL, NULL, NULL, NULL, sd_debug) 为其他外设注册调试回调,在超时路径上执行喂狗或日志。

测试覆盖说明

本次探索未在源码中发现针对系统基础服务(启动序列、电源、看门狗)的独立单元测试文件;其正确性主要通过以下机制保障:启动期诊断打印(复位源/唤醒原因/时钟信息)用于回归验证,以及看门狗作为运行期兜底防止静默故障。建议在新增启动阶段服务或修改电源路径时,通过复位源打印与低功耗唤醒日志进行手工回归。

Related Links

  • 启动入口 main.c
  • 电源管理 power_api.c
  • 空闲检测低功耗调用 idle_check.c
  • 音乐播放低功耗调用 music_play.c
  • RTC 模式低功耗调用 rtc_mode.c
  • 相关主题:音频服务、配置存储服务、外设驱动(见"Purpose and Scope"中的页面边界说明)
Next
CPU 平台与运行库