i2cDACFast.cpp

This sketch talks to a MCP4725 digital-to-analog converter (as sold in the Sparkfun breakout board at http://sparkfun.com/products/8736). This version uses the 'fast mode write' feature of the MCP4725, which allows the DAC to be updated with only two bytes (and two ACK bits) sent on the I2C bus.

Contrary to some claims around the web, with the fast mode write the MCP4725 can produce credible, if low-fidelity, audio output. For example, see the demo at http://www.youtube.com/watch?v=lAZ0fpSPscw, which uses fast mode writes -- although it also uses quite a bit more and more complex code than is shown here.

Furthermore, the sample rate can be nearly doubled over the 11.025KHz used in that demo, while staying within the 'official I2C' clocking range, and it also appears to be possible to drive the MCP4725 with an I2C clock significantly above 400KHz without obviously ill effects.

/*                                             -*- mode:C++ -*-
 *
 * Sketch description: Demonstration of driving an MCP4725 DAC via
 * I2C, using 'fast mode writes'.  This sketch makes a fairly
 * plausible (and annoying) alarm sound, generating sawtooth waves
 * that repeatedly sweep upward in frequency (with the frequency also
 * changing in a sawtooth pattern, hmm).
 *
 * Schematic:
 *  U1: IXM
 *  U2: MCP4725
 *
 *      +--------------+       +--------------+
 *  VSS-|GND   N    U1 |    D3-|VDD     ANALOG|-> To some kind of amp
 *  VDD-|D3            |   GND-|VSS   U2      |
 *  SDA-|Tx   LED      |    RX-|SCL           |
 *      |12V  FACE    E|    TX-|SDA           |
 *  SCL-|Rx            |       +--------------+
 *      |D2            |
 *      |GND   S       |
 *      +--------------+
 *
 * Sketch author: Dave
 *
 */

#define I2C_ADDR 0x60  // MCP4725

SFBHWI2C i2c(I2C_1);   // Create object 'i2c', set up for I2C controller 1

u32 nextLevel = 0;     // Sound level we're currently sending

// INTERRUPT LEVEL: I2C 'next byte' function.
u32 i2cByteSource(int bytes) {
  u32 ret;
  if ((bytes&1)==0) {           // Every other sample, get new level
    u32 step = ((bytes>>8)&0xff)+70; // Determine current frequency bump
    nextLevel = (nextLevel+step)&0xfff;
    ret = (nextLevel>>8)&0xf;   // Get high four bits to send
  } else
    ret = nextLevel&0xff;       // Get low eight bits to send

  return ret;
}

void setup() {
  pinMode(WEST_D3_PIN,OUTPUT);         // The DAC draws little power,
  digitalWrite(WEST_D3_PIN,HIGH);      // so we feed it off an output pin..

  i2c.init(I2C1_PINS_WEST_TX_RX,400);  // Range is officially 100..400KHz,
                                       // but higher values also work
                                       // in this sketch (e.g., 800KHz)
  i2c.setByteSource(i2cByteSource);    // i2c will call this for each byte
  i2c.transmit(I2C_ADDR, 0, 0);        // Start an I2C transmission
}

void loop() {
  ledSet(NORTH_LED_PIN,millis()&0x40);      // Of course need heartattack-
  ledSet(SOUTH_LED_PIN,!(millis()&0x40));   // inducing 'law enforcement'
  ledSet(BODY_RGB_RED_PIN,millis()&0xc0);   // lights to go with..
}

#define SFB_SKETCH_CREATOR_ID B36_4(d,a,v,e)
#define SFB_SKETCH_PROGRAM_ID B36_5(a,l,a,r,m)
#define SFB_SKETCH_COPYRIGHT_NOTICE "2011 Dave Ackley Placed in the public domain"

Generated on Fri Apr 22 06:54:10 2011 for SFB by doxygen 1.5.9