ADE120x Library Files
Diff: ADE120x.cpp
- Revision:
- 1:2eb9d6296ec3
- Parent:
- 0:952a6272c495
- Child:
- 2:f9a986799375
--- a/ADE120x.cpp Mon Jul 29 16:38:44 2019 +0000 +++ b/ADE120x.cpp Thu Oct 03 15:05:59 2019 +0000 @@ -0,0 +1,426 @@ +/** + * @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" + +/*! \mainpage ADE120x Library Introduction + * + * # Introduction + * + * The documentation is for ADE120x library and examples. + * TBD + */ + + + /* 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 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; +} + +/** + @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 fvoltage 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 Configure Device with default settings. + @param addr: the address of the ADE120x device. + @return 0. +**/ +uint8_t ADE120x::DefaultConfig(uint8_t addr) +{ + /** Array defined for configuration ***/ + uint16_t config[] = { + //REG_CTRL, 0x04, + // REG_BIN_CTRL, 0x0000, + REG_BIN_THR, 0x757d, // fail + REG_WARNA_THR, 0xcccc, + REG_WARNB_THR, 0x5a88, + REG_WARNC_THR, 0x2d2d, + REG_BIN_FILTER, BIN_FILTER_VAL, //fail using this register to validate against unintended resets in the DOUT validate + REG_WARNA_FILTER, 0x80fa, + REG_WARNB_FILTER, 0x80fa, + REG_WARNC_FILTER, 0x80fa, + REG_MASK, 0x4000, + REG_PL_CTRL, 0x0000, + REG_PL_RISE_THR, 0x007d, // fail + REG_PL_LOW_CODE, 0x001e, + REG_PL_HIGH_CODE, 0x000f, // fail + REG_PL_HIGH_TIME, 0x0001, // fail + REG_EGY_MTR_CTRL, 0x0505, + REG_EGY_MTR_THR, 0x9ba3, + REG_PL_EN, 0xC000, //fail + REG_PGA_GAIN, ADCPGA_10 }; //fail + + uint8_t config_size = sizeof(config)/sizeof(*config); + uint8_t i = 0; + int resp; + wait_us(10000); + while(i<config_size-1) + { + WriteReg(addr, config[i], config[i+1]); + resp = ReadReg(addr, config[i]); + if (resp != config[i+1]) + { + printf("Register 0x%x write failed: Expected: 0x%x , Actual: 0x%x \r\n", config[i], config[i+1], resp); + return 255; + } + // printf("Register 0x%x write passed: Expected: 0x%x , Actual: 0x%x \r\n", config[i], config[i+1], resp); + i+=2; + wait_us(1000); + } + return 0; +}