Document BLE-MIDI add-on: EFM8<->nRF52 custom framed protocol over UART1
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# BLE-MIDI add-on: EFM8 ↔ nRF52 custom framed protocol
|
||||
|
||||
Plan for adding Bluetooth MIDI to the QuNexus by attaching a BLE-MIDI
|
||||
module (bare **nRF52832**, chosen for lowest power / battery-later) to the
|
||||
EFM8's dormant **UART1** — the same pair wired to the empty MIDI-expander
|
||||
jack (**P1.2 / P1.3**, pins 44 / 43). UART1 is never enabled in stock v2.2.1
|
||||
firmware (no `XBR2` write, no `SBUF1`/`SCON1` use), so we reclaim it for BLE
|
||||
without disturbing the DIN-MIDI UART0 or the P2/P3/P4 scan bus.
|
||||
|
||||
See [[EFM8UB20_PINOUT.md]] for the pin map and the port-config block this
|
||||
modifies.
|
||||
|
||||
## Transport: frame everything (SLIP-style)
|
||||
|
||||
MIDI bytes and control commands share one UART, so **both** are carried in
|
||||
framed packets. Escaping means any MIDI byte value (0x00–0xFF) is safe in a
|
||||
payload — no reliance on "undefined MIDI bytes," no collision with real
|
||||
MIDI status/system bytes.
|
||||
|
||||
```
|
||||
END = 0xC0 ESC = 0xDB (ESC_END = 0xDC, ESC_ESC = 0xDD)
|
||||
|
||||
Frame on wire: END CMD LEN payload[0..LEN-1] CRC8 END
|
||||
- CMD, LEN, payload, CRC8 are byte-stuffed:
|
||||
0xC0 -> ESC 0xDC , 0xDB -> ESC 0xDD
|
||||
- LEN = payload byte count (0..255)
|
||||
- CRC8 = computed over (CMD, LEN, payload) *unstuffed*
|
||||
- Receiver collects bytes between END markers, un-stuffs, checks CRC, parses.
|
||||
```
|
||||
|
||||
Baud: **31250 8N1** (matches MIDI; frames are short, throughput is ample).
|
||||
|
||||
## Command set
|
||||
|
||||
```
|
||||
EFM8 -> nRF52
|
||||
0x01 MIDI_TX payload = MIDI bytes to send over BLE-MIDI
|
||||
0x10 ENTER_PAIRING (len 0) start fast advertising / pairing
|
||||
0x11 DISCONNECT (len 0)
|
||||
0x12 CLEAR_BONDS (len 0) wipe stored bonds (force re-pair)
|
||||
0x13 GET_STATUS (len 0)
|
||||
|
||||
nRF52 -> EFM8
|
||||
0x02 MIDI_RX payload = MIDI bytes received over BLE-MIDI (-> inject into router)
|
||||
0x20 STATUS payload = [state, bonded_peers, rssi]
|
||||
state: 0=disconnected 1=advertising 2=connected 3=pairing
|
||||
0x21 EVENT payload = [event_code] (connected / disconnected / bond_added / error)
|
||||
```
|
||||
|
||||
`MIDI_TX`/`MIDI_RX` are just frames whose CMD carries MIDI bytes; the nRF52
|
||||
routes by CMD — `MIDI_TX` → BLE-MIDI TX, control CMDs → BLE stack actions.
|
||||
BLE crypto/bonding is handled **entirely by the nRF52**; the EFM8 only
|
||||
triggers pairing and reads status.
|
||||
|
||||
## Data flow on the EFM8 side
|
||||
|
||||
- **Outgoing MIDI:** hook the existing MIDI-send path (same place DIN MIDI
|
||||
out is fed) to also emit a `MIDI_TX` frame on UART1 — a straight mirror,
|
||||
exactly like the USB-1→CV stub mirrors into the CV ring.
|
||||
- **Incoming MIDI:** UART1 RX ISR parses frames; on `MIDI_RX`, inject the
|
||||
bytes into the router/event buffer — same injection mechanism as the
|
||||
USB-1→CV stub (which injects at `0x8126`).
|
||||
- **Pairing control:** a key combo (detected in the existing key-scan path)
|
||||
→ emit `ENTER_PAIRING` / `CLEAR_BONDS` / `DISCONNECT`.
|
||||
- **Status:** on `STATUS`/`EVENT` frames, set a state byte that the P2 scan
|
||||
ISR reads to drive the LED matrix (blink = pairing, steady = connected,
|
||||
off = disconnected).
|
||||
|
||||
## EFM8 firmware pieces (asm patches in `firmware.asm`, verified by `roundtrip.py`)
|
||||
|
||||
1. **UART1 init:** `XBR2 |= 0x01`, `P1MDOUT 0x3F → 0x37` (RX open-drain),
|
||||
SCON1, Timer3 baud @31250.
|
||||
2. **UART1 ISR:** small frame RX state machine (collect → un-stuff → CRC →
|
||||
dispatch by CMD). A few bytes of state + a small ring buffer.
|
||||
3. **Frame TX helper** (stuff + CRC + END-wrap) used by the mirror and the
|
||||
control commands.
|
||||
4. **MIDI mirror hook + MIDI inject** (reuse the USB-1→CV injection pattern).
|
||||
5. **Key-combo detect → control frame.**
|
||||
6. **LED status** state variable read by the P2 scan ISR.
|
||||
|
||||
The nRF52 side (BLE-MIDI peripheral + this frame protocol) is a separate
|
||||
firmware project — spec'd here, not written in this repo.
|
||||
|
||||
## Phasing (keeps each step verifiable)
|
||||
|
||||
1. **Phase 1 — transport + MIDI:** UART1 + frame RX/TX + `MIDI_TX`/`MIDI_RX`
|
||||
mirror/inject. BLE-MIDI works end-to-end (auto-pair, Model A). Smallest
|
||||
useful mod; proves the UART/framing on real hardware.
|
||||
2. **Phase 2 — control:** add the control commands + key-combo + LED status
|
||||
(Model B pairing). All on top of the Phase-1 frame layer, no rework.
|
||||
|
||||
Both phases are asm patches in `firmware.asm` that round-trip byte-identical
|
||||
against a known-good image (same workflow as the USB-1→CV patch).
|
||||
|
||||
## Safety constraint (hard rule for any firmware mod)
|
||||
|
||||
The bootloader region **0x0000–0x23FF must NOT be erased**; only
|
||||
**0x2400–0xF806** is the app region; **no mass erase should ever be
|
||||
performed.** Firmware is read-only unless explicitly asked to write. See
|
||||
`RECOVERY.md` for the C2 flash reader/patcher constraints.
|
||||
Reference in New Issue
Block a user