Eurorack CV Calibration Without Test Equipment
alchemy-lab · alchemy-sdk · hardware-design

Most Eurorack modules that care about voltage accuracy are calibrated on a bench, by someone with a meter and a small screwdriver. The Alchemy Lab calibrates itself. With nothing plugged in, hold both buttons and boot any Alchemy Lab firmware. Enjoy the animation, and you have a calibrated module; it measured every CV jack on the panel, fit correction coefficients to what it found, and wrote them to flash. Most importantly, I don't have to get modules shipped back to me for re-calibration.
This post is about how it works and the story of how I didn't set out to build it.
Eurorack Jacks (generally) go One Direction
We've got to do work to get hot Eurorack signals into our microcontroller (reading with an ADC) and vice versa (via a DAC). An output needs a driving stage that can hold its voltage steady for downstream ingesters. An input needs a stage that protects it and presents a high enough impedance not to load the source. And both need levels shifted safely and precisely. Those are different literal physical analog circuits.
Between a DAC and jack, that circuit is a chain of analog parts, each of which has a tolerance. On the Alchemy Lab, an op amp stage maps the DAC's 0 to 3.3 V output onto the ±5 V that Eurorack expects. Ordinary resistors, the op amp's own offset, and a supply rail that is near 3.3 V rather than exactly 3.3 V stack up to accumulate error. How much error?
Millivolts are easy to shrug at, let's convert to 1 volt per octave. For the unfamiliar, this is the standard: raise a control voltage by exactly one volt and the oscillator receiving it should be calibrated to play one octave higher. An octave is twelve semitones, which puts one semitone at about 83 mV, and one cent, a hundredth of a semitone, at about 0.83 mV.
Against that scale, 300 mV of uncalibrated error is three and a half semitones. So, you calibrate each individual unit. Trimmers behind the panel work, with a meter, a screwdriver, and a manual explaining which trimmer does what. Factory bench calibration works, and it happens once before shipping. It's all a pain in the ass.
Whoops all jacks
Six of the Alchemy Lab's ten jacks are field-programmable: each carries a full output stage and a full input stage, and firmware picks the direction at runtime. I built that so the panel could repatch itself, a delay wants six CV inputs, a sequencer wants pitch outputs, same panel.
The switch that flips direction only exists on the output side, between the DAC's driver and the jack. The input stage is high impedance, so it never needs to disconnect from anything; it stays wired to the jack and reads whatever is there. Enabling an output just means the DAC starts driving a node the ADC never stopped watching.
So every board ships with an accidental calibration tool built in. Each of those six jacks can generate a voltage and then measure what actually came out of itself. It took me a while to even realize I could do this feature, because of this next point...
Two references
We need definitive points of reference to do this calibration, and the module can source two with nothing patched in. The first is 0 V, provided by the input jacks themselves: an unpatched jack rests at ground.
The second comes from a more interesting place. The obvious objection to a self-measuring module is that its DAC and ADC could share a scale error and agree with each other anyway, so an absolute yardstick has to come from outside that loop. ST supplies it: every STM32 carries an internal voltage reference that gets measured on their production test equipment and the result is burned into ROM. Read the live reference through the ADC, compare it to the burned-in value, and you get the board's actual supply voltage, which sets the scale for every reading after it. The module inherits the accuracy of ST's factory gear, which is far better than anything I own.
The sweep
From there it's easy. For each jack in turn the module closes the output switch, steps the DAC through seventeen codes across its full range, and averages five hundred readings at each one. A least-squares line through those points is the calibration: that jack's true gain and offset, which the SDK inverts every time firmware asks for volts.
The fit also finds the bottom and top ends. Near the rails the output stage runs out of headroom and compresses, so the outermost points that fall off the line are excluded and the usable range is stored per jack.
Each knob ring maps to a jack and fills as its sweep runs, parking on dim green when that jack passes. Three green flashes means everything passed and the record is written; release the buttons and the module reboots calibrated. A red panel with one ring blinking bright red means that jack failed its sweep. A previous calibration survives a failed attempt, because the record is only rewritten after all six jacks pass.
Just do it once
The result is 120 bytes: gain, offset, usable range, and zero point for each jack, plus the measured supply voltage, written to a flash sector that firmware images never touch. Echoa, Spagyros, and anything you build on the Alchemy SDK read the same record through the same calls without knowing it exists; volts in and volts out are simply correct. A board with no record falls back to design-nominal constants.
Steal it
The whole procedure is MIT-licensed in v2_factory_cal.cpp, next to the acceptance firmware I use to check boards against a scope. If you're designing hardware where a DAC and an ADC can see the same node, the trick ports. The developer page covers the toolchain, the browser flasher skips it, and Discord is where to tell me what you built.
FAQ
Do I need a multimeter to calibrate an Alchemy Lab?
No. The module drives each jack with its own DAC, reads it back with its own ADC, and takes its absolute reference from the factory-measured voltage reference inside the processor. All you do is unplug the CV jacks.
Does reflashing firmware erase calibration?
No. The record sits outside the region firmware images occupy, so it survives USB flashing and the browser flasher alike. Every SDK firmware you run afterward picks it up automatically.
What happens on a board that has never been calibrated?
It works, just at hardware tolerance instead of calibrated accuracy, roughly 3 to 5 percent of full scale. The SDK falls back to design-nominal constants, and firmware can ask whether a real record was found and tell the user.