Skip to content

Keep the RX8130 timer /IRQ pulse catchable and follow the datasheet re-arm sequence - #339

Merged
lovyan03 merged 1 commit into
m5stack:developfrom
ainyan03:rx8130_timer_pulse
Aug 25, 2026
Merged

Keep the RX8130 timer /IRQ pulse catchable and follow the datasheet re-arm sequence#339
lovyan03 merged 1 commit into
m5stack:developfrom
ainyan03:rx8130_timer_pulse

Conversation

@ainyan03

Copy link
Copy Markdown
Contributor

Problem

RX8130_Class::setTimerIRQ() selected the 4096Hz source clock for every period below 16s. The RX8130 releases /IRQ automatically after tRTN2, which is only 122us for the 4096Hz clock but 7.57ms for all the other clocks (datasheet Table 16). Boards that route the RTC /IRQ through a scanning PMIC or IO expander (e.g. M5PaperMono: RX8130 → M5PM1 GPIO0 → PM1 IRQ → MCU) miss such a short pulse, so common requests like setTimerIRQ(1000) or (10000) never reached the MCU.

Changes (src/utility/rtc/RX8130_Class.cpp)

  • Clock selection: try 64Hz → 1Hz → 1/60Hz → 1/3600Hz and take the first whose rounded count keeps the period within 1/256 (~0.39%) and has at least 16 counts (the first countdown can be short by up to one source clock, so this bounds that error). 4096Hz is used only for periods no other clock can represent (below ~2s). All arithmetic is 32-bit; when a finer clock runs out of range the coarser one rounds up, so the returned period is monotonic in the request.
  • Re-arm sequence per the datasheet example flow: TE=0 (+TSEL) → clear TF → TIE=1 → preset → TE=1 last. The old code rewrote the counter with TE still set, which the datasheet does not allow and which left the timer counting with the stale preset (observed: TF never set after a re-arm).
  • Preset is read back while TE=0 and rewritten if it does not match; every access in the arming path is checked and a failure stops the timer (verified by read-back) and returns 0. The @return comment now states that 0 means either disabled or "could not be set".
  • Flags in 0x1D are write-0-to-clear, so TF (and AF in clearIRQ/disableIRQ) is cleared with a single constant write instead of a read-modify-write that could drop a flag raised in between.
  • The returned period is rounded to the nearest ms and is never 0 while the timer runs (1ms used to report 0).

Alarm interrupts are unaffected (their /IRQ is held until cleared).

Verification

Host-side sweep of the selection over the full uint32_t range: max period error 0.39%, no non-monotonic point, 4096Hz only used for requests ≤ 1961ms.

On M5PaperMono (RTC /IRQ observed through the PM1 IRQ line):

request clock chosen /IRQ reached the MCU
raw 4096Hz × 4096 (old behaviour for 1s) 4096Hz missed (0/1, occasionally 1/8)
setTimerIRQ(1000) 64Hz × 64 first pulse at ~990ms, every run
setTimerIRQ(16000) 1Hz × 16 ~16s

Fork CI (ArduinoBuild / IDFBuild) passed on this branch.

…e-arm sequence

The RX8130 wakeup timer releases /IRQ automatically after tRTN2, which is
only 122us with the 4096Hz source clock but 7.57ms with the other clocks
(Table 16). setTimerIRQ() picked 4096Hz for every period below 16s, so
boards whose RTC /IRQ is routed through a scanning PMIC or IO expander
(e.g. the M5PM1 GPIO IRQ path) missed the interrupt for common requests
such as 1s or 10s.

Clock selection now tries 64Hz, 1Hz, 1/60Hz and 1/3600Hz in that order and
takes the first whose rounded count keeps the period within 1/256 and has
at least 16 counts (the first countdown can be short by up to one source
clock - 1s for the two slowest clocks - so this bounds that error to ~6%
or less); 4096Hz is used only for periods no other clock can represent
(below ~2s). The arithmetic stays in 32 bits: each clock carries its
65535-count range so msec*div cannot overflow, and the period error is
the division remainder. When a finer clock runs out of range the coarser
one rounds up, so the returned period never steps backwards as the
request grows.

The re-arm sequence follows the datasheet example flow: TE=0 (+TSEL) ->
clear TF -> TIE=1 -> preset -> TE=1 last, so the first event can never
precede the interrupt enable. The old code rewrote the counter with TE
still set, which the datasheet does not allow and which left the timer
running with the stale preset. The preset is read back while TE=0 and
rewritten if it does not match. Every access in the arming path is
checked; on failure the timer is stopped (TE=0/TIE=0, verified by
read-back, retried) and 0 is returned - the return value cannot
distinguish that from a requested stop, which the API comment now states.
Flags in 0x1D are write-0-to-clear, so TF (and AF in clearIRQ/disableIRQ)
is cleared with a single constant write instead of a read-modify-write
that could drop a flag raised in between. The returned period is rounded
to the nearest ms and is never 0 while the timer runs.
@lovyan03
lovyan03 merged commit 4aa5d8d into m5stack:develop Aug 25, 2026
27 checks passed
@ainyan03
ainyan03 deleted the rx8130_timer_pulse branch August 25, 2026 00:58
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