Post Go back to editing

ADE7763 commucation - write register issue

Hello,

I have problem with writing to ADE7763 registers. After write any value to register is readed register default value. Tested with MODE (writed 0x0005, readed 0x00C0) and IRQEN (writed 0x0010, readed 0x0040).

Clock of ADE7763 is 3.3MHz from microcontroler port. SPI is used in Mode 1 with SCL frequency 5MHz and MSB first. RESET pin ADE7763 is High.

Write timing (see fig. 3 and Table 2 in datasheet):
t1 = 620ns
t2 = 120ns
t3 = 100ns
t4 = 100ns
t5 = 100ns
t6 = 9 160ns
t7 = 7720ns
t8 = 4 480ns

For write to MODE are send 0x89, 0x00, 0x05.

Read tested from several registers and work fine. Why write don't work?

Best Regards

  • Hi Dania

    You will need to provide more information. 

    Can you provide a diagram of your connections from the micro the the ADE7763.

    Any connections the reset pin. 

    This is a 5v part are you using a 5v micro? do you have level shifters? 

    Can you scope capture the spi packet? 

    Can you share your read write code.

    maybe a picture of your setup

    Dave

  • Hi Dave

    SPI- wiring + Write WaveformsSPI packet detail

    I did not copy the analog part .5V is provided from 78L05. Actual Value is 5.02V.

    SPI.h

    :

    #ifndef SPI_H_
    #define SPI_H_
    
    #include "Ade7763.h"
    
    extern volatile bool spi_finished;
    extern volatile bool spi_busy;
    extern Ade7763* spi_device;
    
    void SpiInit();
    void SpiStartTransmision(Ade7763* device);
    void SpiWaitForTransferComplete();
    
    
    #endif /* SPI_H_ */

    SPI.cpp:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "Ade7763.h"
    
    
    #define SS_PIN_MASK			0x10
    
    
    volatile uint8_t transfered;
    volatile bool spi_finished = false;
    volatile bool spi_busy = false;
    Ade7763* spi_device;
    
    
    
    void SpiInit()
    {
    	PORTA.OUTSET = SS_PIN_MASK;	//deselect all SS
    	PORTB.OUTSET = SS_PIN_MASK;
    	SPI0.CTRLA = 0x20;			//Master, CLK/4
    	SPI0.CTRLB = 0x05;			//SS disabled, SPI Mode 1
    	SPI0.INTCTRL = 0x01;		//interrupts enable
    	SPI0.CTRLA |= 0x01;			//SPI enable
    }
    
    void SpiStartTransmision(Ade7763* device)
    {
    	spi_busy = true;
    	spi_device = device;
    	spi_device->port->OUTCLR = SS_PIN_MASK;
    	transfered = 0;
    	SPI0.DATA = spi_device->command[0];
    }
    
    void SpiWaitForTransferComplete()
    {
    	while(!spi_finished)
    	{
    	}
    	spi_busy = false;
    	spi_finished = false;
    }
    
    ISR(SPI0_INT_vect)
    {
    	spi_device->in_data[transfered] = SPI0.INTFLAGS;
    	spi_device->in_data[transfered] = SPI0.DATA;
    	if (++transfered < spi_device->lenght)
    	{	//send next byte after min 4 mikrosec pause
    		TCA0.SINGLE.PER = 84;			//interval cca 4.2 mikrosec
    		TCA0.SINGLE.CNT = 0;
    		TCA0.SINGLE.INTCTRL = 0x01;		//Overflow interrupt enable
    		TCA0.SINGLE.CTRLA = 0x01;		//Start without divider
    	}
    	else
    	{
    		//deselect all SS
    		spi_finished = true;
    		PORTA.OUTSET = SS_PIN_MASK;
    		PORTB.OUTSET = SS_PIN_MASK;
    	}
    }
    
    ISR(TCA0_OVF_vect)
    {	//send next byte to SPI after min 4 mikrosec pause
    	TCA0.SINGLE.CTRLA = 0x00;
    	TCA0.SINGLE.INTFLAGS = 0x01;	//reset overflow interrupt flag
    	SPI0.DATA = spi_device->command[transfered];
    }

    ADE7763.h:

    #ifndef __ADE7763_H__
    #define __ADE7763_H__
    
    #include <avr/io.h>
    
    //ADE7763 Registers use: Register_neme | Direction
    //Example MODE | WRITE
    typedef enum {
    	WAVEFORM =	0x01,
    	AENERGY =	0x02,
    	RAENERGY =	0x03,
    	LAENERGY =	0x04,
    	VAENERGY =	0x05,
    	RVAENERGY =	0x06,
    	LVAENERGY = 0X07,
    	MODE =		0x09,
    	IRQEN =		0x0A,
    	STATUS =	0x0B,
    	RSTSTATUS =	0x0C,
    	CH1SO =		0x0D,
    	CH2OS =		0x0E,
    	GAIN =		0x0F,
    	PHCAL =		0x10,
    	APOS =		0x11,
    	WGAIN =		0x12,
    	WDIV =		0x13,
    	CFNUM =		0x14,
    	CFDEN =		0x15,
    	IRMS =		0x16,
    	VRMS =		0x17,
    	IRMSOS =	0x18,
    	VRMSOS =	0x19,
    	VAGAIN =	0x1A,
    	VADIV =		0x1B,
    	LINECYC =	0x1C,
    	ZXTOUT =	0x1D,
    	SAGCYC =	0x1E,
    	SAGLVL =	0x1F,
    	IPKLVL =	0x20,
    	VPKLVL =	0x21,
    	IPEAK =		0x22,
    	RSTIPEAK =	0x23,
    	VPEAK =		0x24,
    	RSTVPEAK =	0x25,
    	TEMP =		0x26,
    	PERIOD =	0x27,
    	TMODE =		0x3D,
    	CHKSUM =	0x3E,
    	DIEREV =	0x3f,
    	
    	READ =		0x00,
    	WRITE =		0x80
    } Registers;
    
    typedef enum{
    	SAG = 0x0002,
    	CYCEND = 0x0004,
    	ZX = 0x0010,			//Zero-Crossing detection
    	RESET = 0x0040,
    	ZXTO = 0x1000			//Zero-Crossing missing 
    	}IRQ_BIT_MASK;
    
    typedef enum{
    	NONE,					//wait for zero crossing interrupt
    	VOLT_READ_REQ,
    	READ_VOLTAGE,
    	CURR_READ_REQ,
    	READ_CURRENT,
    	POWER_READ_REQ,
    	READ_POWER,
    	IGNORE_READ,
    	
    	INT_STATE_REQ,			//read interrupt state requested
    	READ_INT_STATE,
    	DECODE_INT_STATE
    	} States;
    
    #define RELAY_PIN_MASK		0x20
    #define IRQ_PIN_MASK		0x08
    #define INPUT_PIN_MASK		0x40
    #define RESET_PIN_MASK		0x08
    
    class Ade7763
    {
    //variables
    public:
    	PORT_t* port;
    	uint8_t command[4];
    	volatile uint8_t lenght;
    	volatile uint8_t* in_data;		//pointer to input buffer
    
    	volatile uint8_t data_buffer[4];
    	volatile uint8_t voltage[4];
    	volatile uint8_t current[4];
    	volatile uint8_t power[4];
    	
    	volatile uint8_t scheduler_irq_status;
    	volatile uint8_t scheduler_status;
    	volatile uint16_t irq_status_reg;
    protected:
    private:
    
    	
    //functions
    public:
    	Ade7763();
    	Ade7763(PORT_t* control_port);
    	~Ade7763();
    	
    	void Init();
    	void ReadModeReg();
    	void WriteModeReg(uint16_t value);
    	void WriteInterruptEnableRegister(uint16_t value);
    	void ReadInterruptEnableRegister();
    	void ReadRstInterruptStatusRegister();
    	void SetSagLevelRegister(uint8_t value);
    	void SetSagCycleRegister(uint8_t value);
    	void SetLineCycRegister(uint16_t value);
    	uint16_t Get16BitData();
    
    protected:
    private:
    	Ade7763( const Ade7763 &c );
    	Ade7763& operator=( const Ade7763 &c );
    
    }; //Ade7763
    
    #endif //__ADE7763_H__

    ADE7763.cpp:

    //#include "Ade7763.h"
    #include "SPI.h"
    #include <string.h>
    
    
    
    
    // default constructor
    Ade7763::Ade7763()
    {
    	scheduler_irq_status = NONE;
    	scheduler_status = NONE;
    } //Ade7763
    
     Ade7763::Ade7763(PORT_t* control_port)
     {
    	port = control_port;
    	scheduler_irq_status = NONE;
    	scheduler_status = NONE;
     }
    
    // default destructor
    Ade7763::~Ade7763()
    {
    } //~Ade7763
    
    
    void Ade7763::Init()
    {
    	uint16_t rst_status;
    	
    
    	PORTC.OUTSET = RESET_PIN_MASK;			//ADE7763 RESET pins go High
    	do										//Wait for Reset Done
    	{
    		ReadRstInterruptStatusRegister();
    		SpiWaitForTransferComplete();
    		rst_status = Get16BitData();
    	} while (!(rst_status & RESET));
    
    	WriteModeReg(0x0005);
    	SpiWaitForTransferComplete();
    }
    
    void Ade7763::ReadModeReg()
    {
    	uint8_t p[] = {MODE | READ, 0xFF, 0xFF};
    	memcpy(command, p, 3);
    	in_data = data_buffer;
    	lenght = 3;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::WriteModeReg(uint16_t value)
    {
    	command[0] = MODE | WRITE;
    	command[1] = value >> 8;
    	command[2] = value & 0x00FF;
    	in_data = data_buffer;
    	lenght = 3;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::WriteInterruptEnableRegister(uint16_t value)
    {
    	command[0] = IRQEN | WRITE;
    	command[1] = value >> 8;
    	command[2] = value & 0x00FF;
    	in_data = data_buffer;
    	lenght = 3;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::ReadInterruptEnableRegister()
    {
    	uint8_t p[] = {IRQEN | READ, 0xFF, 0xFF};
    	memcpy(command, p, 3);
    	in_data = data_buffer;
    	lenght = 3;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::ReadRstInterruptStatusRegister()
    {
    	uint8_t p[] = {RSTSTATUS | READ, 0xFF, 0xFF};
    	memcpy(command, p, 3);
    	in_data = data_buffer;
    	lenght = 3;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::SetSagLevelRegister(uint8_t value)
    {
    	command[0] = SAGLVL | WRITE;
    	command[1] = value;
    	in_data = data_buffer;
    	lenght = 2;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::SetSagCycleRegister(uint8_t value)
    {
    	command[0] = SAGCYC | WRITE;
    	command[1] = value;
    	in_data = data_buffer;
    	lenght = 2;
    	SpiStartTransmision(this);
    }
    
    void Ade7763::SetLineCycRegister(uint16_t value)
    {
    	command[0] = LINECYC | WRITE;
    	command[1] = value >> 8;
    	command[2] = value & 0xFF;
    	in_data = data_buffer;
    	lenght = 3;
    	SpiStartTransmision(this);
    }
    
    uint16_t Ade7763::Get16BitData()
    {
    	return ((uint32_t)data_buffer[1] << 8) | data_buffer[2];
    }

    main.cpp:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include "SPI.h"
    #include "Ade7763.h"
    
    
    #define PA_DIRECTION_MASK	0xB0	//PA4, PA5, PA7 = outputs
    #define PB_DIRECTION_MASK	0x37	//PB0, PB1, PB2, PB4, PB5 = outputs
    #define PC_DIRECTION_MASK	0x0D	//PC0, PC2, PC3 = outputs
    
    #define VACUUM_PORT			(&PORTB)	//pointer to vacuum port
    #define VACUMM_INTERRUPT	PORTB_PORT_vect
    
    
    Ade7763 Vacuum(VACUUM_PORT);
    
    uint16_t stav;
    
    
    
    
    int main(void)
    {
        //Switch MCLK without divide
        uint8_t div = 0;
        CCP = CCP_IOREG_gc;
        CLKCTRL.MCLKCTRLB = div;
        
        //Ports setup
        PORTMUX.CTRLB = 0x14;				//alternate pins used for IIC and SPI
        PORTA.DIRSET = PA_DIRECTION_MASK;
        PORTB.DIRSET = PB_DIRECTION_MASK;
        PORTC.DIRSET = PC_DIRECTION_MASK;
        PORTA.PIN3CTRL = 0x08;				//Pullup enabled
        PORTB.PIN3CTRL = 0x08;				//Pullup enabled
        
        //TCA WO0 (PB0) as Clock Generator 3,33MHz for ADE7763
        TCA0.SINGLE.CMP0 = 0x0002;
        TCA0.SINGLE.CTRLB = 0x71;			//Frequency Mode
        TCA0.SINGLE.CTRLA = 0x01;			//Start, clock no divided
    	
    	//SPI
    	SpiInit();
    
    	sei();
    	
    	//ADE7763 Init
    	Vacuum.Init();
    	
    	//Read
    	Vacuum.ReadModeReg();
    	SpiWaitForTransferComplete();
    	
        while (1) 
        {
    		asm("nop");
        }
    }

    Microchip Studio 7.0 used.

  • Cause: Clock of ADE7763 is 3.3MHz

    With Clock = 3,579545MHz write and read registers is OK.

    Analog Devices had quality and fast technical support. This forum is just a bad substitute.

  • The 3.3Mhz will limit the max speed of the spi port but will work if the spi is slowed down. 

  • It would have been useful to see the crystal in pin signal during you spi transfer. 

    But happy you figured it out. 

  • The Clock period has been extended by about 7%. I expected the write timing to be extended by 7% as well. In the first post, I presented the measured values. I think SPI with 5MHz is slow enough. I should have learned the dependence of write timing from the datasheet or, worse, from technical support. I just got the experience that I can't expect help with the application of AD products.

  • This clk for this part is from 1Mhz to 4 Mhz 3.3Mhz should have fine unless the 3.3Mhz clk provided from the micro has an issue or there was a spi timing issue. 

    glad you resolved you issue.

  • ATTINY 416 TCA timer in frequency mode is used. The timer works as a hardware divider without any CPU interventions. The frequency is stable just like the RC oscillator in ATTINY 416.