1. What?

This is a hardware/firmware which connects to a PC via a serial port (or usb-to-serial-converter) and enables it to flash/program/read/verify/debug microcontrollers of the AVR family by http://www.atmel.com

2. Purpose

There already are some programmers around, but I wanted to have additional features:

  • Provide several interfaces to the target hardware with adjustable voltage levels: SPI, UART, TWI.

  • Use any of these interfaces to connect to the target hardware while it is up and running in order to read/write variables (debug helper).

  • Modular software to make using different hardware implementations easy. Porting to another hardware should not touch a large number of files.

3. Origin

Lots of things (protocol for AVR109 and AVR910) have been taken from Klaus Leidinger’s avr910\_2313\_v37e.asm.

4. Hardware

4.1. Connectors

I do not use standard connectors for several reasons.

4.1.1. SPI connector to target

In contrast to the usual connector, this one contains a pin which connects to the /SS pin of the target to help debugging it.

4.1.2. Serial connector (PC, target)

The serial connector features a VCC output and a VCC input. Examples uses:

  • a serial-to-usb converter will provide +5V at its VCC output pin

  • the avrdev hardware can be powered by the serial-to-usb converter which is used to connect it to the PC

  • the avrdev hardware can be used to power the target hardware via the serial link which is used for debugging

Voltage levels on TXD and RXD are not UART-like, but 1.8V..5V.

4.2. Controller

The programming hardware itself uses an AVR, so you need to be able to program that one in the first step…

4.3. Target interface: voltage levels

The voltage level of the output pins on the SPI and UART interface is adjustable via software ([lAVRDebug]). Note that levels on both interfaces can be different.

The variable voltage output is made using PWM output, an opamp and transistors. At 5.0V supply voltage, the PWM outputs are able to provide nearly 5V, but the opamp may not. I used a LM358, which gives 3.8V. However, this is sufficient for an AVR, which recognizes high level at 0.6\*VCC and above. At VCC\_max=5.5V it would be sufficient to provide 0.6\*5.5V=3.3V.

Use a rail-to-rail type or the jumper to get higher voltages.

5. Supported devices

This programmer should be able to handle the devices which can be handled using other AVR910-type programmers, too…but I currently have limited the device-data-tables to devices which I have actually tested:

  • ATMega8

  • ATMega16

  • ATMega48 (not thoroughly tested, but I was able to flash/verify the device)

  • ATMega644

  • ATMega128

  • ATMega8535

  • AT90S4433A

  • AT90S8515A

  • AT90S8535

Adding another device should be easy (just add a line with three values from the datasheet, compile).

6. Usage

The application AVRDebug ([lAVRDebug]) can be used to adjust voltage levels and debug the target device.

In order to flash/verify program memory, eeprom and fuses, I have only used this programmer with avrdude on the PC, but there are lots of others talking the same protocol.

Some devices (for example 8535) need to leave reset state and resync after memory erase. Therefore use avrdude in two steps: first erase using -D, program in a second step using -e to inhibit auto erase.

Sadly, avrdude changed its behaviour after version 5.2, so using it is not that easy and straightforward as it used to be.

6.1. avrdude <= 5.2

These versions are nice, because they allow you to have unified scripts (usually part of the make system) in all of your AVR projects to read/write everything of your AVR; you only need to supply the string ID of the device (for example m64 for the ATMega64). Aside from this ID the rest of the avrdude command line is just the same, no matter which device is connected.

read/write eeprom, erase/write/verify flash on any device: -c butterfly

read/write fuses, read calibration byte on any device: -c avr910

6.2. avrdude 5.3.1

This version did not work for me, but I didn’t care about finding out why…

6.3. avrdude >= 5.4

These versions show a strange behaviour with -c butterfly, I’ll go into details here and first describe what happened up to version 5.2:

  1. avrdude knows which device is connected by the string ID (option -p) and looks up the corresponding avr910_devcode in its config file. Let’s assume we want to program an ATMega16; its avr910_devcode is 0x74.

  2. avrdude asks the programmer about which device codes it does support. The programmer will respond with a list of codes, for example (0x68, 0x74, 0x43). If the needed code (0x74 in this case) is not included in the list, avrdude would stop here.

  3. avrdude tells the programmer "hey, there is a 0x74 connected, adjust yourself to it".

Starting from 5.4, the behaviour changed. In step 3, avrdude does not send the avr910_devcode for the connected device, but some other code (the first one from the list of supported codes). As the programmer needs this code to correctly adjust itself to the device, it will fail now.

Starting from firmware 0.7, this programmer has a workaround: it simply ignores the code sent by avrdude, identifies the device by its signature bytes and adjusts itself to it. This does work in any case.

However, there is another problem: avrdude does not use block mode with byte mode devices since 5.4. This is no problem for other programmers, as they implement byte transfer AND block transfer — this one does not do so: byte transfer is slow (and even more if you’re using a usb-to-serial-converter); this one does only provide block transfer and is smart enough to use the correct programming algorithm.

6.3.1. Workaround using avrdude.conf

You can workaround this problem by editing avrdude.conf. For example, I added paged, page_size, and num_pages to the 8535:

memory "flash"
    paged           = yes;
    size            = 8192;
    page_size       = 128;
    num_pages       = 64;
    min_write_delay = 9000;

Just use page_size = 128 and num_pages = size / page_size.

6.3.2. Workaround by recompiling avrdude

Edit avr.c: remove && mem->page_size != 0 in avr_read and avr_write, the resulting lines are

if (pgm->paged_load != NULL) {

and

if (pgm->paged_write != NULL) {

Compile, install.

7. avrdebug

The software to adjust voltage levels and debug the target device can be found here:

7.1. Debugging the target using avrdebug

avrdebug talks to avrdev using a block oriented serial protocol. avrdev talks to the target using a simple SPI protocol or (when using the UART) a simple serial protocol; both of them are explained in the documentation of avrdebug. Furthermore there are code examples which show how to implement both protocols for the AVR.

8. TWI/I2C interface

avrdev is able to act as a TWI/I2C interface even while debugging a device. However, I didn’t publish an application to use this feature yet.

9. Details

9.1. Debugging the target

Both the firmware on the adapter and the software on the host PC are not designed to debug via SPI, UART and SELF at the same time. This means you can only debug one target, although three can be connected at the same time. I thought that this will rarely be neccessary.

9.2. Optimization for speed in debug mode

Some things have been tweaked especially for usb to serial converters, but offer an enhancement with standard serial ports, too (see below). One can read a range of addresses in one command and it is possible to send a set of commands which are not answered before the whole block of commands has been received. Using such a usb to serial converter, exchanging a little number of big packets is faster than a high number of small packets (half duplex mode).

Stateless communication is not used because the hardware is not able to receive/send on its (hardware) uart and doing a software uart or spi at the same time.

For example, my prototype has a buffer of 128 bytes to receive commands from the host (PC). I tested writing 512 bytes on the target, which takes 512 single commands. Baudrate is only 19200 baud. There is no real communication to a target (uDebugMode==DEBUG\_SELF). The host PC runs linux 2.6.8. I measured the complete runtime of the program, which includes some additional communication not included in the calculation below (syncing to adapter, reading status information).

commands: 512\*6 Bytes (plus 25\*6 Bytes when using command blocks)
replies: 512\*2 Bytes
4096 Byte -> 2.13 seconds at 19200 baud
4246 Byte -> 2.21 seconds at 19200 baud
using a usb-serial converter:
time with command blocks : 2.8 s
time without command blocks : 8.6 s
using standard serial port:
time with command blocks : 2.6 s
time without command blocks : 4.0 s

Latest modification: 02.05.2009 00:00
Jens W. Wulf

Impressum
Datenschutzerklärung