August 15, 2026

teaching the encoders to ignore the screen

By Geoffrey Broomfield · 1 min read

I had the encoders polling 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, because I’d made them share a schedule. 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 don’t use twice.

The part I didn’t touch is worth saying plainly: 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 wasn’t the bottleneck. The screen was.

Updates on the project page.