ARM Linux RTC 时间的读取与设置
问题描述
这里的平台是 i.MX6 Yocto Linux,没有使用 NTP 对时服务,而是使用我们自己对时机制。RTC 芯片是 PCF8563T,不使用 SoC 上的 RTC。Linux 系统使用 date
命令设置时间,使用 hwclock
命令同步 RTC 时间。一段时间后发现 Linux 系统时间与本地时间相差 8 个小时。
分析问题
直觉告诉我们这是时区造成的,要么是系统的时区配置不对,要么是 RTC 时间的读写不对。要解决这个问题,我需要重新理清时区配置,以及 RTC 时间与 Linux 系统时间的关系。
时区配置
时区配置主要是两个文件:/etc/localtime 和 /etc/timezone,其中 /etc/localtime 是软链接,看来是已经配置成 CST(中国标准时间)的了。
# ls -l /etc/localtime
lrwxrwxrwx 1 root root 33 Jan 1 1970 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
# cat /etc/timezone
Asia/Shanghai
我们这里并没有 /etc/sysconfig/clock 文件,即便加上去了,似乎也不起作用。
# cat /etc/sysconfig/clock
ZONE="Asia/Shanghai"
UTC=false
ARC=false
时间方案
设定了时区,还要确定 Linux 系统的时间方案。Linux 支持 UTC 时间,也就是本初子午线上的时间,它和以前的格林尼治时间(GMT)的区别似乎在于 UTC 是由多个原子钟平均出来的。
协调世界时,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT,Coordinated Universal Time)和法文(TUC)的缩写不同,作为妥协,后来都统一简称 UTC。
在文件 /etc/default/rcS 中,设定了系统是否使用 UTC,UTC=yes
则使用 UTC 时间,UTC=no
则使用本地时间。
# Assume that the BIOS clock is set to UTC time (recommended)
UTC=yes
读写 RTC 硬件时间,使用 hwclock 命令,其用法如下:
Usage: hwclock [-r|--show] [-s|--hctosys] [-w|--systohc] [-t|--systz] [-l|--localtime] [-u|--utc] [-f|--rtc FILE]Options:[-r|--show] Show hardware clock time[-s|--hctosys] Set system time from hardware clock(RTC时间 --> 系统时间)[-w|--systohc] Set hardware clock to system time (系统时间 --> RTC时间)[-u|--utc] Hardware clock is in UTC[-l|--localtime] Hardware clock is in local time[-f|--rtc FILE] FILE Use specified device (e.g. /dev/rtc2)
隐约感觉到问题就在于 --utc
和 --localtime
参数!
继续往下看!
保存RTC时间戳
ARM Linux 有个时间戳文件 /etc/timestamp,一开始的值为:
# cat /etc/timestamp
201611171515
我们找一下,看看它是怎么产生的:
# grep -rn "/etc/timestamp" /*
/etc/init.d/bootmisc.sh:62:if test -e /etc/timestamp
/etc/init.d/bootmisc.sh:65: read TIMESTAMP < /etc/timestamp
/etc/init.d/save-rtc.sh:13:date -u +%4Y%2m%2d%2H%2M > /etc/timestamp
我们把目光定位在 /etc/init.d/save-rtc.sh,它的内容如下:
# cat /etc/init.d/save-rtc.sh
#!/bin/sh
### BEGIN INIT INFO
# Provides: save-rtc
# Required-Start:
# Required-Stop: $local_fs hwclock
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Store system clock into file
# Description:
### END INIT INFO# Update the timestamp
date -u +%4Y%2m%2d%2H%2M > /etc/timestamp
那到底是它怎么被调用的呢?我们找到了端倪,实际上 /etc/rc0.d/S25save-rtc.sh 和 /etc/rc6.d/S25save-rtc.sh 都是 /etc/init.d/save-rtc.sh 的软链接。
再看看内核启动后的第一个用户进程 init,它会调用脚本 /etc/inittab,其中:
# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS
可以看到,inittab 中启动的第一个脚本是 /etc/init.d/rcS,其中包含如下内容片段:
. /etc/default/rcS
exec /etc/init.d/rc S
也就是说,该脚本会先设置 /etc/default/rcS 中的环境变量,其中包括一个 UTC 变量:
# Assume that the BIOS clock is set to UTC time (recommended)
UTC=yes
然后执行 /etc/init.d/rc S
,rc 中会循环调用 rcS.d 中的脚本,其中一段内容如下:
# Now run the START scripts for this runlevel.for i in /etc/rc$runlevel.d/S*do[ ! -f $i ] && continueif [ $previous != N ] && [ $previous != S ]then## Find start script in previous runlevel and# stop script in this runlevel.#suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]}stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffixprevious_start=/etc/rc$previous.d/S[0-9][0-9]$suffix## If there is a start script in the previous level# and _no_ stop script in this level, we don't# have to re-start the service.#[ -f $previous_start ] && [ ! -f $stop ] && continueficase "$runlevel" in0|6)startup $i stop;;*)startup $i start;;esacdone
当 runlevel 为 0 或 6 时,也就是关机模式(halt、poweroff)或重启模式(reboot)会分别调用 rc0.d 和 rc6.d 中的 S* 脚本。
而这里面就有 S25save-rtc.sh 脚本,它执行了如下操作,更新了时间戳文件:
date -u +%4Y%2m%2d%2H%2M > /etc/timestamp
总结一下:执行保存 RTC时间戳的是 /etc/init.d/save-rtc.sh 脚本,当我们的 ARM Linux 关机和重启时,会将 RTC 时间以“年月日时分”的格式保存到 /etc/timestamp 文件,而且是以 UTC 时间保存的。
使用RTC时间戳
在前面我们搜索出来了,操作 RTC 时间戳的脚本除了 /etc/init.d/save-rtc.sh 之外,还有 /etc/init.d/bootmisc.sh,bootmisc.sh 脚本的部分片段如下:
. /etc/default/rcS#
# This is as good a place as any for a sanity check
#
# Set the system clock from hardware clock
# If the timestamp is more recent than the current time,
# use the timestamp instead.
test -x /etc/init.d/hwclock.sh && /etc/init.d/hwclock.sh start
if test -e /etc/timestamp
thenSYSTEMDATE=`date -u +%4Y%2m%2d%2H%2M`read TIMESTAMP < /etc/timestampif [ ${TIMESTAMP} -gt $SYSTEMDATE ]; thendate -u ${TIMESTAMP#????}${TIMESTAMP%????????}test -x /etc/init.d/hwclock.sh && /etc/init.d/hwclock.sh stopfi
fi
: exit 0
先设置环境变量 UTC=yes
,然后执行 /etc/init.d/hwclock.sh start
,我们看看 hwclock.sh 脚本干了些什么:
[ ! -x /sbin/hwclock ] && exit 0[ -f /etc/default/rcS ] && . /etc/default/rcS[ "$UTC" = "yes" ] && tz="--utc" || tz="--localtime"
case "$1" instart)if [ "$HWCLOCKACCESS" != no ]thenif [ -z "$TZ" ]thenhwclock $tz --hctosyselseTZ="$TZ" hwclock $tz --hctosysfifi;;stop|restart|reload|force-reload)if [ "$HWCLOCKACCESS" != no ]thenhwclock $tz --systohcfiexit 0;;# 省略
hwclock.sh 脚本先判断 UTC 变量是否为 yes,如果是则设置参数 tz 为 --utc
,否则为 --localtime
。
当后面紧接着的是 start 命令时,执行 hwclock $tz --hctosys
将 RTC 硬件时间同步到 Linux 系统。
回到 bootmisc.sh 脚本,将 RTC 时间读取到 Linux 系统后,接下来判断 data -u
系统时间是否领先于 /etc/timestamp 保存的时间,如果没有则说明 Linux 系统时间落后了,有可能是因为 RTC 时间出错了。这时候就会认为上次关机或重启时保存的 RTC 时间戳更合理,从而将其更新到系统时间,然后执行 hwclock $tz --systohc
将它同步到 RTC 硬件。(此时的 RTC 时间依然不正确,但认为更接近实际的时间)
bootmisc.sh 的调用实际上是通过 /etc/rcS.d/S55bootmisc.sh,可以从 inittab 入手分析。
# ls -l /etc/rcS.d/S55bootmisc.sh
lrwxrwxrwx 1 root root 21 Jan 1 1970 /etc/rcS.d/S55bootmisc.sh -> ../init.d/bootmisc.sh
时间为什么会改变
虽然分析了一通 RTC 时间和 Linux 系统时间,但依然没有解决时间被修改的幽灵现象。但显然,直觉告诉我,很可能是因为某个地方读写 RTC 时间没有正确使用 --utc
和 --localtime
参数导致的。
经检查,我们加入的用户代码没有相关操作,那么可能是这个 Yocto Linux 里隐藏了。这时候想起 cron 定时任务,检查发现真的在这里埋了雷!
# cat /var/spool/cron/root
30 * * * * /usr/bin/ntpdate-sync silent
0 0-23/12 * * * /sbin/hwclock --hctosys
系统时间应该就是在这里被修改的,因为此处将 RTC 时间同步到系统时间并没有加 --utc
参数,hwclock 默认使用的是 --localtime
。
直接把它删掉吧,毕竟我们有自己的对时机制。
时间为什么不正确
有的开发人员故意将 /etc/timestamp 设置成一个很大的时间,并且一些嵌入式设备没有提供正常关机或重启的功能,而是直接断电,因此没法更新 RTC 时间戳。
另一个原因是 UTC 的设置问题。例如在这里,系统设置了 UTC=yes,那么在使用 hwclock --hctosys
或者 hwclock --systohc
命令时,应该统一加上 --utc
参数。意思是将 RTC 硬件时间看作 UTC 时间,从而使 hwclock 在读写时间的时候协调好时区问题。这样的话,即便是 hwclock --show
也应该加上 -u|--utc
参数,也就是把 RTC 硬件时间当成 UTC 时间来看,所以打印处理的时间会加上 8 个小时,形成我们的本地时间。
总结
总结一下:遇到这个问题,我首先通读了 PCF8563T 的芯片手册,发现根本没有时区的概念。RTC 的意义在于系统断电的情况下继续保持时间,它能处理好年月日和星期的关系,也能处理闰年的问题,但是没有时区的概念。时区是在系统层面处理的,通常来说,一个嵌入式 Linux 设备有俩个时间,一个是 RTC 实时时钟的时间,一个是系统时间。hwclock 等应用程序遵守 RTC 字符驱动程序接口,并通过 /dev/rtc 进行操作。所以,时区对 RTC 设备来说是透明的,因为被 hwclock 过滤掉了。经过这么一分析,时间和时区的问题就很简单了,只需要把操作统一起来就成!要么都加 --utc
,要么都加 --localtime
(缺省)。既然系统设置了 UTC=yes,那我们都遵循它的规定就好了,加上 --utc
吧。
ARM Linux RTC 时间的读取与设置相关推荐
- STM32F103C8T6使用RTC实现日历读取、设置和输出
目录 一.使用STM32cubeMX创建项目 二.添加代码 三.结果 四.总结 五.参考链接 一.使用STM32cubeMX创建项目 前面的创建过程都差不多选芯片就完事了!直接配置开始 1.RCC配置 ...
- Linux 有关时间日期和时区设置
目录 时间概述 Linux 中两个时钟 date --> 系统时钟 hwclock --> 硬件时钟 如何查看和设置时区 查看时区 设置时区 tzselect timedatectl ca ...
- Linux RTC 驱动实验
目录 Linux 内核RTC 驱动简介 I.MX6U 内部RTC 驱动分析 RTC 时间查看与设置 RTC 也就是实时时钟,用于记录当前系统时间,对于Linux 系统而言时间是非常重要的,就和我们使用 ...
- 【正点原子Linux连载】第六十章 Linux RTC驱动实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
- linux页表,arm linux 页表(转)
最近在看arm linux 的mm部分,看的是2.6.8.1,芯片是INTEL PXA255,参考资料有arm linux演艺.<情景分析>等.一遍看下来只能说似懂非懂.这里有几个基础的问 ...
- 【linux】ARM开发板上设置RTC时间,断电重启后,设置失效的原因分析
问题描述 linux中使用date设置时间后用hwclock -w同步到RTC,断电重启后,有时会失效 原因分析 保存时间戳 1.使用命令关机(halt)会调用rc0.d中的脚本: 2.使用命令重启( ...
- linux开发板断电重启后rtc归0,开发板RTC时间设置有效,但断电后自动恢复
博主使用的是天嵌的开发板型号IMX6Q_coreC. 1.发现使用开发板是时间总是被设置为2028年6月18日3时41分,一开始以为是底层驱动的问题, 故去底层加打印信息调试. 2.发现在系统内hwc ...
- QT在linux环境下读取和设置系统时间
QT在linux环境下读取和设置系统时间 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:Fedora12 开发软件:QT 读取系统时间 ...
- Linux板子RTC时间设置和修改
一.查寻/设置系统时间 之前使用开发板时发现每次开机后,系统的时间都恢复到初始状态1970年. 比 如说硬件时间要设置为2008年6月29日20时50分10秒 ,则应该先用date 062920502 ...
最新文章
- oauth最后的确认按钮_绕过GitHub的OAuth授权验证机制($25000)
- 开源 Serverless 里程碑:Knative 1.0 来了
- 查询各个分区的数据量_分库、分表、分区的区别,傻傻分不清?
- 【强化学习】DQN 的三种改进在运筹学中的应用
- 阿里开源支持10万亿模型的自研分布式训练框架EPL(EasyParallelLibrary)
- Spring项目启动加载xml配置文件替换数据库提高响应速度
- 复选框 ComboBox 1129
- Zabbix 监控LVS连接的状态
- Selenium2+python自动化49-判断文本(text_to_be_present_in_element)
- Django 中related_name,%(app_label)s_%(class)s_related
- java周报简单模板_快速成长从写一份走心的周报开始
- 大学计算机vb基础知识6,大学计算机基础vb试题大学计算机基础试题和答案.doc
- mac的win10蓝牙鼠标问题
- Power BI集成Power Apps,轻松实现用户在报告中任意输入信息
- win7系统什么时候停止服务器,Win7系统什么时候停止服务?Win7停止更新时间一览表图解...
- javascript eval 函数作用
- PHP是什么,其优势有哪些?
- 五款最优秀的java微服务框架
- beeline 查询表数据导出到本地文件csv
- TCL智能电视ROOT教程 附ROOT工具下载
热门文章
- QOS 优先级 PHB,EXP,浅解 .
- 4K高清无损信号传输 电影院级别的视听盛宴
- 大学生计算机无纸测评,计算机无纸化测评系统参数.pdf
- Unity Github 项目收集
- iOS 隐藏顶部状态栏
- 贷款中介业务管理系统-具备完善的贷前审批及贷后监管功能
- 【算法】计算组合数的四种常用方法
- 5,10,15,20-四(4-甲基苯基)卟啉((TmPP)H2);2-硝基-5,10,15,20-四(4-甲基苯基)卟啉铜(NO2TmPP)Cu)齐岳定制
- DLL,SDK,API专业技术术语
- 最新网站被挂马被跳转解决办法