06 — Control Surface
The control surface is everything the player touches except keys: knobs (pots), motor-faders, buttons/switches, and LEDs. The RP2350/MCP2221A design below is the software MVP and bench path. The selected product integration brings touch and control events through the Tang FPGA/PCIe card; it does not assume every S90 control is natively I²C.
1. Bench topology
Section titled “1. Bench topology”flowchart TB
subgraph HOST["N100 host"]
direction TB
DRV["userspace control daemon"]
DEV["/dev/i2c-N"]
BR["MCP2221A<br/>USB→I²C bridge<br/>(master)"]
DRV --- DEV --- BR
end
BR -->|"USB"| USBP["host USB port"]
BR === BUS{{"I²C bus SDA/SCL + 3.3 V + GND"}}
BUS --- N1["RP2350 node A @0x10<br/>pots + buttons + LEDs"]
BUS --- N2["RP2350 node B @0x11<br/>motor-faders + driver"]
BUS --- N3["RP2350 node C @0x12<br/>buttons + LEDs"]
PU["pull-ups 1k–3.3k<br/>(one pair on the bus)"] --- BUS
- One I²C master = the MCP2221A bridge on the host.
- Each RP2350 node is an I²C target with a unique 7-bit address, exposing a small register map (control values in, LED/fader commands out).
- The host runs a control daemon that polls nodes (~1 kHz), publishes stable
physical ids and raw values over local IPC, and applies LED/fader feedback.
Hardware profiles and synth-target mapping live in the app/core, not the daemon
(
15§3).
2. Host link: USB→I²C bridge
Section titled “2. Host link: USB→I²C bridge”The N100 board has no usable I²C header,1 so the bus is hosted over USB.
| Adapter | Real /dev/i2c-N? |
Speeds | Verdict |
|---|---|---|---|
| MCP2221A | Yes — mainline hid-mcp2221 (≥ 5.7) |
100 / 400 kHz | Primary — driverless, robust, handles clock-stretch.2 |
| i2c-tiny-usb | Yes — mainline | ~50–100 kHz | Alternative; rock-solid but slower.3 |
| CH341A | Out-of-tree | up to 750 kHz | 26-byte msg cap; avoid for production.4 |
| FT232H | Userspace only (no /dev/i2c) |
up to 1 MHz | Fragile on Linux; not recommended.5 |
Choice: MCP2221A — it appears as a normal Linux I²C bus, needs no custom kernel module on the immutable image, and correctly tolerates RP2350 clock-stretching.2 The Adafruit MCP2221A breakout (#4471, ~$7) is a ready board.6
Integrated FPGA topology
Section titled “Integrated FPGA topology”The FPGA owns the physical I/O boundary. Actual I²C peripherals (for example
the selected touch controller or add-on I/O nodes) can attach to an FPGA I²C
master; GPIO/ADC/shift-register or MCU links handle controls that are not I²C.
The S90 keybed is a separate passive matrix and follows doc 05.
The original S90 panel’s wiring and protocols must be measured before assigning
any of its controls to I²C. Versioned, timestamped PCIe event/command queues
connect FPGA input and LED/fader feedback to the N100 daemon; Linux evdev
carries touch and suitable input events. The app’s physical IDs, profiles,
paging and soft takeover remain independent of the transport. The MCP2221A
remains a bench/fallback adapter, not a second concurrent bus master.
3. Node MCU: RP2350
Section titled “3. Node MCU: RP2350”Each node is an RP2350 (Raspberry Pi Pico 2 class):7
- 2× hardware I²C blocks, each configurable as target with hardware clock-stretching — exactly what a bus peripheral needs.
- ADC: 4 channels (RP2350A) / 8 (RP2350B), 12-bit — for reading potentiometers. Use an external analog mux (e.g. 74HC4051/4067) to fan out to many pots per node.
- 3× PIO / 12 state machines — for WS2812 LEDs, extra I/O, or fader PWM.
- Use A3/A4 silicon to avoid the early GPIO pull-down errata.7
Suggested node register map (per node)
Section titled “Suggested node register map (per node)”| Offset | Dir | Meaning |
|---|---|---|
0x00 |
R | node type / capability flags |
0x01 |
R | input-changed bitmap (for fast polling) |
0x10.. |
R | pot values (8/12-bit) |
0x20.. |
R | button states (bitfield) |
0x40.. |
W | LED states / PWM |
0x60.. |
RW | fader target / current position |
4. Bus electrical design
Section titled “4. Bus electrical design”I²C across an instrument chassis is the part most likely to bite. Design rules:8
- Total bus capacitance ≤ 400 pF (Standard/Fast mode). Each device ~10–20 pF; ribbon/Cat5 ~100 pF/m. Keep the bus short and star-free.
- Pull-ups: one pair for the whole bus. ~2.2–3.3 kΩ at 100 kHz with short runs; ~1–2.2 kΩ at 400 kHz. (Min ≈ 1 kΩ at 3.3 V; max set by rise-time/capacitance.)
- Addresses: assign each node a unique 7-bit address (e.g. 0x10, 0x11, …). 112 usable addresses, but capacitance limits you long before that.
- Practical limits: short PCB run → 8–10 nodes @ 400 kHz; ~0.5 m chassis ribbon → 4–6 nodes @ 100 kHz with 3.3 kΩ pull-ups (verify with a scope).
- Long runs / many nodes: insert an I²C bus buffer/extender (TI PCA9517, NXP P82B96) to segment the bus and restore drive.8
- Run the I²C harness away from the 19 V switching and the audio cabling (
08).
5. Motor-faders
Section titled “5. Motor-faders”Motor-faders need three things, all handled at the node:
- Position sense — the fader’s potentiometer → RP2350 ADC.
- Motor drive — a small H-bridge (e.g. DRV8833/TB6612) driven by RP2350 PWM, so the host can recall/automate fader positions.
- Touch sense (optional) — capacitive touch strip so the engine knows when the user grabs a fader (to stop fighting the motor).
The host writes a target position; the node runs a local PI loop to drive the motor there — keeping the motion loop off the I²C bus and off the host.
6. LEDs & buttons
Section titled “6. LEDs & buttons”- Buttons: matrix or shift-register/
MCP23017-style expansion off each node’s GPIO; debounced on the MCU. - LEDs: simple GPIO/PWM, or WS2812 addressable strings driven from PIO for RGB indicators with one data pin.
- The node aggregates all of this into its register map so the host polls one I²C transaction per node per cycle.
Footnotes
Section titled “Footnotes”-
Linux kernel, “i2c-i801” driver docs (no user I²C header; SMBus reserved). https://docs.kernel.org/i2c/busses/i2c-i801.html ↩
-
Microchip MCP2221A; mainline
hid-mcp2221presents/dev/i2c-N. https://www.microchip.com/en-us/product/mcp2221a ↩ ↩2 -
Linux
i2c-tiny-usbdriver. https://github.com/torvalds/linux/blob/master/drivers/i2c/busses/i2c-tiny-usb.c ↩ -
i2c-ch341-usbout-of-tree driver (26-byte message cap). https://github.com/gschorcht/i2c-ch341-usb ↩ -
Adafruit FT232H Linux setup (userspace libftdi, deprecated path). https://learn.adafruit.com/adafruit-ft232h-breakout/linux-setup ↩
-
Adafruit MCP2221A breakout (#4471). https://www.adafruit.com/product/4471 ↩
-
Raspberry Pi, “RP2350 datasheet” (I²C target, ADC, PIO; stepping). https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf ↩ ↩2
-
“I²C design mathematics: capacitance and resistance.” https://www.allaboutcircuits.com/technical-articles/i2c-design-mathematics-capacitance-and-resistance/ ↩ ↩2