draft: false Name: GBA PSG Voice short-description: "Boots a cartridge-less Game Boy Advance over the pulse jacks via BIOS Multiboot, then plays it as a chiptune synth voice with the whole sound editor on the GBA's own screen" Language: C++ (Pico SDK + ComputerCard) + C (GBA payload) Creator: Andy Jenkinson (uglifruit) Version: 1.0.3 Status: Released License: MIT repository: https://github.com/uglifruit/89_GBA Editor: none date-created: 2026-07-04 date-updated: 2026-09-20 contact: social: github: https://github.com/uglifruit uf2: - path: UF2/gba_link.uf2 name: GBA PSG Voice 1.0.3 tags: - gba - link-cable - multi-boot - chiptune - psg - synth-voice - drums - screen - quantiser summary: | GBA PSG Voice turns the Workshop Computer into a Game Boy Advance link-cable master and the GBA into a synth voice you play from the rack. No cartridge, no flashcart, no modification to the console: the program is uploaded from the module every time you switch on, in about six seconds. Full guide in README.md.

THE CABLE. Use a GAME BOY COLOR link cable, not a third-party GBA one. The connector has been the same six-pin part since the Game Boy Pocket so it fits a GBA, and GBC cables are normally 6-CORE - every pin has a wire behind it. Third-party GBA cables often carry only the three or four conductors that cable's intended use needed, and which three varies between production runs, so a signal you need can simply be absent. That fault looks exactly like bad wiring. (The old DMG-era cable, with the big connector, will not fit.)

Cut one end off and wire it to the pulse jacks, common ground, with 1k series resistors on the two lines the module drives:

Pulse Out 1 -> GBA pin 5, SC (clock) 1k
Pulse Out 2 -> GBA pin 3, SI (data in) 1k
Pulse In 1 -> GBA pin 2, SO (data out) NO resistor
ground -> GBA pin 6, GND

Pin 1 is 3.3V the GBA SOURCES - leave it floating. Pin 4 is unused. NO RESISTOR ON SO: Pulse In 1 is a transistor gate input whose pull-up biases the stage, and a series resistor fights it. The two that are there protect the console: the pulse outputs swing to about 6V and the GBA's inputs are 3.3V logic.

Terminate it on a breakout so the resistors cannot be left out by accident - a female link socket, or the board at https://oshpark.com/shared_projects/srSgm3Yj with the two 1k resistors soldered on.

THE CROSSOVER. Peer-to-peer link cables generally swap SO and SI between their two ends, and you cannot tell the ends apart by eye. Do not reason about it: build and flash the cablecheck diagnostic (see diagnostics/) and run MODE 0, which listens on Pulse In 1 and Pulse In 2 at once and reports which wire actually carries SO. If crossed, swap the two data wires at the Workshop end; SC and GND stay put. The failure this prevents is silent - everything looks wired and the GBA simply never sees a valid sync word.

POWERING UP. Computer first, then the GBA - the console only syncs if the master is already clocking when it boots. Cartridge removed, on the logo screen. LED 0 blinks while it looks for a console; LEDs 1-5 sweep as a progress bar during the upload; the GBA's screen goes plain green, which is the payload's own code running and your proof it worked. LED 0 goes solid.

POWER-CYCLE THE GBA WHENEVER YOU RE-FLASH THE WORKSHOP. A console already running a payload never answers a multiboot sync, so the host retries for ever: LED 0 blinking, LED 1 lit. This catches everyone once, and it is not a wiring fault.

If it fails, LEDs 1-3 hold the last result as a 3-bit code: 1 = nothing answered, 2 = handshake failed, 1+2 = transfer error, 3 = CRC mismatch, 1+3 = bad payload. Work down BENCH.md, which isolates one thing at a time.

SOUND comes out of the GBA's HEADPHONE JACK. It is around 1 Vpp against Eurorack's 10 Vpp, so it will be quiet - straight into a mixer channel. The original AGB-001 has a headphone socket; the GBA SP does not and needs the official SP adapter, whose ground can short the signal against a shared ground - use a ground-isolating cable if that happens. The Game Boy Micro uses a different, smaller link connector and needs an adapter to take this cable at all.

PLAYING. It boots playing something: a hard-panned square pair with a sine shimmer over the top, triggered by the module's own switch, so it makes a sound with nothing patched. CV In 2 is 1V/oct pitch, the Main knob rides channel 3, X and Y are attack and release. Pulse In 2, CV In 1 and the Audio Ins are deliberately unassigned - nothing should move that you did not patch. All four jacks, the three knobs and the switch's UP position are assignable on the GBA's MAP page, each with its own set of per-voice tickboxes. Audio In 1, Audio In 2 and CV In 1 can also be armed as TRIGGER sources on the TRIG page, alongside Pulse In 2, the switch and a GBA button - they fire on a rising level, so loud audio or a gate works and a drifting CV does not. Off by default, like everything else that has to be patched to matter.

CV Out 2 is the quantised note as calibrated 1V/oct, so setting a scale on the SET page turns the pair into a quantiser for the rest of the rack. Audio Out 1 and 2 send the GBA's A and B buttons back out as gates, so a performance gesture can drive another module.

THE EDITOR. START opens it on MEM - patch recall is the one editor action that happens mid-performance, so it is one gesture away - and SELECT + Left/Right walks the eleven pages: MEM, CHAN, TRIG, ENV, MIX, BTN, MAP, ORN, DRUM, CAL, SET. Editing is A + D-pad throughout; inside a menu no button carries its performance meaning.

THE CAL PAGE trims the CV input scale and offset. The module's CV OUTPUTS are factory calibrated from its EEPROM, so the quantised pitch out is in tune for free, but the CV INPUTS are not calibrated at all - so 1V/oct tracking on CV In 2 has to be trimmed once. The page carries a live tuner: an IN line reads CV In 2's raw voltage straight through the current calibration, note name plus cents, and an OUT line shows the note actually sounding - so with a sequence patched in you can watch both at once and trim CV SCALE/OFFSET until IN reads true and OUT matches it.

PATCHES. Sixteen slots on the card itself (MEM page: A+UP saves, A+DOWN loads). The GBA's own RAM is wiped when it is switched off, so the Workshop is where a patch persists. Saving erases a flash sector, which briefly stops the audio - expect a click. panel: inputs: - id: CVIn2 name: Pitch description: 1V/oct pitch CV. Trim tracking on the GBA CAL page (CV inputs are not factory calibrated) - id: PulseIn2 name: Gate description: Gate and trigger. Edges shorter than the 1ms poll are still caught - id: CVIn1 name: Mod 1 description: Unassigned by default - nothing should move that you did not patch. Give it a job on the MAP page, or arm it as a trigger source on the TRIG page - id: AudioIn1 name: Mod 2 description: Unassigned by default; assignable on the MAP page with per-voice tickboxes, or armable as a trigger source on the TRIG page - id: AudioIn2 name: Mod 3 description: Unassigned by default; assignable on the MAP page with per-voice tickboxes, or armable as a trigger source on the TRIG page - id: PulseIn1 name: GBA SO (MISO) description: Serial data back from the GBA. Read directly via PIO, not the 48kHz pulse path outputs: - id: PulseOut1 name: GBA SC (clock) description: Master serial clock driven by the RP2040 (PIO), inversion handled in hardware - id: PulseOut2 name: GBA SI (MOSI) description: Serial data to the GBA (payload upload, then the live input stream) - id: CVOut2 name: Quantised pitch description: The note the GBA is sounding, as calibrated 1V/oct. Turns the pair into a quantiser for the rest of the rack - id: CVOut1 name: Gate out description: 5V while a note is sounding - id: AudioOut1 name: A button gate description: High while the GBA's A button is held - the performance gesture as a patchable voltage - id: AudioOut2 name: B button gate description: High while the GBA's B button is held controls: knobs: - main: name: Level (Ch. 3) description: Level of channel 3 by default; assignable on the MAP page x: name: Attack description: Attack, both envelopes together, by default; assignable on the MAP page y: name: Release description: Release, both envelopes together, by default; assignable on the MAP page switch: down: name: Trigger description: Momentary down fires a note; a column of the GBA's TRIG grid up: name: Modulation description: An eighth source on the GBA's MAP page - assign it to anything. Up is full, middle and down are zero leds: - display: list items: - id: LED0 name: Link (solid booted, blinking connecting) - id: LED1 name: Gate in / upload progress / fault code bit 0 - id: LED2 name: Note sounding / upload progress / fault code bit 1 - id: LED3 name: Editing on the GBA / upload progress / fault code bit 2 - id: LED4 name: Edit page bit 0 / upload progress - id: LED5 name: Edit page bit 1 / upload progress