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|
|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.
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:
- Open a command prompt and navigate to the folder that AVRDude.exe is stored in
- Enter the following to read the Fuse settings:
avrdude –c [programmer] -p [MCU] -U lfuse:r:-:h
- Enter the following to program a Fuse:
avrdude –c [programmer] -p [MCU] -v -U lfuse:w:0xFF:m
- [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
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!
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.