Library files for AD1234.

ADE120x.cpp

Committer:
mlambe
Date:
2019-10-22
Revision:
3:6c708642886d
Parent:
2:f9a986799375

File content as of revision 3:6c708642886d:

/**  
 @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;
}