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

Dependents:   mbedSerialInterface_talkback2 MCP4728test mbedSerialInterface_sequencer

Committer:
wbeaumont
Date:
Wed Jul 06 14:55:28 2016 +0000
Revision:
5:164362cf5836
Parent:
3:2a2eafba8a1d
added methods to set output gain, ref source and power mode

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wbeaumont 0:7a0ebc527fb9 1 #include "mcp4728.h"
wbeaumont 0:7a0ebc527fb9 2 #include "mbed.h"
wbeaumont 0:7a0ebc527fb9 3
wbeaumont 0:7a0ebc527fb9 4
wbeaumont 3:2a2eafba8a1d 5 #define VERSION_MCP4728_SRC "0.49"
wbeaumont 0:7a0ebc527fb9 6
wbeaumont 1:cd7c70a46739 7 #define VREFVOLTAGE 2.048
wbeaumont 0:7a0ebc527fb9 8 #define CMDFAST 0
wbeaumont 1:cd7c70a46739 9
wbeaumont 0:7a0ebc527fb9 10 //#define CMDWRITEI2CADDR 3 // handled in a different class
wbeaumont 0:7a0ebc527fb9 11 #define CMDWRITEVREF 4
wbeaumont 0:7a0ebc527fb9 12 #define CMDWRITEGAIN 6
wbeaumont 0:7a0ebc527fb9 13 #define CMDWRITEPWDDOWN 5
wbeaumont 0:7a0ebc527fb9 14
wbeaumont 1:cd7c70a46739 15 #define WRITEFCTMULTI 8 // write to multiple DAC ch given by ch selectio bits
wbeaumont 1:cd7c70a46739 16 //#define WRITEFCTSEQ 2 // write to DAC AND eeprom, from ch given in ch selection bits to D
wbeaumont 1:cd7c70a46739 17 //#define WRITEFCTSINGLE 3 // write to a singe DAC AND eeprom ch given in ch selection bits
wbeaumont 0:7a0ebc527fb9 18
wbeaumont 1:cd7c70a46739 19 MCP4728::MCP4728(I2CInterface* i2cinterface, int device_address_bits , float Vddin ):
wbeaumont 1:cd7c70a46739 20 getVersion( VERSION_MCP4728_HDR,VERSION_MCP4728_SRC, __TIME__, __DATE__),_i2c_interface(i2cinterface)
wbeaumont 0:7a0ebc527fb9 21 {
wbeaumont 1:cd7c70a46739 22 _adrbytes= device_address_bits & 7;
wbeaumont 0:7a0ebc527fb9 23 // Assemble the full I2C device address.
wbeaumont 0:7a0ebc527fb9 24 _device_address = 0xC0; // Prime the full device address with the device code.
wbeaumont 0:7a0ebc527fb9 25 _device_address |= (device_address_bits<<1);
wbeaumont 0:7a0ebc527fb9 26 // next has to be read back from the device but
wbeaumont 1:cd7c70a46739 27 Vdd=Vddin;
wbeaumont 0:7a0ebc527fb9 28 for ( int ch=0;ch<4;ch++) {
wbeaumont 0:7a0ebc527fb9 29 ChCfg[ch].pwr=Normal;
wbeaumont 0:7a0ebc527fb9 30 ChCfg[ch].vref=InternRef;
wbeaumont 0:7a0ebc527fb9 31 ChCfg[ch].gain=GainX2;
wbeaumont 0:7a0ebc527fb9 32 }
wbeaumont 0:7a0ebc527fb9 33 }
wbeaumont 0:7a0ebc527fb9 34
wbeaumont 0:7a0ebc527fb9 35 int MCP4728::getDACvalue(int& value, int ch){
wbeaumont 1:cd7c70a46739 36 ch = ch & 7;
wbeaumont 1:cd7c70a46739 37 value =chstat[ch].dacvalue;
wbeaumont 3:2a2eafba8a1d 38 return lastupdateresult;
wbeaumont 0:7a0ebc527fb9 39 }
wbeaumont 1:cd7c70a46739 40 int MCP4728::getVoltage(float &voltage, int ch){
wbeaumont 1:cd7c70a46739 41 int value ;
wbeaumont 1:cd7c70a46739 42 int result = getDACvalue( value , ch );
wbeaumont 1:cd7c70a46739 43 voltage = dig2volt( (short int) value, chstat[ch].gain, chstat[ch].vref);
wbeaumont 1:cd7c70a46739 44 return result;
wbeaumont 1:cd7c70a46739 45 };
wbeaumont 0:7a0ebc527fb9 46
wbeaumont 1:cd7c70a46739 47 int MCP4728::setVoltage (float voltage, int ch){
wbeaumont 3:2a2eafba8a1d 48 short int value = volt2dig( voltage, ChCfg[ch].gain, ChCfg[ch].vref);
wbeaumont 1:cd7c70a46739 49 return setDACvalue( (int) value, ch);
wbeaumont 1:cd7c70a46739 50
wbeaumont 1:cd7c70a46739 51 };
wbeaumont 1:cd7c70a46739 52
wbeaumont 1:cd7c70a46739 53
wbeaumont 1:cd7c70a46739 54
wbeaumont 1:cd7c70a46739 55 float MCP4728::dig2volt( short int value, GainMode gain, VrefMode vref ){
wbeaumont 1:cd7c70a46739 56 float vout =(float)value / 4096;
wbeaumont 1:cd7c70a46739 57 if ( vref == ExternRef ) {
wbeaumont 1:cd7c70a46739 58 vout = Vdd * vout;
wbeaumont 1:cd7c70a46739 59 }
wbeaumont 1:cd7c70a46739 60 else {
wbeaumont 1:cd7c70a46739 61 vout = VREFVOLTAGE * vout;
wbeaumont 1:cd7c70a46739 62 if ( gain == GainX2 ) vout = vout*2;
wbeaumont 1:cd7c70a46739 63 }
wbeaumont 1:cd7c70a46739 64 return vout;
wbeaumont 1:cd7c70a46739 65 }
wbeaumont 1:cd7c70a46739 66 short int MCP4728::volt2dig( float voltage, GainMode gain, VrefMode vref ){
wbeaumont 1:cd7c70a46739 67 float tmp;
wbeaumont 1:cd7c70a46739 68 tmp= 4096 * voltage;
wbeaumont 1:cd7c70a46739 69 if ( vref == ExternRef ) {
wbeaumont 1:cd7c70a46739 70 tmp= tmp/Vdd ;
wbeaumont 1:cd7c70a46739 71 }
wbeaumont 1:cd7c70a46739 72 else {
wbeaumont 1:cd7c70a46739 73 if ( gain == GainX2 ) tmp=tmp/2;
wbeaumont 1:cd7c70a46739 74 tmp = tmp / VREFVOLTAGE;
wbeaumont 1:cd7c70a46739 75 }
wbeaumont 1:cd7c70a46739 76 return (short int) ( tmp +.5 );
wbeaumont 1:cd7c70a46739 77 }
wbeaumont 1:cd7c70a46739 78
wbeaumont 1:cd7c70a46739 79
wbeaumont 1:cd7c70a46739 80 int MCP4728::update(bool checkall ) {
wbeaumont 1:cd7c70a46739 81 int result;
wbeaumont 0:7a0ebc527fb9 82
wbeaumont 0:7a0ebc527fb9 83 // Read the raw data from the device.
wbeaumont 1:cd7c70a46739 84 result = _i2c_interface->read(_device_address, rbdata, sizeof(rbdata)/sizeof(*rbdata), false);
wbeaumont 0:7a0ebc527fb9 85
wbeaumont 0:7a0ebc527fb9 86 // Parse the raw data, extracting our fields. Refer to MCP4728 ref manual, section 6.2
wbeaumont 1:cd7c70a46739 87 if (result == 0){
wbeaumont 1:cd7c70a46739 88 int bytecnt=0;
wbeaumont 1:cd7c70a46739 89 char chancheck=0;
wbeaumont 1:cd7c70a46739 90 char addrcheck=0;
wbeaumont 1:cd7c70a46739 91 for ( int cc =0 ; cc < 4 ; cc++) {
wbeaumont 1:cd7c70a46739 92 bytecnt= cc*6; // 6 byte per channel
wbeaumont 3:2a2eafba8a1d 93 chstat[cc].busy= (rbdata[bytecnt] & 0x80)? false:true;
wbeaumont 1:cd7c70a46739 94 chstat[cc].por= (rbdata[bytecnt] & 0x40)? false:true;
wbeaumont 1:cd7c70a46739 95 if (checkall) {
wbeaumont 1:cd7c70a46739 96 chancheck=(rbdata[bytecnt] & 0x30) ;
wbeaumont 1:cd7c70a46739 97 chancheck=chancheck >>4; chancheck=chancheck & 3;
wbeaumont 1:cd7c70a46739 98 if ( cc != chancheck ) { result= chancheck ; result = result <<4 ; result=0xC |result | cc;}
wbeaumont 1:cd7c70a46739 99 addrcheck= (rbdata[bytecnt] & 0x07) ;
wbeaumont 1:cd7c70a46739 100 if ( _adrbytes != addrcheck) { result= 0x08 | addrcheck ; result = result <<4 ; result=0x8 | result | cc;}
wbeaumont 1:cd7c70a46739 101 }
wbeaumont 1:cd7c70a46739 102 bytecnt++; // point to the second addr
wbeaumont 1:cd7c70a46739 103 chstat[cc].vref = (enum VrefMode) ((rbdata[bytecnt] & 0x80)>>7);
wbeaumont 1:cd7c70a46739 104 chstat[cc].pwr = (enum PowerMode) ((rbdata[bytecnt] & 0x06)>>5);
wbeaumont 1:cd7c70a46739 105 chstat[cc].gain = (enum GainMode) ((rbdata[bytecnt] & 0x10)>>4);
wbeaumont 1:cd7c70a46739 106 chstat[cc].dacvalue = (rbdata[bytecnt++] & 0xF );// point to the third addr
wbeaumont 1:cd7c70a46739 107 chstat[cc].dacvalue = chstat[cc].dacvalue << 8 ;
wbeaumont 1:cd7c70a46739 108 chstat[cc].dacvalue = chstat[cc].dacvalue | rbdata[bytecnt++] ;// point to the forth addr
wbeaumont 1:cd7c70a46739 109 // eprom bytes
wbeaumont 3:2a2eafba8a1d 110 chstat[cc].busy= (rbdata[bytecnt] & 0x80)? false:true;
wbeaumont 1:cd7c70a46739 111 chstat[cc].por= (rbdata[bytecnt] & 0x40)? false:true;
wbeaumont 1:cd7c70a46739 112 if (checkall) {
wbeaumont 1:cd7c70a46739 113 chancheck=(rbdata[bytecnt] & 0x30) ;
wbeaumont 1:cd7c70a46739 114 chancheck=chancheck >>4; chancheck=chancheck & 3;
wbeaumont 1:cd7c70a46739 115 if ( cc != chancheck ) { result= chancheck ; result = result <<4 ; result=0xC |result | cc;}
wbeaumont 1:cd7c70a46739 116 addrcheck= (rbdata[bytecnt] & 0x07) ;
wbeaumont 1:cd7c70a46739 117 if ( _adrbytes != addrcheck) { result= 0x08 | addrcheck ; result = result <<4 ; result=0x8 | result | cc;}
wbeaumont 1:cd7c70a46739 118 }
wbeaumont 1:cd7c70a46739 119 bytecnt++; // point to the second addr
wbeaumont 1:cd7c70a46739 120 chstat[cc].promvref = (enum VrefMode) ((rbdata[bytecnt] & 0x80)>>7);
wbeaumont 1:cd7c70a46739 121 chstat[cc].prompwr = (enum PowerMode) ((rbdata[bytecnt] & 0x06)>>5);
wbeaumont 1:cd7c70a46739 122 chstat[cc].promgain = (enum GainMode) ((rbdata[bytecnt] & 0x10)>>4);
wbeaumont 0:7a0ebc527fb9 123
wbeaumont 1:cd7c70a46739 124 chstat[cc].promvalue = (rbdata[bytecnt++] & 0xF );
wbeaumont 1:cd7c70a46739 125 chstat[cc].promvalue = chstat[cc].promvalue << 8 ;
wbeaumont 1:cd7c70a46739 126 chstat[cc].promvalue = chstat[cc].promvalue | rbdata[bytecnt] ;
wbeaumont 1:cd7c70a46739 127 }
wbeaumont 1:cd7c70a46739 128 }
wbeaumont 3:2a2eafba8a1d 129 lastupdateresult=result;
wbeaumont 0:7a0ebc527fb9 130 return result;
wbeaumont 0:7a0ebc527fb9 131 }
wbeaumont 0:7a0ebc527fb9 132
wbeaumont 0:7a0ebc527fb9 133
wbeaumont 0:7a0ebc527fb9 134 int MCP4728::setDACvalue( int value, int ch){
wbeaumont 0:7a0ebc527fb9 135 char data[3], tmp ;
wbeaumont 1:cd7c70a46739 136
wbeaumont 1:cd7c70a46739 137 data[0] = WRITEFCTMULTI << 3 ; // select write multi ch no eeprom
wbeaumont 0:7a0ebc527fb9 138 ch =ch & 3;
wbeaumont 1:cd7c70a46739 139 tmp =(char) ch << 1; // select the channel
wbeaumont 0:7a0ebc527fb9 140 data[0] = data[0] | tmp ;
wbeaumont 1:cd7c70a46739 141 data[0] = data[0] & 0xFE ; // update now , assuming !LDAC =0
wbeaumont 1:cd7c70a46739 142
wbeaumont 1:cd7c70a46739 143 data[2] = 0xFF & (char)value; // lower byte
wbeaumont 1:cd7c70a46739 144 value=value >>8;
wbeaumont 0:7a0ebc527fb9 145 data[1] = 0x0F & (char)value;
wbeaumont 0:7a0ebc527fb9 146 data[1] = data[1] | (char)( ChCfg[ch].gain <<4); //set gain
wbeaumont 0:7a0ebc527fb9 147 data[1] = data[1] | (char)( ChCfg[ch].pwr <<5); // set pwr mode
wbeaumont 0:7a0ebc527fb9 148 data[1] = data[1] | (char)( ChCfg[ch].vref <<7); // set pwr mode
wbeaumont 1:cd7c70a46739 149
wbeaumont 1:cd7c70a46739 150 //data[0]= 0x52; // 0b0101 0010 ch 1 !UDAC=0
wbeaumont 1:cd7c70a46739 151 //data[1]= 0x17; // 0b0000 0111 ref=Vdd, pwd =0 normal ; gain =1 d11=0 ,111,
wbeaumont 0:7a0ebc527fb9 152 return _i2c_interface->write(_device_address, data, sizeof(data)/sizeof(*data), false);
wbeaumont 0:7a0ebc527fb9 153
wbeaumont 0:7a0ebc527fb9 154
wbeaumont 0:7a0ebc527fb9 155 }
wbeaumont 0:7a0ebc527fb9 156
wbeaumont 1:cd7c70a46739 157 // kept c compatible
wbeaumont 1:cd7c70a46739 158 // no text interpretation of gain ,ref and power mod
wbeaumont 1:cd7c70a46739 159 int MCP4728::StatusString(int ch,bool updatereq , bool eprom, char *str , int length){
wbeaumont 1:cd7c70a46739 160 if (length < 200 ) return -200;
wbeaumont 1:cd7c70a46739 161 int result=0;
wbeaumont 1:cd7c70a46739 162 if ( updatereq ) result= update (false);
wbeaumont 1:cd7c70a46739 163 if ( result ) return result ;
wbeaumont 1:cd7c70a46739 164 ch=ch&3 ;
wbeaumont 0:7a0ebc527fb9 165
wbeaumont 1:cd7c70a46739 166 int dataidx= ch* 6 + 3* (int) eprom;
wbeaumont 1:cd7c70a46739 167 if ( eprom ) {
wbeaumont 0:7a0ebc527fb9 168
wbeaumont 1:cd7c70a46739 169
wbeaumont 1:cd7c70a46739 170 result= sprintf( str, "d1:%02X d2:%02X d3:%02X EEP Ch: %1d pwr: %1d Ref: %1d gain: %1d, value %04d",
wbeaumont 1:cd7c70a46739 171 (int)rbdata[dataidx++],(int)rbdata[dataidx++],(int)rbdata[dataidx],
wbeaumont 1:cd7c70a46739 172 ch,(int) chstat[ch].prompwr, (int) chstat[ch].promvref , (int) chstat[ch].promgain, (int) chstat[ch].promvalue );
wbeaumont 0:7a0ebc527fb9 173
wbeaumont 1:cd7c70a46739 174 }else {
wbeaumont 1:cd7c70a46739 175 result= sprintf( str, "d1:%02X d2:%02X d3:%02X DAC Ch: %01d pwr: %04d Ref: %04d gain: %04d, value %04d",
wbeaumont 1:cd7c70a46739 176 (int)rbdata[dataidx],(int)rbdata[dataidx+1],(int)rbdata[dataidx+2],
wbeaumont 1:cd7c70a46739 177 ch,(int) chstat[ch].pwr, (int) chstat[ch].vref , (int) chstat[ch].gain, (int) chstat[ch].dacvalue );
wbeaumont 1:cd7c70a46739 178 }
wbeaumont 1:cd7c70a46739 179 return result;
wbeaumont 0:7a0ebc527fb9 180 }