RTC
In this chapter, we will learn how to read and write the date and time of the RTC, and how to implement system time correction.Note: Only RV1106 has a built-in RTC, RV1103 does not have a built-in RTC.
Sample program : Code.zip
1. RTC
RTC (Real-Time Clock) is a hardware module that can continue to keep time in microcontrollers or embedded systems even when power is disconnected. It is typically equipped with an independent persistent power supply, such as a common button cell battery, to ensure the accuracy of time and date even when the main power is disconnected. This feature makes RTC play a crucial role in many applications that rely on real-time and reliable timestamps, such as data logging, device wake-up timing, and maintaining system time synchronization.
2.RTC reading and writing application
2.1 Read and Write RTC (Shell)
In the Linux operating system environment, interacting with RTC usually depends on specific system commands and interfaces. The following details how to use shell commands to read and set RTC time
2.1.1 Read RTC Time
In the Linux operating system environment, interacting with RTC usually depends on specific system commands and interfaces. The following details how to use shell commands to read and set RTC time:
hwclock --show
This command will output time information in a format similar to the following:
Sat Jan 13 12:00:00 2024 0.000000 seconds
2.1.2 Set RTC Time
To synchronize the current system time to RTC, you can use the --systohc
option of the hwclock
command:
hwclock --systohc
Conversely, if you need to get the time from RTC and synchronize it to the system time, you can use the --hctosys
option:
hwclock --hctosys
2.1.3 Calibrate RTC Time
For situations where calibration of the RTC time is required, the first step is to ensure the accuracy of the system time and then synchronize the calibrated system time to the RTC. For specific operation procedures, please refer to the "System Time Calibration" section.
2.2 Read and Write RTC (Python Program)
The Python program interacts with the system by calling external hwclock
commands, providing functionality to get and set RTC time.
import subprocess
def get_rtc_time():
try:
result = subprocess.run(['hwclock', '-r'], capture_output=True, text=True, check=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error in get_rtc_time: {e}")
return None
def set_rtc_time():
try:
subprocess.run(['hwclock', '-w'], check=True)
print("RTC time set successfully.")
except subprocess.CalledProcessError as e:
print(f"Error in set_rtc_time: {e}")
rtc_time = get_rtc_time()
if rtc_time:
print(f"RTC time: {rtc_time}")
set_rtc_time()
Now let's analyze the code:
2.2.1 Read RTC Time
The get_rtc_time()
function gets the RTC time by running the hwclock -r
command.
def get_rtc_time():
try:
result = subprocess.run(['hwclock', '-r'], capture_output=True, text=True, check=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error in get_rtc_time: {e}")
return None
2.2.2 Set RTC Time
The set_rtc_time()
function sets the RTC time to the current system time by running the hwclock -w
command.
def set_rtc_time():
try:
subprocess.run(['hwclock', '-w'], check=True)
print("RTC time set successfully.")
except subprocess.CalledProcessError as e:
print(f"Error in set_rtc_time: {e}")
2.2.3 Running the Program
Use the nano tool in the terminal to create a Python file, paste the Python program, and save it.
# nano rtc.py
Run the program.
# python3 rtc.py
Experimental Observations
Output the obtained RTC time and synchronize the system time to RTC:
2.3 Read and Write RTC (C Program)
In the previous section, we discussed how to interact with the RTC using shell tools and Python programs. In practical programming, direct reading and setting of the RTC can be achieved by calling C library functions or system calls. For embedded Linux environments, accessing the RTC typically involves opening and operating on the /dev/rtc
or /dev/rtc0
device files. Please note that to run programs on specific embedded systems, cross-compilation tools are usually required to compile the code, generating executable files that can run on the target development board. Now, let's delve into the specific implementation steps.
2.3.1 Read RTC Time
Implement the function to read the RTC time.
int rtc_get_time(struct tm *time) {
int ret,fd;
struct rtc_time rtc_tm;
fd=open("/dev/rtc", O_RDONLY);
if(fd == -1) {
perror("error open /dev/rtc");
return -1;
}
ret = ioctl(fd, RTC_RD_TIME, &rtc_tm);
if(ret == -1) {
perror("error RTC_RD_TIME ioctl");
close(fd);
return -1;
}
if (!time) {
printf("time is NULL\n");
close(fd);
return -1;
}
time->tm_sec = rtc_tm.tm_sec;
time->tm_min = rtc_tm.tm_min;
time->tm_hour = rtc_tm.tm_hour;
time->tm_mday = rtc_tm.tm_mday;
time->tm_mon = rtc_tm.tm_mon;
time->tm_year = rtc_tm.tm_year;
close(fd);
return 0;
}
Implement the function to read the RTC time.
Open RTC Device
Open the RTC device file (/dev/rtc
) in read-only mode.
fd=open("/dev/rtc", O_RDONLY);
if(fd == -1) {
perror("error open /dev/rtc");
return -1;
}
Read RTC Time
Call the ioctl
function to read the RTC time from the opened device file.
ret = ioctl(fd, RTC_RD_TIME, &rtc_tm);
if(ret == -1) {
perror("error RTC_RD_TIME ioctl");
close(fd);
return -1;
}
Store RTC Time
Assign the values of the read RTC time to the passed parameter time
.
time->tm_sec = rtc_tm.tm_sec;
time->tm_min = rtc_tm.tm_min;
time->tm_hour = rtc_tm.tm_hour;
time->tm_mday = rtc_tm.tm_mday;
time->tm_mon = rtc_tm.tm_mon;
time->tm_year = rtc_tm.tm_year;
2.3.2 Set RTC Time
Implement the function to set the RTC time.
int rtc_set_time(struct tm *time) {
int fd, ret;
struct rtc_time rtc_tm;
if (!time) {
printf("time is NULL\n");
return -1;
}
fd = open("/dev/rtc",O_RDWR);
if(fd == -1) {
perror("error open /dev/rtc");
return -1;
}
rtc_tm.tm_sec = time->tm_sec ;
rtc_tm.tm_min = time->tm_min ;
rtc_tm.tm_hour = time->tm_hour ;
rtc_tm.tm_mday = time->tm_mday ;
rtc_tm.tm_mon = time->tm_mon - 1;
rtc_tm.tm_year = time->tm_year - 1900;
ret = ioctl(fd, RTC_SET_TIME, &rtc_tm);
if(ret == -1) {
perror("error RTC_SET_TIME ioctl");
close(fd);
return -1;
}
close(fd);
return 0;
}
Below is an analysis of the function:
Open RTC Device
Open the RTC device file (/dev/rtc
) in read-write mode.
fd = open("/dev/rtc",O_RDWR);
if(fd == -1) {
perror("error open /dev/rtc");
return -1;
}
Set RTC Time
Assign the values of the passed parameter time
to rtc_tm
in preparation for setting the RTC time.
rtc_tm.tm_sec = time->tm_sec ;
rtc_tm.tm_min = time->tm_min ;
rtc_tm.tm_hour = time->tm_hour ;
rtc_tm.tm_mday = time->tm_mday ;
rtc_tm.tm_mon = time->tm_mon - 1;
rtc_tm.tm_year = time->tm_year - 1900;
Call the ioctl
function to set the RTC time.
ret = ioctl(fd, RTC_SET_TIME, &rtc_tm);
if(ret == -1) {
perror("error RTC_SET_TIME ioctl");
close(fd);
return -1;
}
2.3.3 Main Function
The main function first reads the current RTC time and then sets the specified RTC time.
int main() {
int ret;
struct tm *input_time = NULL;
struct tm *output_time = NULL;
input_time = (struct tm *)malloc(sizeof(struct tm));
if (!input_time) {
printf("Malloc input struct tm fail!\n");
return -1;
}
output_time = (struct tm *)malloc(sizeof(struct tm));
if (!output_time) {
printf("Malloc output struct tm fail!\n");
return -1;
}
memset(input_time, 0, sizeof(struct tm));
memset(output_time, 0, sizeof(struct tm));
ret = rtc_get_time(output_time);
if (ret)
printf("rtc_get_time fail!\n");
else
printf("GET RTC TIME : %04d-%02d-%02d,%02d:%02d:%02d\n",
output_time->tm_year + 1900,output_time->tm_mon + 1, output_time->tm_mday,
output_time->tm_hour, output_time->tm_min, output_time->tm_sec);
input_time->tm_year = 2024;
input_time->tm_mon = 1;
input_time->tm_mday = 13;
input_time->tm_hour = 12;
input_time->tm_min = 0;
input_time->tm_sec = 0;
ret = rtc_set_time(input_time);
if (ret)
printf("rtc_set_time fail!\n");
else
printf("SET RTC TIME : %04d-%02d-%02d,%02d:%02d:%02d\n",input_time->tm_year, input_time->tm_mon,
input_time->tm_mday, input_time->tm_hour, input_time->tm_min, input_time->tm_sec);
free(input_time);
free(output_time);
return 0;
}
Below is an analysis of the main function:
Read RTC Time
Read the RTC time by calling the rtc_get_time()
function and format the output
ret = rtc_get_time(output_time);
if (ret)
printf("rtc_get_time fail!\n");
else
printf("GET RTC TIME : %04d-%02d-%02d,%02d:%02d:%02d\n",
output_time->tm_year + 1900,output_time->tm_mon + 1, output_time->tm_mday,
output_time->tm_hour, output_time->tm_min, output_time->tm_sec);
Set RTC Time
Set the RTC time by calling the rtc_set_time()
function and format the output.
ret = rtc_set_time(input_time);
if (ret)
printf("rtc_set_time fail!\n");
else
printf("SET RTC TIME : %04d-%02d-%02d,%02d:%02d:%02d\n",input_time->tm_year, input_time->tm_mon,
input_time->tm_mday, input_time->tm_hour, input_time->tm_min, input_time->tm_sec);
2.3.4 Cross-Compilation
Specify the Cross-Compilation Tool
First, you need to add the path to the cross-compilation tool to the system's
PATH
environment variable so that you can use the cross-compilation tool from anywhere. You can add the following line to your shell configuration file (usually~/.bashrc
or~/.bash_profile
or~/.zshrc
, depending on your shell). Note that the path afterPATH=
should point to the directory where the cross-compilation tool is located.gcc path
<SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
Open the shell configuration file.
vi ~/.bashrc
Add the path of the cross-compilation tool to the system's PATH environment variable.
Replace
<SDK Directory>
with your own SDK path, such as/home/luckfox/luckfox-pico/
.export PATH=<SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin:$PATH
Reload the shell configuration file to apply the changes:
source ~/.bashrc
Compile the Program Using the Cross-Compilation Tool
arm-rockchip830-linux-uclibcgnueabihf-gcc rtc.c -o rtc
After successful cross-compilation, an executable file that can run on the development board will be generated in the current directory.
# ls
rtc rtc.c
2.3.5 Running the Program
File Transfer
First, transfer the
rtc
program from the virtual machine to Windows, and then transfer it to the development board via TFTP or ADB. Here are the steps to transfer the file from Windows to the development board using ADB:adb push path_to_file destination_on_development_board
eg: (Transferring the `rtc` file from the current directory to the root directory of the development board)
adb push rtc /Running the Program
Modify the permissions of the
rtc
file and then run the program:# chmod +x rtc
# ./rtcExperimental Observations
Get RTC time and set RTC time:
3.System Time Adjustment
Below we introduce how to add the ntpd package in Buildroot and configure ntpd in client mode for network time synchronization.
3.1 Add the ntpd Package
Press / to search for "ntpd", find "ntpd" under "ntp", and press 2 to jump (for detailed steps, please refer to the kernel configuration section of SDK environment deployment)
Press Y to select "ntp" and "ntpd" respectively ("ntpd" will be displayed after "ntp" is enabled)
3.2 Reburn Firmware
Compile by selecting the branch and specifying the development board model:
luckfox@luckfox:~/luckfox-pico$ ./build.sh lunch
Compile:
luckfox@luckfox:~/Luckfox-Pico/luckfox-pico$ ./build.sh
Reflash the firmware:
After compiling, reflash the firmware.
3.3 Network Time Synchronization
Modify the time zone:
Open the file:
vi /etc/profile
Add the line:
export TZ=CST-8
Reload configuration file:
source /etc/profile
Check the current time zone:
date -R
Terminate the ntpd process:
# ps | grep ntpd
204 root /usr/sbin/ntpd -g -p /var/run/ntpd.pid
423 root grep ntpd
# kill -9 204Network time synchronization
# ntpd -p cn.ntp.org.cn -qn
8 Dec 14:27:51 ntpd[423]: ntpd 4.2.8p15@1.3728-o Fri Dec 8 06:12:46 UTC 2023 (1): Starting
8 Dec 14:27:51 ntpd[423]: Command line: ntpd -p cn.ntp.org.cn -qn
8 Dec 14:27:51 ntpd[423]: ----------------------------------------------------
8 Dec 14:27:51 ntpd[423]: ntp-4 is maintained by Network Time Foundation,
8 Dec 14:27:51 ntpd[423]: Inc. (NTF), a non-profit 501(c)(3) public-benefit
8 Dec 14:27:51 ntpd[423]: corporation. Support and training for ntp-4 are
8 Dec 14:27:51 ntpd[423]: available at https://www.nwtime.org/support
8 Dec 14:27:51 ntpd[423]: ----------------------------------------------------
8 Dec 14:27:51 ntpd[423]: proto: precision = 1.166 usec (-20)
8 Dec 14:27:51 ntpd[423]: basedate set to 2023-11-26
8 Dec 14:27:51 ntpd[423]: gps base set to 2023-11-26 (week 2290)
8 Dec 14:27:53 ntpd[423]: restrict: ignoring line 11, address/host '[::1]' unusable.
8 Dec 14:27:53 ntpd[423]: Listen and drop on 0 v4wildcard 0.0.0.0:123
8 Dec 14:27:53 ntpd[423]: Listen normally on 1 lo 127.0.0.1:123
8 Dec 14:27:53 ntpd[423]: Listen normally on 2 eth0 192.168.10.148:123
8 Dec 14:27:53 ntpd[423]: Listen normally on 3 usb0 172.32.0.93:123
8 Dec 14:27:53 ntpd[423]: Listening on routing socket on fd #20 for interface updates
8 Dec 14:28:00 ntpd[423]: ntpd: time slew -0.019767 s
ntpd: time slew -0.019767sSynchronize system time to hwclock
hwclock --systohc
Check hwclock
hwclock
During startup, synchronize from hwclock to system time
hwclock -u -s