I recently discovered that I was unable to program AVRs with my usual method (the AVRDUDE parallel-port programmer) as I no longer own a working computer with a parallel port. I had purchased an Olimex SAM7-H64 board with an Atmel ARM chip and all I/Os exposed on headers, and figured that it would make a fine AVR programmer.
The SAM7-H64 board has a USB interface for connection to a PC, and lots of I/Os exposed on nice pin header sockets. Wiring can be totally avoided by plugging the header sockets directly in to the 6-pin AVR ISP headers I put on AVR projects, all that remains is to persuade the ARM to send programming commands to the correct pins.
The only way round I could physically fit the SAM7-H64 on my board meant that the following connections were made:
|AVR ISP pin||signal||SAM7-H64 pin|
Whilst the SAM7-H64 runs the ARM on 3.3V, the I/Os are 5V-tolerant, and conveniently a 5V-powered AVR interprets the 3.3V logic levels as highs (and crucially also interprets the 3.3V RESET input as high).
The AVR In System Programming algorithm is fairly simple, consisting of 4-byte commands sent over SPI, which return a 4-byte response (infact, the last byte of read commands is ignored, required only to clock back the response from the chip). The commands are documented in this Atmel datasheet.
Helpfully, the AT91 ARM chips come pre-programmed with the 'SAM-BA' bootloader, a simple environment providing register and memory access, and the ability to run uploaded code. It is possible to write directly to the I/O registers with commands from the host, allowing the pins to be set and accessed, without any writing any ARM code.
To communicate with the SAM7-H64 the python script uses pyusb, sending simple serial commands to the first endpoint. The SAM-BA protocol is described here, the interesting commands being the 'write word' and 'read word' ones.
A procedure in the code sends SPI commands to the AVR, and reads the response, by bit-banging the SPI pins using the writeWord and readWord routines. This is effective, but very slow (every SPI bit requires about 50 USB bytes, over four transactions). An alternative method was implemented, which uses a small C routine (based on flashif.c from Sam I Am) uploaded to the ARM to receive the SPI bytes directly and write them out. This increases the performance by several orders of magnitude.
There is very little circuit protection, it would probably be possible for an errant circuit to roast the ARM chip, and possibly even the USB port. Some current-limiting resistors and chunky clamping diodes would make everything safer, but make this hack less convenient.
The SPI timing characteristics are largely guesswork - observe the hideous delay loop in the target SPI routine. It wouldn't be hard to work out the clock speed, read the datasheet and set the delays to something accurate.
Download / Instructions
Released under the GNU GPL, contains code borrowed from Sam I Am and intelhex.py by Alexander Belchenko. Use at your own risk, etc.
Download here: samba-avr-0.1.tar.gz
To run, unpack the file, cd to the folder, and run:
sudo python samba-avr.py
To erase the AVR flash, use:
sudo python samba-avr.py -erase
To program the code flash memory, use:
sudo python samba-avr.py -write file.hex
Presumably there are other common ISP headers that this could be made to work with, and the same trick should allow a whole range of devices to be programmed with the same SAM7-H64 board.