Calibrate and get energy readings from ADE7758 IC from Analog Devices

Fork of ADE7758 by Emma

Currently this library can be used to calibrate and get VRMS, IRMS, active, and apparent energy. I havent worked on reactive energy measurement.

Revision:
2:ea36884772ae
Parent:
1:f5e8c8591449
Child:
3:4fad91cf047a
--- a/ade7758.cpp	Fri Apr 10 03:58:10 2015 +0000
+++ b/ade7758.cpp	Fri Apr 10 10:12:27 2015 +0000
@@ -18,7 +18,7 @@
     write8bits(OPMODE, 0x04);
 }
 
-void ADE7758::CalibrateVI(uint8_t numSamples) 
+void ADE7758::calibrateVI(uint8_t numSamples) 
 {    
     write8bits(LCYCMODE, 0x38);
     write24bits(MASK, 0xE00);
@@ -39,7 +39,100 @@
     CVRMSCalib = CVRMSBuffer/numSamples;
     AIRMSCalib = AIRMSBuffer/numSamples;
     BIRMSCalib = BIRMSBuffer/numSamples;
-    CIRMSCalib = CIRMSBuffer/numSamples;
+    CIRMSCalib = CIRMSBuffer/numSamples;    
+    
+    // Collect for ITEST & VNOM, IMIN & VMIN
+    // Calculate these values in an Excel sheet according to page
+    // Write the results to the xIRMSOS and xVRMSOS registers
+//    write16bits(AIRMSOS, 0xF5B); // Current channel A
+//    write16bits(BIRMSOS, 0xF52); // Current channel B
+//    write16bits(CIRMSOS, 0xF6C); // Current channel C
+    write16bits(AVRMSOS, 0xF5B); // Voltage channel A
+    write16bits(BVRMSOS, 0xF52); // Voltage channel B
+    write16bits(CVRMSOS, 0xF6C); // Voltage channel C
+}
+
+void ADE7758::calibrateGain(char phase) { // see datasheet ADE 7758 page 49 of 72
+    // 1. Clear xWG, xVARG, xVAG
+    write16bits(AWG, 0x0000);
+    write16bits(BWG, 0x0000);
+    write16bits(CWG, 0x0000);        
+    write16bits(AVARG, 0x0000);
+    write16bits(BVARG, 0x0000);
+    write16bits(CVARG, 0x0000);
+    write16bits(AVAG, 0x0000);
+    write16bits(BVAG, 0x0000);
+    write16bits(CVAG, 0x0000);
+    
+    // 2. Select phase for line period measurement
+    lineFreq(phase);
+
+    // 3. Configure LCYCMODE register with 0xBF
+    write8bits(LCYCMODE, 0xBF);
+    
+    // 4. Set number of half line cycles
+    write16bits(LINECYC, 0x800);
+    
+    // 5. Set LENERGY bit in MASK register for interrupt
+    uint16_t mask;
+    mask = read16bits(MASK);
+    write24bits(MASK, mask | (1<<LENERGY));
+    wait_ms(10);
+    
+    // 6. Environment setting
+    // set environment - ITEST and VNOM
+    
+    // 7. Reset RSTATUS
+    read24bits(RSTATUS);
+    
+    // 8. Wait LENERGY interrupt and read 6 energy registers
+    while ( _ADEINT != 0 ) { } // wait until INT go low
+    int AWATTHRTemp = getWattHR(PHASE_A);
+    int AVAHRTemp = getVAHR(PHASE_A);
+    int BWATTHRTemp = getWattHR(PHASE_B);
+    int BVAHRTemp = getVAHR(PHASE_B);
+    int CWATTHRTemp = getWattHR(PHASE_C);
+    int CVAHRTemp = getVAHR(PHASE_C);
+
+    // 9. Write xWG and xVAG
+    // Calculate expected WattHr
+    int APCFDENVal = read16bits(APCFDEN);
+    int APCFNUMVal = read16bits(APCFNUM);
+    int WDIVVal = read8bits(WDIV);
+    int VARCFDENVal = read16bits(VARCFDEN);
+    int VARCFNUMVal = read16bits(VARCFNUM);
+    int VADIVVal = read8bits(VADIV);
+
+    float AccumTime = getAccumulationTime();
+    float tempWH = ((4*3200*0.6*220*1*AccumTime)/(1000*3600));
+    float WattHRExpected = tempWH * (APCFDENVal/APCFNUMVal) * (1/WDIVVal);
+    float VAHRExpected = tempWH * (VARCFDENVal/VARCFNUMVal) * (1/VADIVVal);
+        
+    // 9a. Calculate xWG values
+    int AWGValue = ((WattHRExpected/AWATTHRTemp) - 1)*4096;
+    int BWGValue = ((WattHRExpected/BWATTHRTemp) - 1)*4096;
+    int CWGValue = ((WattHRExpected/CWATTHRTemp) - 1)*4096;
+
+    // 9b. Calculate xVAG values
+    int AVAGValue = ((VAHRExpected/AVAHRTemp) - 1)*4096;
+    int BVAGValue = ((VAHRExpected/BVAHRTemp) - 1)*4096;
+    int CVAGValue = ((VAHRExpected/CVAHRTemp) - 1)*4096;
+
+    // 10. Write the values to xWG and xVAG
+    write16bits(AWG, AWGValue);
+    write16bits(BWG, BWGValue);
+    write16bits(CWG, CWGValue);
+    write16bits(AVAG, AVAGValue);
+    write16bits(BVAG, BVAGValue);
+    write16bits(CVAG, CVAGValue);
+}
+
+float ADE7758::getAccumulationTime() {
+    uint16_t frequency = lineFreq(phase);
+    uint16_t LineCYC = read16bits(LINECYC);
+    write8bits(LCYCMODE, 0xBF);
+    float LineFrequency = 1/(frequency*0.0000096);
+    return LineCYC/(2*LineFrequency*3);
 }
 
 int ADE7758::getWattHR(char phase)
@@ -59,30 +152,30 @@
 
 int ADE7758::WattHR(char phase)
 {
-  return getWattHR(phase);
+    return getWattHR(phase);
 }
 
 int ADE7758::VARHR(char phase)
 {
-  return getVARHR(phase);
+    return getVARHR(phase);
 }
 
 int ADE7758::VAHR(char phase)
 {
-  return getVAHR(phase);
+    return getVAHR(phase);
 }
 
 long ADE7758::VRMS(char phase)
 {
-  char i=0;
-  long volts=0;
-  getVRMS(phase);//Ignore first reading
-  for(i=0;i<10;++i){
-          volts+=getVRMS(phase);
-          wait_us(50);
-  }
-  //average
-  return volts/10;
+    char i=0;
+    long volts=0;
+    getVRMS(phase);//Ignore first reading
+    for(i=0;i<10;++i){
+        volts+=getVRMS(phase);
+        wait_us(50);
+    }
+    //average
+    return volts/10;
 }
 
 long ADE7758::IRMS(char phase)
@@ -99,33 +192,72 @@
 }
 
 
-float ADE7758::CalculateIRMS(char phase) {
+float ADE7758::calculateIRMS(char phase) {
+    long IRMSBuffer = 0;
+    float AvgIRMS = 0;
+    for (char i=0; i<NUMSAMPLES; i++) {
+        IRMSBuffer += IRMS(phase);
+    }
+    AvgIRMS = IRMSBuffer/NUMSAMPLES;
+
     if ( phase == PHASE_A ) {
-        return IRMS(phase) * 0.00000967;
+        return AvgIRMS * 0.00000967;
     }
     else if ( phase == PHASE_B ) {
-        return IRMS(phase) * 0.00000955;
+        return AvgIRMS * 0.00000955;
     }    
     else if ( phase == PHASE_C ) {
-        return IRMS(phase) * 0.00000958;
+        return AvgIRMS * 0.00000958;
     }
 }
 
-float ADE7758::CalculateVRMS(char phase) {
+float ADE7758::calculateVRMS(char phase) {
+    long VRMSBuffer = 0;
+    float AvgVRMS = 0;
+    for (char i=0; i<NUMSAMPLES; i++) {
+        VRMSBuffer += VRMS(phase);
+    }
+    AvgVRMS = VRMSBuffer/NUMSAMPLES;
+
     if ( phase == PHASE_A ) {
-        return VRMS(phase) * 0.000158;
+        return AvgVRMS * 0.000158;
     }
     else if ( phase == PHASE_B ) {
-        return VRMS(phase) * 0.000157;
+        return AvgVRMS * 0.000157;
     }
     else if ( phase == PHASE_C ) {
-        return VRMS(phase) * 0.000156;
-    }        
+        return AvgVRMS * 0.000156;
+    }
 }
 
-void accumulateEnergy()
+void ADE7758::calculateEnergy()
 {
+    // 1. Set phase used for line zero cross detection
+    lineFreq(phase);
+
+    // 2. Configure LCYCMODE register with 0xBF
+    write8bits(LCYCMODE, 0xBF);    
+
+    // 3. Set number of half line cycles
+    write16bits(LINECYC, 0x800);    
+
+    // 4. Set LENERGY bit in MASK register for interrupt
+    uint16_t mask;
+    mask = read16bits(MASK);
+    write24bits(MASK, mask | (1<<LENERGY));
+    wait_ms(10);
+
+    // 5. Reset RSTATUS
+    read24bits(RSTATUS);
     
+    // 6. Wait LENERGY interrupt and read 6 energy registers
+    while ( _ADEINT != 0 ) { } // wait until INT go low
+    AWATTHRValue = getWattHR(PHASE_A);
+    AVAHRValue = getVAHR(PHASE_A);
+    BWATTHRValue = getWattHR(PHASE_B);
+    BVAHRValue = getVAHR(PHASE_B);
+    CWATTHRValue = getWattHR(PHASE_C);
+    CVAHRValue = getVAHR(PHASE_C);
 }
 
 long ADE7758::waveform(char phase,char source)
@@ -157,16 +289,14 @@
         return read24bits(STATUS);
 }
 
-
 long ADE7758::getResetInterruptStatus(void){
         return read24bits(RSTATUS);
 }
 
-
 int ADE7758::lineFreq(char phase){
     uint8_t mmode;
     mmode = read8bits(MMODE);
-    write8bits(MMODE,(mmode&0x11111100 )| phase);
+    write8bits(MMODE,( mmode&0xFC )| phase);
     wait_ms(10);
     return read16bits(FREQ);
 }