Introduction: How to Change Fuse Bits of AVR Atmega328p - 8bit Microcontroller Using Arduino
In this instructable you will learn how to change the fuse bits of Atmega328p microcontroller. I am using Arduino mega as a programmer to program Atmega328P-PU on breadboard. It comes with a default 1MHz Internal calibrated oscillator frequency. I will change the fuses to work with 8MHz Internal calibrated Oscillator.
Fuse bits play a crucial role in the working of a microcontroller. These are like switches which have two values 0 (programmed) and 1 (unprogrammed). Now there are basically two types of fuse bytes: low fuse byte (or lfuse) and high fuse byte (or hfuse). In some microcontrollers there is an additional fuse byte called Extended fuse byte (or efuse). Programming fuse bits are like tuning your microcontroller. I will not go in much details aboutthese things. If you are new to microcontroller programming you should learn these in a bit more detail. You can find lot of information on internet on this subject.
Warning: Before going to change the fuses please note that programming incorrect fuse bits may lead to permanent damage of your microcontroller chip. If you go through this instructable and follow every step properly then you won't be having any problem.
Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.
Step 1: Materials That You Are Going to Need
- A microcontroller that you are going to change the fuses. (may be any AVR Atmega-8bit microcontroller.)
- 1 x Breadboard.
- Few Breadboard jumpers.
- 1 x LED
- 1 x 220 ohm resistance
- 1 x 100nF capacitor
- USB A to B cable
- And a PC with available USB port (running windows OS only. Sorry I can't help you if you are using Mac or Linux)
I am using Arduino mega as programmer. You don't need the 100nF capacitor if you are using any other programmer.
- Arduino IDE. (Download Arduino IDE here)
- Download Full datasheet of the microcontroller that you are going to change fuses.
If you have installed arduino IDE then you already have it. You can check if you are having avrdude installed or not. Just go to command prompt and type avrdude and press "enter". See the image attached in this step. There is another image that show the message that you will get if you don't have avrdude installed or its not working. Well if you have no avrdude installed there is nothing to worry. Here is a link to Download WinAVR.
Step 2: Understanding Fuse Bits From Datasheet
The AVR AtmegaXXX microcontrollers comes with a default 1 MHz internal oscillator. In this instructable I will show you how to change the fuses of Atmega328P-PU to work at 8MHz internal oscillator. The location of specific fuse bits differs among all three fuse bytes (low, high and extended fuses) depending on AVR chip used. So be sure to write them down before setting them.
Low Byte Fuses
The low byte fuse deals with the clock source, how fast the chip will run, and how long it waits at startup. 1 byte equals 8 bits. So there are 8 bits in the low fuse byte. These 8 bits are explained here:
- Bit-7 : CKDIV8 : When set divides the clock speed by 8
- Bit-6 : CKOUT : When set clock pulses are output on PB0 (Pin 14)
- Bit-5 : SUT1 : Startup time delay
- Bit-4 : SUT0 : Startup time delay
- Bit-3 : CKSEL3 : Set the clock source
- Bit-2 : CKSEL2 : Set the clock source
- Bit-1 : CKSEL1 : Set the clock source
- Bit-0 : CKSEL0 : Set the clock source
The ATmega chips can be run at different speeds or frequencies and the frequency is determined by the clock source that is used. The clock source is set by using the CKSEL3...0 fuse bits. To work with internal Clock source we need to set CLSEL3 = 0, CKSEL2 = 0, CKSEL1 = 1 and CKSEL0 = 0. You have to find this value in the datasheet of the microcontroller. In the datasheet there is a chapter "System clock and clock options". There is a sub-topic in that chapter "Clock Sources".There you will find a table where the value of CKSEL3...0 can be fount. I have attached a screenshot of the datasheet.
For the Startup time there is another sub-topic "Calibrated internal RC Oscillator". There you will find another table for the SUT0...1. I am going to use Slow rising power option. So SUT1 = 1 and SUT0 = 0.
Now we are left with two more bits to set : CKOUT and CKDIV8. I don't need any clock pulse output on PB0. So I will set this to 1 (unprogrammed).
The maximum frequency of internal RC oscillator for Atmega328P-PU is 8 MHz. This is achieved when CKDIV8 is 1 (or unprogrammed). If you set this to 0 (or programmed) then your chip will runt at 1 MHz. So in order to run the chip at 8 MHz we have to set CKDIV8 = 1.
Now combining all the 8 bits, ourrequired low fuse byte is 11100010.
High byte Fuses
The high byte fuse is explained below. You can simply skip this part. Here I have only explained the high fuse bits. We don't need to change the high fuse bits in order to change the clock source and operating frequency. But if your are interested to know about the high byte fuses then go through the below paragraph.
There are 8 bits in the high byte fuse also. These are:
- Bit-7 : RSTDISBL : External Reset disable
- Bit-6 : DWEN : Debug Wire enable
- Bit-5 : SPIEN : Enable serial programming and data downloading
- Bit-4 : WDTON : Watchdog timer always on
- Bit-3 : EESAVE : Preserve EEPROM memory through chip erase
- Bit-2 : BOOTSZ1 : Sets the bootloader memory size
- Bit-1 : BOOTSZ0 : Sets the bootloader momory size
- Bit-0 : BOOTRST : Select the reset vector
Now I will explain each bit:
RSTDISBL (External reset disable)
PC6 of Atmega328 is a reset pin, hold it low (to ground) and the chip will reset. This is how the switch on the Arduino works. When you press the reset button it connects PC6 to ground and resets the chip. PC6 can also be used as a regular IO pin but this means disabling the reset function which in turns means the chip can no longer be inline programmed (in line programming requires a reset). This is one of the options it is better not to change. I imagine RSTDISBL is implemented for security reasons to stop the chip being reprogrammed or the firmware being downloaded. When RSTDISBL is programmed the start up time (SUT1 SUT0) is increased to 14CK + 4.1ms to ensure the programming mode can be entered.
By default, the setting is RSTDISBL = 1 (unprogrammed).
DWEN (debug WIRE enable)
ATmega chips have built in debugging tools which are by default turned off. The DWEN fuse is used to turn them on. DWEN uses the same pin as reset (PC6) and when DWEN is enabled (and the lock bits are not set) the reset pin becomes a communication pin and normal reset no longer works. For example, if you enable DWEN on an Arduino the reset button no longer works. To use the on-chip debugging you need a compatible programmer such as the AVR Dragon. Since I do not have a suitable programmer I have never used and do not know how to use debugging. If you would like to know more then there is a good article to get you started.
This is one of the fuses you should take care with. If you enable DWEN and also enable the lock bits you can no longer program the chip in the normal way.
If you are just starting then leave DWEN to 1 (unprogrammed). After all, reset is very useful.
SPIEN (Enable Serial programming and Data Downloading)
ATmega chips can be programmed using serial programming. Serial programming is used for on board programming using a serial protocol via an ISP (inline serial programmer) or UART (universal asynchronous receiver / transmitter). The normal method of programming the ATmega chips is via the SPI interface using the SCK (clock), MOSI (input) and MISO (output) pins. If you disable serial programming then you can no longer use the SPI to program the chip. You can also disable serial programming using the lock bits. For normal use and development leave SPIEN enabled, however, if you have a device that is final and no further programming is required then you can use this option to stop people accessing the chip through serial communication.
The default setting is SPIEN enabled, SPIEN = 0 (programmed).
WDTON (Watchdog Timer Always On)
The watchdog is basically a timer that will cause the chip to reset if it does not receive an OK signal at specific times. This can be useful when you have unstable code or have a system that must not be allowed to permanently lock up. When the watchdog timer is enabled, should a sketch crash or freeze then the timer will time out and reset the chip causing a restart similar to pressing the reset button an a running Arduino. The Watchdog Timer can be activated in software so the fuse settings doesn’t really need to be used. By default, the watchdog timer is off, WDTON = 1 (unprogrammed).
EESAVE (Preserve EEPROM memory)
When the ATmega chip is programmed the memory is erased just before the new code is uploaded. Under normal circumstances the EEPROM memory is erased as well as the program memory. The EESAVE fuse can be used to tell the chip not to erase the EEPROM. This is useful when you want to upgrade code but keep user settings that are stored in EEPROM.
I have got into the habit of setting this fuse; EEPROM has a limited life cycle so the less you write to it the better. Erasing the eeprom has no effect on uploading new code and the majority of my projects don’t use the eeprom memory so not erasing it is not a problem. The dropController stores settings and drop times in eeprom and so I set EESAVE to preserve the data when I upload new versions of the code.
The default value is EESAVE = 1 (unprogrammed), and EEPROM memory is erased during the chip erase cycle when programming.
BOOTSZ1 & BOOTSZ0 (Boot loader Size)
The ATmega chips have the ability to use a boot loader, this is a small program that runs when the chip is first started or when it is reset. Boot loaders are normally used to initialize the device and check for external communication. The Arduino uses a boot loader to talk to a connected computer to see if there is a new program to be uploaded. This is the reason the Arduino resets when you upload new code, the reset runs the boot loader, the boot loader checks to see if you have new code.
The boot loader is stored in program memory, the same memory used for the user application and since the boot loader can be different sizes you can tell the ATmega chip how much space to reserve. The regular (older) Arduino boot loader is 2 kilobytes (KB) but the newer Optiboot (used on the UNO) is only 0.5KB (512 bytes). If using Optiboot and setting the boot loader size accordingly you gain an extra 1.5KB for your own program. 1.5KB can be a lot of space, running out of program space is why I started programming stand alone ATmega chips in the first place. The code for the drop Controller became too large for the regular Arduino so I removed the boot loader.
If you have a boot loader then BOOTSZ has to be used in conjunction with BOOTRST. BOOTRST tells the ATmega chip the memory address where the boot loader starts. If BOOTRST is not set then the user application can use the whole of the memory regardless of the BOOTSZ settings.
The default for new chips is BOOTSZ1 = 0 (programmed) and BOOTSZ0 = 0 (programmed) which means they have maximum memory reserved for a boot loader.
BOOTRST (Select reset vector)
ATmega chips can use a boot loader, this is a small program that runs when the chip is reset. If you have a boot loader then you need to inform the MCU and this is done by using the BOOTRST fuse setting. When the BOOTRST Fuse is set, on reset the device will jump to the Bootloader address. If not set, the chip will jump to the program start address at 0x0000.
The default value is BOOTRST = 1 (unprogrammed).
If BOOTRST is not set (no bootloader) then the BOOTSZ fuses are not used regardless of the value.
WARNING: The RSTDISBL, SPIEN and DWEN fuses have the potential to brick the ATmega chip, or at least make the chip very very difficult to use again. For general use, and especially if you are just starting out with programming stand-alone chips, you should not change these fuse settings. You should also double check that you are not changing them when you re-write the other fuse settings.
So our our required high fuse byte is 11011011.
Extended Fuse Bits
The extended fuses are only used to set the brown-out detection level (BOD). The ATmega chips can become unstable or unreliable when used with insufficient voltage. For example, the Atmega328/328P can run safely at 16 MHz if it has at least 4 V supply. Anything below 4V means the chip is likely to misbehave. This would be a problem if the device were being used with sensors to take measurements or relied on accurate timings.
To ensure the chip has sufficient input voltage a minimum voltage level can be set. If the voltage falls below this level then the chip will reset itself. This is called the brown-out detector level. Basically, if the supplied voltage is below the BOD the chip keeps reset low.
I am not going through each bits of extended fuse byte. By default all the bits in this byte is set as 1 (unprogrammed).
And here is our extended fuse byte is 11111111.
Step 3: Calculating the Fuse Bits
Okay so now we are familiar with the fuses and already calculated the fuse bits.
Low byte fuse (lfuse) : 0b11100010
High byte fuse (hfuse) : 0b11011001
Extended fuse (efuse) : 0b11111111
Now you can simply write these in binary or you may convert these to Hexadecimal. I am going to convert these to hex because I usually make mistake in typing 0 and 1 repeatedly any you know how much important these are. If you set wrong fuse bits then you may probably brick the chip.
So here is the hex value:
lfuse : 0xE2
hfuse : 0xD9
efuse : 0xFF
If you are having trouble in calculating binary to hex then here is a calculator.
If you find that calculating fuse from the datasheet is difficult then here is a fuse calculator. However, changing fuse without having knowledge in this subject is not recommended.
Step 4: Set Up the Circuit on a Breadboard
In this instructable I will be using Arduino mega as ISP programmer. Connect the pins as shown
Name-----------Arduino mega Pin-------------------Atmega328P Pin
MISO--------------Digital pin - 50-------------------------------18
MOSI--------------Digital pin - 51-------------------------------17
SCK---------------Digital pin - 52-------------------------------19
Slave Select-----Digital pin - 53--------------------------------1
VCC--------------------5 V---------------------------------------7 & 20
GND-------------------GND--------------------------------------8 & 22
Connect the anode of LED to pin 14 of Atmega328p (digital Pin 8) and cathode to a 220 ohm resistance. Ground the other end of resistance.
Note : Do not connect the capacitor between 5V and RESET in this step. After uploading the arduinoISP sketch we will connect the capacitor.
Step 5: Upload Arduino As ISP Sketch
After you have done the connections on the breadboard double check that you have made the connections correct. Then connect your Arduino mega with the PC using the USB cable. Open Arduino IDE. In the examples > ArduinoISP. Now click on tools > board > Arduino mega or mega 2560. Again click on tools > Processor > ATmega2560 (Mega 2560). Once again click on tools > Port > COMX (For me its COM3).
Now compile the sketch and upload it into the board.
When the upload completes connect a 100nF capacitor between the 5V pin and RESET pin of arduino mega. You will get error message if you don't this.
Step 6: Change the Fuses Using Avrdude
Go to your command prompt window and type "avrdude" and see if your avrdude is working.
Now type the command "avrdude -c arduino -p m328p -P COM3 -b 19200 -v" to see details about the microcontroller.
Okay I will only change the low byte fuse. Because we have already calculated the fuses and to change the CPU frequency only the low fuse byte fuse needs to be changed. High byte fuse and extended fuse doesnot deals with the oscillator frequency and clock source.
Type the command "avrdude -c arduino -p m328p -P COM3 -b 19200 -U lfuse:w:0xe2:m" to write the low fuse byte.
Again type the command "avrdude -c arduino -p m328p -P COM3 -b 19200 -v" and check if you have successfully changed the fuses.
Step 7: Upload the Blink LED Sketch
You can download the blink LED sketch.
Before uploading the sketch we have to make a few changes. Now we don't have a board that operates at 8 MHz internal oscillator. The standard arduino UNO uses the atmega328p microcontroller but it operates at 16 MHz external crystal oscillator. So we have to add a new board to the tools menu.
Go to C:\program files\Arduino\hardware\arduino\avr\variants
Add a new folder and name it as "Atmega328p".
Now go to C:\program files\Arduino\hardware\arduino\avr\variants\standard and copy the file "pins_arduino" and paste it in the location C:\program files\Arduino\hardware\arduino\avr\variants\Atmega328p
Go to the location C:\program files\Arduino\hardware\arduino\avr. There is a text file with name "boards.txt". copy this file somewhere else and open it to edit.
Scroll down to the end of the codes and add these few lines:
##############################################################<br> ATmega328p-8.name=ATmega328p-Internal 8Mhz ATmega328p-8.upload.tool=avrdude ATmega328p-8.build.mcu=atmega328p ATmega328p-8.build.f_cpu=8000000L ATmega328p-8.build.core=arduino:arduino ATmega328p-8.build.variant=ATmega328p ATmega328p-8.upload.maximum_size=32000 ##############################################################
Save the file and copy the edited "boards.txt" to the location "C:\program files\Arduino\hardware\arduino\avr". You may be asked for administrator permission. (You may download the "boards.txt" from this page and paste it into the location "C:\program files\Arduino\hardware\arduino\avr").
Now open arduino IDE and go to tools menu "tools > boards > Atmega328p". Again go to tools option and select the correct COM port and check the programmer Arduino as ISP (tools > programmer > Arduino as ISP).
Download the blinkled.ino file from this instructable and upload it. You should see LED blinking at 1 sec interval.