cancel
Showing results for 
Search instead for 
Did you mean: 

STPM34 UART communication with ESP32

vivek_7
Associate II

I have developed code in arduino IDE , I am only getting the output receive from UART 04000A075 . I understand that this is the default value in register DSP_CR1. Could someone please tell me what does this mean.
I hereby provide the code for receiving and transmission of signal from STPM34 to ESP32 using UART.

 

 

#include <HardwareSerial.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <Arduino.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 1024
char 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
uint32_t raw_RMS_Voltage  = 0;
uint32_t raw_RMS_Current  = 0;
uint64_t calc_RMS_Voltage = 0;
uint64_t calc_RMS_Current = 0;
int32_t BRR_REG1;
int32_t raw_ACT_power=0;
int64_t calc_ACT_power=0;
int32_t raw_apparent_pwr=0;
int64_t calc_apparent_pwr=0;
int32_t PH1_REG1=0;
int32_t TOT_REG1=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;


void setup() {
  // put your setup code here, to run once:
   Serial.begin(9600);
  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();
  // timer = timerBegin(80);//timer frequency 80 Mhz
  // timerAttachInterrupt(timer,&onTimer);//call function timer handler
  // timerAlarm(timer,50000,true,0);
}

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();
  RMS_Curr=readRMScurrent();
  Serial.print("RMS Current =");
  Serial.print(RMS_Curr);
  Serial.print("A");
  Serial.println();
  Active_Pwr = readActivePower();
  Serial.print("Active Power =");
  Serial.print(Active_Pwr);
  Serial.print("kW");
  Serial.println();
  Active_Nrj = readActiveEnergy();
  Serial.print("Active Energy =");
  Serial.print(Active_Nrj);
  Serial.print("kWh");
  Serial.println();
  delay(100);
  read_stpm3x_init();
  Serial.print("DSP_CR2_LSB=");
  Serial.print(DSP_CR2_LSB,HEX);
  Serial.println();
  Serial.print("DSP_CR2_MSB=");
  Serial.print(DSP_CR2_MSB,HEX);
  Serial.println();
  Serial.print("DSP_CR3_LSB=");
  Serial.print(DSP_CR3_LSB,HEX);
  Serial.println();
  Serial.print("DSP_CR5_LSB=");
  Serial.print(DSP_CR5_LSB,HEX);
  Serial.println();
  Serial.print("DSP_CR5_MSB=");
  Serial.print(DSP_CR5_MSB,HEX);
  Serial.println();
  delay(100);
}

void STPM_UART_init()
{
  snd_cmmnd_stpm3x(0xFF,0x24,0x2007);//US_REG1 LSB configuration
  snd_cmmnd_stpm3x(0xFF,0x25,0x03E8);// 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,0x00);// US_REG2 MSB config Frame delay = 0
  snd_cmmnd_stpm3x(0xFF,0x28,0x00);// US_REG3 
}

void stpm3x_init()
{
  snd_cmmnd_stpm3x(0xFF,0x00,0xA0);// 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,0x0000);
	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 read_stpm3x_init()
{
	rcvData(0x02);
  memcpy(&DSP_CR2_LSB,STPM3x_RCV,4);
	rcvData(0x03);
  memcpy(&DSP_CR2_MSB,STPM3x_RCV,4);
	rcvData(0x04);
  memcpy(&DSP_CR3_LSB,STPM3x_RCV,4);
  rcvData(0x08);
  memcpy(&DSP_CR5_LSB,STPM3x_RCV,4);
  rcvData(0x09);
  memcpy(&DSP_CR5_MSB,STPM3x_RCV,4);
}

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);
				
				CRC_DATA=CalcCRC8(DATA_WITHOUT_CRC);
				CRC_DATA=u8ByteReverse(CRC_DATA);
				memset(STPM3x_RCV,0,sizeof(STPM3x_RCV));// Clear the uart buffer for stpm3x

        //Write to UART
        if(stpm3xSerial.write(READ_ADDRESS)!=1)
        {
          //Handle UART write error
          Serial.println("UART Write error for READ_ADDRESS");
          return;
        }
        if(stpm3xSerial.write(WRITE_ADDRESS)!=1)
        {
          Serial.println("UART Write error for WRITE_ADDRESS");
          return;
        }
        if(stpm3xSerial.write(LSB_DATA)!=1)
        {
          Serial.println("UART Write error for LSB_DATA");
          return;
        }
        if(stpm3xSerial.write(MSB_DATA)!=1)
        {
          Serial.println("UART Write error for MSB_DATA");
          return;
        }
        if(stpm3xSerial.write(CRC_DATA)!=1)
        {
          Serial.println("UART Write error for CRC_DATA");
          return;
        }
}

void rcvData(uint8_t read_addr)
{
  //Send data to read from register
   snd_cmmnd_stpm3x(read_addr,0xFF,0xFFFF);
   //Serial.println(read_addr,HEX);
  while(stpm3xSerial.available())
  {
    char u2_data = stpm3xSerial.read();//Read from UART2
    if(u2_chk<BUFFER_SIZE -1){
    STPM3x_RCV[u2_chk++]=u2_data;
    // Serial.print("Data received by ESP32:");
    // Serial.println(u2_data,HEX);
    }
    else
    {
      Serial.println("Buffer overflow reset");
      u2_chk=0;
    }
    //STPM3x_RCV[u2_chk] = '\0';
    //Serial.print("Data received by ESP32:");
    //Serial.println(STPM3x_RCV);
  }
}

/*
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()
{
     /********		LATCHING		********/
	   snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
  	/********		 Vrms and Irms 		********/
    rcvData(0x48);
    uint32_t raw_RMS_Voltage  = 0;
    uint64_t calc_RMS_Voltage = 0;
    memcpy(&raw_RMS_Voltage,STPM3x_RCV,4);
    RawRms_volt=raw_RMS_Voltage;
    calc_RMS_Voltage = (uint64_t)raw_RMS_Voltage*116274;
    calc_RMS_Voltage *=  10;
		calc_RMS_Voltage >>= 15;
    CalcRMS_volt=calc_RMS_Voltage/1000000;
    return CalcRMS_volt;
}

float readRMScurrent()
{
   /********		LATCHING		********/
	   snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
  rcvData(0x48);
  memcpy(&raw_RMS_Current,STPM3x_RCV,4);	  
  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/1000000;
  return CalcRMS_curr;
}

float readActivePower()
{
     /********		LATCHING		********/
	   snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
    rcvData(0x5C);
		memcpy(&raw_ACT_power,STPM3x_RCV,4);
		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 readApparentRMSpwr()
{
   /********		LATCHING		********/
	   snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
  rcvData(0x62);
  memcpy(&raw_apparent_pwr,STPM3x_RCV,4);
  raw_apparent_pwr=raw_apparent_pwr&(uint32_t)0x1FFFFFFF;
  raw_apparent_pwr<<=4;
  raw_apparent_pwr>>=4;
  calc_apparent_pwr=((int64_t)raw_apparent_pwr*30154605);
}
float readActiveEnergy()
{
     /********		LATCHING		********/
	   snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
    rcvData(0x54);		
		memcpy(&PH1_REG1,STPM3x_RCV,4);
		active_nrj=nrj_calc(PH1_REG1);
		active_nrj = active_nrj/1000;// dividing by 1000 to get watt hour mWh to Wh
    return active_nrj;
}

float readTotalEnergy()
{
     /********		LATCHING		********/
	   snd_cmmnd_stpm3x(0xFF,0x05,0x0060);
    rcvData(0x84);
    memcpy(&TOT_REG1,STPM3x_RCV,4);
    total_nrj=nrj_calc(TOT_REG1);
    total_nrj=total_nrj/1000;//dividing by 1000 to get watt hour mWh to Wh
    return total_nrj;
}

 

 

10 REPLIES 10
Didier HERROUIN
ST Employee

Sorry, but I can not review you code.

You will find a code example to access to the STPM32 on st.com: https://www.st.com/en/embedded-software/stsw-stpm002.html

You will get a 5 bytes answer after your reading request: bit [0:14] is the RMS voltage, bit[15:31] is the RMS current.
Let me know the value that you read.


You can use the excel file attached to convert the hexa values to the real values (tabulation “Data registers calculation”).

You just have to fill the blue cells with your design parameters and the grey cells with your nominal values (I put 230V and 5A).

Then, all other values will be automatically calculated in the yellow cells, including:

  • the LSB value for RMS voltage and current (cells D24 / D33), which just has to be multiplied by register value (example in F23/F32) to get the real value (example in C23/C32)
  • the LSB value for Instantaneous voltage (cell D25)
  • the LSB value for Power register (cell D38), which just has to be multiplied by register value (example in F40) to get the real value in mW (example in D40)
  • the LSB value for Energy register (cell D41), which just has to be multiplied by register value (example in F43) to get the real value in mWs (example in D43)
  • etc…

The green cells provide also some examples of the conversion between register value to real value.

 

I hope it helps.