To replace a hardware clock with a dead battery, I chose another
model based on the same DS3231 chip, but with a replaceable battery. This
new device is not designed to be plugged directly into the Raspberry Pi
GPIO header. To accommodate the battery holder the board is much larger
which made it possible to add I²C flash memory. The 8 pin chip,
beside the much bigger DS3231, is a 32K bit (4K bytes) AT24C32 EEPROM.

Instructions on how to connect the clock to the
hardware I²C bus of the Raspberry Pi running Raspbian
Buster and how to access the flash memory follow. The post also shows
how to connect the module to I/O pins other than pins 2 and 3 used for the
hardware I²C bus. This can be done with a software I²C bus. Finally, we can
read the temperature of the DS3231 temperature sensor.
Hopefully, the information in this post is valid for the latest versions of
Raspbian Buster. When preparing this post, I was mostly using the September 2019 version of
Buster but I did some tests against the June 2019 and February 2020 versions. A few days ago, a reader from Norway kindly wrote to warn me that my description of I²C "seems to work on version 4.19.97-v7, but not on 4.19.118-v7". I think the later is the first version of the operating system from the Raspberry Pi Foundation to be released under the
Raspberry Pi OS label, but it is still based on
Debian 10 and the 4.19
Linux kernel. Rather than trying to patch this text, I decided to write a
new version for the Raspberry Pi OS.
Table of content
- I²C on the Raspberry Pi
- Useful Software
- Using the Hardware Clock Connected to the Hardware I²C Bus
- Using the Flash Memory Connected to the Hardware I²C Bus
- Using the Hardware Clock Connected to a Software I²C Bus
- Using the Flash Memory Connected to the Software I²C Bus
- Multiples I²C Buses
- The Second Harware I²C Bus
- Reading the DS3231 Temperature Sensor
- RTC/EEPROM Module Backup Power
I²C (Inter-Integrated Circuit or TWI - Two Wire Interface) is a serial
communication protocol frequently used to connect many devices such as
clocks, displays, EEPROM memories, and sensors to a micro-controller. The
communication, which is not very fast, is done using two signals and a
connection to ground.
- SDA - Serial Data Line
- SCL - Serial Clock Line
All Raspberry Pi models have a hardware I²C bus on pins 3 (SDA) and 5 (SCL) of GPIO connector which has 26 or 40 pins depending on the model. However, the bus is not enabled by default and until it is activated pins 3 and 5 are general I/O pins. If the GPIO connector of the Raspberry Pi has 40 pins, there is a second I²C hardware bus which is assigned to the identification of the extension cards (so called HATs) using pins 27 (ID_SD) and 28 (ID_SC). Unfortunately, use of this bus is not recommended even in the absence of a HAT. However, additional software I²C buses can be created by adding kernel modules.
While several devices can be connected to the I²C bus simultaneously,
only two devices can exchange data at any given time. The device that
initiates the connection is the master, the recipient is the slave. There can
be more than one master on the bus, but data exchange between masters is
impossible, as well as between slaves. In addition, a slave cannot initiate
communication with a master. See Understanding
the I²C Bus, Texas Instruments Application Report SLVA704, p. 3. by
Jonathan Valdez and Jared Becker (juin 2015).
If the GPIO connector of the Raspberry Pi has 40 pins, there is a second
I²C hardware bus which is assigned to the identification of the extension
cards (so called HATs) using pins 27 (ID_SD) and 28 (ID_SC). Unfortunately,
it is not possible to use this bus even in the absence of a HAT.
As one would expect in Linux, an I²C bus is
represented by a file in the device directory /dev
. As an
example, there are three I²C buses activated on an Orange Pi PC 2.
opipc@orangepipc2:~$ ls -l /dev/i2*
crw-rw---- 1 root i2c 89, 0 Feb 16 04:02 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1 Feb 16 04:02 /dev/i2c-1
crw-rw---- 1 root i2c 89, 2 Feb 16 04:02 /dev/i2c-2
Here is the list of I²C devices on a Raspberry Pi 3 B whose hardware I²C
bus has been enabled.
woopi@goldserver:~ $ ls -l /dev/i2c*
crw-rw---- 1 root i2c 89, 1 Feb 10 22:17 /dev/i2c-1
As we can see the device i2c-0 (or is i2c-2 ?) that would be linked to the I²C
bus used to recognize the expansion cards is not created.
Three software utilities are used below. There are i2cdetect
and ic2get
which are contained in the package
i2c-tools
. The first displays the address of the devices
connected to an I²C bus. The second can read the registers of an I²C slave.
Installing the package i2c-tools
is very simple.
woopi@goldserver:~ $ sudo apt install -y i2c-tools
Installing the program eeprog
that can write to and read
from EEPROM is a little more complex. The utility must be compiled from the
source code. In addition, several versions of eeprog
are
available on the Web. The only ones that work are based on the "tear" fork of
eeprog
developed by Kris Rusocki among which the version by Ján Sáreník on
GitHub.
woopi@goldserver:~ $ wget https://github.com/jsarenik/eeprog/archive/master.zip
--2020-01-29 19:10:06-- https://github.com/jsarenik/eeprog/archive/master.zip
...
2020-01-29 19:10:07 (268 KB/s) - ‘master.zip’ saved [19445]
woopi@goldserver:~ $ unzip master.zip
...
woopi@goldserver:~ $ mv eeprog-master eeprog
woopi@goldserver:~ $ cd eeprog
woopi@goldserver:~/eeprog $ make
...
The problem with the original versions of eeprog
is that in
writing they use too high a frequency. It has to be slowed down. The I²C
frequency of the AT24C32 EEPROM depends on the voltage. It may be
possible to save data to the EEPROM if running at 5 volts using the original version of
eeprog
. The synchronization signal (SCL) of the EEPROM can reach
400 KHz. However, the memory is connected to 3.3 volts to be compatible
with Raspberry Pi GPIO that. The I²C operating frequency of the EEPROM decreases
rapidly when the voltage is reduced. I don't know the exact value of this
frequency at 3.3 volts, but at 2.7 volts the maximum frequency is reduced to
100 KHz.
Neither i2c-tools
nor eeprog
are needed for
normal operation of the clock and flash memory. We can therefore eliminate
everything later if desired. Here's how.
woopi@goldserver:~/some_dir/or_other $ cd ~
woopi@goldserver:~ $ rm eeprog-0.7.7_master.zip
woopi@goldserver:~ $ rm -r eeprog
woopi@goldserver:~ $ sudo apt purge i2c-tools -y
The connection of the module is easy since the connections are clearly labelled
on the board. At a minimum, it is necessary to connect four
pins from the latter to the corresponding pins of the Raspberry Pi GPIO
connector: the power and ground (VCC
and GND
) and the data and
synchronization signals (SDA
and SCL
) of the I²C bus.
At this point, I did not install a battery, for reasons explained later.

Initially, the I²C and the clock drivers can be
installed temporarily. A single command is sufficient to carry out these two
tasks. Then, it is a simple matter to check that the devices have been
created.
woopi@goldserver:~ $ sudo dtoverlay i2c-rtc ds3231
woopi@goldserver:~ $ ls -l /dev/i2c* /dev/rt*
crw-rw---- 1 root i2c 89, 1 Jan 29 02:57 /dev/i2c-1
lrwxrwxrwx 1 root root 4 Jan 29 02:57 /dev/rtc -> rtc0
crw------- 1 root root 253, 0 Jan 29 02:57 /dev/rtc0
The i2c-1
decice (also called an I²C controller) was
created, as well as the rtc0
device which communicates with the
clock via the i2c-1
controller. The command
i2cdetect
displays the addresses of the I²C devices connected to
the hardware bus.
woopi@goldserver:~ $ sudo 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: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
Two devices were found. The first is flash memory (EEPROM) at address
0x57 and the second is the clock at address 0x68. The UU
displayed instead of the address 68
is an indication that a
driver is handling the device.
woopi@goldserver:~ $ sudo hwclock -v
hwclock from util-linux 2.33.1
System Time: 1580275162.357510
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1580060171 seconds after 1969
Last calibration done at 1580060171 seconds after 1969
Hardware clock is on UTC time
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/rtc0 to change
...got clock tick
Time read from Hardware Clock: 2020/01/29 05:19:23
Hw clock time : 2020/01/29 05:19:23 = 1580275163 seconds since 1969
Time since last adjustment is 214992 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2020-01-29 01:19:22.840443-04:00
Clearly the hardware clock is working. It may be surprising to see that
the time is correct in the absence of a battery. The explanation is simple.
The operating system, or more precisely the component
systemd-timesync
, obtains the current time from an SNTP
reference server on the Web when the Raspberry Pi starts. As soon as the
i2c-rtc
module is installed, the system adjusts the hardware
clock.
Since everything works, i2c-rtc
can be installed permanently
by adding the dtoverlay
command used temporarly above in the
operating system configuration file.
woopi@goldserver:~ $ sudo nano /boot/config.txt
...
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# For access to I2C RTC and other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3)
dtoverlay=i2c-rtc,ds3231
...
It is not necessary to activate the I²C protocol with the raspi-config
utility. Previously, I said that we also had to modify the script that
adjusts the time of the hardware clock when the i2c-rtc
module is
loaded. Here's how.
woopi@goldserver:~ $ sudo nano /lib/udev/hwclock-set
Normally the script does nothing, because its execution is stopped by the
initial test, at least in distributions using systemd
including
Raspbian. It is necessary to remove this test or to
disable it by adding leading "#" at the start of the lines which transform
them into comments.
#!/bin/sh
# Reset the System Clock to UTC if the hardware clock from which it
# was copied by the kernel was in localtime.
dev=$1
#if [ -e /run/systemd/system ] ; then
# exit 0
#fi
...
If you installed the clock as described in the previous section, you can immediately check that it is possible to write and read the AT24C32 EEPROM . Otherwise, the I²C bus is not yet enabled.
woopi@goldserver:~ $ sudo i2cdetect -l
woopi@goldserver:~ $ ls /dev/i2*
ls: cannot access '/dev/i2*': No such file or directory
The temporary installation of the i2c1
module that implements the hardware I²C bus on GPIO pins 2 and 3 is very simple.
woopi@goldserver:~ $ sudo dtoverlay i2c1
woopi@goldserver:~ $ ls -l /dev/i2c*
crw-rw---- 1 root i2c 89, 1 Jan 29 02:57 /dev/i2c-1
If the addresses of the I²C devices connected to bus 1 are displayed when the bus is controlled by i2c1
, at least two are observed.
woopi@goldserver:~ $ sudo 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: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Address 0x57
is used by the AT24C32 EEPROM (in reality it is a default address that can be modified with some soldering). Address 0x68
is that of the hardware clock. Because only the I²C bus is activated and because there is no driver for the clock, i2detect
shows the latter's address, 0x68
and not UU
as in the previous section or below.
If the i2c-rtc
module was installed rather than i2c1
, then i2cdetect
displays UU
instead of 0x68
indicating that the clock driver is loaded.
woopi@goldserver:~ $ sudo 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: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Since the I²C bus is enabled and the address of the EEPROM is known, one can write a string in the memory and then read it to make sure that access is possible.
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-1 0x57 -r 0:29 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit
Operation: read 29 bytes from offset 0, Output file: <stdout>
Reading 29 bytes from 0x0
Lorem ipsum dolor si...
woopi@goldserver:~ $ echo "This is working!" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-1 0x57
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit
Operation: write at offset 0, Input file: <stdin>
Write cycle time: 2 milliseconds
Writing <stdin> starting at address 0x0
.................
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-1 0x57 -r 0:18 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit
Operation: read 18 bytes from offset 0, Output file: <stdout>
Reading 18 bytes from 0x0
This is working!
Older Rapsberry Pi models have only one readily available I²C hardware bus; the exceptions are the Pi model 4 and the Compute module. If GPIO pin 2 or 3 is used for other purposes, a software I²C bus can be created with the module i2c-rtc-gpio
to which the RTC can be connected using different GPIO pins.
woopi@goldserver:~ $ sudo dtoverlay -h i2c-rtc-gpio
Name: i2c-rtc-gpio
Info: Adds support for a number of I2C Real Time Clock devices
using the software i2c controller
Usage: dtoverlay=i2c-rtc-gpio,<param>=<val>
Params: abx80x Select one of the ABx80x family:
AB0801, AB0803, AB0804, AB0805,
AB1801, AB1803, AB1804, AB1805
ds1307 Select the DS1307 device
ds1339 Select the DS1339 device
ds3231 Select the DS3231 device
m41t62 Select the M41T62 device
mcp7940x Select the MCP7940x device
mcp7941x Select the MCP7941x device
pcf2127 Select the PCF2127 device
pcf2129 Select the PCF2129 device
pcf8523 Select the PCF8523 device
pcf8563 Select the PCF8563 device
rv3028 Select the Micro Crystal RV3028 device
addr Sets the address for the RTC. Note that the
device must be configured to use the specified
address.
trickle-diode-type Diode type for trickle charge - "standard" or
"schottky" (ABx80x only)
trickle-resistor-ohms Resistor value for trickle charge (DS1339,
ABx80x, RV3028)
wakeup-source Specify that the RTC can be used as a wakeup
source
backup-switchover-mode Backup power supply switch mode. Must be 0 for
off or 1 for Vdd < VBackup (RV3028 only)
i2c_gpio_sda GPIO used for I2C data (default "23")
i2c_gpio_scl GPIO used for I2C clock (default "24")
i2c_gpio_delay_us Clock delay in microseconds
(default "2" = ~100kHz)
As you can see, GPIO23 and GPIO24 will be used for the SDA and SCL signals respectively. If the i2c-rtc
module had been added to the configuration file /boot/config.txt
, it must be removed and the Pi must be restarted. If the module had been temporarily loaded, it can be removed with dtoverlay
. As soon as you know there is no more device for the clock, you can install i2c-rtc-gpio
.
woopi@goldserver:~ $ sudo dtoverlay -l
Overlays (in load order):
0: i2c-rtc ds3231=true
woopi@goldserver:~ $ sudo dtoverlay -r 0
woopi@goldserver:~ $ ls /dev/rtc
ls: cannot access '/dev/rtc': No such file or directory
woopi@goldserver:~ $ sudo dtoverlay i2c-rtc-gpio ds3231
Message from syslogd@goldserver at Jan 30 14:18:16 ...
kernel:[45446.974763] Internal error: Oops - BUG: 0 [#1] SMP ARM
Message from syslogd@goldserver at Jan 30 14:18:16 ...
kernel:[45447.002358] Process dtoverlay (pid: 3690, stack limit = 0xb07f204f)
...
Message from syslogd@goldserver at Jan 30 14:18:16 ...
kernel:[45447.108343] Code: 1a000003 e5932004 e3120001 1a000000 (e7f001f2)
Segmentation fault
That clearly does not work. Indeed, I never managed to install the device tree module at run-time, but it does work if the system configuration file is modified.
woopi@goldserver:~ $ sudo nano /boot/config.txt
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
...
# for access to I2C RTC and other I2C devices on software I2C bus (SDA on GPIO23, SCL on GPIO24 by default)
dtoverlay=i2c-rtc-gpio,ds3231
...
After a reboot, the software I²C bus and the clock device are installed correctly.
woopi@goldserver:~ $ sudo i2cdetect -l
i2c-3 i2c i2c-gpio-rtc@0 I2C adapter
woopi@goldserver:~ $ sudo i2cdetect -y 3
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
woopi@goldserver:~ $ sudo hwclock -v
hwclock from util-linux 2.33.1
System Time: 1580409344.320549
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1580060171 seconds after 1969
Last calibration done at 1580060171 seconds after 1969
Hardware clock is on UTC time
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/rtc0 to change
...got clock tick
Time read from Hardware Clock: 2020/01/30 18:35:45
Hw clock time : 2020/01/30 18:35:45 = 1580409345 seconds since 1969
Time since last adjustment is 349174 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2020-01-30 14:35:44.845273-04:00
If the i2c-rtc-gpio
module has been installed as explained in the previous section, then you can communicate with flash memory at address 0x57 on device i2c-3
. If there is the flash memory is used without a hardware clock, then add the i2c-gpio
module.
woopi@goldserver:~ $ dtoverlay -h i2c-gpio
Name: i2c-gpio
Info: Adds support for software i2c controller on gpio pins
Usage: dtoverlay=i2c-gpio,<param>=<val>
Params: i2c_gpio_sda GPIO used for I2C data (default "23")
i2c_gpio_scl GPIO used for I2C clock (default "24")
i2c_gpio_delay_us Clock delay in microseconds
(default "2" = ~100kHz)
bus Set to a unique, non-zero value if wanting
multiple i2c-gpio busses. If set, will be used
as the preferred bus number (/dev/i2c-<n>). If
not set, the default value is 0, but the bus
number will be dynamically assigned - probably
3.
The module can be installed directly in this case and obviously, the i2c-rtc-gpio
module not be loaded.
woopi@goldserver:~ $ sudo dtoverlay i2c-gpio
woopi@goldserver:~ $ sudo i2cdetect -l
i2c-3 i2c ffffffff.i2c I2C adapter
woopi@goldserver:~ $ sudo i2cdetect -y 3
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
The 0x68 address will not be shown if there is no I²C clock. The EEPROM can be accessed as before but the I²C bus must be adjusted; it is now i2c-3
.
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-3 0x57 -r 0:29 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit
Operation: read 29 bytes from offset 0, Output file: <stdout>
Reading 29 bytes from 0x0
Lorem ipsum dolor si...
woopi@goldserver:~ $ echo "* A new EEPROM *" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-3 0x57
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit
Operation: write at offset 0, Input file: <stdin>
Write cycle time: 2 milliseconds
Writing <stdin> starting at address 0x0
.................
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-3 0x57 -r 0:18 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit
Operation: read 18 bytes from offset 0, Output file: <stdout>
Reading 18 bytes from 0x0
* A new EEPROM *
It is possible to have more than one I²C bus enabled. Here is the relevant part of the /boot/config.txt
file that creates the hardware bus and a software bus.
...
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# For access to I2C RTCand other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3)
dtoverlay=i2c-rtc,ds3231
# For access to I2C devices other than RTC on software i2c bus (SDA on GPIO23, SCL on GPIO24 by default)
dtoverlay=i2c-gpio
...

woopi@goldserver:~ $ ls /dev/i2c*
/dev/i2c-1 /dev/i2c-3
woopi@goldserver:~ $ sudo i2cdetect -l
i2c-3 i2c ffffffff.i2c I2C adapter
i2c-1 i2c bcm2835 I2C adapter I2C adapter
woopi@goldserver:~ $ sudo 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: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
woopi@goldserver:~ $ sudo i2cdetect -y 3
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
woopi@goldserver:~ $ sudo hwclock -v
hwclock from util-linux 2.33.1
System Time: 1580420342.707524
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1580060171 seconds after 1969
Last calibration done at 1580060171 seconds after 1969
Hardware clock is on UTC time
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/rtc0 to change
...got clock tick
Time read from Hardware Clock: 2020/01/30 21:39:04
Hw clock time : 2020/01/30 21:39:04 = 1580420344 seconds since 1969
Time since last adjustment is 360173 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2020-01-30 17:39:03.151299-04:00
woopi@goldserver:~ $ echo "Hardware I2C bus" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-1 0x57
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit
Operation: write at offset 0, Input file: <stdin>
Write cycle time: 2 milliseconds
Writing <stdin> starting at address 0x0
.................
woopi@goldserver:~ $ echo "Software I2C bus" | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-3 0x57
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit
Operation: write at offset 0, Input file: <stdin>
Write cycle time: 2 milliseconds
Writing <stdin> starting at address 0x0
.................
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-1 0x57 -r 0:18 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-1, Address: 0x57, Mode: 16bit
Operation: read 18 bytes from offset 0, Output file: <stdout>
Reading 18 bytes from 0x0
Hardware I2C bus
4woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-3 0x57 -r 0:18 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-3, Address: 0x57, Mode: 16bit
Operation: read 18 bytes from offset 0, Output file: <stdout>
Reading 18 bytes from 0x0
Software I2C bus
Contrary to comments read on the forums, there does not seem to be any constraints on the I²C bus number or on the bus creation sequence.
...
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
dtoverlay=i2c-gpio,bus=6,i2c_gpio_sda=27,i2c_gpio_scl=22
# For access to I2C RTCand other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3)
dtoverlay=i2c-rtc,ds3231
# For access to I2C devices other than RTC on software i2c bus (SDA on GPIO23, SCL on GPIO24 by defa$
dtoverlay=i2c-gpio
...
woopi@goldserver:~ $ sudo i2cdetect -l
i2c-3 i2c ffffffff.i2c I2C adapter
i2c-1 i2c bcm2835 I2C adapter I2C adapter
i2c-6 i2c 6.i2c I2C adapter
...
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
# For access to I2C devices other than RTC on software i2c bus (SDA on GPIO23, SCL on GPIO24 by default)
dtoverlay=i2c-gpio
# For access to I2C RTCand other I2C devices on hardware I2C bus (SDA on GPIO2, SCL on GPIO3)
dtoverlay=i2c-rtc,ds3231
dtoverlay=i2c-gpio,bus=9,i2c_gpio_sda=27,i2c_gpio_scl=22
woopi@goldserver:~ $ sudo i2cdetect -l
i2c-3 i2c ffffffff.i2c I2C adapter
i2c-1 i2c bcm2835 I2C adapter I2C adapter
i2c-9 i2c 9.i2c I2C adapter
The only constraint is that the bus number cannot be 0 or 2.
If the Raspberry Pi GPIO connector has 40 pins, there is a second hardware I²C bus which identifies expansion cards (HAT) using pins 27 (ID_SD) and 28 (ID_SC). In principle, this bus should not be used. There are many warnings about this. The Raspberry Foundation says it not once but twice in its instructions on designing expansion cards. In the paragraphs entitled GPIO Requirements and ID EEPROM there is the same passage:
Within the set of pins available on the GPIO header, ID_SC and ID_SD (GPIO0/SCL and GPIO1/SDA) are reserved for board detection / identification. The only allowed connections to the ID_ pins are an ID EEPROM plus 3.9K pull up resistors. Do not connect anything else to these pins!
The same warning is on the schematics of the various models. In a tutorial on the I²C protocol, Sparkfun adds "It's only there to talk to EEPROMs at addresses 0x50 during boot time. User access at runtime is problematic. If you want a general purpose I²C bus on the B +, you'll need to use I2C-1, on pins 3 and 5 of the 40-pin connector ”. However, the tutorial continues with the procedure for using the bus. It requires i2c_vc
module that can be loaded with the dtparam
utility. Before installing it, let's see the information that the utility displays about this module.
woopi@goldserver:~ $ sudo dtparam -h i2c_vc
i2c_vc Set to "on" to enable the i2c interface
usually reserved for the VideoCore processor
(default "off")
woopi@goldserver:~ $ sudo dtparam i2c_vc=on
woopi@goldserver:~ $ ls /dev/i2*
/dev/i2c-0
Since the device is in place, I took the chance to connect the clock module with flash memory to pins 27 (SDA) and 28 (SCL) of the second I²C bus (and also to ground and to 3.3 volts of course) taking care to turn off the power before proceeding. After that it was easy to verify that it was possible to use flash memory.
woopi@goldserver:~ $ sudo i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-0 0x57 -r 0:29 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-0, Address: 0x57, Mode: 16bit
Operation: read 29 bytes from offset 0, Output file: <stdout>
Reading 29 bytes from 0x0
Lorem ipsum dolor si...
woopi@goldserver:~ $ echo "eeprom on i2c-0 " | eeprog/eeprog -f -16 -w 0x00 -t 2 /dev/i2c-0 0x57
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-0, Address: 0x57, Mode: 16bit
Operation: write at offset 0, Input file: <stdin>
Write cycle time: 2 milliseconds
Writing <stdin> starting at address 0x0
.................
woopi@goldserver:~ $ eeprog/eeprog -16 /dev/i2c-0 0x57 -r 0:18 -f
eeprog 0.7.7-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
Bus: /dev/i2c-0, Address: 0x57, Mode: 16bit
Operation: read 18 bytes from offset 0, Output file: <stdout>
Reading 18 bytes from 0x0
eeprom on i2c-0
There does not seem to be a module that supports the clock with this I²C bus. However, I was able to verify that it was possible to access the DS3231 chip with a Python script which is described in more detail in another post.
woopi@goldserver:~ $ ve rtcpy
(rtcpy) woopi@goldserver:~ $ ./rtc -i 0
-bash: ./rtc: No such file or directory
(rtcpy) woopi@goldserver:~ $ rtcpy/rtc -i 0
Sat Feb 22 20:53:42 2020
(rtcpy) woopi@goldserver:~ $ rtcpy/rtc -i 0 -u -s "2138-12-09 12:13:14"
(rtcpy) woopi@goldserver:~ $ rtcpy/rtc -i 0
Tue Dec 9 12:13:27 2138
To install a controler for this hardware I²C bus permanently, add a line in the configuration file.
woopi@goldserver:~ $ sudo nano /boot/config.txt
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
dtparam=i2c_vc=on
I have not tested the use of this bus with the other hardware I²C bus or other software buses, but I think it should work. That said, it is definitely not recommended and may not even be possible to use the i2c0
controller. As indicated at the end of the general help command of the dtparam
utility, there could be a conflict with the Pi camera.
woopi@goldserver:~ $ sudo dtparam -h
...
N.B. It is recommended to only enable those interfaces that are needed.
Leaving all interfaces enabled can lead to unwanted behaviour (i2c_vc
interfering with Pi Camera, I2S and SPI hogging GPIO pins, etc.)
Similarly, it is very likely that there would be a conflict with any I²C device connected to this bus if it uses address 0x50.
To ensure accuracy, the DS3231 chip protects against variations caused by temperature changes. Therefore, it incorporates a temperature sensor which can be accessed. The temperature of the chip is in registers 0x11 and 0x12 which can be read with the i2cget
utility .
woopi@goldserver:~ $ sudo i2cget -y 1 0x68 0x11
Error: Could not open file `/dev/i2c-1' or `/dev/i2c/1': No such file or directory
woopi@goldserver:~ $ i2cget -y 1 0x68 0x11
Error: Could not set address to 0x68: Device or resource busy
The problem is that the rtc0
device which owns ic2-1
. The device module is named rtc_ds1307
.
woopi@goldserver:~ $ lsmod | grep rtc
rtc_ds1307 24576 0
hwmon 16384 2 rtc_ds1307,raspberrypi_hwmon
Removing that module will give access to the DS3231 through I²C bus.
woopi@goldserver:~ $ sudo rmmod rtc_ds1307
woopi@goldserver:~ $ sudo i2cget -y 1 0x68 0x11
0x14
woopi@goldserver:~ $ sudo i2cget -y 1 0x68 0x12
0x40
Register 0x11 contains the integer part of the temperature in degrees Celsius, while the two most significant bits of register 0x12 contain the fractional part of the temperature in quarter degrees Celsius. Now 0x40 = 01000000 of which the two most significant bits are 01. So the temperature is 20 + 1 * (1/4) = 20.25 °C which was reasonable.
The rtc_ds1307
module can be reinstalled and the clock will work again.
woopi@goldserver:~ $ sudo modprobe rtc_ds1307
woopi@goldserver:~ $ sudo hwclock -v
hwclock from util-linux 2.33.1
System Time: 1580085041.982210
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 1580060171 seconds after 1969
Last calibration done at 1580060171 seconds after 1969
Hardware clock is on UTC time
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/rtc0 to change
...got clock tick
Time read from Hardware Clock: 2020/01/27 00:30:43
Hw clock time : 2020/01/27 00:30:43 = 1580085043 seconds since 1969
Time since last adjustment is 24872 seconds
Calculated Hardware Clock drift is 0.000000 seconds
2020-01-26 20:30:42.444318-04:00
The module includes support for a button battery cell whose function is to keep the clock running when there's no power. There is a rather basic circuit to constantly charge the battery when power is supplied to the module. Initially the rechargeable LIR2032 was supplied with these modules. Unsurprisingly, the modules I got from two vendors lately didn't have batteries included. The new regulations regarding the transportation of lithium-ion batteries are much more severe so that sellers avoid shipping them.

There is an Arduino Forum discussion about the backup battery which begins in November 2014 and which remains active. Let me sum up this long debate.
- The LIR2032 is a rechargeable battery with a nominal voltage of 3.6 / 3.7 volts which must be charged at 4.2 volts.
- Some believe that the voltage will be too high if 5 volts supply the module. Others do clever calculations to conclude that the effective voltage after the diode and the resistor is close to 4.2 volts.
- There is no consensus on the true charging voltage when attempts are made to measure it.
- Some believe that the charging circuit will do nothing if the module is powered at 3.3 volts
- A Li-ion battery at its maximum admissible voltage (4.2 volts for the LIR2032) must not be charged. "It is important to note that Li-Ion cells will not tolerate trickle charging at all after they arefully charged. If current is continuously forced into a fully-charged Li-Ion cell (even a very minute current) the cell will be damaged. For this reason, Li-Ion cells are charged using constant-voltage (CV) chargers, and not constant-current (CC) chargers". (Texas Instruments Characteristics of Rechargeable Batteries).
For these reasons, at least one dealer removes the 200 ohm resistor to deactivate the circuit and recommends the use of a non-rechargeable CR2032 lithium battery. Since it is difficult to find the LIR2032 locally at a reasonable price and since I highly doubt the efficacy of the circuit to charge the battery when the module is supplied at 3.3 volts, I followed the dealer lead with the modules in my possession.