1

I am trying to communicate between my PC and Arduino Mega 2560 using this serial library. It works reliably, however I am having trouble passing messages at a high rate over serial. I set the baud to 460800 bps on both systems, and am using a serial handshake. The Arduino reads the values by parsing a string, however during my testing I cannot parse more than ~240 messages per second. Each message into the Arduino is either of the form "r/n" to reset some variables or "0,0,0\n" where in this case the zeroes are the ints I want to parse, these can change. My Arduino code in the loop is as follows:

if(Serial.available() > 0){
  resultString = Serial.readStringUntil('\n');
  if(resultString.equals("r")){
    countEnc0 = 0;
    countEnc1 = 0;
    countEnc2 = 0;
  }else{
    int counter = 0;
    int lastIndex = 0;
    for (int i = 0; i < resultString.length(); i++) {
      // Loop through each character and check if it's a comma
      if (resultString.substring(i, i+1) == ",") {
        // Grab the piece from the last index up to the current position and store it
        write[counter] = resultString.substring(lastIndex, i).toInt();
        // Update the last position and add 1, so it starts from the next character
        lastIndex = i + 1;
        // Increase the position in the array that we store into
        counter++;
      }
      // If we're at the end of the string (no more commas to stop us)
      if (i == resultString.length() - 1) {
        // Grab the last part of the string from the lastIndex to the end
        write[counter] = resultString.substring(lastIndex, i+1).toInt();
      }
    }
    analogWrite(8, write[0]); 
    analogWrite(9, write[1]);
    analogWrite(10, write[2]);
  }
  Serial.println(String(countEnc0) + "," + String(countEnc1) + "," + String(countEnc2));
}

I know there are more efficient ways to parse this, however my attempts to use them yield similar results (Using parseInt(), char*, etc). Additionally, I am using 3 interrupts to read sensor values and store them in variables here, and writing the values I acquire to the PWM. As long as I can read and send up to 1000 messages per second that's all I need for now. Many thanks...been banging my head against the wall on this one.

  • 2
    Yup, parsing is slow. Use raw binary whenever possible. – Ignacio Vazquez-Abrams Jun 19 '15 at 19:27
  • 2
    If you are getting ~240 message/sec, comment out your for loop and see what the maximum throughput might be is the cost of processing your data were 0. That would be an interesting number to hear from you and would then give us a base line on your expectations. – Kolban Jun 20 '15 at 2:31
1

First off, I would recommend strtok or even getline to parse comma delimited strings.

Secondly, I'm pretty sure no PWM is responsive enough for 1000 updates per second. But for other purposes this data rate might be needed.

To do this, build a custom cache that does the following:

  1. Reads 1000 characters per go, if available, or less.
  2. Parses on the go. From this set up callbacks to you PWM class, so that you can set PWM values while parsing.

Why this? I am not convinced that the sluggishness is due to the for parsing data. More likely, it's because you are processing every instruction as you get it.

1000 serial reads with 6 length for loops over strings (your case) will be significantly slower than 1 serial read and a 6k length for loop.

1

The String class is slow. I would get rid of that first. I am confused about whether you are sending or receiving, or both, as your code seems to parse and then send. See this test code here:

int countEnc0 = 123;
int countEnc1 = 456;
int countEnc2 = 789;

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  unsigned long start = micros ();
  Serial.println(String(countEnc0) + "," + String(countEnc1) + "," + String(countEnc2));
  Serial.flush ();

  Serial.print ("Time taken = ");
  Serial.print (micros () - start);
  Serial.println (" uS");  
  }  // end of setup

void loop () { }

That replicates the time taken for that one line which echoes the three figures. My results were:

Time taken = 1632 uS

OK, yours will be faster at the faster baud rate, but only 4 times as fast.

So, 240 times that and allowing for the faster baud rate gives:

1632 * 240 / 4 = 97920 µS

That's a fair bit of that second gone (a tenth), without even parsing anything.

0

If your bottleneck is really in the parsing (and you should confirm this before you spend any effort to optimize it), eliminate the parsing.

I usually recommend sending ASCII strings on serial channels to make debugging simpler, and I'd still suggest you get everything working this way first, even if you can't make the sample rate you need.

Once you're convinced your system works except for its speed, you can replace the ASCII communication with raw binary. A simple protocol would suffice: 3 or 6 bytes (do you need int16_ts?) of data and a 1 byte checksum downstream, and an ACK / NAK byte upstream to trigger a resend if needed, will probably be more than sufficient.

The receiver would only have to confirm the checksum and process the already ready-to-go binary sample values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.