2.8. RTC

2.8.1. 概述

AC792N 芯片内置一个 RTC(实时时钟)模块,可提供系统时间计时、闹钟唤醒以及 PR 口唤醒等功能。

主要特性:

  • 支持多种时钟源选择:外部 32K 晶振、内部 LRC

  • 支持系统时间读写(年/月/日/时/分/秒)

  • 支持闹钟功能

  • 支持 PR 口(PR0~PR1)唤醒,可配置唤醒边沿和滤波时间

  • 支持 PR 口 GPIO 基本操作(输入/输出/上下拉/强驱/数字输入)

  • 振荡器驱动电流可配

例程路径: apps/common/example/peripheral/rtc/rtc_test.c,可使用hello_demo工程测试,使用时在app_config.h中使能相应例程的宏开关USE_RTC_TEST_DEMO


2.8.2. RTC 参数配置

2.8.2.1. 配置结构体

RTC 的平台配置通过 rtc_platform_data 结构体完成,各字段含义如下:

字段

类型

说明

default_sys_time

struct sys_time

默认系统时间。当 RTC 未被设置过时间时,将此值作为初始时间

alarm_wakeup_cb_in_irq

void (*)(void)

闹钟中断回调函数,在中断上下文中调用

pr_wakeup_cb_in_irq

void (*)(int)

PR 口唤醒中断回调函数,参数为唤醒的 PR 口编号

clk_sel

rtc_clk_sel_t

RTC 时钟源选择

x32xs

x32xs_t

32K 振荡器驱动电流档位

sys_time 结构体定义:

struct sys_time {
    u16 year;   // 年
    u8  month;  // 月
    u8  day;    // 日
    u8  hour;   // 时
    u8  min;    // 分
    u8  sec;    // 秒
};

Board 层配置示例:

#if TCFG_RTC_ENABLE
// 闹钟唤醒回调(在中断上下文中执行)
static void alarm_wakeup_cb_in_irq(void)
{
    // TODO,不要加打印
}

// PR口唤醒回调(在中断上下文中执行)
static void pr_wakeup_cb_in_irq(int port)
{
    // TODO,不要加打印
}

// RTC平台数据初始化
RTC_PLATFORM_DATA_BEGIN(rtc_data)
    .default_sys_time       = {
        .year               = 2024,
        .month              = 1,
        .day                = 1,
        .hour               = 0,
        .min                = 0,
        .sec                = 0,
    },
    .alarm_wakeup_cb_in_irq = alarm_wakeup_cb_in_irq,
    .pr_wakeup_cb_in_irq    = pr_wakeup_cb_in_irq,
    .clk_sel                = TCFG_RTC_CLK_SEL,
    .x32xs                  = TCFG_RTC_X32XS_LEVEL,
RTC_PLATFORM_DATA_END()
#endif // TCFG_RTC_ENABLE

2.8.2.2. 应用配置宏

app_config.h 中通过以下宏配置 RTC 使能和参数:

//*********************************************************************************//
//                                  RTC配置                                        //
//*********************************************************************************//
#ifdef USE_RTC_TEST_DEMO
#define TCFG_RTC_ENABLE                     1       // RTC功能使能
#define TCFG_RTC_CLK_SEL                    CLK_SEL_32K     // 时钟源:外部32K晶振
#define TCFG_RTC_X32XS_LEVEL                X32XS_LEVEL_1   // 晶振驱动电流档位
#endif // USE_RTC_TEST_DEMO

配置说明:

可选值

说明

TCFG_RTC_ENABLE

0 / 1

RTC 功能使能开关,置 1 开启

TCFG_RTC_CLK_SEL

CLK_SEL_32K / CLK_SEL_LRC

RTC 时钟源选择,推荐使用 CLK_SEL_32K,暂不支持BTOSC

TCFG_RTC_X32XS_LEVEL

X32XS_LEVEL_0 ~ X32XS_LEVEL_3

外部 32K 振荡器驱动电流

2.8.2.3. 注册设备

在板级设备表中将 RTC 设备注册到系统:

// 设备表注册
REGISTER_DEVICES(device_table) = {
// ...
#if TCFG_RTC_ENABLE
    { "rtc", &rtc_dev_ops, (void *)&rtc_data },
#endif
// ...
};

2.8.3. RTC 驱动使用

2.8.3.1. 板级初始化

在使用 RTC 之前,需要在板级代码中完成以下初始化步骤。RTC 初始化依赖 ADC 模块,必须确保 ADC 先于 RTC 初始化。

初始化顺序(按启动流程):

步骤1: power_early_flowing() 中设置平台数据并初始化电源时钟:

void power_early_flowing(void)
{
    PORT_TABLE(g);

    // ... 其他初始化 ...
    power_set_mode(TCFG_POWER_MODE);

#if TCFG_RTC_ENABLE
    set_rtc_platform_data(&rtc_data);
#endif
}

步骤2: board_power_init() 中通过 PCONTROL_RTC_CLK 命令告知 power RTC的时钟源,防止低功耗流程影响RTC晶振配置:

static void board_power_init(void)
{
#if TCFG_RTC_ENABLE
    power_control(PCONTROL_RTC_CLK, TCFG_RTC_CLK_SEL);
#endif
    // ... 其他电源控制 ...
}

步骤3: board_init() 中初始化 ADC 和 RTC:

void board_init(void)
{
    // ...
#if TCFG_ADKEY_ENABLE || TCFG_RTC_ENABLE
    adc_init();         // ADC必须先于RTC初始化
#endif

#if TCFG_RTC_ENABLE
    rtc_early_init();   // RTC开机初始化
#endif
    // ...
}

2.8.3.2. 打开设备

RTC 设备名为 "rtc",通过标准驱动接口 dev_open() 打开:

void *rtc_hdl;

rtc_hdl = dev_open("rtc", NULL);
if (!rtc_hdl) {
    printf("err: rtc open fail!!!\n");
    return;
}

2.8.3.3. 获取/设置系统时间

通过 dev_ioctl() 读写系统时间:

struct sys_time time;

// 获取当前系统时间
dev_ioctl(rtc_hdl, IOCTL_GET_SYS_TIME, (u32)&time);
printf("%d-%02d-%02d %02d:%02d:%02d\n",
       time.year, time.month, time.day,
       time.hour, time.min, time.sec);

// 设置系统时间
time.sec = 0;
dev_ioctl(rtc_hdl, IOCTL_SET_SYS_TIME, (u32)&time);
printf("set_sys_time: %d-%02d-%02d %02d:%02d:%02d\n",
       time.year, time.month, time.day,
       time.hour, time.min, time.sec);

2.8.3.4. 闹钟功能

RTC 支持两种闹钟模式:

模式1:绝对时间闹钟(指定具体时间点)

struct sys_time alarm_time;

alarm_time.sec = 59;  // 设置闹钟时间为当前分钟的第59秒
dev_ioctl(rtc_hdl, IOCTL_SET_ALARM, (u32)&alarm_time);

// 使能闹钟
dev_ioctl(rtc_hdl, IOCTL_SET_ALARM_ENABLE, 1);

模式2:倒计时闹钟(指定延迟秒数)

dev_ioctl(rtc_hdl, IOCTL_SET_COUNTDOWN_ALARM, 30);   // 30秒后闹钟触发

// 使能闹钟
dev_ioctl(rtc_hdl, IOCTL_SET_ALARM_ENABLE, 1);

注意: 闹钟触发后,rtc_platform_data 中配置的 alarm_wakeup_cb_in_irq 回调函数将在中断上下文中被调用。请在回调中仅做必要的标志位设置,避免阻塞操作。

获取当前闹钟配置:

struct sys_time alarm_info;
dev_ioctl(rtc_hdl, IOCTL_GET_ALARM, (u32)&alarm_info);

PR口作IO的基本操作:

// 设置PR口方向
rtc_port_pr_dir(IO_PORT_PR_01, 1);     // 1: 输入, 0: 输出

// 读取PR口输入电平
int level = rtc_port_pr_read(IO_PORT_PR_01);  // 0: 低电平, 1: 高电平

// 设置PR口输出电平
rtc_port_pr_out(IO_PORT_PR_01, 1);     // 1: 高电平, 0: 低电平

// 设置PR口强驱
rtc_port_pr_hd(IO_PORT_PR_01, 1);      // 1: 打开, 0: 关闭

// 设置上拉/下拉
rtc_port_pr_pu(IO_PORT_PR_01, 1);      // 1: 打开上拉
rtc_port_pr_pd(IO_PORT_PR_01, 0);      // 0: 关闭下拉

// 设置数字输入功能
rtc_port_pr_die(IO_PORT_PR_01, 1);     // 1: 打开, 0: 关闭

2.8.3.5. 软关机保存时间

RTC时钟源选择LRC时,软关机前需调用 poweroff_save_rtc_time() 保存 RTC 校准数据:

u8 power_soff_callback(void)
{
#if TCFG_RTC_ENABLE
    poweroff_save_rtc_time();  // 软关机前保存RTC校准数据
#endif
    // ...
}

2.8.3.6. PR 口唤醒功能

RTC 模块提供 PR 口(PR0~PR1)的 IO 操作和唤醒功能。详见《开关机-唤醒开机》章节


2.8.4. RTC IOCTL 命令

IOCTL 命令

功能说明

参数类型

IOCTL_GET_SYS_TIME

获取当前系统时间

struct sys_time *

IOCTL_SET_SYS_TIME

设置系统时间

struct sys_time *

IOCTL_GET_ALARM

获取当前闹钟配置

struct sys_time *

IOCTL_SET_ALARM

设置绝对时间闹钟

struct sys_time *

IOCTL_SET_ALARM_ENABLE

闹钟使能/关闭

bool (1=使能, 0=关闭)

IOCTL_SET_COUNTDOWN_ALARM

设置倒计时闹钟

u32 (倒计时秒数)


2.8.5. 常见问题说明

1、RTC 初始化失败

答:RTC 初始化依赖 ADC 模块,若 ADC 未初始化或初始化顺序错误会导致 RTC 异常。 确保 adc_init()rtc_early_init() 之前调用。

2、系统复位后时间丢失

答:系统复位重启,RTCVDD在断电复位后会重新从 default_sys_time 开始计时。该行为为硬件特性。若需要掉电保持时间,需外接备用电池供电。

3、RTC模块报错"RTC_UNACCESSIBLE!!! Please ensure the power supply of RTCVDD"

答:RTCVDD工作电压太低,无法获取RTC值。RTCVDD电压要求大于等于2.0V

4、RTC模块报错"RTC_ACCESSIBLE_TIME_UNRELIABLE!!!"

答:RTC模块出现复位,获取到的RTC时间不可靠。


2.8.6. API 参考

ioctl cmd for rtc

RTC_MAGIC
IOCTL_GET_SYS_TIME
IOCTL_SET_SYS_TIME
IOCTL_GET_ALARM
IOCTL_SET_ALARM
IOCTL_SET_ALARM_ENABLE

RTC时钟源选择

enum rtc_clk_sel_t

Values:

enumerator CLK_SEL_32K
enumerator CLK_SEL_BTOSC_DIV1
enumerator CLK_SEL_BTOSC_DIV2
enumerator CLK_SEL_LRC

PR口唤醒边沿

enum pr_io_wkup_edge_t

Values:

enumerator PR_RISING_EDGE
enumerator PR_FALLING_EDGE
enumerator PR_BOTH_EDGE

PR口唤醒滤波时间

enum pr_io_wkup_flt_t

Values:

enumerator PR_PORT_FLT_DISABLE
enumerator PR_PORT_FLT_16us
enumerator PR_PORT_FLT_128us
enumerator PR_PORT_FLT_1ms
enumerator PR_PORT_FLT_4ms

振荡器电流选项

enum x32xs_t

Values:

enumerator X32XS_LEVEL_0
enumerator X32XS_LEVEL_1
enumerator X32XS_LEVEL_2
enumerator X32XS_LEVEL_3

rtc_platform_data

void set_rtc_platform_data(const struct rtc_platform_data *priv)
int rtc_early_init(void)

rtc开机初始化函数,必须先初始化完adc

void poweroff_save_rtc_time(void)

软关机前保存rtc校准数据

int rtc_port_pr_dir(int port, u8 dir)

设置PR口的方向

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • dir – 1: 输入 0: 输出

Returns

0: 成功 非0: 失败

int rtc_port_pr_read(int port)

获取PR口输入电平

Parameters

gpio – 参考宏IO_PORT_PR_0X

Returns

0: 低电平 1: 高电平

int rtc_port_pr_out(int port, u8 on)

设置PR口的输出电平

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • on – 1: 高电平 0: 低电平

Returns

0: 成功 非0: 失败

int rtc_port_pr_hd(int port, u8 on)

设置PR口的强驱

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • on – 1: 打开 0: 关闭

Returns

0: 成功 非0: 失败

int rtc_port_pr_pu(int port, u8 on)

设置PR口的上拉电阻

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • on – 1: 打开 0: 关闭

Returns

0: 成功 非0: 失败

int rtc_port_pr_pd(int port, u8 on)

设置PR口的下拉电阻

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • on – 1: 打开 0: 关闭

Returns

0: 成功 非0: 失败

int rtc_port_pr_die(int port, u8 on)

设置PR口的数字输入功能

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • on – 1: 打开 0: 关闭

Returns

0: 成功 非0: 失败

int rtc_port_pr_wkup_cfg(int port, pr_io_wkup_edge_t wkup_edge, pr_io_wkup_flt_t flt_cfg)

设置PR口的唤醒功能

Parameters
  • gpio – 参考宏IO_PORT_PR_0X

  • wkup_edge – 唤醒边沿

  • flt_cfg – 唤醒滤波时间

Returns

0: 成功 非0: 失败

int rtc_port_pr_wkup_disable(int port)

关闭PR口的唤醒功能

Parameters

gpio – 参考宏IO_PORT_PR_0X

Returns

0: 成功 非0: 失败

struct rtc_platform_data

Public Members

struct sys_time default_sys_time
void (*alarm_wakeup_cb_in_irq)(void)
void (*pr_wakeup_cb_in_irq)(int)
rtc_clk_sel_t clk_sel
x32xs_t x32xs