BlackMark 50c424d3d2 deps: the pin advances to the identity check that reads its own sibling
libavr 93d8b0e. The check is handed the sibling build tree now and asks its build system whether the image is current, so a comparison against a tree the run did not build skips rather than passing. Gated at the pin. Its own gate builds both modes, so the comparison still happens.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 08:23:57 +02:00

ds3231

Maxim DS3231 RTC driver on 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.

using bus = dev::i2c<{.frequency = 100_kHz}>;
using rtc = ds3231::device<bus>;

auto now = rtc::read_clock();       // result<date_time>
auto armed = rtc::set_alarm1({}, ds3231::alarm1_rate::once_per_second);

example/main.cpp is the full tour. 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:

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 and the alarm rate encodings, and holds the example to its stated size — 1480 B on the mega328P and 1270 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:

using rtc = ds3231::device<bus, ds3231::weekday_source::external>;

An alarm arms its INT/SQW output unless told otherwise, and can be muted and re-wired without re-arming:

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 <project dir>/<Configuration> 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/):

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 now actually set the DY bit (the old setAlarmHelper always cleared it), reads/writes are single coherent bus transactions, and errors are reported instead of ignored.

Description
Zero overhead template library driver for DS3231 RTC module.
Readme 292 KiB
Languages
C++ 100%