At last! Yet another tutorial, this one covering a topic which is the main source of frustration to those new with AVRs; timers. What are they, and what can they do for us?

Introduction - The AVR Timer

The timer systems on the AVR series of Microcontrollers are complex beasts. They have a myriad of uses ranging from simple delay intervals right up to complex PWM (more on this later) generation. However, despite the surface complexity, the function of the timer subsystem can be condensed into one obvious function: to time.

We use timers every day - the most simple one can be found on your wrist. A simple clock will time the seconds, minutes and hours elapsed in a given day - or in the case of a twelve hour clock, since the last half-day. AVR timers do a similar job, measuring a given time interval.

The AVR timers are very useful as they can run asynchronous to the main AVR core. This is a fancy way of saying that the timers are separate circuits on the AVR chip which can run independent of the main program, interacting via the control and count registers, and the timer interrupts. Timers can be configured to produce outputs directly to pre-determined pins, reducing the processing load on the AVR core.

One thing that trips those new to the AVR timer is the clock source. Like all digital systems, the timer requires a clock in order to function. As each clock pulse increments the timer's counter by one, the timer measures intervals in periods of one on the input frequency:

Timer Resolution = (1 / Input Frequency)

This means the smallest amount of time the timer can measure is one period of the incoming clock signal. For instance, if we supply a 100Hz signal to a timer, our period becomes:

For the above example, our period becomes .01 seconds - so our timer will measure in multiples of this. If we measure a delay to be 45 timer periods, then our total delay will be 45 times .01 seconds, or .45 seconds.

For this tutorial, I will assume the target to be a MEGA16, running at at 1MHz clock. This is a nicely featured AVR containing certain timer functionality we'll need later on. As modern AVRs come running off their internal ~1MHz RC oscillator by default, you can use this without a problem (although do keep in mind the resultant timing measurements will be slightly incorrect due to the RC frequency tolerance).

In the sections dealing with toggling a LED, it is assumed to be connected to PORTB, bit 0 of your chosen AVR (pin 1 of DIP AVRMEGA16).

To start off, we will deal with basic timer functionality and move on from there.

Part One - Timers running at Fcpu

We'll start with a simple example. We'll create a simple program to flash a LED at about 20Hz. Simple, right?

First, let's look at the pseudo-code required to drive this example:

Set up LED hardware
Set up timer
WHILE forever
IF timer value IS EQUAL TO OR MORE THAN 1/20 sec THEN
Reset counter
Toggle LED
END IF
END WHILE

Very simple. We're just starting out, so we'll use the polled method of determining the elapsed time - we'll put in an IF statement in our code to check the current timer value, and act on it once it reaches (or exceeds) a certain value. Before we start on the timer stuff, let's create the skeleton of our project:

#include
int main (void)
{
// TODO: Set up LED hardware
// TODO: Set up timer
for (;;)
{
// TODO: Check timer value, reset and toggle LED when count matches 1/20 of a second
}
}

Extremely simple. I'm going to assume you are familiar with the basics of setting up AVR ports as well as bit manipulation (if you're uncertain about the latter, refer to this excellent tutorial). With that in mind, I'll add in the LED-related code and add in the IF statement:

Now we need to start dealing with the timer. We want to do nothing more than start it at 1MHz, then check its value later on to see how much time has elapsed. We need to deviate for a second and learn a little about how the timer works in its most basic mode.

The AVR timer circuits come in two different widths, 8 and 16 bit. While the capabilities of the two timer types differ, at the most basic level (simple counting), the only difference is the maximum amount of time the timer can count to before overflowing and resetting back to zero. Those familiar with C will know that an unsigned eight bit value can store a value from 0 to (2^8 - 1), or 255, before running out of bits to use and becoming zero again. Similarly, an unsigned 16 bit value may store a value from 0 to (2^16 - 1), or 65535 before doing the same.

As the name suggests, an 8 bit timer stores its value as an eight bit value in its count register, while the 16 bit timer stores its current count value in a pair of eight bit registers. Each advancement of the counter register for any AVR timer indicates that one timer period has elapsed.

Our project needs a fairly long delay, of 1/20 of a second. That's quite short to us humans, but to a microcontroller capable of millions of instructions per second it's a long time indeed!

Our timer will be running at the same clock speed as the AVR core to start with, so we know that the frequency is 1MHz. One Megahertz is 1/1000000 of a second, so for each clock of the timer only one millionth of a second has elapsed! Our target is 1/20 of a second, so let's calculate the number of timer periods needed to reach this delay:

So running at 1MHz, our timer needs to count to 49999 before 1/20th of a second has elapsed - the normal calculated value is decremented by one, as the 0th count of the timer still takes one tick. That's a very large value - too large for an 8 bit value! We'll need to use the 16 bit timer 1 instead.

Firstly, we need to start the timer at the top of our main routine, so that it will start counting. To do this, we need to supply the timer with a clock; as soon as it is clocked it will begin counting in parallel with the AVR's CPU core (this is called synchronous operation). To supply a clock of Fcpu to the timer 1 circuits we need to set the CS10 bit (which selects a Fcpu prescale of 1 - more on that later) in the TCCR1B, the Timer 1 Control Register B.

Now, with only one line of code, we've started the hardware timer 1 counting at 1MHz - the same speed as our AVR. It will now happily continue counting independently of our AVR. However, at the moment it isn't very useful, we still need to do something with it!

We want to check the timer's counter value to see if it reaches 1/20 of a second, or a value of 49999 at 1MHz as we previously calculated. The current timer value for timer 1 is available in the special 16-bit register, TCNT1. In actual fact, the value is in two 8-bit pair registers TCNT1H (for the high byte) and TCNT1L (for the low byte), however the C library implementation we're using helpfully hides this fact from us.

Let's now add in our check to our code - it's as simple as testing the value of TCNT1 and comparing against our wanted value, 49999. To prevent against missed compares (where the timer updates twice between checks so our code never sees the correct value), we use the equal to or more than operator, ">=".

Great! We've only got one more line of code to write, to reset the timer value. We already know the current value is accessed via the TCNT1 register for Timer 1, and since this is a read/write register, we can just write the value 0 to it once our required value is reached to rest it.

And there we have it! We've just created a very basic program that will toggle our LED every 1/20 of a second at a 1MHz clock. Testing it out on physical hardware should show the LED being dimmer than normal (due to it being pulsed quickly). Good eyesight might reveal the LED's very fast flickering.

Next, we'll learn about the prescaler so we can try to slow things down a bit.

Part Two - Prescaled Timers

In part one of this tutorial we learned how to set up our 16-bit timer 1 for a 1/20 second delay. This short (to us humans) delay is actually quite long to our AVR - 50,000 cycles in fact at 1MHz. Notice that Timer 1 can only hold a value of 0-65535 - and we've almost reached that! What do we do if we want a longer delay?

One of the easiest things we can do is to use the timer's prescaler, to trade resolution for duration. The timer prescaler is a piece of timer circuitry which allows us to divide up the incoming clock signal by a power of 2, reducing the resolution (as we can only count in 2^n cycle blocks) but giving us a longer timer range.

Let's try to prescale down our Fcpu clock so we can reduce the timer value and reduce our delay down to a nice 1Hz. The Timer 1 prescaler on the MEGA16 has divide values of 1, 8, 64, 256 and 1024 - so let's re-do our calculations and see if we can find an exact value.

Our calculations for our new timer value are exactly the same as before, except we now have a new prescaler term. We'll look at our minimum resolution for each first:

Now, we want to see if there is a prescaler value which will give an *exact* delay of 1Hz. One Hertz is equal to one cycle per second, so we want our compare value to be one second long, or 1000000uS. Let's divide that by each of our resolutions and put the results in a different table:

The results are interesting. Of the available prescaler values, we can immediately discount 256 and 1024 - they do not evenly divide into our wanted delay period. They are of course usable, but due to the rounding of the timer count value the resultant delay will be slightly over or under our needed delay. That leaves us with three possible prescales; 1, 8 and 64.

Our next task is to remove the values that aren't possible. On an 8-bit timer, that means discounting values of more than (( 2 ^ 8 ) - 1), or 255, as the value won't fit into the timer's 8-bit count register. For our 16-bit timer, we have a larger range of 0 to ((2 ^ 16) - 1), or 65535. Only one of our prescaler values satisfies this requirement - a prescale of 64 - as the other two possibilities require a timer count value of more bits than our largest 16-bit timer is capable of storing.

Let's go back to our original timer program and modify it to compare against our new value of 15624, which we've found to be 1 second at a prescale of 64 and a Fcpu of 1MHz:

Note I've removed the timer setup line, as it is no longer valid. We want to set up our timer to run at Fcpu/64 now. To do this, we need to look at the datasheet of the MEGA16 to see which bits need to be set in which control registers.

Checking indicates that we need to set both the CS10 and CS11 prescaler bits in TCCR1B, so let's add that to our program:

Compile it, and we're done! Remembering that our timer runs as soon as it gets a clock source, our program will now work, flashing the LED at a frequency of 1Hz.

Part Three - Long Timer Delays in Firmware

So far, we've learned how to use the timers in their most basic counting mode to delay a specified duration. However, we've also discovered a limitation of the timers - their maximum duration that their timer count registers can hold. We've managed to get a 1Hz delay out of a prescaled 16-bit timer with a prescale, but what if we want a delay of a minute? An hour? A week or year?

The answer is to create a sort of prescaler of our own in software. By making the hardware timer count to a known delay - say the 1Hz we created earlier - we can increment a variable each time that period is reached, and only act after the counter is reached a certain value. Let's pseudocode this so we can get a better understanding of what we want to do:

Set up LED hardware
Set up timer
Initialise counter to 0
WHILE forever
IF timer value IS EQUAL TO 1 sec THEN
Increment counter
Reset timer
IF counter value IS EQUAL TO 60 seconds THEN
Toggle LED
END IF
END IF
END WHILE

The above pseudocode will build on our last experiment - a timer with a one second count - to produce a long delay of one minute (60 seconds). It's very simple to implement - all we need extra to our last example is an extra IF statement, and a few variable-related lines. First off, we'll re-cap with our complete code as it stands at the moment:

We need some code to create and initialise a new counter variable to 0, then increment it when the counter reaches one second as our pseudocode states. We also need to add in a test to see if our new variable reaches the value of 60, indicating that one minute has elapsed.

Now that we have our new program's structure, replacing the TODOs becomes very simple. We want a target count of 60, which is well within the range of an unsigned integer variable, so we'll make our counter variable of type unsigned integer. The rest of the code is extremely simple, so I'll add it all in at once:

Compile and run, and the LED should toggle once per minute. By extending this technique, we can produce delays of an arbitrary duration. One point of interest is to note that any timing errors compound - so if the timer input frequency is 1.1MHz rather than 1.0MHz our one minute timer will be sixty times that small error out in duration. For this reason it is important to ensure that the timer's clock is as accurate as possible, to reduce long-term errors as much as possible.

Part Four - The CTC Timer Mode

Up until now, we've been dealing with the timers in a very basic way - starting them counting, then comparing in our main routine against a wanted value. This is rather inefficient - we waste cycles checking the timer's value every time the loop runs, and slightly inaccurate (as the timer may pass our wanted compare value slightly while processing the loop). What if there was a better way?

Well, there is. The AVR timers usually incorporate a special function mode called "Clear on Timer Compare", or CTC for short. The CTC operating mode does in hardware what we've previously experimented in software; it compares in hardware the current timer value against the wanted value, and when the wanted value is reached a flag in a status register is set and the timer's value reset.

This is extremely handy; because the comparing is done in hardware, all we have to worry about is checking the flag to determine when to execute our LED toggling - much faster than comparing bytes or (in the case of the 16-bit timer) several bytes.

CTC mode is very straightforward. Before we look into the implementation, let's pseudocode what we want to do.

Set up LED hardware
Set up timer in CTC mode
Set timer compare value to one second
WHILE forever
IF CTC flag IS EQUAL TO 1 THEN
Toggle LED
Clear CTC flag
END IF
END WHILE

Very short, and very simple. Note that the name of the mode is Clear on timer compare - the timer's value will automatically reset each time the compare value is reached, so we only need to clear the flag when the delay is reached. This set-and-forget system is very handy, as once the timer is configured and started we don't need to do anything other than check and clear its status registers.

Now then, we'll grab our previous example, modifying it to fit with our new pseudocode:

Now, we need to flesh out the skeleton code we have. First up we need to configure our timer for CTC mode. As you might be able to guess, we want to configure our timer, thus the bits we want will be located in the timer's Control registers. The table to look for is the one titled "Waveform Generation Mode Bit Description", and is located in timer Control register descriptions for each timer. This table indicates all the possible timer modes, the bits required to set the timer to use those modes, and the conditions each mode reacts to.

You should note that our previous examples have ignored this table altogether, allowing it to use its default value of all mode bits set to zero. Looking at the table we can see that this setup corresponds to the "Normal" timer mode. We want to use the CTC mode of the timer, so let's look for a combination of control bits that will give us this mode.

Interestingly, it seems that two different combinations in Timer 1 of the MEGA16 will give us the same CTC behaviour we desire. Looking to the right of the table, we can see that the "Top" value (that is, the maximum timer value for the mode, which corresponds to the compare value in CTC mode) uses different registers for each. Both modes behave in the same manner for our purposes and differ only by the register used to store the compare value, so we'll go with the first.

The table says that for this mode, only bit WGM12 needs to be set. It also says that the register used for the compare value is named OCR1A.

Looking at the timer control registers (TCCR1A and TCCR1B) you should notice that the WGM1x bits - used to configure the timer's mode - are spread out over both registers. This is a small pain as you need to find out which bits are in which register, but once found setting up the timer becomes very easy. In fact, as we only have one bit to set - WGM12 - our task is even easier. The MEGA16's datasheet says that WGM12 is located in the TCCR1B register, so we need to set that.

The second task for this experiment is to set the compare value - the value that will reset the timer and set the CTC flag when reached by the timer. We know from the datasheet that the register for this is OCR1A for the MEGA16 in the first CTC timer mode, so all we need is a compare value. From our previous experiment we calculated that 1Hz at 1MHz with a prescaler of 64 needs a compare value of 15624, so let's go with that.

There, almost done already! Last thing we need is a way of checking to see if the compare has occurred, and a way to clear the flag once its been set. The place to look for the compare flags is in the timer's Interrupt Flag register - an odd place it seems, but the reason will become clear in the next section dealing with timer interrupts. The MEGA16's Timer 1 interrupt flags are located in the combined register TIFR, and the flag we are interested in is the "Output Compare A Match" flag, OCF1A. Note the "A" on the end; Timer 1 on the MEGA16 has two CTC channels (named channel A and channel B), which can work independently. We're only using channel A for this experiment.

Checking for a CTC event involves checking the OCF1A flag in this register. That's easy - but what about clearing it? The datasheet includes an interesting note on the subject:

Quote:

...OCF1A can be cleared by writing a logic 1 to its bit location

Very strange indeed! In order to clear the CTC flag, we actually need to set it - even though it's already set. Due to some magic circuitry inside the AVR, writing a 1 to the flag when its set will actually cause it to clear itself. This is an interesting behaviour, and is the same across all the interrupt bits.

Despite that, we can now add in our last lines of code to get a working example:

Note that when clearing the OCF1A flag, we assign its value to the TIFR register. This is because it will assign a logic one to the flag's position (clearing it) but also because as writing zeros to the other flags won't affect them, we can go ahead and use the smaller (codesize-wise) direct assignment, rather than ORing the register to form a read/modify/write sequence. This is also beneficial because it prevents the compiler from writing logic one to the other flags if they were already set via the read/modify/write, which would clear unwanted flags.

And there we have it, a working 1Hz LED flasher using the CTC timer mode!

Part Five - CTC Mode using Interrupts

Important: The interface for defining and working with Interrupts has changed in the more recent versions of WinAVR - please make sure you've updated your installation to the latest version if you encounter errors relating to the unknown macro "ISR".

For all our previous experiments, we've been using a looped test in our main code to determine when to execute the timer action code. That's fine - but what if we want to shift the responsibility of choosing when to execute the timer code to the AVR hardware instead? To do this, we need to look at the timer interrupts.

Interrupts are events that when enabled, cause the AVR to execute a special routine (called an Interrupt Service Routine, or ISR for short) when the interrupt conditions are met. These interrupts can happen at any time and when executing the main routine is paused while the ISR executes, the main routine continues until the next interrupt. This is useful for us, as it means we can eliminate the need to keep checking the timer value and just respond to its interrupt events instead.

The AVR timers can have several different Interrupts - typically Overflow, Compare and Capture. Overflow occurs when the timer's value rolls past it's maximum and back to zero (for an 8 bit timer, that's when it counts past 11111111 in binary and resets back to 00000000). However, for this section we'll deal with the Compare interrupt, which occurs in CTC mode when the compare value is reached.

Again, we'll pseudocode this to start with:

Set up LED hardware
Set up timer in CTC mode
Enable CTC interrupt
Enable global interrupts
Set timer compare value to one second
WHILE forever
END WHILE
ISR Timer Compare
Toggle LED
END ISR

We can start off this by working with our skeleton main code, used in previous examples. I'll skip the details on the parts already discussed in previous sections.

Note how it's a modified version of the non-interrupt driven CTC example covered in the last section. All we need to do is tell the timer to run the compare ISR we define when it counts up to our compare value, rather then us polling the compare match flag in our main routine loop.

We'll start with creating the ISR first, as that's quite simple. In AVR-GCC - specifically, the avr-libc Standard C Library that comes with it - the header file for dealing with interrupts is called (unsurprisingly) "interrupt.h" and is located in the "avr" subdirectory. We need to include this at the top of our program underneath our include to the IO header file. The top of our code should look like this:

#include
#include
int main (void)
{
...

This gives us access to the API for dealing with interrupts. We want to create an ISR for the Timer 1 Compare Match event. The syntax for defining an ISR body in AVRGCC is:

ISR(VectorName_vect)
{
// Code to execute on ISR fire here
}

Where "VectorName" is the name of the ISR vector which our defined ISR handles. The place to go to find this name is the "Interrupt" section of the datasheet, which lists the symbolic names for all the ISR vectors that the chosen AVR supports. When writing the vector name into GCC, replace all spaces with underscores, and append "_vect" to the end of the vector's name.

Like in part four we are still dealing with Channel A Compare of Timer 1, so we want the vector named "TIMER1 COMPA". In GCC this is called "TIMER1_COMPA_vect", after performing the transformations outlined in the last paragraph. Once the ISR is defined, we can go ahead and write out it's body, adding the LED toggling code.

Notice how we don't clear the CTC event flag like in part four - this is automatically cleared by the AVR hardware once the ISR fires. Neat, isn't it!

Running the code so far won't yield any results. This is because although we have our ISR all ready to handle the CTC event, we haven't enabled it! We need to do two things; enable the "TIMER1 COMPA" interrupt specifically, and turn on interrupt handling on our AVR.

The way to turn on our specific interrupt is to look into the second interrupt-related register for our timer, TIMSK. This is the Timer Interrupt Mask register, which turns on and off ISRs to handle specific timer events. Note that on the MEGA16 this single register contains the enable bits for all the timer interrupts for all the available timers. We're only interested in the Timer 1 Compare A Match interrupt enable bit, which we can see listed as being called OCIE1A (Output Compare Interrupt Enable, channel A).

By setting that bit we instruct the timer to execute our ISR upon compare match with our specified compare value. Let's put that line into our program's code and see how it all looks.

Only one more thing to do - enable global interrupts. The AVR microcontrollers have a single control bit which turns on and off interrupt handling functionality. This is used in pieces of code where interrupt handling is not desired, or to disable interrupts while an ISR is already being executed. The latter is done automatically for us, so all we need to do is turn on the bit at the start of our code, and our compare interrupt will start to work.

The command to do this is called "sei" in the avr-libc library that ships with WinAVR, and is named to correspond with the assembly instruction which does the same for AVRs (the SEI instruction). That's irrelevant however, as we just need to call the command in our code.

And our example is finished! Running this will give a nice 1Hz LED flashing, using the timer's event interrupts. The nice thing is that the timer operation is now completely handled for us in hardware - once set up, we just need to react to the events we've configured. Notice that our main loop is now empty; if this is the case you may put sleep commands inside the main loop to save power between compares.

Part Six - Pure Hardware CTC

You probably think by now that we've improved our example as much as possible - after all, what more improvements are there to make? Well, it's time to finish of the CTC topic by looking at the hardware outputs.

All AVRs' pins have alternative hardware functions. These functions (currently non re-routable) when activated interface the IO pins directly to the AVR's internal hardware - for instance the Tx/Rx alternative functions which are the direct interface to the AVR's USART subsystem. Alternative pin functions can be very useful; as they can be internally connected straight to a hardware subsystem, the maximum possible performance can be achieved.

In this section, we'll be looking at the Compare Output settings of the AVR timer.

Looking at the timer 1 control registers, we can see a few pairs of bits we've previously ignored, called (for timer 1) COM1A1/COM1A0 and COM1B1/COM1B0. Bonus points to anyone who's linked the "A" and "B" parts of the bit names to the timer compare channels - you're spot on.

These bits allow us to control the hardware behaviour when a compare occurs. Instead of firing an interrupt, the hardware can be configured to set, clear or toggle the OCxy (where "x" is the timer number, "y" is the channel letter for timers with more than one channel) hardware pins when a compare occurs. We can use the toggle function with our LED flasher, so that the hardware toggles the LED's state for us automatically, making it a true set-and-forget operation.

Before we do anything else, let's work out which pins of our MEGA16 are linked to the Compare Output hardware - we want the pins with alternative functions starting with "OC". On our PDIP package version, that maps to:

Quote:

PB3 = OC0
PD4 = OC1B
PD5 = OC1A

So timer 0 has one Compare Output channel, while timer 1 has two (channels A and B) as we've already discovered. As always we'll just deal with Channel A in our example.

Now we have a problem. All the previous chapters have assumed the LED is attached to PORTB, bit 0 - but we'll have to move it for this chapter. As stated above the alternative functions cannot be moved to another pin, so we must move moses...I mean, our LED, to the pin with the required alternative function.

Timer 1 Channel A's Compare Output is located on PD5, so move the LED there for the rest of this example. Now, let's psudocode:

Set up LED hardware
Set up timer in CTC mode
Enable timer 1 Compare Output channel A in toggle mode
Set timer compare value to one second
WHILE forever
END WHILE

Amazing how simple it is, isn't it! Well, we can already fill in almost all of this:

All we need is to configure the timer so that it'll toggle our channel A output each time the timer value is equal to our compare value. The datasheet has several descriptions for the functionality of the COM1Ax and COM1Bx bits, so we need to find the table corresponding to the mode we're using the timer in.

CTC mode isn't listed - instead the appropriate table is listed as "Compare Output mode, Non PWM". PWM stands for "Pulse Width Modulation", and will be covered later on in this tutorial. For now, it is sufficient to know that the CTC mode is not a form of PWM and thus the non-PWM bit description table is the one we're looking for.

To make the channel A Compare Output pin toggle on each compare, the datasheet says we need to set bit COM1A0 in TCCR1A. That's our missing line - let's add it in!

Simple, isn't it! We've now created the simplest (code-wise) LED flasher possible using pure hardware functionality. Running this will cause the LED to flash at 1Hz, without any code other than the timer initialization!

Part Seven - The Overflow Event

Well, now that we've had fun creating a LED flasher via a variety of software and hardware CTC methods, we'll move on to one last LED flashing program. This time we'll be using a different Timer event to manage the toggling of the LED - the overflow.

As previously stated, timers store their values into internal 8 or 16 bit registers, depending on the size of the timer being used. These registers can only store a finite number of values, resulting in the need to manage the timer (via prescaling, software extention, etc) so that the interval to be measured fits within the range of the chosen timer.

However, what has not been discussed yet is what happens when the range of the timer is exceeded. Does the AVR explode? Does the application crash? Does the timer automatically stop?

The answer is simple, if rather boring. In the event of the timer register exceeding its capacity, it will automatically roll around back to zero and keep counting. When this occurs, we say that the timer has "overflowed".

When an overflow occurs, a bit is set in one of the timer status registers to indicate to the main application that the event has occured. Just like with the CTC hardware, there is also a corresponding bit which can enable an interrupt to be fired each time the timer resets back to zero.

So why would we need the overflow interrupt? Well, I leave that as an excersize to the reader. However, we can demonstrate it here in this tutorial - via another LED flasher, of course.

Calculating the frequency of the flashing is a little different to our previous examples, as now we have to calculate in reverse (to find the frequency from the timer count and timer resolution rather than the timer count from a known frequency and timer resolution). We'll still be working with our 16-bit timer 1 for this example, to be consistent with previous chapters.

Let's go back to our one of the timer equations we used back in chapter 2:

Since we know that for the overflow equation, the "Target Timer Count" becomes the maximum value that can be held by the timer's count register, plus one (as the overflow occurs after the count rolls over from the maximum back to zero). The formula for the maximum value that can be held in a number of bits is:

Max Value = (2 ^ Bits) - 1

But we want one more than that to get the number of timer counts until an overflow occurs:

Counts Until Overflow = (2 ^ Bits)

Change "Max Value" to the more appropriate "Target Timer Count" in the first timer equation:

And substitute in the formula for the counts until overflow to get the timer period equation. Since frequency is just the inverse of period, we can also work out the frequencies of each duration as well:

Target Period = (1 / Target Frequency)

Target Period = ((2 ^ Bits) * (Prescale / Input Frequency)

Which is a bit complex, but such is life. Now's the fun part - we can now work out the overflow frequencies and periods for our 16-bit Timer 1 running at different prescales of our AVR's 1MHz system clock:

Note how our frequency decreases (and period increases) as our prescaler increases, as it should. Because we have a reasonably slow main system clock, and a large timer count register, we end up with frequencies that are easy to see with the naked eye (with the exception of the case where no prescaler is used). Unlike the CTC method however, we are limited to the frequencies above and cannot change them short of using a smaller timer, different prescaler or different system clock speed - we lose the precision control that the CTC modes give us.

For this example, we'll use a prescaler of 8, to give a 1.8Hz flashing frequency, and a period of about half a second.

Almost time to get into the code implementation. But first, pseudocode! I'm going to extrapolate on the preceding chapters and jump straight into the ISR-powered example, rather than begin with a polled example. It works in the same manner as previous polled experiments, except for the testing of the overflow bit rather than the CTC bit.

Set up LED hardware
Set up timer overflow ISR
Start timer with a prescale of 8
WHILE forever
END WHILE
ISR Timer Overflow
Toggle LED
END ISR

Let's begin with filling in the bits we can already do. The ISR code is easy - we can use the same ISR as part five, except we'll be changing the compare vector to the overflow vector of timer 1.

Looking in the MEGA16 datasheet, the overflow interrupt for timer 1 is obvious - it's listed as "TIMER1 OVF" in the Interrupts chapter. Just like in part five, we need to replace the spaces in the vector name with underscores, and add the "_vect" suffix to the end.

We can also fill in the "Enable global interrupts" line, as that is identical to previous chapters and is just the "sei()" command from the header file.

Next, we need to figure out how to enable the overflow vector, so that our ISR is run each timer the overflow occurs. The datasheet's 16-bit Timer/Counter section comes to our rescue again, indicating that it is the bit named "TOIE1" located in the Timer 1 Interrupt Mask register, TIMSK:

The last thing we need to do, is start the timer with a prescaler of 8. This should be easy for you to do - if not, refer back to chapter 2.

The MEGA16 Datasheet, Timer 1 section tells us that for a timer running with a prescaler of 8, we need to start it with the bit CS11 set in the control register TCCR1B. Adding that to our code finishes our simple program:

All done! This simple program will cause the LED to toggle each time the overflow occurs and serves as a practical use of the overflow interrupt.

Part Eight - Overflow as CTC

One neat application of the overflow event is for creating a CTC timer on AVRs which don't support true hardware CTC. It's not as neat as the pure hardware CTC discussed in part six, but faster than the pure software CTC discussed in part two.

CTC works by having a fixed BOTTOM value - that's the timer's minimum value - of zero, and a variable TOP value, the value at which resets the timer and fires the event. However, with the overflow event we seemingly have a fixed BOTTOM of again zero, and a fixed TOP of the maximum timer's value. Not so - with a small trick we can adjust the BOTTOM value to give us the equivelent of a CTC implementation standing on it's head.

This tecnique is called timer reloading. When configured, we preload the timer's count register (which is both readable and writeable) with a value above zero. This shortens the time interval before the next overflow event, although only for a single overflow. We can get around that by again reloading the timer's value to our non-zero value inside the overflow event for a hybrid software/hardware CTC.

Psuedocode time!

Set up LED hardware
Set up timer overflow ISR
Load timer count register with a precalculated value
Start timer with a prescale of 8
WHILE forever
END WHILE
ISR Timer Overflow
Toggle LED
Reload timer count register with same precalculated value
END ISR

Let's examine the maths again. From part two, we know that the formula for determining the number of timer clock cycles needed for a given delay is:

Target Timer Count = (Input Frequency / Prescale) / Target Frequency

Which works for a fixed BOTTOM of zero, and a variable TOP. We've got the "upside-down" implementation of a fixed top of ((2 ^ Bits) - 1) and a variable BOTTOM. Our BOTTOM value becomes the TOP minus the number of clock cycles needed for the equivelent CTC value, so the formula becomes:

Let's go with the previous example in part two: a 1Hz flasher, using a 1MHz clock and a prescale of 64. We found the timer count to be 15625 for those conditions. Plugging it into the above Reload Timer Value formula gives:

So we need to preload and reload our overflow timer on each overflow with the value 49911 to get our desired 1Hz delay. Since we've already gone over the code for an interrupt-driven overflow example in part seven, we'll build upon that.

Both the reloading and preloading of the timer takes identical code - we just need to set the timer's count register to the precalculated value. The timer's current count value is avaliable in the TCNTx register, where "x" is the timer's number. We're using the 16-bit timer 1, so the count value is located in TCNT1.

And done! This is less preferable to the pure hardware CTC mode, as it requires a tiny bit more work on both the programmer and the AVR to function. However, it will work just fine for AVRs lacking the complete CTC timer functionality.

Due to forum software length limits, the PWM section of this tutorial is continued HERE

Dean, I am a total AVR newb. I've gotten the book and kit from SmileyMicros and am about halfway through the experiments. Your tutorial was a refreshing different perspective. I am totally building this example tonight! I will of course look in my databook for the 169 though and try to figure out any different pin/register names first :D

Write a book Dean I'll buy it! Ooh better yet, make a robot kit with a tutorial book. That would be SWEET.

Cheers Sakko - don't forget to tell me how you went! You're not the first person to tell me to write a book - perhaps I might look into the possibility at the end of the year in my break from University. I'll have to work on my writing abilities first!

I've added part three, but I've currently got Uni exams. Once those are over around the 20th I'll pick up where I left off.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

A extremely good n easy to learn tutorial...
Good job. :D
we were greatly helped by your tutorial on timers.
we are new to avr programming.we want to program avr system in c.Please tell where can we get examples of c codes for avr and also tell where we can learn to program and stimulate interrupts in c .

Damn! I had missed most of the fun! Why isn't AVRFreaks software notifying me! You edit your post adding 2booksworth of info and I miss it all :( Now I have to read it all in one go.. ;D

Good work Dean! I can't understand, from where can you find the time... Do you sleep? do you eat? or is it just so, that you have an AVR implanted with a small WiFi transceiver so you can be online 24/7 and data input is from your brain? It sure seems so ;)

But seriously. I knew this tutorial would be a long one (I'm only just realizing how long when I went over it again - it's 5800 words and counting) when I started it, hence why I'm writing it in sections when I have the time. Now that I'm on Uni break I have more time to write.

Just doing what I love doing - sharing knowledge. Perhaps I should start asking for a dollar donation per person, that way I could skip my working life and retire now ;).

Quote:

Shouldn't we include the '#include ' line in the code?

Oops! I explained that that header file was needed in the text, then ignored it when I wrote the full code. Fixed.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Yes, 106 (0x66) is correct for your given clock, prescaler and required frequency.

As an aside, if you check your AVR's model, some can toggle the output pin state if a logic 1 is written to the AVR port's PIN register. That might make the ISR smaller and faster - if supported the ISR would become:

ISR(TIMER1_COMPA_vect)
{
PINB = (1<<0); // toggle led
}

I'll also be discussing in the next chapter the generation of CTC waveforms via the output toggle modes. There's actually a bit you can set which will toggle the OCRxy pin of the AVR automatically each time the compare occurs - so if you can change your hardware so that the output pin resides on the pin with the alternate function "OCR1A", you can do all the compare and toggling purely in hardware.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Perhaps I'll write a book at the end of the next semester, as it seems to be common here to suggest me to do so ;).

Don't know WHAT I was doing in that last sentence, but the rest are fixed. I think it was the common occurrence of me being distracted by something while my hands are still typing my previous thought! I've replaced it with what I meant to say instead.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Hi dean, nice tutorial.
I have some basic question.
First, is the timer running on the cpu clock, or based on the instruction? I try to simulate the code in AVR Studio and find that the timer increment is not fixed although I set the prescaler to one. Instead, the timer is increase with the value of cycle of instruction.
Second, when the timer is configured as CTC with OC0 activated, is there any chance that the AVR misses in the comparing of OCR0 and TCNT0 register? I think if the timer is run based on the cycle instruction maybe this misses have a chance to be happen. Conversely, it will not be happen if the timer is run on the cpu clock.
Maybe this is out of scope because you haven't come with PWM tutorial. I do some project using AVR m8535 and use its timer1 as Phase and Frequency Correct PWM with ICR1 as TOP value. I use OC1A and OC1B as PWM output and define OCR1A and OCR1B to control the duty cycle. Then I check the output using oscilloscop and find that if I use the time/div in high time (25mS), there is void in the output. It seem that the AVR misses the compare so the output is not working. Any suggestion?

The timer is clocked from the system clock by default - I'll cover using an external crystal later. With a prescaler of 1, that means the timer value is advancing one count for each clock of the CPU.

If the Compare Outputs are enabled, there should be no chance of missing the compare - it's done via hardware and is independent of the CPU core. Same with the interrupts - you might process them several cycles after the compare has occurred, but the hardware is responsible for doing the compare.

The only chance of missing a compare is in the earlier examples, with a software compare testing the TCNT value against a constant, where the timer value may wrap back to 0 before it's read and compared.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Uhmmm, wellll.. Sorry if I misunderstood you, but, if it is toggled every second, then a full on-off cycle will take two seconds and that is 0.5 Hz (not 2 Hz).

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Uhmmm, wellll.. Sorry if I misunderstood you, but, if it is toggled every second, then a full on-off cycle will take two seconds and that is 0.5 Hz (not 2 Hz).

Yes of course, you are right, I am making a similar error or even worse !! :P

After reading this great tutorial I made a conclusion:
Because one can load a well defined value in OCR1A :
One can use a cristal of 14.7456 Mhz (or 12.288 Mhz), have a error free baudrate of 9600 and make an error free RTC !
Is this correct ? If yes, great :D

I translated here the c-program from"Part Five CTC Mode using Interrupts" into assembler.
Also I changed the following settings to have faster Timer-1 increment and to see how the Interrupt is simulated in Studio AVR without to hit F11 so many times.
Should you run this in hardware, note that the LED will blink to fast this way !
> Prescaler = 1 : (CS11 not set)
> Compare value in OCR1AL set to 0x1F

I'll try to take a look at the code tonight to see if I can spot any errors in the code or changes in the MEGA8's timers that would affect it, but I don't think I'll have much time (plenty of Physics homework to get through). In the meantime, has anyone confirmed the CTC code to be working on a MEGA16 or MEGA8?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

I'll try to take a look at the code tonight to see if I can spot any errors in the code or changes in the MEGA8's timers that would affect it, but I don't think I'll have much time (plenty of Physics homework to get through). In the meantime, has anyone confirmed the CTC code to be working on a MEGA16 or MEGA8?

I can confirm all codes work on atmega88 (which is very similar to atmega8). I have written a very simple 24hr clock with the CTC interrupt routine, works perfectly:

wow what a detailed guide you have in this topic... it's really cool... looking forward for your PWM posting... how do i keep a update of what you have posted? i worried that i missed it and as a result i have to read all your post and editing at one whole shot... which will spend me lots of time to understand and follow...

so can anyone tell me how to keeop myself update for Dean's or anyone's new tutorial posted?

will*

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

o ok.. hi clawson again.. thanks.. hehe... em actually i wanted to know is like when someone, eg you, dean, etc, have a new topic being posted in AVR and when you all do the 1st posting, i will be notify about it... so i can go take a 1st quick look at the start of the tutorial posted...

thanks again :)
will*

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

abcminiuser, I wanted to thank you for putting together this amazing tutorial. It is very easy to read and quickly got me up and running using timers. They really aren't as mysterious and difficult as I originally thought they were. :)

Hey guys, I'm rather new to AVRs, anyways this might not be the most appropriate place to ask this, but I have an stk500 board with a mega8515 installed on it right now. And I'm only able to set the STK500 oscillator to 921.6 kHz. (I've tried typing in 1Mhz and writing to the chip, but once I read it I get 921.6 kHZ back)

Is there anyway I can force the chip to run at 1 Mhz? Or is the 921.6 kHz the closest I can get?

That was actually a cross-post that's been answered in AVR Forum - his problem is that he's using CV where the reg names (TCCR1B etc.) are defined but the bit names (CS10 etc.) are not. For anyone reading this later the solution (as posted to the other thread) is to use xmlconvert to generate a set of .h files with bit definitions.

Hey Dean good work on all of this. Just wondering if you have completed your PWM tut or if it's posted. I didn't find it in search. I am looking for a PWM tutorial to reference; don't want to 'rewrite the wheel'.

Hey Dean good work on all of this. Just wondering if you have completed your PWM tut or if it's posted. I didn't find it in search. I am looking for a PWM tutorial to reference; don't want to 'rewrite the wheel'.

Sorry, not yet. I've been (and still am) busy trying to complete all my end-of-year Uni assignments so I can pass the course for this year. I'll try to start writing it next week, but my time is very limited until the holidays in about four weeks, so don't expect it to be all done for at *least* two weeks. Sorry for the inconvenience.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

This is my first attempt to post, as I'm a total newbie both to AVR and forums,

I've been watching this forum for some time, and i have learned a lot, and when I found this excellent tutorial,
I was amazed with the simplicity of it that guided me, I did all the experiment I found here with no problem, then I combined a code, which drove me nuts :shock: I realized that I'm not even a newbie

here it is , I'm trying to make an 8 bit counter on the stk500, I'm using the following
AVR Studio 4.13.557 Service Pack 1
GUI Version 4, 13, 0, 557
JTAGICE mkII 1, 0, 1, 140
ATmega644 77

This works with no problem, I geta an 8bit LED counter at near 1 second intervals.
but when i move the "PORTD = ~led;" to the for loop, interrupts work, led var increments, but the LEDs won't change state,
I tried by clickin on the PORTD bits in the I/O view interface , it's Ok LEDs state change , but for some reason the instruction "PORTD = ~led;" does nothing inside the for loop;

What optimisation level do you use?
With no optimisation it should work.
With -oS it won't.
The reason is that with higher levels of optimisation the compiler will guess (wrongly) that led never changes and so remove your code. Cheeky isn't it?

the 'volatile' keyword is what you want when you declare led. This is generally the case when a variable is changed/used in an ISR and the main thread.

The other time it is commonly needed is if you are setting up an external memory mapped peripheral, such as a UART or a SCSI chip. Here you might send multiple commands to the same address, and the last thing you want is for the compiler to decide, "the last value written was 0x3b, I don't need to write the earlier ones". That is wrong.

volatile uint8_t led;

'volatile' tells the compiler, "I know what I'm doing. Don't get fancy and change anything to do with this variable. OK?"

Inspect the disassembled code to check this.

see FAQ#1 at the end of any posting from clawson (you won't have to wait long!!)

where can I find more details about this optimization and compiler behavior ?

Some of the big guns can probably explain the differences between the various optimisation settings, but it is out of my league. The manuals are the ultimate reference if you really want to know it all, but sometimes a pointer helps to direct your learning.
I'm always glad to find a question I can actually answer correctly :wink:

'volatile' works for all settings. The idea is that a volatile variable can change at any time, independent of how the program is running, so it must be left untouched (as written by you).

EDIT: The post below by me is not correct. I am leaving it here only so as not to disturb the flow of the thread, but please be aware that the information given is not correct.

ORIGINAL POST:

DDRB |= _BV(0);

If you want to set PORTB pin 0 as output the above wont do it. This will:

DDRB |= _BV(1<<0);

For more information on things like "1<<0" look in the tutorials forum for the tutorial named Bit manipulation (AKA "Programming 101").

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Actually I realised my mistake now. My actual clock source which comes from a 16 MHz crystal was running at 1 MHz speed. I found this out from the following extract in the ATmega16 datasheet:

Quote:

The device is shipped with CKSEL = “0001” and SUT = “10”. The default clock source setting is
therefore the 1 MHz Internal RC Oscillator with longest startup time. This default setting ensures
that all users can make their desired clock source setting using an In-System or Parallel
Programmer.

So I then modified the code as below, and there I got my LED toggling :)

Did you change the MEGA16's fuses from their default settings? If not, your AVR will still be running from its internal 1MHz RC oscillator, even if you have a 16MHz clock source of some description set up. That would cause the program to run at 1/16 the speed, so your 1Hz timer would take a full 16 seconds to reach your compare value.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Well I haven't changed the ATmega16's fuse settings as I don't know how. Earlier I was just experimenting assuming that it was running @ 16MHz.But i changed the code as above, and I got an exact 1 sec delay for toggling the LED.

Is there a tutorial you can point me to for programming those fuses?You see I am a newbie and still learning :)

Sorry, no tutorials that I know off the top of my head (and I'm glad my timers tutorial worked out for you!). It's quite easy however if you're using AVRStudio for your programming - the fuses tab makes it as simple as checking the desired setting's box and pressing program.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Great tutorial! It got me going into timer events in no time!
Just a small remark about your counter calculations:
If you'r using a 1MHz clock this means you have 1,000,000 cicles per second ;-)
So you will have to count until 1,000,000 to have an event for each second. Of course your counter will overflow because you only have 16 bits, so you have to use the frequency division but as you program in C you can write down:
// CTC value to 1Hz at 1MHz clock, prescaler of 64
OCR1A = 1000000 / 64;

I did change the fuse settings to run @ 8 MHz and I could get my LED toggling at 1 Hz with a few calculation and code changes.Thanks for letting me know that.

However, I have created a new problem for myself :(
I accidentally clicked on some fuse setings for the clock settings and now I am unable to program my AVR. I tried erasing the device too, but I keep getting this error:

Entering programming mode.. FAILED!
Leaving programming mode.. OK!

I am using the AVR Studio version 4.13.I am using the ISP mode to program the AVR. I get an "ISP Mode Error" pop-up each time I click on program or erase the device.Appreciate any help on this as I am unable to proceed due to these errors.Please see the attached screen shot of the error pop-up.

If you want to set PORTB pin 0 as output the above wont do it. This will:

DDRB |= _BV(1<<0);

Upon returning from the weekend trip I re-read this, and realized what a load of crap this posting of mine is. I honestly can not figure out what part of my brain actually did that. Sorry for any confusion I might have created...

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Did you catch which fuse setting you changed your AVR to? Chances are you changed it to use an external *clock* rather than an external *crystal*. They're two seperate things, and one will not work with the other attached.

To fix your AVR, you could either use a Dragon/STK500 in parallel programming mode, or feed in a fast clock into XTAL1 via an external source (such as a square wave oscillator made from a NES555). Just remember to reduce your ISP programming speed to at most 1/4 of the speed of the clock you input into the AVR when taking the latter route.

Once you regain communications with your AVR, change the fuses to use an external crystal and resume normal operations.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

I guess I'll try feeding in an external 1 Mhz clock using a 555 timer. Hope it works otherwise I'll have to replace my microcontroller with a new one :) as I don't have parallel programming capability on my development board.

I try to write my tutorials in a way that I would understand, which is usually simple and verbose enough for the majority to learn from. I do like changing only one variable at a time; I've had years of maths texts doing multiple operations in one step, which causes me to get lost quite easy.

No plans on writing a book at the moment, but it's certainly not out of the question. I'd hate to muscle in on the fellow forum's members livelihoods (such as Smokey) and don't currently have the time.

- Dean :twisted

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

I have a question.Regarding the Part Five - CTC Mode using Interrupts , by changes [/code] OCR1A , I able to control the interval of interrupt...But is that a way for me to control when I wan to start my interrupt, other then let the interrupt fired thoughout the whole program ?

You have plenty of control over the timer. You could turn the timer on and off (via the prescaler bits - turn them off to disconnect any clock to the timer circuitry) which would halt the count. You could change the TOP register in CTC mode to change the interval.

If what you want is to allow the timer to keep running but block the CTC interrupt until you want it to occur (defeating the point of having a known interval in the first place), you could just disable the CTC interrupt enable bit in the timer control registers. When you're ready to process it again, re-enable the bit and if the CTC event occurred while the CTC interrupt was disabled, it will immediately fire the ISR.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Hi Dean, thanks for the prompt reply, but now we have another problem. We have programmed our interrupt function to calculate a value. Is it possible to return a variable from the interrupt function or can we just declare the value as a global variable?

ISR's can't return values directly - where would the return value go to? You need to use a global, and mind that you make the variable volatile (do a search on 'Freaks for an explanation) if you want to share the value between the ISR and your main code.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

That should be fine, however, there's one more thing you're not accounting for - atomic access of the variables.

It's possible for your COMPA interrupt to fire in between the reading of a multi-byte global variable, which results in corrupted data being used. The solution is to read the volatile value into a normal local variable while interrupts are disabled in your main code:

The added benefit of this in your code, is that since all globals are cached locally with the interrupts disabled, you prevent the update from also occuring between the variable reads. Without this you might get the corrupt data as above, but also correct data, but with half the variables from one sample, and half from another.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Just to note that when you want to interrupt protect access to a variable you may not always know that the current interrupt state is SEI or CLI so rather than wrapping the access in a cli() before and an sei() afterwards it sometimes makes sense to define a 'uint8_t sreg_state' then do 'sreg_state = SREG; cli();' before the access and then 'SREG = sreg_state;' afterwards which recovers the pre-existing interrupt state rather than making the assumption that it was SEI.

is this a correct way to disable and enable the interrupt? and another problem is even we intend to set to 20ms interrupt but the program seem to perform one second interrupt? did we set the interrupt interval correctly ?

Great tutorial! I successfully ran several of the code examples in this tutorial on an Olimex AVR MT 128 board (ATMega 128-based) after changing the timer prescale to 1/1024 to match a 16MHz system clock. I also changed the pin assignment to Port E Pin 2 because that pin on my board is adjacent to a ground pin. I'm just starting out with the AVR, and code from your tutorials is the first code I've successfully run on an AVR.

You write very well. You definitely have the right mindset when you write these tutorials - assume NOTHING of the reader. That's where many tutorials fall short. I teach for a living, and I've seen many "introductory" books in several different areas that miss this point. If you ever do get the time to write the book everyone is suggesting, I'll certainly buy it.

Thanks for the great tutorial. Using your tutorial alone, I've just wrote my very first interrupt implementation, to drive a servo with PWM signal in software, on a atmega8. Loaded it up, and it worked first time. Great tutorial! I'm very impressed. You've taught me how periodic interrupts work.

FYI, the PDF of this tutorial is not in sync with the online version at the top of the thread. I just spent two hours chasing a mistake in the PDF that was fixed online a while ago. Once I figured out that the PDF was old, I fixed it in minutes. On the flip side, I have spent two hours reading the mega168 datasheet trying to figure this mess out :) .

Dean, is there a plan to update the PDF? If not, it might be a good idea to either take it offline or add a disclaimer at the beginning that the document is not up to date.

The tutorial was great even though I had problems. Thanks for putting it together.

Sorry about that, my fault. I'm going to remove the PDF version for the meantime, while I try to find an automated solution; maintaining two formats is a pain in the rear and I want to simplify things. Ideally I'd want to go from BBCode from the post straight to a formatted PDF, but that's a pipe-dream. I think the best I can hope for is a BBCode-HTML converter, then a HTML to PDF converter. I'll have a look around.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Actually, I've been thinking today about the comments others have made about me writing a book. Books on AVR and the C language has been done, and I don't want to take away money from hungry mouths like Smokey (and that, as he will tell you, is a big mouth :lol:). However, I think that a book that is essentially a set of worked examples using the different AVR peripherals might fill a niche while not treading on any toes. A bit like a book of my tutorials, but ones that flow from one to the next. Thoughts?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Well, speaking from my days of having to tackle that cursed Perl language, the Perl Cookbook was a lifesaver. The reference books (i.e. datasheets) are not a good place to learn the basics. The beginner books (i.e. turorials) are not much good once you have run through them once because the examples are too simple. Something like a cookbook that illustrates each function helps bridge the gap.

For example, as of right now, I would KILL for an example of a working input capture counter! I am not ready to give up and go to the AVR Forum yet but a cookbook would be high on my list to Santa right now.

I have made a simple timer program that would toggle 3 LEDs after set time. I am using tiny13 uc. The program works perfect if I simulate it using AVR simulator or debug it using JTAGICE mk II but doesn't work at all if I flash program using ISP. All 3 LEDs stay ON instead of toggling after a set time.

I don't think there is an error with ISP. I have developed few other programs (not shown below) and they work fine when I flash them using ISP.

Any idea whats wrong ? I have tried playing with different clock prescales and different time delays (as explained using variable elapstedtimeseconds for longer time delays) but it didn't really help.

If the LEDs appear to be on all the time it suggests that on/off toggling is simply happening too fast for you to see it (which is the difference between the simulator and real life - one is hundreds of times slower than the other). For one thing start by increasing the clock prescaler to the highest setting - you comment says "Fcpu/1024" but that's not what you are setting - I'll bet you speeded it up so you could see something happening in the simulator!

hi
guys can any one tell me how do i start my AVR studies i m bit confused plz help me with this k where i should i start my AVR program......some of my frends said to start studies of AVR 4m ATMEGA8 datasheet....plz tell me or give any brief or supporting tutorial
thanx....

hi
guys can any one tell me how do i start my AVR studies i m bit confused plz help me with this k where i should i start my AVR program......some of my frends said to start studies of AVR 4m ATMEGA8 datasheet....plz tell me or give any brief or supporting tutorial
thanx....

Thanks for the new year gift Dean.
Thanks a lot for ur dedicated work on even the new years eve.
i have a doubt.i simulated the code in part part five of ur tutorial in avrstudio.i am not able to see the counting in the tcnt registers.
is it so that the count is not visibile while using interrupts?

Studio has a number of known issues when simulating timers, depending on the version. Check your version's help file -- see if there are any timer-related issues. It should indeed show the timer counting correctly.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

i was breaking my head over this.
when i programmed mega16 with this code it worked properly.
only problem was with simulation.
i checked up the help page.there is a problem with tcnt buffering wen we use 16 bit timer.

Don't put the sei() in the ISR - the compiler takes care of that for you.

The ISR takes quite a few clock cycles to execute, about 9 just to get to it, plus a whole bunch more to execute your code, and the ISR overhead. 368KHz sounds about right for the maximum ISR speed.

You can do two things.

1) If your ISR is very basic, and has no side-effects, register or otherwise, you can make the ISR "naked" and ommit all the prologue and epilogue code. That'll speed it up, but will cause problems if your ISR tries to modify any of the registers or CPU flags.

2) Switch over to the hardware CTC method I outline. The timer circuitry can toggle the hardware compare pin as fast as the compare flag triggers, with no CPU overhead. That's the preferable option.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

I thought about the issue and it seems that the isr routine needs about 80 cycles to run. A naked one could be ok. I'll try the hardware one.

Oh, thanks for the tutorial.
I ran your examples and monitoring things on my digital scope. One one monitor I had the datasheet and on the other your tutorial and avr studio. The datasheet is quite cryptic and contains hardly any quick to use info. I've been looking at the microchip website lately and they have much more info about different things. Atmel is quite sparse with info.

Ah bugger, I've had the PWM section on my "ToDo" list for months, but can never quite seem to bring myself to sit down and really type it out. I lack motivation, and six seasons of Stargate on DVD doesn't help much.

Part Six: Pure Hardware CTC is the section you want to read on the hardware-only toggling solution.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Well I know the feeling... Ever heard of Firefly? just one season and a film called Serenity.

Anyway, I would like to have 3 pwm timers in an atmega168. Plenty of questions and the datasheet is cryptic. Perhaps if you just wrote something about the scope of this (strategy of what to use and perhaps why). Then I have enough to work on.

Each timer can only have *one* CTC channel operating at a time - if you use both, the timer will clear when the first channel compares, and the second one will never be reached. The point of the multiple channels is for PWM mode, where you can have dual channels operating simultaneously.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Now I've been playing with pwm on timer 0 using two outputs. I would like to get a possibility to set the freq and duty cycle of both outputs independently. But alas. I can only do one channel or use two channels with a fixed freq.
I do not yet understand it completely.
Perhaps you can have a look at the following code and tell me what I'm missing:

As far as I am aware, you set the frequency per-timer, then the duty-cycle per channel. Different frequencies require different timers - but most of the time muti-channel PWM applications all use the same frequency anyway (e.g. robots with servos, LED light controllers, etc).

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

As a newbie, this is THE most informative guide I have found yet relating timers. WOW, before most the code was greek to me but after the explanations, I can actually understand what is going on. Thanks! I hope you find the motovation soon, I cannot wait until you get the PWM section done!!!!!

hi , this is another great work. i cant describe how its useful. thanks..
I am trying with this tutorial because it doesn't require any tools beside my mega162 and small programmer.
I read the first four parts and try it , i fail :(
i changed anything with respect to my avr. here is the code:

another thing to notice is that my programmer has a 4MHZ crystal. but in the program i am asuming i am suing the internal 8mhz.. after programmed i use it in my board without any crystal.!
does it make sense!??

man this is an awesome tutorial it completely cleared my fundamentals cant wait for the pwm section to come in but i got one doubt i worked ont the principle u had given and i made led flash at a frequency of 0.5 hz that means 2 times in a sec the code i had written is as follows
# include
int main(void)

{
DDRD|=(1<<2);
TCCR1B|=((1<<CS10)|(1<<CS11));
while(1)
{

if(TCNT1>=31250)

{
PORTD^=(1<<2);
TCNT1=0;
}
}
return(1);
}
but when i connected the led nothing happened instead og toggling it never lit on (the led is fine) is something wrong in the code

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Nice job so far. Timers can be quite a pain sometimes. I have a hard time remembering how my own PWM code works sometimes.

I'd attack the PWM section with several different examples, since PWM is used in so many different ways. Maybe single timer fixed frequency-variable duty cycle examples first like switching power supplies, then a variable frequency-variable duty cycle example using one timer, then end it with a more complicated multiple timer example.

Good luck, feel free to use my teslaphonic code or webcam servo code for examples if you want.

So you can reliably making the timing change wildly by commenting out the second XOR in the loop?

That baffles me. Your timer prescaler is 64, so any code with an execution length of less than 64 clock cycles won't change the timer's count value by more than 1. The code uses a >= comparison, so any slight overshoot won't make any difference.

Perhaps someone else can jump in. I don't see how a three cycle operation (IN EOR OUT) inside the IF statment (which executes after the duration has elapsed) would vary the timing so much.

Is that an exact copy of the code you are working with?

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

I suspect no-one will bother to read your code unless you change the QUOTE tags to CODE tags and fix the indentation.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

The timer is never started (make a prescaler selection using the CS02-CS00 bits in TCCR0). Also, you will be better off using the CTC mode (read about it in this tutorial). Any code that assigns the TCNTx register from an interrupt will suffer (i.e., timing will be inaccurate) because of interrupt latency.
/Lars

The timer is never started (make a prescaler selection using the CS02-CS00 bits in TCCR0). Also, you will be better off using the CTC mode (read about it in this tutorial). Any code that assigns the TCNTx register from an interrupt will suffer (i.e., timing will be inaccurate) because of interrupt latency.
/Lars

but the thing is, my project is working when i tested with a free falling object (it shows about 600 us when it falls from 1 meter).

but when i give some velocity here (blowing it with 2 bar pressure), the system (just like i say) gave me ZERO result.

and about the latency things, have you read the tutorial ?. i've done my code just like the tut's.

and about the latency things, have you read the tutorial ?. i've done my code just like the tut's.

Read "Part Five - CTC Mode using Interrupts ". That said, the timer 1 input capture function is a better fit for your application. It would make better use of the timer HW so your program is not so busy with timer interrupts. I suspect your current solution suffers from this but I don't think that this alone explains the problem you have.
/Lars

Why are you preloading timer? This is normally done when you want to control the time ( such as flashing an LED at a set rate) It seems here you want to measure the time in which case I would just zero and start the timer on the first int0 and forget the reload values. If the device you are using has an input capture that would be an even better way to accomplish this.

Read "Part Five - CTC Mode using Interrupts ". That said, the timer 1 input capture function is a better fit for your application. It would make better use of the timer HW so your program is not so busy with timer interrupts. I suspect your current solution suffers from this but I don't think that this alone explains the problem you have.
/Lars

i missed that part.... sorry

but you were right about the busy part..
a friend of mine told me that my code in interrupt overflow need more than 4 cycle. and thats it.

Quote:

Have you checked the signals connected at INT0 and INT1 (with a oscilloscope). Do they look ok also when a higher speed test is done?
/Lars

the signal always ok i think.
because the result is always zero... not the "Ready" words.

first of all thank you very much Dean for this wonderful tutorial.
next..
pleeease help me..

I'm using this function to control the speed of a small DC motor using pwm, and the problem is that the output of OC1A is still VCC whether I give OCR1A any value including 0xFFFF and 0x0000 and any value between them.. this is the function...

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

You're right Johan , But after I added this topic here I noticed that there is no body here (at this moment at least) so I put it at the AVR forum , any way I want to be one of these who thanked Dean for this wonderful tutorial....

First of all, I'd like to thank Dean for this excellent tutorial. I have used the information here with much success on an ATmega8.

I am now starting another small project based on an ATtiny2313, and I am not sure what the problem with my code is. The idea is that I need a timer to be triggered every second. It doesn't have to be as accurate as an atomic clock, so "about 1 Hz" should be good enough.

The ATtiny2313 is running off the internal oscillator at 8 MHz; indeed, the only thing I changed in the fuses is enabling the EESAVE bit (lfuse 0x64, hfuse 0x9f, efuse 0xff).
I calculated that 1 Hz requires the timer to get to 31250 with clk/256 prescaler (8000000 / 256 = 31250):

The interrupt routine is just a boring led blinker so far ( PORTD ^= 1<<PD5; )
The problem is that it doesn't blink at 1 Hz at all, it takes MUCH longer (around 7 seconds, measured very empirically). Indeed, using a smaller prescaler, that is clk/64, gives a blinking that is somewhat closer to 1 Hz, but not quite (it should be only 4 times faster though!).
However, I'm quite confused as to why I am having such weird behavior. Truth be told, I am almost sure that it's something very stupid that it's before my eyes and I'm just missing, but any hint is certainly appreciated as I risk getting old looking for it. :)

Check your fuse settings again. The Tiny2313 has a divide by 8 option that is selected by default. It divides the frequency by 8 so you are actually running at 1 Mhz instead of 8.

Oops! That's right, thanks for making me notice that. I had completely skipped that fuse, and to think it's been there in front of me for a good two hours. :)

Edit in case someone needs it: running the ATtiny2313 off 3.1 V (instead of 5 V) seems to yield a much more reliable 1 Hz timer (at 5 V, my clock was ahead of a good two minutes after barely half an hour!). :)

Another edit: it's still not quite accurate: after an hour and a half, it's ahead of 4 minutes. I thought that at most the timer would be *slower* than real time, but it seems it's actually faster. Would an external crystal for the clock (or just for the timers) help? Before I dismantle this and add a 74HC595 (or use an ATmega8), as I'm out of pins already, I'd like to be sure it's worth it. :) Thanks!

Great tutorial on timers. I will look forward to the PWM section for additions.
Thank you for your work and efforts, this is the kind of thing that makes avrfreaks.net a great place for AVR beginners as well as the advanced audience.
I too would consider a book as a benefit to my technical library. Once again, thanks.

Hard to say. I'm being perpetually sidetracked by other projects -- right now I'm implementing the RNDIS specification on to my MyUSB USB stack to set up a webserver over USB. I have started the next tiny bit - when I feel like it I'll write the remainder.

I know, I've been meaning to do it for a long time, I just feel the call of writing code more than the call of writing tutorials these days. What's the world coming to!

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

However, I ended up doing all the coding in a poxy basic language for the AVRs (BASCOM... *shudders*). I'm now porting the code to C, and this has really helped with setting up all the pesky interrupts, timers and PWMs I used.

In fact, let me know if you want someone to lay out some PWM code for the tutorial. I have all the registers I setup all already in a log book, I'm sure it won't take me long to work out how to access them.

So thanks! Keep up the good work, and I hope your Uni exams went well (last year)!

Nice balancing robot Paul! Thanks for the offer for the PWM code. It's not a matter of myself being unable to write a trivial example, it's finding the motivation to write the tutorial around it!

Oh, and G'day cmetom! Make those crazy Canadians see the true culture of us Aussies :).

agising: The code is designed for an AVR running off its internal 1MHz RC oscillator, and should toggle at 1Hz. The Butterflies' bootloader sets the RC oscillator to 2MHz, so you're seeing twice the toggle rate (.5Hz).

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.

No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]