you@there$ apt-get install gcc-avr binutils-avr avr-libc simulavr
The hardware between the computer and the microcontroller is called the "programmer". The programmer could simply be a cable or it could be a PCB full of extra features. When the microcontroller may be programmed without removing it from its circuit they call it In-System Programming (ISP).
The UISP man page defines one of its supported cables (dasa) as: dasa (RESET=RTS SCK=DTR MOSI=TXD MISO=CTS), which seems like nothing but four wires and that is all it is.
Beware of incorrect serial cable pin-outs, which are available on the web. Such a pin-out is the reason behind the unusual colours of the wires in the photo. Below is the correct pin-out.
The following table shows how to connect a 9-pin serial port to an ATtiny26:
AVR pin ATtiny26 pin serial pin DB9 pin wrong colour MOSI 1 TxD 3 green MISO 2 CTS 8 orange SCK 3 DTR 4 white RESET 10 RTS 7 red
No more is required than is shown on the left. The battery pack is connected to the black and red wires at the top of the image. Dip switch 1 connects power to all red buses on the breadboard. All light blue buses are ground. The upside-down potentiometer is a handy resistor with a long wire and is connected to switch 4 allowing it to pull the light blue wire (connected to RESET on the ATmega32) to ground. The ATtiny26 is grounded and otherwise unconnected on the right. The two LEDs and two resistors on the left are the ATmega32 test circuit and the ones on the right are the same for the ATtiny26. Bypass capacitors are visible either side of the ZIF socket. If you're in New Zealand, components are available over the Internet from Dick Smith's Electronics and the South Island Component Centre. |
Check that your programmer works like so:
you@there$ uisp -dserial=/dev/ttyS0 -dprog=dasa --rd_fuses..which may tell you:
Probably the AVR MCU is not in the RESET state. Check it out and run me again...but if the programmer is working then it will say:
Atmel AVR ATtiny26 is found.
Fuse Low Byte = 0xe1
Fuse High Byte = 0xf7
Fuse Extended Byte = 0xff
Calibration Byte = 0xa6 -- Read Only
Lock Bits = 0xff
BLB12 -> 1
BLB11 -> 1
BLB02 -> 1
BLB01 -> 1
LB2 -> 1
LB1 -> 1
..or for the ATmega32:
Atmel AVR ATmega32 is found.
Fuse Low Byte = 0xe1
Fuse High Byte = 0x99
Fuse Extended Byte = 0xff
Calibration Byte = 0xb6 -- Read Only
Lock Bits = 0xff
BLB12 -> 1
BLB11 -> 1
BLB02 -> 1
BLB01 -> 1
LB2 -> 1
LB1 -> 1
"dasa" worked for me roughly one time in ten. Manually pulling RESET low (with dip switch 4 in the photo) allowed me to program reliably with the remaining three wires. A second attempt to program the microcontroller without first allowing RESET up is prompted by:
Cannot identify device because it is locked. Device similar to the ATmega103-old is found. Device is locked. Address out of memory range.
Allowing RESET up and then pulling it low again allows the microcontroller to be programmed again.
A typical session goes:
The pin-out of the microcontroller can be found in the "complete" document for your microcontroller model from Atmel (see references). The pin-out will be required to build the test circuit.
An int is 16 bits in size. A long contains 32 bits and libc will link in small routines for 32-bit arithmetic.
Start the program to be debugged like this:
you@there$ simulavr -d atmega16 -P simulavr-disp -g monitor.bin
Then do this to gdb (note that you give monitor.elf to gdb while giving monitor.bin to simulavr).:
you@there$ gdb monitor.elf Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-linux"...Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1". (gdb) target remote localhost:1212 Remote debugging using localhost:1212 0x00000000 in __vectors () (gdb) cont Continuing. Reply contains invalid hex digit 59 (gdb)There is automatically a breakpoint in main, which is why gdb stopped. The simulavr-disp window will show the CPU stopped at the address of main. To see where in the source it has stopped, do this:
you@there$ avr-objdump -m avr -Sl monitor.elf | less
The "AVR instruction set" from Atmel (see references) will help you see what the compiler has done to your source code.
DB-9 DB-25 Signal Direction Desc 1 8 DCD <<-- Data Carrier Detect (Modem connected to another) 2 3 RxD <<-- Receives bytes into PC 3 2 TxD -->> Transmits bytes out of PC 4 20 DTR -->> Data Terminal Ready (I'm ready to communicate) 5 7 GND n/a Signal Ground 6 6 DSR <<-- Data Set Ready (I'm ready to communicate) 7 4 RTS -->> Request to Send (flow control) 8 5 CTS <<-- Clear to Send (flow control) 9 22 RI <<-- Ring Indicator (telephone line is ringing)(taken from UISP 20050207)
#include <avr/io.h>
#define true 1
// delay for a minimum of <millis>
// with a 1Mhz clock, the resolution is 1 ms
void delay_ms( unsigned int millis )
{
// Note: this function is faulty, see avrm8ledtest-0.2.tar.gz for
// updated code.
unsigned int outer1;
unsigned int outer2;
for ( outer1 = 50; outer1; outer1 -- )
{
for ( outer2 = 1000; outer2; outer2 -- )
{
while ( millis ) { millis --; }
}
}
}
int main( void )
{
/* INITIALIZE */
/* enable PA0 as output */
DDRA |= _BV(PA0);
/* BLINK, BLINK ... */
while ( true )
{
/* switch the LED off */
PORTA &= ~_BV(PA0);
delay_ms( 500 );
/* switch the LED on */
PORTA |= _BV(PA0);
delay_ms( 500 );
}
}
# Compiler flags, paths for include files and libraries PROJECT = blink TARGET = attiny26 #TARGET = atmega32 CC = avr-gcc OBJCOPY = avr-objcopy CFLAGS = -mmcu=$(TARGET) -Os -Wall $(DEBUG) INCLUDES = -I. SRC = $(PROJECT).c OBJ = $(SRC:.c=.o) UISP_OPTS = -dserial=/dev/ttyS0 -dprog=dasa # "-c" means compile but don't link .c.o: $(RM) $@ $(CC) -c $(CFLAGS) $(INCLUDES) $*.c # Targets... all: $(OBJ) $(PROJECT).hex: $(PROJECT).elf $(OBJCOPY) -j .text -O ihex $(PROJECT).elf $(PROJECT).hex $(PROJECT).bin: $(PROJECT).elf $(OBJCOPY) -j .text -O binary $(PROJECT).elf $(PROJECT).bin $(PROJECT).elf: $(OBJ) $(CC) $(CFLAGS) -o $(PROJECT).elf -Wl,-Map,$(PROJECT).map $(OBJ) simulate: $(PROJECT).bin simulavr -d atmega16 -P simulavr-disp $(PROJECT).bin identify: uisp $(UISP_OPTS) --rd_fuses erase: uisp $(UISP_OPTS) --erase upload: $(PROJECT).hex uisp $(UISP_OPTS) --upload if=$(PROJECT).hex clean: rm -f *.o *.elf *.map *.hex *.bin $(PROJECT)