I finally got around to reading Akiba’s excellent blog article entitled Intermittent Bugs and How to Strike Fear In the Heart of Experienced Devs, and this statement jumped out at me:
It just so happens that print statements in the Arduino library use an interrupt service routine and since the AVR doesn’t allow nested interrupts, any interrupt must wait until the current interrupt is finished before being serviced.
In short, one should never issue a print statement from within an interrupt service routine on the Arduino platform. This implementation was the root cause of a rather nasty hanging bug in Akiba’s ChibiArduino product, and it was a tricky one to track down.
I’ve been working with Arduino for a few years now, and time and time again I’ve run into odd problems which were ultimately traced down to serial.print(). Timing glitches, random lockups, and other bizarre behaviors were all ultimately caused by relying on print statements to provide status during development. Serial buffer overflows are a huge issue – it’s really easy to cram more data into the UART than the receiving end is able to handle, especially at low baud rates. The default 9600 baud setting certainly exacerbates this issue; bumping this up to 115200 often avoids the lockup-causing buffer overflow but can introduce other odd timing issues.
As Akiba alludes to in the aforementioned article, it is often safer to toggle or pulse a debug pin to externally monitor events. This technique is very helpful for measuring time consumption for a block of code – toggle the pin high at the beginning of the block of code to measure (preferably by directly manipulating port register bits – Arduino’s digitalOut() is horrifically inefficient) and toggle it low at the end of the block. Monitor this pin on your oscilloscope to measure the time.
A couple of pearls of wisdom to pass along:
- Keep ISR implementations as short as possible.
- Do not perform expensive operations (eg, logging, printing, etc) within an ISR.
- If you find your Arduino code hanging randomly, print statements may be to blame.
- If you do use Arduino Serial.print(), set the baud rate as high as possible.
Recently I’ve found myself working less and less with the Arduino environment and moving more towards direct AVR development. Arduino is a double-edged sword – lots of libraries and community support, but the indirection and abstractions offered by the platform often come at a high price.