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.

Need help solving runtime library conflict

Other Parts Discussed in Thread: CC3200, ENERGIA, UNIFLASH

Hey everyone,

I have a simple sketch for an energy monitor using a variation of openenergymonitor.org/emon on a CC3200 LaunchPad. This sketch works successfully, as do the WiFiWebClient and WiFiWebClientRepeating sample projects.

However, if I simply add this line of code to my sketch, it uploads successfully but does not run. Serial returns nothing and the board is inactive.

#include <WiFi.h>

It works fine if I simply remove this line. The WiFi sample sketches on their own work fine too.

If I do the opposite and add the EmonLib.h library include to the Wifi sketch, the same problem occurs.

Code added to WifiLibClientRepeating.ino:

#include <EmonLib.h>

Maybe this is a library conflict? I'm confused because the compilation and upload are successful - so it must be a runtime issue. But as I mentioned above - both sketches work on their own - just not together.

I'm using the latest version of Energia on windows (energia-0101E0014), board is Rev 4.1.

I really appreciate any help as I'm really stuck. Hope you have a great afternoon!

Cheers, Rich


Sketch Code:

#include <WiFi.h>           // Sketch works if this line is removed
#include <EmonLib.h>

EnergyMonitor emon1;                // CT1
EnergyMonitor emon2;                // CT2

struct POWERDATA {
    double w;
    double va;
    double v;
    double a;
    double f;
    double kwh;
    double kwhday;
} pwr;

const int ct1Pin = A0;
const int ct2Pin = A1;
const int acBiasPin = A2;

void setup()
{
    
  Serial.begin(115200);
  Serial.println("starting...");   // <-- never displayed if this line exists: #include <WiFi.h>
 
  pinMode(RED_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(ct1Pin, INPUT);            // CT1
  pinMode(ct2Pin, INPUT);            // CT2
  pinMode(acBiasPin, INPUT);            // AC Bias
 
  emon1.current(ct1Pin, 60.6);            // Current: input pin, calibration.
  emon1.voltage(acBiasPin, 123.5, 1.7);            // Voltage: input pin, calibration, phase_shift

  emon2.current(ct2Pin, 60.6);            // Current: input pin, calibration.
  emon2.voltage(acBiasPin, 123.5, 1.7);            // Voltage: input pin, calibration, phase_shift

}

void loop()
{

  digitalWrite(RED_LED, HIGH);
  emon1.calcVI(20, 2000);            // Calculate all. No.of wavelengths, time-out
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  emon2.calcVI(20, 2000);            // Calculate all. No.of wavelengths, time-out
  digitalWrite(GREEN_LED, LOW);

  pwr.w = emon1.realPower + emon2.realPower;
  pwr.va = emon1.apparentPower + emon2.apparentPower;
  pwr.v = (emon1.Vrms + emon2.Vrms) / 2.0;
  pwr.a = emon1.Irms + emon2.Irms;
  pwr.f = (emon1.powerFactor + emon2.powerFactor) / 2.0;
  pwr.kwh += (pwr.w / 3600000.0);        // 1000W/kW / 3600s/h
  pwr.kwhday += (pwr.w / 3600000.0);
 
  Serial.print(pwr.w);
  Serial.println(" w");

}


Here is the EmonLib.h library for reference as the issue must be related to this:

/*
Emon.h - Library for openenergymonitor
Created by Trystan Lea, April 27 2010
GNU GPL
modified to use up to 12 bits ADC resolution (ex. Arduino Due)
by boredman@boredomprojects.net 26.12.2013
*/

#ifndef EmonLib_h
#define EmonLib_h

#if defined(ARDUINO) && ARDUINO >= 100

#include "Energia.h"

#else

#include "WProgram.h"

#endif

// to enable 12-bit ADC resolution on Arduino Due,
// include the following line in main sketch inside setup() function:
// analogReadResolution(ADC_BITS);
// otherwise will default to 10 bits, as in regular Arduino-based boards.
#if defined(__arm__)
#define ADC_BITS 12
#else
#define ADC_BITS 10
#endif

#define ADC_COUNTS (1<<ADC_BITS)


class EnergyMonitor
{
public:

void voltage(int _inPinV, double _VCAL, double _PHASECAL);
void current(int _inPinI, double _ICAL);

void voltageTX(double _VCAL, double _PHASECAL);
void currentTX(int _channel, double _ICAL);

void calcVI(int crossings, int timeout);
double calcIrms(int NUMBER_OF_SAMPLES);
void serialprint();

long readVcc();
//Useful value variables
double realPower,
apparentPower,
powerFactor,
Vrms,
Irms;

private:

//Set Voltage and current input pins
int inPinV;
int inPinI;
//Calibration coeficients
//These need to be set in order to obtain accurate results
double VCAL;
double ICAL;
double PHASECAL;

//--------------------------------------------------------------------------------------
// Variable declaration for emon_calc procedure
//--------------------------------------------------------------------------------------
    int lastSampleV,sampleV; //sample_ holds the raw analog read value, lastSample_ holds the last sample
    int lastSampleI,sampleI;

    double lastFilteredV,filteredV; //Filtered_ is the raw analog value minus the DC offset
    double lastFilteredI, filteredI;

    double phaseShiftedV; //Holds the calibrated phase shifted voltage.

    double sqV,sumV,sqI,sumI,instP,sumP; //sq = squared, sum = Sum, inst = instantaneous

    int startV; //Instantaneous voltage at start of sample window.

    boolean lastVCross, checkVCross; //Used to measure number of times threshold is crossed.
    int crossCount; // ''


};

#endif



And EmonLib.cpp:

/*
Emon.cpp - Library for openenergymonitor
Created by Trystan Lea, April 27 2010
GNU GPL
modified to use up to 12 bits ADC resolution (ex. Arduino Due)
by boredman@boredomprojects.net 26.12.2013
*/

//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
#include "EmonLib.h"

#if defined(ARDUINO) && ARDUINO >= 100

#include "Energia.h"

#else

#include "WProgram.h"

#endif

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltage(int _inPinV, double _VCAL, double _PHASECAL)
{
inPinV = _inPinV;
VCAL = _VCAL;
PHASECAL = _PHASECAL;
}

void EnergyMonitor::current(int _inPinI, double _ICAL)
{
inPinI = _inPinI;
ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors based on emontx pin map
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
{
inPinV = 2;
VCAL = _VCAL;
PHASECAL = _PHASECAL;
}

void EnergyMonitor::currentTX(int _channel, double _ICAL)
{
if (_channel == 1) inPinI = 3;
if (_channel == 2) inPinI = 0;
if (_channel == 3) inPinI = 1;
ICAL = _ICAL;
}

//--------------------------------------------------------------------------------------
// emon_calc procedure
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kwh increment
// From a sample window of the mains AC voltage and current.
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
//--------------------------------------------------------------------------------------
void EnergyMonitor::calcVI(int crossings, int timeout)
{
#if defined emonTxV3
    int SUPPLYVOLTAGE=3300;
#else
    int SUPPLYVOLTAGE = readVcc();
#endif

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

//-------------------------------------------------------------------------------------------------------------------------
// 1) Waits for the waveform to be close to 'zero' (500 adc) part in sin curve.
//-------------------------------------------------------------------------------------------------------------------------
boolean st=false; //an indicator to exit the while loop

unsigned long start = millis(); //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

while(st==false) //the while loop...
{
startV = analogRead(inPinV); //using the voltage waveform
if ((startV < (ADC_COUNTS/2+50)) && (startV > (ADC_COUNTS/2-50))) st=true; //check its within range
if ((millis()-start)>timeout) st = true;
}

//-------------------------------------------------------------------------------------------------------------------------
// 2) Main measurment loop
//-------------------------------------------------------------------------------------------------------------------------
start = millis();

while ((crossCount < crossings) && ((millis()-start)<timeout))
{
numberOfSamples++; //Count number of times looped.

lastSampleV=sampleV; //Used for digital high pass filter
lastSampleI=sampleI; //Used for digital high pass filter

lastFilteredV = filteredV; //Used for offset removal
lastFilteredI = filteredI; //Used for offset removal

//-----------------------------------------------------------------------------
// A) Read in raw voltage and current samples
//-----------------------------------------------------------------------------
sampleV = analogRead(inPinV); //Read in raw voltage signal
sampleI = analogRead(inPinI); //Read in raw current signal

//-----------------------------------------------------------------------------
// B) Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
//-----------------------------------------------------------------------------
filteredV = 0.996*(lastFilteredV+(sampleV-lastSampleV));
filteredI = 0.996*(lastFilteredI+(sampleI-lastSampleI));

//-----------------------------------------------------------------------------
// C) Root-mean-square method voltage
//-----------------------------------------------------------------------------
sqV= filteredV * filteredV; //1) square voltage values
sumV += sqV; //2) sum

//-----------------------------------------------------------------------------
// D) Root-mean-square method current
//-----------------------------------------------------------------------------
sqI = filteredI * filteredI; //1) square current values
sumI += sqI; //2) sum

//-----------------------------------------------------------------------------
// E) Phase calibration
//-----------------------------------------------------------------------------
phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);

//-----------------------------------------------------------------------------
// F) Instantaneous power calc
//-----------------------------------------------------------------------------
instP = phaseShiftedV * filteredI; //Instantaneous Power
sumP +=instP; //Sum

//-----------------------------------------------------------------------------
// G) 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 = true;
else checkVCross = false;
if (numberOfSamples==1) lastVCross = checkVCross;

if (lastVCross != checkVCross) crossCount++;
}

//-------------------------------------------------------------------------------------------------------------------------
// 3) Post loop calculations
//-------------------------------------------------------------------------------------------------------------------------
//Calculation of the root of the mean of the voltage and current squared (rms)
//Calibration coeficients applied.

double V_RATIO = VCAL *((SUPPLYVOLTAGE/1000.0) / (ADC_COUNTS));
Vrms = V_RATIO * sqrt(sumV / numberOfSamples);

double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / (ADC_COUNTS));
Irms = I_RATIO * sqrt(sumI / numberOfSamples);

//Calculation power values
realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
apparentPower = Vrms * Irms;
powerFactor=realPower / apparentPower;

//Reset accumulators
sumV = 0;
sumI = 0;
sumP = 0;
//--------------------------------------------------------------------------------------
}

//--------------------------------------------------------------------------------------
double EnergyMonitor::calcIrms(int NUMBER_OF_SAMPLES)
{

#if defined emonTxV3
    int SUPPLYVOLTAGE=3300;
#else
    int SUPPLYVOLTAGE = readVcc();
#endif


for (int n = 0; n < NUMBER_OF_SAMPLES; n++)
{
lastSampleI = sampleI;
sampleI = analogRead(inPinI);
lastFilteredI = filteredI;
filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

// Root-mean-square method current
// 1) square current values
sqI = filteredI * filteredI;
// 2) sum
sumI += sqI;
}

double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / (ADC_COUNTS));
Irms = I_RATIO * sqrt(sumI / NUMBER_OF_SAMPLES);

//Reset accumulators
sumI = 0;
//--------------------------------------------------------------------------------------

return Irms;
}

void EnergyMonitor::serialprint()
{
Serial.print(realPower);
Serial.print(' ');
Serial.print(apparentPower);
Serial.print(' ');
Serial.print(Vrms);
Serial.print(' ');
Serial.print(Irms);
Serial.print(' ');
Serial.print(powerFactor);
Serial.println(' ');
delay(100);
}

//thanks to hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
//and Jérôme who alerted us to provideyourown.com/.../secret-arduino-voltmeter-measure-battery-voltage

long EnergyMonitor::readVcc() {
long result;

//not used on emonTx V3 - as Vcc is always 3.3V - eliminates bandgap error and need for calibration harizanov.com/.../thoughts-on-avr-adc-accuracy

#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560 openenergymonitor.org/.../2253
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
    
#endif


#if defined(__AVR__)
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; //1100mV*1024 ADC steps openenergymonitor.org/.../1186
return result; //Arduino Due
#else
return (1400); //Changed from 3300 to 1400 for the TI CC3200 vref (note some users said its 1.46V to get full 4095 range)
#endif
}



  • Through the process of elimination I have isolated the cause of this - but I'm even more baffled as to why it is happening or how to fix it.

    If I edit EmonLib.cpp to remove the three references to the sqrt() function, everything works as expected - of course with the exception that the values are wrong due to the calculations being changed.

    If I modify these three lines from EmonLib.cpp:

    157 Vrms = V_RATIO * sqrt(sumV / numberOfSamples);

    160 Irms = I_RATIO * sqrt(sumI / numberOfSamples);

    200 Irms = I_RATIO * sqrt(sumI / NUMBER_OF_SAMPLES);

    To removing the sqrt() functions as follows:

    157 Vrms = V_RATIO * sumV / numberOfSamples;

    160 Irms = I_RATIO * sumI / numberOfSamples;

    200 Irms = I_RATIO * sumI / NUMBER_OF_SAMPLES;

    Then everything works fine.

    This is very strange as the calculations with sqrt() work fine when WiFi.h is not included as stated above. I am also able to add a simple test to WiFiWebClientRepeating.ino which also works - such as:

    double test = sqrt(4);

    I'd be grateful if anyone could shed some light on this. I really appreciate any help!

    Cheers, Rich

  • I gave this a try and enhanced the Sketch with code to connect to a WiFi network. It seems to work for me with Energia 14. It connects to a WiFi network and then prints the wattage. Also the LED's are blinking as expected. Can you give the attached Sketch a try on Energia 14?

    Thanks,

    Robert

    Emon.zip

  • Hi Robert,


    Thanks for taking the time to look at this.

    I took your zip as is, changed the ssid settings and ran it on my CC3200 LP with the same result as I had before - no serial output and the board does nothing.

    I then removed the sqrt() functions and ran it again - and it works fine. I took two screen captures to compare:

    1. With sqrt() - not working

    2. With sqrt() removed - works:

    And here is the physical board after successful upload but not working (with sqrt() included):

    My board is rev 4.1, Energia for windows 0101E0014. I also used UniFlash to get the version details:

    [12:33:20] Begin GetVersion operation.
    [12:33:22] INFO: > Executing Operation: Connect
    [12:33:24] INFO: setting break signal
    [12:33:24] INFO: --- please restart the device ---
    [12:33:24] INFO: connection succeeded
    [12:33:24] INFO: getting storage list
    [12:33:24] INFO: > Executing Operation: GetVersion
    [12:33:24] INFO: reading version info
    [12:33:24] INFO: > Bootloader version: 2.1.4.0
    [12:33:24] INFO: > Chipset version: 16
    [12:33:24] INFO: > Executing Operation: Disconnect
    [12:33:24] Operation GetVersion returned.

    Also, as mentioned above, the EmonLib does work fine WITH the sqrt() functions if WiFi.h is not included.

    Thanks again for your efforts - I really appreciate it!


    Cheers, Rich

  • Hi Robert,

    Just wondering if you are looking into this or could suggest an alternative support route for me? I'm roadblocked on my project until I resolve this...

    Thanks and hope you have a great day!

    Cheers, Rich

  • Hi Rick,

    The board I tried with is the same version as yours. Right now I am not able to reproduce it and will be hard to get you an alternative. Will try again putting the library in the library folder rather than including in the Sketch. Can you try one thing for me? Can you remove the EmonLib library from the Energia library folder so that there is no confusion between the one I included in the Sketch vs the one you have installed in the library folder? I will try the other way around in an attempt to reproduce.

    Thanks,

    Robert

  • Thanks for the update!

    Yes - as you suggested I removed the original EmonLib from the Energia library folder - so I'm sure I was using your version.

    Thanks again!

    Cheers, Rich
  • Hi Robert,

    Hope you had a nice weekend!

    If you are still unable to reproduce this, could you confirm the board jumper positions you have or any other environment specific setup I can try?

    Otherwise, I'm not sure what else to do. Could it be a physical problem with my board?

    Thanks,
       Rich