Display & Menu System
The vacuum fluorescent display is driven through a 4-bit parallel GPIO interface using the HD44780 instruction set. The display is a 2-line × 16-character module, write-only — the R/W pin is tied to ground, so the firmware cannot read the busy flag and relies on software delays instead.
VFD pin mapping
Section titled “VFD pin mapping”| GPIO Pin | HD44780 Signal | Function |
|---|---|---|
| P0.4 | DB4 | Data bit 4 (4-bit mode, high nibble first) |
| P0.5 | DB5 | Data bit 5 |
| P0.6 | DB6 | Data bit 6 |
| P0.7 | DB7 | Data bit 7 |
| P0.11 | RS | Register Select: 0 = command, 1 = data |
| P0.18 | E | Enable: data latched on falling edge |
| — | R/W | Hardwired to GND (write-only) |
The VFD driver sends each byte as two nibbles — high nibble first, then low nibble — toggling the E pin for each. The E pulse function (FUN_00003a5c) drives P0.18 HIGH, executes a short delay, then pulls it LOW. The falling edge of E is when the HD44780 controller latches the data.
Initialization sequence
Section titled “Initialization sequence”The VFD init (FUN_00003d50) follows the standard HD44780 power-on procedure for 4-bit mode:
| Step | Command | Meaning |
|---|---|---|
| 1 | 0x03 | Reset — forces 8-bit mode (HD44780 init requirement) |
| 2 | 0x28 | Function set: 4-bit interface, 2 lines, 5×8 dot font |
| 3 | 0x0C | Display control: display ON, cursor OFF, blink OFF |
| 4 | 0x06 | Entry mode: cursor increment, no display shift |
| 5 | 0x80 | Set DDRAM address to 0x00 (cursor to line 1, position 0) |
After initialization, the boot message is displayed:
SNAPAV EPISODEEA500 AMPLIFIERThe string print function (FUN_00003e24) walks a null-terminated string and sends each character as a data write (RS=1). When it encounters a newline character, it sends command 0xC0 to move the cursor to line 2 (DDRAM address 0x40).
VFD compositor
Section titled “VFD compositor”The main status display is not rendered by simple string writes. Instead, a compositor function (FUN_00007214) builds a 32-byte buffer — two lines of 16 characters each — by layering information with a priority system. The compositor runs on every VFD update call in the main loop and writes the complete buffer to the display.
The priority layers, from lowest to highest:
| Priority | Layer | Line | Content |
|---|---|---|---|
| 1 | Base display | 1 | " VOLUME 42 " (or " VOLUME MUTE ") |
| 2 | Power mode | 2 (left) | "TRIG" (12V trigger) or "AUTO" (audio sense) or blank (front panel) |
| 3 | Night mode | 2 (center-left) | "NIGHT" appended if enabled |
| 4 | Sound mode | 2 (center) | "MUSIC" or "MOVIE" (blank for BYPASS) |
| 5 | Lock | 2 (left) | "LOCK" — overrides power mode position |
| 6 | CL FAULT | 2 (full) | Current limit fault — overrides entire line 2 |
| 7 | TH FAULT | 2 (full) | Thermal fault — overrides entire line 2 |
Higher-priority layers overwrite lower-priority content at the same screen positions. Under normal operation with BYPASS sound mode and FRONT PANEL power control, line 2 is blank. With 12V TRIGGER and MUSIC mode active, line 2 reads "TRIG MUSIC ". If a thermal fault occurs, line 2 becomes "TH FAULT " regardless of what was there before.
Menu state machine
Section titled “Menu state machine”The menu system (FUN_00004e38) is a 3-state machine driven by the rotary encoder and its push button on P0.8:
| State | Behavior |
|---|---|
| 0 — Idle | Normal status display. Encoder press enters menu. Encoder rotation adjusts volume. |
| 1 — Menu navigation | Encoder rotation scrolls through 10 menu items. Press selects current item for editing. |
| 2 — Parameter editing | Encoder rotation adjusts the selected parameter. Press confirms and returns to navigation. |
The menu system has 10 items, dispatched through a jump table at address 0x5644:
| # | Menu Item | Value Range |
|---|---|---|
| 1 | CROSSOVER | 40 Hz – 260 Hz in variable steps, or LFE |
| 2 | SPEAKER EQ | FLAT, DUAL8, BSUB8, BSUB10, BSUB12, HSUB10 |
| 3 | PHASE | 0° – 315° in 45° steps (8 values, index 0-7) |
| 4 | SOUND MODE | BYPASS, MUSIC, MOVIE |
| 5 | NIGHT MODE | OFF, ON |
| 6 | POWER CTRL | FRONT PANEL, 12V TRIGGER, AUDIO SENSE |
| 7 | IR DEVICE ID | 1, 2, 3, 4 |
| 8 | LOCK | OFF, ON (special handling: hold encoder 10 sec to unlock) |
| 9 | FACTORY RESET | Displays " SW V1.19 RESET>", then ">ARE YOU SURE?" |
| 10 | (reserved) | — |
The lock menu item (item 8) has special behavior: when locked, the encoder is disabled for all other menu items, and the user must hold the encoder button for 10 seconds to unlock. This prevents accidental changes in installed systems where the front panel is physically accessible but not meant to be adjusted.
Crossover frequency encoding
Section titled “Crossover frequency encoding”The crossover display function (FUN_00005c60) reveals the actual frequency mapping. The setting byte stores an index (0-28), and the display function converts it to a frequency:
- Index 0-12: frequency = index × 5 + 40 (gives 40, 45, 50, … 100 Hz in 5 Hz steps)
- Index 13-28: frequency = index × 10 - 20 (gives 110, 120, 130, … 260 Hz in 10 Hz steps)
- Index 29 (max + 1): displays “LFE” (crossover bypassed)
The maximum crossover frequency is 260 Hz, not 250 Hz as stated in the manual. The dual-resolution step scheme gives finer control in the 40-100 Hz range where subwoofer crossover points are most commonly set, and coarser 10 Hz steps above 100 Hz where the exact frequency matters less.
Settings storage
Section titled “Settings storage”All user settings are stored as a byte array in SRAM and persisted to the D2-81431’s internal EEPROM via I2C:
| Byte | Setting | Default | Max | Validation reset |
|---|---|---|---|---|
| [0] | Power Control | 0 | 1 | 0 |
| [1] | Night Mode | 0 | 1 | 0 |
| [2] | IR Device ID | 0 | 2 | 0 |
| [4] | Volume | 50 | 101 | 50 |
| [5] | Crossover | 28 | 28 | 8 |
| [6] | Phase | 0 | 7 | 0 |
| [7] | Sound Mode | 0 | 2 | 0 |
| [8] | Speaker EQ | 0 | 5 | 0 |
| [9] | Mute | 0 | 1 | 1 |
| [0xB] | Lock / IR Dev ID | 0 | 3 | 0 |
The validation function (FUN_000076c4) runs at boot after loading settings from EEPROM. It range-checks every byte against the Max column — if a value exceeds its maximum, it is reset to the Validation Reset column value (which is not always the same as the default). This protects against EEPROM corruption causing out-of-range parameter values that could crash the DSP configuration functions.
Auto-save with debounce
Section titled “Auto-save with debounce”Settings are not saved immediately when changed. The firmware uses a 200-tick (2-second) debounce delay:
- When any setting changes,
settings_mark_dirty()(FUN_00003864) sets a dirty flag - The auto-save function (FUN_00003884) runs every tick in the main loop
- If the dirty flag is set, it starts a 200-tick countdown
- If another setting changes during the countdown, the timer resets to 200
- When the countdown expires, the settings are enqueued to the I2C command ring buffer
- The ring buffer drains the write to the D2-81431’s EEPROM register
The 2-second debounce prevents excessive EEPROM writes when the user is scrolling through values with the rotary encoder. Without it, spinning the encoder through 20 volume steps would trigger 20 separate EEPROM write cycles. With the debounce, only the final value gets written.
Factory reset
Section titled “Factory reset”The factory reset function (FUN_000049d8) resets all settings to their compiled-in defaults. The defaults represent a conservative startup state: volume at 50%, BYPASS sound mode, no night mode, FLAT EQ, phase at 0°, front panel power control, mute ON. The mute-on default is deliberate — the amp starts silent, requiring the user to unmute before audio passes.
Heartbeat LED
Section titled “Heartbeat LED”P0.12 drives a status LED with an XOR toggle pattern. The toggle rate changes based on the amplifier’s power state:
| State | Toggle interval | LED period |
|---|---|---|
| Active (amplifier on) | 40 ticks | 400 ms (fast blink) |
| Standby (amplifier off) | 120 ticks | 1.2 seconds (slow blink) |
The XOR toggle means the LED alternates between on and off with equal duty cycle — 200 ms on / 200 ms off in active mode, 600 ms on / 600 ms off in standby. This gives a visual indication of the amplifier’s state from across a rack room without needing to read the VFD.