User Tools

Site Tools


arduino:atmega328p_arduinos_and_custom_fuse_settings

ATmega328P Arduinos and custom fuse settings

Programming your device with the code you want to execute, whether with a bootloader or directly with a programmer, is one layer of programming your device. Another layer is the so-called fuses inside an ATmega microcontroller.

Fuses are programmable nonvolatile registers that are used to configure things like what the clock source and rate for the microcontroller is, whether brown-out detection is enabled, whether you're using a bootloader and if so how much flash will be reserved for a bootloader. Programming fuses can be scary because if you don't do it right, you can brick the micro. However, you can gain finer-grained control over your project by setting the micro's fuses yourself.

In this article, I will investigate using fuses to configure a 3.3V/8MHz Pro Mini to set a brown-out detection level that is different from what the standard 3.3V/8MHz Pro Mini uses because this happens to be the use case that has driven me to learn about this. However, what I cover should be adaptable to other Arduinos that use other ATmega processors. It may not be very relevant to other micro families.

The hard way or the hard way?

There are a couple ways we can go about setting the fuses on an ATmega328P Arduino. We can use a programmer along with the command-line avrdude utility to explicitly set fuse values, or we can create an additional Arduino board specification with the desired fuse settings, then burn a bootloader using the Arduino IDE, which will also set the fuses for us.

Both create different kinds of difficulties. To keep things as “Arduino” as possible, in what follows I am going to pursue the second approach. You can think of this process in terms of four questions, which I try to answer below. After that I walk through a case study.

Four general questions

Where do I put new board specs?

Specs for Arduino boards, including fuse bit settings, are found in various board.txt files, themselves found in various hardware folders. This can get a little confusing as there are number of these folders and files that you'll find on your computer. I'll try to go through the differences below.

The install bundle

A board.txt file is included in the Arduino package you installed and will be found at

/path-where-you-installed-arduino/hardware/arduino/avr

This file has board descriptions written in a syntax the IDE understands for the default boards Arduino supported at the time the package was released. This is not where you will add descriptions for your custom board or existing board with modified fuse settings, but it's good place to look to begin to grok the syntax.

When you open the default boards.txt file in a text editor, look for the line:

uno.name=Arduino/Genuino Uno

Following that are a number of lines starting with uno. These are all parameters that describe the specifics of the Arduino/Genuino Uno board. Knowing this, you can probably make at least partial sense of some of the parameters. The lines that begin uno.bootloader. are where the fuse settings are given. You can see hexadecimal entries for the low bits, high bits, and extended bits along with the lock and unlock bits.

If you do some more searching, you'll find an entry for

pro.name=Arduino Pro or Pro Mini

The syntax here is a little more elaborate because the Pro and Pro Mini come in different flavors: they have been made with both ATmega328P and ATmega168 micros, and in 5V/16MHz and 3.3V/8MHz versions. Bootloader parameters that apply to all Pro Minis are prefixed with pro.bootloader. Those that apply to a specific version are prefixed with pro.menu.cpu.<version-identifier>.bootloader.

Your profile

You will find another boards.txt file if you look in

/your-Arduino-profile-folder/packages/arduino/hardware/avr/<a-version-number>

This is not your Arduino sketch folder. Rather it's where global application configuration information is stored. You can see the path to your profile folder towards the end of the Preferences dialog box. The Arduino profile folder on Linux systems is /home/<username>/.arduino15.

The boards.txt here is one that your Aurdino IDE actually uses. It might be a copy of the boards.txt that shipped with the installation bundle, or it might have been subsequently updated by the IDE.

If you have added additional boards using the IDE, you are likely to find additional folders for their architectures under /your-Arduino-profile-folder/packages or its subfolders.

It's my understanding that you can add your custom board descriptions in these areas, but the prevailing advice is not to. This area is designed to be managed by the IDE. If you make additions here, the IDE may overwrite them or you might corrupt the ability for the IDE to successfully add/remove/update boards. You can safely add new boards here if you go through a somewhat cumbersome process involving a few additional files. But there seems to be an easier way.

Your sketch folder

The following method works on the version of Arduino I used at the time or writing this: 1.8.8. I don't know whether it can be relied on to hang around for a while or has been deprecated.

So, until I'm advised this is a horrible idea, the way I recommended you add your own custom board descriptions is to create a folder called hardware in your Arduino sketches folder and add the needed files there. I walk through the details in the case study that follows.

How do I specify new board characteristics?

There is a lot of arcane knowledge that applies to writing custom Arduino board.txt entries, and I haven't found a source that documents it thoroughly. So my best advice is to study the boards.txt found at

/path-where-you-installed-arduino/hardware/arduino/avr/

to get as familiar with the syntax. What interests us here are the entries for low_fuses, high_fuses, and extended_fuses (and to a certain extent unlock_bits and lock_bits.

Another good resource to look through is the files found in the breadboard-1-6-x.zip archive found under “Minimal Circuit (Eliminating the External Clock)” at From Arduino to a Microcontroller on a Breadboard

What specs do I want?

This article covers making a variant of an existing board where only the fuses have been changed. The relevant parameters in the boards.txt specs will have low_fuses, high_fuses, and extended_fuses in their names. The values associated with those parameters are hexadecimal.

Exactly which fuses do what and how is an article in and of itself. I haven't written one of those, so you might want to check out this article by Martyn Currey for a friendly description. You might also find online fuse calculators from Eleccelerator and Engbedded to be helpful. But be forewarned, there's no guarantee these calculators are bug-free. The ultimate reference is the ATmega328P datasheet.

When you're figuring out what your fuse values should be, don't be afraid to reference back to the original settings in whatever board.txt file entry you're basing things off.

There is one additional caveat here: You can only change fuses that are compatible with what the bootloader you plan to use will let you do. Again there isn't a lot of documentation here, so if you've done everything right but things still don't work, this might be the reason. The solution to this is to compile a custom bootloader, which is well beyond the scope of this piece.

How do I burn a bootloader?

This too is a pretty big topic, but the TL;DR is: hook up a programmer to your board, select the right board and programmer, then do a Tools > Burn Bootloader. This Sparkfun tutorial is a good reference if you need more hand-holding.

With this covered, let's get busy.

Reading fuse settings

Reading an Atmega328P's fuse settings is a lot easier than writing them. So we start with this. We will also need this to confirm that everything had gone to plan when we burn the new settings.

With a USBtinyISP (or theoretically any supported programmer) connected to your Atmega328P target, use the following command to get a reading of how the fuses are configured.1) This assumes you are using a Linux-like CLI and do not have avrdude installed as a global command.

$ /path/to/avrdude -C /path/to/avrdude.conf -c usbtiny -p m328p -U lfuse:r:-:i -v

The /path/to/avrdude is typically:

/path-to-where-you-installed-arduino/hardware/tools/avr/bin/avrdude

The /path/to/avrdude.conf is typically:

/path-to-where-you-installed-arduino/hardware/tools/avr/etc/avrdude.conf

Newer versions of these might be found under

/your-Arduino-profile-folder/packages/arduino/tools/avrdude

The output of the above for an Arduino Uno looks like:

# preamble, preamble, preamble ...

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DE
avrdude: safemode: efuse reads as FD
avrdude: safemode: Fuses OK (E:FD, H:DE, L:FF)

avrdude done.  Thank you.

For a stock 3.3V/8MHz Pro Mini it's:

# preamble, preamble, preamble ...

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DA
avrdude: safemode: efuse reads as FD
avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)

avrdude done.  Thank you.

For the nitty-gritty breakdown on the command see this page.


Case study

In the section, I walk through the process of creating a custom version of a 3.3V/8MHz Pro Mini where the nominal brown-out detection (BOD) threshold is changed from the stock 2.7V to 1.8V.

If you reduce the BOD threshold or turn off BOD entirely, don't run programs uploaded by the bootloader at low voltages. See this for an explanation why.

Calculating new fuse settings

The only fuse settings I want to change are those that affect the BOD. These are defined in the lowest three bits of the extended fuse bits. The upper five bits are not used/reserved.

extended fuse bit function
7 not used/reserved
6 not used/reserved
5 not used/reserved
4 not used/reserved
3 not used/reserved
2 BODLEVEL2
1 BODLEVEL1
0 BODLEVEL0
BODLEVEL2, 1, 0 VBOT
111 BOD disabled
110 1.8V2)
101 2.7V
100 4.3V
0xx not used/reserved

Now is a good time to mention that the ATmega328P fuses are active low, meaning that a 0 sets (“programs”) a bit, and a 1 unsets (“unprograms”) it. This can sometimes lead to hilarious misunderstandings, so be careful.

So, to set the brown-out threshold to 1.8V I want the last three bits of the extended fuse byte to be b110 and the entire byte to be b11111110 or 0xFE. Online fuse calculators agree, so it's probably right.

Preparing the new board files

Folder structure

Inside my Arduino sketches folder (/home/<username>/Arduino in Debian), I created the following folder structure:

<arduino-sketches-folder>/
+-- hardware/
    +-- mfkcustom/
        +-- avr/
            +-- bootloaders/
                +-- atmega/
            +-- variants/

mfkcustom is where I will put all my own custom board definitions. The remaining folder structure is needed by Arduino to make things work.

boards.txt

Inside the avr folder, create a text file called boards.txt for your board definition(s). I based the board definition here on the specs for the standard 3.3V Pro Mini and the format of boards.txt found in the breadboard-1-6-x.zip archive found under “Minimal Circuit (Eliminating the External Clock)” at From Arduino to a Microcontroller on a Breadboard:

boards.txt
##############################################################
# Arduino Pro Mini 3.3V/8Mhz, 1.8V BOD (ATmega328P only)
 
mfkpro18bod.name=Pro Mini 3.3V/8Mhz, 1.8V BOD, ATmega328P
 
mfkpro18bod.upload.protocol=arduino
mfkpro18bod.upload.maximum_size=30720
mfkpro18bod.upload.maximum_data_size=2048
mfkpro18bod.upload.speed=57600
 
mfkpro18bod.bootloader.low_fuses=0xFF
mfkpro18bod.bootloader.high_fuses=0xDA
mfkpro18bod.bootloader.extended_fuses=0xFE
 
mfkpro18bod.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex
mfkpro18bod.bootloader.unlock_bits=0x3F
mfkpro18bod.bootloader.lock_bits=0x0F
 
mfkpro18bod.build.mcu=atmega328p
mfkpro18bod.build.f_cpu=8000000L
mfkpro18bod.build.core=arduino:arduino
mfkpro18bod.build.variant=arduino:eightanaloginputs
mfkpro18bod.build.board=AVR_PRO
 
mfkpro18bod.bootloader.tool=arduino:avrdude
mfkpro18bod.upload.tool=arduino:avrdude
 
##############################################################

I didn't create an option to use an ATmega168 instead of an ATmega328P because I wanted to keep the syntax as simple as possible.

Some things to note here:

  • Your board's identifier (mfkpro18bod here) needs to be unique throughout the installation.
  • Some parameter values are prefaced with arduino: to indicate (I think) that global Arduino files and tools that define these should be used rather than a local ones.
  • The parameter mfkpro18bod.bootloader.file refers to a hex file that's is in a local folder called atmega. That's the folder at
    <arduino-sketches-folder>/hardware/mfkcustom/avr/bootloaders/atmega/

    created above. We'll copy in that hex file next.

Bootloader

I will be using the same bootloader that is used for the standard 3.3V/8MHz Pro Mini. Standard bootloader files for ATmega-based Arduinos are found in:

/path-to-where-you-installed-arduino/packages/arduino/hardware/avr/<version-number>/bootloaders/atmega/

Copy ATmegaBOOT_168_atmega328_pro_8MHz.hex there to:

<arduino-sketches-folder>/hardware/mfkcustom/avr/bootloaders/atmega/

and make sure the name matches with what you specified in boards.txt.

Burn the bootloader and test

Whether you plan to upload your sketches with a USB to serial converter (i.e., using the bootloader) or directly using a programmer, you still need to burn the bootloader to set the fuses. So let's burn and test it.

Burn it

  • Create a new project consisting of a simple sketch (e.g. blink.)
  • Under Tools > Board you should see an entry for “Pro Mini 3.3V/8Mhz, 1.8V BOD, ATmega328P”. Select it.
  • As a sanity check, Verify/Compile the project. No errors is good.
  • Hook up a programmer to a 3.3V/8MHz Pro Mini and select the programmer you're using under Tools >Programmer.
  • Plug the programmer into your computer
  • Burn the bootloader by executing Tools > Burn Bootloader.

Test it

  • With the programmer still plugged in, follow the instructions above to read the fuse settings. You should see:
    # preamble, preamble, preamble ...
    
    avrdude: safemode: lfuse reads as FF
    avrdude: safemode: hfuse reads as DA
    avrdude: safemode: efuse reads as FE
    avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)
    
    avrdude done.  Thank you.

    Verify that the extended fuse setting has changed to 0xFE.

  • Unplug the programmer and hook up a USB to serial converter.
  • Upload your simple sketch to the Pro Mini to see if it works as expected.

If you reduce the BOD threshold or turn off BOD entirely, don't run programs uploaded by the bootloader at low voltages. To run a sketch at low voltage you should upload your sketch directly using a programmer. See this for an explanation why.

Upload with programmer and test

After burning the bootloader to set the fuses, hook up your programmer. Be sure you have set both the board and programmer to the correct values under Tools. Then upload your simple test sketch with Sketch > Upload Using Programmer. Your sketch should upload and start running (possibly only after you have disconnected the programmer).

Follow the instructions above to read the fuse settings. You should see:

# preamble, preamble, preamble ...

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DA
avrdude: safemode: efuse reads as FE
avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)

avrdude done.  Thank you.

Confirm that the extended fuse is still 0xFE.

You can now connect the Pro Mini to a variable supply to see whether it works as expected below 2.7V. It may not work all the way down to 1.8V though, but because you're not using a bootloader, you won't run the risk of corrupting the program memory.

2)
The ATmega328P datasheet indicates this state is “reserved”, but several other sources indicate it sets the VBOT to 1.8V, including Microchip's own Developer Help.
arduino/atmega328p_arduinos_and_custom_fuse_settings.txt · Last modified: 2020/01/04 02:45 by mithat