General usable MCP4728 quad DAC implementation only limited function has to be used together with the DevInterface lib
Dependents: mbedSerialInterface_talkback2 MCP4728test mbedSerialInterface_sequencer
Diff: mcp4728.cpp
- Revision:
- 1:cd7c70a46739
- Parent:
- 0:7a0ebc527fb9
- Child:
- 3:2a2eafba8a1d
diff -r 7a0ebc527fb9 -r cd7c70a46739 mcp4728.cpp --- 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