2025-01-15 05:27 AM - last edited on 2025-01-15 07:38 AM by Peter BENSCH
I am using this code to read the RMS Voltage and Current. I am also able to get output which I have attached as a .txt file. The expected voltage from the hardware which I am using STPM34 is up to range of 20 V. I am unable to understand where I am going wrong.
#include <HardwareSerial.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <Arduino.h>
#include "soc/uart_reg.h"
const int STPM34_ENABLE_PIN = 4; //Enable pin for STPM3x
//UART2 Pins of ESP32 connected to STPM32
const int PIN_16 = 16; //UART Rx pin of STPM3x
const int PIN_17 = 17; //UART Tx pin of STPM3x
HardwareSerial stpm3xSerial(2);
hw_timer_t *timer;
const int baud_rate = 9600;
uint8_t CRC_u8Checksum = 0;
#define BUFFER_SIZE 5
uint16_t STPM3x_RCV[BUFFER_SIZE];
volatile bool timer_call = false;
volatile uint8_t u2_chk=0;
uint16_t RawRms_volt;
uint16_t RawRms_curr;
float CalcRMS_volt;
float RMS_Volt;
float RMS_Curr;
float CalcRMS_curr;
float active_pwr;
float Active_Pwr;
float active_nrj;
float Active_Nrj;
float total_nrj;
float Total_Nrj;
int32_t energy;
int32_t energy_extension;
const int TIME_OUT =1000;// 1s timeout
int32_t BRR_REG1;
int32_t raw_apparent_pwr=0;
int64_t calc_apparent_pwr=0;
int32_t raw_act_nrj=0;
int32_t raw_tot_nrj=0;
uint32_t DSP_CR2_LSB;
uint32_t DSP_CR2_MSB;
uint32_t DSP_CR3_LSB;
uint32_t DSP_CR5_LSB;
uint32_t DSP_CR5_MSB;
uint8_t readAddress;
uint8_t writeAddress;
uint8_t lsbData;
uint8_t msbData;
uint8_t endian_data1;
uint8_t endian_data2;
uint16_t recvd_data;
uint32_t stpmData;
volatile bool udr = false;
volatile int rcvInd = 0;
#define RCV_DATA_SIZE 5
uint8_t recvData[RCV_DATA_SIZE];
uint8_t reverse_data1;
uint8_t reverse_data2;
uint8_t reverse_data3;
uint8_t reverse_data4;
uint8_t reverse_data5;
uint8_t CalcCRC8(uint8_t *pBuf);
void Crc8Calc(uint8_t in_Data);
uint8_t u8ByteReverse(uint8_t in_byte);
bool UartWriteCheck(const uint8_t reg_addr);
void snd_cmmnd_stpm3x(uint8_t READ_ADDRESS,uint8_t WRITE_ADDRESS,uint16_t DATA);
void rcvData(uint8_t read_addr);
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Starting ESP32.....");
stpm3xSerial.begin(baud_rate,SERIAL_8N1,PIN_16,PIN_17);
pinMode(STPM34_ENABLE_PIN,OUTPUT);
digitalWrite(STPM34_ENABLE_PIN,HIGH);
delay(100);
digitalWrite(STPM34_ENABLE_PIN,LOW);
Serial.println("STPM3x Enabled");
STPM_UART_init();//Establish STPM3x UART communication
stpm3x_init();
stpm3xSerial.setTimeout(1000);
}
void loop() {
// put your main code here, to run repeatedly:")
RMS_Volt = readRMSvoltage();
Serial.print("RMS Voltage =");
Serial.print(RMS_Volt);
Serial.print("V");
Serial.println();
delay(100);
RMS_Curr=readRMScurrent();
Serial.print("RMS Current =");
Serial.print(RMS_Curr);
Serial.print("A");
Serial.println();
delay(100);
}
void STPM_UART_init()
{
snd_cmmnd_stpm3x(0xFF,0x24,0x4007);//US_REG1 LSB configuration
snd_cmmnd_stpm3x(0xFF,0x25,0x000);// US_REG1 MSB configuration Timeout = 1 ms
snd_cmmnd_stpm3x(0xFF,0x26,0x0683);// US_REG2 LSB config Buadrate = 9600 bps
snd_cmmnd_stpm3x(0xFF,0x27,0x0000);// US_REG2 MSB config Frame delay = 0
snd_cmmnd_stpm3x(0xFF,0x28,0x0066);// US_REG3
snd_cmmnd_stpm3x(0xFF,0x29,0x0000);// US_REG3
}
void stpm3x_init()
{
snd_cmmnd_stpm3x(0xFF,0x00,0x00A0);// DSP_CR1 LSB
snd_cmmnd_stpm3x(0xFF,0x01,0x0400);
snd_cmmnd_stpm3x(0xFF,0x02,0x00A0);
snd_cmmnd_stpm3x(0xFF,0x03,0x2400);
snd_cmmnd_stpm3x(0xFF,0x04,0x04E0);
snd_cmmnd_stpm3x(0xFF,0x05,0x0020);
snd_cmmnd_stpm3x(0xFF,0x06,0x0000);
snd_cmmnd_stpm3x(0xFF,0x07,0x0000);
snd_cmmnd_stpm3x(0xFF,0x08,0xF800);
snd_cmmnd_stpm3x(0xFF,0x09,0x003F);
snd_cmmnd_stpm3x(0xFF,0x0A,0xF800);
snd_cmmnd_stpm3x(0xFF,0x0B,0x003F);
snd_cmmnd_stpm3x(0xFF,0x0C,0xF800); //Calibration register of secondary voltage channel
snd_cmmnd_stpm3x(0xFF,0x0D,0x003F); //Swell threshold of secondary voltage channel
snd_cmmnd_stpm3x(0xFF,0x0E,0xF800); //Calibration register of secondary current channel
snd_cmmnd_stpm3x(0xFF,0x0F,0x003F); //Swell threshold of secondary current channel
snd_cmmnd_stpm3x(0xFF,0x10,0x0FFF); //Primary channel RMS upper threshold (for AH)
snd_cmmnd_stpm3x(0xFF,0x11,0x0000);
snd_cmmnd_stpm3x(0xFF,0x12,0x0FFF); //Primary channel RMS lower threshold (for AH)
snd_cmmnd_stpm3x(0xFF,0x13,0x0000);
snd_cmmnd_stpm3x(0xFF,0x14,0x0FFF); //Secondary channel RMS upper threshold (for AH
snd_cmmnd_stpm3x(0xFF,0x15,0x0000);
snd_cmmnd_stpm3x(0xFF,0x16,0x0FFF); //Secondary channel RMS lower threshold (for AH)
snd_cmmnd_stpm3x(0xFF,0x17,0x0000);
snd_cmmnd_stpm3x(0xFF,0x18,0x0327); //current 1 gain
snd_cmmnd_stpm3x(0xFF,0x19,0x0327);
snd_cmmnd_stpm3x(0xFF,0x1A,0x0327); //current 2 gain
snd_cmmnd_stpm3x(0xFF,0x1B,0x0327);
snd_cmmnd_stpm3x(0xFF,0x1C,0x0000);
snd_cmmnd_stpm3x(0xFF,0x1D,0x0000);
snd_cmmnd_stpm3x(0xFF,0x1E,0x0000);
snd_cmmnd_stpm3x(0xFF,0x1F,0x0000);
snd_cmmnd_stpm3x(0xFF,0x20,0x777F);
snd_cmmnd_stpm3x(0xFF,0x21,0x0204);
snd_cmmnd_stpm3x(0xFF,0x22,0x0000);
snd_cmmnd_stpm3x(0xFF,0x23,0x0200);
}
void snd_cmmnd_stpm3x(uint8_t READ_ADDRESS,uint8_t WRITE_ADDRESS,uint16_t DATA)
{
uint8_t LSB_DATA = 0;
uint8_t MSB_DATA = 0;
uint8_t CRC_DATA = 0;
uint8_t DATA_WITHOUT_CRC[4] = {0,0,0,0};
LSB_DATA = DATA & 0xFF;
MSB_DATA = (DATA>>8) & 0xFF;
DATA_WITHOUT_CRC[0]=u8ByteReverse(READ_ADDRESS);
DATA_WITHOUT_CRC[1]=u8ByteReverse(WRITE_ADDRESS);
DATA_WITHOUT_CRC[2]=u8ByteReverse(LSB_DATA);
DATA_WITHOUT_CRC[3]=u8ByteReverse(MSB_DATA);
// memset(STPM3x_RCV,0,sizeof(STPM3x_RCV));// Clear the uart buffer for stpm3x
CRC_DATA = CalcCRC8(DATA_WITHOUT_CRC);
CRC_DATA = u8ByteReverse(CRC_DATA);
if(UartWriteCheck(DATA_WITHOUT_CRC[0]));
delay(1);
if(stpm3xSerial.available())
{
reverse_data1 = stpm3xSerial.read();
lsbData = u8ByteReverse(reverse_data1);
Serial.print("LSB = 0x");
Serial.print(lsbData,HEX);Serial.println();
}
if(UartWriteCheck(DATA_WITHOUT_CRC[1]));
delay(1);
if(stpm3xSerial.available())
{
reverse_data2 = stpm3xSerial.read();
endian_data1 = u8ByteReverse(reverse_data2);
Serial.print("Byte2 = 0x");
Serial.print(endian_data1,HEX);Serial.println();
}
if(UartWriteCheck(DATA_WITHOUT_CRC[2]));
delay(1);
if(stpm3xSerial.available())
{
reverse_data3 = stpm3xSerial.read();
endian_data2 = u8ByteReverse(reverse_data3);
Serial.print("Byte3 = 0x");
Serial.print(endian_data2,HEX);Serial.println();
}
if(UartWriteCheck(DATA_WITHOUT_CRC[3]));
delay(1);
if(stpm3xSerial.available())
{
reverse_data4 = stpm3xSerial.read();
msbData = u8ByteReverse(reverse_data4);
Serial.print("MSB = 0x");
Serial.print(msbData,HEX);Serial.println();
}
stpm3xSerial.write(CRC_DATA);
}
bool UartWriteCheck(const uint8_t reg_addr)
{
stpm3xSerial.write(reg_addr);
uint32_t status_reg = READ_PERI_REG(UART_STATUS_REG(2));
if(status_reg)// & UART_TXFIFO_EMPTY_INT_ENA)
{
//Serial.println("The data is written STPM34");
return true;
}
else
{
Serial.println("The data is not written properly to registers of STPM34");
return false;
}
}
void rcvData(uint8_t read_addr)
{
//Send data to read from register
snd_cmmnd_stpm3x(read_addr,0xFF,0xFFFF);
snd_cmmnd_stpm3x(read_addr,0xFF,0xFFFF);
}
/*
uint8_t rcvData(uint8_t read_addr)
{
uint8_t bytesRead=0;
unsigned long start_time = millis();
while(bytesRead<BUFFER_SIZE)
{
if(stpm3xSerial.available()){
STPM3x_RCV[bytesRead++] = stpm3xSerial.read();
}
if(millis() - start_time>100)
{
Serial.print("Waiting for UART data");
break;
}
}
}
*/
int32_t nrj_calc(uint32_t raw_nrj)
{
int64_t calc_nrj = 0;
/* manage the 2 U32 to have enougth place to save energy cumulated */
/* Make sure between two reads inside hardware registers if we have to add carry inside ext U32 */
if (((uint32_t)energy>0xA0000000) && ((uint32_t)raw_nrj<0x60000000))
{
energy_extension++;
}
if (((uint32_t)energy<0x60000000) && ((uint32_t)raw_nrj>0xA0000000))
{
energy_extension--;
}
/* save the new result cumulated come from register inside internal structure */
energy = raw_nrj;
/* calculate the nrj value and add the 32 bits extension */
calc_nrj = (uint64_t)raw_nrj + ((int64_t)energy_extension<< 32);
calc_nrj *= (int64_t)35145;
/* multiply by 10 to have in milli- */
calc_nrj *= 10;
/* Put the result in 32 bits format */
calc_nrj >>= 32;
/* return the nrj value */
return((int32_t)calc_nrj);
}
/* CRC CALUCULATIOPN */
uint8_t CalcCRC8(uint8_t *pBuf)
{
void Crc8Calc(uint8_t in_Data);
uint8_t i;
uint8_t CRC_u8Checksum = 0x00;
for (i=0; i<4; i++)
{
Crc8Calc(pBuf[i]);
}
return CRC_u8Checksum;
}
void Crc8Calc(uint8_t in_Data)
{
uint8_t loc_u8Idx;
uint8_t loc_u8Temp=0;
for(loc_u8Idx=0;loc_u8Idx<8;loc_u8Idx++)
{
loc_u8Temp=in_Data^CRC_u8Checksum;
CRC_u8Checksum<<=1;
if(loc_u8Temp&0x80)
{
CRC_u8Checksum^=0x7;
}
in_Data<<=1;
}
}
/* BYTE REVERSE FUNCTION */
uint8_t u8ByteReverse(uint8_t in_byte)
{
in_byte = ((in_byte >> 1) & 0x55) | ((in_byte << 1) & 0xaa);
in_byte = ((in_byte >> 2) & 0x33) | ((in_byte << 2) & 0xcc);
in_byte = ((in_byte >> 4) & 0x0F) | ((in_byte << 4) & 0xF0);
return in_byte;
}
float readRMSvoltage()
{
uint32_t raw_RMS_Voltage = 0;
uint64_t calc_RMS_Voltage = 0;
uint16_t v1;
uint8_t received_data[5] = {0};//array to store received bytes
uint8_t revData[5] = {0};
/******** LATCHING ********/
snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
/******** Vrms and Irms ********/
rcvData(0x48);
raw_RMS_Voltage = (uint32_t)(msbData<<24)|(endian_data2<<16)|(endian_data1<<8)| lsbData;
RawRms_volt=raw_RMS_Voltage;
Serial.print("Raw RMS Voltage=");
Serial.print(RawRms_volt);Serial.println();
raw_RMS_Voltage=(raw_RMS_Voltage&0x7FFF);
calc_RMS_Voltage = (uint64_t)raw_RMS_Voltage*116274;
calc_RMS_Voltage *= 10;
calc_RMS_Voltage >>= 15;
CalcRMS_volt=calc_RMS_Voltage/1000;
return CalcRMS_volt;
}
float readRMScurrent()
{
uint8_t received_data[5] = {0};//array to store receeived bytes
uint8_t revData[5] = {0};
uint32_t raw_RMS_Current = 0;
uint64_t calc_RMS_Current = 0;
/******** LATCHING ********/
snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
rcvData(0x48);
raw_RMS_Current = (uint32_t)(msbData<<24)|(endian_data2<<16)|(endian_data1<<8)| lsbData;
Serial.print("Raw RMS Current=");
Serial.print(raw_RMS_Current);Serial.println();
raw_RMS_Current=(raw_RMS_Current>>15);
RawRms_curr=raw_RMS_Current;
calc_RMS_Current = (uint64_t)raw_RMS_Current*25934;
calc_RMS_Current *= 10;
calc_RMS_Current >>= 17;
CalcRMS_curr=calc_RMS_Current/1000;
return CalcRMS_curr;
}
float readActivePower()
{
int32_t raw_ACT_power=0;
int64_t calc_ACT_power=0;
uint8_t received_data[5] = {0};//array to store receeived bytes
/******** LATCHING ********/
snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
rcvData(0x5C);
for(int i=0;i<5;i++)
{
if(stpm3xSerial.available())
{
delay(1);
received_data[i] = stpm3xSerial.read();
Serial.print("Received Data Byte:0x");
Serial.print(received_data[i],HEX);
Serial.println();
}
}
for(int i=0;i<5;i++)
{
raw_ACT_power |= (uint32_t)u8ByteReverse(received_data[i])<<(8*i);
}
raw_ACT_power=raw_ACT_power&(uint32_t)0x1FFFFFFF;
raw_ACT_power <<= 4; // handle sign extension as power is on 28 bits
raw_ACT_power >>= 4;
calc_ACT_power=((int64_t)raw_ACT_power*30154605);
calc_ACT_power *= 10;
calc_ACT_power >>= 28;
active_pwr=(int32_t)calc_ACT_power/1000;//kW
return active_pwr;
}
float readActiveEnergy()
{
uint8_t received_data[5] = {0};//array to store receeived bytes
/******** LATCHING ********/
snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
rcvData(0x54);
for(int i=0;i<5;i++)
{
while(stpm3xSerial.available())
{
delay(1);
received_data[i] = stpm3xSerial.read();
Serial.print("Received Data Byte:0x");
Serial.print(received_data[i],HEX);
Serial.println();
}
}
for(int i=0;i<5;i++)
{
raw_act_nrj |= (uint32_t)u8ByteReverse(received_data[i])<<(8*i);
}
active_nrj=nrj_calc(raw_act_nrj);
active_nrj = active_nrj/1000;// dividing by 1000 to get watt hour mWh to Wh
return active_nrj;
}