# What “external” source can change a General Purpose Working Register if no interrupts are enabled?

I have a 8-bit ATmega processor (from the 48/88/168 family) and encounter a strange behavior: after a brown-out reset, sometimes (around 20%-30%) it fails to start after a short brown-out. It always starts correctly after a longer power-down.

I narrowed down the problem to the part of the startup which is generated by the compiler and has the role of clearing the RAM:

;CLEAR SRAM
LDI  R24,LOW(__CLEAR_SRAM_SIZE)
LDI  R25,HIGH(__CLEAR_SRAM_SIZE)
LDI  R26,LOW(__SRAM_START)
LDI  R27,HIGH(__SRAM_START)
__CLEAR_SRAM:
ST   X+,R30
SBIW R24,1
BRNE __CLEAR_SRAM


This code segment does the following: it counts down the word in R24,R25, meanwhile incrementing the X Register (R26,R27) and writing R30 (which is zero) to the location pointed by the X Register. This clears the RAM until R24,R25 reaches zero. However, the code is stuck in this loop. Whenever I halt the progam, it stops on one of the last 3 lines in the above code, with seemingly random values in R24 and R25. Interestingly, if I run it step by step, it correctly decrements R24, and when it reaches zero, it correctly sets R24 to 0xFF and decrements R25. When I set both to a very small number they correctly reach zero and the loop is exited correctly, but only when running it step-by step. It seems that something writes some values into R24 or R25, but I have interrupts disabled, and I even set breakpoints to the interrupt registers to make sure and they are never triggered.

When this test is running (stuck in the loop) the power is stable, so there is no brownout while in this loop.

The watchdog is disabled while we are in this loop.

Does anyone have any ideas what to look for?

"The watchdog is disabled while we are in this loop." - So you provided code that disables the watchdog? Note that it will not be disabled automatically by a normal reset.

The ATmega1284P datasheet quotes for example:

Note: If the Watchdog is accidentally enabled, for example by a runaway pointer or brown-out condition, the device will be reset and the Watchdog Timer will stay enabled. If the code is not set up to handle the Watchdog, this might lead to an eternal loop of time-out resets.

Then there's the WDTON fuse which forces the WDT to be always on. You may want to check on that.

Oh, and by the way: You did enable the brown-out detector of the µC, didn't you? - Otherwise, upon a brown-out condition, anything could happen to the internal state of the µC.

• Yes, there is code for the disabling of the Watchdog, and it's part of the auto-generated "startup asm" part generated by the compiler. Should I post the full auto-generated startup code? It never failed me in over a dozen projects. – vsz Jun 11 '13 at 9:40
• Which compiler/library are you using? I'm pretty sure avr-gcc with the avr-libc does not touch the WDT in its initialization code. – JimmyB Jun 11 '13 at 9:44
• cvavr. It disables the global interrupt flag, places the interrupt vectors, disables the watchdog, clears the working registers, clears the ram, and does with the global variable initialization, before the user-created code. – vsz Jun 11 '13 at 9:46
• By the way, (if the debugger is working properly, which I assume it does, because it can read and write properly), the Watchdog is indeed inactive (so no matter what might have went wrong in other parts of the code, I can see it's inactive while in this loop) – vsz Jun 11 '13 at 9:48
• Not necessarily so: The WDT is stopped while debugging, reference here. Whether this fact is also reflected in the WDTCR I cannot tell. – JimmyB Jun 11 '13 at 9:51