linux?rtc linux rtc i2c

首先makemenuconfig,在字符驱动中选中s3c2410rtc,光是这样是不会出现/dev/rtc节点的。因为默认在初始化里没有加入S3C2410RTC的设备。因此,接下来要修改arch/arm/mach-s3c2410/mach-smdk2410.c,在structplatform_device*smdk2410_devices[]中添加"&s3c_device_rtc,"。s3c_device_rtc结构体已在arch/arm/mach-s3c2410/devs.c中定义。

改为重新编译,下载内核到板子上,boot后可以见到/dev/rtc0节点,hwclock命令也有效了。我使用busybox的hwclock和date命令来设置RTC,为什么不行呢?
下面是我的顺序操作步骤:

[root@myboad:~]# date -s 042215452009
Wed Apr 22 15:36:00 UTC 2009
[root@myboad:~]# date
Wed Apr 22 15:45:25 UTC 2009
[root@myboad:~]# hwclock
Wed Dec 31 23:59:59 1969 0.000000 seconds
[root@myboad:~]# hwclock -w
[root@myboad:~]# hwclock
Wed Dec 31 23:59:59 1969 0.000000 seconds
[root@myboad:~]# date
Wed Apr 22 15:45:52 UTC 2009

使用date命令时,输出的是我设置的时间,使用hwclock-w命令把日期时 间写入RTC硬件,没有提示错误,然后使用hwclock查看,时间没有设置成功,使用date还是自己设的日期时间。
这问题出在哪呢?真是搞不懂。 首先,明确一个问题:
  1、嵌入式系统板子上的时间是用date标准系统命令查看的,date是SHELL命令,例如busybox或者uClinux上的sash等。这个时间是有运行起来的嵌入式LINUX
软件
维护的,其实就是内存中的一个全局变量,LINUX默认启动给这个全局变量赋值就是19700101这样的数值。
  2、RTC
芯片
(很多是嵌入式
处理器
内置RTC模块,那么就是CPU内部寄存器)内部的寄存器维护的时间值。
  一般的,LINUX启动后,您可以通过date命令来设置更改系统时间,但掉电就会丢失的,启动后又是1970这样的时间了。若要能date设置后保存系统时间,使得在下次重启后还能保持的话,就必须有RTC+后备电池的软
硬件
支持。
  例如,我们PC上可以设置系统时间,重启后也不会丢失,就是因为我们PC
主板
上有RTC支持。
  RTC可以是外接的一个芯片,例如常见的X1226/1227等,它们就是通过I2C接到处理器上的。
  当然,现在更多的情况是CPU内置RTC模块,这样您硬件设计的话就只要提供后备电池即可。
  明确了系统时间的两个概念后,我们来看看RTC的实现机制。
  在嵌入式系统上,实现的方法可以灵活多样,只要能达到最终的目的:
  您可通过某种操作获取当前的正确的时间,而且重启不会丢失。
  那么看看几种实现机制。
  在开始介绍几种方法前,我们先说明一下软件时间的方式:
  我们的平台是嵌入式LINUX,要实现RTC支持,则必须是“驱动+应用程序”的方式,而我们的驱动都建议是采用MODULES方式独立加载的方式,这样可不影响整个LINUX内核。
  下面开始介绍实现方法:
  从上面可以看到,时间实际上是两个地方同时在维护的,一个是RTC芯片内部寄存器或CPU的RTC寄存器;另一个则是LINUX维护的时间。LINUX的时间重启就会丢失,而RTC由于有后备电池保护,则不会丢失,在板子断电后还可以继续维持计时。所以,最好理解的实现方式就是让LINUX内核启动的时候,从RTC芯片里面读取时间值,赋给LINUX的时间变量。这样LINUX一启动时间就校正过来,不再是1970了。当然,这样做,就不能用独立的RTC驱动的MODULES形式了。而当您通过date命令设置LINUX时间时,您还要修改date命令的代码,使之同时还要通过I2C修改RTC芯片内部寄存器数值(或CPU内部寄存器数值),当然了,这样还是需要一个读写RTC的驱动的。
  下面则是一个更简化的实现方法
  即LINUX启动时,不从RTC芯片里面读取时间,而您直接修改date命令的代码,让它不要从LINUX提供的接口读取,而是直接通过驱动从RTC里面直接读取。
  另外,如果您的系统允许的话,您都可以不走date的路线,即读取系统时间不用date命令也可以,可以自己直接写个读取时间的函数,例如read_rtc/write_rtc,就用这两个函数取代date命令读取和设置系统时间的功能。
  呵呵,写了这么多,好像也没说清楚,最后,大家记住:
  我们看到的时间,实际是在两个不同的地方维护的
  一个是LINUX维护的,一个是RTC芯片里面的。
  这样就存在一个两个时间同步的问题,一个发生在LINUX启动的时候,需要从RTC里面获取时间;另一个发生在您设置系统时间的时候,需要两个同时更改。
  当然了,中间一些猫腻就可以发生,例如您可以偷懒跳过LINUX时间,让date或者您自己的代码直接读取RTC时间,而完全不理会LINUX的时间(还让它是1970...吧)
  在ARM9实验箱等板子上,我们是通过修改busybox的date.c代码来实现的的;而在HHGW-L
IT
E-R3等HHPPC平台上则是通过自己写的writeRTC来作的。
  前一种方法改变了系统运行方式,后一种则没有把硬件时间同LINUX系统时间联系起来。在
嵌入式Linux
中,与设置时间相关的常用命令有两个:date和hwclock。
1、date命令用于显示或设定当前系统时间,其格式如下:
date [-参数] [日期和时间格式]
在 嵌入式 领域的常用参数-s:设置时间
示例:
显示当前系统时间:
[root@EM9X60 /]# date
设置时间为2010年12月23日下午16:50:00:
[root@EM9X60 /]# date -s “2010-12-23 16:50:00”
修改时间为16:54:20:
[root@EM9X60 /]# date -s 16:54:20
2、hwclock命令用于显示或设定硬件实时时钟RTC,其格式如下:
hwclock [-参数]
在 嵌入式 领域的常用参数--systohc:将硬件时钟RTC调整为与当前系统时间一致
示例:
显示当前RTC时间:
[root@EM9X60 /]# hwclock
将设置好的系统时间存入实时时钟RTC:
[root@EM9X60 /]# hwclock –systohc
如上所述,用户如需修改英利
嵌入式Linux工控主板
的时间,有两种方法,一种是通过超级终端直接键入命令进行修改,具体方法如前文命令介绍中的示例;另一种是在应用程序中通过函数system调用date和hwclock命令进行时间修改,具体代码如下:
// 生成时间设置命令字符串
sprintf(str,'date -s %s', timestr );
// 设置系统时间
system( str );
//将系统时间写入到RTC硬件中,以保留设置。这一操作是为了将修改好的时间写入到RTC中保存。如果不进行这一步操作,则重新上电开机以后系统从RTC中读取到的仍然是原来的时间
system('hwclock --systohc');首先搞清楚RTC在kernel内的作用:
linux
系统有两个时钟:一个是由主板电池驱动的“Real Time Clock”也叫做RTC或者叫
CMOS
时钟,
  硬件时钟。当
操作系统
关机的时候,用这个来记录时间,但是对于运行的系统是不用这个时间的。
  另一个时间是 “System clock”也叫内核时钟或者软件时钟,是由软件根据时间中断来进行计数的,
  内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取RTC时间
  来进行时间同步。并且在系统关机的时候将系统时间写回RTC中进行同步。如前所述,Linux内核与RTC进行互操作的时机只有两个:
  1) 内核在启动时从RTC中读取启动时的时间与日期;
  2) 内核在需要时将时间与日期回写到RTC中。系统启动时,内核通过读取RTC来初始化内核时钟,又叫墙上时间,该时间放在xtime变量中。
  The current time of day (the wall time) is defined inkernel/timer.c:
  struct timespec xtime;
  The timespec data structure is defined in as:struct timespec{
  time_t tv_sec;
  long tv_nsec;
  };
  问题1:系统启动时在哪读取RTC的值并设置内核时钟进行时间同步的呢?
  最有可能读取RTC设置内核时钟的位置应该在arch/arm/kernel/time.c里的time_init函数内.time.c为系统的时钟驱动部分.time_init函数会在系统初始化时,由init/main.c里的start_kernel函数内调用.
X86
架构就是在这里读RTC值并初始化系统时钟xtime的. ARM架构的time_init代码如下:void __inittime_init(void)
  {
  if (system_timer->offset == NULL)
  system_timer->offset = dummy_gettimeoffset;
  system_timer->init();#ifdef CONFIG_NO_IDLE_HZ
  if (system_timer->dyn_tick)
  system_timer->dyn_tick->lock = SPIN_LOCK_UNLOCKED;
  #endif
  } 上面system_timer->init()实际执行的是时钟驱动体系架构相关(具体平台)部分定义的init函数,若是s3c2410平台,则执行的为arch/arm/mach-s3c2410/time.c里定义的s3c2410_timer_init函数.不过s3c2410_timer_init()也没有读RTC的代码.整个时钟驱动初始化的过程大致就执行这些代码.既然在系统时钟驱动初始化的过程中没有读RTC值并设置内核时钟,那会在哪设置呢?我搜了一下,发现内核好象只有在arch/cris/kernel/time.c里有RTC相关代码,如下:
  
  
  //读RTC的函数
  unsigned long get_cmos_time(void)
  {
  unsigned int year, mon, day, hour, min, sec;
  sec = CMOS_READ(RTC_SECONDS);
  min = CMOS_READ(RTC_MINUTES);
  hour = CMOS_READ(RTC_HOURS);
  day = CMOS_READ(RTC_DAY_OF_MONTH);
  mon = CMOS_READ(RTC_MONTH);
  …………
  return mktime(year, mon, day, hour, min, sec);
  } 这个函数会在update_xtime_from_cmos内被调用:
  void update_xtime_from_cmos(void)
  {
  if(have_rtc) {
  xtime.tv_sec = get_cmos_time();
  xtime.tv_nsec = 0;
  }
  } 另外还有设置rtc的函数
  int set_rtc_mmss(unsigned long nowtime);不过我加了printk测试了一下,好象arch/cris/kernel/time.c这个文件和这两个函数只是适用与X86?
  arm平台启动时并不走这边.因此执行不到这些函数。
  那arm平台启动时,系统是在哪读RTC的值并对内核时钟(WallTime)进行初始化的呢? 已解决:
  嵌入式Linux内核(arm)是在系统启动时执行/etc/init.d/hwclock.sh脚本,这个脚本会调用hwclock小程序读取RTC的值并设置系统时钟。
  (换句话说,这要取决于你制作的文件系统里是否有这样的脚本)
  DAEMON1=/sbin/hwclock
  start() {
  local RET ERROR= [ ! -f /etc/adjtime ]&&echo"0.0 00.0">/etc/adjtime
linux?rtc linux rtc i2c
  log_status_msg"Setting the System Clock using the Hardware Clockas reference..."-n # Copies Hardware Clock time to System Clockusing the correct
  # timezone for hardware clocks in local time, and setskernel
  # timezone. DO NOT REMOVE.
  [""!= no ]&& --hctosys #
  # Now that /usr/share/zoneinfo should be available,
  # announce the local time.
  #
  log_status_msg"System Clock set. Local time: `date`"
  log_status_msg""
  return 0
  }
  hwclock最先读取的设备文件是 /dev/rtc ,busybox里面的hwclock是这样实现的:
  static int xopen_rtc(int flags)
  {
  int rtc; if (!rtcname) {
  rtc = open("/dev/rtc", flags);
  if (rtc>= 0)
  return rtc;
  rtc = open("/dev/rtc0", flags);
  if (rtc>= 0)
  return rtc;
  rtcname ="/dev/misc/rtc";
  }
  return xopen(rtcname, flags);
  } 2. 内核如何更新RTC时钟?
  通过set_rtc函数指针指向的函数,set_rtc在arch/arm/kernel/time.c内
  
  
  int(*set_rtc)(void);但是set_rtc函数指针在哪初始化的呢?set_rtc应该是和RTC驱动相关的函数.搜索kernel源码后发现,好象内核其他地方并没有对其初始化。待解决!
  set_rtc在do_set_rtc内调用
  static inline void do_set_rtc(void)
  {
  ……
  if (set_rtc())
  
  next_rtc_update = xtime.tv_sec 60;
  else
  next_rtc_update = xtime.tv_sec 660;
  } do_set_rtc在timer_tick里调用
  
  void timer_tick(struct pt_regs *regs)
  {
  profile_tick(CPU_PROFILING, regs);
  do_leds();
  do_set_rtc();
  do_timer(1);
  ……
  }
  timer_tick为Kernel提供的体系架构无关的时钟中断处理函数,通常会在体系架构相关的时钟中断处理函数内调用它。如s3c2410是这样的:在arch/arm/mach-s3c2410/time.c中
  * IRQ handler for the timer
  */
  static irqreturn_t
  s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs*regs)
  {
  write_seqlock(&xtime_lock);
  timer_tick(regs);
  write_sequnlock(&xtime_lock);
  return IRQ_HANDLED;

  

爱华网本文地址 » http://www.413yy.cn/a/25101014/234985.html

更多阅读

如何在linux系统中设置静态ip地址 linux系统设置ip地址

如何在linux系统中设置静态ip地址——简介本篇主要是介绍一下在linux系统中设置静态ip地址方法。如何在linux系统中设置静态ip地址——工具/原料redhat6.4 x64如何在linux系统中设置静态ip地址——方法/步骤如何在linux系统中设置

linux系统改装win7 新机如何装win7系统

linux系统改装win7——简介很多新买的电脑都没有预装win系统,出厂厂家为了节约成本,一般预装了linux或dos,但是这个linux一般是国产的红旗linux,对于一般的用户根本没有任何可以使用的价值,连播放个视频可能就得捣鼓半天。所以

linux服务器配置 在线linux服务器

Tips:linux服务器配置,linux服务器配置方法,快速搭建linux服务器环境,linux环境一键安装linux服务器配置——准备工作linux服务器配置 1、一台拥有root权限可以访问互联网的linux服务器一台。linux服务器配置 2、SSH连接软件,推荐使

LINUX操作系统VIM的安装和配置 linux中vim基本操作

LINUX操作系统VIM的安装和配置——简介VI是LINUX下最老牌的编辑工具,而VIM则是VI的升级版本,LINUX系统必备啊。LINUX操作系统VIM的安装和配置——工具/原料LINUX操作系统(ubuntu/Centos)LINUX操作系统VIM的安装和配置——VIM的安装

声明:《linux?rtc linux rtc i2c》为网友很爱我的情人分享!如侵犯到您的合法权益请联系我们删除