1.RTC简介1.1 RTC是什么RTC (Real Time Clock):实时时钟,是指可以像时钟一样输出实际时间的电子设备。简单来说,RTC就是个32位定时器,每隔1秒,定时器记一次数。修改定时器的值可以修改时间和日期。 为了保证RTC时间断电不丢失,一般还会单独接一个小电池给RTC供电。一旦小电池被取下来,断电之后,RTC的时间会丢失。 但是,电脑右下角的时间、linux下用date 看到的时间,都不是RTC时间。系统运行时,会将芯片上的一个高精度寄存器作为系统时间基准。为了避免系统运行时间比较长以后出现偏移,以及掉电之后系统时间丢失的情况,每次启动系统会从RTC获取时间,作为系统时间。 1.2 内部RTC和外部RTC的区别相较于内部RTC,外部RTC的主要优势有: 所以一般采用外部RTC。 2.unix时间戳Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量 世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间
3.常用操作3.1 datedate命令可以读/写当前系统时间,也可以查看时区。常用的几种操作: 查看时间: 修改时区之前 root@fl-imx6ull:~# date Thu Sep 21 04:43:03 UTC 2017 修改时区之后 root@fl-imx6ull:~# date Thu Sep 21 12:43:50 HKT 2017 查看时区: 修改时区之前 root@fl-imx6ull:~# date -R Fri, 26 Apr 2019 19:07:20 +0000 修改时区之后 root@fl-imx6ull:~# date -R Thu, 21 Sep 2017 12:45:37 +0800 设置时间: root@fl-imx6ull:~# date -s "20240531 12:00:00" Fri May 31 12:00:00 UTC 2024 3.2 修改时区时区文件为/etc/localtime ,当需要修改时区时,只需要将对应的时区文件软链接到/etc/localtime 。 root@fl-imx6ull:~# rm /etc/localtime root@fl-imx6ull:~# ln -s /usr/share/zoneinfo/Asia/Hong_Kong /etc/localtime 3.3 hwclock读取rtc时间 root@fl-imx6ull:~# hwclock -r Thu Sep 21 04:47:03 2017 0.000000 seconds 写入时间 hwclock -w root@fl-imx6ull:~# date Thu Sep 21 12:50:41 HKT 2017 root@fl-imx6ull:~# hwclock -w root@fl-imx6ull:~# hwclock -r Thu Sep 21 12:51:36 2017 0.000000 seconds hwclock -wu root@fl-imx6ull:~# date Thu Sep 21 12:52:51 HKT 2017 root@fl-imx6ull:~# hwclock -wu root@fl-imx6ull:~# hwclock -r Thu Sep 21 04:52:56 2017 0.000000 seconds 注意:如果开启了UTC,并且修改了时区,应该使用hwclock -wu 系统时间同步到RTC hwclock --systohc RTC时间同步到系统 hwclock --hctosys 4.系统同步RTC前文提到,系统启动时,会将RTC时间读出来,作为系统时间。以imx6ull为例,上电之后,关于RTC的操作如下: 在/etc/rcS.d/S55bootmisc.sh 当中,有以下内容 # # 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 then SYSTEMDATE=`date -u +%4Y%2m%2d%2H%2M%2S` read TIMESTAMP < /etc/timestamp if [ ${TIMESTAMP} -gt $SYSTEMDATE ]; then # format the timestamp as date expects it (2m2d2H2M4Y.2S) TS_YR=${TIMESTAMP%??????????} TS_SEC=${TIMESTAMP#????????????} TS_FIRST12=${TIMESTAMP%??} TS_MIDDLE8=${TS_FIRST12#????} date -u ${TS_MIDDLE8}${TS_YR}.${TS_SEC} test -x /etc/init.d/hwclock.sh && /etc/init.d/hwclock.sh stop fi fi 这部分内容的主要作用是: /etc/init.d/hwclock.sh 内容如下,篇幅原因,只保留部分内容
...... [ "$UTC" = "yes" ] && tz="--utc" || tz="--localtime" case "$1" in start) ...... if [ "$HWCLOCKACCESS" != no ] then if [ -z "$TZ" ] then hwclock $tz --hctosys else TZ="$TZ" hwclock $tz --hctosys fi fi ...... stop|restart|reload|force-reload) ...... if [ "$HWCLOCKACCESS" != no ] then hwclock $tz --systohc fi if [ "$VERBOSE" != no ] then echo "Hardware Clock updated to `date`." fi exit 0 ;; ...... 这部分内容的主要作用如下: 当启用UTC时,将tz变量赋值为“--utc”,反之为“--localtime” 当参数为start 时,执行hwclock $tz --hctosys ,将硬件时间同步到系统时间; 如果$UTC为yes,则认为读到的时间是UTC时间,反之认为读到的是localtime。 这里的区别主要在于,如果系统认为读到的时间是UTC时间,则根据/etc/localtime 指向的时区,对时间进行调整。比如当前时区为东八区,如果加了--utc ,则系统会将读出来的时间加8小时。如果不加--utc ,或者加--localtime ,系统会认为读到的时间就是当前时间,不会再进行调整。 注意hwclock -w 默认写入的时间,是系统时间。hwclock -w 是将当前系统时间写入到RTC; hwclock -wu 默认写入的时间,是utc时间。以东八区为例,hwclock -wu 是将当前系统时间减8小时写入到RTC;
当参数为stop 时,执行hwclock $tz --systohc 将系统时间写入到硬件RTC当中
注:hctosys的全拼是hardware clock to system systohc的全拼是system to hardware clock timestamp 时间戳的由来:
在ls /etc/rc6.d/S25save-rtc.sh 当中,有这样的内容: date -u +%4Y%2m%2d%2H%2M%2S 2>/dev/null > /etc/timestamp 由于系统的runlevel是5,系统启动时执行的是/etc/rc5.d 可以从开机过程中的打印信息看出: INIT: Entering runlevel: 5 通过在脚本当中加打印信息如下: ...... echo -e "\033[32mupdate timestamp\033[0m" date -u +%4Y%2m%2d%2H%2M%2S 2>/dev/null > /etc/timestamp ...... 在调用reboot时,可以看到添加的打印信息: root@fl-imx6ull:~# reboot ...... update timestamp Unmounting remote filesystems... urandom stop: failed. Deactivating swap... Unmounting local filesystems... Rebooting... reboot: Restarting system 得出结论:执行reboot时,会将当前的系统时间,写入到时间戳当中。这样下次启动后的系统时间,一定会比reboot的时间要晚。 5.RTC测试注意:以下几个案例都是以东8区为例 案例1: 将RTC时间手动设置比较靠前,比如2022年。 root@fl-imx6ull:~# date Wed May 22 16:58:20 HKT 2024 root@fl-imx6ull:~# date -s "20220101 09:00:00" Sat Jan 1 09:00:00 HKT 2022 root@fl-imx6ull:~# hwclock -wu root@fl-imx6ull:~# hwclock -r Sat Jan 1 01:00:50 2022 0.000000 seconds 此时执行reboot,重启后当前时间减去八小时变成了时间戳,同时时间戳被写入到了硬件时间。重启后的系统时间为: root@fl-imx6ull:~# cat /etc/timestamp 20220101010109 root@fl-imx6ull:~# date Sat Jan 1 09:01:52 HKT 2022 此时给板子断电十分钟左右,确保RTC电池有电,十分钟后再次给板子上电,可以看到板子的时间为: root@fl-imx6ull:~# cat /etc/timestamp 20220101010109 root@fl-imx6ull:~# date Sat Jan 1 09:13:49 HKT 2022 时间戳依旧保持不变 案例2: 将RTC时间手动设置比较靠前,比如2022年。 root@fl-imx6ull:~# date Sat Jan 1 09:03:49 HKT 2022 root@fl-imx6ull:~# hwclock -w root@fl-imx6ull:~# hwclock -r Sat Jan 1 09:05:44 2022 0.000000 seconds 使用ntpdate 对时,然后执行reboot,触发更新时间戳 root@fl-imx6ull:~# ntpdate cn.ntp.org.cn 22 May 18:05:10 ntpdate[664]: step time server 182.92.12.11 offset 75372823.050443 sec 更新后的时间戳为系统时间减8小时 root@fl-imx6ull:~# cat /etc/timestamp 20240522100608 root@fl-imx6ull:~# date Wed May 22 18:07:30 HKT 2024 此时断电10分钟左右,确保RTC电池有点,10分钟后再次给板子上电,板子的时间为: root@fl-imx6ull:~# date Wed May 22 18:17:57 HKT 2024 root@fl-imx6ull:~# cat /etc/timestamp 20240522100608 时间戳依旧保持不变 案例3: 使用hwclock -w 将系统时间直接写入RTC,然后断电,不更新时间戳,重新上电 root@fl-imx6ull:~# hwclock -w root@fl-imx6ull:~# hwclock -r Wed May 22 19:01:17 2024 0.000000 seconds root@fl-imx6ull:~# date Wed May 22 19:02:18 HKT 2024 此时时间戳保持不变,但系统时间往后移了8小时 root@fl-imx6ull:~# cat /etc/timestamp 20240522022104 root@fl-imx6ull:~# date Thu May 23 03:04:00 HKT 2024 案例4: 将RTC时间直接读出来作为系统时间,然后直接断电再重新上电 root@fl-imx6ull:~# date Wed May 22 19:25:44 HKT 2024 root@fl-imx6ull:~# hwclock -wu root@fl-imx6ull:~# hwclock -r Wed May 22 11:25:53 2024 0.000000 seconds root@fl-imx6ull:~# date Wed May 22 19:25:56 HKT 2024 root@fl-imx6ull:~# hwclock --localtime --hctosys root@fl-imx6ull:~# date Wed May 22 11:26:49 HKT 2024 root@fl-imx6ull:~# cat /etc/timestamp 20240522022104 注意,系统时间要比时间戳时间靠后,才不会受时间戳影响 再次启动后,系统将RTC时间加八小时作为系统时间,所以时间是正常的 root@fl-imx6ull:~# date Wed May 22 19:28:49 HKT 2024 root@fl-imx6ull:~# hwclock -r Wed May 22 11:28:55 2024 0.000000 seco=nds 6.常见问题排查6.1 断电时间丢失6.2 外部RTC不识别首先用i2ctools扫描I2C总线,看能否找到RTC芯片的I2C地址。RX8010的地址是0x32,PCF8563的地址是0x51。 如果找不到,排查硬件,可以检查焊接、晶振、供电、更换芯片; 如果能找到,但是显示的I2C地址是数字,说明驱动没有加载,检查镜像版本,是不是用的比较老的镜像,没有支持PCFD8563; 如果能找到,并且显示UU,这种情况出现的可能性不大。如果遇见,可以从这几个方面排查:查看系统启动的打印信息,RTC加载的部分,内核有没有报错;排查硬件上是不是有地址冲突。 RX8010 root@fl-imx6ull:~# i2cdetect -r -y 0 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
|