Error when serial.print() to LabVIEW in interrupt

Status
Not open for further replies.

lelox93

Active member
Hi everyone!
I'm trying to acquire two analog signals @1kHz, my fixed sampling frequency.
To accomplish this i'm using the library IntervalTimer and calling a function every 1000 microseconds.
The next step that i cannot manage to do is to collect this live stream of data while
displaying it in LabVIEW (I'm using VISA).

This is the code written and uploaded on teensy 3.2 with Teensy Loader 1.40,
Teensyduino version 1.40 installed over Arduino IDE 1.8.3:

Code:
//  Acquisition & display variables
IntervalTimer myTimer; // Create an IntervalTimer object
const int Ch0 = A0;    // the pin with analog input (Channel 0)
const int Ch1 = A1;    // the pin with analog input (Channel 1)
float val_Ch0 = 0;     // the value read from Channel 0 (16 bit)
float val_Ch1 = 0;     // the value read from Channel 1 (16 bit)
float volts_Ch0 = 0;   // value of Channel 0 in volts
float volts_Ch1 = 0;   // value of Channel 1 in volts

// Processing variables
int counter_ms = 0;
int counter_s = 0;

/////////////
//  Setup  //
/////////////

void setup(void) {
  pinMode(Ch0, INPUT);
  pinMode(Ch1, INPUT);
  analogReadResolution(16);
  Serial.begin(9600);
  delay(3000);
  myTimer.begin(ChnlsReadPrint, 1000); // function executed every 1000 us
}


/////////////////////////////////////////////////////////////////////
//  ChnlsReadPrint() is a function called inside an interrupt.     //
//  Is called every 1000 microseconds and performs these tasks:    //
//  - Acquire two analog channels;                                 //
//  - Converts the values in volts;                                //
//  - write them together with the time;                           //
/////////////////////////////////////////////////////////////////////

void ChnlsReadPrint(void) {
  val_Ch0 = analogRead(Ch0);                // read Channel 0
  val_Ch1 = analogRead(Ch1);                // read Channel 1
  volts_Ch0 = val_Ch0 * 3.3 / pow(2, 16);   // conversion to volts
  volts_Ch1 = val_Ch1 * 3.3 / pow(2, 16);   // conversion to volts

  counter_ms += 1;
  if (counter_ms > 999) {
    counter_ms = 0;
    counter_s += 1;
  }
  String stringOne = String(counter_s, DEC);
  String stringTwo = String(counter_ms, DEC);
  String stringThree = String(volts_Ch0, 4);
  String stringFour = String(volts_Ch1, 4);
  String stringTot = String(stringOne + " " + stringTwo + " " + stringThree + " " + stringFour);
  Serial.print(stringTot);
  Serial.print("\r\n");
  Serial.flush();

}

////////////////////////////////////////
//  The main program will do nothing  //
////////////////////////////////////////

void loop(void) {
}


////////////////////////////////////////
//            END OF FILE             //
////////////////////////////////////////

This code works until it happens the "jump" depicted in the following picture:

LabviewProblem2.PNG
LabviewProblem3.PNG

What LabVIEW does is simply:
- reading the serial port with VISA and obtaining a new line with a string
- split the string received into 4 numbers (2 integers and 2 float)
- append each new value into arrays
- plot the array in a xy graph.

Here is the Block Diagram:

LabviewProblem.jpg

I cannot figure out why these jumps happen after tens of thousands of strings...
Thank you in advance,
Leo
 
First, try slowing the speed to only 20 or 100 per second.

My guess is Labview just can't keep up with this speed on a sustained basis. Eventually all the buffers between Serial.print() and Labview acquiring the data fill up, and somewhere something has to give (delete data).

So the first step is to check if much slower speed works, so you can know whether to focus your effort at improving the speed, or whether there is some bug happening which loses data even when running slowly.

If it does turn out the be speed related, then you're going to have to do something to improve the speed for Labview can keep up. Long ago the Arduino Serial Monitor had these same sorts of problems. I put quite a lot of work into improvements, which eventually became part of modern Arduino versions. The main thing that helped was not updating the GUI for every new line of incoming data. Instead, I put a 30 Hz timer into the code. Incoming data was instead just appended to a buffer, and then the buffer contents were used to update the GUI at 30 Hz. Redrawing graphics is incredibly CPU intensive, so if you're asking Labview to do that 1000 times per second, simply storing the data into an array and doing the graph update for every 20, 33, 50 or even 100 measurements will probably help dramatically. In the Arduino IDE, the other CPU critical issue was parsing full USB rate data into lines, partly because Java is inefficient (probably probably still a lot faster than Labview) and partly because Java does quite a lot of special character for non-ASCII characters, which I never did figure out how to turn off. Whether those lessons I learned with Java apply for Labview is a good question.... but before going down this optimization path, first at least do careful testing at slower speeds to figure out if the data loss really is speed related, or some sort of bug that doesn't depend on speed.

If this is a well funded commercial project being done with billable hours, as many Labview uses often are, the other possible speed "optimization" that might be more cost effective would involve just throwing an insanely powerful PC at the problem!
 
ahah if only i had money! (No pressure to learn :D)
Thanks so much for the fast reply, I'm amazed by your kindness.
I will try to follow your suggestions and update the results!
 
Labview actually has quite advanced serial modifications that can greatly speed up the overall VI, check out the Advanced Serial Example. Another thing is using the consumer-producer model that Labview has many examples for so you can make large serial buffer in the consumer loop that is read in the producer loop. Also look at the Serial examples where you can set the delimiters and such in the serial setup part before it runs any loops. Another is you are appending all your data to be read on your front panel with the capturing of serial data, move writing data to the graph and response block to a producer loop at lower a priority and slower update rate than the consumer loop and possibly dump old data in the response block so that it does not consume to much memory.
 
Status
Not open for further replies.
Back
Top