MCP4725 and Mozzi – Part 2

So, ignoring the delirium that turned out to be MCP4725 and Mozzi this is using the built-in I2C “TwoWire” support in the Mozzi library to talk to the MCP4725 and generate audio.

Warning! I strongly recommend using an old or second hand keyboard for your MIDI experiments.  I am not responsible for any damage to expensive instruments!.

This builds on the following previous projects:

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

Parts list

  • Arduino Uno
  • 4x 10k potentiometers
  • 1x 110Ω resistor
  • 1x 390Ω resistor
  • 1x 10uF non-polar capacitor
  • 1x Uno Proto Shield or stripboard
  • MCP4725 breakout board (I’ve used the Sparkfun board as described in the previous tutorials)
  • 3.5mm stereo jack socket
  • MIDI receive module (see Arduino MIDI Interfaces)

The Circuit

MCP4725 Mozzi_bb

I’ve wired up four potentiometers to the Arduino A0 to A3 input pins.  Recall that A4 and A5 are required for the I2C link.  The above circuit shows the Adafruit MCP4725 breakout, but I have the Sparkfun board which has SCL and SDA reversed.  Otherwise they are essentially similar boards.

To use the circuit with a MIDI receive device, the MIDI module will need to connect to RX and GND on the Arduino and potentially 5V if power is required too.

Advanced

MCP4725 Mozzi Shield_bb

The above circuit is largely optional, but I took the opportunity to put the four potentiometers and my MCP4725 output circuit (as described in Part 2) onto a home-made shield.  Note for the sake of clarity I’ve not wired up the potentiometers to A0-A3, but of course you’ll need to do that.  I’ve also not added GND and 5V to the second two potentiometers, but I’m sure you get the idea!

I have added a header for a MIDI link though – it connects to the RX and GND.

For my final version, see the photos below.

You might be able to spot that I also added a 5V header to optionally power a MIDI module if required, and added a header on the final stage of the audio out to allow me to easily hook up an oscilloscope.

I’ve turned the MCP4725 around to get it nicely onto the shield, which means that the SCL/SDA pins no longer line up – one has to cross the other (that pink blob in the top right of the second photo is actually the two wires crossing).  The resistors are situated underneath the MCP4725 board – I forgot to take a photo prior to soldering in the board.

Once again I’ve powered the MCP4725 properly from the Arduino 5V, which gives me A2 and A3 back to play with as potentiometers.  If you use the previous circuit rather than a shield, remember that by default it was using A2 and A3 for power.

The Code

It turns out that the key limiting factor in my previous efforts wasn’t having an interrupt-driven I2C driver being called from an interrupt, it was have the code waiting around while the hardware replied.  Mozzi includes a “non-blocking” (i.e. non-waiting-around) version of the I2C library which user “Bayonet” on the Mozzi forums managed to get working with the Adafruit MCP4725 library.

However, on looking at the code, I realised this is quite a thin layer between your own code and the actual I2C implementation, so I just didn’t bother with it and used the “twi_nonblock” Mozzi code directly.

You can see the final thing in my code on GitHub, but the key points to note are:

  • I created two functions dacSetup() and dacWrite() to be called from the main setup() and updateAudio() functions respectively.
  • dacSet() initialises the SCL/SDA pins for IO; calls the initialize_twi_nonblock() function; and finally overrides the frequency used for I2C by programming the hardware TWBR register directly to set it up for 400kHz bus operation.
  • dacWrite() takes a 16-bit value and turns it into the two values to be written out to the I2C bus to send a value to the DAC.  Unlike the Adafruit code, I am using “fast mode” which only requires two writes instead of three.  For details see the code.
  • dacWrite is then called from the updateAudio function.  Whereas the updateAudio function was scaling the sample value for use with PWM, my function now scales it and adds a bias for use with a 12-bit DAC.  This essentially means taking a +/-243 value provided by Mozzi, multiplying it by the envelop (a 0 to 255 value) and rather than then dividing the result by 256 (>>8) to get back to a +/- 243 value, I only divide by  32, but then add 1024 to give me a value in the range 0 to 2048.  Finally I just return 0 rather than the original sample value for PWM.
  • Recall as mentioned above, I’ve now enabled four potentiometer controls and taken out the “use A2 and A3” as power code. If you are using the board from the previous projects you might need to put this back in and drop back down to two potentiomers.

Then find my code on GitHub here.

Closing Thoughts

Mozzi certainly has better fidelity if you use it with a DAC but adding an external DAC to an Arduino is pushing the limits of sound quality.  However it is nice to be able to use the MCP4725 as they are so easily available and fit so neatly onto the Arduino.

For any further experiments with DACs though I think I’ll be digging out my Teensy.  The one exception might be to fire up Mozzi on my R2R shield at some point.

Kevin

Leave a comment