Today I first attempted to set up and program an ATtiny2313 AVR microcontroller mounted on an independent breadboard rather than the STK500’s own sockets. (I had until now only had chips which required external crystals — and all the crystals I had were well above their speed ratings!)

But I was getting extremely unreliable communication; avrdude would repeatedly fail to correctly read the device signature bytes or verify fuses. The failures were random; individual bytes were often correct, and very rarely the communication was completely successful. Sample failure:

avrdude: Device signature = 0x14910a
avrdude: Expected signature for ATtiny2313 is 1E 91 0A
         Double check chip, or use -F to override this check.

Or, when the signature read worked but the fuse-verify read failed:

avrdude: AVR device initialized and ready to accept instructions
avrdude: Device signature = 0x1e910a
avrdude: safemode: Verify error - unable to read hfuse properly. Programmer may not be reliable.
avrdude: safemode: To protect your AVR the programming will be aborted
That the failures are partial tells me that the chip is basically working and the programming connections are correct; there's just something marginal about the system. But what? Were my wires too long or too haywire? Did I need a closer decoupling capacitor? I got my hint while reading the ATtiny2313 datasheet's section on “Serial Downloading”:

Depending on CKSEL Fuses, a valid clock must be present. The minimum low and high periods for the serial clock (SCK) input are defined as follows:

Low:> 2 CPU clock cycles for fck < 12 MHz, 3 CPU clock cycles for fck >= 12 MHz

High:> 2 CPU clock cycles for fck < 12 MHz, 3 CPU clock cycles for fck >= 12 MHz

Hmm—what's my fck? The ATtiny2313 as shipped defaults to internal RC oscillator mode with a clock frequency of 1.0 MHz. The STK500 has a SCK period parameter, and mine’s set to: 1.1 µs. A clock frequency of 1.0 MHz (106 cycles/second) is a period of 1.0 µs (10-6 seconds), so this SCK period is way out of spec; I'm surprised it worked as well as it did.

I set the SCK period to 3 µs (the STK500 rounded it to 3.3 µs), putting it comfortably above the datasheet requirement of greater than 2 µs, and everything's working fine as far as I can tell — I haven't tried programming the chip yet, but repeated reads give no errors.

As can be found in the avrdude manual page, in order to set the SCK period, you use terminal mode (avrdude -t) and enter the command sck desired-period-in-µs. (The current period can be read with the parms command.) The tricky part is that avrdude attempts to communicate with the target chip before entering terminal mode! So you have to either keep trying until it works (-F to skip the signature check helps), or connect the STK500 to a target for which it is already correctly configured! (I haven't tried disconnecting the ISP interface entirely.)

I hope this helps the next person searching for “Programmer may not be reliable.”

This is not a complete tutorial; it is intended to collect the information that I needed to get started and didn't find obvious, particularly explaining the operations needed to compile a program, and the most basic of syntax, operators, and IO operations to use microcontroller-specific operations from C/avr-gcc/avr-libc. It does not cover designing circuits or choosing a programmer.

Needed software

Get avr-gcc, avr-binutils, avr-libc, and avrdude. If you're on Mac OS X, all three are available through MacPorts.

Setup

Create ~/.avrduderc to specify what kind of programmer you have and where it's connected. Mine looks like this:

  default_serial = "/dev/cu.KeySerial1";
  default_programmer = "stk500v1";

default_serial is the device for the serial port the programmer is attached to; default_programmer is the type of programmer; see the manual section on command line options for programmer type names. You can also specify these on the command line, but I figure since these are specific to your computer it's better to leave them unspecified in makefiles.

Writing code

  • char is 8 bits and int is 16.
  • The entry point is the normal int main(void); you don't have to do any special initialization.
  • Special registers are exposed as variables — e.g. PORTD = 0 to do output.
  • All normal variables take up scarce RAM — for constant data, use the facilities in <avr/pgmspace.h> to store it in program space.
  • Basic IO: Each port has three registers. For some port x, DDRx specifies direction: a 1 bit makes the corresponding pin an output, whereas 0 makes it an input. Reading PINx takes input from the pins; writing PORTx sets output. If DDRx has a 1 bit, then PORTx controls internal pullups on those pins.
  • For further info on the functions of the chip, read the datasheet for it; the translation into C is mostly straightforward.
  • The avr-libc manual contains info on its avr-specific features.
  • The avr-libc demo projects are informative and well-explained.

Compiling

  avr-gcc -mmcu=at90s8515 -Werror foo.c bar.c -o foo.elf

Substitute the part number of your target chip for at90s8515. I use -Werror to reduce the chances I'll run broken code on real hardware.

  avr-objcopy -O ihex foo.elf foo.hex

This step discards the metadata the .elf file contains, leaving just the code, suitable for programming.

Programming (downloading)

avrdude -p 8515 -U flash:w:foo.hex

Substitute the part number of your target chip for 8515.