bontor humala / ADE7758

Fork of ADE7758 by Emma

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ade7758.cpp Source File

ade7758.cpp

00001 #include "mbed.h"
00002 #include "ade7758.h"
00003 #include "SWSPI.h"
00004 
00005 // public
00006 ADE7758::ADE7758(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName interrupt):
00007     _ADE7758SPI(mosi, miso, sclk), _ADESS(cs), _ADEINT(interrupt)
00008 {
00009     _ADESS = 1;
00010 }
00011 
00012 void ADE7758::begin()
00013 {
00014     enableChip();
00015     //normal mode
00016     _ADE7758SPI.format(8, 1); // pha 0, pol 1
00017     _ADE7758SPI.frequency(1000000);    
00018     write8bits(OPMODE, 0x04);
00019 }
00020 
00021 void ADE7758::calibrateVI(uint8_t numSamples) 
00022 {    
00023     write8bits(LCYCMODE, 0x38);
00024     write24bits(MASK, 0xE00);
00025     long AVRMSBuffer = 0, BVRMSBuffer = 0, CVRMSBuffer = 0;
00026     long AIRMSBuffer = 0, BIRMSBuffer = 0, CIRMSBuffer = 0;
00027     for (uint8_t i=0; i<numSamples; i++) {
00028         read24bits(RSTATUS);
00029         while ( _ADEINT != 0 ) { } // wait until INT go low
00030         AVRMSBuffer += VRMS(PHASE_A);
00031         BVRMSBuffer += VRMS(PHASE_B);
00032         CVRMSBuffer += VRMS(PHASE_C);
00033         AIRMSBuffer += IRMS(PHASE_A);
00034         BIRMSBuffer += IRMS(PHASE_B);
00035         CIRMSBuffer += IRMS(PHASE_C);
00036     }
00037     AVRMSCalib = AVRMSBuffer/numSamples;
00038     BVRMSCalib = BVRMSBuffer/numSamples;
00039     CVRMSCalib = CVRMSBuffer/numSamples;
00040     AIRMSCalib = AIRMSBuffer/numSamples;
00041     BIRMSCalib = BIRMSBuffer/numSamples;
00042     CIRMSCalib = CIRMSBuffer/numSamples;
00043 }
00044 
00045 void ADE7758::writeRMSOffset(uint16_t AIRMSOSValue, uint16_t BIRMSOSValue, uint16_t CIRMSOSValue, uint16_t AVRMSOSValue, uint16_t BVRMSOSValue, uint16_t CVRMSOSValue) {
00046     // Collect for ITEST & VNOM, IMIN & VMIN
00047     // Calculate these values in an Excel sheet according to page
00048     // Write the results to the xIRMSOS and xVRMSOS registers
00049     write16bits(AIRMSOS, AIRMSOSValue); // Current channel A
00050     write16bits(BIRMSOS, BIRMSOSValue); // Current channel B
00051     write16bits(CIRMSOS, CIRMSOSValue); // Current channel C
00052     write16bits(AVRMSOS, AVRMSOSValue); // Voltage channel A
00053     write16bits(BVRMSOS, BVRMSOSValue); // Voltage channel B
00054     write16bits(CVRMSOS, CVRMSOSValue); // Voltage channel C
00055 }
00056 
00057 void ADE7758::calibrateGain(char phase) { // see datasheet ADE 7758 page 49 of 72
00058     // 1. Clear xWG, xVARG, xVAG
00059     write16bits(AWG, 0x0000);
00060     write16bits(BWG, 0x0000);
00061     write16bits(CWG, 0x0000);
00062     write16bits(AVARG, 0x0000);
00063     write16bits(BVARG, 0x0000);
00064     write16bits(CVARG, 0x0000);
00065     write16bits(AVAG, 0x0000);
00066     write16bits(BVAG, 0x0000);
00067     write16bits(CVAG, 0x0000);
00068     
00069     // 2. Select phase for line period measurement
00070     lineFreq(phase);
00071 
00072     // 3. Configure LCYCMODE register with 0xBF
00073     write8bits(LCYCMODE, 0xBF);
00074     
00075     // 4. Set number of half line cycles
00076     write16bits(LINECYC, 0x800);
00077     
00078     // 5. Set LENERGY bit in MASK register for interrupt
00079     uint16_t mask;
00080     mask = read16bits(MASK);
00081     write24bits(MASK, mask | (1<<LENERGY));
00082     wait_ms(10);
00083     
00084     // 6. Environment setting
00085     // set environment - ITEST and VNOM
00086     
00087     // 7. Reset RSTATUS
00088     read24bits(RSTATUS);
00089     
00090     // 8. Wait LENERGY interrupt and read 6 energy registers
00091     while ( _ADEINT != 0 ) { } // wait until INT go low
00092     int AWATTHRTemp = getWattHR(PHASE_A);
00093     int AVAHRTemp = getVAHR(PHASE_A);
00094     int BWATTHRTemp = getWattHR(PHASE_B);
00095     int BVAHRTemp = getVAHR(PHASE_B);
00096     int CWATTHRTemp = getWattHR(PHASE_C);
00097     int CVAHRTemp = getVAHR(PHASE_C);
00098 
00099     // 9. Calculate Wh/LSB and VAh/LSB
00100     float accumTime = getAccumulationTime(PHASE_A);
00101     float tempEnergy = ITEST*VNOM*accumTime;
00102     AWhLSB = tempEnergy/(3600*AWATTHRTemp);
00103     BWhLSB = tempEnergy/(3600*BWATTHRTemp);
00104     CWhLSB = tempEnergy/(3600*CWATTHRTemp);
00105     AVAhLSB = tempEnergy/(3600*AVAHRTemp);
00106     BVAhLSB = tempEnergy/(3600*BVAHRTemp);
00107     CVAhLSB = tempEnergy/(3600*CVAHRTemp);
00108 
00109     // 10. Clear and wait LENERGY interrupt and read 6 energy registers
00110     wait_ms(10);
00111     read24bits(RSTATUS);
00112     while ( _ADEINT != 0 ) { } // wait until INT go low
00113     int AWHREXPECTED = getWattHR(PHASE_A);
00114     int AVAHREXPECTED = getVAHR(PHASE_A);
00115     int BWHREXPECTED = getWattHR(PHASE_B);
00116     int BVAHREXPECTED = getVAHR(PHASE_B);
00117     int CWHREXPECTED = getWattHR(PHASE_C);
00118     int CVAHREXPECTED = getVAHR(PHASE_C);
00119 
00120     // 11. Calculate xWG and xVAG values
00121     AWGCalib = ((float)(AWHREXPECTED/AWATTHRTemp) - 1)*4096;
00122     BWGCalib = ((float)(BWHREXPECTED/BWATTHRTemp) - 1)*4096;
00123     CWGCalib = ((float)(CWHREXPECTED/CWATTHRTemp) - 1)*4096;
00124     AVAGCalib = ((float)(AVAHREXPECTED/AVAHRTemp) - 1)*4096;
00125     BVAGCalib = ((float)(BVAHREXPECTED/BVAHRTemp) - 1)*4096;
00126     CVAGCalib = ((float)(CVAHREXPECTED/CVAHRTemp) - 1)*4096;
00127 
00128     // 10. Write the values to xWG and xVAG
00129     write16bits(AWG, AWGCalib);
00130     write16bits(BWG, BWGCalib);
00131     write16bits(CWG, CWGCalib);
00132     write16bits(AVAG, AVAGCalib);
00133     write16bits(BVAG, BVAGCalib);
00134     write16bits(CVAG, CVAGCalib);
00135 }
00136 
00137 float ADE7758::getAccumulationTime(char phase) {
00138     uint16_t frequency = lineFreq(phase);
00139     uint16_t LineCYC = read16bits(LINECYC);
00140     write8bits(LCYCMODE, 0xBF);
00141     float LineFrequency = 1/(frequency*0.0000096);
00142     return LineCYC/(2*LineFrequency*3);
00143 }
00144 
00145 int ADE7758::getWattHR(char phase)
00146 {
00147     return read16bits(AWATTHR+phase);
00148 }
00149 
00150 int ADE7758::getVARHR(char phase)
00151 {
00152     return read16bits(AVARHR+phase);
00153 }
00154 
00155 int ADE7758::getVAHR(char phase)
00156 {
00157     return read16bits(AVAHR+phase);
00158 }
00159 
00160 int ADE7758::WattHR(char phase)
00161 {
00162     return getWattHR(phase);
00163 }
00164 
00165 int ADE7758::VARHR(char phase)
00166 {
00167     return getVARHR(phase);
00168 }
00169 
00170 int ADE7758::VAHR(char phase)
00171 {
00172     return getVAHR(phase);
00173 }
00174 
00175 long ADE7758::VRMS(char phase)
00176 {
00177     char i=0;
00178     long volts=0;
00179     getVRMS(phase);//Ignore first reading
00180     for(i=0;i<10;++i){
00181         volts+=getVRMS(phase);
00182         wait_us(50);
00183     }
00184     //average
00185     return volts/10;
00186 }
00187 
00188 long ADE7758::IRMS(char phase)
00189 {
00190   char i=0;
00191   long current=0;
00192   getIRMS(phase);//Ignore first reading
00193   for(i=0;i<10;++i){
00194     current+=getIRMS(phase);
00195     wait_us(50);
00196   }
00197   //average
00198   return current/10;
00199 }
00200 
00201 
00202 float ADE7758::calculateIRMS(char phase) {
00203     long IRMSBuffer = 0;
00204     float AvgIRMS = 0;
00205     for (char i=0; i<NUMSAMPLES; i++) {
00206         IRMSBuffer += IRMS(phase);
00207     }
00208     AvgIRMS = IRMSBuffer/NUMSAMPLES;
00209 
00210     if ( phase == PHASE_A ) {
00211         return AvgIRMS * 0.0000125;
00212     }
00213     else if ( phase == PHASE_B ) {
00214         return AvgIRMS * 0.0000123;
00215     }    
00216     else if ( phase == PHASE_C ) {
00217         return AvgIRMS * 0.0000124;
00218     }
00219     else { return 0; }
00220 }
00221 
00222 float ADE7758::calculateVRMS(char phase) {
00223     long VRMSBuffer = 0;
00224     float AvgVRMS = 0;
00225     for (char i=0; i<NUMSAMPLES; i++) {
00226         VRMSBuffer += VRMS(phase);
00227     }
00228     AvgVRMS = VRMSBuffer/NUMSAMPLES;
00229 
00230     if ( phase == PHASE_A ) {
00231         return AvgVRMS * 0.000158;
00232     }
00233     else if ( phase == PHASE_B ) {
00234         return AvgVRMS * 0.000157;
00235     }
00236     else if ( phase == PHASE_C ) {
00237         return AvgVRMS * 0.000156;
00238     }
00239     else { return 0; }
00240 }
00241 
00242 void ADE7758::getEnergy(char phase, uint8_t samplingPeriod, float *AWattHr, float *BWattHr, float *CWattHr, float *AVAHr, float *BVAHr, float *CVAHr) {    
00243     float period = 0;
00244     long AWattHrSum = 0;
00245     long BWattHrSum = 0;    
00246     long CWattHrSum = 0;
00247     long AVAHrSum = 0;
00248     long BVAHrSum = 0;    
00249     long CVAHrSum = 0;
00250         
00251     uint16_t AWattHrValue, BWattHrValue, CWattHrValue, AVAHrValue, BVAHrValue, CVAHrValue;
00252     while (period < samplingPeriod*60.0) {
00253         period += ADE.getAccumulationTime(PHASE_A);
00254         ADE7758::getAccumulatedEnergy(phase, &AWattHrValue, &BWattHrValue, &CWattHrValue, &AVAHrValue, &BVAHrValue, &CVAHrValue);
00255         AWattHrSum += AWattHrValue;
00256         BWattHrSum += BWattHrValue;
00257         CWattHrSum += CWattHrValue;
00258         AVAHrSum += AVAHrValue;
00259         BVAHrSum += BVAHrValue; 
00260         CVAHrSum += CVAHrValue;
00261     }
00262     *AWattHr = AWattHrSum * AWhLSB;
00263     *BWattHr = BWattHrSum * BWhLSB;
00264     *CWattHr = CWattHrSum * CWhLSB;
00265     
00266     *AVAHr = AVAHrSum * AVAhLSB;
00267     *BVAHr = BVAHrSum * BVAhLSB;
00268     *CVAHr = CVAHrSum * CVAhLSB;
00269 }
00270 
00271 void ADE7758::getAccumulatedEnergy(char phase, uint16_t *AWattHr, uint16_t *BWattHr, uint16_t *CWattHr, uint16_t *AVAHr, uint16_t *BVAHr, uint16_t *CVAHr)
00272 {
00273     // 1. Set phase used for line zero cross detection
00274     lineFreq(phase);
00275 
00276     // 2. Configure LCYCMODE register with 0xBF
00277     write8bits(LCYCMODE, 0xBF);    
00278 
00279     // 3. Set number of half line cycles
00280     write16bits(LINECYC, 0x800);    
00281 
00282     // 4. Set LENERGY bit in MASK register for interrupt
00283     uint16_t mask;
00284     mask = read16bits(MASK);
00285     write24bits(MASK, mask | (1<<LENERGY));
00286     wait_ms(10);
00287 
00288     // 5. Reset RSTATUS
00289     read24bits(RSTATUS);
00290     
00291     // 6. Wait LENERGY interrupt and read 6 energy registers
00292     while ( _ADEINT != 0 ) { } // wait until INT go low
00293     *AWattHr = getWattHR(PHASE_A);
00294     *AVAHr = getVAHR(PHASE_A);
00295     *BWattHr = getWattHR(PHASE_B);
00296     *BVAHr = getVAHR(PHASE_B);
00297     *CWattHr = getWattHR(PHASE_C);
00298     *CVAHr = getVAHR(PHASE_C);
00299 }
00300 
00301 long ADE7758::waveform(char phase,char source)
00302 {
00303   return 1;
00304 }
00305 
00306 void ADE7758::powerOff()
00307 {
00308 
00309 }
00310 
00311 void ADE7758::powerON()
00312 {
00313 
00314 }
00315 
00316 void ADE7758::sleep()
00317 {
00318 
00319 }
00320 
00321 void ADE7758::wakeUp()
00322 {
00323 
00324 }
00325 
00326 long ADE7758::getInterruptStatus(void){
00327         return read24bits(STATUS);
00328 }
00329 
00330 long ADE7758::getResetInterruptStatus(void){
00331         return read24bits(RSTATUS);
00332 }
00333 
00334 int ADE7758::lineFreq(char phase){
00335     uint8_t mmode;
00336     mmode = read8bits(MMODE);
00337     write8bits(MMODE,( mmode&0xFC )| phase);
00338     wait_ms(10);
00339     return read16bits(FREQ);
00340 }
00341 // private
00342 
00343 void ADE7758::enableChip()
00344 {
00345     _ADESS = 0;
00346 }
00347 
00348 void ADE7758::disableChip()
00349 {
00350     _ADESS = 1;
00351 }
00352 
00353 void ADE7758::write8bits(char reg, unsigned char data)
00354 {
00355     enableChip();
00356         
00357     wait_ms(10);
00358     _ADE7758SPI.write(REG_WRITE(reg));
00359     wait_ms(2);
00360 
00361     _ADE7758SPI.write(data);
00362 
00363     wait_ms(1);
00364     
00365     disableChip();
00366 }
00367 
00368 void ADE7758::write16bits(char reg, unsigned int data)
00369 {
00370     enableChip();
00371     
00372     wait_ms(10);
00373     _ADE7758SPI.write(REG_WRITE(reg));
00374     wait_ms(2);
00375     _ADE7758SPI.write((unsigned char)((data>>8)&0xFF));
00376     wait_ms(2);
00377     _ADE7758SPI.write((unsigned char)(data&0xFF));
00378     wait_ms(1);
00379 
00380     disableChip();
00381 }
00382 
00383 void ADE7758::write24bits(char reg, unsigned int data)
00384 {
00385     enableChip();
00386     
00387     wait_ms(10);
00388     _ADE7758SPI.write(REG_WRITE(reg));
00389     wait_ms(2);
00390     _ADE7758SPI.write((unsigned char)((data>>16)&0xFF));
00391     wait_ms(2);
00392     _ADE7758SPI.write((unsigned char)((data>>8)&0xFF));
00393     wait_ms(2);
00394     _ADE7758SPI.write((unsigned char)(data&0xFF));
00395     wait_ms(1);
00396 
00397     disableChip();
00398 }
00399 
00400 unsigned char ADE7758::read8bits(char reg)
00401 {
00402     enableChip();
00403     
00404     unsigned char ret;
00405     wait_ms(10);
00406     _ADE7758SPI.write(REG_READ(reg));
00407     wait_ms(2);
00408     ret=_ADE7758SPI.write(0x00);
00409     wait_ms(1);
00410     
00411     disableChip();
00412 
00413     return ret;
00414 }
00415 
00416 unsigned int ADE7758::read16bits(char reg)
00417 {
00418     enableChip();
00419     unsigned int ret=0;
00420     unsigned char ret0=0;
00421     wait_ms(10);
00422     _ADE7758SPI.write(REG_READ(reg));
00423     wait_ms(2);
00424     ret=_ADE7758SPI.write(0x00);
00425     wait_ms(2);
00426     ret0=_ADE7758SPI.write(0x00);
00427     wait_ms(1);
00428     
00429     disableChip();
00430     ret= (ret<<8)|ret0;
00431     return ret;
00432 }
00433 
00434 unsigned long ADE7758::read24bits(char reg)
00435 {
00436     enableChip();
00437     unsigned long ret=0;
00438     unsigned int ret1=0;
00439     unsigned char ret0=0;
00440     wait_ms(10);
00441     _ADE7758SPI.write(REG_READ(reg));
00442     wait_ms(2);
00443     ret=_ADE7758SPI.write(0x00);
00444     wait_ms(2);
00445     ret1=_ADE7758SPI.write(0x00);
00446     wait_ms(2);
00447     ret0=_ADE7758SPI.write(0x00);
00448     wait_ms(1);
00449     
00450     disableChip();
00451     ret= (ret<<16)|(ret1<<8)| ret0;
00452     return ret;
00453 }
00454 
00455 long ADE7758::getIRMS(char phase)
00456 {
00457     return read24bits(AIRMS+phase);
00458 }
00459 
00460 long ADE7758::getVRMS(char phase)
00461 {          
00462     return read24bits(AVRMS+phase);
00463 }
00464 
00465 // ADE7758 ADE(mosi, miso, sclk, cs);