1125 lines
41 KiB
C
Executable File
1125 lines
41 KiB
C
Executable File
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include "driver/spi_master.h"
|
||
#include "sdkconfig.h"
|
||
#include "esp_log.h"
|
||
#include "ade7758.h"
|
||
#include "driver/gpio.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include "esp_rom_sys.h"
|
||
|
||
|
||
|
||
#define PIN_ADUM_EN 4 // ou o pino real conectado ao VE1 do ADUM1401
|
||
|
||
|
||
static const char *TAG = "ade7758";
|
||
|
||
// --- SPI internals ---
|
||
static spi_device_handle_t ade7758_spi_handle = NULL;
|
||
static spi_host_device_t spi_host = SPI2_HOST; // default
|
||
|
||
static spi_transaction_t spi_transaction;
|
||
|
||
// --- Configuração SPI do dispositivo ---
|
||
static const uint8_t MODE = 2;
|
||
static const uint8_t ADDR_BITS = 7;
|
||
static const uint8_t CMD_BITS = 1;
|
||
static const uint8_t SPI_WRITE = 1;
|
||
static const uint8_t SPI_READ = 0;
|
||
static const int BUS_SPEED_HZ = 1000000;
|
||
|
||
|
||
static void adum1401_select(void) {
|
||
gpio_set_level(PIN_ADUM_EN, 1);
|
||
esp_rom_delay_us(2); // curto delay para estabilização
|
||
}
|
||
|
||
static void adum1401_deselect(void) {
|
||
esp_rom_delay_us(2); // opcional: aguarde para evitar glitch
|
||
gpio_set_level(PIN_ADUM_EN, 0);
|
||
}
|
||
|
||
// === Transações básicas ===
|
||
|
||
static esp_err_t transfer_byte(uint8_t reg_addr, uint8_t data, uint8_t command) {
|
||
adum1401_select();
|
||
|
||
spi_transaction.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
|
||
spi_transaction.length = 8;
|
||
spi_transaction.cmd = command;
|
||
spi_transaction.addr = reg_addr;
|
||
spi_transaction.tx_data[0] = data;
|
||
|
||
esp_err_t err = spi_device_transmit(ade7758_spi_handle, &spi_transaction);
|
||
|
||
adum1401_deselect();
|
||
return err;
|
||
}
|
||
|
||
|
||
static esp_err_t transfer_bytes(uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t len, uint8_t command) {
|
||
if (len < 1) len = 1;
|
||
|
||
spi_transaction_t t = {
|
||
.flags = 0,
|
||
.length = 8 * len,
|
||
.cmd = command,
|
||
.addr = reg_addr,
|
||
.tx_buffer = tx_buf,
|
||
.rx_buffer = rx_buf
|
||
};
|
||
|
||
adum1401_select();
|
||
esp_err_t err = spi_device_transmit(ade7758_spi_handle, &t);
|
||
adum1401_deselect();
|
||
return err;
|
||
}
|
||
|
||
|
||
// === Interface pública ===
|
||
|
||
esp_err_t Init(spi_host_device_t host, int pin_miso, int pin_mosi, int pin_sclk) {
|
||
// Essa função não inicializa o barramento SPI
|
||
// Apenas armazena os parâmetros
|
||
spi_host = host;
|
||
return ESP_OK;
|
||
}
|
||
|
||
esp_err_t InitSpi(int cs_gpio) {
|
||
spi_device_interface_config_t devcfg = {
|
||
.command_bits = CMD_BITS,
|
||
.address_bits = ADDR_BITS,
|
||
.mode = MODE,
|
||
.clock_speed_hz = BUS_SPEED_HZ,
|
||
.spics_io_num = cs_gpio,
|
||
.queue_size = 5,
|
||
};
|
||
|
||
gpio_config_t io_conf = {
|
||
.pin_bit_mask = BIT64(PIN_ADUM_EN),
|
||
.mode = GPIO_MODE_OUTPUT,
|
||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||
.intr_type = GPIO_INTR_DISABLE
|
||
};
|
||
gpio_config(&io_conf);
|
||
gpio_set_level(PIN_ADUM_EN, 0); // inicialmente desativado
|
||
|
||
|
||
return spi_bus_add_device(spi_host, &devcfg, &ade7758_spi_handle);
|
||
}
|
||
|
||
spi_device_handle_t GetHandle(void) {
|
||
return ade7758_spi_handle;
|
||
}
|
||
|
||
// === Registro de acesso ===
|
||
|
||
uint8_t ReadRegister(uint8_t reg_addr, uint8_t command) {
|
||
transfer_byte(reg_addr, 0, command);
|
||
return spi_transaction.rx_data[0];
|
||
}
|
||
|
||
esp_err_t WriteRegister(uint8_t reg_addr, uint8_t data, uint8_t command) {
|
||
return transfer_byte(reg_addr, data, command);
|
||
}
|
||
|
||
esp_err_t WriteRegisterMultipleBytes(uint8_t reg, uint8_t *data, uint8_t count, uint8_t command) {
|
||
return transfer_bytes(reg, data, NULL, count, command);
|
||
}
|
||
|
||
esp_err_t ReadRegisterMultipleBytes(uint8_t reg, uint8_t *buf, uint8_t count, uint8_t command) {
|
||
return transfer_bytes(reg, NULL, buf, count, command);
|
||
}
|
||
|
||
// === Leitura e escrita de tamanho fixo ===
|
||
|
||
esp_err_t write8(uint8_t reg, uint8_t value) {
|
||
return WriteRegister(reg, value, SPI_WRITE);
|
||
}
|
||
|
||
esp_err_t write16(uint8_t reg, uint32_t value) {
|
||
uint8_t buf[2] = {
|
||
(value >> 8) & 0xFF,
|
||
(value >> 0) & 0xFF
|
||
};
|
||
return WriteRegisterMultipleBytes(reg, buf, 2, SPI_WRITE);
|
||
}
|
||
|
||
esp_err_t write24(uint8_t reg, uint32_t value) {
|
||
uint8_t buf[3] = {
|
||
(value >> 16) & 0xFF,
|
||
(value >> 8) & 0xFF,
|
||
(value >> 0) & 0xFF
|
||
};
|
||
return WriteRegisterMultipleBytes(reg, buf, 3, SPI_WRITE);
|
||
}
|
||
|
||
uint8_t read8(uint8_t reg) {
|
||
uint8_t buf[1];
|
||
ReadRegisterMultipleBytes(reg, buf, 1, SPI_READ);
|
||
return buf[0];
|
||
}
|
||
|
||
uint32_t read16(uint8_t reg) {
|
||
uint8_t buf[2];
|
||
ReadRegisterMultipleBytes(reg, buf, 2, SPI_READ);
|
||
return (buf[0] << 8) | buf[1];
|
||
}
|
||
|
||
uint32_t read24(uint8_t reg) {
|
||
uint8_t buf[3];
|
||
ReadRegisterMultipleBytes(reg, buf, 3, SPI_READ);
|
||
return (buf[0] << 16) | (buf[1] << 8) | buf[2];
|
||
}
|
||
|
||
esp_err_t readBlockData(uint8_t reg, uint8_t *buf, int len) {
|
||
return ReadRegisterMultipleBytes(reg, buf, len, SPI_READ);
|
||
}
|
||
|
||
|
||
/*****************************
|
||
*
|
||
* public functions
|
||
*
|
||
*****************************/
|
||
|
||
/**
|
||
* In general:
|
||
* @params: void
|
||
* @return: register content (measure) of the proper type depending on register width
|
||
*/
|
||
|
||
unsigned char getVersion()
|
||
{
|
||
return read8(VERSION);
|
||
}
|
||
|
||
/** === setOpMode / getOpMode ===
|
||
OPERATIONAL MODE REGISTER (0x13)
|
||
The general configuration of the ADE7758 is defined by writing to the OPMODE register.
|
||
Table 18 summarizes the functionality of each bit in the OPMODE register.
|
||
|
||
Bit Location Bit Mnemonic Default Value Description
|
||
0 DISHPF 0 The HPFs in all current channel inputs are disabled when this bit is set.
|
||
1 DISLPF 0 The LPFs after the watt and VAR multipliers are disabled when this bit is set.
|
||
2 DISCF 1 The frequency outputs APCF and VARCF are disabled when this bit is set.
|
||
3 to 5 DISMOD 0 By setting these bits, ADE7758<35>s ADCs can be turned off. In normal operation, these bits should be left at Logic 0.
|
||
DISMOD[2:0] Description
|
||
0 0 0 Normal operation.
|
||
1 0 0 Redirect the voltage inputs to the signal paths for the current channels and the current inputs to the signal paths for the voltage channels.
|
||
0 0 1 Switch off only the current channel ADCs.
|
||
1 0 1 Switch off current channel ADCs and redirect the current input signals to the voltage channel signal paths.
|
||
0 1 0 Switch off only the voltage channel ADCs.
|
||
1 1 0 Switch off voltage channel ADCs and redirect the voltage input signals to the current channel signal paths.
|
||
0 1 1 Put the ADE7758 in sleep mode.
|
||
1 1 1 Put the ADE7758 in power-down mode (reduces AIDD to 1 mA typ).
|
||
6 SWRST 0 Software Chip Reset. A data transfer to the ADE7758 should not take place for at least 18 <20>s after a software reset.
|
||
7 RESERVED 0 This should be left at 0.
|
||
|
||
*/
|
||
|
||
void setOpMode(uint8_t m)
|
||
{
|
||
write8(OPMODE, m);
|
||
}
|
||
uint8_t getOpMode()
|
||
{
|
||
return read8(OPMODE);
|
||
}
|
||
|
||
/** === setMMode / getMMode ===
|
||
MEASUREMENT MODE REGISTER (0x14)
|
||
The configuration of the PERIOD and peak measurements made by the ADE7758 is defined by writing to the MMODE register.
|
||
Table 19 summarizes the functionality of each bit in the MMODE register.
|
||
|
||
Bit Location Bit Mnemonic Default Value Description
|
||
0 to 1 FREQSEL 0 These bits are used to select the source of the measurement of the voltage line frequency.
|
||
FREQSEL1 FREQSEL0 Source
|
||
0 0 Phase A
|
||
0 1 Phase B
|
||
1 0 Phase C
|
||
1 1 Reserved
|
||
2 to 4 PEAKSEL 7 These bits select the phases used for the voltage and current peak registers.
|
||
Setting Bit 2 switches the IPEAK and VPEAK registers to hold the absolute values
|
||
of the largest current and voltage waveform (over a fixed number of half-line cycles)
|
||
from Phase A. The number of half-line cycles is determined by the content of the
|
||
LINECYC register. At the end of the LINECYC number of half-line cycles, the content
|
||
of the registers is replaced with the new peak values. Similarly, setting Bit 3 turns
|
||
on the peak detection for Phase B, and Bit 4 for Phase C. Note that if more than one
|
||
bit is set, the VPEAK and IPEAK registers can hold values from two different phases, that is,
|
||
the voltage and current peak are independently processed (see the Peak Current Detection section).
|
||
5 to 7 PKIRQSEL 7 These bits select the phases used for the peak interrupt detection.
|
||
Setting Bit 5 switches on the monitoring of the absolute current and voltage waveform to Phase A.
|
||
Similarly, setting Bit 6 turns on the waveform detection for Phase B, and Bit 7 for Phase C.
|
||
Note that more than one bit can be set for detection on multiple phases.
|
||
If the absolute values of the voltage or current waveform samples in the selected phases exceeds
|
||
the preset level specified in the VPINTLVL or IPINTLVL registers the corresponding bit(s) in the
|
||
STATUS registers are set (see the Peak Current Detection section).
|
||
|
||
*/
|
||
|
||
void setMMode(uint8_t m)
|
||
{
|
||
write8(MMODE, m);
|
||
}
|
||
uint8_t getMMode(void)
|
||
{
|
||
return read8(MMODE);
|
||
}
|
||
|
||
/** === setWavMode / getWavMode ===
|
||
WAVEFORM MODE REGISTER (0x15)
|
||
The waveform sampling mode of the ADE7758 is defined by writing to the WAVMODE register.
|
||
Table 20 summarizes the functionality of each bit in the WAVMODE register.
|
||
|
||
Bit Location Bit Mnemonic Default Value Description
|
||
0 to 1 PHSEL 0 These bits are used to select the phase of the waveform sample.
|
||
PHSEL[1:0] Source
|
||
0 0 Phase A
|
||
0 1 Phase B
|
||
1 0 Phase C
|
||
1 1 Reserved
|
||
2 to 4 WAVSEL 0 These bits are used to select the type of waveform.
|
||
WAVSEL[2:0] Source
|
||
0 0 0 Current
|
||
0 0 1 Voltage
|
||
0 1 0 Active Power Multiplier Output
|
||
0 1 1 Reactive Power Multiplier Output
|
||
1 0 0 VA Multiplier Output
|
||
-Others- Reserved
|
||
5 to 6 DTRT 0 These bits are used to select the data rate.
|
||
DTRT[1:0] Update Rate
|
||
0 0 26.04 kSPS (CLKIN/3/128)
|
||
0 1 13.02 kSPS (CLKIN/3/256)
|
||
1 0 6.51 kSPS (CLKIN/3/512)
|
||
1 1 3.25 kSPS (CLKIN/3/1024)
|
||
7 VACF 0 Setting this bit to Logic 1 switches the VARCF output pin to an output
|
||
frequency that is proportional to the total apparent power (VA).
|
||
In the default state, Logic 0, the VARCF pin outputs a frequency proportional
|
||
to the total reactive power (VAR).
|
||
*/
|
||
|
||
void setWavMode(uint8_t m)
|
||
{
|
||
write8(WAVMODE, m);
|
||
}
|
||
uint8_t getWavMode()
|
||
{
|
||
return read8(WAVMODE);
|
||
}
|
||
|
||
/** === setCompMode / getCompMode ===
|
||
|
||
COMPUTATIONAL MODE REGISTER (0x16)
|
||
The computational method of the ADE7758 is defined by writing to the COMPMODE register.
|
||
|
||
Bit Location Bit Mnemonic Default Value Description
|
||
0 to 1 CONSEL 0 These bits are used to select the input to the energy accumulation registers.
|
||
CONSEL[1:0] = 11 is reserved. IA, IB, and IC are IA, IB, and IC phase shifted by <20>90<39>, respectively.
|
||
Registers CONSEL[1, 0] = 00 CONSEL[1, 0] = 01 CONSEL[1, 0] = 10
|
||
AWATTHR VA <20> IA VA <20> (IA <20> IB) VA <20> (IA<49>IB)
|
||
BWATTHR VB <20> IB 0 0
|
||
CWATTHR VC <20> IC VC <20> (IC <20> IB) VC <20> IC
|
||
|
||
AVARHR VA <20> IA VA <20> (IA <20> IB) VA <20> (IA<49>IB)
|
||
BVARHR VB <20> IB 0 0
|
||
CVARHR VC <20> IC VC <20> (IC <20> IB) VC <20> IC
|
||
|
||
AVAHR VARMS <20> IARMS VARMS <20> IARMS VARMS <20> ARMS
|
||
BVAHR VBRMS <20> IBRMS (VARMS + VCRMS)/2 <20> IBRMS VARMS <20> IBRMS
|
||
CVAHR VCRMS <20> ICRMS VCRMS <20> ICRMS VCRMS <20> ICRMS
|
||
|
||
2 to 4 TERMSEL 7 These bits are used to select the phases to be included in the APCF and VARCF pulse outputs.
|
||
Setting Bit 2 selects Phase A (the inputs to AWATTHR and AVARHR registers) to be included.
|
||
Bit 3 and Bit 4 are for Phase B and Phase C, respectively.
|
||
Setting all three bits enables the sum of all three phases to be included in the frequency outputs
|
||
(see the Active Power Frequency Output and the Reactive Power Frequency Output sections).
|
||
|
||
5 ABS 0 Setting this bit places the APCF output pin in absolute only mode.
|
||
Namely, the APCF output frequency is proportional to the sum of the absolute values of the watt-hour
|
||
accumulation registers (AWATTHR, BWATTHR, and CWATTHR).
|
||
Note that this bit only affects the APCF pin and has no effect on the content of the corresponding
|
||
registers.
|
||
|
||
6 SAVAR 0 Setting this bit places the VARCF output pin in the signed adjusted mode.
|
||
Namely, the VARCF output frequency is proportional to the sign-adjusted sum of the VAR-hour accumulation
|
||
registers (AVARHR, BVARHR, and CVARHR).
|
||
The sign of the VAR is determined from the sign of the watt calculation from the corresponding phase,
|
||
that is, the sign of the VAR is flipped if the sign of the watt is negative, and if the watt is positive,
|
||
there is no change to the sign of the VAR.
|
||
Note that this bit only affects the VARCF pin and has no effect on the content of the corresponding
|
||
registers.
|
||
|
||
7 NOLOAD 0 Setting this bit activates the no-load threshold in the ADE7758.
|
||
*/
|
||
|
||
void setCompMode(uint8_t m)
|
||
{
|
||
write8(COMPMODE, m);
|
||
}
|
||
uint8_t getCompMode(void)
|
||
{
|
||
return read8(COMPMODE);
|
||
}
|
||
|
||
/** === setLcycMode / getLcycMode ===
|
||
|
||
LINE CYCLE ACCUMULATION MODE REGISTER (0x17)
|
||
The functionalities involved the line-cycle accumulation mode in the ADE7758 are defined by writing to the LCYCMODE register.
|
||
|
||
Bit Location Bit Mnemonic Default Value Description
|
||
|
||
0 LWATT 0 Setting this bit places the watt-hour accumulation registers
|
||
(AWATTHR, BWATTHR, and CWATTHR registers) into line-cycle accumulation mode.
|
||
1 LVAR 0 Setting this bit places the VAR-hour accumulation registers (AVARHR, BVARHR, and CVARHR registers)
|
||
into line-cycle accumulation mode.
|
||
2 LVA 0 Setting this bit places the VA-hour accumulation registers (AVAHR, BVAHR, and CVAHR registers)
|
||
into line-cycle accumulation mode.
|
||
3 to 5 ZXSEL 7 These bits select the phases used for counting the number of zero crossings in the line-cycle
|
||
accumulation mode. Bit 3, Bit 4, and Bit 5 select Phase A, Phase B, and Phase C, respectively.
|
||
More than one phase can be selected for the zero-crossing detection,
|
||
and the accumulation time is shortened accordingly.
|
||
6 RSTREAD 1 Setting this bit enables the read-with-reset for all the WATTHR, VARHR, and VAHR registers for all three
|
||
phases, that is, a read to those registers resets the registers to 0 after the content of the registers
|
||
have been read. This bit should be set to Logic 0 when the LWATT, LVAR, or LVA bits are set to Logic 1.
|
||
7 FREQSEL 0 Setting this bit causes the FREQ (0x10) register to display the period, instead of the frequency of the
|
||
line input.
|
||
*/
|
||
|
||
void setLcycMode(uint8_t m)
|
||
{
|
||
write8(LCYCMODE, m);
|
||
}
|
||
uint8_t getLcycMode(void)
|
||
{
|
||
return read8(LCYCMODE);
|
||
}
|
||
|
||
/** === gainSetup ===
|
||
GAIN REGISTER (0x23)
|
||
The PGA configuration of the ADE7758 is defined by writing to the GAIN register.
|
||
Table 18 summarizes the functionality of each bit in the GAIN register.
|
||
|
||
Bit Location Bit Mnemonic Default Value Description
|
||
0 to 1 PGA1 0 Current GAIN
|
||
PGA1[1:0] Description
|
||
0 0 x1
|
||
0 1 x2
|
||
1 0 x4
|
||
1 1 RESERVED
|
||
2 ---- RESERVED Reserved.
|
||
3 to 4 SCALE 0 Current input full-scale select
|
||
SCALE[1:0] Description
|
||
0 0 0.5v
|
||
0 1 0.25v
|
||
1 0 0.125v
|
||
1 1 Reserved
|
||
5 to 6 PGA2 0 Voltage GAIN
|
||
PGA2[1:0] Description
|
||
0 0 x1
|
||
0 1 x2
|
||
1 0 x4
|
||
1 1 RESERVED
|
||
7 INTEGRATOR 0 This bit enables the integrator on the current chanel when set.
|
||
*/
|
||
|
||
void gainSetup(uint8_t integrator, uint8_t scale, uint8_t PGA2, uint8_t PGA1)
|
||
{
|
||
char pgas = (integrator << 7) | (PGA2 << 5) | (scale << 3) | (PGA1);
|
||
write8(GAIN, pgas); // write GAIN register, format is |3 bits PGA2 gain|2 bits full scale|3 bits PGA1 gain
|
||
}
|
||
|
||
void setupDivs(uint8_t Watt_div, uint8_t VAR_div, uint8_t VA_div)
|
||
{
|
||
write8(WDIV, Watt_div);
|
||
write8(VARDIV, VAR_div);
|
||
write8(VADIV, VA_div);
|
||
}
|
||
|
||
/** === getMaskInterrupts / setMaskInterrupts
|
||
MASK REGISTER (0x18)
|
||
When an interrupt event occurs in the ADE7758, the IRQ logic output goes active low if the mask bit for this event is Logic 1 in the MASK register.
|
||
The IRQ logic output is reset to its default collector open state when the RSTATUS register is read.
|
||
describes the function of each bit in the interrupt mask register.
|
||
|
||
Bit Location Interrupt Flag Default Value Description
|
||
0 AEHF 0 Enables an interrupt when there is a change in Bit 14 of any one of the three WATTHR registers,
|
||
that is, the WATTHR register is half full.
|
||
1 REHF 0 Enables an interrupt when there is a change in Bit 14 of any one of the three VARHR registers,
|
||
that is, the VARHR register is half full.
|
||
2 VAEHF 0 Enables an interrupt when there is a 0 to 1 transition in the MSB of any one of the three VAHR
|
||
registers, that is, the VAHR register is half full.
|
||
3 SAGA 0 Enables an interrupt when there is a SAG on the line voltage of the Phase A.
|
||
4 SAGB 0 Enables an interrupt when there is a SAG on the line voltage of the Phase B.
|
||
5 SAGC 0 Enables an interrupt when there is a SAG on the line voltage of the Phase C.
|
||
6 ZXTOA 0 Enables an interrupt when there is a zero-crossing timeout detection on Phase A.
|
||
7 ZXTOB 0 Enables an interrupt when there is a zero-crossing timeout detection on Phase B.
|
||
8 ZXTOC 0 Enables an interrupt when there is a zero-crossing timeout detection on Phase C.
|
||
9 ZXA 0 Enables an interrupt when there is a zero crossing in the voltage channel of Phase A
|
||
(see the Zero-Crossing Detection section).
|
||
10 ZXB 0 Enables an interrupt when there is a zero crossing in the voltage channel of Phase B
|
||
(see the Zero-Crossing Detection section).
|
||
11 ZXC 0 Enables an interrupt when there is a zero crossing in the voltage channel of Phase C
|
||
(see the Zero-Crossing Detection section).
|
||
12 LENERGY 0 Enables an interrupt when the energy accumulations over LINECYC are finished.
|
||
13 RESERVED 0 Reserved.
|
||
14 PKV 0 Enables an interrupt when the voltage input selected in the MMODE register is above
|
||
the value in the VPINTLVL register.
|
||
15 PKI 0 Enables an interrupt when the current input selected in the MMODE register is above the
|
||
value in the IPINTLVL register.
|
||
16 WFSM 0 Enables an interrupt when data is present in the WAVEMODE register.
|
||
17 REVPAP 0 Enables an interrupt when there is a sign change in the watt calculation among any one of
|
||
the phases specified by the TERMSEL bits in the COMPMODE register.
|
||
18 REVPRP 0 Enables an interrupt when there is a sign change in the VAR calculation among any one of
|
||
the phases specified by the TERMSEL bits in the COMPMODE register.
|
||
19 SEQERR 0 Enables an interrupt when the zero crossing from Phase A is followed not by the zero crossing
|
||
of Phase C but with that of Phase B.
|
||
*/
|
||
uint32_t getMaskInterrupts(void)
|
||
{
|
||
return read24(MASK);
|
||
}
|
||
void setMaskInterrupts(uint32_t m)
|
||
{
|
||
write24(MASK, m);
|
||
}
|
||
/** getStatus / resetStatus
|
||
INTERRUPT STATUS REGISTER (0x19)/RESET INTERRUPT STATUS REGISTER (0x1A)
|
||
The interrupt status register is used to determine the source of an interrupt event.
|
||
When an interrupt event occurs in the ADE7758, the corresponding flag in the interrupt status register is set.
|
||
The IRQ pin goes active low if the corresponding bit in the interrupt mask register is set.
|
||
When the MCU services the interrupt, it must first carry out a read from the interrupt status register to determine the source of the interrupt.
|
||
All the interrupts in the interrupt status register stay at their logic high state after an event occurs.
|
||
The state of the interrupt bit in the interrupt status register is reset to its default value once the reset interrupt status register is read.
|
||
|
||
Bit Location Interrupt Flag Default Value Event Description
|
||
0 AEHF 0 Indicates that an interrupt was caused by a change in Bit 14 among any one of the three
|
||
WATTHR registers, that is, the WATTHR register is half full.
|
||
1 REHF 0 Indicates that an interrupt was caused by a change in Bit 14 among any one of the three
|
||
VARHR registers, that is, the VARHR register is half full.
|
||
2 VAEHF 0 Indicates that an interrupt was caused by a 0 to 1 transition in Bit 15 among any one of the three
|
||
VAHR registers, that is, the VAHR register is half full.
|
||
3 SAGA 0 Indicates that an interrupt was caused by a SAG on the line voltage of the Phase A.
|
||
4 SAGB 0 Indicates that an interrupt was caused by a SAG on the line voltage of the Phase B.
|
||
5 SAGC 0 Indicates that an interrupt was caused by a SAG on the line voltage of the Phase C.
|
||
6 ZXTOA 0 Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase A.
|
||
7 ZXTOB 0 Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase B.
|
||
8 ZXTOC 0 Indicates that an interrupt was caused by a missing zero crossing on the line voltage of the Phase C.
|
||
9 ZXA 0 Indicates a detection of a rising edge zero crossing in the voltage channel of Phase A.
|
||
10 ZXB 0 Indicates a detection of a rising edge zero crossing in the voltage channel of Phase B.
|
||
11 ZXC 0 Indicates a detection of a rising edge zero crossing in the voltage channel of Phase C.
|
||
12 LENERGY 0 In line energy accumulation, indicates the end of an integration over an integer number of
|
||
half- line cycles (LINECYC). See the Calibration section.
|
||
13 RESET 1 Indicates that the 5 V power supply is below 4 V. Enables a software reset of the ADE7758
|
||
and sets the registers back to their default values. This bit in the STATUS or RSTATUS register
|
||
is logic high for only one clock cycle after a reset event.
|
||
14 PKV 0 Indicates that an interrupt was caused when the selected voltage input is above the value in the
|
||
VPINTLVL register.
|
||
15 PKI 0 Indicates that an interrupt was caused when the selected current input is above the value
|
||
in the IPINTLVL register.
|
||
16 WFSM 0 Indicates that new data is present in the waveform register.
|
||
17 REVPAP 0 Indicates that an interrupt was caused by a sign change in the watt calculation among any
|
||
one of the phases specified by the TERMSEL bits in the COMPMODE register.
|
||
18 REVPRP 0 Indicates that an interrupt was caused by a sign change in the VAR calculation among any
|
||
one of the phases specified by the TERMSEL bits in the COMPMODE register.
|
||
19 SEQERR 0 Indicates that an interrupt was caused by a zero crossing from Phase A
|
||
followed not by the zero crossing of Phase C but by that of Phase B.
|
||
*/
|
||
|
||
uint32_t getStatus(void)
|
||
{
|
||
return read24(STATUS);
|
||
}
|
||
|
||
uint32_t resetStatus(void)
|
||
{
|
||
return read24(RSTATUS);
|
||
}
|
||
|
||
/** === getAIRMS ===
|
||
* Phase A Current RMS Value
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with the data (24 bits unsigned).
|
||
*/
|
||
int32_t getAIRMS(void)
|
||
{
|
||
long lastupdate = 0;
|
||
resetStatus(); // Clear all interrupts
|
||
while (!(getStatus() & ZXA)) // wait Zero-Crossing
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // breack;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
return read24(AIRMS);
|
||
}
|
||
|
||
/** === getBIRMS ===
|
||
* Phase B Current RMS Value
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with the data (24 bits unsigned).
|
||
*/
|
||
|
||
int32_t getBIRMS(void)
|
||
{
|
||
long lastupdate = 0;
|
||
resetStatus(); // Clear all interrupts
|
||
while (!(getStatus() & ZXB)) // wait Zero-Crossing
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // breack;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
return read24(BIRMS);
|
||
}
|
||
/** === getCIRMS ===
|
||
* Phase C Current RMS Value
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with the data (24 bits unsigned).
|
||
*/
|
||
int32_t getCIRMS(void)
|
||
{
|
||
long lastupdate = 0;
|
||
resetStatus(); // Clear all interrupts
|
||
while (!(getStatus() & ZXC)) // wait Zero-Crossing
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // breack;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
return read24(CIRMS);
|
||
}
|
||
|
||
/** === getAVRMS ===
|
||
* Phase A RMS Value (Voltage Channel).
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with the data (24 bits unsigned).
|
||
*/
|
||
|
||
int32_t getAVRMS(void)
|
||
{
|
||
long lastupdate = 0;
|
||
resetStatus(); // Clear all interrupts
|
||
while (!(getStatus() & ZXA)) // wait Zero-Crossing
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // breack;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
return read24(AVRMS);
|
||
}
|
||
|
||
/** === getBVRMS ===
|
||
* Phase B RMS Value (Voltage Channel).
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with the data (24 bits unsigned).
|
||
*/
|
||
|
||
int32_t getBVRMS(void)
|
||
{
|
||
long lastupdate = 0;
|
||
resetStatus(); // Clear all interrupts
|
||
while (!(getStatus() & ZXB)) // wait Zero-Crossing
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // breack;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
return read24(BVRMS);
|
||
}
|
||
|
||
/** === getCVRMS ===
|
||
* Phase C RMS Value (Voltage Channel).
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with the data (24 bits unsigned).
|
||
*/
|
||
|
||
int32_t getCVRMS(void)
|
||
{
|
||
long lastupdate = 0;
|
||
resetStatus(); // Clear all interrupts
|
||
while (!(getStatus() & ZXC)) // wait Zero-Crossing
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // break;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
return read24(CVRMS);
|
||
}
|
||
|
||
/** === vrms ===
|
||
* Returns the mean of last 20 readings of RMS voltage. Also supress first reading to avoid
|
||
* corrupted data.
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with RMS voltage value
|
||
*/
|
||
|
||
uint32_t avrms(void)
|
||
{
|
||
uint8_t i = 0;
|
||
uint32_t v = 0;
|
||
if (getAVRMS())
|
||
{ // Ignore first reading to avoid garbage
|
||
for (i = 0; i < 10; ++i)
|
||
{
|
||
v += getAVRMS();
|
||
}
|
||
return v / 10;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
uint32_t bvrms()
|
||
{
|
||
uint8_t i = 0;
|
||
uint32_t v = 0;
|
||
if (getBVRMS())
|
||
{ // Ignore first reading to avoid garbage
|
||
for (i = 0; i < 10; ++i)
|
||
{
|
||
v += getBVRMS();
|
||
}
|
||
return v / 10;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
uint32_t cvrms()
|
||
{
|
||
uint8_t i = 0;
|
||
uint32_t v = 0;
|
||
if (getCVRMS())
|
||
{ // Ignore first reading to avoid garbage
|
||
for (i = 0; i < 10; ++i)
|
||
{
|
||
v += getCVRMS();
|
||
}
|
||
return v / 10;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/** === irms ===
|
||
* Returns the mean of last 20 readings of RMS current. Also supress first reading to avoid
|
||
* corrupted data.
|
||
* To minimize noise, synchronize the reading of the rms register with the zero crossing
|
||
* of the voltage input and take the average of a number of readings.
|
||
* @param none
|
||
* @return long with RMS current value in hundreds of [mA], ie. 6709=67[mA]
|
||
*/
|
||
|
||
uint32_t airms()
|
||
{
|
||
char n = 0;
|
||
long i = 0;
|
||
if (getAIRMS())
|
||
{ // Ignore first reading to avoid garbage
|
||
for (n = 0; n < 10; ++n)
|
||
{
|
||
i += getAIRMS();
|
||
}
|
||
return i / 10;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
uint32_t birms()
|
||
{
|
||
char n = 0;
|
||
long i = 0;
|
||
if (getBIRMS())
|
||
{ // Ignore first reading to avoid garbage
|
||
for (n = 0; n < 10; ++n)
|
||
{
|
||
i += getBIRMS();
|
||
}
|
||
return i / 10;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
int32_t cirms()
|
||
{
|
||
char n = 0;
|
||
int32_t i = 0;
|
||
if (getCIRMS())
|
||
{ // Ignore first reading to avoid garbage
|
||
for (n = 0; n < 10; ++n)
|
||
{
|
||
i += getCIRMS();
|
||
}
|
||
return i / 10;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/** === getFreq ===
|
||
* Period of the Phase selected in MMode.
|
||
* @param none
|
||
* @return int with the data (12 bits unsigned).
|
||
*/
|
||
|
||
int32_t getFreq(void)
|
||
{
|
||
return read16(FREQ);
|
||
}
|
||
|
||
/** setLineCyc: sets the number of cycles required for the accumulations.
|
||
**/
|
||
|
||
void setLineCyc(uint32_t d)
|
||
{
|
||
write16(LINECYC, d);
|
||
}
|
||
|
||
/** === setCurrentOffset / getCurrentOffset ===
|
||
* @param none
|
||
* @return int with the data (12 bits 2-complement signed).
|
||
*/
|
||
|
||
int32_t getACurrentOffset()
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(AIRMSOS) << 20) >> 20);
|
||
return data;
|
||
}
|
||
int32_t getBCurrentOffset()
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(BIRMSOS) << 20) >> 20);
|
||
return data;
|
||
}
|
||
int32_t getCCurrentOffset()
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(CIRMSOS) << 20) >> 20);
|
||
return data;
|
||
}
|
||
void setACurrentOffset(int32_t o)
|
||
{
|
||
write16(AIRMSOS, o);
|
||
}
|
||
void setBCurrentOffset(int32_t o)
|
||
{
|
||
write16(BIRMSOS, o);
|
||
}
|
||
void setCCurrentOffset(int32_t o)
|
||
{
|
||
write16(CIRMSOS, o);
|
||
}
|
||
|
||
void setAWattOffset(int32_t o)
|
||
{
|
||
write16(AWATTOS, o);
|
||
}
|
||
void setBWattOffset(int32_t o)
|
||
{
|
||
write16(BWATTOS, o);
|
||
}
|
||
void setCWattOffset(int32_t o)
|
||
{
|
||
write16(CWATTOS, o);
|
||
}
|
||
|
||
void setAVAROffset(int32_t o)
|
||
{
|
||
write16(AVAROS, o);
|
||
}
|
||
void setBVAROffset(int32_t o)
|
||
{
|
||
write16(BVAROS, o);
|
||
}
|
||
void setCVAROffset(int32_t o)
|
||
{
|
||
write16(CVAROS, o);
|
||
}
|
||
/** === setVoltageOffset / getVoltageOffset ===
|
||
* @param none
|
||
* @return int with the data (12 bits 2-complement signed).
|
||
*/
|
||
|
||
int32_t getAVoltageOffset()
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(AVRMSOS) << 20) >> 20);
|
||
return data;
|
||
}
|
||
int32_t getBVoltageOffset()
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(BVRMSOS) << 20) >> 20);
|
||
return data;
|
||
}
|
||
int32_t getCVoltageOffset()
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(CVRMSOS) << 20) >> 20);
|
||
return data;
|
||
}
|
||
void setAVoltageOffset(int32_t o)
|
||
{
|
||
write16(AVRMSOS, o);
|
||
}
|
||
void setBVoltageOffset(int32_t o)
|
||
{
|
||
write16(BVRMSOS, o);
|
||
}
|
||
void setCVoltageOffset(int32_t o)
|
||
{
|
||
write16(CVRMSOS, o);
|
||
}
|
||
|
||
/** === setZeroCrossingTimeout / getZeroCrossingTimeout ===
|
||
* Zero-Crossing Timeout. If no zero crossings are detected
|
||
* on Channel 2 within a time period specified by this 12-bit register,
|
||
* the interrupt request line (IRQ) is activated
|
||
* @param none
|
||
* @return int with the data (12 bits unsigned).
|
||
*/
|
||
|
||
void setZeroCrossingTimeout(int32_t d)
|
||
{
|
||
write16(ZXTOUT, d);
|
||
}
|
||
int32_t getZeroCrossingTimeout()
|
||
{
|
||
return read16(ZXTOUT);
|
||
}
|
||
|
||
/** === setPotLine(Phase) ===
|
||
Set the conditions for Line accumulation in the selected phase.
|
||
Then wait for the interruption and return the phase number when it occurs.
|
||
If it does not happen for more than 1.5 seconds, it returns a 0.
|
||
**/
|
||
|
||
uint8_t setPotLine(uint8_t Phase, uint32_t Cycles)
|
||
{
|
||
long lastupdate = 0;
|
||
char m = 0;
|
||
switch (Phase)
|
||
{
|
||
case PHASE_A:
|
||
m = (LWATT | LVAR | LVA | ZXSEL_A);
|
||
break;
|
||
case PHASE_B:
|
||
m = (LWATT | LVAR | LVA | ZXSEL_B);
|
||
break;
|
||
case PHASE_C:
|
||
m = (LWATT | LVAR | LVA | ZXSEL_C);
|
||
break;
|
||
}
|
||
setLcycMode(0);
|
||
setLcycMode(m);
|
||
resetStatus();
|
||
setLineCyc(Cycles);
|
||
lastupdate = 0;
|
||
while (!(getStatus() & LENERGY)) // wait to terminar de acumular
|
||
{ // wait for the selected interrupt to occur
|
||
lastupdate++;
|
||
if (lastupdate > 20)
|
||
{
|
||
return 0; // breack;
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(20));
|
||
}
|
||
|
||
return Phase;
|
||
}
|
||
|
||
/** === getWatt(phase) / getVar(phase) / getVa(phase) ===
|
||
Devuelve los valores de la potencia requerida de la fase seleccionada.
|
||
Utilizar antes setPotLine(phase) para generar los valores.
|
||
**/
|
||
|
||
int32_t getWatt(uint8_t Phase)
|
||
{
|
||
int32_t temp = 0;
|
||
switch (Phase)
|
||
{
|
||
case PHASE_A:
|
||
temp = read16(AWATTHR);
|
||
break;
|
||
case PHASE_B:
|
||
temp = read16(BWATTHR);
|
||
break;
|
||
case PHASE_C:
|
||
temp = read16(CWATTHR);
|
||
break;
|
||
}
|
||
return temp;
|
||
}
|
||
int32_t getVar(uint8_t Phase)
|
||
{
|
||
int32_t temp = 0;
|
||
switch (Phase)
|
||
{
|
||
case PHASE_A:
|
||
temp = read16(AVARHR);
|
||
break;
|
||
case PHASE_B:
|
||
temp = read16(BVARHR);
|
||
break;
|
||
case PHASE_C:
|
||
temp = read16(CVARHR);
|
||
break;
|
||
}
|
||
return temp;
|
||
}
|
||
int32_t getVa(uint8_t Phase)
|
||
{
|
||
int32_t temp = 0;
|
||
switch (Phase)
|
||
{
|
||
case PHASE_A:
|
||
temp = read16(AVAHR);
|
||
break;
|
||
case PHASE_B:
|
||
temp = read16(BVAHR);
|
||
break;
|
||
case PHASE_C:
|
||
temp = read16(CVAHR);
|
||
break;
|
||
}
|
||
return temp;
|
||
}
|
||
void setAPCFDEN(int32_t d)
|
||
{
|
||
write16(APCFDEN, d);
|
||
}
|
||
int32_t getAPCFDEN(void)
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(APCFDEN) << 20) >> 20);
|
||
return data;
|
||
}
|
||
void setAPCFNUM(int32_t d)
|
||
{
|
||
write16(APCFNUM, d);
|
||
}
|
||
int32_t getAPCFNUM(void)
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(APCFNUM) << 20) >> 20);
|
||
return data;
|
||
}
|
||
void setVARCFNUM(int32_t d)
|
||
{
|
||
write16(VARCFNUM, d);
|
||
}
|
||
int32_t getVARCFNUM(void)
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(VARCFNUM) << 20) >> 20);
|
||
return data;
|
||
}
|
||
void setVARCFDEN(int32_t d)
|
||
{
|
||
write16(VARCFDEN, d);
|
||
}
|
||
int32_t getVARCFDEN(void)
|
||
{
|
||
int32_t data;
|
||
data = ((int32_t)(read16(VARCFDEN) << 20) >> 20);
|
||
return data;
|
||
}
|
||
void setAWG(int32_t d)
|
||
{
|
||
write16(AWG, d);
|
||
}
|
||
int32_t getAWG()
|
||
{
|
||
return ((read16(AWG)) << 4) >> 4;
|
||
}
|
||
void setBWG(int32_t d)
|
||
{
|
||
write16(BWG, d);
|
||
}
|
||
void setCWG(int32_t d)
|
||
{
|
||
write16(CWG, d);
|
||
}
|
||
void setAVARG(int32_t d)
|
||
{
|
||
write16(AVARG, d);
|
||
}
|
||
int32_t getAVARG()
|
||
{
|
||
return ((read16(AVARG)) << 4) >> 4;
|
||
}
|
||
void setBVARG(int32_t d)
|
||
{
|
||
write16(BVARG, d);
|
||
}
|
||
int32_t getBVARG()
|
||
{
|
||
return ((read16(BVARG)) << 4) >> 4;
|
||
}
|
||
void setCVARG(int32_t d)
|
||
{
|
||
write16(CVARG, d);
|
||
}
|
||
int32_t getCVARG()
|
||
{
|
||
return ((read16(CVARG)) << 4) >> 4;
|
||
}
|
||
void setAVAG(int32_t d)
|
||
{
|
||
write16(AVAG, d);
|
||
}
|
||
void setBVAG(int32_t d)
|
||
{
|
||
write16(BVAG, d);
|
||
}
|
||
void setCVAG(int32_t d)
|
||
{
|
||
write16(CVAG, d);
|
||
} |