Add main entry point + systemd services + integration tests
New files:
main.py - PedalApp: boots all subsystems in order,
wires MIDI/footswitch callbacks, graceful
teardown reverses boot order
src/system/config.py - YAML config loader with deep-merge
(separated to avoid hardware deps)
src/system/services.py - systemd unit generator for pedal.service
+ multi-fx-pedal.target
scripts/install_service.sh - copies project, creates venv, installs
+ enables service units
tests/test_integration.py - 41 tests: boot, routing, display sync,
teardown, systemd content, CLI, edge cases
Modified:
tests/conftest.py - add project root to sys.path
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
# MIDI Optoisolator Circuit — 5-pin DIN Input
|
||||
|
||||
## Why Optoisolation?
|
||||
|
||||
MIDI specification (MIDI 1.0, §3.1) **requires** galvanic isolation on the
|
||||
MIDI IN port to prevent ground loops between connected devices. Without it:
|
||||
|
||||
- Hum/buzz from ground potential differences
|
||||
- Possible damage to the Raspberry Pi's GPIO/UART when hot-plugging
|
||||
- Electrical noise coupling into the audio path
|
||||
|
||||
The 6N138 (or compatible H11L1) optoisolator breaks the ground path while
|
||||
preserving the 31.25 kbaud MIDI data stream.
|
||||
|
||||
## Schematic
|
||||
|
||||
```
|
||||
+5V (3.3V for RPi)
|
||||
│
|
||||
┌┤ R2 ─┐
|
||||
│ 270Ω │
|
||||
│ │
|
||||
MIDI Pin 4 ──┬── R1 ──┐├ │
|
||||
(Current) │ 220Ω ││ │
|
||||
│ ││ │
|
||||
┌┴┐ 1N4148 │
|
||||
│ │ ││
|
||||
│ │ ││
|
||||
└┬┘ ││
|
||||
│ ││
|
||||
MIDI Pin 5 ──┴──────────────┘│
|
||||
(Return) 6N138 │
|
||||
│ │
|
||||
│ ├─── Pin 3 (TX) ──> RPi UART RX (GPIO 15)
|
||||
│ │
|
||||
┌┤ │
|
||||
│R3 │
|
||||
│4k7Ω
|
||||
│ │
|
||||
└───┘
|
||||
│
|
||||
GND
|
||||
|
||||
Protection:
|
||||
D1: 1N4148 reverse-protection diode
|
||||
R1: 220Ω current limit (MIDI spec 5 mA loop)
|
||||
R2: 270Ω pull-up for 6N138 output (use 470Ω for 3.3V)
|
||||
R3: 4.7kΩ pull-down to keep UART line low when no MIDI connected
|
||||
```
|
||||
|
||||
## Bill of Materials
|
||||
|
||||
| Component | Value | Notes |
|
||||
|-----------|-------|-------|
|
||||
| U1 | 6N138 | Optoisolator (DIP-8) — use socket |
|
||||
| Alt U1 | H11L1 | Drop-in replacement, faster switching |
|
||||
| R1 | 220Ω | 1/4W, ±5% |
|
||||
| R2 | 270Ω (5V) / 470Ω (3.3V) | Pull-up for opto output |
|
||||
| R3 | 4.7kΩ | Pull-down for UART line |
|
||||
| D1 | 1N4148 | Signal diode |
|
||||
| C1 | 100nF | Decoupling cap near 6N138 (optional) |
|
||||
| J1 | 5-pin DIN | Female chassis-mount (180°) |
|
||||
| J2 | 3-pin header | Connection to RPi GPIO |
|
||||
|
||||
## SixN138 Pinout
|
||||
|
||||
```
|
||||
1: NC (not connected)
|
||||
2: Anode ──┬── R1 ──> MIDI Pin 4
|
||||
│
|
||||
D1 (cathode) ──> MIDI Pin 4
|
||||
3: Cathode ──> MIDI Pin 5 (GND return)
|
||||
4: NC
|
||||
5: GND
|
||||
6: Output ──> RPi GPIO 15 (UART RX)
|
||||
7: Enable ──> GND (always enabled)
|
||||
8: Vcc ──> 3.3V (RPi) or 5V
|
||||
```
|
||||
|
||||
## MIDI OUT (direct, no opto)
|
||||
|
||||
MIDI OUT does not need optoisolation — the Raspberry Pi drives the
|
||||
UART TX directly. Use a 220Ω resistor in series on MIDI Pin 5
|
||||
to comply with the MIDI current loop spec:
|
||||
|
||||
```
|
||||
RPi TX (GPIO 14) ──> 220Ω ──┬──> MIDI Pin 4
|
||||
│
|
||||
GND (MIDI Pin 2)
|
||||
```
|
||||
|
||||
## Raspberry Pi UART Setup
|
||||
|
||||
Enable UART on the RPi 4B for MIDI:
|
||||
|
||||
```bash
|
||||
# Enable UART hardware
|
||||
echo "enable_uart=1" | sudo tee -a /boot/config.txt
|
||||
|
||||
# Disable Bluetooth serial (frees UART from BT)
|
||||
echo "dtoverlay=disable-bt" | sudo tee -a /boot/config.txt
|
||||
|
||||
# For stable 31.25 kbaud on RPi 4B:
|
||||
echo "core_freq=250" | sudo tee -a /boot/config.txt
|
||||
|
||||
# Disable serial console on UART
|
||||
sudo raspi-config nonint do_serial 2
|
||||
|
||||
# Remove console from cmdline.txt
|
||||
sudo sed -i 's/console=serial[^ ]* //g' /boot/cmdline.txt
|
||||
|
||||
# Reboot
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
After reboot, the UART appears as `/dev/ttyAMA0`.
|
||||
|
||||
## Verification
|
||||
|
||||
After hardware is wired:
|
||||
|
||||
```bash
|
||||
# Check UART device exists
|
||||
ls -l /dev/ttyAMA0
|
||||
|
||||
# Connect a MIDI keyboard/controller, then test
|
||||
python scripts/midi_test.py --uart /dev/ttyAMA0 --no-usb --discover
|
||||
|
||||
# Monitor raw bytes (test without pyserial)
|
||||
cat /dev/ttyAMA0 | xxd
|
||||
```
|
||||
|
||||
Expected output on xxd when pressing keys — bursts of 3-byte groups
|
||||
at 31.25 kbaud. Each group is one MIDI message (status + 1-2 data bytes).
|
||||
|
||||
## PCB Layout Notes
|
||||
|
||||
- Keep the optoisolator close to the DIN connector (< 5 cm traces)
|
||||
- Separate MIDI ground from audio ground — single-point star ground
|
||||
- Add a 100 nF ceramic cap between Vcc and GND near the 6N138
|
||||
- Use 6N138 in a DIP-8 socket for serviceability
|
||||
- Route UART TX/RX traces away from I2S audio data lines (GPIO 18-21)
|
||||
Reference in New Issue
Block a user