Serial packet speed

Hello, I'm new to the forum so please don't shout at me if the question is trivial. :slight_smile:

I have to send regularly packets of 27 bytes at a constant pace using an Arduino MEGA and the USB
port.

I tested with a rather simple code:

unsigned char data[27]; //data to be sent each cycle
const char delta=5; //period of data write [ms]
unsigned long t;
unsigned long old_t;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  t=millis();
  old_t=t;
}

void loop() {
  // put your main code here, to run repeatedly:
  t=millis();
  if(t==old_t){delay(delta-1);t=millis();}
  while(t%delta){delayMicroseconds(100);t=millis();}
  old_t=t;

  /*point where some further code may be added*/

  data[0]=t%256;
  data[1]=(t/256)%256;
  data[2]=(t/256/256)%256;
  data[3]=(t/256/256/256);
  Serial.write(data, 27);  
}

A dedicated program on the PC collects data and stores them in a file.
When I check for the presence of all packets, I obtain that up to a delta of 8ms
all the packets are correctly received and logged;
For delta = 7, 6 and 5 milliseconds I observed that I lose randomly 2.3% of packets on
average. Going from 7 to 5 ms does not change the data loss percentage. Data is not corrupted.
Adding code taking about 3ms to execute at the indicated point (between /* */) does not change this behavior.

I searched a lot but I found no explanation for that... most of the topics concern latency
and speed of serial communication.

Is it possible that between loop() executions some code is executed that may take more
than 7ms? Code executed on interrupts may cause so long delays? Is there maybe a
smarter way to do this kind of data transfer?
Any advice would be warmly appreciated.

Cheers,

Riccardo

if you consider that at 115200baud you can send approximately 11520 bytes/second (8 data bits + 1 start bit and 1 stop bit) a simple calculation will tell you how long it will take to transmit 27bytes
you can always try increasing the baud rate but the PC may start to loose data

Indeed, I didn't mention that I tried to increase the baud rate up to 256000. Exactly the
same behavior (8ms ok, 7,6,5ms packets lost) and percentage of data packets lost (2.3%).

Data is lost in packets, not in single bytes.

27 bytes * 10SerialBits/byte / 0.005 s = 54000 baud... less than half the communication speed I'm using.

what software are you using on the PC to receive the bytes?
is it using interrupts to receive data - if so how large is its buffer?
do you do any processing after you receive a packet
could you be loosing data while processing the previous packet?

Any loss of data is on the PC side and NOT the Arduino so ask MS.

Mark

RBit:
Indeed, I didn't mention that I tried to increase the baud rate up to 256000.

I normally communicate between my Arduino program and Python programs on my Linux laptop at 500,000 baud and I don't recall ever missing any data.

It sounds like there is a problem on your PC program.

You have a very strange way of managing time in your Arduino program. Have a look at how millis() is used to manage timing in Several things at a time. Note that the tests for elapsed time always use subtraction as that avoids a problem when millis() rolls over.

...R

I wonder if it has to do with "t%delta" being much faster to calculate with delta=8 than with delta = 7, 6, or 5. If you miss the millisecond where t%delta == 0 then that send will not occur.

115200/10 = 11520 bytes per second / 27 = 426.666 packets per second or 2.34 milliseconds per packet

Try delta=4. That is also easy to calculate and it that value works it would tend to show that the unsigned long modulo is taking too much time and you are missing 2.3% of your millisecond intervals

When you are using millis() for timing, you don't need to insert special little delays in an attempt to delay "just enough" to get to the next time. Have it check the millis() timer several thousand times per second (yes, more than once per millisecond) and then it will do the required action at the required time. The Arduino never gets bored asking "are we there yet?" billions of times over.

void loop() {
  // put your main code here, to run repeatedly:
  t=millis();
  if(t - old_t >= delay){
    old_t += delay;

    /*point where some further code may be added*/

    data[0]=t%256;
    data[1]=(t/256)%256;
    data[2]=(t/256/256)%256;
    data[3]=(t/256/256/256);
    Serial.write(data, 27);  
  }
}

The % operator is actually absurdly slow. It's best to avoid using it. However simple powers of 2 such as 256 are detected by the compiler as a special case and it will usually generate extremely efficient code. You might look up the right-shift operator (>>) and see how that may help with your particular example.