Oct 262014

Earlier this week I had an idea.  We’ve got an old clock radio that picks up interference from the fridge when it turns on and the buttons on it are starting to fail with age.

I thought: “Why not build a new one?”

So the requirements are simple.  We need a real-time clock, display driver, and of course, a receiver.  The unit we have spends most of its time tuned to 792kHz AM (4QG or “ABC Radio National”), so a simple direct conversion receiver was what I was thinking of.  But what about the LO?

Now I do have some clock radio ICs that implement the timing circuitry, alarm function and LED panel driver somewhere in a junk box.  You feed them with the 50Hz or 60Hz waveform that comes out of the transformer and they use that as the timing source.  Easy to use a 555 timer for the time source, and I’d make a traditional receiver.  Another option is to use a AVR microcontroller, I have a few ATMega8Ls in the junk box with a NXP I2C RTC chip which I also have a few of.

The ATMega8L has a couple of PWM channels one 16-bit and one 8-bit: could they be used as an LO?

So: after digging around and locating my bought-years-ago and not-yet-used AVR programmer, and dusting off a breadboard that had an ATMega8L on it from a previous experiment I set to work.

This page explains in good detail how the PWM channels work. I started with those examples as a guide and tweaked from there.

For the PWM channel to work as a receiver LO, I want it to cover 540kHz to ~2MHz, with reasonable granularity. Question is, how far can I crank this? I have a 4MHz crystal, not the fastest I can use with this chip, but the absolute top of the range for the ATMegas isn’t much higher: 16MHz or maybe 20MHz. So if you’ve got a 16MHz crystal, you can expect to quadruple what I do here.

I started off with some blink code. If you take out all the delays, you get the following code:

#include <avr/io.h>
int main(void)
        DDRB |= (1 << DDB1);
        while (1)
                PORTB ^= (1 << DDB1);

and the following waveform:

Waveform done in software with GPIOs

Waveform done in software with GPIOs

The yellow waveform there is off one of the crystal pins. The cyan one is the PWM pin output, which in this case is a software driven GPIO. Even if this one worked, you wouldn’t want to do it this way unless your chip was doing only this task, and who’d use a programmable chip like an ATMega8L for that?

So, after reading through the documentation and examples, I loaded in the following code:

#include <avr/io.h>

#define TCCR1_COM1A     1
#define TCCR1_COM1B     0
#define TCCR1_FOC1A     0
#define TCCR1_FOC1B     0
#define TCCR1_WGM1      0xf
#define TCCR1_ICNC1     0
#define TCCR1_ICES1     0
#define TCCR1_CS1       1
#define TCCR1A_VAL      (                       \
                        (TCCR1_COM1A    << 6)   \
                |       (TCCR1_COM1B    << 4)   \
                |       (TCCR1_FOC1A    << 3)   \
                |       (TCCR1_FOC1B    << 2)   \
                |       (TCCR1_WGM1 & 0x3)      )
#define TCCR1B_VAL      (                       \
                        (TCCR1_ICNC1    << 7)   \
                |       (TCCR1_ICES1    << 6)   \
                |       (((TCCR1_WGM1 & 0xc) >> 2) << 3) \
                |       TCCR1_CS1)

int main (void)
        DDRB |= (1 << DDB1);
        OCR1A = 0x001;
        TCCR1A = TCCR1A_VAL;
        TCCR1B = TCCR1B_VAL;

The frequency can be adjusted by playing with OCR1A. If I leave it at 1 (basically as fast as the PWM can go) I get the following:

Waveform from AVR PWM

Waveform from AVR PWM

Bump it up one, and it sinks to 600kHz. Way too coarse for what I want sadly. I guess I was hopeful, but maybe the above might serve as a useful spring-off point for experiments with PWM.