[RTEX] Horloge RTC sur odroid c2 et odroid c4 en armbian

Bonjour,

Je viens d’équiper les systèmes odroid (c2 et c4 en armbian) de la box jeedom de mon fils et la mienne d’une horloge RTC.
Ca m’a pris du temps, car le peu de doc qu’on trouve concerne des odroid c2 et c4 en ubuntu ; et ça diffère pas mal.

J’ai utilisé des ‹ shield RTC › comme celui-ci : RTC Shield – ODROID ; achetés 2.40€ pièce chez domadoo, mais je crains avoir acheté la fin du stock …
Ce périphérique contient une puce pcf8563 ; il fonctionne en device i2c, à l’adresse 0x51.

La principale doc qui m’a été utile est celle-ci (malheureusement pour ubuntu) : https://wiki.odroid.com/accessory/add-on_boards/rtc_shield

Ce premier post concerne l’installation sur un odroid c2 ; le post suivant concernera les différences pour l’odroid c4.

Les deux systèmes sont en Bullseye

Installation sur odroid C2
En préalable, on constate que le support i2c est compilé dans le noyau ; le device /dev/i2c-0 correspond à l’interface i2c du GPIO (adresse c1108500), il est actif, et le support du pcf8563 est disponible en module.
/dev/rtc0 correspond à un device RTC virtuel, utilisé par le service fake-hwclock qui tente de faire pour le mieux coté horloge lors du boot, en l’absence d’une vrai horloge RTC.

# ls -al /dev/i2c*
crw-rw---- 1 root i2c 89, 0  6 juin  07:17 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1  6 juin  07:17 /dev/i2c-1

# udevadm info /dev/i2c-0
P: /devices/platform/soc/c1100000.bus/c1108500.i2c/i2c-0/i2c-dev/i2c-0

# ls -al /dev/rtc*
lrwxrwxrwx 1 root root      4  6 juin  07:17 /dev/rtc -> rtc0
crw------- 1 root root 251, 0  6 juin  07:17 /dev/rtc0

# lsmod | grep rtc
rtc_meson_vrtc         16384  1

# apt install device-tree-compiler i2c-tools

# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
...
50: -- 51 -- -- -- -- -- -- -- -- -- -- -- -- -- --

grace à i2cdetect, on voit que le pcf8563 est bien vu à l’adresse 51 sur /dev/i2c-0

################ premiers essais, pour vérifier le fonctionnement ###########################
On va charger le module correspondant au pcf8563 :

# lsmod | grep rtc
rtc_pcf8563            24576  0
rtc_meson_vrtc         16384  1

puis on informe le noyau de la présence d’un périphérique pcf8563 présent à l’adresse 0x51 sur /dev/ic2-0

# echo pcf8563 0x51 > /sys/class/i2c-adapter/i2c-0/new_device

# tail /var/log/syslog
2024-06-04T18:51:26.987235+02:00 odroidc2VM kernel: [10104.566303] rtc-pcf8563 0-0051: registered as rtc1
2024-06-04T18:51:26.992491+02:00 odroidc2VM kernel: [10104.569934] i2c i2c-0: new_device: Instantiated device pcf8563 at 0x51

# ls -al /dev/rtc*
lrwxrwxrwx 1 root root      4  3 juin  19:12 /dev/rtc -> rtc0
crw------- 1 root root 251, 0  3 juin  19:12 /dev/rtc0
crw------- 1 root root 251, 1  3 juin  19:18 /dev/rtc1

# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
...
50: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- --

#### The "UU" indicates devices owned by the kernel, being managed by a device driver. 

maintenant, on vérifie le fonctionnement du RTC avec hwclock

# hwclock -v --show -f /dev/rtc1
hwclock from util-linux 2.38.1
System Time: 1717435134.720866
Using the rtc interface to the clock.
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
ioctl(4, RTC_UIE_ON, 0): Argument invalide
Waiting in loop for time from /dev/rtc1 to change
...got clock tick
Time read from Hardware Clock: 2024/06/03 17:11:42
Hw clock time : 2024/06/03 17:11:42 = 1717434702 seconds since 1969
Time since last adjustment is 1717434702 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2024-06-03 19:11:41.460319+02:00

##### lire la date de la RTC
# hwclock -r -f /dev/rtc1

#### écrire la date système dans la rtc :
# hwclock -w -f /dev/rtc1

############## rendre permanente la prise en charge du RTC ######################
Tout fonctionne donc correctement ; il reste maintenant à faire démarrer tout cela automatiquement lors du boot. il faut également que l’horloge RTC soit prise en compte au plus tôt ; donc on n’utilisera pas le fichier /etc/rc.local, qui serait traité trop tard.

Pour la prise en charge du module, c’est très simple : ajout de la ligne suivante dans /etc/modules

# cat /etc/modules
rtc_pcf8563

# reboot

Pour la déclaration du périphérique, on va créer un ‹ user overlay ›.
On créer un fichier DTS (source device-tree) comme celui-ci :

# cat meson-pcf8563.dts
/dts-v1/;
/plugin/;

/ {
        compatible = "amlogic";


        fragment@0 {
        target-path = "/soc/bus@c1100000/i2c@8500";
                __overlay__ {
                        pcf8563@51 {
                                compatible = "rtc-pcf8563,pcf8563";
                                reg = <0x51>;
                                status = "okay";
                        };
                };
        };
};

La commande suivante va compiler ce fichier vers /boot/overlay-user/meson-pcf8563.dtbo et déclarer le user overlay dans armbianEnv.txt :

# armbian-add-overlay meson-pcf8563.dts

# cat /boot/armbianEnv.txt
...
user_overlays=meson-pcf8563

# reboot

Au boot suivant, on vérifie que tout fonctionne corectement :

# ls -al /dev/rtc*
lrwxrwxrwx 1 root root      4 11 juin  08:45 /dev/rtc -> rtc0
crw------- 1 root root 251, 0 11 juin  08:45 /dev/rtc0
crw------- 1 root root 251, 1 11 juin  08:45 /dev/rtc1

# dmesg | grep rtc
[    2.037327] meson-vrtc c81000a8.rtc: registered as rtc0
[    2.037376] meson-vrtc c81000a8.rtc: setting system clock to 1970-01-01T00:00:02 UTC (2)
[    3.751523] rtc-pcf8563 0-0051: registered as rtc1

Maintenant, on veut que le système soit mis à jour avec l’horloge RTC au boot, au plus tôt. Pour cela, on va créer puis activer un service (hwrtc) :

# cat /lib/systemd/system/hwrtc.service

[Unit]
Description=Synchronise System clock to hardware RTC
DefaultDependencies=no
After=systemd-modules-load.service fake-hwclock.service
Before=systemd-journald.service time-sync.target sysinit.target cron.service shutdown.target
Conflicts=shutdown.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/hwclock --hctosys --rtc=/dev/rtc1 --utc --noadjfile
RestrictRealtime=yes

[Install]
WantedBy=sysinit.target

# systemctl enable hwrtc

# reboot

On controle au boot suivant :

# dmesg | grep rtc
[    2.037327] meson-vrtc c81000a8.rtc: registered as rtc0
[    2.037376] meson-vrtc c81000a8.rtc: setting system clock to 1970-01-01T00:00:02 UTC (2)
[    3.751523] rtc-pcf8563 0-0051: registered as rtc1
[    3.833695] systemd[1]: Starting hwrtc.service - Synchronise System clock to hardware RTC...
[    3.928232] systemd[1]: Finished hwrtc.service - Synchronise System clock to hardware RTC.


# systemctl status hwrtc
● hwrtc.service - Synchronise System clock to hardware RTC
     Loaded: loaded (/lib/systemd/system/hwrtc.service; enabled; preset: enabled)
     Active: active (exited) since Tue 2024-06-11 08:45:30 CEST; 18min ago
    Process: 1161 ExecStart=/sbin/hwclock --hctosys --rtc=/dev/rtc1 --utc --noadjfile (code=exited, status=0/SUCCESS)
   Main PID: 1161 (code=exited, status=0/SUCCESS)
        CPU: 14ms

Maintenant, je ne suis pas certain que l’horloge du pcf8563 se mette à jour automatiquement à partir du système synchronisé en NTP. Je pense que c’est souhaitable pour éviter une dérive.

J’ai créé le script suivant, exécuté une fois par semaine ; il pourra également m’informer en cas de problème (pile déchargée, …)

#!/bin/bash

DEST=xxxx@yyyy
REPLYTO=xxxx@yyy

HOSTNAME=`hostname`
DATE=`date`

for i in {1..5}
do
  /usr/sbin/ntpwait -v
  RET=$?
  if [ $RET -eq 0 ]; then
    break
  fi
  sleep 2
done

if [ $RET -ne 0 ]; then
  echo "ERREUR lors de la mise a jour de l'horloge RTC : synchro NTP" | mail -s "$HOSTNAME. erreur mise a jour horloge RTC, $DATE" -r $REPLYTO $DEST
fi

/usr/sbin/hwclock -w -f /dev/rtc1
if [ $? -ne 0 ]; then
  echo "ERREUR lors de la mise a jour de l'horloge RTC, sur la commande hwclock" | mail -s "$HOSTNAME. erreur mise a jour horloge RTC, $DATE" -r $REPLYTO $DEST
fi

Et voila, l’horloge RTC fonctionne parfaitement sur mon système android c2 en armbian …

1 « J'aime »

installation horloge RTC pfc8563 sur odroid c4 en armbian

La procédure est similaire à la précédente, … avec quelques différences liées surtout à des bugs

Comme sur odroid c2, le support i2c est compilé dans le noyau et le support du pcf8563 est disponible en module.
Mais le device correspondant à l’interface i2c du GPIO (adresse ffd1d000) n’est pas activé dans le device-tree ; surtout, ce qui m’a pris beaucoup de temps, c’est que la définition de cette interface dans le device-tree est incomplète : il manque l’information ‹ pinctrl-0 ›.

J’ai donc du créer un overlay plus complexe que pour l’odroid c2 : il corrige la déclaration de l’interface i2c, il l’active, et il rajoute l’intégration du pcf8563, comme précédemment.
Le voici :

# cat meson-pcf8563.dts
/dts-v1/;
/plugin/;

/dts-v1/;
/plugin/;

/ {
    compatible = "amlogic";

    fragment@0 {
        target-path = "/aliases";
        __overlay__ {
            i2c0 = "/soc/bus@ffd00000/i2c@1d000";
        };
    };

    fragment@1 {
        target-path = "/soc/bus@ffd00000/i2c@1d000";
        __overlay__ {
            pinctrl-0 = <&i2c2_sda_x_pins>, <&i2c2_sck_x_pins>;
            pinctrl-names = "default";
            status = "okay";

            pcf8563: rtc@51 {
                compatible = "rtc-pcf8563,pcf8563";
                reg = <0x51>;
            };

        };
    };
};

Pour faire propre, j’aurais pu créer deux overlays : l’un pour l’interface i2c, l’autre pour le pcf8563 ; j’ai préféré faire simple.

La commande armbian-add-overlay ne fonctionne pas sur odroid c4 ; c’est un bug. J’ai donc compilé puis activé l’overlay à la main :

# mkdir /boot/overlay-user/

# dtc -I dts -O dtb -o /boot/overlay-user/meson-pcf8563.dtbo meson-pcf8563.dts
meson-pcf8563.dts:23.17-30: Warning (reg_format): /fragment@1/__overlay__/rtc@51:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
...

# cat /boot/armbianEnv.txt
...
user_overlays=meson-pcf8563

# reboot

A noter : lors de la compilation du fichier meson-pcf8563.dts (commande dtc), plusieurs warnings s’affichent, en lien avec le format de la directive ‹ reg › ; je n’ai pas trouvé comment éviter ces messages, mais la compilation fonctionne correctement

Maitenant, le reste de la procédure est identique à celle de l’odroid c2 :smiley: