Arduino pro mini @ 1MHz — 1.8V
I’m always trying to find the best option for low power consumption projects. Using the Arduino pro mini at 1MHz and 1.8V gives new perspectives!
Jean-Matthieu DECHRISTE
During my water tank project, I realized that even with 3 AAA batteries, the voltage will go below 3.3V quite quickly :
Extract from AAA Energizer datasheet
If I extrapolate, it will remain around 25% of capacity of each battery when the voltage will be at 3.3V (1.1V per battery).
The cut-off voltage of these batteries is 0.8V. With 3 batteries, I will get 2.4V.
The ATmega328P will still work under this voltage, but only at 8MHz (which is the frequency of the Arduino Pro Mini 3.3V).
But why stop here ? With 2 batteries, it will go lower than 1.8V.
For that, we need to have a maximum frequency of 4MHz.
From what I understand, we have two options :
- Change the crystal oscillator of the Arduino
- Use the internal oscillator of the ATmega chip, and go down to 1MHz
Today, I will try the second option. I think that it is possible to change the crystal of some Arduino Pro Mini (it has to be visible), but I don’t have the pieces for the moment.
Internal RC oscillator
Atmega datasheet: By default, the Internal RC Oscillator provides an approximate 8MHz clock. Though voltage and temperature dependent, this clock can be very accurately calibrated by the user.
I don’t have the equipment to calibrate the oscillator. But as I don’t make a time sensitive device, I don’t think it will ba a problem. The factory calibration accuracy is +/-10% (as the user calibration accuracy is +/-1%).
The oscillator input can be selected through the fuses of the ATmega.
The fuses can be program to configure the chip. Contrary to what the name suggests, the fuses configuration is reversible. However, some of them are used to enable/disable some functionalities used to flash the ATmega (external reset, serial programming. ) so be careful to check your modifications before applying them.
Flashing process
If you don’t already know, the classical way to use the Arduino, is to have a bootloader (small program), started at the reset of the atmega.
The bootloader enable us to change the active sketch through the serial port (write into memory), read memory, get device signature, and so on. It also starts the uploaded sketch when programming mode is not started through the serial port.
On the ATmega328p, the bootloader can have 4 different sizes (256 bytes, 512 bytes, 1024 bytes or 2048 bytes).
With the ATmega328p, two bootloaders are commonly used:
- ATmegaBOOT (2kB), original Arduino bootloader [GitHub];
- Optiboot (500 bytes), lighter bootloader, default with Arduino Uno [GitHub].
You will find other bootloaders for Arduino Mega (ATmega1280) for example.
The second way to use the ATmega, is to program it with an ISP programmer , which doesn’t need the bootloader. As such, the bootloader can be removed, allowing a memory gain up to 2kB (depends on the bootloader).
As we want to change the frequency of the ATMega328p, we have two options :
- Bypass the bootloader, programming the atmega directly with the ISP programmer;
- Flash a compatible bootloader on the Arduino with the ISP programmer.
Whatever option is used, an ISP programmer is required.
Moreover, if you want to use a bootloader, you need to compile it (or find it somewhere on the internet), as the Arduino IDE does not come with a compliant bootloader.
For now, I will bypass the bootloader as I don’t want to install the toolchain required to build it.
Changing the fuses
To change the fuses, you cannot use the serial / USB link. You will need an ISP programmer. Same remark with the Arduino Uno and the Arduino Nano.
Note: if we used the bootloader method with the Arduino IDE, the fuses will be automatically changed during the bootloader flashing process (always through the ISP programmer).
The ATmega328p has 3 fuses (+2 special fuses, not mentionned here), 1 byte each :
Please note:
- A bit set to «1» is «unprogrammed», and a bit set to «0» is «programmed»;
- Some numerical values refer to fuses containing undefined bits. Depending on the target device these fuse bits will be read either as «0» or «1». Everything is fine if the values read from the device are either the same as programmed (for AVRdude software, use «1», for Arduino IDE, use «0» for undefined bits with atmega328p).
- The «default value» column of the datasheet is for standalone chips. For the Arduino chip, the fuses configuration is different.
Datasheet extract
Following paragraphs are extracted from the Atmel datasheet.
Mithat Konar (the wiki)
User Tools
Site Tools
Sidebar
Interaction
Programming
Table of Contents
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
1. 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. You’ll find it at
This file has board descriptions written in a syntax the IDE understands for 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 this boards.txt file in a text editor, look for the line:
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
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. .bootloader.
Your profile
You will find another boards.txt file if you look in
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/ /.arduino15 .
The boards.txt here is one that the 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 the folder where your sketches are located and add the needed files there. I walk through the details in the case study that follows.
2. 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
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 . The values for these entries will change depending on what features and behavior you want to enable or disable.
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
3. 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.
4. How do I burn a bootloader?
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.
The /path/to/avrdude is typically:
The /path/to/avrdude.conf is typically:
Newer versions of these might be found under
The output of the above for an Arduino Uno looks like:
For a stock 3.3V/8MHz Pro Mini it’s:
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.8V 2) |
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/ /Arduino in Debian), I created the following folder structure:
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:
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:
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:
Copy ATmegaBOOT_168_atmega328_pro_8MHz.hex there to:
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
Test it
Verify that the extended fuse setting has changed to 0xFE .
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:
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.