You can find cheap ds3231 i2c RTC module
, like https://www.aliexpress.com/item/1pcs-SAMIORE-ROBOT-DS3231-Precision-RTC-Module-Memory-Module/32828162429.html
but it needs set-up first. By the way, it connects on pins 1, 3, 5, (7), 9. See https://pinout.xyz/pinout/i2c.
As the ds3231
driver is compiled as a module (rtc-ds1307
), and not built-in,
the RTC_HCTOSYS
kernel config option which controls https://github.com/torvalds/linux/blob/master/drivers/rtc/hctosys.c
becomes useless: modules are loaded after the late_initcall()
hook (https://stackoverflow.com/questions/18605653/module-init-vs-core-initcall-vs-early-initcall).
So the kernel cannot set the time from the RTC (device is recognized too late). And systemd don't touch the time set by the kernel (not it's job):
- https://lists.freedesktop.org/archives/systemd-devel/2011-May/002526.html
- https://www.freedesktop.org/software/systemd/man/systemd-timedated.service.html
- https://www.freedesktop.org/software/systemd/man/timedatectl.html
- https://www.freedesktop.org/wiki/Software/systemd/timedated/
As neither the kernel nor systemd handle this out-of-the-box, and as ArchLinux doesn't embed messy script to handle that, you have to take care of this.
There's many solutions for this on Internet, many are wrong (main reason might be they're outdated) or overcomplicated:
- you can't really use a service: too early it'll fail because the device isn't present yet, too late you'll miss the opportunity to set the clock early
- you don't need to init the device using dtoverlay
- you don't need a service for this one-time command, and even less a script called by whatever
- you don't need to edit system files (like
/etc/init.d/hwclock.sh
or/lib/udev/hwclock-set
.. hello raspbian users)
The first inspiration for this solution is http://blog.fraggod.net/2015/11/25/replacing-built-in-rtc-with-i2c-battery-backed-one-on-beaglebone-black-from-boot.html, which is the right solution if you want to have the time-sync.target
"System Time Synchronized" target respected.
In the end I found https://gist.github.com/h0tw1r3/11191428/ and https://gist.github.com/Lahorde/2bc5e4a3b69fc6ca5797 but they're still not as simple as one config.txt
line & one udev
rule.
Some useful links:
- https://archlinuxarm.org/forum/viewtopic.php?f=9&t=9957
- https://lists.freedesktop.org/archives/systemd-devel/2011-November/003917.html
- http://reactivated.net/writing_udev_rules.html
- https://wiki.archlinux.org/index.php/udev#Writing_udev_rules
- https://www.freedesktop.org/software/systemd/man/udev.html
[root@alarmpi alarm]# udevadm info -a /dev/rtc0
looking at device '/devices/platform/soc/20804000.i2c/i2c-1/1-0068/rtc/rtc0':
KERNEL=="rtc0"
SUBSYSTEM=="rtc"
DRIVER==""
ATTR{date}=="2018-02-06"
ATTR{hctosys}=="0"
ATTR{max_user_freq}=="64"
ATTR{name}=="ds3231"
ATTR{since_epoch}=="1517960429"
ATTR{time}=="23:40:29"
looking at parent device '/devices/platform/soc/20804000.i2c/i2c-1/1-0068':
KERNELS=="1-0068"
SUBSYSTEMS=="i2c"
DRIVERS=="rtc-ds1307"
ATTRS{name}=="ds3231"
looking at parent device '/devices/platform/soc/20804000.i2c/i2c-1':
KERNELS=="i2c-1"
SUBSYSTEMS=="i2c"
DRIVERS==""
ATTRS{name}=="bcm2835 I2C adapter"
looking at parent device '/devices/platform/soc/20804000.i2c':
KERNELS=="20804000.i2c"
SUBSYSTEMS=="platform"
DRIVERS=="i2c-bcm2835"
ATTRS{driver_override}=="(null)"
looking at parent device '/devices/platform/soc':
KERNELS=="soc"
SUBSYSTEMS=="platform"
DRIVERS==""
ATTRS{driver_override}=="(null)"