Sunday, February 24, 2013

Arduino I2C DAC Array Using MCP4725

The XBee in line passing mode would output signals via PWM.  However, this method is not very good because of the low PWM frequency of the XBee and the need to filter signals introducing additional phase delays on top of transmission times.

To remove this problem, I use an Arduino to receive signals from XBee and send appropriate values to an array of MCP4725 DAC chips.

The MCP4725 chips come with a set address on I2C with just one address bit selectable by the user.  To implement the DAC array, connected the selectable address bits of the DACs on the I2C to digital outputs of the Arduino.  To select one DAC for writing, the Arduino sets its address bit high.  The Arduino is programmed to write to that specific address.

Here is the datasheet for the MCP4725:
http://www.sparkfun.com/datasheets/BreakoutBoards/MCP4725.pdf

All schematic etc can be found here: https://docs.google.com/folder/d/0Byu6zHhzDPqVQlEtMFBaeHRZUlE/edit?usp=sharing

Here is my breakout board for an array of four MCP4725s and a picture of the array on top of the XBee shield from sparkfun:
The green colored board is the DAC breakout.  Blue is the XBee and red is the SparkFun XBee Shield.

The PCB Layout.

The circuit schematic.
The Arduino code is as follows:


#include <Wire.h>

#define BUFFER_LEN 64

// constants
#define START_DELIMITER 0x7E
#define API_ID          0x83

#define PACKET_LEN      0x10
#define N_SAMPLES       0x01

#define MCP4725_ID      0b01100000  

int DAC_BUS_PINS[] = {9,11,12,13};
int N_DAC = 4;

int i, j;

byte buffer[BUFFER_LEN];
byte L12[2];
byte dac_bits[2];

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 115200 bits per second:
  Serial.begin(115200);
  Wire.begin();
  
  
  for (i=0;i<N_DAC;i++)
  {
    pinMode(DAC_BUS_PINS[i],OUTPUT);
    digitalWrite(DAC_BUS_PINS[i],LOW);
  }
  
  dac_bits[0] = 0;
  dac_bits[1] = 0;
}

// the loop routine runs over and over again forever:
void loop() {
  
  int len;
  unsigned char firstByte;
    
  int value, X, Y, Z;
  word adc_val;

  if (Serial.available()) {
  
    firstByte = Serial.read();

    if (firstByte==START_DELIMITER) // start of a packet
    {
      Serial.readBytes((char*)L12,2);
      len = word(L12[0],L12[1]);

      if (len==PACKET_LEN) { // check for API packet of right length
        
        Serial.readBytes((char*)buffer,len);  
       
        //      [ sniff |   X   |   Y   |   Z   ]
        //buffer[  8, 9, 10, 11,  12,13,  14,15 ]
       
        // DAC Communication
        for (j=0;j<N_DAC;j++)
        {
          // adc value
          value=word(buffer[(j*2)+8],buffer[(j*2)+9]);
          //value=word(buffer[8],buffer[9]);
          adc_val = value*4;
   
          digitalWrite(DAC_BUS_PINS[j],HIGH); // address a DAC chip [0b1100011]
          Wire.beginTransmission(99); //99
          Wire.write(0b01000000); // write dac register command [c2 c1 c0 x x pd1 pd0 x]  for write dac c2 = 0, c1 = 1, c0 = 0
          for (i=0;i<8;i++) bitWrite(dac_bits[0],i,bitRead(adc_val,i+4)); // shift bits around for making i2c compatible
          for (i=0;i<4;i++) bitWrite(dac_bits[1],i+4,bitRead(adc_val,i));
          Wire.write(dac_bits[0]);
          Wire.write(dac_bits[1]);
          Wire.endTransmission();
          digitalWrite(DAC_BUS_PINS[j],LOW); // null DAC address to [0b1100010]
        } 
        // END DAC Communication  
      }          
    }
  }
  
}

No comments:

Post a Comment