WriteOptiBoot.bat

I have lots of projects across a range of microcontroller architectures where reliably programming a new instance of the target is required.

Using an IDE to compile and load, eg traditional / common use of the Arduino IDE, is not a path to that reliability.

A better approach is to save compiled binaries, and have a saved method of programming the chip, binary application code, EEPROM if needed, and hardware settings such as fuse bits, options etc.

Let’s look at an example,  a cmd file or bat file to program certain Arduino architecture boards with a customised Optiboot bootloader.

Custom Optiboot example

The customised Optiboot loader can read and write EEPROM, and it does not flash the LED on startup (which can disrupt the application’s use of that pin).

The two binaries mainly used are ones for:

  • 16MHz AtMega328P*; and
  • 8MHz AtMega328P* (as found on 3.3V boards).

Programming these is a production job, when I buy a lot of say 10, I want to program them reliably and quickly.

WriteOptiBoot.bat

The programming commands and parameters are encasulated in a Windows bat or cmd file as follows.

@echo off

echo.
echo Processing
echo.
set FL=
rem custom Optiboot, 1k, no LED flashes, r+w EEPROM
rem if *%FL%==* set FL=d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328.hex.hex& rem 8MHz Pro mini, 57600 serial
if *%FL%==* set FL=d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex

echo FL=%FL%
set PRG=usbasp
set PORT=usb
rem set -B 10 for 8MHz Pro
set OPTS=-B 1
set DEVICE=atmega328p
set AVRDUDE=avrdude
rem preserve EEPROM
rem AVRDUDE now likes unused fuse bits set to 1
set EFUSE=0xFE& rem 0xFE for 1.8V BOD, 0xFD for 2.7V, CFD enabled (328P)
set HFUSE=0xD4& rem HFUSE=0xD6 (std Optiboot), HFUSE=0xD4 1k boot sector
set LFUSE=0xFF
set LOCK=0xCF& rem protect boot sector

:flash
echo.
echo Write boot loader (%FL%)...
echo.

echo on
%AVRDUDE% %OPTS% -c %PRG% -P %PORT% -p %DEVICE% -e -Ulock:w:0xFF:m -Uefuse:w:%EFUSE%:m -Uhfuse:w:%HFUSE%:m -Ulfuse:w:%LFUSE%:m
@timeout /nobreak /t 1 >nul
%AVRDUDE% %OPTS% -c %PRG% -P %PORT% -p %DEVICE% -U flash:w:%FL%:i -Ulock:w:%LOCK%:m
@echo off
goto cleanup

:cleanup
echo.
:end
pause

The console log from a single operation follows:

D:\src\optiboot>writeoptiboot

Processing

FL=d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex

Write boot loader (d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex)...


D:\src\optiboot>avrdude -B 1 -c usbasp -P usb -p atmega328p -e -Ulock:w:0xFF:m -Uefuse:w:0xFE:m -Uhfuse:w:0xD4:m -Ulfuse:w:0xFF:m

avrdude: set SCK frequency to 750000 Hz
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: erasing chip
avrdude: set SCK frequency to 750000 Hz
avrdude: reading input file "0xFF"
avrdude: writing lock (1 bytes):

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

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0xFF:

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

avrdude: 1 bytes of lock verified
avrdude: reading input file "0xFE"
avrdude: writing efuse (1 bytes):

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

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xFE:

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

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

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

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xD4:

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

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

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

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xFF:

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

avrdude: 1 bytes of lfuse verified

avrdude done.  Thank you.


D:\src\optiboot>avrdude -B 1 -c usbasp -P usb -p atmega328p -U flash:w:d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex:i -Ulock:w:0xCF:m

avrdude: set SCK frequency to 750000 Hz
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e950f (probably m328p)
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: set SCK frequency to 750000 Hz
avrdude: reading input file "d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex"
avrdude: writing flash (32768 bytes):

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

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex:

Reading | ################################################## | 100% 0.01s

avrdude: 32768 bytes of flash verified
avrdude: reading input file "0xCF"
avrdude: writing lock (1 bytes):

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

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0xCF:

Reading | ################################################## | 100% 0.01s

avrdude: 1 bytes of lock verified

avrdude done.  Thank you.


Press any key to continue . . .

Important things to check are that all the verify checks are correct and reconcile with the bytes written.

Note that the process uses lock bits to protect the boot loader segment from being written by errant (or otherwise) application flash code. The bootloader can only be replaced using ICSP (or HVP).

One of the very important benefits of this method of working is that it reduces the risk of writing wrong fuse bits to a chip, fuse bits that might make recovery very difficult. The batch file captures the important details of a particular application, and minimises the risk of finger trouble.

But what about those marvelous GUIs that everyone just loves?

Above, the default fuse settings when AVRDUDESS is opened. Hitting the Write button may make changes that are very difficult to recover, serial programming on many AVR chips will be disabled by such fuse settings. Some common fuse traps are inadvertedly disabling serial programming, setting an external clock or crystal for hardware that doesn’t have such, setting an extremely low freq internal clock (too slow for the programmer SCK in use).

Chips can be removed from the board, and wrong fuses fixed with a HVP, but some kind of fixture will be needed to connect to the isolated chip.

Above, another kind of jig that is really handy for programming TQFP32 chips  on or off board (I have lots of things with AtMega328 chips and no ISP pads)… though of course to use a HVP on board, the reset pin has to be isolated.

Don’t mess the fuses up!

So, this article is not just about OptiBoot (which is a good thing), but a method of working that is applicable not just to boot loaders but to developed projects across a range of architectures and platforms.