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.

This entry was posted in atmega. Bookmark the permalink.

34 Responses to Setting fuse-bits on Atmel Atmega8 AVR

  1. anon says:

    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. k man says:

    Good explanation but how to write hfuse bit?

  3. louic says:

    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. AL says:

    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. AL says:

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

  6. AL says:

    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. louic says:

    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. AL says:

    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. AL says:

    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. louic says:

    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. ReLe says:

    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. louic says:

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

  13. Bill says:

    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. louic says:

    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. Marius says:

    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. louic says:

    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. Pingback: Programming Arduino with Arduino « Wire Jungle

  18. kim says:

    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.

  19. 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

  20. louic says:

    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.

  21. Pingback: Can 89S programmed using USBasp? - Page 5

  22. vishnu says:

    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

  23. vishnu says:

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

  24. louic says:

    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.

  25. thanks louic says:

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

  26. Sandhan Sarma says:

    I had the following problem with my newly purchased atmega8 when i was testing it with usbasp and avrdude. Each time i entered " avrdude -p m8 -c usbasp -n "
    just test the hardware and software i got the following error
    "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."

  27. Sandhan Sarma says:

    I had three new atmega8 mcus, and all of them had the same problem.

  28. soham says:

    What should i do if i am using a 12MHz oscillator?

  29. Martin says:

    Hi,

    what happens when is CKOPT = 1 and is used 16 MHz crystal? I set CKOPT = 1 (seller recommended in a manual) on development kit, where is used 16MHz and this seems, that ATmega32 working correct.

    Thank you

  30. louic says:

    Interesting question! I don't know.

    The datasheet says:

    ... the maximum frequency is 8MHz with CKOPT unprogrammed and 16MHz with
    CKOPT programmed. C1 and C2 should always be equal for both crystals and resonators.

    Unprogrammed here means "1" and programmed "0", so according to the datasheet when CKOPT=1 the maximum frequency is 8 MHz. I don't know what happens if you try CKOPT=1 with higher frequencies, but would be happy to hear from someone who tried this out (and measured what happens to the clock frequency of the chip).

  31. Pinaki Sekhar Gupta says:

    I'm new to AVR world and I just started learning Arduino. Raw AVR codes are still 'All Chinese' to me. So I'm asking a silly question.
    I actually damaged an ATMEGA328-PU (non-pico) uc, trying to install the bootloader for ATMEGA328P-PU (pico power) while I was setting up my stand-alone ATMEGA328-PU uc on a breadboard, supply voltage fed was also wrong, nearly 6V. I used an external crystal oscillator of 16MHz with two 22pF ceramic disc caps. Now the chip is not responding, I'm getting several error messages from AVRDUDE such as invalid device signature, not getting sync and even Programmer not Responding like errors. I use my Arduino Uno R3 Board (China clone) as ISP and nothing else, the programmer at that time was this UNO R3, protocol for UNO R3 as ICSP in AVRDUDE is stk500v1. Since I damaged one ATMEGA328-PU I had to buy another one ATMEGA328-PU. None of them are pico-power and have a different fuse bits than ATMEGA328P-PU (pico).
    With the second chip I bought I did create a BAT file as:

    @echo off
    set path="C:\Program Files (x86)\Arduino\hardware\tools\avr\bin";%path%;
    avrdude -c stk500v1 -p m328 -P COM3 -b 19200 -U lfuse:w:0xFF:m -U hfuse:w:0xDE:m -U efuse:w:0x05:m
    @echo on
    cmd

    Then added a few line to the file "C:\Program Files (x86)\Arduino\hardware\arduino\avr\boards.txt" as:

    ############################################################## Modified Version for Low cost ATMEGA328-PU ##############################################################

    uno328-pu.name=Arduino Uno R3 targetting ATMEGA328-PU (no-pico power) on Breadboard

    uno328-pu.vid.0=0x2341
    uno328-pu.pid.0=0x0043
    uno328-pu.vid.1=0x2341
    uno328-pu.pid.1=0x0001
    uno328-pu.vid.2=0x2A03
    uno328-pu.pid.2=0x0043

    uno328-pu.upload.tool=avrdude
    uno328-pu.upload.protocol=arduino
    uno328-pu.upload.maximum_size=32256
    uno328-pu.upload.maximum_data_size=2048
    uno328-pu.upload.speed=115200

    uno328-pu.bootloader.tool=avrdude
    uno328-pu.bootloader.low_fuses=0xFF
    uno328-pu.bootloader.high_fuses=0xDE
    uno328-pu.bootloader.extended_fuses=0x05
    uno328-pu.bootloader.unlock_bits=0x3F
    uno328-pu.bootloader.lock_bits=0x0F
    uno328-pu.bootloader.path=optiboot
    uno328-pu.bootloader.file=optiboot/optiboot_atmega328.hex

    uno328-pu.build.mcu=atmega328
    uno328-pu.build.f_cpu=16000000L
    uno328-pu.build.board=AVR_UNO
    uno328-pu.build.core=arduino
    uno328-pu.build.variant=standard

    ##############################################################

    Copied "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" to "C:\Program Files (x86)\Arduino\hardware\tools\avr\bin".

    Then selected this board from the IDE and burnt the bootloader accordingly.
    Now everything seems fine and working as I desired.

    But how can I repair the damaged one?
    I could compile and verify your code with Arduino IDE.
    But I did not understand which pin of the working ATMEGA should be connected to which pin of the dead one?
    What does the following mean?
    DDRC = 0xFF; //Make Port C output values
    PORTC = 0x00; //Turn all output pins on port c off
    I wish to have my dead ATMEGA back (I bought each of them at Rs 150/-, nearly 2.4 USD),
    So I'm waiting for your help. Please..

  32. Jothi says:

    Iam facing a problem with ATMEGA 128. This controller was programmed with wrong fuse bits( all 0s) by mistake and from then the controller is locked and i could not even read signature through AVR programmer. So the controller was changed and with the new ATMEGA 128 on PCB also faces the same problem. i.e., am not able to read even signature. After that i changed even the crystal oscillator on PCB with new one (16MHz) thinking that this could solve the issue. Still facing same problem. Pls help

  33. preeti gupta says:

    wt if i am not using any external oscillator and while working with atmega16a microcontroller i was trying to set the oscillator frequency to 8 MHz and by mistake did the wrong fuse bit setting and now, rc=-1 , initialization failed is coming n my usbasp is not writing the program in atmega16. I would really appreciate if you let me know how to fix this issue of setting up of wrong fuse bits . Thanx in advance. I ll b waiting for ur response

  34. Adrian Olariu says:

    I am new to uC programming (I work with an atmega8 for 2 days now) and after I have managed to configure the Arduino Uno as a programmer for the M8 (using a 16mhz crystal and 2 x 22uF capactiros) and makeing my first LED blink (using the Atmel Studio IDE) I begin to mess around with the fusses using a fuse calculator and I have written by mistake the fuses to go with external clock (I wanted external crystal, but I wasn't paying attention). Thanks to this article, i have managed to set back the fuses by makeing my other Arduino (Chinese Atmega 2560) generate a signal (the clock) and the Uno(Original Arduino) as the programmer. Thank you so much.

Leave a Reply

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