How to Use AVR Fuses – and Understanding What They Do

Fuse-Header

How to Use AVR Fuses – and Understanding What They Do

Avoid frustration and get over the fear with this quick guide to AVR Fuses.

If you’ve been working with AVR microcontrollers, it’s likely that you’ve come across references to Fuses, Fuse bits and Fuse bytes. When I first read about them I thought they sounded very primitive for something as sophisticated as a microcontroller. After researching them further I came to the conclusion that whoever had originally named these mechanisms “fuses” was hell-bent on causing general confusion! AVR Fuse Bytes are not that complicated, are very useful, and are not to be feared – but they should be treated with some respect. This post will make you comfortable enough to use fuses to get the most out of your microcontroller and will be focussing on the ATmega328P (the microcontroller from the Arduino UNO). It’s a little longer than usual, so grab a cup of coffee and let’s jump in!

What is an AVR Fuse Byte?

The trusty ATmega328 data sheet doesn’t tell us much about what fuse bytes are, so let’s start out with a layman’s explanation. The ATmega328 has a number of settings that the designers originally wanted to keep separated from the code executing on the microcontroller. These settings are contained in three fuse bytes: High, Low and Extended, and are designed to be configured using an external programmer. There are now ways to modify them through code (thanks to GCC), but it doesn’t make sense to alter certain of the settings through code.

What Settings do Fuse Bytes Control?

The three tables below set out the Fuse Bits for the ATmega328P. Take a quick look through them before continuing.

Extended Fuse Byte:

Bit Name Bit No Description Default
7 1
6 1
5 1
4 1
3 1
BODLEVEL2 2 Brown-out Detection trigger level 1 (unprogrammed)
BODLEVEL1 1 Brown-out Detection trigger level 1 (unprogrammed)
BODLEVEL0 0 Brown-out Detection trigger level 1 (unprogrammed)

 
High Fuse Byte:

Bit Name Bit No Description Default
RSTDISBL 7 External Reset Disable 1 (unprogrammed)
DWEN 6 debugWIRE Enable 1 (unprogrammed)
SPIEN 5 Enable Serial program and Data Downloading 0 (programmed)
WDTON 4 Watchdog Timer Always On 1 (unprogrammed)
EESAVE 3 EEPROM preserved through Chip Erase 1 (unprogrammed)
BOOTSZ1 2 Select Boot Size 0 (programmed)
BOOTSZ0 1 Select Boot Size 0 (programmed)
BOOTRST 0 Select Reset Vector 1 (unprogrammed)

 
Low Fuse Byte:

Bit Name Bit No Description Default
CKDIV8 7 Divide clock by 8 0 (programmed)
CKOUT 6 Clock output 1 (unprogrammed)
SUT1 5 Select start-up time 1 (unprogrammed)
SUT0 4 Select start-up time 0 (programmed)
CKSEL3 3 Select Clock source 0 (programmed)
CKSEL2 2 Select Clock source 0 (programmed)
CKSEL1 1 Select Clock source 1 (unprogrammed)
CKSEL0 0 Select Clock source 0 (programmed)

 

Now that you’ve studied those tables, are you feeling completely comfortable with fuses and ready to wrap this post up? Not very likely, if you’re anything like me! Even turning to the data sheet had me paging back-and-forth in an attempt to work out just what heck all these fuse bits meant. After working through all the descriptions, tables and cross-references, I finally realised that the only fuse byte I needed to really worry about (for my applications at least) was the Low Fuse Byte – this controls the clock speed and clock source of the microcontroller.

Something to bear in mind is that a value of “1” doesn’t mean the functionality is enabled, and a “0” doesn’t mean it’s disabled. That’s what the “programmed” and “unprogrammed” annotations mean in the table above.

Extended and High Fuse Bytes

The Extended Fuse Byte controls the voltage level that triggers Brown-Out Detection (BOD) reset. Brown Out Detection monitors the input (VCC) voltage levels to the microcontroller, and enters a reset-state if they drop below a certain level.

The High Fuse Byte contains setting that are relevant to programming and debugging your project. These are more advanced topics that aren’t really useful to a hobbyist or enthusiast, unless you’re looking at doing things like writing boot loaders or programmers. The SPIEN end DWEN bits are often used by programmers and debuggers – changing these yourself can make your chip unprogrammable. When in doubt, make sure that SPIEN is left as “0” as this allows you to programme you chip using an SPI programmer. The only bit you may use is the WDTON bit, which controls whether the watchdog timer is permanently on or not (it can be overridden in software though).

The Low Fuse Byte

Even though the descriptions for the Low Fuse Byte are pretty self-explanatory, they don’t give much information about what values you should be programming into the individual bits. This is where a Fuse Calculator comes into play, and is something that I rely on exclusively (the data sheet is just not as easy to use). I really like the one from Engbedded: you choose the functionality you want set and it spits out a fuse value at the bottom. Here’s some more detail on the individual bits:

CKDIV8: setting this to a “0”divides the clock speed by 8 – effectively causing the microcontroller to run 8 times slower than the internal or external clock source being used by the MCU.
 

CKOUT: setting this to a “0” results in the clock pulses being output on pin PB0.
 

SUT1 – 0: these determine the start-up time of the microcontroller once power has been applied. I would leave this at the longest setting (it gives all your peripherals time to warm up before your MCU starts) unless you have a specific requirement for starting up as fast as possible. The longest setting ends with “+65ms”.
 

CKSEL3 – 0: these control which clock source the MCU runs off – and there are a bewildering array of choices. The key ones that I use are:

  • “Int. RC Osc. 8MHz” which runs the MCU off its internal 8MHz oscillator
  • “Ext Crystal Osc.: Frequency 8.0- MHz” which uses an external crystal running at more than 8MHz – you’d use this if you connected a 16MHz external crystal, for example.
  • “Ext Crystal Osc.: Frequency 3.0-8.0 MHz” which uses an external crystal of 3 to 8 MHz

Right, we know what the bits mean and how to decide what values they should be programmed with – but just how do we actually programme the fuses?

Programming the Fuse Bytes

I use Atmel Studio for all my projects, and two types of programmer/debugger – a USBTiny and an Atmel ICE. The Atmel ICE is supported natively by Atmel Studio, so I can use Atmel Studio’s functionality to programme the fuses. The USBTiny isn’t supported by Atmel Studio, so I need to rely on AVRDude to programme the fuses. If you are using another IDE, then AVRDude is probably the best bet for you.

Programming from Atmel Studio

Using Atmel Studio is very straightforward. From the Tools menu choose Device Programming. Click on the Fuses tab, and enter your fuse values into the dialog that pops up – I normally enter the values from the Fuse calculator rather than use the check boxes and drop-down lists as the Fuse calculator is less cryptic to me.

Setting the Fuses in Atmel Studio

Setting the Fuses in Atmel Studio


Then click Program, and away you go!

Programming using AVRDude

Assuming that you’ve already downloaded AVRDude, follow these 3 steps to program your fuses:

  1. Open a command prompt and navigate to the folder that AVRDude.exe is stored in
  2. Enter the following to read the Fuse settings:
    avrdude –c [programmer] -p [MCU] -U lfuse:r:-:h
  3. Enter the following to program a Fuse:
    avrdude –c [programmer] -p [MCU] -v -U lfuse:w:0xFF:m

Where:

  • [programmer] is AVRDude’s code for the specific programmer you’re using (eg. usbtiny for the USBTinyISP) – refer to the file avrdude.conf for a list of these
  • [MCU] is AVRDude’s code for the specific MCU being programmed (eg m328p for the ATmega328P)
  • lfuse is the fuse being programmed – use lfuse, hfuse or efuse as appropriate
  • 0xFF is the value of the fuse being set – change this as necessary

So, to programme the low fuse byte on an ATmega328P, using a USBTiny programmer, with a value of 0xFF you would enter:
avrdude -c usbtiny -p m328p -v -U lfuse:w:0xFF:m

AVRDude Programming an AVR Fuse

Programming an AVR Fuse Byte with AVRDude

You’re a Fuse Expert!

Well, not quite yet – but hopefully this short discussion has helped you to get to grips with one of the scarier aspects of working with AVR Fuse Bytes. There are still a few gotchas waiting for you, and some intricacies of AVRDude that you may need to use (documentation is here), but you’re certainly most of the way there.

If you found this post useful and want more great free content, then sign up below and I’ll make sure I send future posts your way first!

Go Beyond the Arduino
ebook - Arduino to AVR

I’ve just completed my brand new guide Arduino to AVR: Get Started in 3 Steps.
Get it now on Payhip for only $1.65.

Challenge yourself and learn how to gain the flexibility and additional control that the AVR microcontroller offers.

As a free bonus, get an ATmega328P pinout cheatsheet.

3 thoughts on “How to Use AVR Fuses – and Understanding What They Do

  1. In the “Programming from Atmel Studio” section above the screen shot is using the internal oscillator… I have an external 16MHz oscillator (standard arduino standalone setup) but when I change the SUT_CKSEL settings to the External Oscillator … When Verifying I receive an error “One or more registers differs”… Should I uncheck the Auto Read & Verify After Programming Check boxes and just hit PROGRAM? Any assistance is greatly appreciated!

  2. Hi Daniel
    Good question. When using an external 16MHz crystal, I usually set the LOW fuse to 0xFF. If you use the Engbedded Fuse Calc (http://www.engbedded.com/fusecalc/), and work in the top section of the page (“Feature Configuration”) it should ensure that your fuses are aligned.
    I would leave the “verify” checked – it’s important that your fuses are being written correctly. If the verify fails, it may point to issues programming the fuse.
    Hope that helps
    Andrew

  3. hi
    i want to read and write to fuse bits in my c program in avr studio.(n run time).
    how can i do it?
    thankyou

Leave a comment

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