Updated version of this for Raspbian Stretch here.
The Raspberry Pi is a great computing device at a great price – but to keep costs down, sacrifices had to be made. One of those sacrifices was a so-called “real-time clock” or RTC. Without one, the device forgets the time as soon as it’s powered down or rebooted. Fortunately, Internet connectivity is available in most cases and NTP can be used to synchronize the clock. In cases where Internet connectivity will be spotty or nonexistent, it may be a good idea to install a real-time clock.
There are many guides to configuring this in Raspbian Wheezy, but I was not able to find much for Jessie. Jessie is different from Wheezy in that it runs systemd, which is a completely new way to manage the system and services. I’d also like to note that this was all done on a Raspberry Pi model 2.
The RTC
I purchased a bunch of RTCs from eBay. Search for Raspberry Pi DS3231 – they can be had for about $2 apiece. Here’s what it looks like:
Install the RTC Device
You’ll want to install the RTC on the inside row of pins at the “bottom” of the connector, like so:
Install the Software
You’ll want two packages: i2c-tools and python-smbus. To install:
1 | sudo apt-get install i2c-tools python-smbus |
Configure the Device
First, go into the raspi-config utility by typing
1 | sudo raspi-config |
You’ll see a screen that looks like this:
Select Advanced Options, then I2C. Select Yes to enable it, and Yes to automatically load the kernel module.
Then, to be safe, add these lines to /etc/modules-load.d/rtc-i2c.conf:
1 2 3 | # /etc/modules-load.d/rtc-i2c.conf i2c-dev i2c_bcm2708 |
Configure udev to set the system time from the RTC when the device appears:
1 2 3 | # /etc/udev/rules.d/rtc-i2c.rules # ACTION=="add", SUBSYSTEM=="rtc", ATTRS{hctosys}=="0", RUN+="/sbin/hwclock -s --utc" |
Load the kernel modules immediately:
1 2 3 | sudo modprobe i2c-bcm2708 sudo modprobe i2c-dev sudo modprobe rtc-ds1307 |
Finally, check to see if the device is available:
1 | i2cdetect -y 1 |
You should see something like this:
1 2 3 4 5 6 7 8 9 | 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: -- -- -- -- -- -- -- -- |
The “68” is the i2c address of the clock module.
Systemd
Next, we’ll need to set up a systemd service called rtc-i2c.service. This will cause systemd to create the RTC device on boot. And remember, when udev sees the device appear, it will call the hwclock utility to set the system clock from the hardware clock.
First, the config file:
1 2 3 4 5 | # /etc/conf.d/rtc-i2c # CHIP="ds1307" ADDRESS="0x68" BUS="1" |
Then, the actual systemd service unit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # /lib/systemd/system/rtc-i2c.service [Unit] Description=Initialize i2c hardware RTC device driver DefaultDependencies=no Requires=systemd-modules-load.service After=systemd-modules-load.service Before=sysvinit.target ConditionPathExists=/sys/class/i2c-adapter 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" [Install] WantedBy=sysinit.target |
Finally, enable the service we just created:
1 | sudo systemctl enable rtc-i2c.service |
Cleanup
Raspbian by default includes a fake hardware clock, which we don’t need anymore because we have a real one. Remove the package and service:
1 2 | sudo apt-get remove fake-hwclock update-rc.d -f fake-hwclock remove |
Notes
If you run ntpd to sync the time to the internet, it will automatically update the hardware clock every 15 minutes.
Credits
Many thanks to github user h0tw1r3 for the systemd instructions which came from this gist.