08/Hardware
The Board, As Built
This page is the electrical ground truth for Alchemy Lab.
Ten jacks, three kinds
J1, J2 are the codec audio inputs, AC-coupled. The coupling blocks DC, so absolute voltage cannot be read, but edges pass cleanly: clocks and triggers work through RisingEdge() with a settable threshold. A module that doesn't process input audio can use them as trigger inputs (clock and reset being great use cases) and keep the switchable jacks free.
J3 to J8 are the field-programmable jacks. Each defaults to CV input; EnableCvOutput() closes an analog switch that routes a backing DAC to the jack, and DisableCvOutput() hands it back. Set the direction at boot, or flip it live from a settings option, a gesture, or the patch itself. No reset required.
J9, J10 are the codec audio outputs, DC-coupled. EnableCvOutput() claims that channel from your audio callback and fills it with the SetVolts() target every block: 24-bit up to 96khz CV, the highest precision on the board.
| Jack | Type | Out bits | Out latency | In bits | How to change |
|---|---|---|---|---|---|
| J1 J2 | codec in, AC | n/a | n/a | 1 (edges) | SetTriggerThreshold(v) |
| J3 - J6 | switchable | 12 | ~70 µs (I²C DAC) | 16 | Enable/DisableCvOutput() |
| J7 J8 | switchable | 12 | <1 µs (STM DAC) | 16 | Enable/DisableCvOutput() |
| J9 J10 | codec out, DC | 24 | audio block | n/a | Enable/DisableCvOutput() |
All outputs swing ±5 V at the panel. Inputs read through Volts() at audio rate. For outputs, the tradeoff between J3-J6 and J7-J8 is capacity against speed: four jacks behind an I²C DAC, two behind the near-instant STM DAC. But realistically, none of the latency matters.
Self-calibration
Every production board calibrates its own six CV jacks, DAC out and ADC in, using the built-in DAC→jack→ADC loopback against the MCU's factory voltage reference.
Unpatch the CV jacks, hold B1+B2 while the board resets, and the panel narrates the ~15 second sweep, flashing green on success. The result is a 120-byte record in its own QSPI sector that survives reflashing: calibrate once, and every firmware picks it up automatically. SetVolts() and Volts() apply it transparently; hw.IsCalibrated() tells you a record exists.
Bootloader and update mode
The board runs a board-specific fork of the Daisy bootloader that serves DFU on the front-panel USB-C and renders its state on the rings: a warm-white comet during the ~2 second boot window, a slow breathe once latched into update mode by B3. It is open source like everything else.
Firmware can also jump there without hands on the panel:
daisy::System::ResetToBootloader(
daisy::System::BootloaderMode::DAISY_INFINITE_TIMEOUT);
HostLink's reboot command uses exactly this, which is how the browser can update a module end to end.
Expansion header
The rear header exposes eight Daisy Seed pins (B1 to B8) carrying SPI1, an I²C bus, and USART1, plus power. Official expanders will use it; until then be careful, and develop at your own risk.
| Pin | Signal | Pin | Signal |
|---|---|---|---|
| 1 | −12 V | 11 | +12 V |
| 2 | GND | 12 | GND |
| 3 | B2 | 13 | GND |
| 4 | B4 | 14 | GND |
| 5 | GND | 15 | 3V3A |
| 6 | B6 | 16 | GND |
| 7 | B5 | 17 | GND |
| 8 | B3 | 18 | GND |
| 9 | B1 | 19 | GND |
| 10 | B7 | 20 | B8 |