RTC SoM driver for Colibri iMX6 running Torizon

Colibri iMX6DL 512MB v1.1B

I am using a custom carrier board, and we planned on using the RTC on the SoM
We modified the circuit to use a rechargeable battery, so it should last since we have stable power…

But I dont see how to add it in the device tree. My device tree expert says:

“As there is no driver for the SoM RTC you will need to create one.”

Is this true? Do you not have a drive available for this SoM RTC?

Thanks

Hi @leighjboyd ,

The SoM RTC has a driver in the kernel (rtc-snvs.c « rtc « drivers - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules) and it should be enabled already. Our default Device Tree is also configured to enable it, so you shouldn’t need to change the DT either.

On the module try running dmesg | grep rtc. The output should be similar to the one found here: Real-Time Clock / RTC (Linux) | Toradex Developer Center. This article also has more information about RTC usage in Linux in general, and it also applies to TorizonCore.

Let me know if this helps you.

Best regards,
Lucas Akira

Hi, thanks for your quick response.

Good to know I will not be needing any more DT intervention. Now its just to learn best practices about how to use the RTC…

I did a grep of the dmesg as you say and got this:

colibri-imx6-10866289:~$ dmesg | grep rtc
[    1.596521] snvs_rtc 20cc000.snvs:snvs-rtc-lp: registered as rtc1
[    2.069132] hctosys: unable to open rtc device (rtc0)

The same result for the Colibri Evaluation board

I suppose i expected one of them to stop working, because I disabled it in the device tree (the colibri Evaluation board approach, with an external RTC is not the approach we will be using) so now I guess I have some reading to do… Am I supposed to be telling the system that it should use rtc1 instead of rtc0?

Here is the result of timedatectl:

colibri-imx6-10866289:~$ timedatectl
               Local time: Tue 2022-07-26 10:12:43 EDT
           Universal time: Tue 2022-07-26 14:12:43 UTC
                 RTC time: n/a
                Time zone: America/Toronto (EDT, -0400)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
colibri-imx6-10866289:~$

I just read about this part, I will try it next!

Change Default RTC

To change the default RTC as e.g. used by hwclock create a file called /etc/udev/rules.d/99-rtc1.rules with e.g. the following contents:

KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="m41t0", SYMLINK="rtc", MODE="0666"

Hi @leighjboyd ,

Let me know if changing the default RTC works or if you have any other questions.

Best regards,
Lucas Akira

I made the above changes to the file 99-rtc1.rules file as follows:

colibri-imx6-10866289:/etc/udev/rules.d$ ls
10-imx.rules                 90-toradex-gpio.rules    92-toradex-spidev.rules     94-toradex-pwm.rules  99-toradex.rules
10-toradex-net-rename.rules  91-toradex-i2cdev.rules  93-toradex-backlight.rules  99-rtc1.rules         touchscreen.rules
colibri-imx6-10866289:/etc/udev/rules.d$ cat 99-rtc1.rules
KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="m41t0", SYMLINK="rtc", MODE="0666"

colibri-imx6-10866289:/etc/udev/rules.d$

but nothing seems to have changed.

I still get:

colibri-imx6-10866289:~$ dmesg | grep rtc
[    1.555881] imx-drm display-subsystem: bound imx-ipuv3-crtc.2 (ops ipu_crtc_ops)
[    1.555986] imx-drm display-subsystem: bound imx-ipuv3-crtc.3 (ops ipu_crtc_ops)
[    1.596417] snvs_rtc 20cc000.snvs:snvs-rtc-lp: registered as rtc1
[    2.069201] hctosys: unable to open rtc device (rtc0)

which I guess is okay, since I have disabled rtc0 in the device tree.


colibri-imx6-10866289:~$ sudo hwclock -v
Password:
hwclock from util-linux 2.35.1
System Time: 1659469025.375691
Trying to open: /dev/rtc0
Trying to open: /dev/rtc
Trying to open: /dev/misc/rtc
No usable clock interface found.
hwclock: Cannot access the Hardware Clock via any known method.

I guess there is some file which dictates what order to look for the RTC…

Also noticed that in the line:
KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="m41t0", SYMLINK="rtc", MODE="0666"

I also see in the device tree that m41t0 is the name given to the RTC on the carrier board, so I’m wondering if that’s the problem (since I want the one on the SoM)… Maybe I need another name here?

/*
 * Colibri I2C: I2C3_SDA/SCL on SODIMM 194/196 (e.g. RTC on carrier board)
 */
&i2c3 {
	status = "okay";

	/* M41T0M6 real time clock on carrier board */
	rtc_i2c: rtc@68 {
		compatible = "st,m41t0";
		reg = <0x68>;
	};
};

also found this helpful link:
arch linux - How can the link target of /dev/rtc be changed? - Unix & Linux Stack Exchange

in that link he says I can run a test command…

colibri-imx6-10866289:/etc/udev/rules.d$ udevadm test /sys/class/rtc/rtc1
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

Load module index
Parsed configuration file /usr/lib/systemd/network/99-default.link
Parsed configuration file /etc/systemd/network/10-toradex-wifi-ifnames.link
Created link configuration context.
Reading rules file: /usr/lib/udev/rules.d/10-dm.rules
Reading rules file: /etc/udev/rules.d/10-imx.rules
Reading rules file: /etc/udev/rules.d/10-toradex-net-rename.rules
Reading rules file: /usr/lib/udev/rules.d/11-dm-lvm.rules
Reading rules file: /usr/lib/udev/rules.d/13-dm-disk.rules
Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules
Reading rules file: /usr/lib/udev/rules.d/60-autosuspend-chromiumos.rules
Reading rules file: /usr/lib/udev/rules.d/60-block.rules
Reading rules file: /usr/lib/udev/rules.d/60-cdrom_id.rules
Reading rules file: /usr/lib/udev/rules.d/60-drm.rules
Reading rules file: /usr/lib/udev/rules.d/60-evdev.rules
Reading rules file: /usr/lib/udev/rules.d/60-fido-id.rules
Reading rules file: /usr/lib/udev/rules.d/60-input-id.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-alsa.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-input.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-tape.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-v4l.rules
Reading rules file: /usr/lib/udev/rules.d/60-sensor.rules
Reading rules file: /usr/lib/udev/rules.d/60-serial.rules
Reading rules file: /usr/lib/udev/rules.d/61-autosuspend-manual.rules
Reading rules file: /usr/lib/udev/rules.d/64-btrfs.rules
Reading rules file: /usr/lib/udev/rules.d/69-dm-lvm-metad.rules
Reading rules file: /usr/lib/udev/rules.d/70-joystick.rules
Reading rules file: /usr/lib/udev/rules.d/70-mouse.rules
Reading rules file: /usr/lib/udev/rules.d/70-power-switch.rules
Reading rules file: /usr/lib/udev/rules.d/70-touchpad.rules
Reading rules file: /usr/lib/udev/rules.d/70-uaccess.rules
Reading rules file: /usr/lib/udev/rules.d/71-seat.rules
Reading rules file: /usr/lib/udev/rules.d/73-seat-late.rules
Reading rules file: /usr/lib/udev/rules.d/75-net-description.rules
Reading rules file: /usr/lib/udev/rules.d/75-probe_mtd.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-cinterion-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-dell-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-dlink-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-ericsson-mbm.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-fibocom-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-haier-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-huawei-net-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-longcheer-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-mtk-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-nokia-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-pcmcia-device-blacklist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-quectel-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-sierra.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-simtech-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-telit-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-tplink-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-ublox-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-usb-device-blacklist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-usb-serial-adapters-greylist.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-x22x-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/77-mm-zte-port-types.rules
Reading rules file: /usr/lib/udev/rules.d/78-sound-card.rules
Reading rules file: /usr/lib/udev/rules.d/80-drivers.rules
Reading rules file: /usr/lib/udev/rules.d/80-mm-candidate.rules
Reading rules file: /usr/lib/udev/rules.d/80-net-setup-link.rules
Reading rules file: /usr/lib/udev/rules.d/80-udisks2.rules
/usr/lib/udev/rules.d/80-udisks2.rules:176 Invalid key/value pair, ignoring.
Reading rules file: /usr/lib/udev/rules.d/85-nm-unmanaged.rules
Reading rules file: /usr/lib/udev/rules.d/90-nm-thunderbolt.rules
Reading rules file: /etc/udev/rules.d/90-toradex-gpio.rules
Reading rules file: /usr/lib/udev/rules.d/90-vconsole.rules
Reading rules file: /etc/udev/rules.d/91-toradex-i2cdev.rules
Reading rules file: /etc/udev/rules.d/92-toradex-spidev.rules
Reading rules file: /etc/udev/rules.d/93-toradex-backlight.rules
Reading rules file: /etc/udev/rules.d/94-toradex-pwm.rules
Reading rules file: /usr/lib/udev/rules.d/95-dm-notify.rules
Reading rules file: /usr/lib/udev/rules.d/99-fuse3.rules
Reading rules file: /etc/udev/rules.d/99-rtc1.rules
Reading rules file: /usr/lib/udev/rules.d/99-systemd.rules
Reading rules file: /etc/udev/rules.d/99-toradex.rules
Reading rules file: /etc/udev/rules.d/touchscreen.rules
Invalid inotify descriptor.
DEVPATH=/devices/soc0/soc/2000000.aips-bus/20cc000.snvs/20cc000.snvs:snvs-rtc-lp/rtc/rtc1
DEVNAME=/dev/rtc1
MAJOR=253
MINOR=1
ACTION=add
SUBSYSTEM=rtc
UDISKS_FILESYSTEM_SHARED=1
USEC_INITIALIZED=11876071
Unload module index
Unloaded link configuration context.
colibri-imx6-10866289:/etc/udev/rules.d$ udevadm test /sys/class/rtc/rtc1

which seems to get an error: invalid inotify descriptor.

I do see the device in /dev though:

colibri-imx6-10866289:/dev$ ls | grep rtc
colibri-uartc
rtc1

I also get this useful information if I type the following udevadm command…

colibri-imx6-10866289:/dev$ udevadm info -a -p /sys/class/rtc/rtc1

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/soc0/soc/2000000.aips-bus/20cc000.snvs/20cc000.snvs:snvs-rtc-lp/rtc/rtc1':
    KERNEL=="rtc1"
    SUBSYSTEM=="rtc"
    DRIVER==""
    ATTR{name}=="snvs_rtc 20cc000.snvs:snvs-rtc-lp"
    ATTR{hctosys}=="0"
    ATTR{range}=="[0,4294967295]"
    ATTR{date}=="1970-01-08"
    ATTR{time}=="00:11:21"
    ATTR{max_user_freq}=="64"
    ATTR{since_epoch}=="605481"
    ATTR{wakealarm}==""

  looking at parent device '/devices/soc0/soc/2000000.aips-bus/20cc000.snvs/20cc000.snvs:snvs-rtc-lp':
    KERNELS=="20cc000.snvs:snvs-rtc-lp"
    SUBSYSTEMS=="platform"
    DRIVERS=="snvs_rtc"
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc/2000000.aips-bus/20cc000.snvs':
    KERNELS=="20cc000.snvs"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc/2000000.aips-bus':
    KERNELS=="2000000.aips-bus"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0/soc':
    KERNELS=="soc"
    SUBSYSTEMS=="platform"
    DRIVERS==""
    ATTRS{driver_override}=="(null)"

  looking at parent device '/devices/soc0':
    KERNELS=="soc0"
    SUBSYSTEMS=="soc"
    DRIVERS==""
    ATTRS{revision}=="1.4"
    ATTRS{soc_id}=="i.MX6DL"
    ATTRS{family}=="Freescale i.MX"
    ATTRS{machine}=="Toradex Colibri iMX6DL/S on Colibri Evaluation Board V3"

Hi @leighjboyd ,

I followed the instructions in the helpful link you referenced, and based on that I wrote this in /etc/udev/rules.d/99-rtc1.rules:

KERNEL=="rtc1", SUBSYSTEM=="rtc", DRIVER=="", ATTR{name}=="snvs_rtc 20cc000.snvs:snvs-rtc-lp", SYMLINK="rtc", MODE="0666"

After this I rebooted the module (Colibri iMX6DL 512MB v1.1A), ran the test command, got pretty much the same output as yours, including the Invalid inotify descriptor.

But hwclock worked anyway:

$ sudo hwclock -v
Password: 
hwclock from util-linux 2.35.1
System Time: 1658517609.833051
Trying to open: /dev/rtc0
Trying to open: /dev/rtc
Using the rtc interface to the clock.
Assuming hardware clock is kept in UTC time.
Waiting for clock tick...
...got clock tick
Time read from Hardware Clock: 1970/01/01 00:30:39
Hw clock time : 1970/01/01 00:30:39 = 1839 seconds since 1969
Time since last adjustment is 1839 seconds
Calculated Hardware Clock drift is 0.000000 seconds
1970-01-01 00:30:38.417336+00:00

The actual time is wrong because the SoM is not connected to the internet, but hwclock is using the SoM RTC.

Try using the 99-rtc1.rules file above and see if it works.

Best regards,
Lucas Akira

Oh good job!

Well, I was a bit impatient and modified the Device Tree (imx6dl-colibri-eval-v3.dts)

image

Seems to work for me as well,
now its just to make the container see the time… I can see the UTC time from the container, but not the local time.

I tried setting up these volumes:
image

and tried to run this in the “target commands”
ENV TZ=America/Los_Angeles;
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

Also trying something like
system("echo torizon1 | sudo -S timedatectl set-timezone America/New_York");
but i get:
sudo: timedatectl: command not found

so… no luck yet…

Glad that you managed to get the RTC working!

About setting the local time in the container, according to this link: https://www.howtogeek.com/devops/how-to-handle-timezones-in-docker-containers/ if you want timezone synchronization between the SoM and the container /etc/localtime and /etc/timezone should be bind mounted, just like you did. But you should also install tzdata in the container.

Try including tzdata in extrapackages and see if the date command returns the local time as defined outside the container. You can use timedatectl to ajust the timezone outside the container if you haven’t already done so.

Best regards,
Lucas Akira

Maybe I am jumping too far ahead of myself, since I don’t even have the timezones working yet, but i was hoping to have a configuration file, (which I may send using the COPY command for now, but in the future, something more elegant) and then at runtime, read the configuration (which contains timezone and other things) and set the timezone with timedatectl from WITHIN the container application…

Doesn’t seem like the right approach though… Since everyone suggests that the container should not have root priviledges, nor should I be sending passwords using systemcommand().

But what is the “best practice” solution then? Any suggestions?

Each time I load the target with a new OS, and deploy a new application container, there are still so many manual things I must do to get things running, like copy configuration files, autostartup.service files, etc. and now I must set the time with timedatectl too.

The more I can streamline things, the better.

Maybe I am jumping too far ahead of myself, since I don’t even have the timezones working yet, but i was hoping to have a configuration file, (which I may send using the COPY command for now, but in the future, something more elegant) and then at runtime, read the configuration (which contains timezone and other things) and set the timezone with timedatectl from WITHIN the container application…

You cannot use timedatectl inside the container, as systemd is not installed in it by default, and it is not recommended to do so.

I think a closer alternative to what you want in this case could be this: Instead of synchronizing timezones, you can pass the timezone you want in the container with the environment variable TZ. Put it in the env field of the IDE extension like this example:

Screenshot_20220804_163724

Don’t forget to put tzdata in extrapackages, or it won’t work.

Each time I load the target with a new OS, and deploy a new application container, there are still so many manual things I must do to get things running, like copy configuration files, autostartup.service files, etc. and now I must set the time with timedatectl too.

If you need to copy things from your host PC to TorizonCore’s filesystem, you can use TorizonCore Builder to create a custom image that has these files included already.

If you have to extensively configure things inside the container you might want to consider creating your own Docker image where you can describe copy/addition of files with a Dockerfile. From there, build it and upload it to DockerHub.

Afterwards you can change the baseimage config of the extension so that the IDE creates images based on your custom one. See this article for more details: Torizon IDE Backend Architecture and Internals | Toradex Developer Center

Best regards,
Lucas Akira

Oh, its so magical…

so I can open the CLI to my container, and use the date command, and guess what?
I get the local time!

Thanks again lucas!!!

One more step in the puzzle is to make the application see the local time…
It seems to work!

I am using the command:

            info = localtime(&curTime.tv_sec);     // gets the local time!
         //info = gmtime(&tmp.tv_sec);               // this gets the time in UTC

One problem I am still having, however, is that it seems to only work when I do the ole’
F1 - torizon: build release container for the application
F1 - torizon: deploy release container
Then I can see the dockerfile.release has updated to:

image

However, when I run in debug mode, I dont see the ENV TZ=America/Toronto anywhere in the dockerfile.debug

image

I was under the impression that this would update itself when I did a make clean and start debug.

I tried F1: torizon: build debug container and there was no change to this file!
oh, tried F1: torizon: switch to debug configuration…
still nothing. No ENV variable. I see that Dockerfile.debug is being created though (I made a backup called Dockerfile_old.debug, and the new one was created as Dockerfile.debug)

After a little monkeying around, I could get it by placing it in the preinstall commands…
ENV TZ=“America/Toronto”

So this is how to implement RTC with local time from a docker container. So cool.

Leigh