Burning an Arduino's bootloader
Some long time ago, I bought some cheap Arduino LilyPad clones from Amazon. I spent weeks trying to get them work, but was heavily frustrated.
No matter what I did, avrdude refused to upload my sketch:
avrdude: Send: 0   avrdude: Send: 0   avrdude: Send: 0   avrdude: ser_recv(): programmer is not responding avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
Somehow I found out that I was able to upload my sketch without using the bootloader with an ISP (I used an Arduino Uno).
That was still not satisfying.
Here is how I debugged:
- Check that the FTDI is working. Connect the FTDI’s RX to its TX (nothing else!) and send data over the serial console. You should receive what you sent.
- Check that the Arduino is working. In my case, an LED started to blink as soon as I connected GND to GND and VCC to 3V/5V (depending on the board).
- Check that the Arduino is receiving data. Connect GND and VCC, then connect the FTDI’s TX to the pin of the Arduino that you think was RX. Now send random data to the Arduino (for example with
cat /dev/random > /dev/ttyUSB0), the RX LED on the Arduino should blink. In my case, it didn’t. It turns out that the manufacturer swapped RX and TX or that I am misreading the datasheet.
- Now try to look at the verbose output while uploading. You can also try to push the reset button.
- Verify that the Arduino itself is working, but the bootloader isn’t. Attach an ISP and upload a sketch without the bootloader (see above), or just click “burn bootloader” in the IDE.
So I knew that something was wrong with the bootloader. What next?
I had a hard time figuring that out, but in the end it turned out to be quite simple:
“Unlock” the bootloader’s fuses. This is a protection mechanism to prevent you from changing the bootloader accidentally. On my laptop and with the LilyPad, the command was
/usr/share/arduino/hardware/tools/avr/bin/avrdude -C/usr/share/arduino/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -cstk500v1 -P/dev/ttyUSB0 -b19200 -e -Ulock:w:0x3F:m -Uefuse:w:0x05:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m. I simply copied it from the Arduino IDE’s verbose output after I clicked “burn bootloader”.
Find the right bootloader. I guessed. On the LilyPad’s Atmel is written “MEGA328P”, so I could be sure that I needed some kind of bootloader for the atmega328. In
/usr/share/arduino/hardware/arduino/avr/bootloaders, I looked for hex files with “328” in their names:
find -iname "*atmega328*.hex"
./optiboot/optiboot_atmega328.hex ./optiboot/optiboot_atmega328-Mini.hex ./bt/ATmegaBOOT_168_atmega328_bt.hex ./atmega/ATmegaBOOT_168_atmega328.hex ./atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex
I found five different bootloaders. It couldn’t be the third, because usually “bt” is an abbreviation of “bluetooth” and my LilyPad did not have built-in bluetooth. It wasn’t some kind of “Mini” variant, either. The Arduino IDE itself burns the “_pro_8MHz” hex file, as can be seen in its output. So I tried the optiboot bootloader. I copied the IDE’s command and replaced the path with optiboot’s:
/usr/share/arduino/hardware/tools/avr/bin/avrdude -C/usr/share/arduino/hardware/tools/avr/etc/avrdude.conf -v -patmega328p -cstk500v1 -P/dev/ttyUSB0 -b19200 -Uflash:w:/usr/share/arduino/hardware/arduino/avr/bootloaders/optiboot/optiboot_atmega328.hex:i -Ulock:w:0x0F:
Again, I tried uploading the sketch. Bummer, “programmer is not responding” again. So optiboot obviously does not work. I tried the last bootloader - unlock the fuses, burn the bootloader, upload a sketch - aaaaaaand it worked! I was freaking out. It seems that the clone does not ship the “pro_8MHz” variant.