本文转载自:http://blog.csdn.net/yaozhenguo2006/article/details/6820218

这个是linux内核文档关于rtc实时时钟部分的说明,此文档主要描述了rtc实时时钟的作用和编程接口,分别介绍了老的rtc接口和新的rtc类架构。并给出了一个测试rtc驱动的程序。

    linux 实时时钟(RTC)驱动
                                                                        翻译:窗外云天yaozhenguo2006@126.com
                                    最后矫正时间:2011.9.25

当linux开发者提到“实时时钟”的时候,他们通常所指的就是墙钟时间,这个时间是电池供电的,所以在系统掉电的情况下还能正常工作。除非在MS-Windows启动的时候设置,否则这个时钟不会同步于本地时区和夏令时间。事实上,他被设置成格林威治时间。
        最新的非pc体系的硬件趋向于记秒数,比如time(2)系统调用的输出,但是实时时钟用公历和24小时表示日期与时间,比如gmtime(3)的输出。
        linux提供两类的rtc兼容性很高的用户空间系统调用接口,如下所示:
       (1) /dev/rtc ... 这个RTC适合pc体系的系统,而并不适合非x86体系的系统
       (2) /dev/rtc0,/dev/rtc1 ... 他们依赖一种架构,这种架构在所有的系统上被RTC芯片广泛的支持。
        程序员必须知道,PC/AT的功能不总是有效,其他的系统可能会有另外的实现。这种情况下,如果在相同的系统结构上使用同样的RTC API,那么硬件会有不同的反应。例如,不是每一个RTC都提供IRQ,所以这些不能处理报警中断;标准的PC系统RTC只能处理未来24小时以内的闹钟,而其他系统的RTC可能处理未来一个世纪的任何时间。
        老的PC/AT驱动:/dev/rtc
        所有基于PC的系统(甚至Alpha体系的机器)都有一个集成的实时时钟。通常他们集成在计算机的芯片组内,但是也有一些系统是在主板上焊接着摩托罗拉MC146818(或者类似的芯片),他们给系统提供时间和日期,这个时间和日期在系统掉电后仍然会保存。
        ACPT(高级配置与电源管理接口)对MC146818的功能进行了标准化,并且在一些方面进行了功能扩展(提供了更长的定时周期,睡眠唤醒功能)。然而这些扩展的功能不适合老的驱动程序。
        这个RTC还可以产生频率从 2HZ 到 8192HZ 的信号,以2的乘方增长。这些信号通过中断信号线8报告给系统。这个RTC还可以用作定时限制为24小时的闹钟,当定时时间到时产生8号中断。这个闹钟可以设置成任意一个可编程值的子集,这意味着可以设置成任意小时的任意分钟任意秒,例如,可以将这个时钟设置成在每个clk产生中断,从而产生1hz的信号。
        这些中断通过/dev/rtc报告给系统(主设备号10,次设备号135,只读字符设备),中断传回一个无符号整数类型的数据。最低的位包含中断的类型(更新,闹钟,或者期),其他的字节代表了最后一次读到现在中断发生的次数。状态信息由虚拟文件/proc/driver/rtc产生,前提条件是使能了/proc文件系统。驱动应该提供锁机制,保证在同一时刻只有一个进程访问/dev/rtc。
        用户进程通过系统调用read(2)或者select(2)读取/dev/rtc来获取这些中断。当调用这两个系统调用的时候,进程会阻塞或者退出直到下一个中断到来。这个功能用在需要不频繁的获取数据而又不希望通过轮询当前时间而占用CPU时间的情况下。
        在高频率中断或者高系统负载下,用户进程应该检查从上次读取到现在发生中断的次数以判断是否有未处理的中断。例如,一个典型的 486-33 对/dev/rtc以大于1024hz的频率进行循环读,偶尔会产生中断积累(从上次读取到现在发生大于一次的中断)。鉴于此你应该检查读取数据的高字节,特别是在频率高于普通定时器中断--100hz的情况下。
        中断频率是可编程的或可以让他超过64hz,但是只有root权限的用户可以这样做。这样做可能有点保守,但是我们不希望有恶意的用户在一个较慢的386sx-16机器上产生很多中断,这样会严重影响系统的性能。我们可以通过向/proc/sys/dev/rtc/max-user-freq写入值来修改这个64hz的限制。但是注意你一定要这样做,减少中断处理程序的代码才会亡羊补牢,使对系统性能的影响降到最小。
        如果内核时间是和外部时钟源同步的,那么内核将每隔11分钟就会将时间写回CMOS时钟。在这个过程中,内核会关闭rtc周期中断,如果你的程序在做一些关键的工作一定要注意到。如果你的内核不和外部时钟源同步,那么内核会一直处理rtc中断,处理方式根据你具体的应用。
        闹钟和中断频率可以通过系统调用ioctl(2)来设置,ioctl的命令定义在./include/linux/rtc.h。与其长篇大论的介绍怎么样使用这个系统调用,还不如写一个实例程序来的方便,这个程序用来演示驱动的功能,对很多人来说用驱动程序提供的功能来进行应用编程他们会更感兴趣。在这个文档的最后有这段程序。
    新接口 “RTC类” 驱动:/dev/rtcn
        因为linux支持许多非ACPI非PC平台,其中一些平台有不只一个RTC,所以需要更多可移植性的设计,而不是仅仅在每个系统都实现类似MC146818的接口。在这种情况下,新的“RTC类”构架产生了。他提供不同的用户空间接口:
       (1) /dev/rtcn 和老的接口一样
       (2)/dev/class/rtc/rtcn   sysfs 属性,一些属性是只读的
       (3) /dev/driver/rtc 第一个rtc会使用procfs接口。更多的信息会显示在这里而不是sysfs。
        RTC类构架支持很多类型的RTC,从集成在嵌入式SOC处理器内的RTC到通过I2C,SPI和其他总线连接到CPU的芯片。这个架构甚至还支持PC系统的RTC,包括使用ACPI,PC的一些新特性。
        新架构也打破了“每个系统只有一个RTC”的限制。例如,一个低功耗电池供电的RTC是一个分离的I2C接口的芯片,但是系统可能还集成了一个多功能的RTC。系统可能从分离的RTC读取系统时钟,但是对于其他任务用集成的RTC,因为这个RTC提供更多的功能。
SYSFS 接口
--------------------
        在/sys/class/rtc/rtcn下面的sysfs接口提供了操作rtc属性的方法,而不用通过Ioclt系统调用。所有的日期时间都是墙钟时间,而不是系统时间。
date:                         RTC提供的日期
hctosys:                   如果在内核配置选项中配置了CONFIG_RTC_HCTOSYS,RTC会在系统启动的时候提供系统时间,这种情况下这个位就是1,否则为0
max_user_freq:     非特权用户可以从RTC得到的最大中断频率
name:                       RTC的名字,与sysfs目录相关
since_epoch:         从纪元开始所经历的秒数
time:                          RTC提供的时间
wakealarm:             唤醒时间的时间事件。 这是一种单次的唤醒事件,所以如果还需要唤醒,在唤醒发生后必须复位。这个域的数据结构或者是从纪元开始经历的妙数,或者是相对的秒数
IOCTL 接口
----------------------
        /dev/rtc支持的Ioctl系统调用,RTC类构架也支持。然而,因为芯片和系统没有一个统一的标准,一些PC/AT功能可能没有提供。以相同方式工作的一些新特性,--包括ACPI提供的,--在RTC类构架中表现出的,在老的驱动上不会工作。
     (1) RTC_RD_TIME,RTC_SET_TIME .. 每一个RTC都至少支持读时间这个命令,时间格式为公历和24小时制墙钟时间。最有用的特性是,这个时间可以更新。
     (2) RTC_ATE_ON,RTC_ATE_OFF,RTC_ALM_SET,RTC_ALM_READ ... 当RTC连接了一条IRQ线,他还能处理在未来24小时的报警中断。
     (3) RTC_WKALM_SET,RTC_WKALM_RD 。。。 RTCs 使用一个功能更强大的api,他可以处理超过24小时的报警时间。这个API支持设置更长的报警时间,支持单次请求的IRQ中断。
     (4) RTC_UIE_ON,RTC_UIE_OFF ... 如果RTC提供IRQ,他可能也提供每秒更新的IRQ中断。如果需要,RTC结构可以模仿这个机制。

(5) RTC_PIE_ON,RTC_PIE_OFF,RTC_IRQP_SET,RTC_IRQP_READ ... 如果一个IRQ是周期中断,那么这个IRQ还有可设置频率的特性(频率通常是2的n次方)

很多情况下,RTC报警时钟通常是一个系统唤醒事件,用于将Linux从低功耗睡眠模式唤醒到正常的工作模式。例如,系统会处于低功耗的模式下,直到时间到了去执行一些任务。注意这些ioctl的一些功能不必在你的驱动程序中实现。如果一个ioctl调用,你的驱动返回ENOIOCTLCMD,那么这个Ioctl就由通用RTC设备接口处理。下面是一些通用的例子:

(6) RTC_RD_TIME, RTC_SET_TIME: read_time/set_time 函数会被调用。
      (7) RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: set_alarm/read_alarm 函数将会被调用.
      (8) RTC_IRQP_SET, RTC_IRQP_READ: irq_set_freq 函数将会调用,用来设置频率,RTC类构架会处理读请求,而频率保存在RTC设备结构中的irq_freq域。你的驱动需要在模块初始化的时候初始化irq_freq,你必须在irq_set_freq函数里检查设置的频率是否在硬件允许的范围。如果不是那么驱动应该返回-EINVAL。如果你不需要改变这个频率,那么不要定义irq_set_freq这个函数。
      (7) RTC_PIE_ON, RTC_PIE_OFF: irq_set_state 函数会被调用。

如果所有的ioctl都失败了,用下面的rtc-test.c检查一下你的驱动吧!

[cpp]  view plain copy
  1. /*
  2. *      Real Time Clock Driver Test/Example Program
  3. *
  4. *      Compile with:
  5. *           gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest
  6. *
  7. *      Copyright (C) 1996, Paul Gortmaker.
  8. *
  9. *      Released under the GNU General Public License, version 2,
  10. *      included herein by reference.
  11. *
  12. */
  13. #include <stdio.h>
  14. #include <linux/rtc.h>
  15. #include <sys/ioctl.h>
  16. #include <sys/time.h>
  17. #include <sys/types.h>
  18. #include <fcntl.h>
  19. #include <unistd.h>
  20. #include <stdlib.h>
  21. #include <errno.h>
  22. /*
  23. * This expects the new RTC class driver framework, working with
  24. * clocks that will often not be clones of what the PC-AT had.
  25. * Use the command line to specify another RTC if you need one.
  26. */
  27. static const char default_rtc[] = "/dev/rtc0";
  28. int main(int argc, char **argv)
  29. {
  30. int i, fd, retval, irqcount = 0;
  31. unsigned long tmp, data;
  32. struct rtc_time rtc_tm;
  33. const char *rtc = default_rtc;
  34. switch (argc) {
  35. case 2:
  36. rtc = argv[1];
  37. /* FALLTHROUGH */
  38. case 1:
  39. break;
  40. default:
  41. fprintf(stderr, "usage:  rtctest [rtcdev]\n");
  42. return 1;
  43. }
  44. fd = open(rtc, O_RDONLY);
  45. if (fd ==  -1) {
  46. perror(rtc);
  47. exit(errno);
  48. }
  49. fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n");
  50. /* Turn on update interrupts (one per second) */
  51. retval = ioctl(fd, RTC_UIE_ON, 0);
  52. if (retval == -1) {
  53. if (errno == ENOTTY) {
  54. fprintf(stderr,
  55. "\n...Update IRQs not supported.\n");
  56. goto test_READ;
  57. }
  58. perror("RTC_UIE_ON ioctl");
  59. exit(errno);
  60. }
  61. fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:",
  62. rtc);
  63. fflush(stderr);
  64. for (i=1; i<6; i++) {
  65. /* This read will block */
  66. retval = read(fd, &data, sizeof(unsigned long));
  67. if (retval == -1) {
  68. perror("read");
  69. exit(errno);
  70. }
  71. fprintf(stderr, " %d",i);
  72. fflush(stderr);
  73. irqcount++;
  74. }
  75. fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:");
  76. fflush(stderr);
  77. for (i=1; i<6; i++) {
  78. struct timeval tv = {5, 0};     /* 5 second timeout on select */
  79. fd_set readfds;
  80. FD_ZERO(&readfds);
  81. FD_SET(fd, &readfds);
  82. /* The select will wait until an RTC interrupt happens. */
  83. retval = select(fd+1, &readfds, NULL, NULL, &tv);
  84. if (retval == -1) {
  85. perror("select");
  86. exit(errno);
  87. }
  88. /* This read won't block unlike the select-less case above. */
  89. retval = read(fd, &data, sizeof(unsigned long));
  90. if (retval == -1) {
  91. perror("read");
  92. exit(errno);
  93. }
  94. fprintf(stderr, " %d",i);
  95. fflush(stderr);
  96. irqcount++;
  97. }
  98. /* Turn off update interrupts */
  99. retval = ioctl(fd, RTC_UIE_OFF, 0);
  100. if (retval == -1) {
  101. perror("RTC_UIE_OFF ioctl");
  102. exit(errno);
  103. }
  104. test_READ:
  105. /* Read the RTC time/date */
  106. retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
  107. if (retval == -1) {
  108. perror("RTC_RD_TIME ioctl");
  109. exit(errno);
  110. }
  111. fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
  112. rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
  113. rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
  114. /* Set the alarm to 5 sec in the future, and check for rollover */
  115. rtc_tm.tm_sec += 5;
  116. if (rtc_tm.tm_sec >= 60) {
  117. rtc_tm.tm_sec %= 60;
  118. rtc_tm.tm_min++;
  119. }
  120. if (rtc_tm.tm_min == 60) {
  121. rtc_tm.tm_min = 0;
  122. rtc_tm.tm_hour++;
  123. }
  124. if (rtc_tm.tm_hour == 24)
  125. rtc_tm.tm_hour = 0;
  126. retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
  127. if (retval == -1) {
  128. if (errno == ENOTTY) {
  129. fprintf(stderr,
  130. "\n...Alarm IRQs not supported.\n");
  131. goto test_PIE;
  132. }
  133. perror("RTC_ALM_SET ioctl");
  134. exit(errno);
  135. }
  136. /* Read the current alarm settings */
  137. retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
  138. if (retval == -1) {
  139. perror("RTC_ALM_READ ioctl");
  140. exit(errno);
  141. }
  142. fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n",
  143. rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
  144. /* Enable alarm interrupts */
  145. retval = ioctl(fd, RTC_AIE_ON, 0);
  146. if (retval == -1) {
  147. perror("RTC_AIE_ON ioctl");
  148. exit(errno);
  149. }
  150. fprintf(stderr, "Waiting 5 seconds for alarm...");
  151. fflush(stderr);
  152. /* This blocks until the alarm ring causes an interrupt */
  153. retval = read(fd, &data, sizeof(unsigned long));
  154. if (retval == -1) {
  155. perror("read");
  156. exit(errno);
  157. }
  158. irqcount++;
  159. fprintf(stderr, " okay. Alarm rang.\n");
  160. /* Disable alarm interrupts */
  161. retval = ioctl(fd, RTC_AIE_OFF, 0);
  162. if (retval == -1) {
  163. perror("RTC_AIE_OFF ioctl");
  164. exit(errno);
  165. }
  166. test_PIE:
  167. /* Read periodic IRQ rate */
  168. retval = ioctl(fd, RTC_IRQP_READ, &tmp);
  169. if (retval == -1) {
  170. /* not all RTCs support periodic IRQs */
  171. if (errno == ENOTTY) {
  172. fprintf(stderr, "\nNo periodic IRQ support\n");
  173. goto done;
  174. }
  175. perror("RTC_IRQP_READ ioctl");
  176. exit(errno);
  177. }
  178. fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp);
  179. fprintf(stderr, "Counting 20 interrupts at:");
  180. fflush(stderr);
  181. /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
  182. for (tmp=2; tmp<=64; tmp*=2) {
  183. retval = ioctl(fd, RTC_IRQP_SET, tmp);
  184. if (retval == -1) {
  185. /* not all RTCs can change their periodic IRQ rate */
  186. if (errno == ENOTTY) {
  187. fprintf(stderr,
  188. "\n...Periodic IRQ rate is fixed\n");
  189. goto done;
  190. }
  191. perror("RTC_IRQP_SET ioctl");
  192. exit(errno);
  193. }
  194. fprintf(stderr, "\n%ldHz:\t", tmp);
  195. fflush(stderr);
  196. /* Enable periodic interrupts */
  197. retval = ioctl(fd, RTC_PIE_ON, 0);
  198. if (retval == -1) {
  199. perror("RTC_PIE_ON ioctl");
  200. exit(errno);
  201. }
  202. for (i=1; i<21; i++) {
  203. /* This blocks */
  204. retval = read(fd, &data, sizeof(unsigned long));
  205. if (retval == -1) {
  206. perror("read");
  207. exit(errno);
  208. }
  209. fprintf(stderr, " %d",i);
  210. fflush(stderr);
  211. irqcount++;
  212. }
  213. /* Disable periodic interrupts */
  214. retval = ioctl(fd, RTC_PIE_OFF, 0);
  215. if (retval == -1) {
  216. perror("RTC_PIE_OFF ioctl");
  217. exit(errno);
  218. }
  219. }
  220. done:
  221. fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
  222. close(fd);
  223. return 0;
  224. }

linux 实时时钟(RTC)驱动【转】相关推荐

  1. ESP32设备驱动-DS3231实时时钟(RTC)驱动

    DS3231实时时钟(RTC)驱动 1.DS3231介绍 DS3231 是一款低成本.极其精确的 I2C 实时时钟 (RTC),具有集成的温度补偿晶体振荡器 (TCXO) 和晶体. 该设备包含电池输入 ...

  2. ESP8266-Arduino编程实例-PCF8563实时时钟(RTC)驱动

    PCF8563实时时钟(RTC)驱动 1.PCF8563介绍 PCF8563 是针对低功耗优化的 CMOS 实时时钟 (RTC) 和日历. 还提供了可编程时钟输出.中断输出和低电压检测器. 所有地址和 ...

  3. imx6 linux 时钟,迅为-iMX6开发板-驱动-实时时钟RTC以及Linux-c测试例程

    当Linux开发者谈论一个实时时钟,他们通常指的是某种能记录墙上时间,并且有备用电 池,以至于在系统关机的时候仍然可以工作的器件. Linux 有两个系列广泛兼容的用户空间 RTC 设备节点: /de ...

  4. linux设备树例程,iTOP-iMX6-设备树内核-实时时钟RTC以及Linux-c测试例程

    当 Linux 开发者谈论一个实时时钟,他们通常指的是某种能记录墙上时间,并且有备用电 池,以至于在系统关机的时候仍然可以工作的器件. Linux 有两个系列广泛兼容的用户空间 RTC 设备节点: • ...

  5. linux下测试RTC驱动相关的命令date和hwclock常见用法简介

    之前对Linux下面时间相关的内容,一无所知,第一次见到hwclock,不知为何物,也没找到解释清楚的帖子.故此整理一下,简单介绍Linux下验证rtc驱动是否工作正常,相关的的命令:date和hwc ...

  6. linux下的rtc设备驱动,linux下测试RTC驱动相关的命令date和hwclock常见用法讲解

    之前对Linux下面时间相关的内容,一无所知,第一次见到hwclock,不知为何物,也没找到解释清楚的帖子.故此整理一下,简单介绍Linux下验证rtc驱动是否工作正常,相关的的命令:date和hwc ...

  7. stm32之实时时钟RTC(掉电计时保持、秒中断、闹钟中断、溢出中断)

    前言:stm32系列产品普遍都有实时时钟RTC模块,它提供一个掉电保持计时功能,掉电后由后备供电区域供电.除了提供时间和日期之外,还可以设置闹钟提醒,且可以在待机模式下设置闹钟唤醒系统.在一些小容量. ...

  8. STM32学习心得二十一:实时时钟RTC和备份寄存器BKP特征、原理及相关实验代码解读

    记录一下,方便以后翻阅~ 主要内容 1) RTC特征与原理: 2) BKP备份寄存器特征与原理: 3) RTC常用寄存器+库函数介绍: 4) 相关实验代码解读. 实验内容: 因为没有买LCD屏,所以计 ...

  9. 【嵌入式】MSP430系统实时时钟RTC学习日志(完善中)

    目录 MSP430系统实时时钟RTC [时钟初始化]系统时钟初始化需要注意的问题 MSP430F149时钟源选择(部分转) MSP430 系统时钟 ACLK.MCLK.SMCLK [MSP430时钟] ...

最新文章

  1. Linux的java服务配置步骤
  2. JavaScript函数式编程之深入理解纯函数
  3. 调用SMS腾讯云短信验证码API的几个坑,及详细使用流程
  4. maven添加本地包命令mvn install:install-file
  5. SAP License:GB01中替代字段释放
  6. 双语阅读:坚持你的方向
  7. 两台linux电脑怎么互推文件夹,Llinux文件目录权限及chmod命令简析
  8. 知网下载论文CAJ格式转为PDF格式
  9. office之转置EXCEL表格
  10. html校验邮箱格式,正则验证邮箱格式
  11. openwrt添加me909s-8201
  12. 客户机键盘某些键失灵
  13. RCLAMP0544T 国产替代上海雷卯ULC0544T
  14. python turtle画樱花树
  15. 通过fpga实现占空比的改变
  16. dx.jar bad class file magic (cafebabe) or version (0034.0000)
  17. 单元识别码是什么意思_NLPer入门指南 | 完美第一步
  18. 设计模式学习(八) 模板方法模式
  19. 专业卡与游戏卡的区别
  20. 蓝桥杯比赛时间在什么时候_喝茶的时候使用公道杯有什么讲究,怎么使用不会失礼?...

热门文章

  1. 响应式织梦模板首饰珠宝类网站
  2. MySQL跳过密码登录并修改用户密码
  3. page builder odata model /UI2/PB_MODEL, first config, then cust and pers
  4. 总结了一些优化性能的小技巧,看官请收好
  5. Docker下Redis Cluster分片集群的搭建、基本操作、集群扩容和集群故障转移(非关系型数据库技术课程 第九周)
  6. SuperBenchmarker 压测工具
  7. php httponly_xss防御之php利用httponly防xss攻击
  8. 有感 Visual Studio 2015 RTM 简介 - 八年后回归 Dot Net,终于迎来了 Mvc 时代,盼走了 Web 窗体时代...
  9. 正则表达式及bash脚本(二)
  10. NOIP2017逛公园