# ds3231 Maxim DS3231 RTC driver on [libavr](https://git.blackmark.me/avr/libavr): clock and alarm read/write, alarm interrupts, oscillator-stop detection, die temperature. One source runs on every libavr chip — TWI hardware on the mega328P, open-drain software I2C on the tinies. All bus errors surface as `std::expected`. ```cpp using bus = dev::i2c<{.frequency = 100_kHz}>; using rtc = ds3231::device; auto now = rtc::read_clock(); // result auto armed = rtc::set_alarm1({}, ds3231::alarm1_rate::once_per_second); ``` `example/main.cpp` is a complete program. libavr rides as the `libavr/` submodule, pinned to the commit this driver builds against; `LIBAVR_ROOT` (cache or environment) overrides it for development against a working tree: ```sh git submodule update --init libavr cmake --preset attiny85-generated cmake --build --preset attiny85-generated ``` Presets cover attiny85/atmega328p in both libavr modes (generated and reflect); `ctest` runs the consteval battery over the BCD, the hours register's two formats, the weekday, the alarm registers each rate writes and the control and status write-backs, and holds the example to its stated size — **1468 B** on the mega328P and **1256 B** on the tiny85, byte-identical across the two modes. The legacy yazoalfa-based driver lives on the `master` branch. The weekday register is derived from the date by default. A program that assigns its own meaning to the device's 1..7 takes ownership of it, and no write here touches it: ```cpp using rtc = ds3231::device; ``` An alarm arms its INT/SQW output unless told otherwise, and can be muted and re-wired without re-arming: ```cpp auto quiet = rtc::set_alarm2(at, ds3231::alarm2_rate::minutes_match, ds3231::alarm_interrupt::off); auto again = rtc::listen_alarm2(); ``` ## Atmel Studio `master` carries a Studio solution, so this branch does too: `ide/ds3231.atsln` builds `example/main.cpp` for both parts the presets cover, each to a **byte-identical `.text`** against the CMake build (`check-flags.py` below is what holds the flag sets equal, so the sizes are the presets' own), with the flags mirrored by hand. CMake remains the build system. `avrdevice` is a project-level property in Studio, so a part means a project, not a configuration: `ide/atmega328p/` and `ide/attiny85/`. They need separate directories rather than separate names — Studio builds into `/` whatever `OutputDirectory` says, so two projects sharing one directory would also share one `example/main.o`, and building one after the other without a rebuild would link the other part's object. Studio finds libavr in the **submodule** at `$(MSBuildProjectDirectory)\..\..\libavr\include` — correct by construction, and anchored to the project because a plain relative path is resolved against the generated makefile's directory (the configuration's output directory), not the project's. There is no `LIBAVR_ROOT` escape hatch: a variable exported in a shell is invisible to Studio launched from the Start menu — which is what the submodule answers. It also needs a GCC 16.1 toolchain registered as flavour `avr-g++-16.1.0`, nothing older reaching `-std=c++26`. One generated file is required before the project will load, and one command checks the flags have not drifted (both from libavr's `tools/atmelstudio/`): ```sh for mcu in atmega328p attiny85; do case $mcu in atmega328p) device=ATmega328P;; attiny85) device=ATtiny85;; esac python libavr/tools/atmelstudio/componentinfo.py \ "ide/$mcu/ds3231-$mcu.componentinfo.xml" --device "$device" python libavr/tools/atmelstudio/check-flags.py --solution ide/ds3231.atsln \ --project "ds3231-$mcu" \ --compile-commands "build/$mcu-generated/compile_commands.json" \ --log "build/as-$mcu.log" done ``` One reference describes one part, hence `--project`. Release is what the gate compares, the presets defining no debug build; Debug carries the `-Og -gdwarf-4` pair libavr's own debug preset uses. Differences from legacy: weekday-rate alarms set the DY bit (the legacy driver always cleared it), each register block is read or written in one coherent bus transaction, and errors are reported instead of ignored.