Customising Optiboot


I wanted to setup programming my custom Atmega328p board over Bluetooth.  Some have used the connection pin to control the Reset pin of the AVR.  However I want to use Bluetooth constantly, and only trigger a reset upon receiving a specific string sequence.  This requires tweaking the bootloader, using Optiboot as a basis:

(1) Change Baudrate to be mutually compatible with Bluebooth and AVR.
(2) Set an EEPROM byte in the main application, which could be read (and written) in the Optiboot routine.


Setting up Optiboot in the Atmel environment:
- Setup a project as usual in Atmel Studio
- Copy files over from github to the project folder: optiboot.c, pindefs.h, stk500.h and boot.h. EDIT: It seems there is an AtmelStudio folder already set up on github.

Setting baud rate to be compatible with AVR and Bluetooth module: 57600 bps

- Insert #define BAUD_RATE 57600 (as required) into optiboot.c.
- Compile and link project with following settings:
Compiler Misc: -g -Wall -Os -fno-split-wide-types -mrelax
Linker Misc: -Wl,-section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe  -Wl,--relax -nostartfiles -nostdlib


Reading/writing EEPROM in Optiboot:
Under certain circumstances, I want to be able to reset the chip with a watchdog timer and enter programming mode - but I don't want every Watchdog reset to enter the bootloader programming mode.  I felt the simplest solution was to write an EEPROM byte (address 0) to 1 in the main code (not shown), trigger a watchdog reset, and then read the EEPROM byte at address 0 in the bootloader.  The EEPROM 'programming' byte is then set back to default (0xFF).

By default EEPROM read/write isn't supported - there might be a simple way of enabling it by #define SUPPORT_EEPROM, but this didn't work for me.  I take the following original code:

if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
      appStart(ch);

which checks if the reset was caused by Watchdog timeout, brownout, or power on reset, and if so, launches the main application.

Using the Atmega328 datasheet (pages 25-26) we can implement the EEPROM read/write check:

uint8_t ebyte;

// Read EEPROM programming byte (address 0)
while(EECR & (1<<EEPE));  // Waits for EEPROM to be available
EEAR = 0;  // Address 0
EECR |= (1<<EERE); // EEPROM Read Enable
ebyte = EEDR; // Read byte

if (ebyte!=1) // Check if programming byte at address 0 has been set or not
{
  if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
      appStart(ch);


// Write EEPROM programming byte (address 0) - set to 0xFF
while(EECR & (1<<EEPE)); // Waits for EEPROM to be available
EEAR = 0;   // Address 0
EEDR = 0xFF;  // Set data as 0xFF
EECR |= (1<<EEMPE); //Set Master Write Enable
EECR |= (1<<EEPE); // Set EEPROM Write Enable

Writing .HEX file to Atmega328p chip
Burn fuses:
avrdude -p m328p -c usbtiny -U lfuse:w:0xFF:m -U hfuse:w:0xDE:m -U efuse:w:0x05:m
Burn bootloader (you'll find the *.hex file in the Debug folder):
avrdude -p m328p -c usbtiny -e -U flash:w:MyOptiboot.hex 

It works!  I can trigger programming when a specific string is sent over Bluetooth, and then program over Bluetooth.  There are a couple of caveats with using the HC-05 module with my custom board, which I cover here.

Comments

Popular posts from this blog

Getting started with the Pro Micro Arduino Board

Arduino and Raspberry Pi serial communciation