Skip to content

01 — System Architecture

This document separates the selected integrated-hardware target from the working software/bench path. The target uses the Tang Mega 138K Pro card; the bench path keeps software and latency experiments possible before that card’s drivers and physical interfaces pass their gates (17).

flowchart LR
    subgraph HOST["N100 · real-time Linux"]
        APP["Auvra engine + GUI<br/>CLAP · SDL3/egui"]
        ALSA["ALSA PCM"]
        DRM["DRM/KMS + evdev"]
        APP <--> ALSA
        APP <--> DRM
    end
    subgraph FPGA["Tang Mega 138K Pro · GW5AST-138"]
        PCIE["PCIe endpoint<br/>priority DMA + event queues"]
        AUDIO["I²S/TDM audio fabric"]
        FB["DDR3 framebuffer<br/>RGB888/DVI scanout"]
        CTRL["key scanner + I²C/GPIO<br/>timestamped input"]
        PCIE <--> AUDIO
        PCIE <--> FB
        PCIE <--> CTRL
    end
    ALSA <--> PCIE
    DRM <--> PCIE
    AUDIO <--> ADC["PCM1822 ADC ×1<br/>2 analog inputs"]
    AUDIO <--> DAC["PCM5122 DAC ×2<br/>4 analog outputs"]
    ADC <--> JACKS["Balanced XLR + unbalanced jack<br/>line I/O"]
    DAC <--> JACKS
    FB --> PANEL["Touch display"]
    PANEL --> CTRL
    MATRIX["S90 passive key matrix"] --> SCANNER["protected FPGA or MCU scanner"] --> CTRL
    BUTTONS["S90 controls · later buttons/LEDs"] <--> CTRL

The N100 always renders the GUI and runs synthesis. The FPGA scans out its host-written framebuffer and exposes audio through an Auvra ALSA driver; touch/controls use Linux input interfaces. The S90 key contacts are not I²C: the scanner topology and existing panel wiring must be measured. I²C applies only to peripherals that actually speak it. Audio DMA and sample timing have priority over display and control traffic. AES67 and AE350 autonomy are later stages; neither blocks local audio/display/control bring-up.

flowchart TB
    subgraph S90["Yamaha S90 chassis"]
        direction TB
        subgraph INPUTS["Physical inputs"]
            KEYBED["88-key BH keybed<br/>passive 2-contact matrix"]
            POTS["Potentiometers<br/>(knobs)"]
            FADERS["Motor-faders<br/>(position + motor)"]
            BTNS["Buttons / switches"]
        end
        subgraph OUTPUTS["Physical outputs"]
            LEDS["LEDs / indicators"]
            DISP["Touch display<br/>7–10″ capacitive"]
        end
    end

    subgraph MCU["RP2350 microcontroller layer"]
        direction TB
        KSCAN["RP2350 — Keybed scanner<br/>matrix scan + velocity timing"]
        NODE1["RP2350 node A<br/>pots + buttons + LEDs"]
        NODE2["RP2350 node B<br/>motor-faders (+ driver)"]
        NODEX["RP2350 node …"]
    end

    subgraph HOST["Sound engine — Intel N100 ITX"]
        direction TB
        RTOS["PREEMPT_RT Linux"]
        SYNTH["Auvra app<br/>UI + plugin host + mixer<br/>(cpal → ALSA, doc 12)"]
        UI["Kiosk UI<br/>(full-screen)"]
        I2CBR["USB→I²C bridge<br/>MCP2221A → /dev/i2c-N"]
        AUDIF["Audio interface<br/>(class-compliant)"]
    end

    AOUT["Balanced stereo/▶ out<br/>TRS / XLR"]
    AIN["Line/mic in<br/>(optional)"]

    KEYBED --> KSCAN
    POTS --> NODE1
    BTNS --> NODE1
    FADERS <--> NODE2
    NODE1 --> LEDS

    KSCAN -->|"USB-MIDI"| RTOS
    NODE1 -->|"I²C"| I2CBR
    NODE2 -->|"I²C"| I2CBR
    NODEX -->|"I²C"| I2CBR
    I2CBR -->|"USB"| RTOS

    DISP -->|"HDMI"| UI
    DISP -->|"USB-HID"| UI

    RTOS --- SYNTH
    RTOS --- UI
    SYNTH <--> AUDIF
    AUDIF --> AOUT
    AIN --> AUDIF
Block Responsibility Detail doc
Keybed scanner (RP2350) Scan the 88-key matrix, derive velocity from make/break timing, emit Note-On/Off as USB-MIDI. 05-keybed-and-midi.md
Control-surface nodes (RP2350) Read pots (ADC), buttons (GPIO), drive LEDs, drive/track motor-faders. Expose state as I²C registers. 06-control-surface.md
USB→I²C bridge Give the N100 a real /dev/i2c-N since the board has no I²C header. 06-control-surface.md
Sound engine (N100 + RT Linux) Host synth/effect plugins in patches, run the mixer and the UI; own the audio device; route MIDI. 12, 02, 03
Audio interface Convert to balanced analog with low latency. 04-audio-io.md
Touch display Kiosk UI surface (HDMI video + USB touch); never shows boot. 07-display-and-boot.md
Power One 19 V DC-in feeds the N100; derived rails feed MCUs, panel, faders. 08-power-and-chassis.md

The diagram and table describe the software MVP/bench path, not the selected integrated product topology. The FPGA card replaces the external audio device, host HDMI scanout and USB control links only after the corresponding gates pass (17-fpga-audio-interface.md).

A deliberate split keeps the hard-real-time path clean:

flowchart LR
    subgraph HARD["Hard real-time — note events"]
      K["Keybed RP2350"] -->|"USB-MIDI<br/>~0–1 ms jitter"| H1["Host MIDI in"]
    end
    subgraph SOFT["Soft real-time — control surface"]
      C["RP2350 nodes"] -->|"I²C 100–400 kHz<br/>polled ~1 kHz"| H2["Host /dev/i2c-N"]
    end
    H1 --> ENG["Synth engine"]
    H2 --> ENG
  • Hard real-time (USB-MIDI): key strikes need bounded, low jitter. USB Full-Speed MIDI bounds jitter to roughly one 1 ms frame; it is the universal, driverless transport.1 Optional DIN-MIDI/UART path exists if sub-100 µs jitter is ever required.2
  • Soft real-time (I²C): a knob moving from 0→127 over tens of milliseconds is fine on a ~1 kHz polled I²C bus. This also matches the host’s only practical option — a USB→I²C bridge — because the N100 board exposes no I²C header.3

Why not put everything on one bus? Because mixing time-critical note events with bulk control polling on a single I²C bus would couple their timing and inherit I²C’s clock-stretching quirks on the RP2350.4 Keeping them separate is the single most important architectural decision in Auvra.

The target is a measured key-to-sound latency below 10 ms. The following unverified estimate applies to the bench USB path only; PCIe, converter and scanner contributions must be measured separately for the integrated card.5

Stage Typical Notes
Keybed contact → scan detects make 0.2–1 ms Depends on scan rate (target ≥ 1 kHz full-matrix).
RP2350 processing + USB-MIDI frame 0.5–1 ms USB FS frame jitter ≤ 1 ms.1
Host MIDI handling → synth voice start < 0.5 ms RT-scheduled MIDI thread.
Synth DSP one audio period 1.3 ms 64 frames @ 48 kHz.6
Audio interface output buffer (RTL) 1.3–2.7 ms Device + driver; see 04.
Total (key→sound) ≈ 4–6 ms Comfortably below the 10 ms threshold.
sequenceDiagram
    participant K as Key contact
    participant M as RP2350 scanner
    participant U as USB-MIDI
    participant S as Synth engine (N100)
    participant A as Audio interface
    K->>M: contact make/break (velocity timing)
    M->>U: Note-On (note, velocity)
    U->>S: MIDI event (≤1 ms frame)
    S->>S: allocate voice, render 1 period (64f ≈ 1.33 ms)
    S->>A: audio buffer
    A-->>K: balanced analog out (audible)
    Note over K,A: budget ≈ 4–6 ms total

How the N100’s real ports are allocated:

N100 port Used by
HDMI Touch display video
USB (×1) Touch display touch (USB-HID)
USB (×1) Keybed scanner (USB-MIDI)
USB (×1) USB→I²C bridge (control surface)
USB (×1) Audio interface (if USB)
PCIe 3.0 x4 (x2) Free in the bench setup; allocated to the selected Auvra FPGA card for integrated hardware (17)
M.2 (M-key) NVMe boot SSD
19 V DC-in System power

The board has 4× USB 3.2 Gen1 + 8× USB 2.0,7 so USB device count is not a constraint. A small powered USB hub is optional for tidy internal wiring.

Failure Designed behaviour
Control-surface node drops off I²C Synth keeps playing; UI flags the node; no audio glitch (separate plane).
USB-MIDI scanner disconnects Keys stop; UI warns; reconnect is hot-pluggable.
Power loss mid-use Immutable rootfs → clean boot next time; only unsaved patch edits lost (writable partition).
Audio xrun (buffer underrun) Logged; if frequent, UI suggests raising buffer; see RT tuning in 03.
  1. MIDI Association, “Jitter and latency: USB/FireWire/Thunderbolt.” https://midi.org/community/midi-connections/jitter-and-latency-usb-firewire-thunderbolt ↩ ↩2

  2. DIN-MIDI/UART worst-case jitter ≈ 32 µs vs ~500 µs average for USB-MIDI. “MIDI throughput, latency & jitter.” https://calcsandcomps.blogspot.com/2021/10/midi-throughput-latency-jitter.html ↩

  3. Linux kernel, “i2c-i801” driver docs (SMBus reserved for SPD/sensors). https://docs.kernel.org/i2c/busses/i2c-i801.html ↩

  4. RP2040/RP2350 hardware I²C clock-stretch limitations. MicroPython issue #8167. https://github.com/micropython/micropython/issues/8167 ↩

  5. Round-trip audio under ~10 ms is generally imperceptible to players. See 03-realtime-os.md. ↩

  6. 64 frames @ 48 kHz = 1.33 ms/period; ≈ 2.7 ms round-trip on a tuned RT kernel. LinuxMusicians, “lowest latency PipeWire or JACK.” https://linuxmusicians.com/viewtopic.php?t=27901 ↩

  7. ASRock, “N100DC-ITX” specification. https://www.asrock.com/mb/Intel/N100DC-ITX/index.asp ↩