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,此文件只可以读

相关推荐
野蛮的大西瓜5 天前
BigBlueButton视频会议 vs 华为云会议的详细对比
人工智能·自动化·音视频·实时音视频·信息与通信·视频编解码
野蛮的大西瓜5 天前
文心一言对接FreeSWITCH实现大模型呼叫中心
人工智能·机器人·自动化·音视频·实时音视频·文心一言·信息与通信
野蛮的大西瓜5 天前
BigBlueButton视频会议 vs 钉钉视频会议系统的详细对比
人工智能·自然语言处理·自动化·音视频·实时音视频·信息与通信·视频编解码
Whappy0015 天前
《第十二部分》1.STM32之RTC实时时钟介绍---BKP实验
stm32·嵌入式硬件·实时音视频
嵌入式小强工作室7 天前
如何在STM32中使用RTC定时器
stm32·单片机·实时音视频
野蛮的大西瓜7 天前
BigBlueButton视频会议 vs 华为视频会议系统的详细对比
人工智能·机器人·自动化·音视频·实时音视频·信息与通信·视频编解码
m0_370565229 天前
stm32 rtc 详解
stm32·单片机·实时音视频
菊风 Juphoon10 天前
物联网养宠,实时音视频为宠物行业“加码”
物联网·实时音视频·宠物
陌夏微秋10 天前
STM32单片机芯片与内部24 RTC——内部实时时钟 简介 特性 框图 原理 UNIX
stm32·单片机·嵌入式硬件·硬件工程·实时音视频·信息与通信·智能硬件
陌夏微秋10 天前
STM32单片机芯片与内部25 RTC BKP——数据手册 寄存器介绍
stm32·单片机·嵌入式硬件·实时音视频·信息与通信·智能硬件