Serial write timing calculation

Hey all,

I am trying to perform some calculations to determine the serial write timing but something is off from expected
I am using a Teensy 4.0 and writing a char array buffer of 64bytes to an open log (SparkFun OpenLog - DEV-13712 - SparkFun Electronics) and an antenna (Transceiver Telemetry Radio V3 433MHz – Holybro) via Serial port. The Antenna is connected to Serial1 and the Open log is connected to Serial 2
Both the open log and the antenna have a baud rate set to 115200.

So according to my calculations:
a 64 bytes data stream corresponds to 64 * 8 + 64 + 64 bits, each packet is composed of 8bits plus 1 start and 1 stop bit, right? So the time to write 64 bytes at 115200 baud should be approximately 64*10/115200 = 5.555ms for each one
However when I use the following code to measure the time of writing:

long ti = micros();
AntenaSerial.write(&buff[0], 64);
long tf = micros();
AntenaSerial.write(10); //line feed
Serial.print(tf-ti); Serial.write('\t');

ti = micros();
SDSerial.write(&buff[0], 64);
tf = micros();
SDSerial.write(10); //line feed
Serial.println(tf-ti);

Now the odd part is that, the printing results are
image

How is this possible? Am I missing something?

Thanks in advance,
Best regards

There is a buffer inside the Serial library.
When you write 64 bytes with .write(), then the data is copied into that buffer, the .write() functions return and the sketch continues. Meanwhile, an interrupt sends the data from that buffer, one byte at a time.

With a logic analyzer you can see the TX and RX data and the gaps between the bytes.

Hi @Koepel,

Thanks for the fast reply, but what does that mean?
That the measured time is only the time that it takes to copy to the buffer?

Yes. You might call that the "overhead".

A Teensy 4.0 runs at 600MHz ? https://www.pjrc.com/store/teensy40.html.

Then 1.7 ms is a long time. There must be a lot going on.

I'm very fond of the 25 dollar LHT00SU1 logic analyzer with sigrok/PulseView. Also the 8 channel 24MHz logic analyzers of 10 dollars work, but the quality is not good enough.

A Teensy 4.0 runs at 600MHz ?
Yes it does

I just found that the open log has the time specified

But even using the 0.087ms of time does not add up correctly

If you use Serial.flush(); that waits until the buffer is empty, but without checking I dont know if that also includes the time for the last character to complete sending.

1 Like

Hi @srnet

I guess you are right

I added the serial.flush()

long ti = micros();
AntenaSerial.write(&buff[0], 64);
AntenaSerial.flush();
long tf = micros();
AntenaSerial.flush();
Serial.print(tf-ti);Serial.write('\t');

ti = micros();
SDSerial.write(&buff[0], 64);
SDSerial.flush();
tf = micros();
Serial.println(tf-ti);

According to the table from the Open log, at 115200 to write 64 bytes (in truth correspoding to 640 bits), it should take 5.568ms so, it is not far either from the new results
image

Now the question is, what is safer in terms of data loss packets?
Use the flush and force the waiting time? Or just fill the buffer and let the interruptions send data?

Thanks to both!

That is a nice result. I was expecting more overhead. Perhaps there was something else going on in the first test.

When you use the flush() function, data is still transmitted in a interrupt. The flush() just waits until the buffer is empty. The timing and the pace of outputting data and the interrupts, everything is still the same.

Data does not get lost when sending, it get lost when receiving.
I (almost) never use the flush() function. There is often no advantage.

Thanks for clarifying

If you try to send more data than will fit in the buffer, the Serial function will not return until space becomes available in the buffer, so you do not lose any data. The delay caused by this action may cause problems if your code has very tight timing requirements.

My tutorial on Arduino Serial I/O for the Real World covers this in detail, including how to add a non-blocking output buffer.
Also see use of the loopTimer for timing the loop( )