RK3568平台 RTC时间框架

一.RTC时间框架概述

RTC(Real Time Clock)是一种用于计时的模块,可以是再soc内部,也可以是外部模块。对于soc内部的RTC,只需要读取寄存器即可,对于外部模块的RTC,一般需要使用到I2C接口进行读取。至于如何供电,都是可以在主电源断开后使用纽扣电源辅助供电,达到设备断电仍然可以计时的效果。

对于soc内部的RTC,需要额外的晶振,而外部模块的RTC不需要。

在linux内核里,rtc是一个字符设备,内核实现了一个通用的字符设备层,提供给应用层系统调用,给底下的RTC硬件驱动层提供注册接口。每款RTC需要编写对应的硬件驱动,填写读取和设置时间的回调函数,并且注册进系统。从上到下分别是应用层、rtc通用字符设备层、rtc底层驱动层。

Linux 内核中,RTC 驱动的结构图如下所示, 可以分为三个层次:

接口层,负责向用户空间提供操作的结点以及相关接口。

• RTC Core, 为rtc 驱动提供了一套API, 完成设备和驱动的注册等。

• RTC 驱动层,负责具体的RTC 驱动实现,如设置时间、闹钟等设置寄存器的操作。

二.RTC设备驱动

申请rtc_device,RTC注册函数:

复制代码
struct rtc_device *devm_rtc_device_register(struct device *dev,  
                              const char *name, 
                              const struct rtc_class_ops *ops,  
                              struct module *owner)

这个接口会自动帮你从设备树的aliases节点获取rtcx的序号,如果没有填写就自动分配一个序号。

注销rtc_device,RTC注销函数:

复制代码
void devm_rtc_device_unregister(struct device *dev,  
                           struct rtc_device *rtc)

内核RTC框架提供了3中数据结构:

struct rtc_time、struct rtc_device和struct rtc_device_ops结构,其定义如下:

复制代码
struct rtc_time {
    int tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year/*从1900开始*/;
    int tm_wday, tm_yday, tm_isdst/*夏令时标志*/;
};
 
struct rtc_device {
    struct device dev;
    struct module *owner;
    int id; // 由内核提供给rtc设备的全局索引,/dev/rtc<id>
    char name[RTC_DEVICE_NAME_SIZE];
    const struct rtc_class_ops *ops; // 一组操作,例如 设置/读取 时间/闹钟
    struct mutex ops_lock;
    struct cdev char_dev;
    ulong flags;
 
    ulong irq_data;
    spinlock_t irq_lock;
    wait_queue_head_t irq_queue;
 
    struct rtc_task *irq_task;
    spinlock_t irq_task_lock;
    int irq_freq;
    int max_user_freq;
 
    struct work_struct irqwork;
};
 
struct rtc_class_ops {
    int (*open)(struct device *dev); // 用户在设备/dev/rtc1上调用read时的callback
    int (*release)(struct device *dev);// 用户在设备/dev/rtc1上调用close时的callback
    int (*ioctl)(struct device *dev, uint cmd, ulong arg); // 用户在设备/dev/rtc1上调用ioctl时的callback
    int (*read_time)(struct device *dev, struct rtc_time *tm); // rtc内核的回调函数
    int (*set_time)(struct device *dev, struct rtc_time *tm);
    int (*read_alarm)(struct device *dev, struct rtc_wkalrm *alarm);
    int (*set_alarm)(struct device *dev, struct rtc_wkalrm *alarm);
    int (*read_callback)(struct device *dev, int data); // 用户在设备/dev/rtc1上调用read时的callback
    int (*alarm_irq_enable)(struct device *dev, uint enabled);
};
 
// rtc模块提供了宏to_rtc_device(d)把 struct device结构转变为struct rtc_device{}结构

读取和设置时间 :

驱动程序负责提供读取和设置设备时间的函数。RTC总是以二进制编码的格式存储/恢复时间,其中每个4位表示0~9而非0~F,内核提供bcd2bin()和bin2bcd()两个转换的宏。提供辅助函数rtc_valid_tm(struct rtm_time *)用于确定struct rtc_time{}表示合法的时间。

函数使用示例:

复制代码
static int foo_rtc_read_time(struct device *dev, struct rtc_time *tm) {
    struct foo_regs regs;
    int error = foo_device_read(dev, &regs, 0, sizeof(regs));
    if (error) return error;
    tm->tm_sec = bcd2bin(regs.seconds);
    tm->tm_min = bcd2bin(regs.minutes);
    tm->tm_hour = bcd2bin(regs.cent_hours);
    tm->tm_mday = bcd2bin(regs.date);
    tm->tm_wday = bcd2bin(regs.day) - 1;
    tm->tm_mon = bcd2bin(regs.month) - 1;
    tm->tm_year = bcd2bin(regs.years) + 100; // 设备的epoch是2000,加回到1900
    return rtc_valid_tm(tm);
}
 
static int foo_rtc_set_time(struct device *dev, struct rtc_time *tm) {
    struct foo_regs regs;
    regs.seconds = bin2bcd(tm->tm_sec);
    regs.minutes = bin2bcd(tm->tm_min);
    regs.cent_hours = bin2bcd(tm->tm_hour);
 
    regs.day = bin2bcd(tm->tm_wday + 1);
    regs.date = bin2bcd(tm->tm_mday);
 
    regs.month = bin2bcd(tm->tm_mon + 1);
 
    regs.cent_hours |= BQ32K_CENT;
    regs.years = bin2bcd(tm->tm_year % 100);
    return write_into_device(dev, &regs, 0, sizeof(regs));
}

三.RTC用户空间

rtc在sys中拥有一个类,可以查看一些信息。

  • name 查看rtc型号

  • range 查看rtc支持的起始时间和结束时间

  • date 查看rtc当前日期

  • time 查看rtc当前时间

  • since_epoch 查看当前rtc时间距离epoch经历了多少秒,epoch是一个时间点1970 年 1 月 1 日凌晨零点零分零秒

  • hctosys 这个rtc是否在上电时候同步设置系统时间

  • max_user_freq 可读可写用于查看和设置RTC周期中断的最大频率,一般是1hz

  • offset 查看和设置当前的rtc校准精度的偏移值,和回调read_offset、set_offset有关,注意是ppb为单位,而且是可正可负

  • wakealarm 查看和设置闹钟时间,有的rtc会被隐藏起来这个属性,sys属性如何隐藏可以参考rtc_attr_group、rtc_attr_is_visible、rtc_does_wakealarm这三个。

在注册rtc驱动的时候,会自动在proc注册一个文件/proc/driver/rtc,此文件只可以读

相关推荐
海水冷却18 小时前
2026年实时音视频服务计费模式指南
实时音视频
番茄灭世神3 天前
PN学堂GD32教程第8篇——RTC
实时音视频
runner365.git3 天前
RTC实现VoiceAgent(二)
大模型·webrtc·实时音视频·voiceagent
xuxie993 天前
N18 RTC
单片机·嵌入式硬件·实时音视频
runner365.git4 天前
RTC会议实时翻译系统
实时音视频
runner365.git4 天前
如何使用RTCPilot配置一个集群RTC服务
webrtc·实时音视频·音视频开发
深念Y5 天前
从WebSocket到WebRTC,豆包级实时语音交互背后的技术演进
websocket·网络协议·实时互动·webrtc·语音识别·实时音视频
海水冷却8 天前
2026 主流 RTC SDK 选型参考,7 大维度横向对比
实时音视频·rtc
TEL189246224779 天前
IT6636/IT66362(3进1出 / 2进1出 HDMI 2.1 48Gbps Retiming Switch,内置 MCU)
音视频·实时音视频·视频编解码
天上路人14 天前
A-59F 多功能语音处理模组在本地会议系统扩音啸叫处理中的技术应用与性能分析
人工智能·神经网络·算法·硬件架构·音视频·语音识别·实时音视频