0

I have a good experience of the real(/critical)time world, but I'm new with Arduino. I noticed that Serial.write is synchronous. If the buffer size is >64 (the USART size) it lasts the time of the physical transmission minus 64char. It is obvious with simple tests as : Serial.write (char64) comes back in 1 millisec if the USART buffeur is empty and comes back in 64*10/baudrate if USART buffer is full. Does anyone has written an asynchronous Serial.write? If not who can help me to write it? That is to say have the docs on the USART, the interrupts and soon? Basically, the point is to fill the buffer, get an interrupt when it is free to fill it again.

Thanks for contacting me.

  • 1
    you can test before write with availableForWrite() – Juraj Nov 11 '18 at 16:19
6

Until the buffer is full, Serial.write is asynchronous. You just have to avoid filling the buffer up.

Fortunately, there is the function Serial.availableForWrite() which returns the number of bytes available in the buffer. You can use that to see if there's room in the buffer for what you want to send, and if there is then send it (i.e., just placing it in the buffer).

By re-writing the UART handing to call your own interrupt routine to send a byte as and when needed you are basically doing exactly the same as the Arduino's HardwareSerial class is doing - just with your own buffer instead of the one in the HardwareSerial class.

There is no hardware buffer in the Arduino. It only has a single byte shift register for sending UART data. Any buffering has to be done in software, so either you implement that yourself, or use the existing buffering, or only ever generate and send one byte at a time, which is fairly useless.

If you really want to re-write it then all the information you need is in the datasheet for the MCU on your chosen development board.


The terms "synchronous" and "asynchronous" when applied to situations like this are better replaced with "blocking" and "non-blocking", since "synchronous" and "asynchronous" when applied to serial communications imply different styles of data transmission, not software implementation.

  • Thank you for your answer, very clear and very helpful. Based on it I will use both of your suggestions : 1 Test first before write. 2 As the buffer size is software, extend it from 64 to 85 to be able to send a NMEA0183 phrase at once, and only wait if the next comes to soon. I agree synchronous/asynchronous can be miss-understood because of data transmission protocol. But you get it! – Olivier Nov 13 '18 at 10:44
  • I checked, the HardwareSerial.h starts with #if !defined(SERIAL_TX_BUFFER_SIZE) that is to say it can be defined outside before (just what I need). But where shall I place my #define SERIAL_TX_BUFFER_SIZE xx ? Is it in the Arduino Sketch itself or in some .h file? If this size is >256 a special mode is used. Does it improve performances or not? I guess each Serialx (on Mega) has its private TX and RX buffers. Have all the TX buffers the same size? Or shall I adjust each? Thank you in advance. – Olivier Nov 13 '18 at 12:34
  • I believe they are all the same size. You want to place the define at the top of the HardwareSerial.h file so that HardwareSerial.cpp etc pick it up. – Majenko Nov 13 '18 at 12:46
0

Thanks to Majenko I have the pieces of a gloabal solution. I just summaries and share : The Serial.availableForWrite() gives the available space left free in the Serial TX buffer. It your string is shorter the Serial.write will be passing, if not blocking (until enought free space). You can adjust the size of this TX buffer (default is 64) in HardwareSerial.h. Take care buffersize larger than 256 (255 available) result in a longer processing time for Serial.write. If you have Serial, Serial1, ... the size will be the same for both and ofcourse the buffers are seperated. I noticed thas Serial.flush is blocking long (80ms). This is to take into account for time critical issues. Enjoy

  • If you change the TX buffer size, please note that it should be a power of two. Otherwise the processing time for HardwareSerial::write() and the TX ISR will be much longer. The performance penalty for sizes larger than 256 is small in comparison. – Edgar Bonet Nov 20 '18 at 14:48
  • Thank you for this Edgar. I've been throught the multiple layers of C++ code for the Serial.xx down to the HardwareSerial.xx. I wanted to implement a very simple and quick SerialTXClear to clear out the TX buffer queue, but I feel I'll miss layer. Where shall I find the doc on theses multiple layers? – Olivier Nov 22 '18 at 15:19
  • I am not aware of any software layer other than the files you mentioned. – Edgar Bonet Nov 22 '18 at 18:20

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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