mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-31 01:08:14 +00:00
fix(eink): drive ringtone note advance from TIMER1 IRQ, not loop() poll
On nRF52 the buzzer advanced notes by polling millis() >= _note_end_ms in loop(). A blocking display refresh (e-ink endFrame) starves loop(), so a note boundary that falls inside a refresh is serviced late — the note plays long, or the next is skipped. The keypress-time 300 ms render delay only masked the first note. Advance notes from a hardware TIMER1 compare interrupt instead, scheduled for each note's exact duration, so timing is independent of render cadence. TIMER0 is the SoftDevice's; TIMER1 is free (tone() uses PWM2, nrfx TIMER1 driver is disabled). loop() becomes a no-op on nRF52; the UITask keypress render-delay workaround is removed. _disarmNoteTimer() clears the latched NVIC pending IRQ (not just the event) on stop()/_nrfBegin(), so a note-advance latched just before a stop can't fire spuriously — which would skip a new melody's first note or blip after an explicit stop. Event read-backs flush the write buffer per the nRF52 event anomaly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -54,7 +54,6 @@ class genericBuzzer
|
||||
const char* _rtttl_pos = nullptr;
|
||||
bool _rtttl_done = true;
|
||||
bool _pwm_on = false;
|
||||
unsigned long _note_end_ms = 0;
|
||||
uint8_t _def_dur = 4;
|
||||
uint8_t _def_oct = 5;
|
||||
uint16_t _def_bpm = 120;
|
||||
@@ -69,5 +68,21 @@ class genericBuzzer
|
||||
uint16_t bpm, uint16_t& freq_hz, uint32_t& dur_ms);
|
||||
static void _parseHeader(const char* melody, uint8_t& def_dur, uint8_t& def_oct,
|
||||
uint16_t& bpm, const char*& notes_start);
|
||||
|
||||
// TIMER1-driven note advance: a hardware compare interrupt calls
|
||||
// _nrfAdvance() at the exact moment the current note's duration ends,
|
||||
// so playback timing survives a blocking display refresh (e-ink)
|
||||
// instead of waiting for the next loop() poll. Same reasoning as
|
||||
// MomentaryButton's GPIO-IRQ edge capture, just timer- rather than
|
||||
// pin-driven. TIMER0 is reserved by the SoftDevice; TIMER1 is free.
|
||||
void _armNoteTimer(uint32_t dur_ms);
|
||||
void _disarmNoteTimer();
|
||||
static genericBuzzer* _isr_instance;
|
||||
|
||||
public:
|
||||
// Must be public: the extern "C" TIMER1_IRQHandler (see buzzer.cpp) is
|
||||
// a free function — the vector table requires that exact symbol — so
|
||||
// it needs access from outside the class to dispatch into it.
|
||||
static void _timer1ISR();
|
||||
#endif
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user