Audio DSP Pipeline
The LPC2103F controls the D2-81431’s audio processing through a single I2C bus at 480 kHz. Every audio parameter — volume, EQ preset, crossover, phase, sound mode, night mode — translates into one or more I2C write transactions. The firmware never reads audio data or processes samples; it is purely a control plane. All signal processing happens inside the D2-81431’s DSP core.
I2C bus configuration
Section titled “I2C bus configuration”The I2C0 peripheral is initialized at 480 kHz in fast mode:
| Parameter | Value |
|---|---|
| I2C0SCLH | 0x49 (73) |
| I2C0SCLL | 0x49 (73) |
| Clock rate | PCLK / (73 + 73) = 14,745,600 / 146 = ~101 kHz per half-cycle = ~480 kHz effective |
| Slave address | 0xB2 (write to D2-81431 at 7-bit address 0x59) |
| VIC slot | 5, IRQ 9 |
The I2C state machine runs entirely in the interrupt handler. The main loop enqueues transactions by copying data to a global transmit buffer, setting the byte count, and asserting the START condition bit. The ISR handles address transmission, data bytes, ACK/NACK detection, and STOP generation. The main loop polls a busy flag and a status register to determine when a transaction has completed.
Packet formats
Section titled “Packet formats”The firmware uses two I2C packet formats to communicate with the D2-81431:
7-byte init packets — used for DSP coefficient writes during EQ preset loading, sound mode changes, and filter configuration:
Byte 0: 0xB2 (I2C address, write mode)Byte 1-2: Register addressByte 3-6: 24-bit fixed-point coefficient dataThe coefficient data in bytes 3-6 represents DSP filter parameters — biquad coefficients, gain values, delay taps — in the D2-81431’s native 24-bit fixed-point format. Each 7-byte packet programs a single register in the DSP’s coefficient RAM.
18-byte command packets — used for more complex DSP operations, built by the command builder function at 0x36FC:
Byte 0-1: Constructed from command ID bits [9:8] (register bank encoding)Byte 2-17: 16 bytes of command dataThe command builder takes a 16-bit command ID and a 16-byte data buffer, constructs the 2-byte sub-address from the command ID’s upper bits, appends the 16 data bytes, and transmits the full 18-byte packet via I2C. This format is used for bulk configuration operations and settings persistence.
I2C command queue
Section titled “I2C command queue”The firmware maintains an 8-slot circular ring buffer for queueing I2C transactions:
| Parameter | Value |
|---|---|
| Buffer size | 8 slots |
| Slot size | 2-byte command + 16-byte data |
| Enqueue | FUN_000035d8 — adds to ring, advances write pointer |
| Dequeue | FUN_000036fc — builds 18-byte packet, transmits via I2C |
The ring buffer decouples the main loop’s settings changes from the I2C bus timing. When a user adjusts a parameter, the new value is enqueued immediately. The dequeue function runs in the EEPROM auto-save path, draining the buffer at a pace the I2C bus can sustain. This prevents I2C bus contention when multiple parameters change in rapid succession — as happens during a factory reset or when loading saved settings at boot.
The mute-configure-unmute pattern
Section titled “The mute-configure-unmute pattern”Every DSP configuration change follows the same protective sequence:
- Mute — set volume to 0 (FUN_000004f8)
- Configure — send the I2C commands that change the DSP state
- Unmute — restore volume to the user’s current level (FUN_00000510)
This pattern prevents audible artifacts (pops, clicks, transient noise) when DSP coefficients are updated. Loading a new EQ preset involves reprogramming 11 to 17 filter coefficients, and if the DSP is actively processing audio while those coefficients change mid-stream, the intermediate states can produce full-scale transients that would damage speakers. The mute-configure-unmute wrapper makes every transition inaudible.
Master DSP configure
Section titled “Master DSP configure”The master configuration function (FUN_00000dfc) orchestrates the complete audio pipeline. It is called at boot after settings are loaded, and again whenever any audio parameter changes:
- Send baseline I2C command
- Restore volume from settings
- Apply phase and crossover configuration (3-way switch based on crossover mode)
- Apply sound mode — dispatches to BYPASS, MUSIC, or MOVIE
- Apply night mode — writes 3 coefficient bytes from a lookup table
- Select speaker EQ preset — 6-way switch into the preset functions
- Send 5 additional output stage I2C commands
- Apply output stage configuration (2-way switch)
- Apply final mute state — either mute or restore volume based on settings
The ordering matters. EQ presets are loaded after sound mode and night mode because the preset coefficients may overlap with mode-specific parameters, and the last write wins at the register level.
Speaker EQ presets
Section titled “Speaker EQ presets”Six speaker EQ presets are hardcoded in the firmware, each loading a different set of DSP filter coefficients optimized for a specific subwoofer enclosure type:
| Index | Name | Function | I2C Commands | Enclosure type |
|---|---|---|---|---|
| 0 | FLAT | FUN_00000630 | 11 | No EQ correction (transparent passthrough) |
| 1 | DUAL8 | FUN_000006f0 | 13 | Dual 8-inch subwoofers |
| 2 | BSUB8 | FUN_000009d0 | 17 | Bass reflex 8-inch |
| 3 | BSUB10 | FUN_00000af0 | 17 | Bass reflex 10-inch |
| 4 | BSUB12 | FUN_000007d0 | 15 | Bass reflex 12-inch |
| 5 | HSUB10 | FUN_000008d0 | 15 | Horn-loaded 10-inch |
Each preset function sends a series of 7-byte I2C packets, programming the DSP’s biquad filter bank with coefficients tuned for that enclosure’s transfer function. The FLAT preset uses the fewest commands because it only needs to zero out (or unity-gain) the EQ stages. The bass reflex presets (BSUB8, BSUB10) use the most commands because they apply multi-band correction for the enclosure’s resonant behavior.
Some DSP coefficient packets are shared across presets — the SRAM addresses 0x4000016C, 0x40000237, and 0x4000002A appear in multiple EQ functions, suggesting common filter stages (perhaps a protection limiter or output filter) that are reloaded identically regardless of which enclosure preset is active.
Sound modes
Section titled “Sound modes”Three sound modes apply bass contour adjustments. Each uses the mute-configure-unmute pattern and sends 2 I2C commands:
| Mode | Function | Effect |
|---|---|---|
| BYPASS | FUN_000005a8 | No bass contouring — flat response through the DSP |
| MUSIC | FUN_00000538 | Music listening contour |
| MOVIE | FUN_00000570 | Cinema bass boost contour |
The 2 I2C commands per mode likely program a single biquad stage with a shelf or peak filter. BYPASS presumably loads unity-gain coefficients.
Night mode
Section titled “Night mode”Night mode applies dynamic range compression to reduce peak output levels for late-night listening:
| State | Function | I2C Commands | Effect |
|---|---|---|---|
| OFF | FUN_000005e0 | 1 | Removes compression — full dynamic range |
| ON | FUN_00000608 | 1 | Adds compression/limiting |
A single I2C command toggles the compression on or off, which suggests it enables or disables a compressor/limiter block that is always present in the DSP signal chain but normally bypassed.
Volume control
Section titled “Volume control”Volume is implemented as a lookup table mapping user levels (0-100) to DSP attenuation coefficients:
The volume set function (FUN_00000350) inverts the user’s volume level (vol = 100 - param), indexes into a 3-byte lookup table, and constructs a 7-byte I2C packet that writes the attenuation value to the D2-81431. The lookup table lives in the .data section (copied from flash at boot) and contains 101 entries — one per integer volume step.
The volume up/down handlers use adaptive step sizes to improve the user experience near the extremes of the range:
| Direction | Condition | Step size |
|---|---|---|
| Volume up | Level < 96 | 1 |
| Volume up | Level >= 96 | 2 |
| Volume down | Level < 5 | 2 |
| Volume down | Level >= 5 | 1 |
The larger step size near the extremes compensates for the logarithmic nature of perceived loudness — at very high or very low levels, single-step changes are inaudible, so the firmware doubles the step to maintain perceptible increments.
D2-81431 status monitoring
Section titled “D2-81431 status monitoring”The firmware monitors the D2-81431’s protection status through P0.13, a GPIO input with 8-sample debounce filtering. The D2-81431 reports current-limit faults (CL FAULT) and thermal protection events (TH FAULT) through this pin. When a fault is detected, the VFD compositor overrides the normal status display with the fault message — CL FAULT or TH FAULT — on line 2 of the display. These fault conditions take the highest display priority, overriding even the LOCK indicator.
The 8-sample debounce means a fault must persist for 8 consecutive 10 ms ticks (80 ms) before the firmware acknowledges it. This filters out transient spikes during heavy bass hits that might momentarily trigger the protection circuitry without indicating a genuine fault condition.