Setting System Clock From External RTC At Startup

Hi,

I have a Jetson Orin Nano Developer Kit Running Ubuntu 22.04 and Jetpack 6.

I am trying to set my system clock to the hardware clock time using an external RTC over I2C (ds3231 from Adafruit Adafruit PiRTC - Precise DS3231 Real Time Clock for Raspberry Pi : ID 4282 : Adafruit Industries, Unique & fun DIY electronics and kits). I tried using the built-in clock on the Jetson, but had issues soldering the surface mount battery connector and resistor to the board…

Anyways, here is what I have so far:

  • I have the external RTC setup as rtc2 and connected to the Jetson I2C pins (rtc0 and rtc1 are internal to the Jetson)
  • The external RTC is successfully maintaining its clock when the Jetson is powered down
  • I am able to manually set the system clock to rtc2’s hardware using the command "sudo hwclock -s -f /dev/rtc2
  • I have disabled NTP/automatic time updating from the internet

I would like to have the system clock automatically update to the external rtc2 clock at startup. I have tried a few things. So far, the Jetson always resets to the rtc0 clock after reboot.

I have tried running the sudo hwclock -s -f /dev/rtc2 command in crontab (both as local and sudo). I’ve confirmed my cron service is running and the command runs on its own. I have also tried modifying to the /etc/init.d/hwclock.sh.

Is there a way to change the rtc clock configurations so that my external clock is rtc0? Or is there another file I need to change to have it use rtc2 as the source?

Many thanks!

#!/bin/sh
timedatectl >> Desktop/date.txt
echo ds3231 0x68 | sudo tee /sys/class/i2c-dev/i2c-7/device/new_device
sudo hwclock --hctosys -f /dev/rtc2

FYI this is the script that I am running to set the system clock to the external RTC clock. It works if I just run from a command line once the system is already boot. Any reason why it doesn’t work when I try and run at startup (thru cron)?

hello ebs27,

here’s kernel driver for setting date and reading it back.
please check whether it’s reporting any errors.
$public_sources/kernel_src/kernel/nvidia-oot/drivers/rtc/nvvrs-pseq-rtc.c

static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
...
        ret = i2c_smbus_read_byte_data(client, info->drv_data->map[RTC_T2]);
        if (ret < 0) {
                dev_err(info->dev, "Failed to read time reg:0x%x ret:(%d)\n",
                        info->drv_data->map[RTC_T2], ret);
                goto out;
        }   
static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
...
        ret = i2c_smbus_write_byte_data(client, info->drv_data->map[RTC_T2], time[2]);
        if (ret < 0) {
                dev_err(info->dev, "Failed to write time reg: 0x%x ret:(%d)\n",
                        info->drv_data->map[RTC_T2], ret);
                goto out;
        }

I’ve got it work! I’m now able to set the system clock from my external rtc (rtc2) via a start-up script. I also tried this as rc.local startup script instead of cron, since I read somewhere in NVIDIA FAQs that that is how you should handle startup scripts on Jetsons

Old script

#!/bin/sh
echo ds3231 0x68 | sudo tee /sys/class/i2c-dev/i2c-7/device/new_device
sudo hwclock --hctosys -f /dev/rtc2 --verbose

I dug a little deeper and found that the first line (echo…) was working properly and creating the device path. I added the --verbose flag and looked at the system status message after booting the Jetson and found that the second line (hwclock…) was failing because “No usable clock interface found.” I thought this was strange because it has root access and I can run that command manually after the cpu had booted. Maybe something wasn’t fully initialized at that point?

New Script

#!/bin/sh
echo ds3231 0x68 | sudo tee /sys/class/i2c-dev/i2c-7/device/new_device
sleep 1
sudo hwclock --hctosys -f /dev/rtc2 --verbose

The solution was to add a sleep (used an arbitrary 1 second, it could probably be lower?) between the two lines. This works.

I haven’t gone back and tried with cron, but I imagine it would work too and that moving the commands to rc.local might not have been necessary. There might be a more “proper” solution for this, but it works for my situation and it’s simple so I’m marking it as a solution.

hello ebs27,

thanks for sharing, glad to know it works.

please refer to service config, for instance, /etc/systemd/system/nv.service
it should works with After commands, which waiting for device to initial completely.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.