This post isn't about the usual kind of dragon (if there even is a "usual" kind). The AVR Dragon is a gizmo made by Atmel, useful for programming their AVR line of microcontrollers. It's relatively cheap (around US$50 at the time of this writing) and does many useful things. The specific application I'm going to talk about here is using it to "fix" parts when you've set the fuses in such a way that said parts won't talk to simpler programmers. Details after the jump.

Why Get a Dragon?

There are lots of AVR programmers out there. If you're just starting out, there are cheaper options that work well (like the USBtinyISP from Lady Ada). If you're averse to soldering, one of the Arduino variants (with on-board programming hardware) may be of more use.

However, the Dragon gives you a lot of flexibility for not much more money -- if you're willing to put up with some extra hassle. Here are some of the features that set it apart from other low-end programmers:

  • high-voltage serial programming, so you can program low-pin-count AVR chips
  • debugWIRE and JTAG support for in-circuit debugging
  • emulation support for devices with 32KB flash or less
  • parallel programming, so you can "unbrick" chips with mis-set fuse bits

It supports the same six-wire ISP as most of the cheap options. The "avrdude" utility supports most of the Dragon modes, too.

Initial Build

The Dragon does not arrive ready for use. They give you a flexible prototyping area and a place where you can solder headers. There are lots of approaches that work. My choice, with which I've had good results, is to add pin headers to the HV Prog connector area and the adjacent 40-pin "EXPAND" connector, then add a 40pin ZIF socket in the prototyping area. This lets me use the Dragon for any supported combination of target and programming mode, merely by adding jumpers in the right place.

The image to the right (from the Atmel website) shows the end result:

The disadvantage of this approach is that changing jumper configuration is somewhat time-consuming and potentially error-prone. There are some clever alternative possibilities, though.

Jumpers: Lazy Method

Jumpers set for parallel programming of ATmega328P

Most of the approaches I've seen to jumper wiring on the Dragon involve ribbon cables with compression-fit connectors on one end and a bunch of individual single-pin sockets on the other. That works, but involves fabricating several such cables. At my local electronics store, I noticed the SchmartBOARD jumpers. These are nice stranded 3" wires with a pin socket on each end, fitted with shrink-fit tubing for insulation and strain relief. Build quality seems good, and at about US$5 for a 10-pack (with a strip of 20 pin headers I'm sure you'll find a use for) they're reasonably cheap.

If you're doing parallel programming, you'll want to get two packs. The 3" version has worked out fine for all the configurations I've used so far, though you may need a handful of longer jumpers if you're programming 40-pin microcontrollers.

Programming Modes

There are several different ways for the Dragon to talk to your microcontroller. One of the easiest and most familiar is the six-wire ISP (in-system programming) bus. That's a popular method as it requires relatively few pins, and lets you program the microcontroller without removing it from the circuit.

You can't always use ISP, though. One reason is that some low-pin-count parts like the ATtiny11 don't support it. Another is that ISP only works with certain combinations of fuse bit settings. Since you can set the fuse bits to arbitrary values using ISP (even values that make no sense), you can "brick" a microcontroller by applying fuse settings that don't work and which you cannot change via ISP. Here are some specific examples:

  • ISP depends on the reset pin acting as a reset rather than a general-purpose I/O. If you enable (set to zero) the RSTDISBL bit, ISP won't work.
  • Turning off (setting to one) the serial programming enable (SPIEN) bit will stop ISP working.
  • Setting the clock bits to something that prevents the microcontroller from clocking reliably (e.g., telling it to use an external crystal when there isn't one) will make ISP not work.

In some cases there are workarounds. For example, if you've turned on RSTDISBL, you can still get the chip to reset by applying +12V to the reset pin. If you've done something silly with the clock, you can sometimes get around it by applying an appropriate square wave (possibly generated by another AVR microcontroller) to the clock input and/or messing with the timing settings on your programmer.

PP jumpers for ATmega48(P)/88(P)/168(P)/328P

However, the only completely general-purpose remedy is using either HVSP (high-voltage serial programming) or PP (parallel programming), depending on the specific microcontroller you're trying to fix.

For the popular ATmega168 and ATmega328P parts, parallel programming is what you want. Start by looking at the AVR Dragon online help, specifically the list of supported devices. Find your device and the required programming mode (one of HVSP or PP). Look at the connection sheet (linked from the list of supported devices) and set the jumpers accordingly.

The image to the right (from the Atmel help website) shows the correct jumper settings for doing parallel programming on the ATmegaXX8(P) parts (where XX is 4, 8, 16 or 32).

Fixing Fuses

Once you have the jumpers set up and target microcontroller in the ZIF socket, actually fixing the fuses is quite simple. Just use the command-line "avrdude" utility with the options "-c dragon_pp -P usb" and program as usual. (Other programming software may work also. The Dragon is supported by Atmel's AVR Studio software, though I have not used it myself.)

For help finding the correct fuse values, the Engbedded fuse calculator is quite useful. It even gives you the correct avrdude command-line arguments to cut and paste. Note, however, that unused/non-existent bits (like bits 3..7 of the extended byte on the ATmega328P) read back as all-one on the Dragon, while other programmers read them back as all-zero.

This means (again using the ATmega328P extended bits as an example), if you want to set the BOD level to 4.3v (BODLEVEL=100)  you'll get a verification error if you try to use '-U efuse:w:0x03:m'. To avoid that, use '-U efuse:w:0xfb:m' instead. (The fuse gets set right either way. The latter method just avoids a misleading error report.)

If you do run into the verification error, answer "no" when avrdude offers to restore the old setting; if you say "yes" it'll hang until interrupted.