PCF8563/BM8563 Real-Time Clock Rust Driver (pcf8563-dd)
A no_std Rust driver for the NXP PCF8563 and compatible BM8563 real-time clock ICs. This driver leverages the device-driver crate with a declarative YAML manifest (device.yaml) for a robust, type-safe register map definition. The low-level API covers 100% of the PCF8563's registers, with device.yaml providing a comprehensive and accurate description of all registers and their fields verified against the official datasheet.
Overview
The pcf8563-dd driver offers:
- Declarative Configuration: The PCF8563 register map is defined in
device.yaml, enablingdevice-driverto generate a type-safe, low-level register access API. - Unified Async/Blocking API: Uses the
bisynccrate to provide both asynchronous (Pcf8563Async) and blocking (Pcf8563) drivers from the same codebase, with no feature flags required. - High-Level and Low-Level APIs:
- High-level methods simplify tasks like reading/setting date and time, configuring alarms, and managing the timer.
- Low-level API (via the
llfield) offers direct, type-safe access to all registers defined indevice.yaml.
no_stdandno-alloc: Optimized for bare-metal and RTOS environments.- Optional Logging: Supports
defmtand thelogfacade for debugging. - Optional
rtccTraits (blocking): Enable thertccfeature to getrtcc::DateTimeAccessandrtcc::Rtccimplementations for the blocking driver.
Features
- Date and Time: Read and set year (2000-2099), month, day, weekday, hours, minutes, and seconds.
- Clock Integrity Detection: Voltage-low (VL) flag indicates if clock data may be invalid due to power loss.
- Century Flag: Track century rollover for extended date range.
- Alarm Function: Programmable alarm with minute, hour, day, and weekday matching.
- Countdown Timer: 8-bit countdown timer with selectable clock frequencies (4096Hz, 64Hz, 1Hz, 1/60Hz).
- Clock Output (CLKOUT): Programmable square wave output (32.768kHz, 1024Hz, 32Hz, 1Hz).
- Interrupt Support: Configurable interrupts for alarm and timer events.
- Low Power: Designed for battery-backed operation.
Supported Devices
- PCF8563 - NXP real-time clock (original)
- BM8563 - Compatible clone found in M5Stack devices
Getting Started
-
Add
pcf8563-ddtoCargo.toml:[] = "0.2.0" # For blocking usage (Pcf8563): = "1.0.0" # For async usage (Pcf8563Async): = "1.0.0" -
Instantiate the driver with your I2C bus:
-
Blocking:
use ; let i2c_bus = /* your I2C bus */; let mut rtc = new; // Initialize the RTC rtc.init?; // Check if clock data is valid let valid = rtc.is_clock_valid?; // Set the date and time let dt = DateTime ; rtc.set_datetime?; // Read current date and time let current = rtc.get_datetime?; -
Async:
use ; let i2c_bus = /* your async I2C bus */; let mut rtc = new; // Initialize the RTC rtc.init.await?; // Read current date and time let current = rtc.get_datetime.await?;
-
High-Level API
Date and Time
// Get current date/time
let dt = rtc.get_datetime?;
// Set date/time
rtc.set_datetime?;
// Set only time (preserves date)
rtc.set_time?;
Clock Control
// Check clock validity (false if power was lost)
let valid = rtc.is_clock_valid?;
// Clear the voltage-low flag after setting time
rtc.clear_voltage_low_flag?;
// Stop/start the clock
rtc.set_clock_running?; // Stop
rtc.set_clock_running?; // Start
Alarm
use Alarm;
// Set alarm for 12:30 on any day
let alarm = Alarm ;
rtc.set_alarm?;
rtc.set_alarm_interrupt?;
// Check and clear alarm flag
if rtc.get_alarm_flag?
// Disable alarm
rtc.disable_alarm?;
Timer
use TimerFrequency;
// Configure 10-second countdown timer
rtc.set_timer_frequency?;
rtc.set_timer_value?;
rtc.set_timer_enabled?;
rtc.set_timer_interrupt?;
// Check timer status
let value = rtc.get_timer_value?;
if rtc.get_timer_flag?
Clock Output
use ClkoutFrequency;
// Enable 1Hz square wave output on CLKOUT pin
rtc.set_clkout_frequency?;
rtc.set_clkout_enabled?;
Low-Level API Usage
The driver provides direct access to all PCF8563 registers through the low-level API via rtc.ll. This API is automatically generated from device.yaml and provides type-safe access to all register fields.
Reading Registers
// Read control status registers
let ctrl1 = rtc.ll.control_status_1.read?;
let is_stopped = ctrl1.stop;
let ctrl2 = rtc.ll.control_status_2.read?;
let alarm_flag = ctrl2.af;
let timer_flag = ctrl2.tf;
// Read seconds register with voltage-low flag
let seconds = rtc.ll.seconds.read?;
let vl = seconds.vl; // Clock integrity flag
let sec_value = seconds.seconds_ten * 10 + seconds.seconds_unit;
Writing Registers
// Configure control status 2
rtc.ll.control_status_2.write?;
// Set timer value
rtc.ll.timer.write?;
Modifying Registers
Use .modify() to read-modify-write, preserving other fields:
// Enable timer without changing frequency
rtc.ll.timer_control.modify?;
Async Low-Level API
Append _async to method names for async usage:
let ctrl1 = rtc.ll.control_status_1.read_async.await?;
rtc.ll.timer_control.modify_async.await?;
Register Map
The complete PCF8563 register map is defined in device.yaml:
| Address | Register | Description |
|---|---|---|
| 0x00 | Control Status 1 | TEST1, STOP, TESTC flags |
| 0x01 | Control Status 2 | Interrupt enables and flags (TI_TP, AF, TF, AIE, TIE) |
| 0x02 | Seconds | VL flag, seconds (0-59) |
| 0x03 | Minutes | Minutes (0-59) |
| 0x04 | Hours | Hours (0-23) |
| 0x05 | Days | Day of month (1-31) |
| 0x06 | Weekdays | Day of week (0-6) |
| 0x07 | Century/Months | Century flag, month (1-12) |
| 0x08 | Years | Year (0-99) |
| 0x09 | Minute Alarm | AE_M flag, minute alarm value |
| 0x0A | Hour Alarm | AE_H flag, hour alarm value |
| 0x0B | Day Alarm | AE_D flag, day alarm value |
| 0x0C | Weekday Alarm | AE_W flag, weekday alarm value |
| 0x0D | CLKOUT Control | FE (enable), FD (frequency) |
| 0x0E | Timer Control | TE (enable), TD (frequency) |
| 0x0F | Timer | Countdown timer value (0-255) |
Examples
Examples for ESP32 using esp-hal are included. Both examples demonstrate high-level convenience methods and low-level register API usage.
- Async Example:
examples/test_pcf8563_async.rs - Blocking Example:
examples/test_pcf8563_blocking.rs
Feature Flags
default = []: No default features; async and blocking drivers are always available.std: Enablesstdfeatures forthiserror.log: Enableslogfacade logging.defmt: Enablesdefmtlogging for embedded debugging.rtcc: Implementsrtcc::DateTimeAccessandrtcc::Rtccfor the blocking driver.
Timer Frequencies
The countdown timer supports four clock frequencies:
| Frequency | Period | Max Duration |
|---|---|---|
| 4096 Hz | ~244 µs | ~62 ms |
| 64 Hz | ~15.6 ms | ~4 seconds |
| 1 Hz | 1 second | ~4.25 minutes |
| 1/60 Hz | 1 minute | ~4.25 hours |
CLKOUT Frequencies
The clock output pin can generate square waves at:
- 32.768 kHz (default)
- 1024 Hz
- 32 Hz
- 1 Hz
Contributing
Contributions are welcome! You can contribute by:
- Adding high-level convenience methods for additional features.
- Enhancing documentation with examples or clarifications.
- Reporting issues or suggesting improvements.
- Testing on different hardware platforms.
Please submit issues, fork the repository, and create pull requests.
License
This project is dual-licensed under the MIT License or Apache License 2.0, at your option.