ADE9000 PAGE_FULL interrupt timing question

Hi, I am following AN-1483 Application Note - Harmonic Analysis Using the ADE9000 and facing some problems.

So first of all, when I request new samples, by sending 0x20000 to STATUS0 register and polling PAGE_FULL form STATUS0 I get interrupt @ 62.5 Hz, which is twice as fast as it should be (8khz / 256 = 31.25 hertz).

What’s also interesting, after PAGE_FULL occurs, every time I pull ADDR_WFB_TRG_STAT register value of WFB_LAST_PAGE differs, and I am getting right value both for 7 and 15 page full interrupt. Of course, when receiving data from buffer at the provided address the data gets corrupted.

I found, that after some waiting (simple delay), before setting STATUS0 to 0x20000 I get exact 31.5Hz interrupt frequency, but of course, I don’t want to synchronize it that way.
Can you provide me the proper way of getting those interrupts in time?

There is also bug in AN-1486 Figure 6 - (IS WFB_LAST_PAGE EQUAL TO 0xBFF?) - WFB_LAST_PAGE will never match 0xBFF as it is ‘WFB_TRG_STAT [15:12] WFB_LAST_PAGE’.

I'm attaching screenshots of the logic analyzer software documenting 62.5 Hz interrupt behavior.

I am looking forward for any answers,

Adam

  • Below you can find the diff of modified Arduino sketch, based on an example from "ADE9000 Arduino Shield Evaluation Software" package, as well as modified source code.
    https://www.diffchecker.com/SPrCOKmM

    #include <Arduino.h>
    
    // original example code
    #include <SPI.h>
    #include  <ADE9000RegMap.h>
    #include <ADE9000API.h>
    
    /*Basic initializations*/
    ADE9000Class ade9000;
    #define SPI_SPEED 5000000     //SPI Speed
    #define CS_PIN A2 // nucleo f411 boaard 
    #define ADE9000_RESET_PIN 5 //Reset Pin on HW
    #define PM_1 4              //PM1 Pin: 4-->Arduino Zero. 15-->ESP8266 
    
    /*Structure decleration */
    struct ActivePowerRegs powerRegs;     // Declare powerRegs of type ActivePowerRegs to store Active Power Register data
    struct CurrentRMSRegs curntRMSRegs;   //Current RMS
    struct VoltageRMSRegs vltgRMSRegs;    //Voltage RMS
    struct VoltageTHDRegs voltageTHDRegsnValues; //Voltage THD
    struct ResampledWfbData resampledData; // Resampled Data
    
    /*Function Decleration*/
    void readRegisterData(void);
    void readResampledData(void);
    void resetADE9000(void);
    
    void SetupADE9000New(void) {
      ade9000.SPI_Write_16(ADDR_PGA_GAIN,0);     
      ade9000.SPI_Write_32(ADDR_CONFIG0,0); 
      ade9000.SPI_Write_16(ADDR_CONFIG1,0);
      ade9000.SPI_Write_16(ADDR_CONFIG2,0);
      ade9000.SPI_Write_16(ADDR_CONFIG3,0);
      ade9000.SPI_Write_16(ADDR_ACCMODE,0);
      ade9000.SPI_Write_16(ADDR_TEMP_CFG,0);
      ade9000.SPI_Write_16(ADDR_ZX_LP_SEL,0);
      ade9000.SPI_Write_32(ADDR_MASK0,0);
      ade9000.SPI_Write_32(ADDR_MASK1,0);
      ade9000.SPI_Write_32(ADDR_EVENT_MASK,0);
      ade9000.SPI_Write_16(ADDR_WFB_CFG,0);
      ade9000.SPI_Write_32(ADDR_VLEVEL,0);
      ade9000.SPI_Write_32(ADDR_DICOEFF,0);
      ade9000.SPI_Write_16(ADDR_EGY_TIME,0);
      ade9000.SPI_Write_16(ADDR_EP_CFG,0);
      ade9000.SPI_Write_16(ADDR_RUN,ADE9000_RUN_ON);
    }
    
    void setup() 
    {
      Serial.begin(115200);
      pinMode(PM_1, OUTPUT);    //Set PM1 pin as output 
      digitalWrite(PM_1, LOW);   //Set PM1 select pin low for PSM0 mode
      pinMode(ADE9000_RESET_PIN, OUTPUT);
      digitalWrite(ADE9000_RESET_PIN, HIGH); 
      void resetADE9000(); 
      delay(1000);
      ade9000.SPI_Init(SPI_SPEED,CS_PIN); //Initialize SPI
      SetupADE9000New();
      
      /* user code start */
      // Identyfi ADE9000
      Serial.print("ADE9000 id: ");
      Serial.println(ade9000.SPI_Read_16(0x00000472), HEX);
    
      // To set the waveform buffer, perform the following procedure:
      // 1. Write 0x03F8 to WFB_CFB (Address 0x4A0) to configure the waveform. 
      uint16_t wfb_cfg_register = 0x03F8;
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 2. Write 0'0b0 to WF_IN_EN (Bit 12) to disable waveform in
      // neutral channel to be read through the serial peripheral
      // interface (SPI).
      bitClear(wfb_cfg_register, 12);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 3. Write 0'b11 to WF_SRC (Bits[9:8]) to enable current and
      // voltage channel waveform samples processed at 8 kSPS by
      // the DSP.
      bitSet(wfb_cfg_register, 9);
      bitSet(wfb_cfg_register, 8);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 4. Write 0'b11 to WF_MODE (Bits[7:6]) to enable continuous
      // fill on the buffer. See the ADE9000 Technical Reference
      // Manual for more information on continuous filling mode.
      bitSet(wfb_cfg_register, 7);
      bitSet(wfb_cfg_register, 6);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 5. Write 0'b1 to WF_CAP_SEL (Bit 5) to enable the fixed data
      // rate sampling (noncoherent).
      bitSet(wfb_cfg_register, 5);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 6. Write 0'b1 to WF_CAP_EN (Bit 4) to start waveform
      // capturer.
      bitSet(wfb_cfg_register, 4);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      Serial.println(wfb_cfg_register, HEX);
    
      // 7. Write 0'b0000 for all channels to BURST_CHAN
      // (Bits[3.0]) to select channels. See the ADE9000 data sheet
      // for other channels. 
      bitClear(wfb_cfg_register, 3);
      bitClear(wfb_cfg_register, 2);
      bitClear(wfb_cfg_register, 1);
      bitClear(wfb_cfg_register, 0);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // To execute this process, take the following steps: 
      // 1. Write 0x20000 to MASK0 (Address 0x405) to enable the page full interrupt.
      ade9000.SPI_Write_32(ADDR_MASK0, 0x20000);
      // 2. Write 0x8080 to WFB_PG_IRQWN (Address 0x4A1) to set the interrupt at Page 7 and Page 15. 
      ade9000.SPI_Write_16(ADDR_WFB_PG_IRQEN, 0x8080);
    
      Serial.print("RUN Register: ");
      Serial.println(ade9000.SPI_Read_16(ADDR_RUN),HEX);
    }
    
    void loop() {
      // readRegisterData();
      readResampledData();
      // delay(10000);
    }
    
    void readRegisterData()
    {
     /*Read and Print Specific Register using ADE9000 SPI Library */
      Serial.print("AIRMS: "); 
      Serial.println(ade9000.SPI_Read_32(ADDR_AIRMS),HEX); // AIRMS
    
     /*Read and Print RMS & WATT Register using ADE9000 Read Library*/
      ade9000.ReadVoltageRMSRegs(&vltgRMSRegs);    //Template to read Power registers from ADE9000 and store data in Arduino MCU
      ade9000.ReadActivePowerRegs(&powerRegs);
      Serial.print("AVRMS:");        
      Serial.println(vltgRMSRegs.VoltageRMSReg_A); //Print AVRMS register
      Serial.print("AWATT:");        
      Serial.println(powerRegs.ActivePowerReg_A); //Print AWATT register
    }
    
    void readResampledData()
    {
      // CLEAR INTERRUPTS, WRITE 0x20000 TO STATUS0
      ade9000.SPI_Write_32(ADDR_STATUS0, 0x20000);
    
      while(digitalRead(pinNametoDigitalPin(PA_0))) {
        ;
      }
      // POLL STATUS0, BIT 17 PAGE FULL
      uint32_t status0 = 0;
      while(1) {
        status0 = ade9000.SPI_Read_32(ADDR_STATUS0);
        // IS PAGE FULL INTERRUPT (BIT 17 IN STATUS0) TRUE?
        if(bitRead(status0, 17) == true) {
          break;
        }
      }
    
      uint16_t wfb_address = 0;
    
      // READ ADDRESS 0x4A3 WFB_TRG_STAT
      uint16_t wfb_trg_stat = ade9000.SPI_Read_16(ADDR_WFB_TRG_STAT) >> 12;
    
      // IS WFB_LAST_PAGE EQUAL TO 0xBFF?
      if(wfb_trg_stat == 7) {
        // READ 0x400 SAMPLES FROM 0x800 TO 0xBFF (PAGE 0 TO PAGE 7)
        wfb_address = 0x800;
      } else if (wfb_trg_stat == 15){
        // READ 0x400 SAMPLES FROM 0xC00 TO 0xFFF (PAGE 8 TO PAGE 15)
        wfb_address = 0xC00;
      } else {
        Serial.println("wfb_trg_stat != 7 && != 15.");
        Serial.print("wfb_trg_stat = ");
        Serial.println(wfb_trg_stat);
      }
    
      Serial.println(wfb_address, HEX);
    
    //  curent version of SPI_Burst_Read_Resampled_Wfb reads 16 bit resampled
    //  data, so has to be reworked due to fixed sampling rate data stream.
    //  for now focusing on PAGE_FULL_IRQ timings
    //  ade9000.SPI_Burst_Read_Resampled_Wfb(wfb_address,128,&resampledData);
    
    }
    
    void resetADE9000(void)
    {
     digitalWrite(ADE9000_RESET_PIN, LOW);
     delay(50);
     digitalWrite(ADE9000_RESET_PIN, HIGH);
     delay(1000);
     Serial.println("Reset Done");
    }
    
    
    
    

  • Below you can find the diff of modified Arduino sketch, based on an example from "ADE9000 Arduino Shield Evaluation Software" package, as well as source code modified by me.
    https://www.diffchecker.com/SPrCOKmM

    #include <Arduino.h>
    
    // original example code
    #include <SPI.h>
    #include  <ADE9000RegMap.h>
    #include <ADE9000API.h>
    
    /*Basic initializations*/
    ADE9000Class ade9000;
    #define SPI_SPEED 5000000     //SPI Speed
    #define CS_PIN A2 // nucleo f411 boaard 
    #define ADE9000_RESET_PIN 5 //Reset Pin on HW
    #define PM_1 4              //PM1 Pin: 4-->Arduino Zero. 15-->ESP8266 
    
    /*Structure decleration */
    struct ActivePowerRegs powerRegs;     // Declare powerRegs of type ActivePowerRegs to store Active Power Register data
    struct CurrentRMSRegs curntRMSRegs;   //Current RMS
    struct VoltageRMSRegs vltgRMSRegs;    //Voltage RMS
    struct VoltageTHDRegs voltageTHDRegsnValues; //Voltage THD
    struct ResampledWfbData resampledData; // Resampled Data
    
    /*Function Decleration*/
    void readRegisterData(void);
    void readResampledData(void);
    void resetADE9000(void);
    
    void SetupADE9000New(void) {
      ade9000.SPI_Write_16(ADDR_PGA_GAIN,0);     
      ade9000.SPI_Write_32(ADDR_CONFIG0,0); 
      ade9000.SPI_Write_16(ADDR_CONFIG1,0);
      ade9000.SPI_Write_16(ADDR_CONFIG2,0);
      ade9000.SPI_Write_16(ADDR_CONFIG3,0);
      ade9000.SPI_Write_16(ADDR_ACCMODE,0);
      ade9000.SPI_Write_16(ADDR_TEMP_CFG,0);
      ade9000.SPI_Write_16(ADDR_ZX_LP_SEL,0);
      ade9000.SPI_Write_32(ADDR_MASK0,0);
      ade9000.SPI_Write_32(ADDR_MASK1,0);
      ade9000.SPI_Write_32(ADDR_EVENT_MASK,0);
      ade9000.SPI_Write_16(ADDR_WFB_CFG,0);
      ade9000.SPI_Write_32(ADDR_VLEVEL,0);
      ade9000.SPI_Write_32(ADDR_DICOEFF,0);
      ade9000.SPI_Write_16(ADDR_EGY_TIME,0);
      ade9000.SPI_Write_16(ADDR_EP_CFG,0);
      ade9000.SPI_Write_16(ADDR_RUN,ADE9000_RUN_ON);
    }
    
    void setup() 
    {
      Serial.begin(115200);
      pinMode(PM_1, OUTPUT);    //Set PM1 pin as output 
      digitalWrite(PM_1, LOW);   //Set PM1 select pin low for PSM0 mode
      pinMode(ADE9000_RESET_PIN, OUTPUT);
      digitalWrite(ADE9000_RESET_PIN, HIGH); 
      void resetADE9000(); 
      delay(1000);
      ade9000.SPI_Init(SPI_SPEED,CS_PIN); //Initialize SPI
      SetupADE9000New();
      
      /* user code start */
      // Identyfi ADE9000
      Serial.print("ADE9000 id: ");
      Serial.println(ade9000.SPI_Read_16(0x00000472), HEX);
    
      // To set the waveform buffer, perform the following procedure:
      // 1. Write 0x03F8 to WFB_CFB (Address 0x4A0) to configure the waveform. 
      uint16_t wfb_cfg_register = 0x03F8;
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 2. Write 0'0b0 to WF_IN_EN (Bit 12) to disable waveform in
      // neutral channel to be read through the serial peripheral
      // interface (SPI).
      bitClear(wfb_cfg_register, 12);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 3. Write 0'b11 to WF_SRC (Bits[9:8]) to enable current and
      // voltage channel waveform samples processed at 8 kSPS by
      // the DSP.
      bitSet(wfb_cfg_register, 9);
      bitSet(wfb_cfg_register, 8);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 4. Write 0'b11 to WF_MODE (Bits[7:6]) to enable continuous
      // fill on the buffer. See the ADE9000 Technical Reference
      // Manual for more information on continuous filling mode.
      bitSet(wfb_cfg_register, 7);
      bitSet(wfb_cfg_register, 6);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 5. Write 0'b1 to WF_CAP_SEL (Bit 5) to enable the fixed data
      // rate sampling (noncoherent).
      bitSet(wfb_cfg_register, 5);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // 6. Write 0'b1 to WF_CAP_EN (Bit 4) to start waveform
      // capturer.
      bitSet(wfb_cfg_register, 4);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      Serial.println(wfb_cfg_register, HEX);
    
      // 7. Write 0'b0000 for all channels to BURST_CHAN
      // (Bits[3.0]) to select channels. See the ADE9000 data sheet
      // for other channels. 
      bitClear(wfb_cfg_register, 3);
      bitClear(wfb_cfg_register, 2);
      bitClear(wfb_cfg_register, 1);
      bitClear(wfb_cfg_register, 0);
      ade9000.SPI_Write_16(ADDR_WFB_CFG, wfb_cfg_register);
    
      // To execute this process, take the following steps: 
      // 1. Write 0x20000 to MASK0 (Address 0x405) to enable the page full interrupt.
      ade9000.SPI_Write_32(ADDR_MASK0, 0x20000);
      // 2. Write 0x8080 to WFB_PG_IRQWN (Address 0x4A1) to set the interrupt at Page 7 and Page 15. 
      ade9000.SPI_Write_16(ADDR_WFB_PG_IRQEN, 0x8080);
    
      Serial.print("RUN Register: ");
      Serial.println(ade9000.SPI_Read_16(ADDR_RUN),HEX);
    }
    
    void loop() {
      // readRegisterData();
      readResampledData();
      // delay(10000);
    }
    
    void readRegisterData()
    {
     /*Read and Print Specific Register using ADE9000 SPI Library */
      Serial.print("AIRMS: "); 
      Serial.println(ade9000.SPI_Read_32(ADDR_AIRMS),HEX); // AIRMS
    
     /*Read and Print RMS & WATT Register using ADE9000 Read Library*/
      ade9000.ReadVoltageRMSRegs(&vltgRMSRegs);    //Template to read Power registers from ADE9000 and store data in Arduino MCU
      ade9000.ReadActivePowerRegs(&powerRegs);
      Serial.print("AVRMS:");        
      Serial.println(vltgRMSRegs.VoltageRMSReg_A); //Print AVRMS register
      Serial.print("AWATT:");        
      Serial.println(powerRegs.ActivePowerReg_A); //Print AWATT register
    }
    
    void readResampledData()
    {
      // CLEAR INTERRUPTS, WRITE 0x20000 TO STATUS0
      ade9000.SPI_Write_32(ADDR_STATUS0, 0x20000);
    
      while(digitalRead(pinNametoDigitalPin(PA_0))) {
        ;
      }
      // POLL STATUS0, BIT 17 PAGE FULL
      uint32_t status0 = 0;
      while(1) {
        status0 = ade9000.SPI_Read_32(ADDR_STATUS0);
        // IS PAGE FULL INTERRUPT (BIT 17 IN STATUS0) TRUE?
        if(bitRead(status0, 17) == true) {
          break;
        }
      }
    
      uint16_t wfb_address = 0;
    
      // READ ADDRESS 0x4A3 WFB_TRG_STAT
      uint16_t wfb_trg_stat = ade9000.SPI_Read_16(ADDR_WFB_TRG_STAT) >> 12;
    
      // IS WFB_LAST_PAGE EQUAL TO 0xBFF?
      if(wfb_trg_stat == 7) {
        // READ 0x400 SAMPLES FROM 0x800 TO 0xBFF (PAGE 0 TO PAGE 7)
        wfb_address = 0x800;
      } else if (wfb_trg_stat == 15){
        // READ 0x400 SAMPLES FROM 0xC00 TO 0xFFF (PAGE 8 TO PAGE 15)
        wfb_address = 0xC00;
      } else {
        Serial.println("wfb_trg_stat != 7 && != 15.");
        Serial.print("wfb_trg_stat = ");
        Serial.println(wfb_trg_stat);
      }
    
      Serial.println(wfb_address, HEX);
    
    //  curent version of SPI_Burst_Read_Resampled_Wfb reads 16 bit resampled
    //  data, so has to be reworked due to fixed sampling rate data stream.
    //  for now focusing on PAGE_FULL_IRQ timings
    //  ade9000.SPI_Burst_Read_Resampled_Wfb(wfb_address,128,&resampledData);
    
    }
    
    void resetADE9000(void)
    {
     digitalWrite(ADE9000_RESET_PIN, LOW);
     delay(50);
     digitalWrite(ADE9000_RESET_PIN, HIGH);
     delay(1000);
     Serial.println("Reset Done");
    }