Only 'problem' with the 328P UART is that it can stall execution of the rest of the application when the software TX buffer is full. If there are 64 bytes (default limit) in the TX buffer and you try to put another 64 (or whatever) in there, your code will stall for 64 character (or whatever) transmit times (1 ms per character at 9600 baud).
You should not end up with your timing depending on that because it can vary based on what you print (e.g. the number of digits of a byte / int / long). You can check how much space there is in the TX buffer using Serial.availableForWrite and base the decision to print/write (or not) on that.
If you're tired of writing tons of #ifdefs and Serial.prints every time you want to debug something, you could use these macros: GitHub - tttapa/Arduino-Debugging: A simple collection of macros for easy debugging on the Arduino platform
I use them all the time when working on larger projects, because they show the filename, function name and line number, and I can enable and disable all debug statements with a menu option in the Arduino IDE. Especially DEBUGVAL is really useful to inspect the values of multiple variables.
lesept: @sterretje: do you know how an ESP32 would behave in this context?
It blocks until there's space in the buffer again. I don't think it uses any flow control, so it won't block if you don't open the USB port.
It's just a personal preference, because sometimes I'm working on projects with both C and C++ header files, so it makes it clear which files are C and which are C++. (Just like .C and .CPP files.)
sterretje:
Only 'problem' with the 328P UART is that it can stall execution of the rest of the application when the software TX buffer is full. If there are 64 bytes (default limit) in the TX buffer and you try to put another 64 (or whatever) in there, your code will stall for 64 character (or whatever) transmit times (1 ms per character at 9600 baud).
You should not end up with your timing depending on that because it can vary based on what you print (e.g. the number of digits of a byte / int / long). You can check how much space there is in the TX buffer using Serial.availableForWrite and base the decision to print/write (or not) on that.
on mcu without native usb or flow control the Serial output of MCU is send no matter if something is connected
As an alternative , I have used a spare digital input to turn printing on/off in the software - can be useful to check problems with sensors etc to just turn printing on by inserting a link on your board .
I tested it using this code, and that seems to confirm it: it slows down from 128 bytes onwards:
#include <array>
#include <soc/uart_struct.h>
void setup() {
std::array<uint8_t, 257> buffer;
size_t lengths[] = {
126, 127, 128, 129,
};
buffer.fill('.');
Serial.begin(1200);
for (size_t len : lengths) {
Serial.print("Sending ");
Serial.print(len);
Serial.println(" bytes");
Serial.flush();
delay(100);
auto start = micros();
Serial.write(buffer.begin(), len);
auto end = micros();
auto availableForWrite = Serial.availableForWrite();
auto cnt = UART0.status.txfifo_cnt;
Serial.println();
Serial.print("Duration: ");
Serial.println(end - start);
Serial.print("Available for write: ");
Serial.println(availableForWrite);
Serial.print("UART0.status.txfifo_cnt: ");
Serial.println(cnt);
Serial.println();
}
}
void loop() {}
Sending 126 bytes
...
Duration: 25
Available for write: 1
UART0.status.txfifo_cnt: 126
Sending 127 bytes
...
Duration: 23
Available for write: 0
UART0.status.txfifo_cnt: 127
Sending 128 bytes
...
Duration: 113894
Available for write: 0
UART0.status.txfifo_cnt: 127
Sending 129 bytes
...
Duration: 117726
Available for write: 0
UART0.status.txfifo_cnt: 127
Correct. You don’t really need to flush, though. (It was for a specific application where the code went into an infinite loop on fatal errors, disabling interrupts. I wanted to get the debug information out before that happened.)
Do you think I should delete it from the code on GitHub?
PieterP:
Do you think I should delete it from the code on GitHub?
Reasonable arguments can be made in either direction. I don’t have a skin in the game (I would just update my copy to reflect what I need; Github makes that easy). I’m not the right person to answer.
I assume, at this point in history, most people expect Serial output to be non-blocking. It could be argued most people would be “astonished” when they first use Arduino-Debugging.
But, it could also be argued that most debugging output libraries block by default1 to ensure the output is synchronized with the rest of the system. It could be argued that most people would be “astonished” if Arduino-Debugging does not synchronize output.
I will offer this: A note in README.md stating which you choose strikes me as a good addition.
It was for a specific application where the code went into an infinite loop on fatal errors, disabling interrupts. I wanted to get the debug information out before that happened.
Add a DEBUGFLUSH for such situations?
Or a DEBUGMARK that outputs a “marker” (e.g. horizontal line) then calls flush?
1 I do not know that to be true. It is meant as an example.