Library files for AD1234.

ADE120x.cpp

Committer:
mlambe
Date:
2019-10-15
Revision:
2:f9a986799375
Parent:
1:2eb9d6296ec3
Child:
3:6c708642886d

File content as of revision 2:f9a986799375:

/**  
 * @file       ADE120x.cpp
 * @brief      ADE120x library. This file contains all ADE120x library functions. 
 * @version    V0.0.1
 * @author     ADI
 * @date       October 2019
 * @par Revision History:
 * 
 * Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
 * 
 * This software is proprietary to Analog Devices, Inc. and its licensors.
 * By using this software you agree to the terms of the associated
 * Analog Devices Software License Agreement.
**/

#include "ADE120x.h"
 
 /* Constructor for ADE120x; intializes the SPI interface only */
ADE120x::ADE120x(   PinName mosi,PinName miso,PinName sclk,PinName cs) : spi_(mosi, miso, sclk), nCS_(cs) {
                    //5MHz, allowed up to 10MHz
                    nCS_ = 1;
                    spi_.frequency(5000000);
                    spi_.format(16, 3);             
                }

/**
    @brief Write to ADE120x register through SPI. 
    @param addr: The address of the ADE120x device.
    @param reg_addr: register address 
    @param data: register data
    @return received data.
**/
void ADE120x::WriteReg(uint8_t addr, uint32_t reg_addr, uint32_t data)
{
    int cmd;
    nCS_ = 0;
    wait_us(1);
    cmd = reg_addr * 0x0010 + addr;    //R/nW bit set to 0
    spi_.write(cmd);
    spi_.write(data);
    wait_us(1);
    nCS_ = 1;
}
/**
    @brief Read ADE120x register through SPI. 
    @param addr: The address of the ADE120x device.
    @param reg_addr: register address 
    @return received data.
**/
uint32_t ADE120x::ReadReg(uint8_t addr, uint32_t reg_addr)
{
    int cmd;
    int resp;    
    nCS_ = 0;
    wait_us(1);
    //cmd = REG*0x0020 + 0x18 + addr;    //R/nW bit set to 0
    cmd = reg_addr*0x0010 + 0x8 + addr;      
    spi_.write(cmd);
    resp = spi_.write(0xFFFF);
    wait_us(1);
    nCS_ = 1;
    return resp;
}

/**
  @brief Reset ADE120x. 
  @param addr: The address of the ADE120x device.
  @return return none.
**/
uint8_t ADE120x::Reset(uint8_t addr)
{
    UnLock(addr);
    WriteReg(addr, REG_CTRL, 0x0010);
    //wait until RSTDONE bit is set
    while ((ReadReg(addr, REG_INT_STATUS) & INTSRC_RSTDONE) == 0)
    {  }
    return 0;
}

/**
  @brief Read back device ID. 
  @param addr: The address of the ADE120x device.
  @return device ID.
**/
uint16_t ADE120x::GetDevID(uint8_t addr)
{
    uint16_t response;
    response = ReadReg(addr, REG_CTRL);
    return response;
}

/**
  @brief Lock ADE120x. When device is locked all register writes are ignored
  @param addr: The address of the ADE120x device.
  @return none.
**/
void ADE120x::Lock(uint8_t addr)
{
    WriteReg(addr, REG_LOCK, DEV_LOCK);
}

/**
  @brief Unlock ADE120x. Unlock device before writing to registers
  @param addr: The address of the ADE120x device.
  @return none.
**/
void ADE120x::UnLock(uint8_t addr)
{
    WriteReg(addr, REG_LOCK, DEV_UNLOCK);
    wait_us(100);
}

/**
    @brief Configure interrupt. 
    @param addr: the address of the ADE120x device.
    @param IntSrcSel: Interrupt source to enable.
    @return Status.
**/
void ADE120x::SetInt(uint8_t addr, uint16_t IntSrcSel)
{
    WriteReg(addr, REG_MASK, IntSrcSel);
}

/**
    @brief Clear interrupt status. 
    @param addr: the address of the ADE120x device.
    @param IntSrcSel: Interrupt source to clear.
    @return Status.
**/
void ADE120x::ClearIntStatus(uint8_t addr, uint16_t IntSrcSel)
{
    WriteReg(addr, REG_INT_STATUS, IntSrcSel);
}

/**
  @brief Get Interrupt Status. 
  @param addr: the address of the ADE120x device.
  @return Status.
**/
uint16_t ADE120x::GetIntStatus(uint8_t addr)
{
    uint16_t status;
    status = ReadReg(addr, REG_INT_STATUS);
    return status;
}

/**
    @brief Configure ADC PGA gain. 
    @param addr: the address of the ADE120x device.
    @param Gain: Select from the following
                            ADCPGA_1, ADCPGA_2, ADCPGA_5, ADCPGA_10.
    @return Status.
**/
void ADE120x::SetPgaGain(uint8_t addr, uint16_t gain)
{
    UnLock(addr);
    WriteReg(addr, REG_PGA_GAIN, gain);
    Lock(addr);
}

/**
    @brief Read ADC data. 
    @param addr: the address of the ADE120x device.
    @param src: ADC source, ADC_DECIMATOR to select decimator output. ADC_RAW for raw output.
    @return Status.
**/
uint8_t ADE120x::ReadADC(uint8_t addr, int8_t src)
{
    uint8_t code;
    if(src == ADC_DECIMATOR)
        code = ReadReg(addr, REG_ADCDEC);
    else
        code = ReadReg(addr, REG_ADC);
    return code;
}

/**
  @brief Set binary Threshold. 
  @param addr: the address of the ADE120x device.
  @param thresh: Threshold value.
  @return none.
**/
void ADE120x::SetBinaryThresh(uint8_t addr, uint16_t thresh)
{
    WriteReg(addr, REG_BIN_THR, thresh);
}

/**
  @brief Calculate threshold register code. 
  @param V_Thresh: Threshold value in volts.
  @param ADCPga: PGA gain value
  @param V_Gain: Gain of external voltage divider circuit
  @return 0.
**/
uint8_t ADE120x::CalculateThreshCode(float V_Thresh, uint8_t ADCPga, float V_Gain)
{
    uint8_t code;
    float tmp;
    tmp = (V_Thresh * V_Gain * ADCPga * 255)/1.25 + 0.5;
    code = (uint8_t)tmp;
    return code;
}

/**
  @brief Configure threshold voltage for BIN, WARNA, WARNB and WARNC. 
  @param addr: the address of the ADE120x device.
  @param pCfg: Pointer to structure
  @return 0.
**/
uint8_t ADE120x::ThresholdCfg(uint8_t addr, THRESHCfg_Type *pCfg)
{
    uint8_t Thresh_H, Thresh_L;
    uint16_t bin_ctrl, tmp;
    UnLock(addr);
    Thresh_H = CalculateThreshCode(pCfg->BIN_HighThresh, pCfg->ADCPga, pCfg->VGain);
    Thresh_L = CalculateThreshCode(pCfg->BIN_LowThresh, pCfg->ADCPga, pCfg->VGain);
    WriteReg(addr, REG_BIN_THR, (Thresh_L<<8)|Thresh_H);
    
    Thresh_H = CalculateThreshCode(pCfg->WARNA_HighThresh, pCfg->ADCPga, pCfg->VGain);
    Thresh_L = CalculateThreshCode(pCfg->WARNA_LowThresh, pCfg->ADCPga, pCfg->VGain);
    WriteReg(addr, REG_WARNA_THR , (Thresh_L<<8)|Thresh_H);
    
    Thresh_H = CalculateThreshCode(pCfg->WARNB_HighThresh, pCfg->ADCPga, pCfg->VGain);
    Thresh_L = CalculateThreshCode(pCfg->WARNB_LowThresh, pCfg->ADCPga, pCfg->VGain);
    WriteReg(addr, REG_WARNB_THR, (Thresh_L<<8)|Thresh_H);
    
    Thresh_H = CalculateThreshCode(pCfg->WARNC_HighThresh, pCfg->ADCPga, pCfg->VGain);
    Thresh_L = CalculateThreshCode(pCfg->WARNC_LowThresh, pCfg->ADCPga, pCfg->VGain);
    WriteReg(addr, REG_WARNC_THR, (Thresh_L<<8)|Thresh_H);
    
    bin_ctrl = (pCfg->BIN_Mode<<6)|(pCfg->WARNA_Mode<<8)|(pCfg->WARNB_Mode<<10)|(pCfg->WARNC_Mode<<12);
    tmp = ReadReg(addr, REG_BIN_CTRL);
    tmp &= 0xFFFF&~(0xFF<<6);
    WriteReg(addr, REG_BIN_CTRL, tmp|bin_ctrl);
    tmp = ReadReg(addr, REG_BIN_CTRL);
    return 0;
}

/**
  @brief Configure programmable load. 
  @param addr: the address of the ADE120x device.
  @param pCfg: Pointer to structure
  @return 0.
**/
uint8_t ADE120x::ProgrammableLoadCfg(uint8_t addr, PLOADCfg_Type *pCfg)
{
    float tmp;
    WriteReg(addr, REG_PL_CTRL, pCfg->mode);
    if(pCfg->mode == LOW_IDLE)
        WriteReg(addr, REG_PL_RISE_THR, 
                    CalculateThreshCode(pCfg->VoltThresh, pCfg->ADCPga, pCfg->VGain));
    
    tmp = (pCfg->HighCurrent/0.2) + 0.5f; /* add 0.5 to round up */
   WriteReg(addr, REG_PL_HIGH_CODE, (uint16_t)tmp);
    
    tmp = (pCfg->HighTime/10) + 0.5f;
    WriteReg(addr, REG_PL_HIGH_TIME, (uint16_t)tmp);
    
    tmp = (pCfg->LowCurrent/0.1) + 0.5f;
    WriteReg(addr, REG_PL_LOW_CODE, (uint16_t)tmp);
    
    if(pCfg->enable == CH1_Enable)
        WriteReg(addr, REG_PL_EN, PL_CH1_ENABLE);
    if(pCfg->enable == CH2_Enable)
        WriteReg(addr, REG_PL_EN, PL_CH2_ENABLE);
    if(pCfg->enable == CH1_CH2_Enable)
        WriteReg(addr, REG_PL_EN, PL_CH2_ENABLE|PL_CH1_ENABLE);
    if(pCfg->enable == CH1_Disable)
       WriteReg(addr, REG_PL_EN, 0);
    
    return 0;
}

/**
  @brief Configure Energy Meter. 
  @param addr: the address of the ADE120x device.
  @param pCfg: Pointer to structure
  @return 0.
**/
uint8_t ADE120x::EnergyMtrCfg(uint8_t addr, EnergyMtrCfg_Type *pCfg)
{
    float pulse_enrgy, AvgADCCode, tmp;
    uint16_t reg_val, reg_mtr_ctrl;
    AvgADCCode = (255*pCfg->WorkingVoltage*pCfg->VGain*pCfg->ADCPga)/1.25;
    /* Step 1: Calculate pulse energy in Jules: (Pulse time * Working Current * Voltage) / 1000 */
    pulse_enrgy = (pCfg->PulseMagnitude * pCfg->FET_Energy * pCfg->PulseTime)/1000;
    
    /* Step 2: Calculate ENERGY_MTR register value:  */
    tmp = (AvgADCCode * (pCfg->PulseTime/1000))/(128 * pCfg->SampleRate)+0.5;
    reg_val = (uint16_t)tmp;
    WriteReg(addr, REG_EGY_MTR_THR, reg_val);


    reg_mtr_ctrl = (pCfg->Cooldown_Decr<<8)|pCfg->Cooldown_Sec|(pCfg->Cooldown_TimeStep<<4)|(pCfg->Ov_Scale<<6);
    WriteReg(addr, REG_EGY_MTR_CTRL, reg_mtr_ctrl);
    
    return 1;
}

/**
  @brief Read all ADE120xregisters. 
  @param addr: the address of the ADE120x device.
  @return 0.
**/
void ADE120x::GetRegisterData(uint8_t addr, RegisterData_Type *pBuff)
{
    uint16_t reg_addr[] = {
        REG_CTRL, 
        REG_BIN_CTRL,       
        REG_BIN_THR,        
        REG_WARNA_THR,          
        REG_WARNB_THR,     
        REG_WARNC_THR,      
        REG_BIN_FILTER,     
        REG_WARNA_FILTER,   
        REG_WARNB_FILTER,   
        REG_WARNC_FILTER,   
        REG_MASK,          
        REG_PL_CTRL,        
        REG_PL_RISE_THR,   
        REG_PL_LOW_CODE,    
        REG_PL_HIGH_CODE,   
        REG_PL_HIGH_TIME,   
        REG_EGY_MTR_CTRL,   
        REG_EGY_MTR_THR,    
        REG_PL_EN, 
        REG_PGA_GAIN};
    
    uint8_t reg_addr_size = sizeof(reg_addr)/sizeof(*reg_addr);
    uint8_t i = 0;
    while(i<reg_addr_size)
    {
        pBuff[i].reg_addr = reg_addr[i]; 
        pBuff[i].reg_data = ReadReg(addr, reg_addr[i]);
        i++;
        wait_us(1000);     
    }
}

/**
  @brief Convert ADC Code to voltage. 
  @param ADCCode: ADC code.
  @param ADCPga: the actual 1.82V reference voltage.
  @param VOLTAGE_Gain: THe gain factor set by the external resistor divider network 
  @return Voltage in volt.
**/
float ADE120x::ADCCode2Volt(uint32_t ADCCode, uint8_t ADCPga, float VOLTAGE_Gain)
{
    float tmp = 0.0;
    float fVolt = 0.0;
    tmp = (ADCCode&0xFF);
    tmp = 1.25 * (tmp/255) / VOLTAGE_Gain;
    switch(ADCPga)
    {
        case ADCPGA_1:
        fVolt = tmp;
        break;
        case ADCPGA_2:
        fVolt = tmp/2;
        break;
        case ADCPGA_5:
        fVolt = tmp/5; 
        break;
        case ADCPGA_10:
        fVolt = tmp/10; 
        break;
        default:break;
        }
        return fVolt;
}