RTC 设备驱动
实时时钟(RTC)的主要功能是在系统掉电的情况下,利用备用电源使时钟继续运行,保证不会丢失时间信息。现以 S3C2440 芯片为例,介绍其内部 RTC 原理及驱动实现。
硬件原理
S3C2440 内部集成了 RTC 模块。其内部的寄存器 BCDSEC,BCDMIN,BCDHOUR,BCDDAY,BCDDATE,BCDMON 和 BCDYEAR 分别存储了当前的秒,分,小时,星期,日,月和年,表示时间的数值都是 BCD 码。这些寄存器的内容可读可写,并且只有在寄存器 RTCCON 的第 0 位为 1 时才能进行读写操作。为了防止误操作,当不进行读写时,要把该位清零。当读取这些寄存器时,用户能够获取当前的时间;当写入这些寄存器时,用户能够设置当前的时间。另外需要注意的是,因为有所谓的“一秒误差”,因此当读取到的秒为 0 时,需要重新再读取一遍这些寄存器的内容,才能保证时间的正确。
寄存器配置
现介绍 RTC 驱动编写中常用的寄存器。
- RTCCON 控制寄存器
用于选择时钟,使能/禁能 RTC 控制。在对存储时间信息的寄存器进行读写前,需要将该寄存器第 0 位置 1,读写结束后需要将该寄存器的第 0 位清零。
- BCDSEC
存储 RTC 时间当前秒信息,用 BCD 码表示。[6:4]取值范围 :0 至 5,[3:0]取值范围 :0 至 9。
- BCDMIN
存储 RTC 时间当前分信息,用 BCD 码表示。[6:4]取值范围 :0 至 5,[3:0]取值范围 :0 至 9。
- BCDHOUR
存储 RTC 时间当前时信息,用 BCD 码表示。[5:4]取值范围 :0 至 2,[3:0]取值范围 :0 至 9。
- BCDDAY
存储 RTC 时间当前星期信息,用 BCD 码表示。[2:0]取值范围 :1 至 7。
- BCDDATE
存储 RTC 时间当前日信息,用 BCD 码表示。[5:4]取值范围 :0 至 3,[3:0]取值范围 :0 至 9。
- BCDMON
存储 RTC 时间当前月信息,用 BCD 码表示。[4]取值范围 :0 至 1,[3:0]取值范围 :0 至 9。
- BCDYEAR
存储 RTC 时间当前年信息,用 BCD 码表示。[7:0]取值范围 :00 至 99。
驱动实现
现以 SylixOS 中 mini2440 的 BSP 为例,介绍该芯片中 RTC 驱动的具体实现。
RTC 设备控制块
首先封装 RTC 设备控制块,其具体结构如下:
#include <SylixOS.h>
typedef struct {
LW_DEV_HDR RTCDEV_devhdr; /* 设备头 */
PLW_RTC_FUNCS RTCDEV_prtcfuncs; /* 操作函数集 */
} LW_RTC_DEV;
- RTCDEV_devhdr :RTC 设备头。
- RTCDEV_prtcfuncs :RTC硬件接口函数。
其中RTC设备头结构参照“字符设备的创建及管理”小节,RTC 硬件接口函数结构如下:
#include <SylixOS.h>
typedef struct {
VOIDFUNCPTR RTC_pfuncInit; /* 初始化 RTC */
FUNCPTR RTC_pfuncSet; /* 设置硬件 RTC 时间 */
FUNCPTR RTC_pfuncGet; /* 读取硬件 RTC 时间 */
FUNCPTR RTC_pfuncIoctl; /* 更多复杂的 RTC 控制 */
/* 例如设置唤醒闹铃中断等等 */
} LW_RTC_FUNCS;
- RTC_pfuncInit :RTC 初始化。
- RTC_pfuncSet :RTC 时间设置。
- RTC_pfuncGet :RTC 时间获取。
- RTC_pfuncIoctl :RTC 其他 I/O 控制。
RTC 设备接口函数获取
RTCDEV_prtcfuncs 接口函数由驱动中 rtcGetFuncs 函数获取。其调用关系如下:
PLW_RTC_FUNCS rtcGetFuncs (VOID)
{
static LW_RTC_FUNCS rtcfuncs = {LW_NULL,
__rtcSetTime,
__rtcGetTime,
LW_NULL};
return (&rtcfuncs);
}
可见,RTC 的硬件操作函数主要实现了 RTC 的时间设置和时间获取函数。
__rtcSetTime :RTC 时间设置
#include <SylixOS.h>
static int __rtcSetTime (PLW_RTC_FUNCS prtcfuncs, time_t *ptimeNow);
函数 __rtcSetTime 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 prtcfuncs 是 RTC 硬件接口函数。
- 参数 ptimeNow 是当前时间,参数类型 time_t 是 long long 类型。
__rtcSetTime :RTC时间设置
#include <SylixOS.h>
static int __rtcGetTime (PLW_RTC_FUNCS prtcfuncs, time_t *ptimeNow);
函数 __ rtcGetTime 原型分析:
- 此函数成功返回 ERROR_NONE ,输出当前 RTC 时间。
- 参数 prtcfuncs 是 RTC 硬件接口函数。
- 参数 ptimeNow 是当前时间,参数类型 time_t 是 long long 类型。
RTC 设备驱动安装
调用 API_RtcDrvInstall 函数安装 RTC 设备驱动程序,其详细描述如下:
#include <SylixOS.h>
INT API_RtcDrvInstall (VOID);
函数 API_RtcDrvInstall 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR 。
该函数中主要调用 API_IosDrvInstall 安装RTC的 Open、Close、Ioctl 操作函数,调用如下:
_G_iRtcDrvNum = iosDrvInstall(__rtcOpen,
(FUNCPTR)LW_NULL,
__rtcOpen,
__rtcClose,
LW_NULL,
LW_NULL,
__rtcIoctl);
__rtcOpen :打开 RTC 设备,打开操作主要是将 RTC 设备打开次数加 1。
#include <SylixOS.h>
static LONG __rtcOpen (PLW_RTC_DEV prtcdev,
PCHAR pcName,
INT iFlags,
INT iMode);
函数 __rtcOpen 原型分析:
- 此函数成功返回 RTC 设备结构体。
- 参数 prtcdev 是 RTC 设备结构体。
- 参数 pcName 是设备名。
- 参数 iFlags 是打开方式。
- 参数 iMode 是打开方法。
__rtcClose :关闭RTC设备,关闭操作主要是将 RTC 设备打开次数减 1。
#include <SylixOS.h>
static LONG __rtcClose (PLW_RTC_DEV prtcdev);
函数 __rtcClose 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR 。
- 参数 prtcdev 是RTC设备结构体。
__rtcIoctl :控制RTC设备,主要是设置 RTC 时间和获取 RTC 时间。
#include <SylixOS.h>
static INT __rtcIoctl (PLW_RTC_DEV prtcdev, INT iCmd, PVOID pvArg);
函数 __rtcIoctl 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR 。
- 参数 prtcdev 是 RTC 设备结构体。
- 参数 iCmd 是控制命令。
- 参数 pvArg 是控制参数。
注意:
rtcIoctl 函数最终调用的就是 RTC 硬件接口函数中的 rtcSetTime 和 __rtcGetTime 函数来设置 RTC 时间和获取 RTC 时间。
RTC 设备创建和管理
调用 API_RtcDevCreate 创建 RTC 设备并将设备加入设备链表进行管理。其函数原型如下:
#include <SylixOS.h>
INT API_RtcDevCreate (PLW_RTC_FUNCS prtcfuncs);
函数 API_RtcDevCreate 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR 。
- 参数 prtcfuncs 是 RTC 操作函数集。
RTC 时间同步
RTC 设备创建完成并安装完设备驱动程序后,即可调用 API_RtcToSys 内核函数获取 RTC 当前时间,并将获取到的时间同步到系统时间。其函数原型如下:
#include <SylixOS.h>
INT API_RtcToSys (VOID);
函数 API_RtcToSys 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR 。