Setting fuse-bits on Atmel Atmega8 AVR

The second thing most people do when they start programming microcontrollers is to try and use an external crystal as a clock source. And many beginners start by setting the wrong fuse bits, so that the AVR expects an external clock signal instead of a crystal, thereby locking themselves out. This may be a problem, because the fuse-bits cannot be changed back without actually connecting the external clock source the microcontroller expects.
I am no exception, and started out by setting the wrong fuse bits. It was however very educational, and I will describe below how I created the problem, and how I corrected it.

The first thing to do, is to read the current fuse bytes:

louic@carbon ~/myavr $ avrdude -c myavr -p m8 -P /dev/parport0 -U hfuse:r:high.bin:b -U lfuse:r:low.bin:b
 
avrdude: AVR device initialized and ready to accept instructions
 
Reading | ################################################## | 100% 0.00s
 
avrdude: Device signature = 0x1e9307
avrdude: reading hfuse memory:
 
Reading | ################################################## | 100% 0.00s
 
avrdude: writing output file "high.bin"
avrdude: reading lfuse memory:
 
Reading | ################################################## | 100% 0.00s
 
avrdude: writing output file "low.bin"
 
avrdude: safemode: Fuses OK
 
avrdude done.  Thank you.
 
louic@carbon ~/myavr $ cat high.bin low.bin
0b11011001
0b11100001

In hex, these values are 0xD9 for the high fuse byte, and 0xE1 for the low byte, the factory settings of my brand new atmaga8. My programmer board has a 3.6864MHz quartz crystal that is connected to the XTAL inputs, and the atmega8 datasheet will tell us the appropriate fuse bit settings.

Now that I write this I do not see why I made a mistake setting the fuse bits, but a fact is that I told the AVR that I have an external clock source by setting the low byte to 0b11100111. The following error message was the result when I tried to upload a program to the microcontroller:

louic@carbon ~/myavr $ avrdude -p m8 -c myavr -P /dev/parport0 -U flash:w:prog.elf:r
avr-objcopy: --change-section-lma .eeprom=0x0000000000000000 never used
 
avrdude: AVR device not responding
avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.
 
avrdude done.  Thank you.

You're welcome. After a long search on the internet (and some experimenting) I succesfully used a second microcontroller as an external clock source, so that the controller with the wrong fuse-bits could be reprogrammed.

First, I removed the external crystal and the two capacitors. Then I connected one of the output pins of a second microcontroller to the XTAL1 pin of the "broken" atmega8. Nothing should be connected to XTAL2. Both of the microcontrollers have to be connected with their GND pin to the same ground, and to a power source of course. The working microcontroller should be programmed to send pulses with regular intervals on its output pin. The program shown below is fine:

#include <avr/io.h>           //Required to use assembler commands
#define F_CPU 1000000UL  // set the internal clock speed of 1 MHz
#include <util/delay.h>
 
int main()
{
 
    DDRC = 0xFF;            //Make Port C output values
    PORTC = 0x00;           //Turn all output pins on port c off
 
    while(1) {
        PORTC = 0x01;
        _delay_ms(5);     //This delay is probably not necessary
        PORTC = 0x00;
        _delay_ms(5);     //This delay is probably not necessary either
    }
 
}

With this setup, the Atmega8 with the wrong fuse bits may be programmed as usual, because the other AVR now serves as external clock source. I started out by setting the default fusebits back:

louic@carbon ~/myavr $ avrdude -c myavr -p m8 -P /dev/parport0 -U lfuse:w:0xE1:m -U hfuse:w:0xD9:m
 
avrdude: AVR device initialized and ready to accept instructions
 
Reading | ################################################## | 100% 0.00s
 
avrdude: Device signature = 0x1e9307
avrdude: reading input file "0xE1"
avrdude: writing lfuse (1 bytes):
 
Writing |                                                    | 0% 0.00s ***failed;
Writing | ################################################## | 100% 0.02s
 
avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xE1:
avrdude: load data lfuse data from input file 0xE1:
avrdude: input file 0xE1 contains 1 bytes
avrdude: reading on-chip lfuse data:
 
Reading | ################################################## | 100% 0.00s
 
avrdude: verifying ...
avrdude: verification error, first mismatch at byte 0x0000
0xe1 != 0x00
avrdude: verification error; content mismatch
 
avrdude: safemode: lfuse changed! Was e1, and is now 0
Would you like this fuse to be changed back? [y/n] y
avrdude: safemode: and is now rescued
avrdude: safemode: hfuse changed! Was d9, and is now 0
Would you like this fuse to be changed back? [y/n] y
avrdude: safemode: and is now rescued
avrdude: safemode: Fuses OK
 
avrdude done.  Thank you.

Because of all the error messages, I tried again, just to check if the fuse-bits would be unchanged this time (they should be, because I just set them):

louic@carbon ~/myavr $ avrdude -c myavr -p m8 -P /dev/parport0 -U lfuse:w:0xE1:m -U hfuse:w:0xD9:m
 
avrdude: AVR device initialized and ready to accept instructions
 
Reading | ################################################## | 100% 0.00s
 
avrdude: Device signature = 0x1e9307
avrdude: reading input file "0xE1"
avrdude: writing lfuse (1 bytes):
 
Writing | ################################################## | 100% 0.00s
 
avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xE1:
avrdude: load data lfuse data from input file 0xE1:
avrdude: input file 0xE1 contains 1 bytes
avrdude: reading on-chip lfuse data:
 
Reading | ################################################## | 100% 0.00s
 
avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "0xD9"
avrdude: writing hfuse (1 bytes):
 
Writing | ################################################## | 100% 0.00s
 
avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xD9:
avrdude: load data hfuse data from input file 0xD9:
avrdude: input file 0xD9 contains 1 bytes
avrdude: reading on-chip hfuse data:
 
Reading | ################################################## | 100% 0.00s
 
avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
 
avrdude: safemode: Fuses OK
 
avrdude done.  Thank you.

To set the correct fuse bits, I referred to the atmega8 datasheet again.

  • For an external crystal, CKSEL3..0 should be set to a value between 1111 and 1010
  • For a 3-8MHz crystal, CKSEL3..1 has to be set to 111
  • And for any crystal, CKSEL0 = 1
  • To make sure it would work, I chose the longest startup time (65ms): SUT1..0 = 11
  • Because the crystal has a speed lower than 8MHz, CKOPT=0 and CKOPT=1 should both work, see the comments on this blog post. I chose to set CKOPT=1

Knowing this, one wonders what the values of the high and low fusebytes have to be. The answer is again found in the datasheet:

hfuse:
bit             7     6     5     4      3       2       1       0
name     RSTDISBL WDTON SPIEN CKOPT EESAVE BOOTSZ1 BOOTSZ0 BOOTRST
 
lfuse:
bit             7     6     5     4      3       2       1       0
name     BODLEVEL BODEN  SUT1  SUT0 CKSEL3  CKSEL2  CKSEL1  CKSEL0

Combining this with the information above, we now know that we want to program the following bits:

hfuse: 0b11011001 (0xD9), so no change here
lfuse: 0b11111111 (0xFF)

And the avrdude command becomes:

avrdude -c myavr -p m8 -P /dev/parport0 -U lfuse:w:0xFF:m

After having put back the crystal and capacitors, I set the fuse-bits to their correct values, and the microcontroller worked perfectly again, now using the speed of the external crystal.

Category(s): atmega

23 Responses to Setting fuse-bits on Atmel Atmega8 AVR

  1. Thank you for an informative article. I was stuck on a similar problem and this helped me to fix it. Just one thing, the hfuse and lfuse are Bytes, not bits. Search in the datasheet for high byte and low byte to find the relevant tables. I was a bit confused when I couldnt find reference to hfuse and lfuse bytes in the datasheet. Thanks.

  2. Good explanation but how to write hfuse bit?

  3. Thanks for your comments. Of course you are right anon, what a stupid mistake. I corrected it.

    And k man:
    just replace lfuse by hfuse in the avrdude command.

  4. Hi,

    I have encountered the same problem and still have the problem after following your instructions above.

    1. I AVRDude on the below after I pressed 'y'. This when I entered the avrdude command 'avrdude -p m8 -P lpt1 -c stk200 -U lfuse:w:0xE1:m -F'

    avrdude: safemode: lfuse changed! Was e1, and is now 0
    Would you like this fuse to be changed back? [y/n] y

    2. Could you kindly post the complete avrdude commands that you used? Your posting seems to get truncated at the right.

    3. I saw your comment: "just replace lfuse by hfuse in the avrdude command." So, not sure if your text has been updated.

    Thanks.

  5. Oops never mind about item (3) from my previous post. :-)

  6. A couple more things: a) my problem is so bad that avrdude can't recognize my "broken" atmega8's device id anymore. It's now of 0xffffff :-( b) I use WINDOWS with parallel programmer.

  7. Hi AL,

    In response to your questions:

    In short:
    - your avrdude command looks good
    - check the (hardware) connections
    - maybe you set the RSTDISBL bit also, and not just the clocksource bits. This is more difficult to solve, and I don't remember how to do it. I believe you need a special kind of programmer for it (the board, not the person :) ).

    1) That is normal and not a problem. I describe it in my post above as well (look at the command-line output blocks)
    2) The full command to SET the both the lfuse and hfuse byte is:

    avrdude -c myavr -p m8 -P /dev/parport0 -U lfuse:w:0xE1:m -U hfuse:w:0xD9:m

    There should have been horizontal scrollbars though. What web-browser are you using?

    a) It depends on when exactly you get the error message. It may be normal and does not necessarily mean that the microcontroller is broken. Check if all the connections (hardware) are good and if the microcontroller is correctly placed in the socket (if you use one).
    b) It should work under windows as well

    Good luck, and have fun!

  8. Thanks for the answers louic...For item 2), worry I didn't see the scrollbars :-) It was 2AM when I wrote the questions. Will try what you suggested and will post if all ok. Thanks again.

  9. I found the solution. Please see http://forum.sparkfun.com/viewtopic.php?t=12789. Note that the solution is only for ATMEGA8.

    Here is the solution: Just put a 1nF cap from OSC1 to ground, and a 370 ohm resistor from OSC1 to Vcc.

    No need to use another ATMEGA8.

  10. Good that you solved the problem, and thanks for letting me know how you solved if. I always like to learn new things :). I will keep an eye on the site you mentioned as well, to see if there are any other interesting replies.
    You had probably set the fuse bits to a different value, so that it does not expect the external clock. If I have some more time I will definetly do some experimenting with both methods.

    cheers!

  11. After just going trough this same thing my self. (who reads manuals before hand anyways :D) I must tell the way i solved the external clock source problem. I downloaded a wave generator program to my pc which i found from this article : http://www.edn.com/article/CA46108.html Then i connected left channel + to the xtal1 pin and left channel ground to ground. I set the freq to 19khz and used -B 250 setting in avrdude.

  12. Thanks ReLe for posting your solution, it is an interesting one ;)

  13. Thank you so much. I'm not sure how long it would have taken me to figure this out by myself. This info is scattered across 2 or 3 different places! You have saved me many hours (days?) of problems.

  14. I'm glad you like it. If I remember correctly it took me about two days to figure it all out when I started playing with microcontrollers. :)

  15. Hello,

    "Because the crystal has a speed lower than 8MHz, CKOPT=0"

    I found on atmega's datasheet, that if crystal freq is lower than 8Mhz, the CKOPT=1

    I'm I right? because you also wrote that high byte left unchanged (that's CKOPT=1) :)

  16. Hi Marius,

    The Atmega 8 manual says:

    "For resonators, the maximum frequency is 8 MHz with CKOPT unprogrammed and 16 MHz with CKOPT programmed."

    unprogrammed = 1
    programmed = 0

    So with CKOPT = 1, the maximum frequency is 8 MHz, but CKOPT = 0 will also work. The opposite is not true however: if the crystal resonates between 8-16 MHz, CKOPT has to be set to 0.

    So if the crystal frequency is not higher than 8MHz, the following quote from the manual can help you decide how to set CKOPT.

    "When CKOPT is programmed, the Oscillator output will oscillate a full rail-to-rail swing on the output. This mode is suitable when operating in a very noisy environment or when the output from XTAL2 drives a second clock buffer. This mode has a wide frequency range.

    When CKOPT is unprogrammed, the Oscillator has a smaller output swing. This reduces power consumption considerably. This mode has a limited frequency range and it cannot be used to drive other clock buffers."

    So yes, you are right that your quote from my weblog is very confusing. I changed it. Thank you for your comment!

  17. Hello everybody
    I also build Atmega48 based external generator
    it is generating signal.
    But when I return crashed atmega48 or atmega8
    Stk200, PonyProg doesn’t recognize my uC.
    uCs still not working.

    taqee ahmed says:

    thanks for informative article

    some people doesnot have very good understanding of English

    can you publish the circuit diagram for removing fuses of broken atmega with working atmega

    thanking you

    Bye

  18. Hi taqee ahmed,

    It is a good idea to include such a picture, but unfortunately I do not have a lot of time at the moment. But let me try to describe it more clearly:

    • For the working atmega that will send the pulses: The easiest is to put this chip on your programmer board. Then connect PIN C0 to XTAL1 of the "broken" atmega.
    • For the broken atmega: All you need is power, ground, and reset connected, and the connection to XTAL1 as said above.

    I hope this helps. More details about connecting an atmega microcontroller can easily be found with google: search for "minimal atmega schematic" or something similar.

  19. hai am doing a project on avr.i am confused.i used extreme burner instead of avr dude
    1.will the fuse bits from frequency to frequency.if so what will be the fuse bits for 8,12,16 MHZ
    2.i checked my atmega8 by programming with test led program,that was ok.i set the fuse bits for 16mhz as c9 and FF.then i erase the chip and burned my actual program.again i set the fuse bits will there be any problem.there was no response from my controller after then

  20. can you tell what all precautions should be taken while setting fuse bits in extreme burner

  21. Hi vishnu,

    I don't understand your first question. All I can say about precautions is to read the datasheet and think carefully before you change fuse bits. If you know what you are doing, and double check the values before you change them there will not be a problem.

    thanks louic says:

    this article really saved me .........
    i thought my atmega16 won't work again
    thanks man

2 Responses in other blogs/articles

  1. [...] Introduction and some do’s and don’ts: here [...]

  2. [...] i cannot write them directly in digit.. so i searched for check box values.. as per this site: Setting fuse-bits on Atmel Atmega8 AVR at Louic's blog – about science and stuff the pattern is hfuse: bit 7 6 5 4 3 2 1 0 name RSTDISBL WDTON SPIEN CKOPT EESAVE BOOTSZ1 BOOTSZ0 [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

 

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>