Conversation
The external clock input (PD4) was polled once per loop() pass, so edge detection jittered by the loop period (a few hundred microseconds, dominated by blocking analogRead calls) and pulses shorter than a blocking call (e.g. an EEPROM write of up to ~26 ms) were missed entirely, leaving the step counter lagging behind the external clock. A PCINT20 ISR now stores a micros() timestamp and a flag; all processing stays in read_clock(). Timing references for clock out, gate windows and step advance use the captured edge timestamp instead of the loop's current time, so the measured clock period and all derived timings are free of polling jitter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
EEPROM.write blocks ~3.3 ms per byte; persisting tempo plus clock-in mult (up to 8 bytes) freezes the loop for up to ~26 ms. These writes were triggered 3 s after the last encoder move, on tap-tempo button release and when the external clock was unplugged - i.e. typically while the sequencer was playing, causing steps, gates and clock out to stall audibly (and, before external clock edges were captured by interrupt, even losing pulses entirely). All EEPROM writes now go through service_pending_EEPROM_writes(), which performs them only while the sequencer is stopped. Pending writes are kept flagged until then, so nothing is lost as long as the module is stopped once before power-down. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
analogRead blocks for ~112 us and read_address() ran once per loop() pass, making it the dominant contributor to the loop period and thus to input polling latency. Reading the address CV at 500 Hz is still far faster than any musically relevant CV change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Like the external clock, the reset input (PC3 / A3) was polled once per loop() pass, so short reset pulses could be missed during blocking calls and reset timing jittered by the loop period. A PCINT11 ISR now latches the falling edge; the pulse is processed in read_one_shot_reset_input() as before, keeping the processing order (reset before clock) within the loop unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The clock input is non-inverting (series resistor plus clamp diodes straight into PD4), so the pin follows the jack and the trigger fires on the falling edge of the incoming clock - as documented in the manual and identical to the polled detection before. Only the reset input is inverted by a transistor stage, making reset act on the rising edge. Comments only, no functional change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When clocking the Muxlicer from an external CV clock + reset, the playhead
was often slightly late and occasionally ended up a full step behind until
the next reset. This PR removes the causes:
External clock via pin change interrupt (PCINT20). The clock input
(PD4) was polled once per
loop()pass, so edge detection jittered bythe loop period (a few hundred microseconds, dominated by blocking
analogReadcalls) and pulses shorter than a blocking call were missedentirely. The ISR only stores a
micros()timestamp and a flag; allprocessing stays in
read_clock(). Timing references (clock out, gatewindows, step advance) now use the captured edge timestamp, so the
measured clock period is free of polling jitter.
Reset via pin change interrupt (PCINT11). Same treatment for the
reset input (PC3/A3); short reset pulses can no longer be missed. The
processing order within the loop (reset before clock) is unchanged.
EEPROM writes deferred while running.
EEPROM.writeblocks ~3.3 msper byte; persisting tempo + clock-in mult (up to 8 bytes) froze the
loop for up to ~26 ms. These writes were triggered 3 s after the last
encoder move, on tap-button release and when the external clock was
unplugged — i.e. typically while playing, stalling steps/gates/clock out
audibly and (before the interrupt capture) even losing pulses. All
writes now go through
service_pending_EEPROM_writes(), which performsthem only while the sequencer is stopped; pending writes stay flagged
until then. Note: settings changed while running are only persisted
once the sequencer is stopped before power-down.
Address CV throttled to 500 Hz.
analogReadblocks ~112 µs and ranevery loop pass; reading the address CV every 2 ms is still far faster
than any musically relevant CV change and roughly halves the loop
period.
No hardware changes required (ATmega328P pin change interrupts).
Tested on a Muxlicer (PCB v1.3) clocked from an Arturia BeatStep Pro
(clock + reset): with clock-in mult/div at 0, ~50 stop/start cycles were
perfectly in sync (previously the playhead lagged audibly and
intermittently lost steps).
Commits