MCP4725 Digital to Analog Converter

After my experiments with Mozzi, one thing I wanted to try was using a dedicated digital to analog converter (DAC), which is something the common Arduinos lack.

After some searching I found the MCP4725 which links up to the Arduino using the I2C bus.  From the datasheet:

“The MCP4725 is a low-power, high accuracy, single channel, 12-bit buffered voltage output Digital-to-Analog Convertor (DAC) with non-volatile memory (EEPROM). Its on-board precision output amplifier allows it to achieve rail-to-rail analog output swing.”

Best of all, both Adafruit and Sparkfun provide a breakout board and supporting example code, details of which you can find here:

Here are the follow-up projects for this board:

These are the key tutorials for the main concepts used in this project:

If you are new to Arduino, see the Getting Started pages.

Parts list

  • Arduino Uno
  • MCP4725 breakout board (I have a Sparkfun board and some equivalents)
  • Breadboard and jumper wires

The Circuit

Both boards have the following connections, which need linking to the Arduino:

  • SCL to A5
  • SDA to A4
  • GND to GND
  • VCC to 5V

Sparkfun has an OUT and GND for the audio output and the Adafruit board has a VOUT.  Both boards have a means to change the I2C address in use, but I’m not getting into that right now.

One nice thing about the layout of the Sparkfun board is that you can plug the SCL/SDA links directly into A5/A4 and then use A3 and A2 as the VCC and GND respectively by setting them up as digital output pins set to HIGH and LOW.  This means that the board will plug directly into your Arduino!

See the Sparkfun tutorial for details.

The output is a 0V to 5V waveform, similar to what you would expect from a direct PWM output we’ve met before which can be fed into a pair of headphones or (sacrificial) amplification.

For simple applications this is as far as you need to go.

Advanced Electronics Bit

(Well, it isn’t advanced if you know your electronics, but I don’t so it is more advanced to me! It is also not strictly accurate, but “hand wavily” close enough for my purposes I believe…)

To convert it to more audio line friendly levels (typically around +/- 0.7V), it is recommended that a resistor voltage divider is used to drop the voltage and an AC coupling capacitor is used to remove the DC bias.

Simplistically, we want to drop the peak 5V down to around 1.1V, but want to keep the current draw within limits for an Arduino output pin (around 20mA peak, aiming for 10mA typical).

Using Ohm’s law, V = IR, this means we want a total resistance of:

R = V / I = 5 / 0.010 = 500Ω

Using the voltage divider equation we can work out

Vout = Vin . R2 / (R1 + R2)

We know R1 + R2 = 500Ω; so we can reframe this as (Vout = 1.1; Vin = 5):

R2 = 1.1 * 500 / 5 = 110

So we can aim for R2 = 110 and R1 = 390.

However, when adding in the AC coupling capacitor I am essentially adding in a high-pass filter, so for a 10uF capacitor, working at a frequency of (say) 20Hz, then using the filter equation (more details here):

freq = 1 / (2πRC)

rearranged, we can calculate a rough equivalent resistance (impedance? reactance? I need to get this straight one day…) for the capacitor of:

R = 1 / (2π * freq * C) = 1 / (2π * 20 * 0.000010) = ~636Ω

So having two “resistors” in parallel (110 and 636) gives a combined resistance of:

R = (R1 * R2) / (R1 + R2) = ~94Ω

So plugging this back into the resistor divider equation gives an output voltage of around:

Vout = 5 * 94 / (390 + 94) = 0.97V

which is a bit less than our target 1.1V, but its close.  When the DC bias is removed this would give just under +/- 0.5V.  Just checking the calculated equivalent current draw from the Arduino IO pin:

I = V / R = 5 / (390 + 94) = ~10mA

Assuming I’ve used the right equations, that’s still ok.  But recall that the effective resistance of the capacitor is frequency dependent too – so I’m going with these values, working on the assumption that it gives me a bit of headroom.  I’m sure there are better ways to do this properly, but as I say I am not really an electronics person.

One key assumption here is that there is no load itself.  Plug in some headphones or a lead to some amplification and things change again…

Illustrating all this with the Adafruit breakout as an example (and using the resistors and capacitors I have to hand):

  • R1 = 110Ω
  • R2 = 330Ω + 61Ω
  • C = 10uF

MCP4725 Output Circuit_bb

The Code

I’ve used the Adafruit MCP4725 library which nicely abstracts away all the I2C bus handling.  Install it in the usual way – open the Arduino IDE library manager and search for MCP4725 and it should come up.

I’ve used the example code for the simple sinewave to check everything is working ok.  As I’m using a Sparkfun board, I’ve had to update it slightly to add in the Sparkfun “A2/A3” hack by adding the following to the setup() function:

// Set A2 and A3 as Outputs to make them our GND and Vcc,
// which will power the MCP4725
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
digitalWrite(A2, LOW); //Set A2 as GND
digitalWrite(A3, HIGH); //Set A3 as Vcc

And then set the I2C address for my specific board:

 dac.begin(0x60);

It is possible to string several of these boards together on the I2C bus, but I’m going into that right now.  You should be able to look up what I2C address your own breakout board uses by default.

The default resolution is set to 8 bits using the line:

#define DAC_RESOLUTION (8)

This outputs a 25Hz waveform which is just on the low end of most human hearing.  The way the example is written means that reducing the resolution increases the frequency.  Losing a single bit of resolution doubles the frequency as follows

  • DAC Resolution = 8 – output frequency is 25Hz
  • 7 = 50Hz
  • 6 = 100Hz
  • 5 = 200Hz

These relate to hard-coded look-up table of sinewaves within the example code.

Closing Thoughts

Here are some photos of the raw and processed outputs.  The scale on the scope is the same, at 1V/div and the yellow arrow on the right shows the zero point.

2020-09-25 13.27.252020-09-25 13.26.14

Getting this far is relatively straightforward (give or take my dodgy electronics knowledge). It should be possible now to take the ideas from the Arduino MIDI R2R Digital Audio and create a controllable wavetable synth.

Another key thing to do next will be to work out how to integrate the external DAC into the Mozzi framework.  There are functions for providing a custom “output the sample value” function, so that is where I’ll go next.

I might also solder up my output stage too to make it a bit easier to use.

Kevin

 

Leave a comment