Sunday, February 10, 2013

The importance of brown-out detection

The batteries expired in one of the AuroraWatchNet test magnetometers this week. I was expecting that to happen since the magnetometer wasn't operating in its low-power mode and the battery voltage from the two 1.5V alkaline cells had been hovering around 2V for some time. The Atmel ATmega1284P microcontroller is actually powered at 3.3V using a boost power supply. What I didn't expect was for the system to not start after replacing the battery. I could tell xboot was working since the LED flashed 3 times as usual after the reset button was pressed. After that the LED stayed on but nothing else happened, not even the start-up debug messages from the serial port. I guessed the flash program memory had somehow got corrupted.

I used the AVR Dragon to extract the contents of the flash memory (avrdude -P usb -c dragon_jtag -p atmega1284p -U flash:r:flash.img:r) and compared it against the saved raw image file using the linux split and cmp commands. Sure enough, three pages of flash memory were set to 0xFF, probably from some erroneous page clear operation. Brown-out detection was disabled by the fuse settings to save power. Big mistake! What I think happened was as the voltage dipped below its valid range the microcontroller started executing random commands, including 3 SPM page clears, one of which was the first page of flash which holds the interrupt vector table. Valid execution was doomed.

What I should have done was to enable brown-out detection in the fuses, 2.7V seems the most appropriate setting for an 8MHz clock and 3.3V operation. To save power during sleeping the brown-out detection can be disabled with a call to sleep_bod_disable(). Lesson learned!

1 comment: