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_32K | 1 | 32kHz 晶振 | 高精度走时,适合需要准确日历的应用 |
CLK_SEL_12M | 2 | 12MHz 系统时钟 | 无 32K 晶振时使用,功耗较高 |
CLK_SEL_24M | 3 | 24MHz 系统时钟 | 无 32K 晶振时使用,功耗较高 |
CLK_SEL_LRC | 4 | 内部低速 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 标准设备框架,生命周期如下:
- 初始化:
rtc_set_overflow_callback()(可选,必须先于 init)→rtc_init(&platform_data),驱动依据default_sys_time与 VM 中保存的上下文决定初始时间; - 运行期:应用读写时间/闹钟、使能闹钟、查询状态,RTC 每秒产生
RTC_1HZ_EVENT(若注册),按trim_interval触发RTC_TRIM_EVENT校准; - 低功耗前:
rtc_is_soff_need_keep_clk()判断软关机是否需要保持时钟;如需保存当前时间上下文,调用rtc_save_context_to_vm()将 RTC 上下文写入 VM; - 注销:
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_enable | bool | 全局常量 | RTC 模块总使能 |
control_rtc_clk_sel | u32 | CLK_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_time | const struct sys_time * | 必填 | 首次启动的基准时间 |
rtc_dev_platform_data.cbfun | 函数指针 | 可为 NULL | 事件回调(闹钟/唤醒/1Hz/校准) |
rtc_dev_platform_data.trim_interval | u8 | 0 | 校准间隔(分钟),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 定时器溢出是低功耗唤醒场景最典型的失败模式:若未注册溢出回调,驱动在初始化检测到溢出时会直接调用软关机(与旧版本行为一致)。这会造成"应用刚启动就被关机"的意外。规避手段:
- 在
rtc_init前调用rtc_set_overflow_callback()注册回调并返回 1; - 应用层根据
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 下不适合做精密计时。
扩展点
- 溢出决策接管:通过
rtc_set_overflow_callback注册自定义回调,把"溢出后是否关机/何时关机"完全交给应用层——这是 SDK 明确暴露的策略扩展点。 - 事件回调:
cbfun可同时接收RTC_ALARM_EVENT/RTC_WKUP_EVENT/RTC_1HZ_EVENT/RTC_TRIM_EVENT(事件字段支持位组合),应用可据此实现秒级心跳、周期校准或组合唤醒处理。 - 标准设备框架接入:
rtc_dev_ops(struct device_operations)将 RTC 挂入 SDK 设备层,可像其他设备一样被上层统一管理、替换或包装。 - 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的持久化目标)参见数据存储相关文档