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% if *%PRG==* set PRG=usbasp echo PRG=%PRG% 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 @echo Unlock and set default HFUSE so that EEPROM can be erased %AVRDUDE% %OPTS% -c %PRG% -P %PORT% -p %DEVICE% -e -Uhfuse:w:0xD9:m @timeout /nobreak /t 1 >nul @echo Erase FLASH and EEPROM, set FUSES %AVRDUDE% %OPTS% -c %PRG% -P %PORT% -p %DEVICE% -e -Uefuse:w:%EFUSE%:m -Uhfuse:w:%HFUSE%:m -Ulfuse:w:%LFUSE%:m @timeout /nobreak /t 1 >nul @echo Write FLASH and LOCK bits %AVRDUDE% %OPTS% -c %PRG% -P %PORT% -p %DEVICE% -U flash:w:%FL%:i -Ulock:w:%LOCK%:m @echo off goto cleanup :usage echo %0 goto end :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 PRG=avrisp2 Write boot loader (d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex)... Unlock and set default HFUSE so that EEPROM can be erased D:\src\optiboot>avrdude -B 1 -c avrisp2 -P usb -p atmega328p -e -Uhfuse:w:0xD9:m avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: erasing chip avrdude: reading input file "0xD9" avrdude: writing hfuse (1 bytes): Writing | ################################################## | 100% 0.01s avrdude: 1 bytes of hfuse written avrdude: verifying hfuse memory against 0xD9: Reading | ################################################## | 100% 0.00s avrdude: 1 bytes of hfuse verified avrdude done. Thank you. Erase FLASH and EEPROM, set FUSES D:\src\optiboot>avrdude -B 1 -c avrisp2 -P usb -p atmega328p -e -Uefuse:w:0xFE:m -Uhfuse:w:0xD4:m -Ulfuse:w:0xFF:m avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: erasing chip avrdude: reading input file "0xFE" avrdude: writing efuse (1 bytes): Writing | ################################################## | 100% 0.01s 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.01s 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.01s 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. Write FLASH and LOCK bits D:\src\optiboot>avrdude -B 1 -c avrisp2 -P usb -p atmega328p -U flash:w:d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex:i -Ulock:w:0xCF:m 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: reading input file "d:\src\optiboot\optiboot\bootloaders\optiboot\optiboot_atmega328E.hex" avrdude: writing flash (32768 bytes): Writing | ################################################## | 100% 0.01s 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 ISP (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.
ISP programmer recommendation
The examples above used a USBasp programmer for the reasons explained. There are many versions of USBasp hardware on the market, they have varying properties / advantages, probably come with stale firmware, and some are just a fraudulent misrepresentation. They are a trap for beginners.
For an absolute beginner, I would recommend a clone AVRisp MkII which you can buy with cables and adapter on Aliexpress for less than $25 posted. It works with AVR Studio (Microchip Studio now) and AVRDUDE, it uses WinUSB driver which comes in Windows. If you happen to buy a modified one with the links to select target power of 3.3 or 5V, take the cover off and remove the link so it does not supply target power.
I did not mention ArduinoISP because it does not deserve mention.