Serial statements ignored when begin method commented out?

I have a question on usage of serial code for troubleshooting. Typically I would comment/uncomment individual Serial.print statements for debugging, but the other day I accidentally commented out the Serial.begin statement without commenting out the Serial.print statements. I would have expected the compiler to throw an error on this, but it did not; furthermore after uploading the code it ran fine and there were no delays typically induced by executing Serial.print.

So, my question is - can I avoid commenting out my serial debug code in a sketch and just comment out the initial Serial.begin function? Any downside?

FYI - I did notice the sketch doesn't get any smaller when removing Serial.begin, so it appears the compiler is not removing the statements before uploading.

willnue

I would not do that (commenting Serial.begin)

Syntax-wise there is no problem without Serial.begin. You are able to use the Serial object without begin but you won't get anything out of print. Plus the print is compiled in so is the begin so you don't save anything. Someone mentioned assert for commenting out debug signals so google it :)

It is probably still sending stuff out at the default baud rate that was last set by the compiler. So I don't know what advantage that has over ignoring the serial output.

Don’t folks use # IFDEF somehow & set a flag at compile time, if the flag is set then code later on bypasses the Serial.prints?
Something along those lines?
I just go the cruder route and take out Serial.prints as I get things working.

If there is a best practice for globally setting the flag that would be great to know. I typically just use IF (debug var) THEN… Serial.print…, which may be fine for most things, but as I am working a project where I need every ounce of speed I am wondering if this “feature” I found might be useful? As far as removing the comments I think commenting them out is better - I assume the compiler removes them from the binary, so you would still gain the space vs. deleting them.

Here is a sample sketch to illustrate the difference. Run it once as is and the LED should be lit for approx. 4 seconds at a time. Run it again with Serial.begin(115200) commented out and the LED will now be lit for approx 1 second at a time.

Try it:

// Sample to test Serial statements without enabling Serial port.
// Run this sample first as is, then run it with Serial.begin commented out.

int c=0; //Counter

void setup() {                
   // initialize the digital pin as an output.
   // Pin 13 has an LED connected on most Arduino boards:
   pinMode(13, OUTPUT);  

  // Run this sample first as is, then run it with Serial.begin commented out.
  Serial.begin(115200);   
}
 
void loop() {  
  
  //Visual feedback
  digitalWrite(13, HIGH);   // set the LED on
  
  //Run a loop and print the results to the serial port
  for (c=0; c < 5000; c++) {
    //debug statements
    Serial.print("C =");
    Serial.print(c);  
    Serial.println();
  }

  //Visual feedback
  digitalWrite(13, LOW);    // set the LED off
  delay(250);               // wait for a bit
}

Let me know what you think.

Liudr - I tried searching for the following etc…, but didn’t come up with anything. Can you find a link?
http://www.google.com/#q=arduino+assert+comment+debug

Thanks,

willnue

Duh - I think I just answered my own question!

Run my code a 3rd time and comment out both Serial.begin and the 3 Serial.begin statements then see how long the LED is lit - if you can even see it light up!

So, it must be defaulting to some baud rate above 115,200 and still sending out the serial data to null/nowhere etc…

So, in the end… just don’t do it!

I really think the compiler should flag it.

willnue

Here’s some code I found by searching for “ifdef serial”, I think it gives you the idea.

#include <Messenger.h>
#include <FiniteStateMachine.h>
//#include <MemoryFree.h>

//#define DEBUG

#define MILLIS_IN_MINUTE 60000
#define MOTOR_PIN 3

(deleted a bunch of variable definitions …

FSM sm = FSM(on); // start in the off state
Messenger message = Messenger();
int curVal = 0;

void setup() {
Serial.begin(38400);
#ifdef DEBUG
Serial.println(“Init…”);
#endif
randomSeed(analogRead(0));
message.attach(messageCompleted);
#ifdef DEBUG
Serial.println(“End Init…”);
#endif
}

You can also use serial.end and then use the pins as something else; and then turn it back on again. How is the compiler to know when when serial.prints should be legit or not?

CrossRoads, Thanks for the example.

After checking out the Atmel docs http://support.atmel.no/knowledgebase/avrstudiohelp/mergedProjects/AVRASM/Html/directives.html#IFDEF it looks like IFDEF holds the code inside the block from the compiler, which in turn makes the binary smaller and doesn't check the debug state at runtime - exactly what I was looking for.

It took me a bit of time to find the docs, since it seems like there is little/no mention of it in the Arduino docs etc... I understand why they might want to keep the directives abstracted, but in this case I think it is an excellent tool to use for debugging.

As far as the compiler goes - I was thinking something like a warning that you are calling the serial object, but haven't defined a target for it. ie..

Warning: Serial.method called but never used.

I'm not that familiar with the inner workings of the ATMEGA. I'm assuming since the compiler allows it there must be an implied/default serial output somewhere?

thanks again, willnue

willnue: Warning: Serial.method called but never used.

You used it ... you did Serial.print. The compiler can't know what order functions are supposed to be called in.

And if it warned for every function (or method) that is declared but never used most compiles would be littered with warnings.

Yes, too bad we can't get a warning for = vs == compier ought to read our minds and know what we want!

The compiler can warn you about that, unfortunately you can't change the warning levels in the shipped IDE.

I guess my assumption was there would be no reason to utilize the serial object without the Serial.begin() method being called. If this is the case order of execution doesn't matter. I see it as similar to a variable being used, but not being declared. Since it appears the ATMEGA is still executing the Serial.print statements if this condition exists it's robbing the MCU of cycles that may not be apparent to the developer.

FYI - For my warning example, what I meant was something similar to: Warning: the variable is declared but never used. ie. http://msdn.microsoft.com/en-us/library/yswdac5w(v=VS.90).aspx

Late night...

My $0.02 anyway...

willnue

I guess my assumption was there would be no reason to utilize the serial object without the Serial.begin() method being called

Bad assumption - All the "begin" method does is set the baud rate and enable the receiver and transmitters and the receive interrupt. Apart from the receiver interrupt, the others are still set to whatever the bootloader set them to, so receive may not work, but I'd probably place a small bet on transmit working, again, at the bootloader's default rate.

Awol, I would agree with you if I saw output from the serial port via FTDI etc..., but I don't - try my sample and you will see. I'm wondering "where" the serial output goes? From my testing it does appear that some baud rate is being set that is higher than 115.2k - maybe 230.4k or 250k (max?)?

As far as the bootloader goes I guess that makes sense since it still needs to be ready for communication for re-programming etc...

No big deal, just curious. In the end IFDEF seems to be the way to handle serial debug code.

thanks for all the help. willnue

As far as the bootloader goes I guess that makes sense since it still needs to be ready for communication for re-programming

I don't understand what you mean by this - the bootloader sets up the serial interface after a reset, and (I'm almost certain) just leaves the registers as they were when it calls the user's program - I can't believe it would go to the effort of resetting them.

(I'm a long way from source or an Arduino - I'll give it a shot later)

Awol, I think you know more about it than I do ;)

When you said you thought the bootloader would set the serial comms to some default at startup I was agreeing thinking it would need to do this to be ready to communicate via serial with a host for re-programming (from the IDE etc..). It was kinda of a "ah-ha" moment since I had not been thinking about the bootloader at all. I didn't mean to imply it was resetting anything after running.

Hope that clears it up.

willnue

but I'd probably place a small bet on transmit working, again, at the bootloader's default rate.

better be a small bet :)

I tested the sketch below with the standard baudrates, 115200..2400 the Serial Monitor did not receive a bit

the tx led didn't blink either..

So commenting Serial.begin() looks like a DEBUG off option, however all the print and receive statements are still executed, takes time, uses memory etc. A serial.available() might block eternaly. So the behavior of the sketch becomes unpredictable at best and is really different from using #ifdef ..

void setup()  
{
  Serial.println("Hello World");
}

void loop(){}

willnue:
it looks like IFDEF holds the code inside the block from the compiler, which in turn makes the binary smaller and doesn’t check the debug state at runtime - exactly what I was looking for.

The gcc compiler is intelligent enough to remove any code blocks which are guaranteed never to be used. So in the following example,
** **#define DEBUG 0** **
has exactly the same effect as commenting out the debugging lines. The compiler can also recognise and remove conditional statements which are always true, so writing
** **#define DEBUG 1** **
will have the effect of deleting the
** **if (DEBUG)** **
check. In either case, the
** **if** **
statements will never actually be compiled into the binary and executed.

#include <Streaming.h>
#define DEBUG 0

void setup() {
  if (DEBUG) Serial.begin(19200);
  pinMode(13,OUTPUT);
}

void loop() {
  for (int n=0; n<10; n++) {
    digitalWrite(13,HIGH); delay(10);
    digitalWrite(13,LOW); delay(100);
    if (DEBUG) Serial << "n is equal to " << n;
  }  
}

AWOL:

I guess my assumption was there would be no reason to utilize the serial object without the Serial.begin() method being called

Bad assumption - All the “begin” method does is set the baud rate and enable the receiver and transmitters and the receive interrupt.
Apart from the receiver interrupt, the others are still set to whatever the bootloader set them to, so receive may not work, but I’d probably place a small bet on transmit working, again, at the bootloader’s default rate.

Right on! I was working on this over a different issue so I dug the code out. Setting baud rate register (correct my term) is all Serial.begin does:

void HardwareSerial::begin(long baud)
{
  uint16_t baud_setting;
  bool use_u2x = true;

#if F_CPU == 16000000UL
  // hardcoded exception for compatibility with the bootloader shipped
  // with the Duemilanove and previous boards and the firmware on the 8U2
  // on the Uno and Mega 2560.
  if (baud == 57600) {
    use_u2x = false;
  }
#endif
  
  if (use_u2x) {
    *_ucsra = 1 << _u2x;
    baud_setting = (F_CPU / 4 / baud - 1) / 2;
  } else {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);
}