Introduction
The Aopen Chromebase (or Chromebox) Mini seems to be equipped with a real time clock (RTC):
[ 0.321120] rk808-rtc rk808-rtc: registered as rtc0
[ 0.321596] rk808-rtc rk808-rtc: setting system clock to 2013-01-18T15:30:40 UTC (1358523040)
The problem is the lack of a battery to keep the time when power is removed.
Note the 2013 date in the above dmesg output.
This post details how to add an external battery backed RTC module connected to the HDMI port.
Hardware
I used a DS3231 RTC module like this:
I removed an HDMI connector from a cable and used a small breadboard for testing:
Pinout:
HDMI | DS3231 |
---|---|
15-SCL | C |
16-SDA | D |
17-GND | - |
18-VCC | + |
19-HPD | + |
Note the 22k ohm resistor in the picture that connects 5v VCC to the hot plug detect pin (19-HPD).
There is contradictory information about the value and even the need for this resistor at all. See references at the bottom of this page.
I tested with the 22k resistor and without and both configurations worked.
I did not have a 1k resistor to test with but I assume that would work fine and aligns with this comment from the ti.com link:
Note that many Sink devices simply connect the HPD signal to the +5V Power signal through a 1000 ohm resistor.
A custom PCB from https://jlcpcb.com/ enabled me to assemble a clean and compact final solution, despite my ineptness with a soldering iron. I used a DS3231 module from Amazon and desoldered the battery (reuse) and pin header (discard). I went with a 1k ohm resistor in the final assembly.
Parts list:
MFR. Part | LCSC Part | Description |
---|---|---|
DS3231 | NA | Real Time Clock Module |
HYC109-HDMIA19-160 | C711355 | 19 male HDMI Board Edge, Straddle Mount Connector |
MF1/4W-1KΩ±1%T52 | C713997 | Metal Film Resistors 1k± 250mW |
Software
The below kernel patch needs to be reverted.
The commit message was “Switch to builtin HDMI DDC bus on rk3288-veyron”.
I was not able to communicate with the external RTC until I backed this change out.
--- a/arch/arm/boot/dts/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi
@@ -175,7 +175,8 @@
};
&hdmi {
- ddc-i2c-bus = <&i2c5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_ddc>;
status = "okay";
};
@@ -346,14 +347,6 @@
i2c-scl-rising-time-ns = <300>; /* 225ns measured */
};
-&i2c5 {
- status = "okay";
-
- clock-frequency = <100000>;
- i2c-scl-falling-time-ns = <300>;
- i2c-scl-rising-time-ns = <1000>;
-};
-
&io_domains {
status = "okay";
Make sure the below kernel options are set.
The century option is probably not required but I set it anyway.
CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_DS1307_CENTURY=y
I tried CONFIG_I2C_CHARDEV built into the kernel instead of as a module but the /dev/i2c-* device files weren’t created on boot.
Loading the i2c-dev module does create them and allows the userspace tools to work correctly so I decided to just leave it as a module.
Loading the module is only needed when using tools like i2cdetect and isn’t required for the system to make use of the rtc.
cbtest:~$ doas i2cdetect -l
cbtest:~$ doas i2cdetect -y 5
Error: Could not open file '/dev/i2c-5' or '/dev/i2c/5': No such file or directory
cbtest:~$ doas modprobe i2c-dev
cbtest:~$ doas i2cdetect -l
i2c-0 i2c rk3x-i2c I2C adapter
i2c-1 i2c rk3x-i2c I2C adapter
i2c-2 i2c rk3x-i2c I2C adapter
i2c-3 i2c rk3x-i2c I2C adapter
i2c-4 i2c rk3x-i2c I2C adapter
i2c-5 i2c rk3x-i2c I2C adapter
i2c-6 i2c DP-AUX I2C adapter
cbtest:~$ doas i2cdetect -y 5
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Before adding the new new device we only see rtc0:
cbtest:~$ ls /dev/rtc*
/dev/rtc /dev/rtc0
Add the device:
/home/cb # echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-5/new_device
We should see rtc1 now:
cbtest:~$ ls /dev/rtc*
/dev/rtc /dev/rtc0 /dev/rtc1
Use hwclock to read the time from /dev/rtc1
cbtest:~$ doas hwclock -r --verbose --rtc=/dev/rtc1
hwclock from util-linux 2.38.1
System Time: 1668960978.460699
Using the rtc interface to the clock.
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
ioctl(3, RTC_UIE_ON, 0): Invalid argument
Waiting in loop for time from /dev/rtc1 to change
...got clock tick
Time read from Hardware Clock: 2022/11/20 16:33:47
Hw clock time : 2022/11/20 16:33:47 = 1668962027 seconds since 1969
Time since last adjustment is 1668962027 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2022-11-20 11:33:46.613956-05:00
Testing looks good but we want the system to use /dev/rtc1 automatically on boot.
The symlink for /dev/rtc is currently pointing to /dev/rtc0
cbtest:~$ ls -alh /dev/rtc
lrwxrwxrwx 1 root root 4 Nov 20 11:05 /dev/rtc -> rtc0
Create a udev rules file name /etc/udev/rules.d/99-rtc1.rules with the following content:
KERNELS=="i2c-5", SUBSYSTEMS=="i2c", DRIVERS=="", ATTRS{name}=="rk3x-i2c", RUN+="/bin/sh -c 'echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-5/new_device'"
KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="rtc-ds1307 5-0068", SYMLINK+="rtc"
The above entries first create the rtc1 device and then change the /dev/rtc symlink to point to /dev/rtc1
Unfortunately, the hwclock utility by default looks for /dev/rtc0 first and then /dev/rtc so just changing the /dev/rtc target isn’t enough.
Edit /etc/conf.d/hwclock to use rtc1 via our retargeted symlink:
clock_args="--rtc=/dev/rtc"
Reboot and /dev/rtc should now be pointing at the new /dev/rtc1
cbtest:~$ ls -alh /dev/rtc*
lrwxrwxrwx 1 root root 4 Jan 18 2013 /dev/rtc -> rtc1
crw------- 1 root root 250, 0 Jan 18 2013 /dev/rtc0
crw------- 1 root root 250, 1 Jan 18 2013 /dev/rtc1
The hwclock init script sets the system time based on the rtc1 time at boot and also updates it on shutdown based on the current system clock, which may have been updated by NTP.
References
https://mitxela.com/projects/ddc-oled
https://blog.danman.eu/emulating-hdmi-connection/
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/arch/arm/boot/dts/rk3288-veyron.dtsi?h=v5.15.74&id=bf09924f21767e6bb7cb3aae48c48c2c2ab8261a
https://unix.stackexchange.com/questions/246605/how-can-the-link-target-of-dev-rtc-be-changed
https://electronics.stackexchange.com/questions/331242/how-to-trigger-hot-plug-detection-in-hdmi-interface
https://e2e.ti.com/support/interface-group/interface/f/interface-forum/580292/tpd12s016-hpd-signal-powered-by-different-power-supply
https://forums.raspberrypi.com/viewtopic.php?t=330201#p1977333
https://bugs.launchpad.net/ubuntu/+source/linux-raspi/+bug/1981078
https://learn.adafruit.com/adding-a-real-time-clock-to-raspberry-pi/set-rtc-time
https://man7.org/linux/man-pages/man8/hwclock.8.html
https://busware.de/tiki-index.php?page=RTUL
https://movella.force.com/XsensKnowledgebase/s/article/My-MTi-6XX-is-not-detected-Installing-the-MTi-USB-dongle-driver-for-Linux?language=en_US
https://www.lcsc.com/
https://jlcpcb.com/