MCP4822 as a quantizer DAC -- intrinsic limits

I am currently working on a quantizer based on Arduino using the MCP4822 which I happen to have stocked. It is a 12bit DAC with an internal voltage reference, in contrast to the MCP49xx family which support external voltage references.

It’s currently work in progress and I have not fully defined what kind of features I’d like to implement but for sure, I want to provide an interface which allows me to select between scales or maybe even select individual semitones.

To understand the capabilities, I did some measurements and now working on a calibration procedure for the MCP4822, which you might be interested in, so I thought I share my findings. I also consider integrating the calibration process into the module, but let’s see :wink: When it’s finished, I’ll polish it up and put it on my website.

I measured the output voltage for a whole bunch of digitally set input voltages from 0 mV to 4000 mV in 50 mV steps. The library I used to talk to the MCP4822 is the one written by Steve Gkountouvas MCP48xx DAC Library.

Here is the result:

output voltages

The differences are quite subtle and more visible in the plot below where I subtracted the measured from the expected voltage. There is a clear correlation of the error with respect to the target voltage so I did a simple linear fit and also a polynomial fit:

calibration fit

The fit parameters can then be used to calculate the offset voltages which are then taken into account when setting the output voltage on the MCP4822. The calibrated voltages are now looking like this when applying the simple linear fit regression:

calibrated output voltages

and the differences are now nicely centred around 0mV:


The MCP4822 I am using here can only output around 4030 mV. I am using 4000 mV to avoid some edge effects. If these 4 V are used for 4 or 5 octaves, we of course have different errors in the notes. In case of 5 octaves squeezed into 4 V, the semi-tone step is 66.67 mV. For 4 octaves we have the usual 83.33 mV.

In terms of “cents”, this means that after the calibration using the linear regression, I get around 1.87 cents mean error (standard deviation) for 4 octaves and 2.34 cents for 5 octaves. I think this should be more or less fine, but I have to hear it myself.

Here is the final calibration results showing the errors in cents using the 4 and 5 octave configuration:

final calibration errors

Overall I think that’s fine, but I’d love to hear your comments. It’s possible to improve the results even more using the polynomial model but for now I just stick to the simple linear model since that one can also be tuned via two trim-pots, so that there isn’t even a need to modify the firmware (updating the coefficients) for a proper calibration.

Btw. the input ADC of the Arduino has 10bit, so that’s more than enough to catch the note with an error of 4.88 mV which is roughly 6 cents of an error.

I will now sketch the schematics.

Any kind of feedback is very welcome!


I used a 4822 in my MIDI/CV, and wrote up some stuff about error, in case you haven’t seen it:

Here it’s shooting for a 7.25 octave range (88 notes) using amplification after the DAC.

It’s generally accepted that the threshold for distinguishing pitch differences with a trained ear is about 3 cents, so from that perspective what you’ve got is probably fine — maybe those 6 cent peaks are something to be concerned about if you’re being a perfectionist. (Note that a separate issue is beat frequencies for notes played together, and those can be audibly different for notes whose frequency difference varies across less than 3 cents. But in most circumstances I think that’s not a concern.)

Of course if you swap in a different chip you’ll get a different calibration; I tried two and one was decidedly better than the other.


Nice write-up.

The non linear behaviour is probably temperature dependant too I guess, but probably fairly flat over reasonable temperature ranges.

The data sheet shows using two channels for ~ twice the resolution - is this something you’d considered?



Yes indeed, I just found that section (totally missed to scroll through), that’s a totally valid point, I’ll definitely do that :slight_smile: thanks for pointing it out.

@analogoutput ah thanks! I was remembering that you have done some studies but could not find it. Thanks for the link! It seems you have found the same “drift”.

…also regarding the perception when playing notes simultaneously, yes I know that the ear is better in comparing frequencies but was not sure about the absolute limits. 3 cents is obviously a good limit for monophonic then :slight_smile:

1 Like

As I think you can tell from the earlier discussion, the resolution’s really not a problem. For a perfectly linear 12 bit DAC with correct scaling, the errors are minuscule. (1 LSB for 7.25 octaves corresponds to about 2 cents.) The much larger problem is DAC nonlinearity. Integral nonlinearity for the 4822 can be several LSB.

As for temperature dependence, part of that (I guess most of it) would be the voltage reference temperature coefficient which is 50 ppm/°C.


Man, i leave regression at work, but its really cool to see this LOE for DAC calibration. Is the idea to use your model to correct errors on the arduino? You could absolutely take the results of this regression and bake in offsets to correct for error. Am i understanding your intent here, or is it to measure the error to see if this is viable?

The error doesnt seem to be bad enough to justify error correction, its like what 2 cents?

1 Like

Yep! Actually I did use the model and what you see in the last plot is already the calibration applied in the Arduino code directly, so I am showing the actual corrected outputs after doing the manual calibration + fit beforehand. It works really nicely.

It is obvious that with a polynomial fit (I used 5 coefficients) it’s much better but I thought I’ll go with a linear one and the two parameters could easily be tuned by two trim-pots, meaning that you don’t even need to recompile the software with the new calibration parameters. Of course this means that there still needs to be a calibration process, but that’s trivial.


You could have an input button that calls a routine to calibrate and store the results to eeprom right?

Exciting stuff though for sure. Whats the RMSE and R2 of the resulting output if you dont mind me asking?

There is a trick that sometimes works which is to create a quadratic component of time to fit your regression upon. You can do that just by taking your time value and multiplying it by itself.

Fit the regression model on both time and quad_time and you will get something like a polynomial fit, but much faster calculation with less variables.

1 Like

One thing I’ve worried about is that when I was calibrating my MIDI/CV, what I was essentially measuring was not the nonlinearity of the DAC but the nonlinearity of the combination of the DAC and the voltage measurement. In my case I was measuring outputs with a fairly cheap handheld multimeter, and I have no idea how linear, or not, it is.

I think it’d be possible to do an accurate calibration in which you measure differential voltages and average out the measurement nonlinearity by adding bias voltages, but that gets complicated…


Complicated and possibly more precise than we need right? We arnt sending people to the moon! :smiley:

1 Like

Yep, or just leave the two trim-pots on two analog inputs :wink: the ranges needs to be tweaked beforehand, so I’d need a handful of chips to figure out the min/max slopes and offsets to achieve an optimal precision from the 10bit input ADCs.

I have not calculated the RMSE/R^2 but the STD was 1.56 mV (1.87 cents with 4 octaves). I am now sitting on my recording desk so don’t have the Jupyter notebook at hand, but I can have a look tomorrow.

Actually the poly fit is very good as you can see above and even the linear one was more than accurate enough. I don’t care about the calculation speed as this procedure only needs to be done once or so per chip :smiley: but I already use Julia for high-performance computing :joy:

Yes I agree with @analogoutput I have a fairly well calibrated DMM though. I can check next week in my lab at the university where we have DMMs in the mid-4-digit-cost-range :see_no_evil:


I’ve long been thinking about auto CV calibration, and I reckon the only way to reliably do it is with a closed loop and a frequency counter.
I.E. hook the CV source you want to calibrate up to the VCO you want to control, and then fire out a few dac values and count the actual frequency you’re getting back - that way you calibrate the system.
I think it would be pretty feasible with typical synth waveforms to have a zero crossing detector, some interrupt driven counter or even a schmitt trigger into a counter IC or something like that.
I wish I could provide concrete details etc, but alas, it is yet another idea on the list of things I want to look into but haven’t.


That of course presumes you only ever want to use that CV source with that VCO and only that VCO (or that the nonlinearities of the VCOs are negligible)…

The MI Module Tester has a frequency counter function, so certainly it could be done.


Yeah - you’d want a button on the front to do calibration so it would be fairly easy to recalibrate if you changed the patch. I guess the question is “what use is a perfectly linear DAC if what you’re driving is non-linear?”. I mean, if you’re not using it as a volt/octave source, you don’t care - but if you are, are you sure that the thing you’re driving is responding to v/oct as it should?


And if you’re driving two things with it simultaneously, well, what can you do? Not much.

And here again maybe the correct response is “it’s good enough, let’s not go nuts trying to make it perfect”.


I’m over here looking at my r2r ladder I’m using for a dac cause I’m too cheap to buy a chip. I haven’t used it for anything but smoothing a sine, but it does do that pretty well, and that’s audio frequency.

My definition of pretty well may not suit everyone or every purpose, but it is pretty neat to get even similar results from a bunch of resistors.


Hey, @tamasgal ! Did you finish this quantizer project? I would be interested in the calibration procedure/code with the trim pots :slight_smile:

Sorry @sebastian for the late response, I was very busy with work and travel during the past weeks, so I had little time working on this project. I still use the prototype, which I calibrated manually (no trimpot feature added yet) using the linear regression fit and it works really good. The firmware still has a funny bug: I need to add hysteresis :laughing: to avoid the wiggles you hear in this video, in which I also have a knob to select the scale-type. Different scales are represented by different LED colours (blue is blues, yellow is octave, …) :

I still have to check the double precision setup as suggested by @jaradical though, but not in the next few weeks. Currently I only have time to play the synth to free up my head :see_no_evil:


Nice! No worries! I have decided to go with the Kassutronics PWM output for my quantizer for now, but maybe I will try a 4822 again… xD