Fuse bits aren’t that scary
I often find that lock and fuse bits of AVR MCUs are somewhat scary to newbies and even rather skilled ones. So this article is aimed to clarify the mist around this mysterious memory area once for all.
What are lock/fuse bits?
Everyone knows that AVR MCUs have, in general, three memory areas: FLASH, which is dedicated to program code, SRAM for run-time variables and EEPROM, which can be used by user code to store data that have to be preserved when MCU is turned off. Now, the lock/fuses form a fourth memory area available for programming. This holds a few bytes that contain those bits. For example, ATmega48 has four of them – one byte for lock bits and three bytes for fuses: low, high and extended.
What are those bits for?
All MCU programmers are familiar with the fact that configuration of peripheral modules is done by setting or clearing some bits in appropriate registers. So the bytes with lock bits and fuses can be thought of as a sort of peripheral configuration registers, determining some very general system settings, like memory access, clock source and divider, start-up options, programming options and so on.
Why do people get so scared of them?
There are some few reasons for this. As being said, lock/fuses determine some very basic MCU options, and particularly they directly affect programming method selection and clock system modes. So setting some wrong combination effectively renders MCU unworkable. This danger is aggravated by the fact that the lock/fuse is considered active when is has a value of ZERO and this leads to additional confusion. The other problem is posed by GUI-based chip programming tools, which have checkboxes for fuses and no any standard of what checked box means. So you must fugure out carefully if those boxes actually mean logic one or zero in the bit of interest. But actually you shouldn’t be that scared of locks and fuses. Datasheets provide extensive information on what they mean, so the best tactics is to read docs carefully before applying any changes to this area.
Now let’s talk about how to avoid getting into trouble.
Generally you should never change lock bits. These bits affect code/data read protection and bootloader functionality. As long as hobbyists rarely need any data protection and, I guess, you don’t write bootloader every weekend, there is no sense in changing anything there. However, these settings are erased during general chip erase, so their value can’t pose great problem anyway.
The strongest destructive potential is associated with RSTDISBL, SPIEN and DWEN fuses. You should think twice and precisely know the desired result before changing them.
If RSTDISBL is active, MCU’s reset pin becomes a GPIO. As long as external reset signal is essential for in-circuit programming, setting this bit makes it impossible.
DWEN turns on DebugWire debug system. But DebugWire port is physically implemented on a reset pin, so enabling this bit have the same effect as previous.
SPIEN – turns off in-system programming when inactive.
The only chance to recover MCU after ocassionally setting these bits is to restore default settings with a parallel programmer. But as long as such an equipment is a kind of exotic, it is usually a lot simplier/cheaper to continue studies with another chip.
The next group you should be very careful about are CKSELn bits, which affect system clock options. Most MCUs are shipped with the internal RC oscillator set as default clock source. By altering CKSELn group you can change this. For example, you can configure system to use your custom crystal or even external clock signal. So, if there’s no crystal on your board, nor external clock source around, the chip will seem breathless. This problem has an easy workaround: you just have to temporarily connect any external crystal or a simple oscillator of NAND gates running on a few megahertz to your MCU, and then it will be easy to correct invalid settings with any programmer. Nevertheless, if you have a chip in a package like TQFP or QFN and there’s no traces to XTAL pins on your PCB, connecting those recovery tools can be a challenge. So double-checking CKSELn bits value before flashing MCU is the best practice.
The other way of making your debug life more exciting is occasional activation of a WDTON bit. Being set active, it makes watchdog timer be always on, so that’s a chance for you to observe the system periodically rebooting without any apparent reason.
You can also be surprised by BOOTRST bit effects. It makes program execution start from bootloader section rather then from normal flash start (0x0000). So it is best just not to alter it, unless you’re actually writing a bootloader.
All other fuses are essentially harmless. Nevertheless, some of them can cost you hours of debug (e.g. ATmega128 compatibility fuse), so read manuals carefully and double-check values. I also recommend to use flashing utilities that allow you to enter fuse bytes with digits (rather then checkboxes) to avoid any surprises.
So, in a short form:
- you should never alter lock-bits;
- RSTDISBL, DWEN, SPIEN must NEVER be changed;
- CKSELn sould be checked twice;
- Other bits are harmless, but you should always have a good knowledge of what and why you are changing.
In addition, I’d advice you to avoid using those fusebit calculators. I think this settings are serious enough to spend your half of an hour reading datasheet.
ATmega48 is shipped with internal 8MHz RC oscillator set as an active clock source and CKDIV8 fuse set. This results in 1MHz system clock. It’s usually too slow for me, and I always turn this fuse off to get full 8MHz.
As mentioned, it’s best to use tool that allows you to specify fuses in a digit form. I use AVRdude, which runs from console, so it is not a problem.
First of all, let’s see datasheet to figure out where that CKDIV8 is located. The table on page 288 shows that the byte of interest is fuse low byte:
Its default value is 0b01100010. CKDIV8 is seventh bit and we don’t need to change any other bits, so only MSB needs to be changed. Hence the new value is 0b11100010=0xE2. The AVRdude command line is as follows:
avrdude.exe -p m48 -c ftbb -P ft0 -e -U lfuse:w:0xE2:m -B 4800 -u
-p m48 – MCU type is ATmega48;
-c ftbb -P ft0 – my programming adapter is ftbb;
-e – erase chip before programming;
-U lfuse:w – write low fuse (lfuse) byte…
:0xE2:m – with 0xE2;
-B 4800 – program at lower speed;
-u – program anyway, ignore signature check.
There’s nothing scary about lock/fuse bits. All essential information is available in datasheet. So all you have to do is to read documentation carefully and double-check values before applying them. And, of course, you have to have precise knowledge of your objectives.