Issue with simultaneous serial communications

I'm developing a piece of test equipment using an Arduino MEGA 2560 interfacing with a 4D Systems uLCD-70-DT resistive touchscreen display. The display allows for the user to input required information, and the Arduino acts as a host to process and return the inputs to display on the screen.

Accepting and displaying user inputs is the first step in my software design. This was a success. However, now I need the Arduino to read and monitor AC current values using a non-invasive current sensor.

I found an Arduino library capable of doing this courtesy of OpenEnergyMonitor.org. Applying this library, and implementing the following code is what allows for the Arduino to read and calculate the current that the sensor is seeing.

#include "EmonLib.h"                   // Include Emon Library
EnergyMonitor emon1;                   // Create an instance
 
void setup()
{  
  Serial.begin(9600);
 
  emon1.current(5, 60);             // Current: input pin, calibration.
  //calibration is explained bellow
}
 
void loop()
{
  double Irms = emon1.calcIrms(1480);  // Calculate Irms only
 
  Serial.print(Irms*230.0);	       // Apparent power
  Serial.print(" ");
  Serial.println(Irms);		       // Irms
}

The following is my code, made to process events from the display, and now with the current sensor:

void setup()
{
  Serial.begin(115200); // baud rate for the Arduino AND THE DISPLAY is set at 115200
  Serial1.begin(115200); // to comminicate with LCD
  genie.Begin(Serial1); // Serial port 1 (RX1 & TX1 on the Arduino) handles user keyboard inputs
  genie.AttachEventHandler(myGenieEventHandler); 
  pinMode(RESETLINE, OUTPUT);  // Set D4 on Arduino to Output (4D Arduino Adaptor V2 - Display Reset)
  digitalWrite(RESETLINE, 1);  // Reset the Display via D4
  delay(100);
  digitalWrite(RESETLINE, 0);  // unReset the Display via D4
  emon1.current(5, 64.3); // Current: input pin, calibration.

  delay (3500); //let the display start up after the reset (This is important)
}

void loop()
{
  //Process events
  genie.DoEvents();
  
  keyvalueConvc = atof(keyvaluec);  // ascii to float conversion for copper inputs
  keyvalueConva = atof(keyvaluea);  // ascii to float conversion for aluminum inputs

/* physical computing for the current sensor:
 *  i(measured) = √2 * i(rms_current) = 1.414 * 150A = 212.1 A
 *  The current at the output of the sensor is defined by its number of turns, which is 2125 turns.
 *  i(sensor) = i(measured) / nb_turns = 212.1A / 2125 = 0.0998A
 *  Arduino can only handle voltage (between 0V and 5V) and so the current needs to be converted into an acceptable voltage. So a burden resistor is needed in the circuit.
 *  As the current is alternative around 0 and to maximize measurement resolution, the max voltage at burden resistance should be Max_accepted_voltage / 2 = 2.5V.
 *  Therefore, the best burden resistor value is
 *  R(burden) = U(sensor)/I(sensor) = 2.5V / 0.0707A = 35.4Ω
 *  A 33Ω resistor will be used in this case.
 *  Arduino can not measure negative voltage, so 2.5V is added to U(sensor) to make the voltage measurable (between 0V and 5V).
 *  Additionally, 2 resistors are added, 10kΩ to avoid too much energy consumption.
 *  Also, a low reactance capacitor, 10uF – a few hundred ohms – is added and provides an alternative path for the alternating current to bypass the resistor.
 *  Finally, the current sensor needs calibration:
 *  calibration_value = ( i(measured) / i(sensor) ) / R(burden)
 *  calibration_value = (212.1 A / 0.0998A) / 33Ω
 *  calibration_value = 2125/33Ω = 64.3
*/

  double Irms = emon1.calcIrms(1480);  // Calculate Irms based on current sensor
    
}

The Arduino now does not return and show user inputs on the display. The one line of code
double Irms = emon1.calcIrms(1480); // Calculate Irms based on current sensor
is what breaks this function.

My theory is that the display and the current calculation are both contending for the serial communication. Thus, user inputs are no longer being processed and returned to the display because it also intends to receive and calculate information from the current sensor.

If I am right, is there a method to achieve simultaneous serial communications? If I am wrong, does anyone see any issues that would cause my prototype to lose this functionality?

Attached is my complete sketch if it is of any assistance.

Thanks for any time and help.

Sketch_RevA.ino (10.3 KB)

I really don't understand these two methods -

float currentValuesc(float keyvalueConvc)  // calculate current values based on user inputed copper wire size
{
  float amp1 = 7200 * pow(keyvalueConvc, 1.65); // current value 1
  float amp2 = amp1 + 400 * pow(keyvalueConvc, 1.65); // current value 2
  float amp3 = amp2 + 400 * pow(keyvalueConvc, 1.65); // current value 3
  float amp4 = amp3 + 400 * pow(keyvalueConvc, 1.65); // current value 4
  float amp5 = amp4 + 400 * pow(keyvalueConvc, 1.65); // current value 5
  float amp6 = amp5 + 400 * pow(keyvalueConvc, 1.65); // current value 6
    
  return amp1, amp2, amp3, amp4, amp5, amp6;
}

float currentValuesa(float keyvalueConva)  // calculate current values based on user inputed aluminum wire size
{
  float amp1 = 867 * pow(keyvalueConva, 1.08); // current value 1
  float amp2 = amp1 + 48 * pow(keyvalueConva, 1.08); // current value 2
  float amp3 = amp2 + 48 * pow(keyvalueConva, 1.08); // current value 3
  float amp4 = amp3 + 48 * pow(keyvalueConva, 1.08); // current value 4
  float amp5 = amp4 + 48 * pow(keyvalueConva, 1.08); // current value 5
  float amp6 = amp5 + 48 * pow(keyvalueConva, 1.08); // current value 6
    
  return amp1, amp2, amp3, amp4, amp5, amp6;
}

What do you expect them to do?

P.S. Have you looked at the compilation warnings?

stowite:
I really don't understand these two methods -

return amp1, amp2, amp3, amp4, amp5, amp6;

Those return states, while goofy, and largely useless, are syntactically valid. The return value will be amp6 only.

Why anyone would write that is beyond me....

Regards,
Ray L.

RayLivingston:
Those return states, while goofy, and largely useless, are syntactically valid.

Syntactically valid - yes - but produces warnings. Taken with the most peculiar body content the methods do not make sense to me.

stowite:
I really don't understand these two methods -

float currentValuesc(float keyvalueConvc)  // calculate current values based on user inputed copper wire size

{
 float amp1 = 7200 * pow(keyvalueConvc, 1.65); // current value 1
 float amp2 = amp1 + 400 * pow(keyvalueConvc, 1.65); // current value 2
 float amp3 = amp2 + 400 * pow(keyvalueConvc, 1.65); // current value 3
 float amp4 = amp3 + 400 * pow(keyvalueConvc, 1.65); // current value 4
 float amp5 = amp4 + 400 * pow(keyvalueConvc, 1.65); // current value 5
 float amp6 = amp5 + 400 * pow(keyvalueConvc, 1.65); // current value 6
   
 return amp1, amp2, amp3, amp4, amp5, amp6;
}

float currentValuesa(float keyvalueConva)  // calculate current values based on user inputed aluminum wire size
{
 float amp1 = 867 * pow(keyvalueConva, 1.08); // current value 1
 float amp2 = amp1 + 48 * pow(keyvalueConva, 1.08); // current value 2
 float amp3 = amp2 + 48 * pow(keyvalueConva, 1.08); // current value 3
 float amp4 = amp3 + 48 * pow(keyvalueConva, 1.08); // current value 4
 float amp5 = amp4 + 48 * pow(keyvalueConva, 1.08); // current value 5
 float amp6 = amp5 + 48 * pow(keyvalueConva, 1.08); // current value 6
   
 return amp1, amp2, amp3, amp4, amp5, amp6;
}




What do you expect them to do? 

P.S. Have you looked at the compilation warnings?

Those are functions I wrote to calculate current values that a test sample will experience. It is with respect to the test method that the tester will conform to. I don't need them "yet" and they don't appear to be an issue at the moment.

I don't see any compilation errors with the sketch as is. Only memory notifications.

My theory is that the display and the current calculation are both contending for the serial communication.

Nope. You'd need to post a link to the library you are using, so we can see what pins, timers, etc. it is using. You'd need to post a link to the touch screen/library, so we can see what pins, timers. etc. it is using.

PaulS:
Nope. You'd need to post a link to the library you are using, so we can see what pins, timers, etc. it is using. You'd need to post a link to the touch screen/library, so we can see what pins, timers. etc. it is using.

No problem.
Library for the resistive touchscreen display: https://github.com/4dsystems/ViSi-Genie-Arduino-Library
Library for the OpenEnergyMonitor electricity monitor: GitHub - openenergymonitor/EmonLib: Electricity monitoring library - install in Arduino IDE's libraries folder then restart the IDE

Which files can I inspect from the libraries to see what pins are being used? That would be helpful moving forward.

Actually, I answered that question myself. I'm inspecting the .h and .cpp files for the Emon Library. Looks like it might be using pin 1 for something. I also used pin 1 for tx and rx with the display. I'm going to switch pins and see what happens.

I switched pins from TX1 and RX1 to TX2 and RX2. Still same issue. My best guess now is that there are still some pins that are conflicting. I can't tell which ones, though.

lanembr:
Looks like it might be using pin 1 for something. I also used pin 1 for tx and rx with the display. I'm going to switch pins and see what happens.

The Mega has 4 hardware serial ports so there is plenty of opportunity to avoid conflicts.

If you want help post your complete program.

...R

Robin2:
The Mega has 4 hardware serial ports so there is plenty of opportunity to avoid conflicts.

If you want help post your complete program.

...R

My original post has my sketch in its current state attached. Below are the libraries I'm using.
Library for the display: GitHub - 4dsystems/ViSi-Genie-Arduino-Library: ViSi-Genie - Arduino Library
Library for the current sensing function: GitHub - openenergymonitor/EmonLib: Electricity monitoring library - install in Arduino IDE's libraries folder then restart the IDE

I've tried changing which pins are used in the Emon library, but that didn't work. I think the display library is using pins 0 and 1 (rx0 and tx0) and is conflicting with the Emon library, but I'm having difficulty tracking this down.

I think the display library is using pins 0 and 1 (rx0 and tx0)

It uses whatever Stream based sub-class instance you tell it to use. The hardware may dictate that certain pins are used. The software doesn't care if you use Serial, Serial1, Serial2, Serial3, or some instance of SoftwareSerial or AltSoftSerial.

The following is some of my code

When you are ready to share it all, I'll have a look.

PaulS:
It uses whatever Stream based sub-class instance you tell it to use. The hardware may dictate that certain pins are used. The software doesn't care if you use Serial, Serial1, Serial2, Serial3, or some instance of SoftwareSerial or AltSoftSerial.
When you are ready to share it all, I'll have a look.

Thanks for all the information so far. I'm racking my head with this issue. Please see attached for my whole sketch, the Emon Library, and the Display Library.

Sketch_RevA.ino (10.3 KB)

genieArduino.h (10.4 KB)

genieArduino.cpp (30.8 KB)

EmonLib.h (2.98 KB)

EmonLib.cpp (10.6 KB)

I have only glanced very briefly through your code - there is an awful lot of it.

It looks to me like the EMON library is a resource hog. For example it seems to go through all your 1480 readings before giving anything else a chance to do anything. Other functions seem to run until a timeout expires.

If that is the problem there is probably no alternative to re-writing the EMON library in a non-blocking style. Unfortunately many Arduino libraries are written with no thought to inter-operability.

I have no idea what the GENIE library is supposed to do. If it is just checking for serial input it seems a rather laborious way to do it.

...R

Robin2:
It looks to me like the EMON library is a resource hog. For example it seems to go through all your 1480 readings before giving anything else a chance to do anything. Other functions seem to run until a timeout expires.

Interesting. I didn't think about that. I'm going to test and see if user inputs are being delayed due to the program running all of those processes. I'll let you know my results.

The simplest way to test that is to simply change the number of samples. It seems to be that 1,480 samples is way more than is needed.

Thanks, I'll try that. If I don't get results that I like then I'll reach out to the 4D Systems community and see if they can identify something that might be conflicting between the two libraries. The displays are built to work with Arduino hosts, afterall. They may know something that I haven't thought of.

I think this is one of those situations where interrupt-driven handling of received characters from the Genie device would be beneficial. After a quick look, it appears that Genie::DoEvents could be split into two methods:

  1. Foreground processing of genieFrames (i.e., loop polling of event queue)
void Genie::DoEvents(bool DoHandler)
{ 
     if ((EventQueue.n_events > 0) && (UserHandler != NULL) && DoHandler) {
          (UserHandler)();
      }
}
  1. Background parsing of received chars, which pushes genieFrames into the event queue:
void Genie::DoChars ( uint8_t c ) {
{
    static uint8_t  rx_data[6];
    static uint8_t  checksum = 0;
    static struct MagicReportHeader magicHeader;
    static uint8_t magicByte = 0;

    ///////////////////////////////////////////
    //
    // Main state machine
    //

    switch (GetLinkState()) {
        case GENIE_LINK_IDLE:
            switch (c) {
                case GENIE_REPORT_EVENT:
                    // event frame out of the blue, set the link state
                    // and fall through to the frame-accumulate code
                    // at the end of this function
                    PushLinkState(GENIE_LINK_RXEVENT);
                    break;
       .
       .
       .

    // return GENIE_EVENT_RXCHAR; // What should we really return here?!
}

This could allow the received data to be handled even though EMon is gathering ADC samples.

A few other things to change:

  1. You'd need to use a drop-in replacement for HardwareSerial (the class for Serial, Serial1, et al) in order to be able to attachInterrupt in setup for the received characters: NeoHWSerial.

  2. The return <code>; statements in DoChars (née DoEvents) would just be return; statements. The return values do not appear to be used.

  3. Verify that the event queue is used in an interrupt-safe fashion. You may need cli/sei inside DequeueEvent.

Just a thought...

Cheers,
/dev

lanembr:
Thanks, I'll try that. If I don't get results that I like then I'll reach out to the 4D Systems community and see if they can identify something that might be conflicting between the two libraries.

I don't think there is any sort of conflict with EmonLib... There is only about 360 lines of code and the only use of the serial device is in the 'serialprint' method (amazingly enough).

As for any other pins used, it looks like the user needs to specify the pin numbers used (as arguments to the 'current' and 'voltage' methods).

I wouldn't think compatibility between the two libraries is the issue here.

Regards,

Brad
KF7FER

My suspicion is that the problem is not what you refer to here, but the way the program is wriitten. It seems to be designed to block while it does its stuff.

...R