General usable MCP4728 quad DAC implementation only limited function has to be used together with the DevInterface lib

Dependents:   mbedSerialInterface_talkback2 MCP4728test mbedSerialInterface_sequencer

Revision:
1:cd7c70a46739
Parent:
0:7a0ebc527fb9
Child:
3:2a2eafba8a1d
--- a/mcp4728.cpp	Fri Oct 23 19:35:27 2015 +0000
+++ b/mcp4728.cpp	Fri Jan 08 11:58:33 2016 +0000
@@ -2,29 +2,29 @@
 #include "mbed.h"
 
 
-#define VERSION_MCP4728_SRC  "0.02"  
-// verions 0.02 has a fixed setDAC but now ch1 reacts on the heart beat  some bit maniputation error in the setDac
+#define VERSION_MCP4728_SRC  "0.48"  
 
+#define VREFVOLTAGE 2.048
 #define CMDFAST  0
-#define CMDWRITEDAC 2  // writes to the DAC and / or eeprom depending on the write funcion
+
 //#define CMDWRITEI2CADDR  3 // handled in a different class 
 #define CMDWRITEVREF  4
 #define CMDWRITEGAIN  6
 #define CMDWRITEPWDDOWN  5
 
-#define WRITEFCTMULTI  0  // write to multiple  DAC ch  given by ch selectio bits 
-#define WRITEFCTSEQ  2       // write to DAC AND eeprom,  from ch given in ch selection bits to D
-#define WRITEFCTSINGLE 3   // write to a singe DAC AND eeprom  ch given in ch selection bits
+#define WRITEFCTMULTI  8  // write to multiple  DAC ch  given by ch selectio bits 
+//#define WRITEFCTSEQ  2       // write to DAC AND eeprom,  from ch given in ch selection bits to D
+//#define WRITEFCTSINGLE 3   // write to a singe DAC AND eeprom  ch given in ch selection bits
 
-MCP4728::MCP4728(I2CInterface* i2cinterface, int device_address_bits  ): _i2c_interface(i2cinterface) ,
-    getVersion( VERSION_MCP4728_HDR,VERSION_MCP4728_SRC, __TIME__, __DATE__)
+MCP4728::MCP4728(I2CInterface* i2cinterface, int device_address_bits , float Vddin ): 
+    getVersion( VERSION_MCP4728_HDR,VERSION_MCP4728_SRC, __TIME__, __DATE__),_i2c_interface(i2cinterface) 
 {
-    
+    _adrbytes= device_address_bits & 7;
     // Assemble the full I2C device address.
     _device_address = 0xC0; // Prime the full device address with the device code.
     _device_address |= (device_address_bits<<1);
     // next has to be read back from the device but
-    
+    Vdd=Vddin;
     for ( int ch=0;ch<4;ch++) {
              ChCfg[ch].pwr=Normal;
              ChCfg[ch].vref=InternRef;
@@ -33,87 +33,148 @@
 }
 
 int MCP4728::getDACvalue(int& value, int ch){
-    // has to limit to reading only the dac value not the other items. 
-    enum PowerMode mode; enum PowerMode mode_eeprom; int dac_value; int dac_value_eeprom; bool eeprom_write_in_progress;
-    int status = read( mode, mode_eeprom,  dac_value, dac_value_eeprom,  eeprom_write_in_progress);
-    value=dac_value;
-    return status;
+    ch = ch & 7;
+    value =chstat[ch].dacvalue;
+    return lastreadresult;
 }
+int  MCP4728::getVoltage(float &voltage, int ch){
+    int value ; 
+    int result = getDACvalue( value , ch ); 
+    voltage = dig2volt( (short int) value, chstat[ch].gain,  chstat[ch].vref);
+    return result;     
+};
 
-int MCP4728::read(enum PowerMode& mode, enum PowerMode& mode_eeprom, int& dac_value, int& dac_value_eeprom, bool& eeprom_write_in_progress)
-{
-    char data[5];
-    int result;
+int MCP4728::setVoltage (float voltage, int ch){   
+    short int value = volt2dig( voltage, chstat[ch].gain, chstat[ch].vref);
+    return  setDACvalue( (int) value, ch);
+        
+};
+
+
+
+    float MCP4728::dig2volt( short int value, GainMode gain,  VrefMode  vref ){
+        float vout =(float)value / 4096;
+        if ( vref == ExternRef ) {
+            vout = Vdd * vout;
+        }
+        else {
+            vout = VREFVOLTAGE * vout; 
+            if ( gain == GainX2 ) vout = vout*2;
+        }   
+        return vout; 
+    }
+    short int MCP4728::volt2dig( float voltage, GainMode gain,  VrefMode  vref ){ 
+        float tmp;
+        tmp= 4096 * voltage;
+        if ( vref == ExternRef ) {
+          tmp= tmp/Vdd  ;                                
+        }    
+        else {
+           if ( gain == GainX2 ) tmp=tmp/2;
+           tmp = tmp /  VREFVOLTAGE;
+        }
+        return (short int) ( tmp +.5 );    
+    }
+
+
+int MCP4728::update(bool checkall ) {
+   int result;
     
     // Read the raw data from the device.
-    result = _i2c_interface->read(_device_address, data, sizeof(data)/sizeof(*data), false);
+    result = _i2c_interface->read(_device_address, rbdata, sizeof(rbdata)/sizeof(*rbdata), false);
     
     // Parse the raw data, extracting our fields. Refer to MCP4728 ref manual, section 6.2
-    if (result == 0)
-    {
-        eeprom_write_in_progress = (data[0] & 0x80)? false:true;
-        
-        mode = (enum PowerMode) ((data[0] & 0x06)>>1);
+    if (result == 0){
+        int bytecnt=0;
+        char chancheck=0;
+        char addrcheck=0;
+        for ( int cc =0 ; cc < 4 ; cc++) {
+            bytecnt= cc*6; // 6 byte per channel
+            chstat[cc].bussy= (rbdata[bytecnt] & 0x80)? false:true;
+            chstat[cc].por= (rbdata[bytecnt] & 0x40)? false:true;
+            if (checkall) {
+                chancheck=(rbdata[bytecnt] & 0x30) ;
+                chancheck=chancheck >>4;  chancheck=chancheck & 3; 
+                if ( cc != chancheck ) { result= chancheck ; result = result <<4 ; result=0xC |result | cc;} 
+                addrcheck= (rbdata[bytecnt] & 0x07) ;
+                if ( _adrbytes != addrcheck) { result= 0x08 | addrcheck ; result = result <<4 ; result=0x8 | result | cc;} 
+            }
+            bytecnt++; // point to the second addr 
+            chstat[cc].vref = (enum VrefMode) ((rbdata[bytecnt] & 0x80)>>7);
+            chstat[cc].pwr = (enum PowerMode) ((rbdata[bytecnt] & 0x06)>>5);
+            chstat[cc].gain = (enum GainMode) ((rbdata[bytecnt] & 0x10)>>4);
+            chstat[cc].dacvalue  = (rbdata[bytecnt++] & 0xF );// point to the third addr
+            chstat[cc].dacvalue = chstat[cc].dacvalue << 8 ;
+            chstat[cc].dacvalue = chstat[cc].dacvalue | rbdata[bytecnt++] ;// point to the forth addr
+            // eprom bytes             
+            chstat[cc].bussy= (rbdata[bytecnt] & 0x80)? false:true;
+            chstat[cc].por= (rbdata[bytecnt] & 0x40)? false:true;
+            if (checkall) {
+                chancheck=(rbdata[bytecnt] & 0x30) ;
+                chancheck=chancheck >>4;  chancheck=chancheck & 3; 
+                if ( cc != chancheck ) { result= chancheck ; result = result <<4 ; result=0xC |result | cc;} 
+                addrcheck= (rbdata[bytecnt] & 0x07) ;
+                if ( _adrbytes != addrcheck) { result= 0x08 | addrcheck ; result = result <<4 ; result=0x8 | result | cc;} 
+            }
+            bytecnt++; // point to the second addr 
+            chstat[cc].promvref = (enum VrefMode) ((rbdata[bytecnt] & 0x80)>>7);
+            chstat[cc].prompwr = (enum PowerMode) ((rbdata[bytecnt] & 0x06)>>5);
+            chstat[cc].promgain = (enum GainMode) ((rbdata[bytecnt] & 0x10)>>4);
         
-        dac_value  = (data[1]<<4) + (data[2]>>4);
-        
-        mode_eeprom = (enum PowerMode)((data[3] & 0x60)>>5);
-        
-        dac_value_eeprom = ((data[3] & 0x0F) <<8) + data[4];
-    }
-     
+            chstat[cc].promvalue  = (rbdata[bytecnt++] & 0xF );
+            chstat[cc].promvalue = chstat[cc].promvalue << 8 ;
+            chstat[cc].promvalue = chstat[cc].promvalue | rbdata[bytecnt] ;       
+        }
+    }        
+    lastreadresult=result; 
     return result;
 }
 
 
 int MCP4728::setDACvalue( int value, int ch){
     char data[3], tmp ; 
- /*   data[0] = CMDWRITEDAC << 6; // select write DAC function
-    data[0] = data[0] | WRITEFCTMULTI << 4 ; // select write multi ch no eeprom 
+ 
+    data[0] =  WRITEFCTMULTI << 3 ; // select write multi ch no eeprom 
     ch =ch & 3;
-    tmp =(char)  ch; // select the channel
+    tmp =(char)  ch << 1; // select the channel
     data[0] = data[0] | tmp ;
-    data[0] = data[0] | 0 ; // update now , assuming !LDAC =0
-*/
-    data[2] = 0xFF &  (char)value;
-/*    value=value >>8;
+    data[0] = data[0] &  0xFE ; // update now , assuming !LDAC =0
+
+    data[2] = 0xFF &  (char)value; // lower byte
+    value=value >>8;
     data[1] = 0x0F &  (char)value;
     data[1] = data[1] | (char)( ChCfg[ch].gain <<4); //set gain
     data[1] = data[1] | (char)( ChCfg[ch].pwr <<5); // set pwr mode 
     data[1] = data[1] | (char)( ChCfg[ch].vref  <<7); // set pwr mode 
-*/
-    data[0]= 0x52; // 0b0101 0010  ch 1  !UDAC=0 
-    data[1]= 0x17; // 0b0000 0111   ref=Vdd, pwd =0  normal  ; gain =1  d11=0 ,111,       
+
+    //data[0]= 0x52; // 0b0101 0010  ch 1  !UDAC=0 
+    //data[1]= 0x17; // 0b0000 0111   ref=Vdd, pwd =0  normal  ; gain =1  d11=0 ,111,       
     return _i2c_interface->write(_device_address, data, sizeof(data)/sizeof(*data), false);
  
     
 }
 
-
-
+// kept c compatible 
+// no text interpretation of gain ,ref  and power mod 
+int   MCP4728::StatusString(int ch,bool updatereq , bool eprom,  char *str , int length){
+if (length < 200 ) return -200;
+int result=0;
+if ( updatereq ) result= update (false);
+if ( result ) return result ;
+ch=ch&3 ;
 
-int MCP4728::write(enum PowerMode mode, int dac_value, bool writeToEeprom)
-{
-    char data[3]={0};
-    int write_command;
+int dataidx= ch* 6 + 3* (int) eprom;
+if ( eprom ) {
     
-    //Which write command are we to use?
-    if (writeToEeprom == true)
-    {
-        //Write DAC Register and EEPROM
-        write_command = 3;
-    }
-    else
-    {
-        //Write DAC Register
-        write_command = 2;
-    }
+    
+    result= sprintf( str, "d1:%02X d2:%02X  d3:%02X EEP Ch: %1d pwr: %1d Ref: %1d gain: %1d, value %04d", 
+    (int)rbdata[dataidx++],(int)rbdata[dataidx++],(int)rbdata[dataidx],
+    ch,(int) chstat[ch].prompwr, (int) chstat[ch].promvref , (int) chstat[ch].promgain, (int)  chstat[ch].promvalue );
     
-    //Assemble our three bytes of data - Refer to MCP4728 ref manual, section 6.
-    data[0] = (write_command <<5) | ((int)mode<<1);
-    data[1] = (dac_value>>4);
-    data[2] = (dac_value<<4);
-    
-    // Now write them to the device.
-    return _i2c_interface->write(_device_address, data, sizeof(data)/sizeof(*data), false);
+}else {
+    result= sprintf( str, "d1:%02X d2:%02X  d3:%02X DAC Ch: %01d pwr: %04d Ref: %04d gain: %04d, value %04d", 
+    (int)rbdata[dataidx],(int)rbdata[dataidx+1],(int)rbdata[dataidx+2],
+    ch,(int) chstat[ch].pwr, (int) chstat[ch].vref , (int) chstat[ch].gain, (int)  chstat[ch].dacvalue  );
+}    
+return result;     
 }
\ No newline at end of file