Raspberry Pi PCF8563 Real Time Clock (RTC)

Having recently received my Raspberry Pi, one of the first things I wanted to do was hook up a real-time clock chip I had lying around (a NXP PCF8563) and learn how to drive I2C from the BCM2835 hardware registers. Turns out it’s quite easy to do, and I think makes a useful project to learn with.

So, here are some notes I made getting it to work, initially with Chris Boot’s forked kernel that incorporates some I2C handling code created by Frank Buss into the kernel’s I2C bus driver framework.

After getting it to work with the kernel drivers, I created some C code to drive the RTC chip directly using the BCM2835 I2C registers, using mmap() to expose Peripheral IO space in the user’s (virtual) memory map, the technique I learned from Gert’s Gertboard demo software, though my code’s simpler (hopefully without limiting functionality!).

Note: Revision 2 boards require the code to access BSC1 (I2C1) rather than BSC0 (I2C0), so changes to the peripheral base address may be required, or in the case if the Linux I2C driver, a reference to i2c-1 rather than i2c-0. It should be simple enough, but I don’t want to write about things I haven’t done or tested, so a bit of extra work by the reader may be required.

The Circuit

The PCF8563 datasheet’s reference schematic is all I used for the Raspi’s clock, though for the crystal I ditched the the trimmer capacitor from the datasheet’s schematic and used two 10pF caps as per datasheet – good enough for the stability that I’m likely to need.

This translates to the following circuit on a breadboard. The large double-layer capacitor can be found easily at Maplin or Farnell, a 1F 5.5V, and while physically quite a bit larger than a CR2032 (or similar) battery, it should give months of power between charges. An electrolytic capacitor would also work for testing, but use a 150-300 ohm resistor in series to limit the current draw when charging, or your Raspi will likely reboot (since we’re only allowed to draw 50mA from the 3V3 pin).

The four wires hooked up to the Raspberry Pi’s expansion header are simply 3V3, GND, I2C0_SCL and I2C0_SDA (pins P1-01, P1-06, P1-05 and P1-03 respectively based on the Wiki reference).

Take care when wiring up the expansion header, since it’s easy to make mistakes when translating pins from diagram to board. It’s always worth at least checking voltage as reference points (e.g. measure +3.3V across what you think are pins 3V3 and GND) to make sure you’re not top to bottom on your translation, for example, before plugging up.

The circuit is so simple that it could just be wired together onto a 26-pin header connector, given a little care and forethought, and perhaps a bit of epoxy putty or similar to fix it all together.

The Kernel Driver

Next I had to think about software – it turned out that between Chris Boot and Frank Buss, there was already a kernel with support for the Raspi’s I2C bus in a way that the existing pcf8563 driver can use.

When running Chris’s kernel, the above commands are all that are required to get the PCF8563 working with the hwclock command. The value 0x51 above is the hardwired I2C device address of the RTC chip.

And that’s it! Chris’s 3.2.18 kernel was screwing up my SD card access periodically (when it boots, it runs more or less flawlessly, but it often fails to boot) and ended up corrupting an otherwise good SD card image. I think this issue has been fixed since his 3.2.19 r3 build, but I haven’t tested it.

The C Code Alternative

My original intention had been to learn how to drive the Raspberry Pi’s IO Peripheral devices at a register level, so having seen that the circuit was wired and working using the kernel drivers, I went back to the Foundation’s official kernel, which has no inbuilt I2C support, to find out how to drive the chip in user-space.

After a quick attempt to access the IO peripheral space directly using pointers (ok, daft to even try, but you never know…), I had a look at the source code of Gert’s demo, which accesses GPIO among others, to see how it can be done.

Essentially, he accesses /dev/mem, which is a virtual file that makes available the physical address space (ARM Physical Addresses in the BCM2835 datasheet), via a chunk of user-space memory that’s judiciously allocated using malloc(), and that’s mapped to /dev/mem using the mmap().

I simplified this by allowing the kernel supply me with the virtual address of the physical address space, on the basis that it will automatically allocate on a page boundary. All the BCM2835 peripherals I’ve looked at in the datasheet are based at a 4K boundary.

If you’re used to driving I2C from a microcontroller, either bit-banging (driving the SCL and SDA pins directly with software) or with an MCU peripheral (through hardware registers), then you may find that the BCM2835 hardware does a little more for you than you’re used to. In particular, you use hardware registers to define the I2C device-address and the number of data-bytes (e.g. BSC0_A & BSC0_DLEN), and the BCM2835 handles the writing of the address, the bytes, and the corresponding acknowledge bits for you automatically.

It also provides a 16 byte FIFO buffer. You fill the buffer and it writes what you put into it. If you’re reading from a device, it buffers it in the FIFO for you to read. There’s very little low level stuff to do other than check if the buffer’s full/empty, and read/write the FIFO accordingly. In the example below, I don’t even need to monitor the buffer’s status, since no transaction exceeds the FIFOs 16 bytes.

Below is the C source of my code used to drive the RTC directly from user-space using the BMC peripheral registers. It allows reading and displaying of the RTC chip time, setting the RTC from the system clock, and setting the system clock from the RTC. All times are handled as UTC. The code also configures GPIO pins 0 and 1 as ALT0 (SDA and SCL for BMC0), since they’re not routed to the I2C peripheral by default.

Everything is written for clarity rather than elegance, and it’s all in a single file for the same reason (it’s not a big program).

Post navigation

18 thoughts on “Raspberry Pi PCF8563 Real Time Clock (RTC)”

Fantastic
Thanks for contributing!!
Would it be possible to add gpio access routines and put the code in a shared library? Unfortunately my understanding of C is very limited. I am working on a class for High
School students and want to use free pascal / Lazarus to do some Hardware experiments and general programming.
Thanks!

I’m about to write up the results of driving a relay from the GPIO peripheral, so there will be more C code available shortly (specifically for GPIO), however the code I’ve written is intended to show what’s happening at a hardware (register) level, so wrapping it up in a library would maybe defeat that purpose. You might consider using the Shell Script example in http://elinux.org/RPi_Low-level_peripherals. This technique could be used to create a library in Pascal using nothing but file I/O.

in directory /sbin
#!/bin/sh
#
# Trivial script to load/save current contents of the kernel clock
# from an i2c RTC.
#
# This Version is made for Raspberry PI fake-hwclock replacement
#
# Tested on: Debian Wheezy with kernel 3.2.21-rp1+_5_armel.deb (2012-06-23)
# This kernel includes support for i2c and spi!
# --> www.bootc.net
#
# Using NTP is still recommended on these machines to get to real time sync
# once more of the system is up and running.
#
# Copyright 2012 Reiner Geiger
#
# License: GPLv2, see COPYING

Thanks for this! I had an old PCF8563 lying around and plugged it. After copy pasting & compiling the code I had it running in under 20 seconds. Very happy to have a working example of i2c with the pi. Thanks!

With this setup, is the RTC IC powered by the battery/capacitor the whole time, or just when the Raspberry Pi is off? It seems sensible to power the RTC chip from the GPIO header most of the time and only use the battery as backup; some rtc ics (eg. the DS1307) appear to have built in support for this mode of operation, but AFAICT the PCF8563 doesn’t. Is this correct?

The capacitor is always charging when power is on, which what we want, and the diode in series with 3V3 prevents it from discharging to the Raspberry Pi when power is off. For a battery, you’d need to have two diodes, one in series with 3V3 (3V3 -> diode -> Vin) and one in series with the battery (+ve -> diode -> Vin).

Modelling this with 3V3 and a 3V cell, the cell only drains around 1uA when the chip is active and drawing, say, 200uA from 3V3. When the chip is in low-power mode, the drain on the cell will be as per the datasheet (e.g. 500nA).

I don’t know anything about the DS1307, but I’ve not seen anything in the PCF8563 data-sheet to suggest there’s an on-chip way to isolate two independent supplies.

I can’t answer either question with any authority. I think that this can be done automatically in the udev/modprobe configuration, if you really don’t want to use rc.local or a modified startup script. I guess the reason it needs to be done at all is so that the RTC driver (rtc-pcf8563.ko) knows what bus the chip is connected to. Perhaps someone else could correct me or elaborate.

Thanks for sharing this. Note that the V2 boards have changed pins 3 & 5 from BSC0 to BSC1, so the peripheral address will be different for these and future boards. I’m working on a PIC based RTC that will emulate a PCF8563 for compatibility, part of the code changes will be to incorporate support for V2 boards (when I get one), so I’ll try to copy you in on updates.

I’ve only just discovered SDCC, but haven’t actually tried it yet – I’d like a system that enables me to compile code on an RPi and then to program the PIC in-situ.

Up until now, I’ve mostly used HiTech C – the free version is good enough and, as long as you don’t make too much use of the built in library functions (printf and scanf in particular), then the code is quite compact. I haven’t warmed to the Eclipse based IDEs for PIC stuff (though I use Eclipse almost exclusively for Java), so I’m still on MPLAB V8.x.