August 15, 2026
Teaching the encoders to ignore the screen
The encoders were being polled in step with display rendering. When the screen had work to do, reading the I2C expanders waited behind it, and a knob turned during a redraw arrived late or not at all. The instrument felt like it was ignoring you — which, technically, it was.
The fix was to decouple the two completely. Polling now runs on its own 1kHz IntervalTimer at priority 255, independent of whatever the display is doing:
- Encoder reads happen on a fixed schedule no matter what is being drawn
- An edge-triggered lockout debouncer, because EC11 switches are noisy and a naive read counts one click as three
- Momentum-based acceleration, so a slow twist is fine adjustment and a fast spin is a full sweep
The acceleration curve is the part that changes how the instrument feels rather than how it measures. Fourteen encoders covering an entire synth means a parameter can be three hundred steps away, and a control that takes ten seconds to travel is a control you stop using.
What didn’t change is worth noting: the audio engine.
Almost every “the synth is laggy” problem in this project has turned out to be something other than the synth. The DSP was never the bottleneck. The screen was.
Updates on the project page.