Reflashing Arduino Uno's Bootloader
November 19, 2012
Reflashing the Arduino Uno’s Bootloader using another Uno
_If you just want the instructions, jump down below
I recently got an Arduino Uno from a friend (thanks Wei!) and have been happily playing with it. The first project we built was a jukebox. The songs can be typed as strings in the header file using the simple notations we developed, and a piezo would sound the notes with the correct pitch and rhythm. However, I found that we couldn’t really put lengthy songs in there, as the RAM of the beast was only 2K. Unfortunately, somewhere in trying to fit songs in and finding out how much RAM was free, the Arduino IDE spit out a dreaded error when I tried to upload (the exact bytes might differ):
avrdude: verification error, first mismatch at byte 0x0000
0x0c != 0x00
avrdude: verification error; content mismatch
It was uploading just fine up until then, so I tried disconnecting and reconnecting the USB cable. Didn’t work, so I figured the bootloader probably got corrupted. After a couple days of restlessly pining for a working Arduino, my friend came by with two more Arduinos. Didn’t really make me feel any better, haha. I missed my first. Being the poor grad student that I am, I didn’t want to shell out $20 to buy a programmer (of the hardware kind) or purchase a new chip ($5 + a few days of waiting). So being the engineer that I am, I searched for other ways to reflash the chip.
Fortunately for me, I came across these directions from SparkFun, which informed me that I could use another working Arduino as the ISP. So when Wei came by Saturday evening, we decided to give it a shot. I built the circuit using some bare steel wire that I had (bad practice, but Fry’s was closed so I couldn’t get jumper cables, and I didn’t have any insulated wires or wire-strippers), while he researched what needed to be done in software. We were all set, and then we tried uploading. Didn’t work.
Then we found similar directions from arduino.cc. The wiring was certainly easier, and it was written by the Arduino guys. What could go wrong? Turns out this:
avrdude: stk500_paged_write(): (a) protocol error, expect=0x14, resp=0x64
avrdude: stk500_cmd(): programmer is out of sync
or this:
avrdude: stk500_getparm(): (a) protocol error, expect=0x14, resp=0x14
avrdude: stk500_getparm(): (a) protocol error, expect=0x14, resp=0x01
avrdude: stk500_initialize(): (a) protocol error, expect=0x14, resp=0x10
avrdude: initialization failed, rc=-1
Double check connections and try again, or use -F to override
this check.
avrdude: stk500_disable(): unknown response=0x12
For the longest time, we thought it was a baud rate problem. But we played with the baud rates in arduino/hardware/arduino/programmers.txt
and in Serial.begin()
of the ArduinoISP sketch, changed the delay in heartbeat()
in the ArduinoISP sketch, tried different versions of the sketch that came with different versions of the IDE (0022, 0023 come to mind), attempting to upload different .hex files from the IDE, adding a resistor between 5V and GND, adding a capacitor between RESET and GND, and probably a few other tips. A few hours later, it still hadn’t worked. We scoured the web for tips, scraped forums for comments, but there seemed to be no solution that worked. Granted, it was like two in the morning, so our analytical minds weren’t working so well. But all our errors fell into the categories of programmer is out of sync
, protocol error
, programmer not responding
, not in sync
, and compile errors on older versions of ArduinoISP sketches that we didn’t feel like debugging.
Around 2:30 AM, as Wei was leaving, I found this. By then, I figured it had something to do with the RESET signal. From what I gleaned (and it still seems like magic to me; I’m just making a best guess here), the Arduino RESET was being triggered whenever the computer tried to open the COM port, and the computer was trying to write right after it opened the COM port. So there’s a mismatch between what was expected and what the board’s response was. So mcnewton’s solution of using gdb
to pause execution after the function open
is called really helped. However, using his method, I was only able to set the fuses, and not actually upload the .hex. When I tried to, it seemed to work until the point the flash was being written. At around 98%, it said:
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.13s
avrdude: Device signature = 0x1e950f
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "optiboot_atmega328.hex"
avrdude: input file optiboot_atmega328.hex auto detected as Intel Hex
avrdude: writing flash (32768 bytes):
Writing | ################################################# | 98% 0.20s
avrdude: stk500_paged_write(): (a) protocol error, expect=0x14, resp=0x64
avrdude: stk500_cmd(): programmer is out of sync
After a few more tries, I went to bed exhausted around 3:30 AM. I came back from church today (now yesterday) and rediscovered the first comment here. Yup. Add -vvvv
to the avrdude
command to slow down that write (I suspect it works now that I got past the first hurdle with gdb
). I’m guessing there’s another reset around that point?
Anyhow, my little Arduino has been peacefully blinking on and off for the last 12 hours. It’s about time we sign off.
Complete Instructions
Disclaimer: follow at your own risk. You have been warned.
- Get Arduino 1.0.2 from here, and upload the ArduinoISP example (without changes) to a working Arduino Uno board. Baud rate should stay at 19200 in both Serial.begin and in programmers.txt. Make sure Tools \> Board (should be Arduino Uno) and Tools \> Serial Port are set correctly.
- Wire the two boards according to this. It should be okay to wire while the first Arduino is plugged in. Just plug in the 5V connection last. Capacitor between RESET and GND and resistor between 5V and GND are probably optional. I didn’t really notice any difference in error messages whether I had them in or not. I just kept them in, using 330 Ω and 100 µF.
- Reset the fuses
- At the shell prompt, type (without line break):
gdb -args avrdude -P COM_PORT -b 19200 -c stk500v1 -p m328p -v -e -U efuse:w:0x05:m -U hfuse:w:0xD6:m -U lfuse:w:0xFF:m
- In the first prompt in
gdb
, typebreak open
- At the next prompt, type
run
- At the next prompt, type
cont
- At the next prompt, type
next
- At this point, you should see your programmer board flash some LEDs
- At the next prompt, type
delete breakpoints 1
- At the next prompt, type
cont
. The fuse-setting should be successful.
- At the shell prompt, type (without line break):
- Upload the .hex file (make sure your .hex file is in the directory in which you’re executing this)
- At the shell prompt, type (without line break):
gdb -args avrdude -P COM_PORT -b 19200 -c stk500v1 -p m328p -vvvv -e -U flash:w:optiboot_atmega328.hex -U lock:w:0x0F:m
- Follow the same commands as above:
break open
,run
,cont
,next
,delete breakpoints 1
,cont
.
- At the shell prompt, type (without line break):