The Arduino Pro Mini is a very minimalistic Arduino board with a small footprint. For this reason, it is an ideal candidate for being used as the target board in a battery operated system. In this blog post I’ll show you how to minimize power consumption and how to burn a new bootloader that saves flash memory, allows debugging, and fixes an annoying WDT bug.
The original boards were designed by Sparkfun and come these days (as clones) in 4 different versions: With an ATmega168P or with an ATmega328P and with 8 MHz or 16 MHz, where in the former case they are powered by 3.3 V and in the latter case by 5 V.
The distinctive feature of the Pro Mini is that you need an additional USB-UART converter, something that is usually integrated on an Arduino board. If you want to use the board in a target system, you most probably do not need such a converter and so it is good news that you do not have one of these on the board because it costs and consumes energy. You can get these USB-UART converters on eBay, Amazon, or at your favorite DIY shop. Make sure that they have a header with pins ordered like that: DTR, RX, TX, Vcc, CTS, GND. These pins match the header on the Pro Mini one-to-one (as in the picture). Well, actually, only almost one-to-one. The GND pin on the adapter is the lowermost pin, and on the Pro Mini board the pin next to the lowermost pin is labeled GND. Since the two lower pins on the Pro Mini board are connected, this does not matter, though.
You can, of course, use converters with other pin orderings, but then you have to make individual connections. One option is, for example, to use a Bus Pirate as described here. You should make sure to have the DTR pin, because this is used to force a RESET on the Pro Mini in order to start an upload. If you do not have a DTR pin on your converter, you have to press RESET by yourself before an upload. Start pressing while the program is compiling and release the reset button immediately when the compilation has finished. You probably need some fiddling around before it works.
One thing should be noted. The Pro Mini clones from China often have a sequence for the pins of the header that is mirrored, i.e., instead of DTR being the uppermost pin (in the above image), it is the lowermost pin. In any way, if you plug in the USB-UART adapter the wrong way, you do not destroy the chips on the board, they simply will not work and the power LED does not light up.
If you have not used a Pro Mini before, make yourself familiar with it. There is also a good tutorial by Sparkfun. Upload a few standard sketches to it and see how it works. Using the Arduino IDE, you have to select the right board (under the
Tools menu) and once you have selected the board, you need to go back to the
Tools menu and select the right
Processor. After that, there is no difference to programming an Arduino Uno.
Well, there is a slight difference when you have a 3.3 V/8 MHz version. It runs at half the speed, it updates the millis counter only every 2 ms, and it consumes significantly less power than when you have a 5 V/16 MHz version (or an Arduino Uno). The 3.3 volt version draws 5.1 mA, the 5 volt version draws 18.75 mA (approximately, depending on the board you have).
Reducing power consumption
When you want to run a system on a battery, then most of the time it should be in a sleep state, where power consumption is minimal. So how minimal can it be? Consulting the data sheet of the ATmega328P, the power down mode with brown-out-detection (BOD) and watchdog timer (WDT) disabled draws 0.1 µA. This corresponds to 1 mAh per year (if you approximate one year with 10k hours, which in reality is only 8760 hours). Note that self discharge of batteries leads to much higher figures! Even Li-SOCl2 batteries, which have a very low self discharge rate of around 1%/year, would lose 26 mAh per year assuming a 2600 mAh battery.
In addition to the 0.1 µA that keeps your MCU alive, you probably need some juice for sensors that will wake up the MCU. This might be in the orders of µA, hopefully. It can be an acceleration sensor or just a vibration switch (with a pull-up resistor), for example. Or perhaps a real-time clock. I often use a vibration switch that is closed in the normal state with a pull-up of 10 MΩ connected to one input pin, which is configured as a pin-change interrupt (PCI) input. The 10 MΩ are outside the specs, but worked for me all the time.
The key to save power is to use the
LowPower library by rocketscream (by the way, if you want to use this library with ATtinys or the ATmega1284(P), then you may want to use my fork of the library). The main method of this library is the
powerDown method. A typical call looks as follows:
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
This leads to powering down the MCU with the analog digital converter (ADC) and the brown-out check (BOD) disabled. If you do not disable the ADC (for which there is hardly any reason), then the ADC will suck up roughly 250 µA. BOD can be disabled or enabled by fuse bits. If BOD is enabled, it will constantly check the supply voltage and force a reset if the supply voltage goes below a configured level. This uses roughly 20 µA. Since you do not need that while sleeping, you can disable BOD by software using the argument
Finally, you may wonder what the first argument
SLEEP_FOREVER does and why you should not pull the plug instead. It simply means that the MCU does not wake up after some configured time interval. Such a wake-up needs to be triggered by an external interrupt, such as a PCI as mentioned above or one of the two external interrupt pins of the ATmega328P.
If you want to wake up the MCU periodically, you can use one of the following arguments:
SLEEP_15MS. Using one of these arguments when calling
powerDown uses the watchdog timer (WDT) to wake up after the specified time. If you do that in a loop, you can wake up, e.g., every 8 seconds, do something, and then sleep again. While sleeping, the MCU uses roughly 5 µA for the WDT.
Try out your newly acquired skills by uploading, for instance, the
LowPower example sketch
powerDownWakePeriodic.ino, which wakes up the MCU every 8 seconds. Then disconnect the USB-UART adapter, and connect the Pro Mini board with external power, measuring the current flowing into the board. Use the
GND pins on the board in order to provide regulated power. The
Raw pin close to the
GND is meant for unregulated input voltage up to 12 V.
While you might expect to see 5 µA (note that WDT is enabled), you probably see something around 3-5 mA. The reason is that the power LED (which you really do not need when you use the Pro Mini in a battery operated device) eats up most of the juice.
Pimp your Pro mini by removing parts
So, if you really want to go into low power, you need to remove the power LED or alternatively the 10 kΩ or 1 kΩ series resistor for the LED. See the picture below for the location of the LED (red) and the resistor (green) for different versions of the board. You may have an entirely different version, so power up the board and have a look at where the power LED is (the one that is permanently on).
I remove them by heating up one of the pads and using tweezers to lift the LED or the resistor. There are other recipes around, such as putting a lot of solder on it so that both pads are heated up. Just give it a try. After the removal of the power LED (or the series resistor), power consumption should be significantly lower, namely, roughly 20-40 µA. Most of it is caused by the voltage regulator, the small IC with 5 pins (yellow).
My advice is to remove the voltage regulator as well. If you really want to use a regulator, e.g., because you want to use a 9 volt cell to power the board, then you should use one with a low quiescent current, such as, e.g., a HT75xx-1 or a MCP1702. The former has the advantage that it also works when the input voltage goes below the guaranteed voltage level, while the latter in this case starts to draw a lot of current. In any case, both regulators have a quiescent current of around 2 µA which fits the idea of ultra low power.
After having removed the voltage regulator and running the example sketch
powerDownWakePeriodic.ino, the current consumption should be down to 5 µA, the current needed by the watchdog timer. Running the example sketch
powerDownWakeExternalInterrupt.ino, where you connect digital pin 2 to Vcc or you comment out the line
attachInterrupt(0, wakeUp, LOW), the current consumption should be down to 0.1 µA. Well, should be! Recently, I got a Pro Mini that after all removals still draws 360 µA. I have no idea why. But this board was funny from the beginning because it had a 3 volt regulator instead of a 5 volt regulator.
Finally, there is the LED connected to digital pin 13. If you need to use pin 13 as an output, then you probably want to remove this LED (blue) or the series resistor close by as well.
Pimp your Pro Mini with optiboot
The bootloader coming with the Pro Mini is from the Stone Age of the Arduino era. It has a size of 2 kB (instead of 512 bytes, which is enough) and it has a very annoying bug that prohibits the use of the watchdog timer. If the MCU is restarted while the watchdog timer is enabled, then after the reset, the watchdog time delay is set to 25 milliseconds. The original bootloader does not disable the watchdog timer, and so the MCU is restarted while booting up. And this happens infinitely often. Basically, it means that your board is unusable, and you even cannot restart it by pushing the reset button. The only way out is to disconnect power and then start again.
Meanwhile, there exists the
optiboot bootloader, which is the standard bootloader on the Arduino Uno. This bootloader does not have the WDT problem, and it uses only 512 bytes of flash memory. Even better, the most recent version 8.0 (which is not yet part of the Arduino distribution) of it supports writing to flash memory, which is instrumental when you want to debug your code, as I described in my tutorial on debugging with a gdb-stub. So there are three good reasons to switch to the most recent version of
First, you need to download or clone the
optiboot GitHub repository. Second (perhaps after unzipping the downloaded zip-file), you need to change into the directory that contains the source files for the bootloader. If you downloaded the zip file, that is
Otherwise the top-level directory is called
optiboot instead of
optiboot-master. This directory contains already a compiled version for the Uno or the Pro Mini 16MHz called
optiboot_atmega328.hex. As the third step, copy this file to the place where the
optiboot bootloaders of your Arduino installation reside. This is
The directory most probably contained a file of the same name, which you can safely overwrite.
Fourth, you can generate a version for the 8 MHz version of the Pro Mini (in the above folder):
make atmega328_pro8 BAUD_RATE=57600
This will generate the file
optiboot_atmega328_pro_8MHz.hex. As the fifth step, copy this file to the same directory of your Arduino installation as mentioned above.
As the sixth step, you need to extend the
boards.txt file that resides in the directory
1.8.3 (see the above directory paths). Load the file into a (pure) text editor, search for the line
## Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega328P, and put the following text before it:
## Arduino Pro or Pro Mini (5V, 16 MHz, optiboot) w/ ATmega328P ## -------------------------------------------------- pro.menu.cpu.16MHzatmega328opti=ATmega328P (5V, 16 MHz, optiboot) pro.menu.cpu.16MHzatmega328opti.upload.maximum_size=32256 pro.menu.cpu.16MHzatmega328opti.upload.maximum_data_size=2048 pro.menu.cpu.16MHzatmega328opti.upload.speed=115200 pro.menu.cpu.16MHzatmega328opti.bootloader.low_fuses=0xFF pro.menu.cpu.16MHzatmega328opti.bootloader.high_fuses=0xDE pro.menu.cpu.16MHzatmega328opti.bootloader.extended_fuses=0xFD pro.menu.cpu.16MHzatmega328opti.bootloader.file=optiboot/atmega328_optiboot.hex pro.menu.cpu.16MHzatmega328opti.build.mcu=atmega328p pro.menu.cpu.16MHzatmega328opti.build.f_cpu=16000000L ## Arduino Pro or Pro Mini (3.3V, 8 MHz, optiboot) w/ ATmega328P ## --------------------------------------------------- pro.menu.cpu.8MHzatmega328opti=ATmega328P (3.3V, 8 MHz, optiboot) pro.menu.cpu.8MHzatmega328opti.upload.maximum_size=32256 pro.menu.cpu.8MHzatmega328opti.upload.maximum_data_size=2048 pro.menu.cpu.8MHzatmega328opti.upload.speed=57600 pro.menu.cpu.8MHzatmega328opti.bootloader.low_fuses=0xFF pro.menu.cpu.8MHzatmega328opti.bootloader.high_fuses=0xDE pro.menu.cpu.8MHzatmega328opti.bootloader.extended_fuses=0xFD pro.menu.cpu.8MHzatmega328opti.bootloader.file=optiboot/optiboot_atmega328_pro_8MHz.hex pro.menu.cpu.8MHzatmega328opti.build.mcu=atmega328p pro.menu.cpu.8MHzatmega328opti.build.f_cpu=8000000L
This extends the usable flash memory from 30720 to 32256 bytes, sets the right communication speed, sets the right fuse bits, and points to the right bootloader files for the new options. When you now restart the Arduino IDE, you will notice that there are new options when you have selected the board
Arduino Pro or Pro Mini in the
As the seventh step, you have to burn the new bootloader to your Pro Mini board. On my Mac, I usually do that manually using
AVRFuses. You have to upload the bootloader and change the fuses that specify the size of the bootloader. Connect the ISP programmer with the Pro Mini as shown in the following Fritzing sketch.
If you want to do it with the Arduino IDE, proceed as follows:
- Select the right board, that is either Pro Mini
Atmega328P (3.3V, 8 MHz, optiboot)or
(5V, 16 MHz, optiboot).
- Connect an ISP programmer to your computer, set the port and the type of programmer under the
Toolsmenu (you can also use an Uno as a programmer as described here).
- Connect the programmer cables to the Pro Mini. You either have to build your own programmer cable or use individual jumper wires (see picture above).
Burn Bootloaderfrom the
Toolsmenu and wait.
- The built-in LED should now blink three times in a fast manner and then pause.
Afterwards, you should be able to upload the Blink sketch through your USB-UART adapter. Moreover, you can now debug your sketch using
avr_debug as described in my tutorial, you can upload bigger sketches and the WDT bug is fixed.