Skip to content

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.

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).

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

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.

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
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

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).

Motor-faders need three things, all handled at the node:

  1. Position sense — the fader’s potentiometer → RP2350 ADC.
  2. Motor drive — a small H-bridge (e.g. DRV8833/TB6612) driven by RP2350 PWM, so the host can recall/automate fader positions.
  3. 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.

  • 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.
  1. Linux kernel, “i2c-i801” driver docs (no user I²C header; SMBus reserved). https://docs.kernel.org/i2c/busses/i2c-i801.html ↩

  2. Microchip MCP2221A; mainline hid-mcp2221 presents /dev/i2c-N. https://www.microchip.com/en-us/product/mcp2221a ↩ ↩2

  3. Linux i2c-tiny-usb driver. https://github.com/torvalds/linux/blob/master/drivers/i2c/busses/i2c-tiny-usb.c ↩

  4. i2c-ch341-usb out-of-tree driver (26-byte message cap). https://github.com/gschorcht/i2c-ch341-usb ↩

  5. Adafruit FT232H Linux setup (userspace libftdi, deprecated path). https://learn.adafruit.com/adafruit-ft232h-breakout/linux-setup ↩

  6. Adafruit MCP2221A breakout (#4471). https://www.adafruit.com/product/4471 ↩

  7. Raspberry Pi, “RP2350 datasheet” (I²C target, ADC, PIO; stepping). https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf ↩ ↩2

  8. “I²C design mathematics: capacitance and resistance.” https://www.allaboutcircuits.com/technical-articles/i2c-design-mathematics-capacitance-and-resistance/ ↩ ↩2