Skip to content

Instantly share code, notes, and snippets.

@Lahorde Lahorde/0_README.md
Last active Jan 31, 2019

Embed
What would you like to do?
Initialize an external I2C RTC module on raspberry using udev and systemd

Description

Enable i2c RTC using systemd. A udev rules triggers an I2C systemd service on I2C kernel module adding. Service then loads I2C driver adding a new I2C device to /sys Then kernel loads I2C RTC driver and adds an RTC device It triggers a udev rules that updates hardware clock

Application on raspberry pi

Enable I2C

  • enable I2C in config.txt, adding device_tree_param=i2c1=on

  • enable I2C driver loading at boot, refer i2c.conf

  • reboot raspberry

  • check an I2C bus is found :

    i2cdetect -l
    i2c-1   unknown         bcm2835 I2C adapter                     N/A
    
  • check I2C rtc is detected :

    i2cdetect -y 1
    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: -- -- -- -- -- -- -- --          
    

Enable I2C RTC

  • create /etc/udev/rules.d/50-i2c_start.rules

  • create /etc/conf.d/rtc-i2c

  • create /etc/systemd/system/i2c_rtc.service

  • create /etc/udev/rules.d//etc/udev/rules.d/60-rtc-i2c.rules

  • test it:

    hwclock -r
    2000-01-02 01:25:04.301281+01:00
    
  • when an NTP service is started, it should set hwclock to a valid time, if not you must set a valid system clock and then set hwclock to system clock

    hwclock --systohc
    
  • reboot

  • system clock should be fine, even if system is not connected to outside world

# /etc/udev/rules.d/50-i2c_start.rules
#
#
#I2C hardware device driver
ACTION=="add", KERNEL=="i2c_bcm2708", SUBSYSTEM=="module", TAG+="systemd"
# /etc/udev/rules.d/60-rtc-i2c.rules
#
#
ACTION=="add", SUBSYSTEM=="rtc", ATTRS{hctosys}=="0", RUN+="/usr/bin/hwclock -s --utc"
#/etc/conf.d/rtc-i2c
# configure there your RTC chip and address
CHIP="ds1307"
ADDRESS="0x68"
BUS="1"
# /etc/modules.load.d/i2c.conf
i2c-bcm2708
i2c-dev
# /etc/systemd/system/i2c_rtc.service
[Unit]
Description=Initialize i2c hardware RTC device driver
DefaultDependencies=no
Requires=sys-module-i2c_bcm2708.device
After=sys-module-i2c_bcm2708.device
Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
EnvironmentFile=/etc/conf.d/rtc-i2c
ExecStart=/bin/sh -c "echo ${CHIP} ${ADDRESS} > /sys/class/i2c-adapter/i2c-${BUS}/new_device"
@solsticedhiver

This comment has been minimized.

Copy link

solsticedhiver commented Jan 31, 2019

That's a lot of file and rule. Most of it is not needed anymore. You don't have to manually load module and and set the i2c thing

Here is my setup.
I have a mcp7941x chip for the RTC.
The dtoverlay stuff takes care of module loading and configure the i2c stuff too. We only need to load i2c-dev.

Then the udev rule trigger a systemd service that calls hwclock. That's it.

Note: I use a systemd service because it seems udev has not the right to access/dev/rtcand then hwclock fails ?? Needs to be confirmed.

# /boot/config.txt

# [...]
dtparam=i2c=on
dtoverlay=i2c-rtc,mcp7941x=0x6f
# /etc/modules.d/i2c.conf
i2c-dev
i2c:mcp7941x
# /etc/udev/rules.d/rtc-i2c.rules 
KERNEL=="rtc0", SUBSYSTEM=="rtc", SUBSYSTEMS=="i2c", TAG+="systemd", ENV{SYSTEMD_WANTS}="hwclock.service"
# /etc/systemd/system/hwclock.service 
[Unit]
Description=Synchronize system clock from RTC

[Service]
ExecStart=/usr/bin/hwclock --hctosys --utc
Type=oneshot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.