Because of the Thanksgiving holiday in the U.S., TI E2E™ design support forum responses may be delayed from November 25 through December 2. Thank you for your patience.

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP430G2553: Emon code for MSP430 (energy monitor code) not working

Part Number: MSP430G2553
Other Parts Discussed in Thread: MSP430I2041

Tool/software: Code Composer Studio

Hello everyone, I'm trying to translate the Arduino Emon code library into the MSP430. Basically the code calculates the RMS voltage, RMS current, active power, reactive power and the power factor.

To simulate a signal from the ZMPT101b voltage sensor, I am using a signal generator with a 60 Hz sinusoid, as shown in the figure below:

This is my code:

#include <msp430g2553.h>
#include <stdlib.h> //Use for rand() function
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>

#define ADC_BITS  10
#define ADC_COUNTS  (1<<ADC_BITS)
const int TIPO_TC = 0;  //0-> 0-5 A; 1-> 0-10 A;2-> 0-20A

void ADC_Config_Sequence_Channel_Mode(void);
void Clock_Config(void);
void GPIO_Config(void);
void UART_Config(void);

float offsetV = ADC_COUNTS >> 1;
float filteredV = 0;
float sqV = 0;
float sumV = 0;
float Vrms = 0;

float offsetI = ADC_COUNTS >> 1;
float filteredI = 0;
float sqI = 0;
float sumI = 0;
float Irms = 0;

float phaseShiftedV = 0;
float phaseShiftedI = 0;
float instP = 0;
float sumP = 0;
float realPower = 0;
float apparentPower = 0;
float powerFactor = 0;

//----------------------CALIBRATION-------------------
float VCAL = 681.5;//681.5; //631
float ICAL = 7.6;//7.6; //2.925
float PHASECAL = 0.783;//0.783; //1.9
//----------------------------------------------------

int lastVCross;
int checkVCross;

int SupplyVoltage = 3300;
float ruido = 0;//0.15;// 0.05;

unsigned int contador_1 = 0;
unsigned int contador_2 = 0;

unsigned int crossCount = 0;                                    //Used to measure number of times threshold is crossed.
unsigned int numberOfSamples = 0;                        //This is now incremented
unsigned int startV;

int crossings = 500;
int timeout = 1000;

float lastFilteredI;
float lastFilteredV;
unsigned int sampleV;
unsigned int sampleI;
float V_RATIO;
float I_RATIO;

  V_RATIO = (float) VCAL * ((SupplyVoltage / 1000.0) / (ADC_COUNTS));
  I_RATIO = (float) ICAL * ((SupplyVoltage / 1000.0) / (ADC_COUNTS));

unsigned int read_samples[2];

int STATE = 0;
int TXByte = 0;

int main(void)
{
    Clock_Config();
    GPIO_Config();
    UART_Config();
    ADC_Config_Sequence_Channel_Mode();

    __bis_SR_register(GIE);

    while(1)
    {
//-------------------------------------------------------------------------------------------------------------------------
// STATE = 0 Read de start voltage by interrupt.
//-------------------------------------------------------------------------------------------------------------------------

        if (STATE == 0)
        {
            ADC10DTC1 = 0x01;
            ADC10CTL0 |= ENC + ADC10SC;
            STATE = 1;
        }
//-------------------------------------------------------------------------------------------------------------------------
// STATE = 2 Waits for the waveform to be close to 'zero' (mid-scale adc) part in sin curve.
//-------------------------------------------------------------------------------------------------------------------------

if (STATE == 2)
        {
            if ((startV > (ADC_COUNTS * 0.45)) && (startV < (ADC_COUNTS * 0.55)))
            {
                contador_2 = 0;
                STATE = 3;
            }
            else if (contador_1 > timeout)
            {
                contador_2 = 0;
                STATE = 3;
            }
            else
                STATE = 0;
        }
//-------------------------------------------------------------------------------------------------------------------------
// STATE = 3 Main measurement loop
//-------------------------------------------------------------------------------------------------------------------------

        if (STATE == 3)
        {
            if ((crossCount < crossings) && (contador_2 < timeout))
            {
                numberOfSamples++;                                  // Count number of times looped.
                lastFilteredV = filteredV;                               // Used for delay/phase compensation
//-----------------------------------------------------------------------------
//STATE = 4 Read in raw voltage and current samples by interrupt
//-----------------------------------------------------------------------------

                ADC10DTC1 = 0x02;
                ADC10CTL0 |= ENC + ADC10SC;
                STATE = 4;
            }
            else
            {

               //-------------------------------------------------------------------------------------------------------------------------
               // Post loop calculations
               //-------------------------------------------------------------------------------------------------------------------------
               //Calculation of the root of the mean of the voltage and current squared (rms)
               //Calibration coefficients applied.
          
                Vrms = (float) V_RATIO *sqrtf( sumV / numberOfSamples);
                Irms = (float) I_RATIO *sqrtf( sumI / numberOfSamples);

                realPower = (float) V_RATIO * I_RATIO * (sumP / numberOfSamples);
                apparentPower = (float) Vrms * Irms;
                powerFactor = (float) realPower / apparentPower;
                sumV = 0;
                sumI = 0;
                sumP = 0;
                contador_1 = 0;
                contador_2 = 0;
                STATE = 0;                     //Return to STATE = 0. Starts new calculations
                crossCount = 0;
                numberOfSamples = 0;
            }
        }

        if (STATE == 5)
        {

           //-----------------------------------------------------------------------------
           // STATE = 5 Apply digital low pass filters to extract the 2.5 V or 1.65 V dc offset,
           // then subtract this - signal is now centred on 0 counts.
           //-----------------------------------------------------------------------------
            offsetV = offsetV + ((sampleV - offsetV) / 1024);
            filteredV = sampleV - offsetV;
            offsetI = offsetI + ((sampleI - offsetI) / 1024);
            filteredI = sampleI - offsetI;
            
           //-----------------------------------------------------------------------------
           // Root-mean-square method voltage and current
           //-----------------------------------------------------------------------------
            sqV = (float) filteredV * filteredV;                                    //1) square voltage values
            sumV += sqV;                                                            //2) sum

            sqI = (float) filteredI * filteredI;                                    //1) square current values
            sumI += sqI;                                                            //2) sum
       
           //-----------------------------------------------------------------------------
           // Phase calibration
           //-----------------------------------------------------------------------------
            phaseShiftedV = (float) lastFilteredV + PHASECAL * (filteredV - lastFilteredV);

            //-----------------------------------------------------------------------------
            //  Instantaneous power calc
            //-----------------------------------------------------------------------------
            instP = (float) phaseShiftedV * filteredI;                              //Instantaneous Power
            sumP += instP;                                                          //Sum
           
            //-----------------------------------------------------------------------------
            // Find the number of times the voltage has crossed the initial voltage
            // - every 2 crosses we will have sampled 1 wavelength
            // - so this method allows us to sample an integer number of half wavelengths which increases accuracy
            //-----------------------------------------------------------------------------
            lastVCross = checkVCross;

            if (sampleV > startV)
                checkVCross = 1;
            else
                checkVCross = 0;

            if (numberOfSamples == 1)
                lastVCross = checkVCross;

            if (lastVCross != checkVCross)
                crossCount++;

            contador_2++;
            STATE = 3;          //Return to STATE = 3.
        }
    }
}

#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{
    if (STATE == 1)
    {
        startV = read_samples[0];             //read raw start voltage
        STATE = 2;
        contador_1++;
    }
    else if (STATE == 4)
    {
        sampleV = read_samples[0];            //read raw votage sample
        sampleI = read_samples[1];            //read raw current sample
        STATE = 5;
        IE2 |= UCA0TXIE;
    }
    ADC10SA = &read_samples[0];
}

#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
    if (IFG2 & UCA0TXIFG)
    {
        if (TXByte == 0)
            UCA0TXBUF = (int)Vrms;
        if (TXByte == 1)
            UCA0TXBUF = (int)Irms;
        TXByte++;
        if (TXByte == 2)
        {
            TXByte = 0;
            IE2 &= ~UCA0TXIE;
        }
    }
}
void Clock_Config(void)
{
    WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
    if (CALBC1_16MHZ==0xFF)                   // If calibration constant erased
        while(1);                             // do not load, trap CPU!!
    DCOCTL = 0;                               // Select lowest DCOx and MODx settings
    BCSCTL1 = CALBC1_16MHZ;                   // Set DCO
    DCOCTL = CALDCO_16MHZ;
}

void ADC_Config_Sequence_Channel_Mode(void)
{
    ADC10CTL1 = INCH_5 + CONSEQ_1 + ADC10SSEL_3;
    ADC10CTL0 = ADC10SHT_0 + MSC + REFON + ADC10ON + ADC10IE;
    ADC10DTC1 = 0x02;
    ADC10AE0 |= BIT4 + BIT5;
    ADC10SA = &read_samples[0];
}

void GPIO_Config(void)
{
    P1DIR |= BIT1 + BIT2;
    P1DIR &= ~(BIT4+BIT5);
    P1OUT |= BIT1 + BIT2;
}

void UART_Config(void)
{
    P1SEL |= BIT1 + BIT2;                     // P1.1 = RXD, P1.2=TXD
    P1SEL2 |= BIT1 + BIT2;                    // P1.1 = RXD, P1.2=TXD
    UCA0CTL1 |= UCSWRST;
    UCA0CTL0 |= UCMODE_0;
    UCA0CTL1 = UCSSEL_2 + UCSWRST;            // UCSSEL_2 = SMCLK; UCSWRST = Reset
    UCA0BR0 = 104;                            // 16MHz 9600
    UCA0BR1 = 0;                              // 16MHz 9600
    UCA0MCTL |= UCBRF2 + UCBRF1 + UCOS16;      // Modulation UCBRSx = 0, UCBRFx = 3, UCOS16 = 1
    UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    IE2 |= UCA0RXIE;
}

But when I start the code, the data sent by the UART is random. And when I simply change the ADC10SHT from ADC10SHT_3 to ADC10SHT_0, the MSP does not send anything else to the UART.

Could someone help me understand where the error is? The code for arduino is in this link: https://community.openenergymonitor.org/t/emon-arduino-program-code/7049

**Attention** This is a public forum