I have a kind of theoretical question. Let's have an Arduino Uno connected through USB that does a lot of Serial.print-ing. Then I disconnect it and I don't see anything on the Serial monitor, but the Arduino is still working. I can judge by the blinking lamps and so on.

Now I see that all printing goes through HardwareSerial::write from the Arduino core. There is this statement:

  // If the output buffer is full, there's nothing for it other than to 
  // wait for the interrupt handler to empty it a bit
  // ???: return 0 here instead?
  while (i == _tx_buffer->tail)

It means that if the output buffer is full, the Serial.print will hang there eternally. However this doesn't happen. I guess somebody is consuming the data and to be more precise in ISR(USART_UDRE_vect). It seems as the only place where within interrupt _tx_buffer->tail can be changed. Otherwise the code would loop endlessly in HardwareSerial::write. This interrupt USART_UDRE_vect should be raised only when the Data Register is empty.

My question is - who is consuming the sent data? Is that done by some USART_to_USB drivers? Or am I missing some part of the picture?

Regards, Boyan

  • Ignacio's answer is half right. | Right: Either the UART bridge is consuming the data - presumably into its own buffer or there is no "flow control" & the Arduino is sending "blind". | Partially wrong inasmuch as: If it can't YOU care as your code would hang. || It doesn't so it can. || If you want to stop it from hanging even if the buffer is full you could do a non hanging test and do a check using millis() N ms later where N is somewhat less than a character time (or longer if you don't mind the buffer partially emptying before you restart. Feb 27 '15 at 2:34

atmega 328p datasheet, section 20.6.3:

The Data Register Empty (UDREn) Flag indicates whether the transmit buffer is ready to receive new data. This bit is set when the transmit buffer is empty, and cleared when the transmit buffer contains data to be transmitted that has not yet been moved into the Shift Register


When interrupt-driven data transmission is used, the Data Register Empty interrupt routine must either write new data to UDRn in order to clear UDREn or disable the Data Register Empty interrupt, otherwise a new interrupt will occur once the interrupt routine terminates.

the USART Data Register Empty vector is run when the hardware for USART serial has taken the byte in the register and sent it, not when a receiving device has polled and "taken" it. Once copied into the shift register and sent out of the chip nothing knows if there was another device to "hear" it or not. Some systems may have hardware flow control and wait for a CTS (clear to send) signal on a different wire, but the arduino does not.

You may also notice that if interrupts are not currently enabled (preventing USART_UDRE_vect from ever occuring) the HardwareSerial::write routine will manually poll the correct condition and run the interrupt handler when appropriate to cycle data through and prevent a deadlock.

  • 1
    Brett - It's apparent that you'll be aware of the following - mainly for completeness". I'm not aware of the specific implementation here and I'm sure that what you say applies, but in general a UART can if desired implement the equivalent of RTS/CTS (DTR/...) so that a hearer is needed. Feb 27 '15 at 2:31

The USB-UART bridge is, if it can. And if it can't, no one cares. A UART is asynchronous, hence it doesn't care if anyone consumes it; as long as it has sent the data, that's all it cares about. There can be additional checks to see if the other side is able to receive data, but that is not implemented on the Uno.

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.