drive the analog devices AD57XX series of DACs using SPI

dac57xx.h

Committer:
daan
Date:
2011-10-26
Revision:
1:59ce04153689
Parent:
0:cbb2d9111355

File content as of revision 1:59ce04153689:

#pragma once
#include <stdint.h>

/**
 *   a library for driving the Analog Devices Dac 57X4 series and more.
 *   Tested on the AD5724 and AD5754. The AD5734 should also work.
 *   http://www.analog.com/en/digital-to-analog-converters/da-converters/ad5724/products/product.html 
 *   the AD5722 AFD5732 and AD5752 should also work with minimal effort.
 *
 *   note: this is the first commit. not all functionalities have been tested with the mbed.
 */

class DacAD57XX : public SPI {
public:
  /**
   *   
   */
  DacAD57XX(PinName mosi, PinName miso, PinName sclk, PinName cs) : 
      SPI(mosi, miso, sclk), 
      mCS(cs)
  {
    // TODO(dps): make the frequency in an argument? 
    frequency(1000000);
    // 8 bits a frame
    // mode 2: ClockPolarity 1 ClockPhase 1
    format(8, 2); 
    disableChipSelect();
  };
  
  enum registers {
    RW   = 128,
    REG2 = 32,
    REG1 = 16,
    REG0 = 8,
    A2   = 4,
    A1   = 2,
    A0   = 1,
    
    PUA = 1,
    PUB = 2,
    PUC = 4,
    PUD = 8
  };
  
  enum control {
    OUTPUT_RANGE_SELECT = REG0,
    CONTROL = REG0 | REG1,
    CONTROL_SET = CONTROL | A0,
    POWER_CONTROL = REG1
  };
  
  // enum resolution {AD5724R, AD5734R, AD5754R};
  enum outputRanges {
    UNIPOLAR_5V =  0, 
    UNIPOLAR_10V = 1, 
    BIPOLAR_5V =   3, 
    BIPOLAR_10V =  4
  };
  enum channels {
    ADDRESS_A = 0,
    ADDRESS_B = A0,
    ADDRESS_C = A1,
    ADDRESS_D = A0+A1,
    ADDRESS_ALL = A2
  };
  
  /**
   *   start communicating with the dac
   */  
  inline void enableChipSelect() 
  {
    mCS = 0; // zero to select
  }
  /**
   *   End communicating with the dac
   */
  inline void disableChipSelect() 
  {
    mCS = 1;
  }
  
  /**
   *   Send 3 bytes to the dac. Discard returned values.
   */
  inline void send(uint8_t a, uint8_t b, uint8_t c)
  {
    enableChipSelect();
     write(a);
     write(b);
     write(c);
     disableChipSelect();
   }
   
  /**
   *   Send 3 bytes, Receive 3 bytes. To receive from the previous command 
   *   use transferNop()
   *   @return: a 32bit unsigned int with the received 3 bytes.
   */
  // do range check your input. 
  inline uint32_t transfer(uint8_t a, uint8_t b, uint8_t c)
  {
     enableChipSelect();
     
     // TODO(dps): refactor to shorter code.
     uint8_t aa = (uint8_t)write(a);
     uint8_t ab = (uint8_t)write(b);
     uint8_t ac = (uint8_t)write(c);
  
     uint32_t result = (uint32_t)aa;
     result = result << 8;
     result |= (uint32_t)ab;
     result = result << 8;
     result |= ac;

     disableChipSelect();
  
     return result;
/*     
     uint32_t r = ((uint8_t)(write(a))) << 16;
     r |= ((uint8_t)(write(b))) << 8;
     r |= (uint8_t)(write(c));
     disableChipSelect();
     return r;
*/
   }

  /**
   *   Send a NOP to receive the output of the previous command.
   *   @return: a 32bit unsigned int with the received 3 bytes.
   */   
   inline uint32_t transferNop() {
     return transfer( 0x18, 0, 0 );
   }
  
   /**
    *   Nothing to be done here yet. TODO(dps): move some items from the constructor?
    */
   void setup() 
   {  
   }
   
   /**
    *  returns the power control register.
    */
   
   uint32_t getPowerControl()
   {
     send( RW | POWER_CONTROL, 0, 0 );
     return transferNop();
   }
   /** 
    *  returns the control register. 
    */
   
   uint32_t getControl()
   {
     send( RW | CONTROL_SET, 0, 0 );
     return transferNop();
   }
   
   /**
    *   Set the output range for the addresses.
    *   example : setOutputRange( ADDRESS_ALL, BIPOLAR_5V );
    *
    */
  
   void setOutputRange(int address, int range)
   {
    uint8_t a = OUTPUT_RANGE_SELECT | address;
    uint8_t b = 0;
    uint8_t c = range; // range & 0x7;
    send(a,b,c);
   }
  
   /**
    *   Query the output range of the given address.
    *   The address is stored in the lower bytes.
    *   (result & 0x3) == BIPOLAR_5V
    */
   
   uint32_t getOutputRange(int address) 
   {
      uint8_t a = RW | OUTPUT_RANGE_SELECT | address;
      send(a,0,0);
      return transferNop();
   }
   
   
   /** 
    *
    *   Set power control.
    *       
    */
   
   void setPowerControl(int channels)
   {
   /* AD5722R http://www.analog.com/static/imported-files/data_sheets/AD5722R_5732R_5752R.pdf
     |R/W |Zero|Reg2|Reg1|Reg0 | A2| A1| A0| | DB15-DB11|10 |  9|  8| |  7|  6|  5|    4|  3|  2|  1|  0|
     |0   |0   |0   |1   |0    |0  |0  |0  | | ---------|X  |OCb|X  | |OCa|0  |TSD|PUref|X  |PUb|X  |PUa|
   */
   uint8_t a = POWER_CONTROL;
   uint8_t b = 0;
   uint8_t c = channels & 15;
   send(a,b,c);
   }
   void setControl()
   {
    uint8_t a = CONTROL_SET;
    uint8_t b = 0;
    uint8_t c = 8+4;  // TSD termal shutdown + clamp enable
    send(a,b,c);
   }
  
   /**
    *   Send a value to the dac.
    */
  
   void setValue(int address, uint16_t value) 
   {
       send(address,(uint8_t)(value >> 8) & 0xFF,(uint8_t)(value) & 0xFF);
   }
   
   private:
     DigitalOut mCS;
   
};