-
Notifications
You must be signed in to change notification settings - Fork 66
Timing and latency
This page summarizes the firmware-side timing that affects switch, encoder, analog input, MIDI, and OSC response latency in OpenDeck.
Latency is not a single fixed number. The total time from a physical action to a MIDI message depends on:
- when the action happens relative to the next firmware scan
- the input topology used by the target
- switch debouncing or analog filtering
- scheduler timing and other active work
- the selected MIDI or network transport
- host operating system, USB/BLE/network stack, DAW, control software, and audio buffer settings
The values below describe OpenDeck firmware timing. They do not include host-side MIDI, network, control software, or audio latency.
| Item | Value | Notes |
|---|---|---|
| Digital scan loop sleep | 1 ms |
Applies to switches and encoders. |
| Analog scan loop sleep | 1 ms |
Applies to analog inputs. |
| I2C loop sleep | 1 ms |
Applies to I2C display/peripheral processing. |
| Zephyr timeslice | 10 ms |
Used when multiple same-priority preemptive threads are ready. |
| MIDI thread priority | 0 |
Higher priority than the I/O scan threads. |
| Digital, analog, output, I2C, touchscreen, and system work priority | 1 |
Lower priority than MIDI processing. |
| Switch debounce depth | 8 samples |
A switch must be stable for 8 consecutive digital scans. |
| BLE MIDI connection interval request | 7.5 ms |
BLE timing also depends on the central device accepting/maintaining the interval. |
| Term | Meaning | Used by |
|---|---|---|
| Digital frame | One complete read of every physical digital input on the target. Switches and encoders are processed after the frame is complete. | Switches, encoders |
| Digital frame acquisition | The time needed to read one complete digital frame. | Switches, encoders |
| Digital scan interval | Digital frame acquisition time plus the 1 ms digital scan loop sleep. |
Switches, encoders |
| Analog frame | One complete analog scan pass for the currently enabled physical analog inputs. Each scanned input is sampled twice and the first sample is discarded. Disabled analog inputs are skipped. | Analog inputs |
| Analog frame acquisition | The time needed to read one complete analog frame. | Analog inputs |
| Analog scan interval | Analog frame acquisition time plus the 1 ms analog scan loop sleep. |
Analog inputs |
Switches are sampled by the digital scan thread and must pass the debounce filter before a state change is accepted.
| Stage | Contribution | Notes |
|---|---|---|
| Digital frame acquisition | One complete digital frame read | Native GPIO is very quick; shift-register and matrix topologies add clock/read time. |
| Debounce |
8 stable digital frames |
Native GPIO targets are close to 8 ms; larger digital topologies add their frame acquisition time to each debounce sample. |
| Processing and routing | Small, workload-dependent | Runs after the debounced state is accepted. |
| MIDI/OSC transport | Transport-dependent | USB, DIN, BLE, network, and the host each add their own timing. |
Approximate firmware-side latency: ~8 ms on native GPIO targets before routing and MIDI/OSC transport.
Native GPIO switches have very little frame acquisition overhead, so their firmware-side debounce time is close to 8 ms plus up to one extra scan interval. Shift-register and matrix topologies add the time needed to clock/read one full digital frame to each debounce sample, so large digital topologies have proportionally higher switch latency.
Encoders use the same digital scan thread as switches, but they do not use the switch debounce filter.
| Stage | Contribution | Notes |
|---|---|---|
| Digital frame acquisition | One completed digital frame read | Encoder state is processed from the completed digital frame. |
| Processing and routing | Workload-dependent | Also depends on encoder pulse rate, message type, limits, and acceleration settings. |
| MIDI transport | Transport-dependent | USB, DIN, BLE, and the host each add their own timing. |
Approximate firmware-side latency: about one completed digital frame acquisition before routing and MIDI transport.
Native GPIO targets are usually close to the 1 ms digital scan interval. Shift-register and matrix topologies add the time needed to clock/read one full digital frame.
Analog inputs are scanned by the analog scan thread.
| Stage | Contribution | Notes |
|---|---|---|
| Analog frame acquisition | Enabled physical analog inputs times 2 ADC conversions, plus mux GPIO overhead | Each conversion uses the ADC acquisition setting from the target devicetree. The first sample after selecting an input is discarded for settling. |
| Filtering and change detection | Configuration-dependent | Deadband, limits, and message type can delay or suppress outgoing messages. |
| Processing and routing | Workload-dependent | Runs after the analog value is accepted as changed. |
| MIDI transport | Transport-dependent | USB, DIN, BLE, and the host each add their own timing. |
Approximate firmware-side latency: target-specific; roughly one analog scan interval before routing and MIDI transport.
Small native ADC targets have short frame acquisition. Large mux targets take longer when many analog inputs are enabled because each enabled physical input adds two ADC conversions to the analog frame. Disabled analog inputs do not add ADC conversion time.
The table below is extrapolated from the target devicetree topology. It shows worst-case analog workload with all analog inputs enabled and ADC timing, not a measured wall-clock time. Tick-based STM32 and SAMD51 settings are converted to time using the ADC clock from the generated devicetree clock tree and ADC prescaler. RP2040/RP2350 timing is converted from the ADC clock divider in devicetree.
| Target | Analog topology | ADC conversions if all inputs are enabled | ADC time per conversion | Minimum ADC time if all inputs are enabled |
|---|---|---|---|---|
arduino_nano_33_ble |
native | 12 | 5 us |
60 us |
bergamot |
mux | 32 | 5.33 us |
171 us |
blackpill411 |
native | 16 | 4.67 us |
75 us |
discovery_f407g |
native | 14 | 5.33 us |
75 us |
dubfocus16t |
mux | 160 | 5.33 us |
853 us |
grand_central_m4 |
native | 32 | 5.0 us |
160 us |
metro_rp2040 |
native | 6 | 4.0 us |
24 us |
nrf52840dk |
native | 16 | 5 us |
80 us |
nrf5340dk |
native | 12 | 5 us |
60 us |
nucleo_f767zi |
native | 34 | 4.15 us |
141 us |
nucleo_h753zi |
native | 38 | 4.33 us |
165 us |
opendeck2 |
mux | 64 | 5.33 us |
341 us |
opendeck21 |
mux | 64 | 5.33 us |
341 us |
opendeck22 |
mux | 64 | 4.0 us |
256 us |
opendeck31 |
mux-on-mux | 128 | 4.0 us |
512 us |
pico |
native | 6 | 4.0 us |
24 us |
pico2 |
native | 6 | 4.0 us |
24 us |
rooibos |
mux | 64 | 5.33 us |
341 us |
teensy4 |
native | 20 | 5.6 us |
112 us |
teensy41 |
native | 32 | 5.6 us |
179 us |
ws_core405r |
native | 32 | 5.33 us |
171 us |
The minimum ADC time is only the listed per-conversion time multiplied by the number of conversions. Full analog frame acquisition also includes mux GPIO switching and driver overhead. The analog scan interval then adds the 1 ms analog loop sleep.
For a partial configuration, approximate the ADC part of the frame as:
enabled analog inputs * 2 * ADC time per conversion
For example, on opendeck31, one enabled analog input is about 8 us of ADC conversion time (1 * 2 * 4 us) before mux GPIO overhead and the 1 ms analog loop sleep. With all 64 analog inputs enabled, the worst-case ADC conversion time is about 512 us.
Analog filtering runs after the frame has been acquired. These filters do not change the ADC acquisition time in the table above; they decide whether the newly scanned value is stable or meaningful enough to publish.
| Filter behavior | Applies to | Timing effect |
|---|---|---|
| ADC deadband | Potentiometers and continuous FSR values | Small ADC movement inside the current deadband is suppressed until the value moves far enough. This reduces jitter, but tiny movements may not emit immediately. |
| Direction-change confirmation | Potentiometers and continuous FSR values | Small opposite-direction movement may need another accepted scan before it is treated as real motion. This prevents brief bounce around the current value. |
| EMA smoothing | Potentiometers and continuous FSR values | Accepted ADC values are blended with the previous filtered value. This does not add a fixed wait, but fast physical movement can be reflected over several scans instead of one abrupt jump. |
| Endpoint assist | Potentiometers and continuous FSR values | Near the configured minimum or maximum, the filter can snap to the endpoint instead of slowly approaching it. This can reduce visible latency at the edges. |
| Idle drift confirmation | Potentiometers and continuous FSR values | After motion has been idle for about 100 ms, a new low-level drift value may need one repeated sample before it is published. Active movement bypasses this path. |
| Hysteresis | Analog inputs configured as switches | Analog switch mode bypasses the continuous-value filter and uses on/off thresholds with hysteresis. It avoids analog smoothing delay, but values inside the hysteresis band are ignored until they cross a threshold. |
After OpenDeck decides to send a MIDI message, transport latency is added on top of the input latency:
| Transport | Firmware-side expectation | Notes |
|---|---|---|
| USB MIDI | Usually the lowest-latency OpenDeck transport | Host USB stack and receiving software still matter. |
| DIN MIDI | Fixed serial line time | A 3-byte MIDI message takes about 0.96 ms on the wire at the MIDI baud rate. |
| BLE MIDI | Depends heavily on the active BLE connection interval | Also depends on central-device behavior and radio conditions. |
Hardware
- Supported microcontrollers
- Supported components
-
Supported boards
- Adafruit
- Arduino
- Generic
- LILYGO
- Nordic Semiconductor
- Olimex
- PJRC
- Raspberry Pi
- Shantea Controls
- Silicognition
- STMicroelectronics
- Waveshare
- WIZnet
- Recommended components and where to get them
- LED indicators
Configuration and usage
- Configurable features
- Output control
- OSC
- Presets
- Timing and latency
- Configuring touchscreens
- Firmware update via bootloader
Advanced