Bootloader-less Programming Arduino Pro Mini

Recently I was creating a configurable timer circuit based Arduino Pro Mini. The circuit has a momentary push button which user can press to turn ON the device. The device will turn OFF itself once the time is elapsed. On starting, Arduino has to turn on a relay to get permanent connection to power source, so it will get power when user released the push button. One issue I faced was that Arduino takes around 3 seconds to start executing the program because of the presence of the bootloader. So, user would have to keep push button pressed for around 3 seconds to get the device started. I wanted to get rid of bootloader so Arduino will start executing the program soon we press the push button for a moment.

I searched over Internet for proper solution to upload program to Arduino Pro Mini without having bootloader in it. I could not find anything useful. I have a USBTinyISP which I thought can be used to program my Arduino Pro Mini ATmega168. I connected USBTinyISP to SPI pins on Arduino Pro Mini in following way:

  • GND -> GND
  • VCC -> VCC
  • MOSI -> pin 11 of Arduino
  • MISO -> pin 12 of Arduino
  • SCK -> pin 13 of Arduino
  • REST -> REST (RST)

I chose USBTinyISP as the programmer in Arduino IDE Tools menu. But I could not upload program with that selection. However, I was able to upload bootloader with same set up! So, it confirms my connection between USBTinyISP and Arduino is good.

Then I thought why can’t I compile Arduino program to get the binary file. Then upload that binary file manually using avrdude.

We can get compiled binary in Arduino IDE by clicking Sketch -> Export compiled Binary menu item. You will see .hex binary files at same location as your sketch. If you are unsure where your sketch is then you can click Sketch -> Show Sketch Folder to go there.

In my case, my sketch is timer. It generated timer.ino.eightanaloginputs.hex and timer.ino.with_bootloader.eightanaloginputs.hex. File names are having eightanaloginputs because Arduino Pro Mini is having surface mount IC, which has extra 2 analog inputs. If it were Arduino Uno then we would have get timer.ino.standard.hex and timer.ino.with_bootloader.standard.hex instead.

Anyway, we just wanted binary without bootloader to upload to Arduino. So, I will have to upload timer.ino.eightanaloginputs.hex.

Now we have to identify the fuse settings to be used in avrdude command. Here I will copy fuse settings from Arduino IDE and modify per our needs. Go to this subdirectory location under your Arduino IDE installation location “hardware/arduino/avr”. Open “boards.txt” file. Then copy the high and low fuse settings against your Arduino.

For example, my “Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega168” got these lines:

pro.menu.cpu.16MHzatmega168.bootloader.low_fuses=0xff
pro.menu.cpu.16MHzatmega168.bootloader.high_fuses=0xdd
pro.menu.cpu.16MHzatmega168.bootloader.extended_fuses=0xF8
So, low fuse is FF, high is DD and extended fuse F8.

As I already described in my earlier post “Program AVR Microcontroller with USBTinyISP and Eclipse IDE”. I had setup Eclipse IDE for programming AVR microcontrollers using USBTinyISP. Eclipse IDE was already setup well to use avrdude and it has facility to select fuse settings graphically. The idea is to create a dummy project in Eclipse IDE with empty main() function for ATmega168 microcontroller and configure avrdue with fuse settings. On modifying the fuse settings graphically, it will give updated fuse settings to be used in our avrdude command (You can also use “AVR Fuse Calculator” available at http://www.engbedded.com/fusecalc/, however I will show only method with Eclipse here).

So, lets do that. Ensure correct MCU Type and MCU Clock Frequency is selected in AVR -> Target Hardware project configuration.

Ensure proper microcontroller and frequency are selected
Ensure proper microcontroller and frequency are selected.

Now go to AVRDude configuration section for Fuses as shown in below image. Enter fuse settings we copied from “boards.txt” to the text fields marked in below screenshot.

Enter fuse values copied from boards.txt
Enter fuse values copied from boards.txt.

Now click Start editor button. Do following:

  • Select No for BOOTRST - Boot Reset vector Enabled
  • Change start up time setting to Start-up time PWRDWN/RESET: 16K CK/14 CK + 0 ms for SUT_CKSEL - Select Clock Source.

Click OK button.

Now the fuse values boxes will get updated with new values. I got DF, DD and F9 as updated fuse values.

Finally, we can burn the Arduino using following command:

avrdude -pm168 -cusbtiny -u -Uflash:w:timer.ino.eightanaloginputs.hex:a -Ulfuse:w:0xdf:m -Uhfuse:w:0xdd:m -Uefuse:w:0xf9:m
Use your binary file name in above commadn and make sure you apply correct fuse settings. Also correct microcontroller to be specified.

If success, then you will get output similar to given below:

$ avrdude -pm168 -cusbtiny -u -Uflash:w:timer.ino.eightanaloginputs.hex:a -Ulfuse:w:0xdf:m -Uhfuse:w:0xdd:m -Uefuse:w:0xf9:m

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9406 (probably m168)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "timer.ino.eightanaloginputs.hex"
avrdude: input file timer.ino.eightanaloginputs.hex auto detected as Intel Hex
avrdude: writing flash (7950 bytes):

Writing | ################################################## | 100% 12.83s

avrdude: 7950 bytes of flash written
avrdude: verifying flash memory against timer.ino.eightanaloginputs.hex:
avrdude: load data flash data from input file timer.ino.eightanaloginputs.hex:
avrdude: input file timer.ino.eightanaloginputs.hex auto detected as Intel Hex
avrdude: input file timer.ino.eightanaloginputs.hex contains 7950 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 7.56s

avrdude: verifying ...
avrdude: 7950 bytes of flash verified
avrdude: reading input file "0xdf"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xdf:
avrdude: load data lfuse data from input file 0xdf:
avrdude: input file 0xdf contains 1 bytes
avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "0xdd"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xdd:
avrdude: load data hfuse data from input file 0xdd:
avrdude: input file 0xdd contains 1 bytes
avrdude: reading on-chip hfuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xf9"
avrdude: writing efuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xf9:
avrdude: load data efuse data from input file 0xf9:
avrdude: input file 0xf9 contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ...
avrdude: 1 bytes of efuse verified

avrdude done.  Thank you.