Timers ROCK - Climber's info on AVR programming

The timers are the facilities built in to the AVR that do Pulse Width Modulation (PWM), counting external events, keeping time, frequency generation and other cool things.

In the simplest terms all timers do is increment or decrement by 1 the value of a register (TCNTx) with each pulse of the clock fed into it. It is what we do with this value that makes timers interesting.

Such values can be MAX (the maximum value the counter can store), certain fixed constants, a value in another register or zero. The doodad inside the AVR that does all this is the compare unit. It continuously compares the counter value with what we ask it to and triggers certain events whenever there's a match; hence the term "compare match."

Each timer is different in it's resolution (16 bits or 8 bits), what things we can use for TOP (described below), what I/O pins are accessible by the counter (not all timers are attached to an I/O pin), what we can use for a clock and what events the timer triggers as it counts.

These events can activate a certain type of interrupt (which is the only way to execute arbitrary code on such events) or set/clear/toggle the value of an I/O pin.

The things that we, as the human oppressor, can adjust while setting all this up are:

how fast it counts up or down by specifying the clock source and the prescale. I call this the input frequency.
what it does when (if) it reaches the value of TOP which can either be MAX, a certain fixed value or the value in either an output compare register (OCRx) or input capture register (ICRx).
what it does when (if) it reaches the value in the OCRx register if it isn't being used as TOP.

It is these events that makes timers so DANG useful.

There are three timers on the mega8, timer0 (8-bit), timer1 16-bit and timer2 (also 8-bit). Timer2 has an access to one I/O pin (oc2) and timer1 (16 bit timer) has access to two I/O pins (OC1A and OC1B). The remaining 8 bit timer, timer0, has no external access on the mega8.

The count for each is stored in the TCNTx register (16 bits on timer1). The counters always count up from zero except when counting down during the second half of "phase correct PWM" that timer1 and 2 can do. Timer0 always counts up.

We can set control bits to adjust how the counters work. The timers have several control bits in common:

CSxy - Clock Select - Usually used to define the pre-scale value. These are the only bits we can twiddle for timer0 other than to enable the interrupt or adjust the clock source that is shared between timer0 and timer1.

WMGxy - Waveform Generation Mode - configures timer to do PWM, frequency generation, etc. by defining what to use as TOP and what happens to TCNTx when it reaches there or MAX. These bits also are partially responsible to define what happens to the OCxy pins in these modes along with the COMxy pins described below.

COMxy - Compare Output Mode - defines how an external pin is affected by the timer. IMPORTANT! You need to set the bits in the appropriate DDRx register to configure those pins as outputs.

All three timers can be programmed to trigger an interrupt when the timer passes MAX. Timer1 and 2 can trigger an interrupt when the counter matches what's in the OCRx register. Timer1 also has an interrupt that can trigger from the input capture.

Any other bits used to configure the timers are either described below or are too boring for me to bother with.

TIMER 0

Let's start with timer 0. It's the simplest of the timers on the mega8 and it does not have access to an I/O pin. Because of that it can't directly be used for PWM or as an external frequency generator without resorting to fancy code.

The mega88 hugely expands on timer0 giving it more options for what to use as TOP and two I/O pins for use along with matching compare units. The hoops we jump through below ALL GO AWAY when we make use of the expanded features.

Anyways, on the mega8 timer0 doesn't have a compare unit. It just counts from 0 to 255 over and over. There's only one interrupt that happens when it overflows (goes from 255 back to 0). This timer is about as boring a timer as you can get in the AVR world.

The frequency that it operates at is equal to the input frequency divided by 256. -That's it.- With it's incredible boringness and the limitations of the built-in prescales of 8, 64, 256 or 1024 the timing events that result from timer0 and up with some odd numbers. This makes it hard for us to use the timer and have the output frequency fall on to any clean boundaries like, say, one hundred times per second. However, there are a couple of things we can do about this.

The first is we aren't necessarily stuck to using crystals, clocks or resonators that have frequencies evenly divisible by 1 million. That's what those other funny crystal frequencies like 15.36 MHz and 18432000 Hz do. They are not just for nailing the precise clock rate for the USART. They also divide nicely by 256 and several of the prescales. With that we can have an interrupt routine that can give us timing more in line with the way we humans like to think.

For example, the 14.7456 MHz crystal divided by 256 gives us 57600. Divide that by a prescale of 64 means our interrupt routine would get called 900 times a second. If we keep our own counter and only do something every 9th time we now have a precise 100hz time base.

Beauty.


TIMER 2

Let's move on to timer 2. It's not as complex as timer1 which we will leave to the last.

The MAX for timer2 is 255 since it is 8 bit. We have two choices of what to use for TOP: 0xFF (MAX) or whatever we put in to the OCR2 register. This counter counts up most of the time but can count down if we are using "phase correct PWM." Let's stick with counting up in this tutorial.

Timer 2 can run on one of four "wave generation modes" defined by the WGM20 and 21 bits:

NORMAL MODE (WGM20=0; WGM21=0)

counter always counts up
overflows to zero after reaching MAX (255)
can trigger interrupt when timer overflows back to zero
can trigger interrupt when TCNT2 = OCR2
can set, clear or toggle OC2 pin when TCNT2 = OCR2 but pointless to use anything but toggle.
frequency = clock/(2 * prescale * 256) in this mode it is nearly as boring as timer0.

CTC (clear timer on compare) or COMPARE OUTPUT MODE (WGM20=0; WGM21=1)

can be used for a nicely variable timebase or generating a variable frequency square wave on the OC2 pin (frequency generation)
counter always counts up
starts back at zero when TCNT2 = OCR2 (i.e. never reaches MAX unless ORC2 = 255).
can trigger interrupt when TCNT2 = OCR2 (and overflow if ORC2 = MAX) frequency = clock/(2 * prescale * (1 + ORC2))

FAST PWM MODE (WGM20=1; WGM21=1)

used for pulse width modulation (i.e. good for motors)
counter always counts up
overflows to zero after reaching MAX (255)
can trigger interrupt on overflow
can trigger interrupt when TCNT0 = OCR2
frequency = clock/(2 * prescale * 256)
can clear OC2 on OCR2 match/set OC2 on overflow (regular PWM)
can set OC2 on OCR2 match/clear OC2 on overflow (inverted PWM)

PHASE CORRECT PWM MODE (WGM20=1; WGM21=0)

ahh, see the PDF.

Normal mode and CTC mode are good for internal timing and don't really need the OC2 pin unless you want to do external frequency generation. Fast PWM/phase correct PWM mode really needs to be connected to the OC2 pin to have any real meaning in life.

The COM20 and 21 bits tell us what happens to the OC2 pin as the counter does it's thing. Depending on the mode we are running at we can either set, clear or toggle OC2 whenever we reach MAX or equal to what is in OCR2.

Since it is so useful in robotics let's look deeper at fast PWM mode with the COM settings for non-inverted PWM.

We can tell the AVR to put a hi out onto the OC2 pin when it reaches MAX and put a low when it reaches what we have in OCR2. This will generate a square wave on the OC2 pin. The frequency of this square wave is 1/256 of the frequency of the clock going into the counter. That's cool but this isn't all. IF OCR2 is small then the amount of time the wave spends at hi will also be small. If OCR2 is large then the wave will spend most of it's time at high. In other words, the shape of the wave is proportional to the value of OCR2. This is PWM or pulse width modulation.

For example, if we put 50 into OCR2. For 50 clock ticks as the counter counts from zero to 50, OC2 will be high. The AVR then sees that OCR2 and TCNT match (this is what the manuals mean by compare match). The AVR now switches OC2 to a low. The counter will keep counting to 255. When it flops back to zero, OC2 will go high again and so on. So, for about 20% of the time OC2 will be high; a 20% duty cycle. 50 is about 1/5 of 255 so the duty cycle is proportional to the value of OCR2 over 255.

Let's go back to the frequency of the PWM. In PWM mode the counter always counts up to 255. The only way to adjust the frequency is either change the system clock, use the TOSC1/2 pins with a crystal (uses two I/O pins) or use the prescaler. The prescale allows us to divide the input clock by preset values (0, 8, 32, 64, 128, 256 or 1024). As timer2 can only count up to 255 in PWM mode we only have 7 different pwm frequencies to choose from when using the prescale unit. If we want to choose a PWM frequency other than that then we have to resort to software tricks to have the timer reach MAX sooner or use the 16 bit timer.

What frequency to choose: higher frequencies are more efficient for the motor but less efficient for the H-bridge. The frequency I like to use is at least 1000hz and up to the limit of my H-bridge. The 754410, for example, is pretty much limited to 4 KHz. With a 16 meg clock the absolute fastest PWM frequency we can get from the system clock is 62.5KHz. That's too fast. Dividing that by 32 gets us 1953 hz. Try that and hook up your frequency counter to OC2. I like to choose a prescale that will land us a PWM frequency in the acceptable range. Other H-bridges such as the motorola MC33887 can go up to 10 KHz (in the PDF or 20 KHz according to their web page). Some PWM devices such as the SI9986 can switch in the 100KHz range. We'll get more into that in motor control


TIMER 1

Timer 1 is much like timer2 but BIGGER

The 16 bit timer can also do PWM and it's much better at it. First it has two compare units and pins (OC1A and OC1B). This means we can have two complete separate PWM channels although both must operate at the same frequency.

Second, with 16 bits in the counter instead of just 8 it increases the resolution or the number of different duty cycles we can use from 256 to 65536. This is very important when we want to use the 16 bit counter to control a hobby servo. For just motors 256 steps is often sufficient (in fact, my bots typically only use 16 or 32 steps in my code). Another advantage of the 16 bit counter is that we can adjust the frequency of the PWM beyond the methods above for the 8-bit counters above. This is also very important to controlling servos.

If you look in the manual timer1 has many more cool things that we can do. There are 4 WGM bits instead of just two. Table 39 tells us what those modes can do. We can use OCR1A, ICR1 and various fixed values as TOP. We can also choose to use 8, 9, 10 or 16 bit PWM. Cool.

Timer1 can also do input capture. That's for another tutorial once I find a purpose for using it.

Timer 1 uses the same clock source as timer0 (although with a different prescale unit). We can also make use of an external clock source instead of using the internal clock. It's different than timer2 which has pins for a crystal. For timer0/1 the external clock needs a clean signal like from an oscillator module.

I mentioned earlier that timer1 is awesome for controlling servos. We do this by telling the AVR to use the value of ICR1 as TOP instead of 255 (or 65535 or one of the other predefined max values). Therefore we can increase the base frequency (clock / 255 / prescale) by reducing the size of ICR2 from below 65535.

Now, why in the world would we want to use a timer to do servo control? The answer: because it is really, really easy. Now, why in the world we we want to use the 16 bit timer for servo control rather than the 8 bit timer? Well, it has to do with resolution and the way hobby servos work. A hobby servo uses a PWM duty cycle to determine where to swing the arm to. At the minimum allowable cycle the arm is swung to one extreme and at the maximum allowable cycle the arm is swung to the other extreme. For most servos one extreme is the duty cycle being on for 1 milliseconds and the other for 2 milliseconds. The frequency of the PWM is around 50 Hertz.

What that means is that the duty cycle from one extreme to the other for servos ranges from only 5 to 10% of the total PWM signal. That is, only 5% of the total choices in duty cycle that we have available for PWM is used to swing the servo arm from one extreme to the other. With 8 bit PWM that means we only have 12 individual locations the arm can swing to. That's usually not useful for anything interesting. With 16 bit resolution we now have 3276 (potential) maximum positions. That's a bit better.

Now, let's talk about how ICR1 is going to help us out with servos. A PWM frequency fo 50 Hz is hard to nail if you just use the system clock and prescale. Instead of dividing the clock by 255 to find the frequency like we are stuck with on timer 2 we can divide by any value we like from 1 to 65535 by putting it into ICR1 and setting the WGM bits to use it as TOP. With a 16 MHz clock using an ICR of 40000 and prescale of 8 we end up with a PWM frequency of 50 Hz. Perfect. Now, to move the servos all we have to do is assign a value of 2000 to 4000 (5 to 10% of 40000) to OCR1A or OCR1B to control the servo hooked up to the matching OC1A or OC1B pin.

The downside: because the clocks, prescale and value in ICR1 affects both sides of the 16 bit timer if we want to control one servo and do motor PWM with the other we are stuck with a frequency of only 50 Hertz. This can be bad for the motor. Therefore, the mega8 can safely control 3 motors or 1 motor and 1 servo. If you want to do 2 motors and a servo you either need to write your own PWM software (yuck) or live with a very low PWM frequency. This is why the mega88 is so beauty or why I generally go to a larger processor as soon as I start having to resort to software weirdness to solve my problem.


EXAMPLES

Complete motor control with PWM

The mega8 has three pins that can do PWM. Pins 15 and 16 (OC1A and OC1B) are controlled by the 16 bit timer and pin 17 (OC2) which is controlled by timer2, one of the two 8-bit timers. Why would you use one over the other? Well, the big thing is resolution. With an 8-bit timer you have only 256 steps or "speeds" to choose from. If you want more you will need to make use of the 16-bit timer.

For this example I am going to use 8 bits since I want to control three motors in more or less the same manner. As timer2 is limited to 8 bit resolution and I would prefer they all operate in the same way that's what I want for all three. Fortunately, the AVR is designed so that we can use the 16 bit timer with 8 bits if we choose. Besides, 256 steps is quite sufficient for our purposes.

For the H-bridges this example will use two of the SN754410 quadruple half-bridges. These chips are totally beauty because they can handle relatively large amounts of current and are internally equipped with back EMF diodes. This makes it easy for us to use. We will use all of one chip and half of the other for this example.

Here is the circuit we'll use.

If you have already perused the mega8 manual you may have noticed that with the internal RC (resistor-capacitor) oscillator already built in we can get by without crystals. I went with a crystal in my design because, later, the hardware will expand to use the serial communications module (USART) and I found that, at least for me, my serial communications were unreliable until I started using a crystal. All of the designs I use for examples will have them.

IMPORTANT!!! This design assumes a smokeless H-bridge!!!!! That means, it must be able to handle both enable inputs of the bridges being either hi or lo at the same time!!!!! The L298, L293 or the SN754410 can do this. Make sure yours can as well before hooking this up!!!!!! You have been warned. Why in world would I want to turn on both halves of an H-bridge! For the brake function!

First, we need to choose a PWM frequency. This is how fast we turn the motor(s) on and off. I like to use as high a frequency as possible because it is better for the motors and a little more efficient (at the motor). However, if we go too high the H-bridge efficiency starts to suffer. Usually, 1 to 4 kilohertz is good even though the motors will make an irritating whine.

An important thing to watch for when using 1-4 kHz frequencies are coreless brushed motors. Because of the lack of cores they can suffer from serious arcing and brush erosion if the frequency is too low. In the electrically powered remote controlled model airplane world (yet another hobby I indulge in) the PWM-based speed controls for coreless motors use frequencies of 60 to 150 kilohertz. Big capacitors across the motor terminals help a little.

So, let's make some code. We want the appropriate pins to act as outputs. PB1 is for OC1A, PB2 OC1B and PB3 for OC2. Unless we tell the mega8 otherwise these pins are configured as inputs. So, we'll set up some output ports to control motor direction.

DDRB = _BV(DDB1)   // OC1A motor 1 PWM
     | _BV(DDB2)   // OC1B motor 2 PWM
     | _BV(DDB3);  // OC2  motor 3 PWM
DDRD = _BV(DDD0)   // motor 1 A
     | _BV(DDD2)   // motor 1 B
     | _BV(DDD3)   // motor 2 A
     | _BV(DDD4)   // motor 2 B
     | _BV(DDD5)   // motor 3 A
     | _BV(DDD6);  // motor 3 B

DDRB is the Data Direction Register for port B. A "1" in a particular bit means the corresponding pin will be configured for output. DDRD does the same thing but for port D. Note that the term "port" simply referes to a collection of I/O pins.

You will note that each motor has two controls: "A" and "B". I use one pin for each half of the H-bridge to control both directions plus allow for a brake function.

Next, we want to set up the registers. First, timer1 (the 16-bit timer). Note that the 16-bit timer has two useable PWM channels although the settings below will apply to both.

// set up PB1 and PB2 with 8bit PWM
TCCR1A = _BV(WGM10)    // 8 bit fast PWM, see WGM12 below
       | _BV(COM1A1)   // set OC1A/B on compare match, clear them at
top
       | _BV(COM1B1);
TCCR1B = _BV(CS11)     // 1/8 prescale
       | _BV(WGM12) ;  // fast PWM

Setting WGM10, 11, 12 and 13 with 1, 0, 1 and 0 sets us up the 16 bit timer with 8 bit fast PWM. That seems to work for me. Setting COM1A1 and COM1B1 to 1 sets the desired mode. CS11 sets up the clock prescale and selects the PWM frequency. Note how the WGM 10 through 13 bits are spread across the TCCR1A and B registers.

The formula on page 89 of the mega8l PDF gives the formula for the fast PWM frequency. With an 8 megahertz clock used for the Fclk_I/O and TOP being 255 (table 39 on page 97 with WGM10 and WGM12 set) this gives us a PWM frequency of 3906.25 Hertz. Reasonably fast and still useable with H-bridges. Just to check, I plugged my frequency counter into OC1A (pin 15) to verify. 3907. Close enough.

Interestingly enough, a 0% duty cycle means (to me at least) that there is no signal going out that channel. Hooking up a scope shows a steady ground-level line. However, my frequency counter was still able to count the right frequency. Neat. Sensitive device. By the way, I got my frequency counter as a kit from Weeder Techologies. I don't know if they have the kit any more but many good multimeters include a frequency counter function.

Now, using an 8 megahertz clock means I have twiddled the "fuses" on my AVR. If you aren't ready for that step yet it's no biggie. This will still all work. By default, the mega8 comes from the factory pre-set to use the internal RC clock at 1 MHz. Plugging that into the formula means PWM frequencies of 488 Hz. If that's ok, go for it. If you also want 3906 Hz then just don't set the prescale bits (CS11 above and CS21 below). Don't forget, the prescale determines the ratio of the system clock that is piped into the timers.

Now, we still want to use the third PWM channel controlled by the second 8-bit counter. WGM20 and 21 set up the mode and CS21 uses the same prescale value as timer1 above. See the formula on page 111 of the manual.

// set up PB3 for 8 bit PWM
TCCR2 = _BV(WGM20)     // timer 2 fast PWM
      | _BV(WGM21)     // ditto
      | _BV(COM21)     // clear OC2 on compare match, set OC2 at TOP
      | _BV(CS21);     // 1/8 prescale

Once this is done we are good to go. The PWM for these channels is started as soon as the code above executes. After that, all we have to do is put the right value into the right register to determine the duty cycle. OCR1A controls the duty cycle of PB1, OCR1B for PB2 and OCR2 for PB3. For example:

OCR1A = 127;    // motor 1
OCR1B = 127;    // motor 2
OCR2 = 127;     // motor 3

Since we are using 8-bit PWM that means we can assign values from 0 to 255. 127 is halfway there. That means a 50% duty cycle on the motors. Note that because of good 'ol friction and the inescapable physics of motors that doesn't mean we get 50% of the RPM out of the motor we would get at full throttle but we have to start somewhere.

This here program has the whole shootin match. It will fire up motor 1 and slowly ramp it up to full speed, hold it there for a sec, slow it down and halfway there slam on the brakes. It will do the same for motor 2 and then motor 3. After that, it does the whole cycle over but with the motors running in reverse. This will demonstrate motor control including using brakes that some H-bridges can do.

DON'T FORGET MY WARNING ABOUT USING SMOKELESS H-BRIDGES!!!!!!!!!!!


Servo control with timer1

Here's some example code of using timer1 to do servo control (assume an 8MHz clock). Except for the clock speed this is precisely the same code I used to control my servos for my automated solar roller racing track.

// set up counter 1 (16 bit) to act as a dual channel PWM generator
// we want OC1A and B to be set on reaching BOTTOM, clear on reaching
// compare match, use ICR1 as TOP and have a prescale of 8.
TCCR1A = _BV(COM1A1) // set OC1A/B at TOP
       | _BV(COM1B1) // clear OC1A/B when match
       | _BV(WGM11); // mode 14 (fast PWM, clear TCNT1 on match ICR1)
TCCR1B = _BV(WGM13)
       | _BV(WGM12)
       | _BV(CS11); // timer uses main system clock with 1/8 prescale
ICR1 = 20000; // used for TOP, makes for 50 hz PWM
OCR1A = 1500; // servo at center
OCR1B = 1500; // servo at center
DDRB = _BV(PB1)
     | _BV(PB2);  // have to set up pins as outputs

To change the servo position all you have to do is assign a value to OCR1A or B. With an 8 MHz clock the normal range you use is 1000 to 2000. I especially like it at 8 MHz because the timing for normal servo control is pulse widths of (usually) 1.0 to 2.0 milliseconds. Just multiply that by 1000 and you get the value to assign to OCR1A or B.

If you want to use a different system clock then all you have to do is adjust the value you assign ICR1 and the useable range to assign OCR1A and B to control the servos is 5% to 10% of the value you use for ICR1. For example, for a 1 MHz clock (like the default RC clock from the factory) use 2500 for ICR1 and 125 - 250 for the range of values to give OCR1A and B.


Using timer 2 for regular timing

PWM isn't the only purpose of counters. We can also use the counter to have the AVR do stuff on a regular basis.

What I like to do often is have one of the timers interrupt the processor on a regular basis so I can keep track of time. Counter 1 and 2 are perfect for the job because we can use the OCRx registers to control the interval. If we leave timer1 for the motors we can make use of timer2. We could use timer0 but it's lack of a compare unit means we have to resort to stupid software tricks or hardware compromises to give us a reasonable timer resolution.

Say we want to keep millisecond time. That is, interrupt the processor once every millisecond so we can poll something or update system time. What we will do is change the timer so that instead of starting over at zero when it reaches 255 it will start over when it reaches something we put into OCR2. Between the timer2 clock prescales (which have more choices than timer0) and OCR2 we can pretty much set up any timer resolution we like.

First, the prescale. We need to choose one that that will result in a timer frequency that when again divided by a number from 0 to 255 will result in a frequency that we want. For a 16 MHz clock 64 is a good choice. That gives us 250000. Divide that by 250 and we get 1000. Bingo. Here we go:

TCCR2 = _BV(WGM21)    // CTC mode, TOP is OCR2
     || _BV(CS22)     // prescale of 64
TIMSK |= _BV(OCIE2);  // enable compare match interrupt
OCR2 = 250;
sei();

Now, all you need is an interrupt handler for SIG_OUTPUT_COMPARE2. This just toggles the PB3 pin.

SIGNAL(SIG_OUTPUT_COMPARE2)
{
  static unsigned char ison;

  if (ison)
  {
    ison = 0;
    cbi(PORT3, PB3);
  }
  else
  {
    isone = 1;
    sbi(PORTB, PB3);
  }
}

Whenver we want to do time sensitive work we should verify it before going on and having the rest of the system depend on it. The signal handler above toggles the PB3 pin. You can also do that without having to do it in the handler with this:

TCCR2 = _BV(WGM21)    // CTC mode, TOP is OCR2
     || _BV(COM20)    // toggle OC2 pin
     || _BV(CS22);    // prescale of 64
TIMSL |= _BV(OCIE2);  // enable compare match interrupt
OCR2 = 250;

Don't forget to set DDRB to 1 for that pin for both methods. For either case, connect a frequency counter to pin 17 to ensure it is 500 hertz. Why not 1000 Hertz? Because it changes state 1000 times a second and that has to happen twice for there to be one complete cycle (which is what we are measuring).

When we use a timer like this we have to be careful of the frequency we choose. Because an interrupt forces the processor to drop whatever it is doing to handle it we don't want to do it too often. Otherwise the processor won't get anything done! With a 16 MHz clock and an interrupt happening every 1/1000 of a second the processor can do about 16000 other instructions in between. That's ok.


to email Craig send to climber at shaw.ca (replace at with @ and remove spaces).
Check out what's new on Craig's pages.
Return to Craig's main page.

Last modified: April 32, 2007 - YAWWWWNNSSVILLEE!!