This is actually a bug in the bootloader.
I can't say how happy I am that you found it! I (probably) never would have figured out that r1 is zeroed out on power-up but not by a hardware reset. (I feel that it must be documented somewhere, but I haven't seen any Atmel AVR chip references other than doc8271.)
Anyhow, here's what I did:
I downloaded the optiboot source from http://code.google.com/p/optiboot/
. At the very beginning of main() in optiboot.c there are these lines:
// After the zero init loop, this is the first code to run.
// This code makes the following assumptions:
// No interrupts will execute
// SP points to RAMEND
// r1 contains zero
// If not, uncomment the following instructions:
SP=RAMEND; // This is done by hardware reset
// asm volatile ("clr __zero_reg__");
I uncommented the cli()
line and the asm
line. Since cli() is defined in the avr interrupt.h header, I added the following right after the #include <avr/pgmspace.h>
Did "make atmega328" and burned the loader into UNO and other boards.
Now I observe that none of the "UNO breaker" programs in this thread seen ti be causing problems. (Whew.)
Tested with UNO as well as with Duemilanove and other FTDI-interface '328P boards on Centos 5.5 Linux and Windows XP workstations.
Get the source tree from http://code.google.com/p/optiboot/source/checkout
the zip file. This is important!
With avr-gcc Version 4.3.4, the code size was too large until I modified the LDFLAGS line in the Makefile as follows:
# Original LDFLAGs resulted in code size greater than 512 bytes
# with avr-gcc version 4.3.4
# Added -nostdlib to make it fit
#override LDFLAGS = -Wl,$(LDSECTION) -Wl,--relax -nostartfiles -Wl,--gc-sections
override LDFLAGS = -Wl,$(LDSECTION) -Wl,--relax -nostartfiles -Wl,--gc-sections -nostdlib