A simple bootloader for the xmega that uses a raw HID interface so it can
work without drivers. It uses the internal RC oscillator for the USB clock.
It also allows for application code to write to flash using the functions
given in spm_interface.h
. Released under MIT software license.
To use the python flashing script you python,
hidapi library. The python libraries
cffi
and intelhex
are also needed. To install them use:
pip install cffi intelhex
To build the bootloader run:
make
The commands make program
and make program-fuses
can be used to flash the
hex file and configure the fuses. For more information read the makefile.
To use the bootloader, run:
./scripts/flash.py -f hex_file
It will search for the first device that matches, and attempt to program it.
To program a specific device instead use:
./scripts/flash.py -d VID:PID -s "<serial_num>" -f hex_file
To list available devices use
./scripts/flash.py -l
For more help use:
./scripts/flash.py -h
On power up the bootloader will by default run the application code if present. There are 3 ways to enter the bootloader:
- Unprogrammed flash
- Reset button
- Software reset into bootloader
If the flash at address 0 is 0xffff
, then the bootloader assumes that
the device is unprogrammed and runs the bootloader code.
The bootloader can also be run by pressing the reset button (bring RST pin low). The bootloader will then attempt to establish a USB connection. If it can't, it will reset and enter the application code if present. If no application code is present then it will keep reseting until it can establish a USB connection.
To determine if a USB connection is present, the bootloader has 2 strategies available.
- An IO pin that monitors VBUS. The pin can be set with
CHECK_PIN
andCHECK_PORT
inconfig.h
. - Checking for USB SOF packets. If no SOF packet is received before
WATCH_DOG_PERIOD
expires, then the bootloader will reset into the application section. The default value is to wait 2s before rebooting.
The IO pin strategy has the advantage of being able to reset instantly when no USB connection is present, but it requires an extra IO pin.
If the reset button is pressed again while the bootloader is running then the bootloader will reset into the application section. This allows you to reset the xmega while a USB connection is present by pressing the reset button twice.
To enter the bootloader from software
#define BOOTLOADER_MAGIC 0x97e1e28e
#if defined(__AVR_ATxmega32a4u__)
#define BOOTLOADER_FLAG_ADDRESS 0x802400
#else
#define BOOTLOADER_FLAG_ADDRESS 0x802700
#endif
void software_reset(void) {
// use xmega software reset functionality
asm volatile("cli\n\t" // disable interrupts
"ldi r24, 0xD8\n\t" // value to write to CCP
"ldi r25, 0x01\n\t" // value to write to SWRST
"ldi r30, 0x78\n\t" // base address of RST peripheral
"ldi r31, 0\n\t"
"out __CCP__, r24\n\t"
"std Z+1, r25\n\t" // +1 is the offset of RST.CTRL
::); // no clobber list because we don't return
}
void reset_to_bootloader(void) {
*((uint32_t*)BOOTLOADER_FLAG_ADDRESS) = BOOTLOADER_MAGIC;
software_reset();
}
At power up the bootloader fills SRAM with the value 0xCC
. This is done
to prevent newly loaded firmware from extracting SRAM data from the previously
loaded firmware. It can also serve as a debugging aid.
The only values that will not be filled with 0xCC
is the 4 bytes at
BOOTLOADER_FLAG_ADDRESS
which are used to pass data to and from the
bootloader when the device is reset. The data at this location is still cleared
before the application code is run, just not necessarily to the value 0xCC.
To write to the flash of AVR XMEGA it is necessary to use the spm
instruction
which can only execute from code in the bootloader section. Several functions
are provided in a jump table at the end of the bootloader to allow writing
flash from the application section. To use these functions include
spm_interface.h
from the application code.
For the bootloader to work correctly, it needs to clear some of the flags
in the RST.STATUS register. So to allow the application code to see these flags,
it makes a copy of RST.STATUS register at the address
BOOTLOADER_FLAG_ADDRESS 0x802400/0x802700
(ATxmega32a4u uses 0x802400
,
others mcu use 0x802700
). Also, if the bootloader itself is reset
while it is running, then bit 0
at 0x802401/0x802701
is set.
The application code should still clear the RST.STATUS flags it uses as the
bootloader does not clear all reset flags.
This code is released under the terms of the
MIT software license. See the LICENSE
for more information.