Pages

Friday, June 17, 2011

Generate a Clock Signal with AVR ATmega

Several times lately my MCU needed to generate a clock signal to interface with a device, such as a camera, or a serial interface on an analog to digital converter (ADC).

Rather than bit-banging the clock signal, let the MCU's timer hardware do the work, freeing up cycles for real code.

Here's how to generate a simple, 50% duty cycle pulse train, aka clock signal, using an AVR MCU. For this experiment I used an ATmega328P but any of the AVR chips that support a 16-bit Timer1 should do.

I wanted a 500kHz clock signal. To generate it, the MCU must toggle an output pin, PB1 aka OC1A at 1MHz, or 1/16 the MCU's 16MHz clock, for a total period of 2us (500kHz).

Timer1 provides a mode called Clear Timer on Compare Match (CTC). The timer register, TCNT1 counts from 0 up to the value in the Output Compare Register, in this case OCR1A (to go along with the OC1A output). When TCNT1 == OCR1A, the MCU resets TCNT1 and starts counting again.

Ok, let's get started with the code.

Though we probably don't need to, why not initialize the counter:

TCNT1=0;

To run the timer at 1MHz, we need to divide the MCU clock by 16. Using a prescaler value of 1, we simply set the output compare register to 15, since the timer counts from 0-15 or 16 ticks.

So we come up with:

OCR1A = 15;

Note that we could also have used a prescaler value of 8 and an OCR1A of 1.

Now it's time to set some mode bits. The AVR has three Timer/Counter Control Registers for timer 1: TCCR1A, TCCR1B and, you guessed it, TCCR1C. In TCCR1A, two bits control the behavior of OC1A when the timer matches OCR1A. Those two bits are COM1A1 and COM1A0. When set to 01, OC1A is toggled when there's a compare match.

TCCR1A |= (1<<COM1A0);

To tell Timer1 to operate in CTC mode, we set bits WGM13, WGM12, WGM11, WGM10 across two control registers. Actually for CTC mode, WGM12=1 and the rest are 0 (initial value on powerup)

TCCR1B |= (1<<WGM12);

To configure Timer1 prescaling, set bits CS12, CS11 and CS10 in TCCR1B. For no prescaling, use 001, respectively. That is, set CS10=1

9 comments:

Hi this is really one of the things I need. thanks for the post. However, I'm having some problems with the results, the output pin is PB1, right? but when I connect it to the oscilloscope, I see frequency of only 100 kHz... thanks,,, I really need some help here.... I need at least 500 kHz for my project... thank you

@Anonymous: I just measured mine and it's running ~470kHz on a 16MHz ATmega328P. That's off by about 5% but that's much better than a 500% error :) We'll figure this out. :)

No offense intended but are you counting divisions correctly? Most scopes show tiny hash marks that equal 0.2 division. The big grid marks count as 1 division.

I set my Hitachi V-1050F's time/div to 1us and the ~500kHz signal shows up with a 2us period = 500kHz. (If you accidentally counted each hash as a division you'd get a 10us period = 100kHz which would explain your off-by-500% result)

hi! i'm a beginner in using microcontroller..i have questions and hope you can gives some pointers or tips..can atmega generate 2 clock signals?? it's because i need 2 clock signals that will be connected to a CCD sensors (charge-couped device)to activate the CCD,these 2 clocks are needed..for the ROG clocks (read-out gate) and CLK..is it possible??

First of all I want to thank you for the time and effort you spend to provide this solution.

I spend nearly two hours to find out, why the solution you provided did not work with my setup (Arudino UNO with 1.0 dev. environment).

I had to actually reset the TCCR1A and TCCR1B registers, because they were initalized with 1 resp. 3??? (No modification done to either board or dev. environment), also I had to move the OCR1A init after the TCCR1A / TCCR1B init, otherwise it still had 0 and the timer didn't start ... (Complete code see below ...)