Skip to content

fix(rtc): Bound RTIC monotonic spin to sync horizon, verify compare arming - #1012

Merged
jbeaurivage merged 1 commit into
atsamd-rs:masterfrom
QuartzShard:fix/rtc_monotonic_spin
Aug 9, 2026
Merged

fix(rtc): Bound RTIC monotonic spin to sync horizon, verify compare arming#1012
jbeaurivage merged 1 commit into
atsamd-rs:masterfrom
QuartzShard:fix/rtc_monotonic_spin

Conversation

@QuartzShard

Copy link
Copy Markdown
Contributor

Summary

The RTC interrupt handler currently spins on count < compare, to ensure that a stale count read does not reach the on_monotonic_interrupt fn.

This is fine during normal operation, but when the handler arms a compare only a few ticks ahead of the counter the match can fire after the handler has already moved CC0 on to the next queued deadline. The re-pended handler then observes a flag raised by an already-serviced compare alongside a CC0 holding an arbitrarily distant target, and spins until COUNT reaches it. Since RTIC places the RTC vector at the same priority as the highest-priority async task, everything at or below that priority is frozen for the duration.

I ran into this causing intermittent issues with my serial comms, specifically under high load, due to the timer getting stuck spinning for longer than my comms timeout.

This commit adds a check that the compare lies within the sync horizon of the current count before spinning, so that if the compare value has been overwritten in a way that would cause a long spin, it will instead be skipped - eliminating the stall. It also replaces MIN_COMPARE_TICKS with a new unified SYNC_SLACK_TICKS based on the worst-case read latency detailed in the datasheet.

set_compare now also re-reads COUNT after the synced write and re-pends the handler if the armed value may already have been passed - an equality match armed in the past otherwise never fires, wedging the queue until counter wrap.

Some RTT logs captured with my reproduction:
post_fix_no_stalls.txt
baseline_stalls.txt
baseline_lost_wake.txt

Checklist

  • All new or modified code is well documented, especially public items
  • No new warnings or clippy suggestions have been introduced - CI will deny clippy warnings by default! You may #[allow] certain lints where reasonable, but ideally justify those with a short comment.

The RTC interrupt handler currently spins on count < compare, to ensure
that stale count read does not reach the on_monotonic_interrupt fn. This
is fine during normal operation, but under tight timing, the compare
target can be moved after the flag is set, causing the spin to wait
until the incorrect time. If this time is far in the future, it wedges
the handler and everything at its priority and below.

This commit adds a one-time check that limit > compare, so that if the
compare value has been overwritten in a way that would cause a long
spin, the spin will instead be skipped - elimitating the stall, as well
as replacing MIN_COMPARE_TICKS with a new unified SYNC_SLACK_TICKS based
on the worst-case read latency detailed in the datasheet
@QuartzShard

Copy link
Copy Markdown
Contributor Author

The 16 Tier 2 failures are unrelated: cortex-m 0.7.8 (2026-08-04, between master's last CI run and this PR's) changed singleton! to expand to critical_section::with, so boards pinning old published HALs that use it (e.g. atsamd-hal 0.14's USB stack) no longer link (_critical_section_1_0_acquire undefined) under fresh resolution. Reproducible on master; passes with cortex-m pinned to 0.7.7. Filed upstream: rust-embedded/cortex-m#683. HAL clippy and rustfmt jobs pass.

@jbeaurivage
jbeaurivage merged commit 1014cfc into atsamd-rs:master Aug 9, 2026
96 of 112 checks passed
@github-actions github-actions Bot mentioned this pull request Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants