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.”

Back to electronics, at least for a weekend...

After making sure to have fresh or cleaned parts, and using fresh (rather than two and a half decades old) solder, I have managed to solder several joints reasonably successfully. I completed two tiny projects:

  • I assembled a WiiChuck Adapter (it imitates a Nintendo Wii controller accessory socket and plugs into a breadboard; the accessory protocol is just I²C).
  • I soldered wires onto a rotary encoder which is part of rev. 2 of my timer project (which I should post about), which was designed for PCB mounting and doesn't fit firmly into a breadboard due to the mounting clips. (It fits, loosely, into a wide DIP socket.) Having these wires, terminated with header pin sockets, I can now mount the encoder in a box. So, I now have a nice box with a knob on it. (The rest of the project hasn't fit into the box yet.)
WiiChuck adapter
WiiChuck joints slant view
WiiChuck joints side view
Encoder joints image #1
Encoder joints image #2
Encoder joints image #3
Encoder joints image #4
Encoder joints image #5
Encoder joints image #6
Encoder joints image #7

As you can see from the pictures, the WiiChuck Adapter went together nearly perfectly. The header and board were held in position by a standard two-alligator-clip helping hands. The one ugly-looking solder joint on the “–” pin is the way it is because it was the first joint I made, and I fed too much solder into it when it started melting. I removed most of the excess, but didn't attempt to fiddle it into looking perfect.

The rotary encoder turned out considerably uglier, but then, it was a harder problem: instead of joining PCB through-holes to pins designed to fit them, I was joining wires to pins. I had the helping hands to hold the wire against the pin, but it still shifted around a bit while I was working. Overall, I'm considering the results non-disastrous and a reasonable first try. The joint on the top in the first image (with lots of copper visible) might be a bit “cold” though. I did make one mistake I recognized afterward: I did not tin either of the surfaces before soldering them, which probably would have resulted in cleaner, quicker joins and less melted insulation.

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.

One of the requirements for the timer project is that the alarm sound be not too unpleasant.

So: What can I do with the current prototype hardware, a piezo element taken from a watch connected directly to a (digital) output pin on the PIC?

Trivially, fixed-volume square waves, by either toggling the output pin in software or setting up the PIC's PWM feature to drive it automatically. (Note that the PWM produces a minimum frequency of 1/16384 of the main oscillator.)

(I've moved the piezo output on the prototype to the RC2/CCP1 pin. This change is not yet reflected in the published circuit and program.)

However, I want software volume control, so I tried something more elaborate. I set the PWM to a very high frequency, and produce the audio-frequency signal by varying the PWM's duty cycle parameter. The characteristics of the piezo crystal filter out the high frequency, producing an effectively analog output.

After much twiddling getting this to work (CCPR1L is not the least-significant bits of the duty cycle), I found that square waves work well, sine waves are very quiet, and changing the amplitude has the expected effect. So while it won't sound great, I can at least program it to increase the volume gradually.

I haven't yet integrated this into the main timer program, so I don't know whether I'll be able to produce decent tones despite (or making use of) the timer program's counting interrupt.

Timer project

Sunday, July 22nd, 2007 23:02

This is my first nontrivial electronics project. The goal is to create a better kitchen timer; over the years I’ve had many break, and the model I’m currently using has an annoying UI and is usually too loud.

Ben Jackson sent me a PIC16F877 microcontroller and a bunch of parts, and I've finally gotten around to doing something with them. (Some of the parts in the photo I already had.)

I've written a separate page with more details on the timer prototype and my plans.

Steps to get to this point: )

The big things remaining are a multi-digit LCD display, calibration to real time, better input devices, and building it into a case.

(Please let me know if you'd like more information about some part.)