RTC Operations on i.MX6ULL Embedded Platform
1. RTC Description
1.1 What's RTC?
RTC (Real Time Clock): It is an electronic device that functions like a clock to output real-world time. RTC Overview: The RTC is a 32-bit timer that increments every second, functioning like a clock. Date and time can be modified by adjusting the timer value.
To ensure that the RTC time is not lost during power outages, a small battery is usually connected separately to provide power to the RTC. Once the small battery is removed, the RTC will lose the time after a power outage.
However, the time in the lower right corner of the computer and the time seen with date under Linux are not RTC time. During system operation, a high-precision register on the chip serves as the system time reference. To avoid drift over extended system operation and prevent time loss after power failure, each time the system starts up, it retrieves the time from the RTC to set as the system time.
1.2 Difference Between Internal and External RTC
External RTC advantages:
Low power consumption
Minimal deviation
Therefore, an external RTC (Real-Time Clock) is generally used.
2. Unix Time Stamp
Unix timestamp is defined as the number of seconds elapsed since 00:00:00 coordinated Universal Time (UTC) on January 1, 1970, excluding leap seconds.
The timestamp is stored in a seconds counter, which is a 32-bit/64-bit integer variable.
The timestamp is stored in a 32-bit/64-bit integer seconds counter, uniform globally across all time zones, with local times derived from applying offsets to this counter.
3. Common operation
3.1 Date
The "date" command can read/write the current system time and also display the time zone. Common operations:
View time:
Before changing the timezone
root@fl-imx6ull:~# date
Thu Sep 21 04:43:03 UTC 2017
After changing the timezone
root@fl-imx6ull:~# date
Thu Sep 21 12:43:50 HKT 2017
View timezone
Before changing the timezone
root@fl-imx6ull:~# date -R
Fri, 26 Apr 2019 19:07:20 +0000
After changing the timezone
root@fl-imx6ull:~# date -R
Thu, 21 Sep 2017 12:45:37 +0800
Set time:
root@fl-imx6ull:~# date -s "20240531 12:00:00"
Fri May 31 12:00:00 UTC 2024
3.2 Timezone modification
The time zone file is/etc/localtime. When the time zone needs to be modified, only the corresponding time zone file needs to be linked to/etc/localtime.
root@fl-imx6ull:~# rm /etc/localtime
root@fl-imx6ull:~# ln -s /usr/share/zoneinfo/Asia/Hong_Kong /etc/localtime
3.3 hwclock
Read RTC time
root@fl-imx6ull:~# hwclock -r
Thu Sep 21 04:47:03 2017 0.000000 seconds
Write in time
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
Note: If UTC is enabled and the time zone is modified, hwclock -wu should be usedSync system time to RTC
hwclock --systohc
Sync RTC time to system
hwclock --hctosys
4. Sync RTC to system
At system startup, the RTC time is read and used as the system time. Using the example of the imx6ull processor, after powering on, the operations related to RTC are as follows:
There are the followings in the /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
The main functions of this part are:
Call the/etc/init.d/hwclock.sh with the parameter start
Read the timestamp /etc/timestamp and compare it to the existing system time, if the timestamp is further back, write the time in the timestamp to the system via date, and then call /etc/init.d/hwclock.sh again with the parameter stop;
The followings are in the /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 ;; ......
The main functions of this part are:
When UTC is enabled, assign the tz variable to "--utc" and vice versa to "--localtime".
When the parameter is start, execute hwclock $tz --hctosys to synchronise hardware time to system time;
If $UTC is yes, the time read is considered to be UTC time, and vice versa for localtime.
The main difference here lies in whether the system interprets the read time as UTC time, and adjusts the time according to the timezone pointed to by /etc/localtime.
For example, in the current time zone (UTC+8), if the --utc option is added, the system will add 8 hours to the read time. If --utc is not added, or --localtime is used, the system will consider the read time as the current time and will not make any adjustments.
Note that hwclock -w by default writes the system time. hwclock -w writes the current system time to the RTC (Real-Time Clock);
hwclock -wu by default writes UTC time. Taking East 8 as an example, hwclock -wu is to write the current system time minus 8 hours to the RTC;
When the parameter is stop, execute hwclock $tz --systohc to write the system time to the hardware RTC.
As mentioned earlier, when the timestamp is later, it will enter this branch;
"If $UTC is yes, it is considered that the time to be written is UTC time; otherwise, it is considered to be localtime."
The main difference here is that if the --utc parameter is added, the system adjusts the system time obtained from date before writing it to the hardware RTC. Conversely, without the parameter, the system writes the time directly to RTC. Taking East 8 as an example, if the --utc parameter is added, the current system time minus 8 hours to the RTC. If --utc is not added, or --localtime is used, the system will write the current system time in hardware RTC;
Note: The full name of hctosys is hardware clock to system.
The full name of systohc is system to hardware clock.
"timestamp" originates from:
There are the followings in ls /etc/rc6.d/S25save-rtc.sh:
date -u +%4Y%2m%2d%2H%2M%2S 2>/dev/null > /etc/timestamp
Due to the system's runlevel being 5, during startup it runs scripts from /etc/rc5.d, as evident from the printed messages during boot.
INIT: Entering runlevel: 5
Printing information is as follows:
...... echo -e "\033[32mupdate timestamp\033[0m" date -u +%4Y%2m%2d%2H%2M%2S 2>/dev/null > /etc/timestamp ......
When reboot is called, you can see the printed information added:
root@fl-imx6ull:~# reboot ...... update timestamp Unmounting remote filesystems... urandom stop: failed. Deactivating swap... Unmounting local filesystems... reboot Restarting system
Conclude that the current system time is written to the timestamp when reboot is executed. After the next boot, the system time will definitely be later than after the last reboot.
5. RTC Test
Please note: The following examples are based on the GMT+8 time zone.
Case 1:
Set the RTC time manually to an earlier date, for example, 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
At this point, executing a reboot will set the current time as a timestamp eight hours ahead, which will then be written to the hardware clock. System time after reboot is:
root@fl-imx6ull:~# cat /etc/timestamp
20220101010109
root@fl-imx6ull:~# date
Sat Jan 1 09:01:52 HKT 2022
At this point, if you power off the board for about ten minutes to ensure the RTC battery remains charged, and then power it on again, you will see that the board's time is:
root@fl-imx6ull:~# cat /etc/timestamp
20220101010109
root@fl-imx6ull:~# date
Sat Jan 1 09:13:49 HKT 2022
The timestamp remains the same.
Case 2:
Set the RTC time manually to an earlier date, for example, 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
Use ntpdate to synchronize the time, then execute a reboot to trigger the update of the timestamp.
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
The updated timestamp is the system time minus 8 hours.
root@fl-imx6ull:~# cat /etc/timestamp
20240522100608
root@fl-imx6ull:~# date
Wed May 22 18:07:30 HKT 2024
At this point, if you power off the board for about ten minutes to ensure the RTC battery remains charged, and then power it on again after ten minutes, the board's time will be:
root@fl-imx6ull:~# date
Wed May 22 18:17:57 HKT 2024
root@fl-imx6ull:~# cat /etc/timestamp
20240522100608
The timestamp remains the same.
Case 3:
Use hwclock -w to directly write the system time to the RTC, then power off without updating the timestamp, and power on again.
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
At this point, the timestamp remains unchanged, but the system time has moved back by 8 hours.
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
Case 4:
Read the RTC time directly as the system time, then power off directly and power on again.
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
Note that the system time has to be later than the timestamp time in order not to be affected by timestamps.
After booting again, the system adds eight hours to the RTC time as the system time, so the time is normal.
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. Common Problems
6.1 Loss of time due to power outage
Check whether the software writes the time to the RTC.
Measuring small cell voltage
Check the number of RTC devices under/dev. Generally, there are two. If there is only one, it means that the external RTC is not recognized.
6.2 External RTC is not identified
First, scan the I2C bus with I2C tools to see if the I2C address of the RTC chip can be found. The address for RX8010 is 0x32, and for PCF8563 it's 0x51.
If the address cannot be found, troubleshooting hardware involves checking soldering, crystal oscillators, power supply, and replacing the chip if necessary.
If the device is found but displays a numeric I2C address, it likely indicates that the corresponding device driver is not correctly loaded. Here are steps for troubleshooting and resolving this issue:
If the device is found and displays ''UU,'' this scenario is unlikely to occur. If encountered, troubleshooting can be approached from these aspects: checking system boot logs for print information, examining the RTC loading section, and verifying if there are any kernel errors; investigating hardware for address conflicts.
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: -- -- -- -- -- -- -- --