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

    • 项目概述与芯片平台
    • 环境搭建与工具链安装
    • 编译与烧录指南
    • 工程结构总览
  • 应用层与公共模块

    • GP MCU 主应用入口
    • AT 指令与调试模块
    • 电池检测与电源管理
    • EEPROM 与参数存储
    • 按键与 USB 设备驱动
    • 音频解码与 APA 语音播报
  • 外设驱动与示例

    • 高精度 ADC(HADC)
    • 通用 ADC 与定时器
    • UART / SPI / IIC 通信外设
    • MCPWM 与电机控制
    • RTC 与低功耗唤醒
    • 段码 LCD 驱动
    • NOR Flash 与红外编解码组件
  • 显示与 UI 系统

    • LCD 驱动与字库引擎
    • UI 平台与控件绘制
    • UI 工程与资源生成工具
  • 系统底层与芯片平台

    • cd09 芯片平台与预编译库
    • GPIO 与 IIC 底层驱动
    • 系统文件系统与设备模型
  • 启动引导与固件升级

    • UBOOT 引导工程
    • 固件升级机制
  • 开发工具与资源

    • 编译脚本与命令行工具
    • 音频文件转换工具
    • 硬件资料与文档资源

RTC 与低功耗唤醒

AC82N SDK 中 RTC(实时时钟)设备驱动与低功耗唤醒机制的完整参考:涵盖时钟源选择、时间读写、闹钟管理、时间戳换算、RTC 端口操作,以及基于 RTC 定时器/溢出与 LPTMR 的低功耗唤醒流程。

Purpose and Scope

本文档介绍 AC82N(Jieli)SDK 中 RTC 设备驱动(rtc_dev)的全部对外接口与工作机制,并重点说明其与低功耗唤醒的配合方式:如何在软关机(sys_softoff)前设置闹钟、如何在低功耗状态下由 RTC 定时器或溢出事件唤醒系统、以及溢出后如何通过回调接管关机决策。

本文档边界:

  • 覆盖:rtc/rtc_dev.h 定义的驱动 API(时钟源、时间转换、闹钟、唤醒、端口操作)以及 rtc_demo.c 展示的完整用法。
  • 不覆盖:其他低功耗模式(如定时器/IO 中断等非 RTC 唤醒源)的细节、电源管理子系统全貌、VM(虚拟内存)存储机制本身。这些属于电源管理页面的主题,本文仅在相关接口处(如 rtc_save_context_to_vm)做交叉指引。

概述

RTC(Real-Time Clock)模块为系统提供持续的日历时间(年/月/日/时/分/秒)跟踪能力,即使主系统进入低功耗或软关机状态,只要时钟源(32K 晶振或 LRC 等)保持供电,时间仍可继续走时。基于这一点,RTC 同时承担了"定时唤醒"职责:应用可以在关机前写入一个闹钟时间,RTC 硬件在到达该时刻时产生事件,将系统从低功耗状态唤醒。

SDK 将 RTC 封装为标准设备驱动,同时提供:

  • 一组纯函数式时间换算工具(闰年判断、时间戳互转、星期计算、秒差计算等),供应用层任意使用;
  • 一组设备操作接口(初始化、读写时间、读写闹钟、使能/查询闹钟、保存上下文到 VM);
  • 一组RTC 端口操作(读 PR 值、设置方向/上下拉/驱动能力),用于复用 RTC 域内 GPIO;
  • 针对 BR28/BR27 平台的 RTC_USE_HW_SFR 硬件寄存器直读优化。
flowchart TD
    subgraph sg_App["应用层"]
        App["应用代码 / rtc_demo.c"]
    end

    subgraph sg_Driver["RTC 设备驱动层 (rtc_dev)"]
        RtcInit["rtc_init / rtc_dev_ops"]
        TimeOps["时间读写<br/>rtc_read_time / rtc_write_time"]
        AlarmOps["闹钟<br/>rtc_write_alarm / rtc_alarm_switch"]
        WkupOps["低功耗唤醒<br/>rtc_lptmr_wakeup_enable / 溢出回调"]
        ConvOps["时间换算工具<br/>datetime_to_timestamp 等"]
        PortOps["RTC 端口<br/>rtc_port_pr_*"]
    end

    subgraph sg_HW["硬件层"]
        ClkSrc["时钟源<br/>32K / LRC / 12M / 24M"]
        RtcHW["RTC 硬件寄存器 (HW_SFR)"]
        Lptmr["低功耗定时器 LPTMR"]
    end

    App --> RtcInit
    App --> TimeOps
    App --> AlarmOps
    App --> WkupOps
    App --> ConvOps
    App --> PortOps
    RtcInit --> RtcHW
    TimeOps --> RtcHW
    AlarmOps --> RtcHW
    WkupOps --> Lptmr
    WkupOps --> RtcHW
    RtcHW --> ClkSrc

上图展示 RTC 模块的分层结构:应用层通过 rtc_dev 提供的设备操作与工具函数访问硬件;驱动层内部将时间/闹钟操作落到 RTC 硬件寄存器,将定时唤醒落到 LPTMR(低功耗定时器);时钟源选择(control_rtc_clk_sel)决定了走时精度与功耗的权衡。

时钟源选择与使能控制

RTC 的时钟源通过两个全局常量在工程配置中决定(rtc_dev.h):

extern const bool control_rtc_enable;   // RTC 使能控制
extern const u32  control_rtc_clk_sel;  // RTC 时钟源选择

来源:rtc_dev.h

可选时钟源(宏定义于 rtc_dev.h):

宏值时钟源适用场景
CLK_SEL_32K132kHz 晶振高精度走时,适合需要准确日历的应用
CLK_SEL_12M212MHz 系统时钟无 32K 晶振时使用,功耗较高
CLK_SEL_24M324MHz 系统时钟无 32K 晶振时使用,功耗较高
CLK_SEL_LRC4内部低速 RC 振荡器最低成本/最低功耗,精度较差

设计意图:32K 晶振是低功耗走时的首选——它精度高且功耗极低,适合"关机后继续走时"的典型 RTC 场景;LRC 用于节省 BOM 成本但时间漂移明显,通常需要配合 trim_interval 定时校准。此外,SDK 对 BR28/BR27 平台定义了 RTC_USE_HW_SFR(rtc_dev.h),表示该平台使用硬件特殊功能寄存器直读 RTC,以降低软件模拟开销。

时间结构与事件模型

时间结构体 sys_time

所有时间接口统一使用紧凑打包的 struct sys_time(rtc_dev.h):

struct sys_time {
    u16 year;   /**< 年份 */
    u8 month;   /**< 月份 (1-12) */
    u8 day;     /**< 日期 (1-31) */
    u8 hour;    /**< 小时 (0-23) */
    u8 min;     /**< 分钟 (0-59) */
    u8 sec;     /**< 秒 (0-59) */
} _GNU_PACKED_;

来源:rtc_dev.h

结构体以 _GNU_PACKED_ 打包,便于按字节协议传输或存入 VM;注意它不含时区/星期字段,星期需通过 get_weekday_from_time 计算。

状态与事件枚举

RTC 状态机定义(rtc_dev.h):

enum {
    RTC_UNACCESSIBLE = 0,              /**< RTC不可访问 */
    RTC_ACCESSIBLE_TIME_UNRELIABLE,    /**< RTC可访问但时间不可靠 */
    RTC_ACCESSIBLE_TIME_RELIABLE,      /**< RTC可访问且时间可靠 */
    RTC_SUCC,                          /**< 操作成功 */
    RTC_ERROR_ALM_DIS,                 /**< 闹钟未使能 */
    RTC_ERROR_ALM_NO_EFFECT,           /**< 闹钟设置无效 */
};

来源:rtc_dev.h

RTC_UNACCESSIBLE / RTC_ACCESSIBLE_TIME_* 通常用于 rtc_read_time 返回值的判断:刚上电且未经过网络/外部校时、仅靠默认时间启动时,时间可能"可读但不可靠"。RTC_ERROR_ALM_DIS 与 RTC_ERROR_ALM_NO_EFFECT 则用于闹钟操作失败的原因区分——前者是闹钟开关未使能,后者是写入的闹钟时间无效(如早于当前时间)。

事件类型(rtc_dev.h):

enum rtc_event {
    RTC_ALARM_EVENT,   /**< 闹钟事件 */
    RTC_WKUP_EVENT,    /**< 唤醒事件 */
    RTC_1HZ_EVENT,     /**< 1Hz定时事件 */
    RTC_TRIM_EVENT,    /**< 校准事件 */
};

来源:rtc_dev.h

事件通过 struct rtc_event_t { enum rtc_event event; } 传入平台数据中注册的回调 cbfun。注意 demo 中回调以位掩码方式判断 ev->event & BIT(RTC_ALARM_EVENT),说明驱动实现中事件字段可携带多个事件位。

平台数据配置

rtc_dev_platform_data 是初始化 RTC 的唯一配置入口(rtc_dev.h):

struct rtc_dev_platform_data {
    const struct sys_time *default_sys_time;  /**< 默认系统时间 */
    void (*cbfun)(const struct rtc_event_t *); /**< 事件回调函数 */
    u8 trim_interval;                          /**< 校准间隔(单位:分钟) */
};

来源:rtc_dev.h

  • default_sys_time:首次启动(VM 中无有效上下文)时写入的基准时间;
  • cbfun:闹钟/唤醒/1Hz/校准事件回调;
  • trim_interval:秒级走时误差自动校准间隔(分钟),为 0 时不校准。

配套宏 RTC_DEV_PLATFORM_DATA_BEGIN(data) / RTC_DEV_PLATFORM_DATA_END() 用于以"指定名称 + 初始化器"形式声明该结构体。

时间换算工具函数

驱动提供一组纯计算工具,不访问硬件,可在任意上下文使用(rtc_dev.h):

函数说明
is_leap_year(u32 year)闰年判断
days_in_year(u32 year)当年总天数(366/365)
days_in_month(u32 year, u32 month)指定月份天数
datetime_to_timestamp(const struct sys_time *)UTC 时间 → Unix 秒级时间戳
datetime_to_timestamp_us(const struct sys_time *)UTC 时间 → 微秒级时间戳
timestamp_to_datetime(u64 total_seconds, struct sys_time *)秒级时间戳 → UTC 时间
get_weekday_from_time(const struct sys_time *)计算星期几(1~7,周一~周日)
get_seconds_delta(old, curr)两个时间的秒差(curr - old)
datetime_add_seconds(struct sys_time *, s32 sec)时间加减秒(支持负数,自动进位/借位)
day_to_ymd(u32 day, struct sys_time *)自 1970 起总天数 → 年/月/日
ymd_to_day(const struct sys_time *)年/月/日 → 自 1970 起总天数
printf_datetime(const struct sys_time *)调试打印时间

设计意图:将日期算法与硬件寄存器解耦,既方便应用层做"当前时间 + N 秒"(闹钟常用)这类运算,也让驱动内部的时间戳换算逻辑可复用、可测试。datetime_to_timestamp_us / rtc_sys_timestamp_us 提供微秒级时间戳,供需要高分辨率定时的场景使用。

低功耗唤醒机制

RTC 与低功耗唤醒的配合是本文档的核心主题。SDK 定义了两种 RTC 定时唤醒类型(rtc_dev.h):

#define RTC_TIMER_WKUP          1    /**< 定时器唤醒 */
#define RTC_TIMER_OVERFLOW_WKUP 2    /**< 定时器溢出唤醒 */

来源:rtc_dev.h

闹钟唤醒(RTC_TIMER_WKUP)

典型路径:应用在软关机前调用 rtc_write_alarm() 写入目标时间并 rtc_alarm_switch(1) 使能闹钟,随后 sys_softoff() 进入低功耗;RTC 硬件在低功耗状态下持续走时,到达闹钟时刻产生 RTC_ALARM_EVENT / RTC_WKUP_EVENT 并唤醒系统,驱动调用 cbfun 通知应用。

sequenceDiagram
    participant App as 应用层 (rtc_demo.c)
    participant Rtc as RTC 驱动 (rtc_dev)
    participant HW as RTC 硬件 / LPTMR
    participant Cb as 事件回调 cbfun

    App->>Rtc: rtc_init(&rtc_config_t)
    Rtc->>HW: 选择时钟源并初始化寄存器
    App->>Rtc: rtc_write_alarm(&alarm_time)
    Rtc-->>App: RTC_SUCC
    App->>Rtc: rtc_alarm_switch(1)
    App->>App: sys_softoff() 进入低功耗
    HW-->>Rtc: 到达闹钟时刻,产生唤醒事件
    Rtc->>Cb: 回调 rtc_event_t (RTC_ALARM_EVENT/RTC_WKUP_EVENT)
    Cb-->>App: 应用处理唤醒
    App->>Rtc: rtc_read_time(&time) 读取当前时间

溢出唤醒与关机决策(RTC_TIMER_OVERFLOW_WKUP)

RTC 定时器可能因配置周期较短或长时间未复位而发生溢出。默认行为是:初始化时检测到溢出 → 驱动内部直接调用软关机接口关机。为了给应用层接管决策的机会,SDK 提供溢出回调(rtc_dev.h):

/**
 * @brief 设置rtc定时器溢出后的回调函数 必须在rtc_init函数前调用
 * @param 回调函数skip_softoff_callback 返回1:跳过rtc定时器溢出后自动关机  返回0:rtc定时器溢出后自动关机
 */
void rtc_set_overflow_callback(u32(*skip_softoff_callback)(void));

来源:rtc_dev.h

回调返回 1 表示"跳过 RTC 内部的关机流程,由应用层决定合适的关机时机";返回 0 则保持与旧版本一致的行为(内部直接关机)。该函数必须在 rtc_init 之前调用才生效。

flowchart TD
    Start([RTC 初始化 rtc_init]) --> Ovf{"RTC 定时器溢出?"}
    Ovf -->|"否"| Normal["正常运行<br/>走时/闹钟/唤醒"]
    Ovf -->|"是"| Cb{"RTC 溢出回调已注册?"}
    Cb -->|"否"| Softoff1["驱动内部自动软关机 sys_softoff"]
    Cb -->|"是"| Ret{"回调返回值?"}
    Ret -->|"1"| AppDecide["跳过自动关机<br/>应用层决定关机时机"]
    Ret -->|"0"| Softoff2["驱动自动软关机"]
    Normal --> End([结束])
    AppDecide --> End
    Softoff1 --> End
    Softoff2 --> End

LPTMR 低功耗定时器唤醒

驱动还提供直接的低功耗定时器唤醒接口(rtc_dev.h):

/**
 * @brief 使能低功耗定时器唤醒
 * @param wkup_ms 唤醒延时(毫秒)
 */
void rtc_lptmr_wakeup_enable(uint32_t wkup_ms);

来源:rtc_dev.h

与"绝对时刻闹钟"不同,LPTMR 唤醒是相对延时:指定若干毫秒后唤醒,适合周期性巡检、定时刷新等无需精确日历时间的低功耗场景。两者可互补:闹钟用于"到点必须醒",LPTMR 用于"每隔多久醒一次"。

设备生命周期与上下文持久化

RTC 驱动通过 rtc_dev_ops(extern const struct device_operations rtc_dev_ops;)挂接到 SDK 标准设备框架,生命周期如下:

  1. 初始化:rtc_set_overflow_callback()(可选,必须先于 init)→ rtc_init(&platform_data),驱动依据 default_sys_time 与 VM 中保存的上下文决定初始时间;
  2. 运行期:应用读写时间/闹钟、使能闹钟、查询状态,RTC 每秒产生 RTC_1HZ_EVENT(若注册),按 trim_interval 触发 RTC_TRIM_EVENT 校准;
  3. 低功耗前:rtc_is_soff_need_keep_clk() 判断软关机是否需要保持时钟;如需保存当前时间上下文,调用 rtc_save_context_to_vm() 将 RTC 上下文写入 VM;
  4. 注销:rtc_dev_deinit() 释放资源、停止走时。

关键判断函数 rtc_is_soff_need_keep_clk()(rtc_dev.h)返回 1 表示软关机后需要保持时钟运行——这是"关机后闹钟仍能唤醒"的前提,应用应在关机流程中据此决定是否保留 RTC 电源域。rtc_wakup_source()(rtc_dev.h)用于查询本次唤醒源,帮助应用区分"闹钟唤醒/溢出唤醒/其他唤醒"。

使用示例

以下示例均来自 SDK 自带的 RTC 演示工程 rtc_demo.c。

初始化、设置闹钟与定时打印

void rtc_test_demo_start(void)
{
    struct sys_time def_sys_time_t = {
        .year = 2026,
        .month = 4,
        .day = 1,
        .hour = 0,
        .min = 0,
        .sec = 0,
    };

    struct rtc_dev_platform_data rtc_config_t = {
        .default_sys_time = &def_sys_time_t,
        .cbfun = alm_ring_fun,
    };

    // 设置RTC溢出回调函数为 rtc_overflow_callback,必须在rtc_init前调用才有用。不注册该接口则RTC溢出后内部直接关机
    rtc_set_overflow_callback(rtc_overflow_callback);
    rtc_init(&rtc_config_t);

    if (rtc_overflow_flag) {
        //rtc溢出,应用层可关机(不强制在此处调用),亦可不关机
        sys_softoff();
    }

    printf("---------------\n");
    printf("\nrtc_dev_init\n");
    rtc_read_time(&temp);
    printf("rtc_default_sys_time: %d-%d-%d %d:%d:%d\n", temp.year, temp.month, temp.day, temp.hour, temp.min, temp.sec);

    datetime_add_seconds(&temp, 55);
    rtc_alarm_switch(1);
    rtc_write_alarm(&temp);
    rtc_read_alarm(&temp);
    printf("rtc_default_alarm: %d-%d-%d %d:%d:%d\n", temp.year, temp.month, temp.day, temp.hour, temp.min, temp.sec);
    printf("---------------\n");

    dump_timer = usr_timer_add(NULL, (void *)rtc_time_test_dump, 1000, 0);
}

来源:rtc_demo.c

要点解读:

  • 平台数据只需提供默认时间与事件回调,trim_interval 缺省为 0(不校准);
  • 溢出回调必须在 rtc_init 之前注册,demo 借此把"是否关机"的决策权留在应用层(rtc_overflow_flag 置位后由应用决定是否 sys_softoff);
  • 闹钟设置采用"读当前时间 → datetime_add_seconds(+55) → 使能闹钟 → 写闹钟"的流程,保证闹钟时刻晚于当前时刻,避免"闹钟设置无效";
  • 用 usr_timer_add 创建 1s 周期定时器周期打印时间与闹钟。

溢出回调(跳过自动关机)

u32 rtc_overflow_callback(void)
{
    // 设置溢出标志
    rtc_overflow_flag = 1;
    return 1;
}

来源:rtc_demo.c

返回 1 表示跳过 RTC 内部的自动关机流程;同时置位标志,由应用层在合适时机(示例中为 rtc_init 返回后)统一处理关机。

事件回调与软关机前重置闹钟

void alm_ring_fun(const struct rtc_event_t *ev)
{
    if (ev->event & BIT(RTC_ALARM_EVENT)) {
        printf("\nalarm_wakeup_event\n");
    }
}

来源:rtc_demo.c

void rtc_reset_alarm_presoftoff_test(void)
{
    if (!dump_timer) {
        return;
    }
    // softoff前设置闹钟
    rtc_read_time(&temp);
    if (temp.sec < 55) {
        temp.sec += 5;
    } else {
        temp.min += 1;
        temp.sec -= 55;
    }
    rtc_alarm_switch(1);
    rtc_write_alarm(&temp);

    // 休眠 等待闹钟唤醒
    /* sys_softoff(); */
}

来源:rtc_demo.c

设计意图:rtc_reset_alarm_presoftoff_test 展示了标准的"关机前埋闹钟"模式——读取当前时间、加 5 秒(处理秒进位)、使能并写入闹钟,随后即可 sys_softoff() 进入低功耗等待闹钟唤醒。demo 中该函数被命名为 "pre-softoff"(软关机前),正是闹钟唤醒应用场景的模板。

配置选项

选项类型默认/可选值说明
control_rtc_enablebool全局常量RTC 模块总使能
control_rtc_clk_selu32CLK_SEL_32K(1) / CLK_SEL_12M(2) / CLK_SEL_24M(3) / CLK_SEL_LRC(4)RTC 时钟源选择
RTC_USE_HW_SFR宏BR28/BR27 为 1,其余为 0是否使用硬件特殊功能寄存器直读 RTC
rtc_dev_platform_data.default_sys_timeconst struct sys_time *必填首次启动的基准时间
rtc_dev_platform_data.cbfun函数指针可为 NULL事件回调(闹钟/唤醒/1Hz/校准)
rtc_dev_platform_data.trim_intervalu80校准间隔(分钟),0 表示不校准

API 参考

初始化与生命周期

  • int rtc_init(const struct rtc_dev_platform_data *arg) — 初始化 RTC,返回 0 成功、负值失败(rtc_dev.h)
  • u32 rtc_dev_deinit(void) — 注销 RTC 设备(rtc_dev.h)
  • void rtc_set_overflow_callback(u32(*skip_softoff_callback)(void)) — 注册溢出回调,须先于 rtc_init;回调返回 1 跳过自动关机(rtc_dev.h)

时间读写与状态

  • u32 rtc_read_time(struct sys_time *time) — 读取当前时间,返回 RTC 状态(RTC_SUCC 成功)(rtc_dev.h)
  • u32 rtc_write_time(const struct sys_time *time) — 写入/校准当前时间(rtc_dev.h)
  • u64 rtc_sys_timestamp_us(void) — 获取自 1970-01-01 起的微秒级时间戳(rtc_dev.h)
  • void rtc_wakup_source(void) — 查询/打印本次唤醒源(rtc_dev.h)
  • void rtc_debug_dump(void) — 打印 RTC 调试信息(rtc_dev.h)

闹钟管理

  • u32 rtc_read_alarm(struct sys_time *time) — 读取当前闹钟时间(rtc_dev.h)
  • u32 rtc_write_alarm(const struct sys_time *time) — 设置闹钟时间;无效时间可能返回 RTC_ERROR_ALM_NO_EFFECT(rtc_dev.h)
  • void rtc_alarm_switch(u32 en) — 使能(1)/禁用(0)闹钟(rtc_dev.h)
  • u32 rtc_is_alarm_en(void) — 查询闹钟是否使能(rtc_dev.h)

低功耗与持久化

  • u32 rtc_is_soff_need_keep_clk(void) — 判断软关机是否需要保持时钟(rtc_dev.h)
  • void rtc_save_context_to_vm(void) — 将 RTC 上下文保存到 VM,供掉电恢复(rtc_dev.h)
  • void rtc_lptmr_wakeup_enable(uint32_t wkup_ms) — 使能低功耗定时器唤醒(相对延时,毫秒)(rtc_dev.h)

RTC 端口操作

RTC 域内 GPIO 通过 rtc_port_pr_* 系列操作(rtc_dev.h):

  • int rtc_port_pr_read(u32 port) — 读取端口 PR 值
  • int rtc_port_pr_out(u32 port, u32 value) — 设置 PR 输出值
  • int rtc_port_pr_dir(u32 port, u32 dir) — 设置方向(0 输入,1 输出)
  • int rtc_port_pr_die(u32 port, u32 die) — 设置驱动能力
  • int rtc_port_pr_pu(u32 port, u32 value) / rtc_port_pr_pu1(...) — 设置上拉(类型 0/1)
  • int rtc_port_pr_pd(u32 port, u32 value) / rtc_port_pr_pd1(...) — 设置下拉(类型 0/1)
  • int rtc_port_pr_hd0(u32 port, u32 value) / rtc_port_pr_hd1(...) — 设置高驱动能力(类型 0/1)

统一返回 0 成功、负值失败。

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

溢出导致的意外关机(最重要)

RTC 定时器溢出是低功耗唤醒场景最典型的失败模式:若未注册溢出回调,驱动在初始化检测到溢出时会直接调用软关机(与旧版本行为一致)。这会造成"应用刚启动就被关机"的意外。规避手段:

  1. 在 rtc_init 前调用 rtc_set_overflow_callback() 注册回调并返回 1;
  2. 应用层根据 rtc_overflow_flag 决定是否关机及关机时机(见 rtc_demo.c)。

闹钟设置无效(RTC_ERROR_ALM_NO_EFFECT)

写入的闹钟时间早于或等于当前时间时,闹钟不会触发或立即触发,驱动可能返回 RTC_ERROR_ALM_NO_EFFECT。demo 的标准做法是先 rtc_read_time 再用 datetime_add_seconds 增加一个安全余量(如 5~55 秒),并处理秒/分进位,确保闹钟时刻严格晚于当前时刻。

时间不可靠(RTC_ACCESSIBLE_TIME_UNRELIABLE)

上电后若仅依赖 default_sys_time 启动且从未校时,rtc_read_time 返回的时间"可读但不可靠"(RTC_ACCESSIBLE_TIME_UNRELIABLE)。应用层(如日志时间戳、闹钟依赖)应检查返回值:使用不可靠时间可能导致闹钟偏差;应通过 rtc_write_time 校时或等待外部时间源(网络/NTP/对端同步)校准后再依赖 RTC。

低功耗下时钟源掉电

若 rtc_is_soff_need_keep_clk() 返回 0 或关机流程未保持 RTC 时钟域供电,关机后 RTC 停止走时,闹钟唤醒将不生效。因此"关机后仍能唤醒"必须满足两个前提:时钟源(32K/LRC)保持供电,且闹钟已使能并写入有效的未来时刻。

并发与中断上下文约束

RTC 事件(闹钟、唤醒、1Hz、校准)通过 cbfun 在中断/低功耗唤醒上下文中回调,回调内不应执行阻塞操作(如长时间打印、malloc、IO 等待),只应设置标志位或做轻量处理,实际业务逻辑延后到应用主循环(demo 即通过标志位 + 主循环判断实现)。时间换算工具为纯函数,无共享状态,可在任意上下文安全调用;但 rtc_read_time / rtc_write_time 等硬件访问若被中断打断,建议由驱动内部锁或应用层临界区保护(具体以驱动实现为准)。

性能与运维注意

  • 时钟源功耗权衡:32K 晶振精度高但需外部器件;LRC 免外部器件但漂移大,应配合 trim_interval 定期校准(如每分钟一次)。trim_interval 越小校准越准,但会带来更频繁的 1Hz/校准事件,增加唤醒次数与功耗,需在精度与功耗间取舍。
  • 校准事件开销:RTC_TRIM_EVENT 按分钟触发,回调处理需轻量;高频打印会显著增加功耗,rtc_time_test_dump 这类调试打印应仅在调试版本开启。
  • VM 持久化:rtc_save_context_to_vm() 应在关机前调用,保证复位后能恢复时间上下文;若跳过,重启后时间回退到 default_sys_time。
  • 微秒时间戳:rtc_sys_timestamp_us() 适合性能打点与高分辨率测量,但需注意其精度受时钟源(32K/LRC)本身精度限制,LRC 下不适合做精密计时。

扩展点

  1. 溢出决策接管:通过 rtc_set_overflow_callback 注册自定义回调,把"溢出后是否关机/何时关机"完全交给应用层——这是 SDK 明确暴露的策略扩展点。
  2. 事件回调:cbfun 可同时接收 RTC_ALARM_EVENT / RTC_WKUP_EVENT / RTC_1HZ_EVENT / RTC_TRIM_EVENT(事件字段支持位组合),应用可据此实现秒级心跳、周期校准或组合唤醒处理。
  3. 标准设备框架接入:rtc_dev_ops(struct device_operations)将 RTC 挂入 SDK 设备层,可像其他设备一样被上层统一管理、替换或包装。
  4. RTC 端口:rtc_port_pr_* 系列允许在 RTC 电源域内扩展 GPIO 功能(如低功耗按键、LED 指示),实现"关机后仍可读的 IO"。

相关链接

  • RTC 设备驱动头文件 rtc_dev.h — 本文档全部 API 的权威定义
  • RTC 演示工程 rtc_demo.c — 初始化、闹钟、溢出回调与软关机前的完整示例
  • 电源管理/低功耗子系统(asm/power_interface.h 中的 sys_softoff 等接口)属于电源管理页面主题,本文仅在唤醒流程中引用
  • VM 存储机制(rtc_save_context_to_vm 的持久化目标)参见数据存储相关文档
Prev
MCPWM 与电机控制
Next
段码 LCD 驱动