is there any downside to leaving Serial.print in release code?

i've been putting stuff like this in my code

#ifdef DEBUG
  Serial.println("Setup done");
#endif

but not sure its necessary or even a good idea. i guess the timing will change if i don't define DEBUG and could result in unintended consequences.

so, in a release environment where no USB serial is connected, is there any difference to when one is connected?

No.

Depends on the processor. You can bring a 32U4 based board to a near grinding halt when disconnecting from the USB.

Nano, 328P

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.

@sterretje: do you know how an ESP32 would behave in this context?

lesept:
@sterretje: do you know how an ESP32 would behave in this context?

I'm sorry, I'm not familiar with ESP. You will have to look at the source for the serial port in the ESP core functions.

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.

Pieter

PieterP, that's very cool, i'll put it in my code, thanks

so i guess the answer to my question is i probably should patch out the serial writes when USB not connected

i don't rely on the timing, everything works in an interrupt callback anyhow, but i don;t want any unexpected holdups

BTW, what's a .hpp file?

steveh2112:
BTW, what's a .hpp file?

A Header file for C Plus Plus.

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

Juraj:
on mcu without native usb or flow control the Serial output of MCU is send no matter if something is connected

True, but it will still block if you try to send more than 64 bytes at once.

PieterP:
True, but it will still block if you try to send more than 64 bytes at once.

it will block only until bytes are send. OP has in the post that he is afraid of changed timing by removing the Serial prints

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 .

Thanks Pieter, do you know the size of the buffer for the ESP32?

Thank you PieterP for sharing.

sterretje:
You can bring a 32U4 based board to a near grinding halt when disconnecting from the USB.

"Disconnected" or "disconnecting"?

PieterP:
If you're tired of writing tons of #ifdefs and Serial.prints every time you want to debug something, you could use these macros:

A word of caution: some / most / all of the macros are blocking. That will effect timing.

larryd:
Thank you PieterP for sharing.

+1!

lesept:
Thanks Pieter, do you know the size of the buffer for the ESP32?

127 Bytes:
It blocks when there are 127 bytes in the buffer: arduino-esp32/esp32-hal-uart.c at 70656aa129701114c1af05c70b8cba93846be960 · espressif/arduino-esp32 · GitHub.

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.

There is this (and similar)…

https://www.google.com/search?q=software+development+least+surprise

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.