DS1307 Real-Time Clock (RTC) Driver in Rust

DS1307 RTC module

After writing the 24x Serial EEPROM IC driver I have written a driver for the DS1307 real-time clock as part of the Weekly Driver Initiative. This platform-agnostic driver is based on embedded-hal.

Modules containing this IC often come often together with a button battery holder like in the picture above and an AT24C32 EEPROM (Electrically Erasable and Programmable Read-Only Memory) IC. Please refer to the 24x Serial EEPROM IC driver to use that IC.

I wrote this driver following Test-Driven-Development using the embedded-hal-mock crate which was very helpful.

The device

The DS1307 serial real-time clock (RTC) is a low-power, full binary-coded decimal (BCD) clock/calendar plus 56 bytes of NV SRAM. Address and data are transferred serially through an I²C, bidirectional bus.

The clock/calendar provides seconds, minutes, hours, day, date, month, and year information. The end of the month date is automatically adjusted for months with fewer than 31 days, including corrections for leap year. The clock operates in either the 24-hour or 12-hour format with AM/PM indicator.

The DS1307 has a built-in power-sense circuit that detects power failures and automatically switches to the backup supply. Timekeeping operation continues while the part operates from the backup supply.

Datasheet: DS1307

In this blog post I will use a module similar to the one in the picute. You can buy the device on AliExpress or eBay for a few cents.

The driver

This driver allows you to:

  • Read and set date and time in 12-hour and 24-hour format. See: get_datetime
  • Enable and disable the real-time clock. See: set_running
  • Read and write user RAM. See: read_ram
  • Control square-wave output. See: enable_square_wave_output

Using the driver

To use the device from Rust, you have to add the ds1307 crate to your project as well as a concrete implementation of the embedded-hal traits. For example if you are using the Raspberry Pi running Linux, you can use linux-embedded-hal.

1
2
3
4
5
# Cargo.toml
...
[dependencies]
ds1307 = "0.2"
linux-embedded-hal = "0.1"

This is an example program which will set the date and time and then read it back:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
extern crate linux_embedded_hal as hal;
extern crate ds1307;

use hal::I2cdev;
use ds1307::{DS1307, DateTime, Hours};

fn main() {
let dev = I2cdev::new("/dev/i2c-1").unwrap();
let mut rtc = DS1307::new(dev);
let datetime = DateTime {
year: 2018,
month: 08,
day: 15,
weekday: 4,
hour: Hours::H24(19),
minute: 59,
second: 58
};
rtc.set_datetime(&datetime).unwrap();

let datetime = rtc.get_datetime().unwrap();

// The hours depend on the RTC running mode.
match datetime.hour {
Hours::H24(h) => println!("{}-{}-{}, {} {}:{}:{}", datetime.year,
datetime.month, datetime.day,
datetime.weekday,
h, datetime.minute, datetime.second),
Hours::AM(h) => println!("{}-{}-{}, {} {}:{}:{} AM", datetime.year,
datetime.month, datetime.day,
datetime.weekday,
h, datetime.minute, datetime.second),
Hours::PM(h) => println!("{}-{}-{}, {} {}:{}:{} PM", datetime.year,
datetime.month, datetime.day,
datetime.weekday,
h, datetime.minute, datetime.second),
}
// This will print something like: 2018-08-15, 4 19:59:58
}

This example is also available in the crate sources here.

The driver also allows individual access to the year, month, day, etc. through functions like:
set_year(), get_year() and so on.

Where to go from here?

There is much more information and example programs in the crate documentation.
Please give this driver a try and report any issues you may encounter in the issue tracker.
Feedback, suggestions and improvements are gladly welcome.

What’s next?

I have a WIP driver for the popular I/O expanders PCF8574, PCF8574A and PCF8575 and another WIP one for the TCA9548A and PCA9548A I2C switches/multiplexers. I will announce them here soon.

Thanks for reading and stay tuned!

Links:

Share