Feb
24
2007

The tale of AVRdude, ATmega168 and extended fuses bits

One thing my mentor always told me was that AVRdude behaves weirdly when it comes to writing fuses to an ATmega168.
Guess which µC I’ve rendered unusable this week trying to write fuses with AVRdude?
If your answer was “peanut butter jelly time” you might have some mental issues, while if it was “ATmega168″ you are right.
There’s more:
not content with having broken a loose one, I decided I had to try the one on the Arduino BT which in the end got to the same end.
The bad aspect of the latter is that the chip is SMD and can’t be replaced easily (by me).

You might be wondering what happened then.
Well, besides trying to have 2 ATmega128 end up the same way, I started wondering why I couldn’t write the efuse properly in AVRdude.

It was so easy on AVRStudio.
I couldn’t write the default fuses values for an arduino with a 168 on.
Being them 0xf8, 0xdf, 0xff (in order for efuse, hfuse, lfuse), I could never succeed writing the efuse.
AVRdude returns "***failed" on every attempt.
The first thing you try then is to write sort of random values to the hfuse and lfuse.
If you’re lucky you’re not touching the RSTDISBL (very easy to affect if you program the hfuse with 0x0f fuse bit or other stuff related to the external/internal clock), then good for you (all I can say about it).

This tought me a good lesson: READ THE DATASHEET BEFORE DOING STUPID THINGS.

Gianluca from the Arduino group told me: “they should release a special license to enable people to touch fuses”, and he’s totally right. I’m just recalling I don’t have one.
But my motto is “fail to learn”, so I’m not sorry that I’ve failed, as I’ve learned a valuable lesson.

Let’s go on.
Reading the datasheet for the ATmega168, I found out that the fuse bytes were a bit strange.
They were 8bit bytes for the hfuse and lfuse, while only the lowest 3 bits were significant for the efuse.

efuse_168_table.jpg

I had to see it again and again to realize there was a connection between this and the maximum value AVRdude allowed me to write on the efuse: 0x7.
If you write this as a binary you get
0 0 0 0 0 1 1 1
and this means that we have a maximum number of 3 bits to set.

It was time to start digging into the avrdude.conf file and see what’s there for the ATmega168.
Here it is with 2 examples from the hfuse and the efuse


memory "hfuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0",
"x x x x x x x x o o o o o o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0",
"x x x x x x x x i i i i i i i i";
;


memory "efuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0",
"x x x x x x x x x x x x x o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
"x x x x x x x x x x x x x i i i";
;

This might look like impossible to read to many newbies (which I’m one of), but paying a little attention to the read and write values and compare the hfuse with the efuse ones, you’ll realize that the amount of cryptic x, o, i you see is the visual key.

Easily explained you can assume

  • x: not used
  • i: input
  • o: output

and you can see that input and output changed based on read/write operations.
All of the above explains why AVRdude fails if you try to write a bigger amount of bits to a field that only expects 3 of them.

AVRStudio works differently, in the sense that it presents you with a panel full of checkboxes, and then deals with what you can set or not based on the cpu selection in the first page.
AVRStudio will then remap whatever value to a 3 bits one, and convert, for instance, 0xff to 0x7.

Now you can choose two ways:
you can follow the right path of reading datasheets and manually adjust that 0xf8 to 0x0, or you can hack the avrdude.conf to allow for the full 8bit byte writing, but I have no idea what will happen then.
I’d go for the former.
[updated thanks to sam's comment. Of course 1 1 1 1 1 0 0 0 (0xf8) removing the first 5 bits becomes x x x x x 0 0 0 (0x0)]

Always hoping this reading will be useful to someone one day, I get back to my daily job: the geek.

Written by Massimo Banzi in: Arduino, hacks, software |

5 Comments »

  • i -always- set my fuses in avrstudio first (since its the atmel standard) and then read them by hand from avrdude and then use those in the Makefile. its just too much effort do figure out the bits otherwise

    Comment | 24 February 2007
  • sam

    Setting the efuse to 0×7 in AVRDUDE causes one big problem:

    The processor never leaves the bootloader, so the downloaded program never actually runs. Using a 0×0 efuse setting sets the bootsize to 1024 words (max) and also enables the Reset Vector. Works like a charm.

    Personally, I’ve been very successful using the following:

    avrdude -p m168 -b 115200 -P usb -c avrispmkII -V -e -U lock:w:0×3F:m -U hfuse:w:0xDF:m -U lfuse:w:0xFF:m -U efuse:w:0×0:m

    avrdude -p m168 -b 115200 -P usb -c avrispmkII -V -D -U flash:w:ATmegaBOOT_168.hex

    avrdude -p m168 -b 115200 -P usb -c avrispmkII -V -U lock:w:0xCF:m

    Comment | 25 February 2007
  • thank you for the errata corrige, sam.
    just updated.
    I got confused by the previous example I brought, in which I demonstrated that 0xff becomes 0×7.

    I’ve also found a funny thing with avrdude and m128, in which there’s an issue in verifying the fuses.
    I’ll be glad to post about it later.

    ciao.ubi

    Comment | 25 February 2007
  • Also note that avrdude has a similar problem with the lock byte. If you write a 0xff to the lock byte (which is actually a bit silly, since the only way to set a lock bit to 1 is by erasing the chip, which sets the byte to 0xff), avrdude will read back a 0×3f from the byte as it fills the unused high two bits with 0’s. Similarly, when locking, you should use 0×0f instead of 0xcf. At least that was my experience.

    Comment | 18 July 2007
  • woz

    awesome sam, helped me out heaps…

    avrdude -p m168 -P /dev/parport0 -c dapa -V -e -U lock:w:0×3F:m -U hfuse:w:0xDF:m -U lfuse:w:0xFF:m -U efuse:w:0xF8:m

    avrdude -p m168 -P /dev/parport0 -c dapa -V -D -U flash:w:ATmegaBOOT_168_ng.hex

    avrdude -p m168 -P /dev/parport0 -c dapa -V -U lock:w:0xCF:m

    Comment | 16 February 2009

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress | © 2008 Tinker.it! Limited | London & Milan