|
For the AVR microcontrollers, control of
program loading to the FLASH memory, and manipulating of the fuse and
lock bits for configuring certain features of the microcontroller, can
be simply done through a PC parallel port programmer (see the cdk4avr
tools howto and references).
Many of the AVRs provide a small section
of FLASH memory with capabilities that allow it to
modify its own
FLASH memory. This is sometimes referred to as the bootblock. It
normally resides
in the top of FLASH memory and can be set, through fuse bits, to
different sizes, typically
256 bytes to 4K bytes. The microcontroller can also be configured
through a
fuse bit so that after a reset, a jump directly to the bootloader
section can be
forced, rather
than the usual jump to address 0.
For microcontrollers that have a UART,
programming can be done through
a PC serial port using the bootloader. This makes programming even
simpler, particularly for PCs and laptops that do not have a parallel
port. For those without a serial port, a commercially available USB to
serial adaptor can be
used.
Some tools developed for AVR programming
are presented here. Similar tools are available in both open source and
commercial versions, including bootloaders, PC programming control
applications and hardware programmers. The tools described here were
constructed to add some useful features.
AVR Bootloader
Atmel's application note AVR109
describes a bootloader that uses the UART to communicate FLASH
programming instructions. They also provide some sample
code in C that allows the programming of FLASH, EEPROM, and
lock bits. Note that the AVR109 bootloader does not support the
programming of fuses. The communication protocol used is compatible
with their
AVRPROG programming software.
After loading this into the bootloader section, the device can be
configured so that on reset the program counter starts at the
bootloader, and programmer software can program the FLASH memory.
The ATMEL example bootloader program
proposes the use of a
port pin on the microcontroller to signal whether to execute the
bootloader
program or to jump directly to the application. This allows a user to
set a jumper on the microcontroller card that pulls the pin low when
programming of the FLASH is
needed.
The adaptation of this code described here,
keeps it almost
unchanged in the interests
of compatibility. By disabling the port pin test and
excluding the EEPROM programming section and the AVRPROG compatibility
section, the code will fit neatly into a 1K block of the
bootloader FLASH section on ATMega48/ATMega88/ATMega168 AVRs*. Disabling
the port pin test means that on
reset the microcontroller always ends up in the bootloader program (if
the appropriate fuse bit has been set), and
must be explicitly sent out again with a bootloader exit command. For
the moment this is acceptable as the device will normally operate while
connected to a PC serial port. For standalone operation a pin will need
to be made
available to implement the port pin test, or the appropriate fuse bit
programmed to
start the device on reset at location 0.
Although the AVR109 code is freely
available,
Atmel has not released it under a clear open source licence. As such
the
modified code will not be reproduced here.
Later I may write my own bootloader or find another suitable source,
however it turns out to be difficult to produce more compact C code
than that
provided in Atmel's sample. There are
assembler versions of
the bootloader available (e.g. that by
Herbert Dingfelder) that take up less space,
however assembler code is less readable and potentially less general
than a higher level lenguage.
The changes made to
the code
are quite reasonable and
simple (most are corrections to perceived minor deficiencies):
- Modify the block read and block write functions to add a
compiler directive
REMOVE_FLASH_BYTE_SUPPORT around the FLASH programming section (be
careful of if-else clauses).
- Modify the
block read and block write functions to add a compiler directive
REMOVE_EEPROM_BYTE_SUPPORT
around the EEPROM programming section (be extra careful of if-else
clauses).
- Move the 'E' command outside of REMOVE_AVRPROG_SUPPORT so
that we can get out of the bootloader into the application.
- Add a compiler directive
REMOVE_PROGPIN_TEST around the the port pin check section. This must
also be added at the end of the "for" loop where the jump to the
application is made.
- The preprocessor.sh script can be modified to generate an
all-encompassing defines.h file covering all microcontroller types,
rather than
using the suggested cut and paste system. This makes use of the
availability of the MMCU variable in avr-gcc to identify the
microcontroller type.
To allow
the application to execute a jump into the bootloader I used an
instruction to enable the Watchdog Timer on a
very short timeout to force the MCU to be reset. There seemed to be a
problem either with the compiler or the AVR that a long jump was not
possible. This has the
advantage that it does not require the exact address of the
bootloader to be set in the code, but of course prevents the Watchdog Timer from
being used for for other purposes. I then added code to disable
the Watchdog Timer at the start of the bootloader. This turned out to
be problematical as the ATMega88 and related microcontrollers use a two
step process to prevent accidental changes to the Watchdog
Timer control registers. Therefore the code below is specific to these
MCUs.
A small amount of work will be needed to adapt it to other devices. The
wdt.h header file provided with avr-libc does not support this at the
time of writing.
For the bootloader, clear all reset flags in the MCUSR, and then
perform a write to WDTCSR to set the WDCE and WDE bits. This enables
changes to occur in a short timeframe. Then immediately afterwards wipe
the entire register to disable the
timer.
asm("cli");
asm("wdr");
MCUSR = 0;
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0;
For the application, clear all
reset flags in the MCUSR, and then perform a write to WDTCSR to set the
WDCE and WDE bits to enable changes. Then immediately
afterwards perform a write to
WDTCSR to
set the
WDE bit to
enable the timer for
system
resets only, with the timeout period set at its smallest value (about
15ms).
MCUSR = 0;
WDTCSR = (1 << WDCE) | (1 << WDE);
WDTCSR = (1 << WDE);
Programmer GUI Application
A GUI programmer
for Linux was written in QT4 and C++ (see the documentation) . This provides basic hex
file load
and
verify, and some fuse/lock bit programming for selected devices (do not
fiddle with these settings until you have carefully read and understood
the datasheets). The programmer opens a serial
port (which may need to be changed to match the target system) and
synchronizes
with the device using no parity, 1 stop bit and 8 bit data. A character
0xDD is sent and the character received back from the device is checked
for either a 0xDD or a "?". The latter indicates that the bootloader
may have been found. The 0xDD character relates to the packet protocol
used
in the Acquisition
project. If this is received, then a packet is sent
to instruct the device to jump to the bootloader. This can
be removed if the application protocol is not needed, but that is not
really necessary as the bootloader will just reject anything unknown.
If the
bootloader is not present the device will probably just reset itself.
If neither character is received, the baud rate is cyclically changed
through a
set of standard rates for a couple of cycles.

When the program has
synchronized with the device, it gathers a bunch of information and
presents the above window. An Intel hex file can be opened and will
be
immediately read and loaded to the application area of the bootloader
(the
bootloader is never overwritten by this: it can only be changed through
the parallel or SPI programming method).
The default baud rate to start with is 38400 baud. If this does not
match that of the
device, then the program will cycle through standard baud rates
between 2400 and 57600 baud until it
finds the correct one. This process can be sped up by changing the
default baud rate to match that of the bootloader.
The program allows for turning off block mode, and also allows
verification without programming and vice-versa. Autoaddress currently
does nothing so it is disabled. There is a chip erase feature provided:
normally the E button is invisible until the checkbox has been selected
to minimize accidental erasures. An erase may be necessary if the lock
bits have been set incorrectly. This requires an external programmer. A
bootloader will not reset the lock bits.
The GUI program relies on inserting delays into the serial
communications to adapt the speed of the PC to the bootloader or serial
programmer. Also when waiting for a response from the programmer, the
program will timeout if this takes too long. If problems are
experienced while programming or verifying, it may be that these delays
need to be increased. This is particularly the case if the clock speed
used with the MCU is low. The GUI program was tested with 8MHz MCU
clock frequencies and 38400 baud communications.
Additional sections have been added to enable fuse and lock bits to be
read and changed for a limited number of devices. The program uses the
device signature bytes to
identify the device uniquely, and the appropriate window is invoked.
Note that there may be bugs in this code so use it at your own risk. It
has only been partly tested.
Installation
To install
this, unpack
into a directory which by default will be serial-programmer-pc. The serial device
used (/dev/ttyUSB0 in Linux) is specified in the main program and
refers to a USB port for use with a USB to serial converter. Obtain QextSerialPort and unpack the tarball
into the directory
qextserialport, making sure
that all the source directories are under the same top directory
(otherwise the .pro files will need to be changed). Make sure that the
QT4 tools are installed and also g++. These should be readily available
for most distros. I have tested this on Ubuntu.
Go into the
directory
qextserialport and execute:
$ qmake-qt4
$ make clean
$ make
This will build the libraries. Now go into the serial-programmer-pc directory and
execute:
$ qmake-qt4
$ make clean
$ make
This
will build the application. Copy the binary to a suitable
place and invoke with:
$sudo avrserialprog
AVR Programmer
An AT90S2313 (possibly obsolete by now
but replaceable by the ATTiny2313) was used to build a small serial
programmer (described here).
This was designed to communicate serially with a PC programming
application using the AVRPROG protocol as used in the bootloader, and
to program the target AVR device using the SPI interface.
A
feature of the circuit is that when programming of a target device has
completed, an output port pin is configured to switch the serial
communications from PC to programmer order to PC to target. This allows
the programmer to remain connected after programming while the target
device program runs normally. To restore to programming mode the
programmer must be physically reset. This approach reduces a lot of
fiddling
with plugs during application development. There are two SPI connectors
in the circuit, a 10 pin header compatible with the ET-AVR series of
boards sold through Futurlec, and a 6-pin polarised header. The AT90S2313 program supports
target programming of FLASH, EEPROM, lock and fuse bits. The programmer
source code
is available but is missing a number of files that were taken from the AVR109
code, notably: defines.h, flash.h, parts.txt, preprocessor.sh,
preprocessor.xls, serial.c, serial.h. These are not reproduced here for
copyright reasons. Also provided is a gEDA schematic of the
circuit shown below.

* Note: the version of avr-gcc
available at the time of writing
produces code that is slightly larger than that produced by the cdk4avr
version of February 2006 even for the best optimization level. This is
enough to push the resulting bootloader binary just beyond the 1K limit
(enough to require the disabling of a number of desirable features).
|