General usable MCP4728 quad DAC implementation only limited function has to be used together with the DevInterface lib
Dependents: mbedSerialInterface_talkback2 MCP4728test mbedSerialInterface_sequencer
mcp4728.cpp@3:2a2eafba8a1d, 2016-01-12 (annotated)
- Committer:
- wbeaumont
- Date:
- Tue Jan 12 15:45:23 2016 +0000
- Revision:
- 3:2a2eafba8a1d
- Parent:
- 1:cd7c70a46739
added more API comments, change to requested config bit for the setVoltage member
Who changed what in which revision?
User | Revision | Line number | New 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 | } |