November 1, 2009

Tick, Tock, Rockin the Clock with Crystal Oscillators

Yesterday I dove into Sparkfun's 3rd tutorial in the Beginning Embedded Electronics series, "What is an Oscillator?" I learned about using the AVR internal oscillator, ceramic resonators, and crystals as a clock source for my projects. Of course all did not go smoothly, which was fortunate (!) since the bumps highlighted some important things.


I started by reading a good article on clocksources on AVR Freaks. Knowing all the different sources and properties is cool, but I really didn't get a good feel for proper applications. I mean, I know the tolerances on ceramic resonators and the internal AVR osclllator aren't tight enough for your highly synchronized stuff like serial or network communication, but they are good for something, right? Besides blinking an LED, what is some other uses for ceramics and/or the internal? I'll try and look into this some more - If you have some experience with this, let me know in the comments.

I monkeyed around with the AVR internal clock by downloading the ATMega168 datasheet from the Atmel site, finding and toggling the CKDIV8 bit. As was expected; unprogramming this bit took our AVR clock output from 1MHz to 8MHz. With the "blink" code from last week still loaded, the LED on the output line started to blink faster. One confusing
thing I noted right here: the bit order listed in a fuse byte is read from bit7 to bit0, not the other way around. Seems backward, but I'll just have to remember this (it will of course, if I know myself, bite me in the ass in the future, stay tuned, heh)

I am still using avrdude on Ubuntu Linux (Intrepid) and a ponyser serial programmer. I practiced dumping the fuse bits set by executing the following on the CLI:
$ sudo avrdude -p m168 -P /dev/ttyS0 -c ponyser -U lfuse:r:-:h -U hfuse:r:-:h 
  avrdude: AVR device initialized and ready to accept instructions
    Reading | ################################################## | 100% 0.00s
    avrdude: Device signature = 0x1e9406
    avrdude: reading lfuse memory:
    Reading | ################################################## | 100% 0.00s
    avrdude: writing output file ""
    0x62
    avrdude: reading hfuse memory:
    Reading | ################################################## | 100% 0.00s
    avrdude: writing output file ""
    0xdf
    avrdude: safemode: Fuses OK
    avrdude done.  Thank you.
(I love how Avrdude thanks me. "No, thank YOU!") Setting the fuse bits is just a matter of figuring which bits you want to program, then using similar syntax to write them back out to the micro. When setting the CKDIV8 bit, I looked at the starting config of the low fuse byte (0x62) and figured out the new value when unprogramming (setting to "1") bit7. The value ends up being 0xe2. Using a calculator that does hex to binary conversions is very helpful. [NOTE: the fuse calculator in the tutorial is also tres useful: http://palmavr.sourceforge.net/cgi-bin/fc.cgi]
Next, I installed the 16MHz crystal on my breadboard, following the schematic in the tutorial. Note that at this point I feel very smug and proper, having installed caps properly, unlike the "bad engineer! bad!" image in the tutorial. This will be important later, trust me.
OK, having set up the hardware, I dug back into the ATMega168 datasheet in search of programming notes regarding selecting the external clock source which I just connected to pins 9 & 10 (PB6 & PB7). Section 1.1.3 of the Pin Descriptions section gave a nice description of the function and linked out directly to what I needed: section 8, System Clock & Clock Options. So I struggled a bit here to understand the different devices you could program up with the 4 CKSEL bits. For a minute there, I was pretty sure I had an "external clock" (0000), but after reading further, and double checking with the tutorial, I found the correct setting was "full swing XTAL oscillator" (0110). NOTE: My homework this week is to find out what qualifies as an "external clock". So, to set my 16MHz external xtal and caps setup as the oscillator, I set the low fuse bit to 11100110 (0xe6)! AND...and? Oh crap. Nothing. Nothing? As soon as I set the fuse bits on the micro, the output LED just quit. I immediatedly attempted to program the fuse low bits back to use internal RC and was met with the following bad news:
$ sudo avrdude -p m168 -P /dev/ttyS0 -c ponyser -U lfuse:w:0xE2:m

    avrdude: AVR device not responding
    avrdude: initialization failed, rc=-1
             Double check connections and try again, or use -F to override
             this check.

    avrdude done.  Thank you.
This time the "thank you" kinda stung. Not responding, thanks? Did I brick my micro with a bad config? After staring for a while, I decided to dig a little. Checked my 5V rail: all good. Checked programmer connections: all ok. Checked fuse low bit config sent (0xe6): confirmed good config. Checked crystal connection: ok. That left the caps - I rolled my eyes and went through the motions of checking the caps, then noticed something odd - "104" marked on the sides. 104? As in, 10uF. Huh, these things were supposed to be 22uF! Pulled the 2nd one, it was also the wrong value. But whatever, right? I mean the demo photo on the tutorial showed no caps at all! However, the subtext was correct. Running with no caps or out-of-spec caps is a crap shoot. The datasheet section 8.4 listed acceptable values for caps C1 and C2 at 12-22uF. I pulled the incorrect caps, installed some 22uF ceramics, and woohoo! Wicked fast blinkage on the output LED. A couple test reads/writes on the micro verified I hadn't damaged anything. Sweet!

So, reading the datasheet and double checking your work are as important as always. Got it.I thinks my flickering LED would look good in a jack-o-lantern! Maybe by next year, I can get something in for Sparkfun's Hack-o-Lantern contest!

 Next week I will be using my cool xtal clock to power some comms! Doing the "UART and Serial Communication" Lab

No comments: