Post Go back to editing

Reading Random values on SPI from Metering IC

Category: Software
Product Number: ADE7758
Software Version: Arduino IDE 2.3.6

I made a custom PCB with following the datasheet reference diagram.



I have tested PCB with connected AC Neutral to DGND
DGND to AGND for a common ground reference.

Also removed the 1K (R14) resistor to feed neutral directly to the Metering IC.

On the IC Pins I checked the voltage level,
Since testing with single phase AC on VAP for now.

At 240VAC, on the IC pin 16 VAP i got 0.240V AC (Checked with multimeter from the Neutral and DGND)

Getting random voltage reading from IC, it reading random values even when no AC input.
04:08:44.097 -> ADE debug registers:
04:08:44.129 -> VERSION: 0x2
04:08:44.129 -> OPMODE : 0x4
04:08:44.161 -> STATUS : 0xC0E00
04:08:44.161 -> RSTATUS: 0xC0E00
04:08:44.193 -> AIRMS : 681
04:08:44.193 -> BIRMS : 5D1
04:08:44.226 -> CIRMS : 10F8
04:08:44.226 -> AVRMS : 17CBD9
04:08:44.259 -> BVRMS : 188CEE
04:08:44.259 -> CVRMS : F3B79
04:08:44.291 -> Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug
04:08:52.771 -> VOLTAGE RMS readings for each phase:
04:08:53.702 -> 180.73
04:08:54.602 -> 193.06
04:08:55.533 -> 110.74
04:08:55.533 -> Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug
04:09:16.945 -> VOLTAGE RMS readings for each phase:
04:09:17.862 -> 181.23
04:09:18.822 -> 170.60
04:09:19.707 -> 110.11
04:09:19.707 -> Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug
04:09:21.014 -> VOLTAGE RMS readings for each phase:
04:09:21.952 -> 182.64
04:09:22.865 -> 189.44
04:09:23.770 -> 108.69
04:09:23.770 -> Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug
04:09:24.064 -> VOLTAGE RMS readings for each phase:
04:09:24.971 -> 185.55
04:09:25.924 -> 166.75
04:09:26.829 -> 108.37
04:09:26.829 -> Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug
04:09:27.939 -> VOLTAGE RMS readings for each phase:
04:09:28.890 -> 185.73
04:09:29.769 -> 188.56
04:09:30.717 -> 109.96
04:09:30.717 -> Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug

Here is the code I'm testing with

#include "Arduino.h"
#include <SPI.h>
#include "ADE7758Lib.h"

char inputChar = 0;
bool rx = false;
ADE7758 myADE(&SPI,5);

void runSPITest() {
  const int samples = 50;
  uint8_t version0 = myADE.read8bits(VERSION);
  uint8_t opmode0 = myADE.read8bits(OPMODE);
  int versionMismatch = 0;
  int opmodeMismatch = 0;

  for (int i = 0; i < samples; i++) {
    if (myADE.read8bits(VERSION) != version0) {
      versionMismatch++;
    }
    if (myADE.read8bits(OPMODE) != opmode0) {
      opmodeMismatch++;
    }
    (void)myADE.read8bits(MMODE);
    delay(1);
  }

  uint8_t mmodeOriginal = myADE.read8bits(MMODE);
  uint8_t mmodeTest = (uint8_t)(mmodeOriginal ^ 0x01);
  myADE.write8bits(MMODE, mmodeTest);
  delay(2);
  uint8_t mmodeReadback = myADE.read8bits(MMODE);
  myADE.write8bits(MMODE, mmodeOriginal);
  delay(2);
  uint8_t mmodeRestored = myADE.read8bits(MMODE);

  Serial.println("SPI self-test:");
  Serial.print("VERSION fixed: 0x");
  Serial.print(version0, HEX);
  Serial.print(" mismatches=");
  Serial.println(versionMismatch);
  Serial.print("OPMODE  fixed: 0x");
  Serial.print(opmode0, HEX);
  Serial.print(" mismatches=");
  Serial.println(opmodeMismatch);
  Serial.print("MMODE write/read: wrote 0x");
  Serial.print(mmodeTest, HEX);
  Serial.print(" read 0x");
  Serial.println(mmodeReadback, HEX);
  Serial.print("MMODE restore   : 0x");
  Serial.println(mmodeRestored, HEX);

  bool pass = (versionMismatch == 0) &&
              (opmodeMismatch == 0) &&
              (mmodeReadback == mmodeTest) &&
              (mmodeRestored == mmodeOriginal);
  Serial.println(pass ? "SPI RESULT: PASS" : "SPI RESULT: FAIL");
}
void setup()
{
  Serial.begin(9600);
  SPI.begin();
  myADE.begin();
  Serial.println("ADE7758 begins operating");
  Serial.println("Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug, s=spi-test");
  delay(1000);
}


void loop()
{
  if (Serial.available() > 0) {
    inputChar = (char)Serial.read();
    if (inputChar != '\r' && inputChar != '\n' && inputChar != ' ') {
      rx = true;
    }
  }

  if (rx) {
    switch(inputChar){
      case 'a':
              Serial.println("ENERGY readings for each phase:");
              Serial.println(myADE.getWattHR(PHASE_A), HEX);
              Serial.println(myADE.getWattHR(PHASE_B), HEX);
              Serial.println(myADE.getWattHR(PHASE_C), HEX);
              break;
      case 'b':
              Serial.println("CURRENT RMS readings for each phase:");
              Serial.println(myADE.IRMS(PHASE_A), HEX);
              Serial.println(myADE.IRMS(PHASE_B), HEX);
              Serial.println(myADE.IRMS(PHASE_C), HEX);
              break;
      case 'c':
              Serial.println("VOLTAGE RMS readings for each phase:");
              Serial.println((float)myADE.VRMS(PHASE_A) * 0.000159024, 2);
              Serial.println((float)myADE.VRMS(PHASE_B) * 0.000159024, 2);
              Serial.println((float)myADE.VRMS(PHASE_C) * 0.000159024, 2);
              // Serial.println(myADE.VRMS(PHASE_B), HEX);
              // Serial.println(myADE.VRMS(PHASE_C), HEX);
              break;
      case 'd':
              Serial.println("Complex Energy readings for each phase:");
              Serial.println(myADE.getVAHR(PHASE_A), HEX);
              Serial.println(myADE.getVAHR(PHASE_B), HEX);
              Serial.println(myADE.getVAHR(PHASE_C), HEX);
              break;
      case 'v':
              Serial.println("ADE debug registers:");
              Serial.print("VERSION: 0x");
              Serial.println(myADE.read8bits(VERSION), HEX);
              Serial.print("OPMODE : 0x");
              Serial.println(myADE.read8bits(OPMODE), HEX);
              Serial.print("STATUS : 0x");
              Serial.println(myADE.getInterruptStatus(), HEX);
              Serial.print("RSTATUS: 0x");
              Serial.println(myADE.getResetInterruptStatus(), HEX);
              Serial.print("AIRMS  : ");
              Serial.println(myADE.getIRMS(PHASE_A), HEX);
              Serial.print("BIRMS  : ");
              Serial.println(myADE.getIRMS(PHASE_B), HEX);
              Serial.print("CIRMS  : ");
              Serial.println(myADE.getIRMS(PHASE_C), HEX);
              Serial.print("AVRMS  : ");
              Serial.println(myADE.getVRMS(PHASE_A), HEX);
              Serial.print("BVRMS  : ");
              Serial.println(myADE.getVRMS(PHASE_B), HEX);
              Serial.print("CVRMS  : ");
              Serial.println(myADE.getVRMS(PHASE_C), HEX);
              break;
      case 's':
              runSPITest();
              break;
      default:
          Serial.println("unknown command");
    }
    rx = false;
    Serial.println("Send command: a=Wh, b=Irms, c=Vrms, d=VAh, v=debug, s=spi-test");
  }
}


//ADE7758Lib.h

#ifndef _ADE7758LIB_h
#define _ADE7758LIB_h

#include <SPI.h>


#define AWATTHR   0x01
#define BWATTHR   0x02
#define CWATTHR   0x03
#define AVARHR    0x04
#define BVARHR    0x05
#define CVARHR    0x06
#define AVAHR     0x07
#define BVAHR     0x08
#define CVAHR     0x09
#define AIRMS     0x0A
#define BIRMS     0x0B
#define CIRMS     0x0C
#define AVRMS     0x0D
#define BVRMS     0x0E
#define CVRMS     0x0F
#define FREQ      0x10
#define TEMP      0x11
#define WFORM     0x12
#define OPMODE    0x13
#define MMODE     0x14
#define WAVMODE   0x15
#define COMPMODE  0x16
#define LCYCMODE  0x17
#define MASK      0x18
#define STATUS    0x19
#define RSTATUS   0x1A
#define ZXTOUT    0x1B
#define LINECYC   0x1C
#define SAGCYC    0x1D
#define SAGLVL    0x1E
#define VPINTLVL  0x1F
#define IPINTLVL  0x20
#define VPEAK     0x21
#define IPEAK     0x22
#define GAIN      0x23
#define AVRMSGAIN 0x24
#define BVRMSGAIN 0x25
#define CVRMSGAIN 0x26
#define AIGAIN    0x27
#define BIGAIN    0x28
#define CIGAIN    0x29
#define AWG       0x2A
#define BWG       0x2B
#define CWG       0x2C
#define AVARG     0x2D
#define BVARG     0x2E
#define CVARG     0x2F
#define AVAG      0x30
#define BVAG      0x31
#define CVAG      0x32
#define AVRMSOS   0x33
#define BVRMSOS   0x34
#define CVRMSOS   0x35
#define AIRMSOS   0x36
#define BIRMSOS   0x37
#define CIRMSOS   0x38
#define AWAITOS   0x39
#define BWAITOS   0x3A
#define CWAITOS   0x3B
#define AVAROS    0x3C
#define BVAROS    0x3D
#define CVAROS    0x3E
#define APHCAL    0x3F
#define BPHCAL    0x40
#define CPHCAL    0x41
#define WDIV      0x42
#define VADIV     0x44
#define VARDIV    0x43
#define APCFNUM   0x45
#define APCFDEN   0x46
#define VARCFNUM  0x47
#define VARCFDEN  0x48
#define CHKSUM    0x7E
#define VERSION   0x7F

#define REG_READ(reg) reg
#define REG_WRITE(reg)  (unsigned char)((reg) | 0x80)

//PHASE_SEL
#define PHASE_A   0
#define PHASE_B   1
#define PHASE_C   2

//WAV_SEL
#define CURRENT   0
#define VOLTAGE   1
#define ACT_PWR   2
#define REACT_PWR 3
#define APP_PWR   4

//interrupt mask/status bit
#define AEHF            0
#define REHF            1
#define VAEHF           2
#define SAGA            3
#define SAGB            4
#define SAGC            5
#define ZXTOA           6
#define ZXTOB           7
#define ZXTOC           8
#define ZXA             9
#define ZXB             10
#define ZXC             11
#define LENERGY         12
#define RESET           13
#define PKV             14
#define PKI             15
#define WFSM            16
#define REVPAP          17
#define REVPRP          18
#define SEQERR          19


#define WAVMODE_VALUE(phase, wave)   (((wave)<<2)|(phase))


class ADE7758
{
  public:
    ADE7758 (SPIClass *,int );
    void begin();
    int WattHR(char );
    int VARHR(char );
    int VAHR(char );
    long VRMS(char );
    long IRMS(char );
    long waveform(char ,char );
    int lineFreq(char );

    void accumulateEnergy();

    void powerOff();
    void powerON();
    void sleep();
    void wakeUp();

    long getInterruptStatus(void);
    long getResetInterruptStatus(void);
    void enableChip();
    void disableChip();
     void write8bits(char , unsigned char );
    void write16bits(char , unsigned int );
    unsigned char read8bits(char );
    unsigned int read16bits(char );
    unsigned long read24bits(char );

    long getIRMS(char );
    long getVRMS(char );
    int getWattHR(char );
    int getVARHR(char );
    int getVAHR(char );

  private:
   
    SPIClass *_ADE7758SPI;
    int _SSpin;
    long accuWattHRA;
    long accuWattHRB;
    long accuVARHRA;
    long accuVARHRB;
    long accuVAHRA;
    long accuVAHRB;
};


#endif


//ADE7758Lib.cpp
#include <Arduino.h>
#include <SPI.h>
#include "ADE7758Lib.h"

#if !defined(MSBFIRST) && defined(SPI_MSBFIRST)
#define MSBFIRST SPI_MSBFIRST
#endif

extern void isrGDO0event(void);
SPISettings ADESETTINGS(125000, MSBFIRST, SPI_MODE1);
//public
ADE7758::ADE7758(SPIClass *ADESPI, int SSpin)
{
  _ADE7758SPI=ADESPI;
  _SSpin=SSpin;
  digitalWrite(_SSpin, HIGH);
  //Ensure Chip select pin is output
  pinMode(_SSpin, OUTPUT);
 
}

void ADE7758::begin()
{
  // Allow device power-up to settle before first config write.
  delay(20);

  // Normal operating mode.
  write8bits(OPMODE, 0x04);
  delay(10);

  // Read reset/status once to clear startup latched flags.
  (void)getResetInterruptStatus();
  (void)getInterruptStatus();
}

int ADE7758::getWattHR(char phase)
{
  return read16bits(AWATTHR+phase);
}

int ADE7758::getVARHR(char phase)
{
  return read16bits(AVARHR+phase);
}

int ADE7758::getVAHR(char phase)
{
  return read16bits(AVAHR+phase);
}

long ADE7758::VRMS(char phase)
{
  long volts = 0;
  int samples = 50;
 
  getVRMS(phase); // Dummy read to clear old data
 
  for(int i = 0; i < samples; i++) {
    volts += getVRMS(phase);
    delayMicroseconds(1000); // 1ms delay * 50 = 50ms averaging window
  }
 
  return volts / samples;
}

long ADE7758::IRMS(char phase)
{
  char i=0;
  long current=0;
  getIRMS(phase);//Ignore first reading
  for(i=0;i<10;++i){
    current+=getIRMS(phase);
    delayMicroseconds(50);
  }
  //average
  return current/10;
}

void ADE7758::accumulateEnergy()
{
  accuWattHRA += getWattHR(PHASE_A);
  accuWattHRB += getWattHR(PHASE_B);
  // Add Phase C if needed
 
  accuVAHRA += getVAHR(PHASE_A);
  accuVAHRB += getVAHR(PHASE_B);
}

long ADE7758::waveform(char phase,char source)
{

}

void ADE7758::powerOff()
{

}

void ADE7758::powerON()
{

}

void ADE7758::sleep()
{

}

void ADE7758::wakeUp()
{

}

long ADE7758::getInterruptStatus(void){
        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);
    delay(10);
    return read16bits(FREQ);
}
//private

void ADE7758::enableChip()
{

    digitalWrite(_SSpin, LOW);
}

void ADE7758::disableChip()
{
    digitalWrite(_SSpin, HIGH);
}

void ADE7758::write8bits(char reg, unsigned char data)
{
  _ADE7758SPI->beginTransaction(ADESETTINGS);
  enableChip();
     
  delay(10);
  _ADE7758SPI->transfer(REG_WRITE(reg));
  delay(2);
 
  _ADE7758SPI->transfer(data);
 
  delay(1);
 
  disableChip();
  _ADE7758SPI->endTransaction();
}

void ADE7758::write16bits(char reg, unsigned int data)
{
  _ADE7758SPI->beginTransaction(ADESETTINGS);
  enableChip();
 
  delay(10);
  _ADE7758SPI->transfer(REG_WRITE(reg));
  delay(2);
  _ADE7758SPI->transfer((unsigned char)((data>>8)&0xFF));
  delay(2);
  _ADE7758SPI->transfer((unsigned char)(data&0xFF));
  delay(1);
 
  disableChip();
  _ADE7758SPI->endTransaction();
}

unsigned char ADE7758::read8bits(char reg)
{
  _ADE7758SPI->beginTransaction(ADESETTINGS);
  enableChip();
 
  unsigned char ret;
  delay(10);
  _ADE7758SPI->transfer(REG_READ(reg));
  delay(2);
  ret=_ADE7758SPI->transfer(0x00);
  delay(1);
 
  disableChip();
  _ADE7758SPI->endTransaction();
  return ret;
}

unsigned int ADE7758::read16bits(char reg)
{
  _ADE7758SPI->beginTransaction(ADESETTINGS);
  enableChip();
  unsigned int ret=0;
  unsigned char ret0=0;
  delay(10);
  _ADE7758SPI->transfer(REG_READ(reg));
  delay(2);
  ret=_ADE7758SPI->transfer(0x00);
  delay(2);
  ret0=_ADE7758SPI->transfer(0x00);
  delay(1);
 
  disableChip();
  _ADE7758SPI->endTransaction();
  ret= (ret<<8)|ret0;
  return ret;
}

unsigned long ADE7758::read24bits(char reg)
{
    _ADE7758SPI->beginTransaction(ADESETTINGS);
    enableChip();
    unsigned long ret=0;
    unsigned int ret1=0;
    unsigned char ret0=0;
    delay(10);
    _ADE7758SPI->transfer(REG_READ(reg));
    delay(2);
    ret=_ADE7758SPI->transfer(0x00);
    delay(2);
    ret1=_ADE7758SPI->transfer(0x00);
    delay(2);
    ret0=_ADE7758SPI->transfer(0x00);
    delay(1);
   
    disableChip();
    _ADE7758SPI->endTransaction();
    ret= (ret<<16)|(ret1<<8)|ret0;
    return ret;
}

long ADE7758::getIRMS(char phase)
{
    return read24bits(AIRMS+phase);
}

long ADE7758::getVRMS(char phase)
{          
    return read24bits(AVRMS+phase);
}