Serial out buffer

My question is about a 8)serial out:grin: buffer.

I am implementing a SW for my University that requires serial port to be sending and receiving messages all the time, very fast.
The main routine takes like 100 ms and cannot wait for a complete message completion.

Is it possible to send messages to a write buffer, something like read buffer, that will be administred with Arduino to send bytes for me, when serial TX port is available automatically?

Thank you very much!!!! :slight_smile:

Arduino 1.0 will have buffered serial output. Beta 3 was just released.

Note that buffering will NOT speed up serial output if you are sending data "all the time, very fast."

I can't figure out why more people don't understand that. If your serial port runs 9600bps, you can't send any faster than 9600bps...

While an app can't go faster than 9600, if that is the set baud rate, it can go slower.

Apps that have a lot of CPU or I/O overhead formatting output can be improved with buffered serial output.

The app can format the next message while previous output is sent by an ISR.

yes, if you send "less than a buffer worth of data, occasionally", then buffering can be a big help.
But that doesn't seem to be the case that people expect it to help...

I agree with westfw that serial output buffering doesn't help most applications. At least not the way most users expect.

In my opinion, forcing output buffers in Arduino 1.0 to be the same size as input buffers is a mistake. I would like an option to use unbuffered serial output.

Large serial input buffers can be very useful in apps like serial data loggers. This allows longer latency for writing to SD cards when logging at high baud rates.

fat16lib:
While an app can't go faster than 9600, if that is the set baud rate, it can go slower.

Apps that have a lot of CPU or I/O overhead formatting output can be improved with buffered serial output.

Only if you put in interrupt handling to send data in the background.

If you do that you run into multithreading problems...it all gets messy very quickly.

Arduino 1.0 beta does use interrupts for output and works fine. No multi-threading problems.

I don't think most Arduino programs need buffered output. I think it is a waste of RAM for most programs.

Not much point in buffered output if there is no flow control to keep it from going out once written to the UART.

CrossRoads:
Not much point in buffered output if there is no flow control to keep it from going out once written to the UART.

???
There won't be any kind of flow control on the interrupt driven buffered serial output in the new version. But it will keep the Serial output commands from being blocking commands, so the rest of the sketch can keep on keeping on while the buffer is emptied via the ISR.

Lefty

The 1.0 beta Serial works and is non-blocking as long as no more than 64 bytes are queued.

If Arduino was a multi-threaded system this could be a real win.

I have played with 1.0 and don't find programs that run faster due to output buffering.

Any one have a real world example where benchmarks show a big win?

fat16lib:
The 1.0 beta Serial works and is non-blocking as long as no more than 64 bytes are queued.

Well that's the problem, right there...

Any program which does a lot of serial output will fill the buffer up and then the buffer becomes useless. It achieves nothing.

The buffer helps with programs which send a byte occasionally and need to return instantly. For programs which are sending large amounts of data it makes virtually no difference.

The buffer helps with programs which send a byte occasionally and need to return instantly. For programs which are sending large amounts of data it makes virtually no difference.

I think you overstate the negative. It of course will help in some very common applications like sending short messages to a serial LCD display. And in cases where it doesn't help, it hurts performance no worst then what we have presently, always blocking, at of course with the cost of the additional buffer. I consider it a worthwhile incremental improvement, like so many added over the last 3 years.

Lefty

It is a big problem for some apps. If you log fast serial data to an SD, having a large input buffer can improve performance due to write latency for the SD. It avoids dropped data.

Now you are required to have a large useless output buffer when you increase the input buffer size.

I don't believe the LCD example without more info.

fat16lib:
It is a big problem for some apps. If you log fast serial data to an SD, having a large input buffer can improve performance due to write latency for the SD. It avoids dropped data.

Now you are required to have a large useless output buffer when you increase the input buffer size.

I don't believe the LCD example without more info.

Well complaining to me won't help you that's for sure. :wink:

Here is a link to the Arduino developers mailing list where they argue about and decide on what changes are and are not to be made to the IDE. http://arduino.cc/pipermail/developers_arduino.cc/

Lefty

Any one have a real world example where benchmarks show a big win?

The average data rate has to be lower than the serial data rate, and the size of data output "per call" has to be lower the the space available in the output buffer.

For example, a 64 byte buffer is a win if I send a 32byte message with a status update of my computations, once every second, at 19200bps. With buffering, the computations will run essentially continuously. Without, they'll be stalled waiting for the serial port. Of course, under those circumstances, you're not spending a lot of time doing output anyway...

The following sketch is an example. It runs about 250ms faster (out of about 20 seconds) in 1.0 than in 0022 (which is a bit odd, since I figure it ought to be running closer to 600ms faster (~30ms for each of ~20 lines printed.) I wonder what's going on?)

unsigned long counter;

void setup()
{
  Serial.begin(9600);
  counter = 0;
}

void loop() {
  counter++;
    if ((millis() % 1000) == 0) {
    Serial.print("Counter reached ");
    Serial.print(counter);
    Serial.print(" in time ");
    Serial.println(millis());
  }
  if (counter >= 500000) {
    Serial.print("\nCounter Completed at ");
    Serial.print(counter);
    Serial.print(" in time ");
    Serial.println(millis());
    while (1) ;  //stop
  }
}
if ((millis() % 1000) == 0) {

millis occasionally increments by 2.

retrolefty:

it hurts performance no worst then what we have presently, always blocking, at of course with the cost of the additional buffer.

When there's only 2K of RAM that cost might be too high.

The answer is to allow it to be customized - #define a size before you include the header file.

(Even worse I think is the problem that a 128 byte input buffer is currently allocated even if you only ever send data...)

westfw,

I think each 32 byte line takes about 15 ms at 19200 baud. With no buffering there is no blocking for the first two bytes so the difference should be for 30 bytes.

20 lines at 15 ms/line is 300 ms total.

That's close to your observed 250 ms.

Thanks for the example.

It only gains about 300 ms out of 20 seconds or about 1.5%.

(yeah, but it's running at 9600bps... And: here's the actual output without buffering. Each print implies that the initial printing (before the second call to millis()) takes nearly 30 ms (as expected.) And there are 21 of them, so that should be close to 600ms of just printing.)
Counter reached 1 in time 24
Counter reached 23839 in time 1029
Counter reached 47416 in time 2029
Counter reached 70968 in time 3028
Counter reached 94437 in time 4029
Counter reached 117989 in time 5029
Counter reached 141432 in time 6030
Counter reached 164851 in time 7029
Counter reached 188187 in time 8030
Counter reached 211739 in time 9030
Counter reached 235158 in time 10030
Counter reached 258576 in time 11030
Counter reached 281862 in time 12029
Counter reached 305280 in time 13030
Counter reached 328567 in time 14029
Counter reached 351878 in time 15030
Counter reached 375059 in time 16029
Counter reached 398585 in time 17030
Counter reached 422003 in time 18030
Counter reached 445397 in time 19030
Counter reached 468708 in time 20030
Counter reached 492101 in time 21029

Counter Completed at 500000 in time 21399
(with buffering, the code shows 1ms or less delay between the millis() calls.)