Skip to main content
Associate II
January 15, 2025
Question

Unable to understand the value from STPM34

  • January 15, 2025
  • 0 replies
  • 599 views

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;
}