[TUT] [C] Newbie's Guide to AVR Timers

Go To Last Post
482 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Great tutorial...do you know how can I compensate the errors due the int. osc. inaccuracy ? If you need 60 sec exactly

Usually, whatever the error is, it's pretty constant for the same Vcc and operating temperature. So if those things don't vary much you can just have a fixed value to tweak the OSCCAL register to bring it back to accuracy. But you will, of course, require a known, accurate timing reference to perform such a calibration. Atmel have an app note about this and if you have an STK500 you even have a command line switch to the Atmel program that drives it that causes it to generate a calibration clock.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
So if those things don't vary much you can just have a fixed value to tweak the OSCCAL register to bring it back to accuracy.

thank you, so im going to tweak the OSSCAL as you said, i was thinking in compensate the timer counter :S

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great tutorial, but one thing is not clear to me.

Let's assume you have a timer tick each 1 µs
I want to measure 1 s = 10^6 µs.
Too big for a 16-bit timer, so let's count the overflows and do some math:

2^16 = 65536

Case 1:
> Overflow at 2^16 ticks (µs)?
10^6 / 2^16 = 15,26... overflows.
after the 15th overflow, 0,26 * 2^16 has to be reached (16960 ticks)

Case 2:
> Overflow at 2^16 - 1 ticks (µs)?
10^6 / (2^16 - 1) = 15,26... overflows.
after the 15th overflow, 0,26 * (2^16 - 1) has to be reached (16975 ticks)

It's just a minor difference but wrong is wrong

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Case 1 is correct, but 1000000 is not evenly divisible by 65536 so you would never get exactly one second. You can put the timer into CTC mode and use a TOP value that results in an exact value. If you use 62499 for TOP (which gives you 62500 ticks between compare matches), then it is exactly 16 compare matches in one second.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you use a /64 prescale and CTC with OCR1A=0x3D08 then avrcalc says you should hit it without having to count overflows/matches.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi all,

it's my first post in here I hope i'm doing things right.
I've some weird issues (don't know if a new topic is necessary) and in spite of this great tutorial I can't get the idea working.

#include 
#include 

int t = 0;

void setup(){
    
    TCCR1B |=   (1<<CS10);     // set timer 1 (16 bits) to full clock source
    TCCR1B |=  (1<<WGM12); // CTC mode enabled
     OCR1A = 15624; //value to compare against
     TIMSK1 |= (1 << OCIE1A); // CTC interupts enabled
     sei();

  Serial.begin(9600);
}
 void loop(){}

 ISR(TIMER1_COMPA_vect)
 {t++;
Serial.println(t);}

the issue is: t only goes to a certain number and stop .it's certainly an obvious mistake but I can't manage to find what's going on .
On the other hand , if I display TCNT1 in the main fonction it works fine. it has to do with the ISR and the compare match.
the code shown is a simple one (Iguess) but it doesn't work as expected, whatever the type of variable.

and even with an interrupt overflow the increment of the variable stops and doesn't count more than few value at the begining.

The project that I have (and for the purpose of using timers ) is to output a sinwave in a DAC in the Interupt via a look up table. The main loop will be used to display imformation on LCD as it doesn't need refresh all the time.

This is for a tinny signal generator and a LFO for musical electronic purposes.

Sorry for the Arduino code , I'm currently using it for convenience but I decided to follow my first idea and get to the AVR instead.

Is this issue a known thing ? a newbie trap ? i'm pretty stock actually.

thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't delved that deeply into Arduino library code but I thought they used timer1 for Arduino's own purposes. If so your use of it may be messing with normal operation. This would be especially so if something inside the Serial class was using timer1 ticks for something like timeouts.

As the program is so simple why not implement it in plain C. The only "tricky" bit is the Serial.println() but if you just implement a UART_init() and a UART_putchar you can connect the putchar to the stdout stream and then printf() or whatever.

BWT just for future reference the threads in Tutorial are for presenting an article then subsequent feedback about it. As your post isn't really directly related to the tutorial as such this should be a separate thread in AVR Forum. I can split it if you like? I'd call it something like "Arduino timer counting problem" so you won't lose it.

Moderator.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good tutorial, thanks :) as a complement to AVR130 application note for assembler.

AVR assembler sources at http://avr-asm.blogspot.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I haven't delved that deeply into Arduino library code but I thought they used timer1 for Arduino's own purposes. If so your use of it may be messing with normal operation. This would be especially so if something inside the Serial class was using timer1 ticks for something like timeouts.

As the program is so simple why not implement it in plain C. The only "tricky" bit is the Serial.println() but if you just implement a UART_init() and a UART_putchar you can connect the putchar to the stdout stream and then printf() or whatever.

BWT just for future reference the threads in Tutorial are for presenting an article then subsequent feedback about it. As your post isn't really directly related to the tutorial as such this should be a separate thread in AVR Forum. I can split it if you like? I'd call it something like "Arduino timer counting problem" so you won't lose it.

Moderator.

Hi, sorry I didn't see that answers was posted :oops: . Sorry for the misplaced message.

actually I decided to leave arduino plateform (nice to start but too many things are hidden and don't help the understanding. Beside you can only use a specific chip)

The timer 0 or 1 is used for the millis() fonction and the compiler specifies an error if you use it for something else.

Anyway, I have some serious readings to do for starting with the proper AVR plateform. I'll post a proper topic with my issues regarding this LFO/frequency generator project in the future.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As a newbie, I found this tutorial informative and useful. Thank you very much!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Likewise, I found this tutorial very useful. I used it to turn my Dragon Rider LCD into a combination clock/calendar, complete with switches for setting the time and date and blinking tick-tock LED.

I found (as one might expect) that the crystal-based clock circuit on the Dragon Rider isn't 100% accurate, given that it lacks temperature compensation and the tolerance of the crystal isn't that tight. So I added a user interface to adjust the CTC timeout value up or down, depending on whether the clock needs to run a bit faster or a bit slower. This added one more constraint to calculating a timer prescaler and interrupt rate, which is that it is better to have as large a number as possible within in the limits of the 16-bit timer, as this allows finer adjustments to the rate at which the clock runs. In my case, the Dragon Rider came with a 7.3728 MHz crystal, so I use no prescaler and a 120Hz interrupt rate, giving me a period of 8 and 1/3 milliseconds and a nominal reset count of 61455. The purist will point out that this doesn't yield exactly 8 and 1/3 milliseconds. However, it is reasonably close, and allows for 4x finer adjustments than if, for example, I went for a rate of 100 Hz and was able to come up with an exact reset count of 9216 with a prescaler of 8.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello,
I am a new learner,it's a good course to study,but I really want to know the for{} what is content inside
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which for{}? This thread is 24 pages long and contains a multitude of for{}s.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can i ask for help? Im trying to run timers on my ATmega328P-PU

I want to use 8-bit Timer/Counter0 and i wrote my code using part 5 of this tutorial the last "Code" section. Unfortunately i cant get it to work. I want to simply test timer interrupt so this is what i want to achieve: Led is off on initialisation, on first interrupt it goes on (and stays on because there is no place in code where it would be toggled off/C5 set to low) so i know interrupts caused with timers are working.

Unfortunately its not working. After programming the led is off all the time. I checked connections for led (when i move that part from ISR interrupt to while() loop it works). Here is my code:

#include 
#include  
#include 
int main (void)
{
	DDRC |= (1 << 5); // set C5 as output (initially low led off)
	
	TCCR0A |= (1 << WGM01); // configure timer 0 for CTC mode
	
	TCCR0B |= (1 << CS02);	// set prescaler to 1024
	TCCR0B |= (1 << CS01);
	TCCR0B |= (1 << CS00);
	
	OCR0A = 179;  //interrupt every 10ms
	
	TIMSK0 |= (1 << OCIE0A); // enable CTC interrupt
	
	sei(); // enable global interrupt
	
	
	while(1)
	{
		
	}
}

ISR(TIMER0_COMPA_vect) 
{
	PORTC |= (1 << 5); // set C5 high (led on)
}

What im missing? Im sure its something silly but i just cant get why its not working, i need another pair of eyes to have fresh look at it :/

Thank you in advance

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why do people insist on using "|=" to set registers, particularly when you want to set several bits in the same register? Do it in one line with "="

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, i just wanted to break it apart to rule out any mistake in syntax, normally i do set multiple bits of same register in one line.
So yeah im still fighting with this problem

#include 
#include 

int main (void)
{
	DDRC |= (1 << 5); // Set LED as output
	TCCR0A|=(1 << WGM01);
	TCCR0B=(1 << CS02)|(1 << CS01)|(1 << CS00);
	sei();
	OCR0A=179;
	TIMSK0|=(1 << OCIE0A);
	
	while(1)
	{	
	}
}

ISR(TIMER0_COMPA_vect)
{
	PORTC |=(1 << 5);
}

Its still not working. I tried using TIMER0 in overflow mode

#include 
#include 

int main (void)
{
 	TIMSK0 |=(1<<TOIE0);
 	sei();
 	TCCR0B |= (1 << CS02);

	while(1)
	{	
	}
}

ISR(TIMER0_OVF_vect)
{
	PORTC |=(1 << 5);
}

and it worked... I just cant get that ATmega328P-PU to run the TIMER0 in CTC mode

--------------------------------------------

found it >< I shouldnt have set CS01 bit high.......... case closed

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried this in the AS6 simulator and you are absolutely right - nothing happens - the clock does not tick. Then I noticed a drop-list saying that the clock was set to 0x07 and I wondered what that meant. So I dropped the list and this is what it said... (hopefully you see the issue!)

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
hopefully you see the issue!

Let's add some data sheet reading to that:

Attachment(s): 

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"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]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a quick question too. :)

timer1 16-bits

	 TCCR1B = (1<<WGM12)|(1<<CS12); // enable CTS mode; 1HZ=62499 clocks=256 prescale
	 OCR1A = 62499;    //sets the desired count for displaying temp every one sec
	 TIMSK1 = (1<<OCIE1A); //Enable timer interrupt for "A" timer

time0 8-bits

	 TCCR0A |=(1<<WGM01);  //enable CTS mode;
	 TCCR0B |=(1<<CS00)|(1<<CS01);  //64 prescale
	 OCR0A = 249; //1000Hz or 1ms (0.001)
	 TIMSK0 = (1<<OCIE0A); // start timer0 "1"

main.c

ISR(TIMER0_COMPA_vect){
     ms++;
}

ISR(TIMER1_COMPA_vect){
      lcd_putint(rpm);
      rpm=0;

}

It prints ~600 for rpm value instead of 1000? Some assumptions ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your assumptions are based on what you think F_CPU is and hence the numeric OCR values.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I could assume the lcd code takes too long to execute. Where does rpm code from? Using ctc mode on timer1 when you should let it free run.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It prints ~600 for rpm value instead of 1000?

So?

You've shown exactly one place (two lines) in code that references the rpm variable:

      lcd_putint(rpm); 
      rpm=0;

I.e. one line prints the current value, and the next sets it to zero. No other code shown that in any way changes the rpm variable.

How do you think anyone is going to do any fault-finding given only that?

Here is the standard advice: Post minimal but complete program that builds and runs and demostrates the problem. Report clearly what you would expect the program to do, and report just as clearly what it actually does.

If you just drop a half-arsed question here you will get half-decent answers.

Remember #1: YOU are responsible for supplying as good a question as possible - i.e. YOU should spend as much time as possible formulating the question so that we need to spend as little time as possible helping you.

Remember #2: You are in a competition for attendance here at AVRfreaks. The better, clearer, more interesting, workable or thrilling your question is - the better the chance of you getting help here. If you pose a bad question while others pose better questions, you will lose and others will get our attention.

Your call.

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"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]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
I could assume the lcd code takes too long to execute. Where does rpm code from? Using ctc mode on timer1 when you should let it free run.

rpm is just a variable which is being increased every 1ms (timer0) and timer1 prints its value every 1sec.
So it should print 1000 for rpm value.

The entire program is bigger, i just posted a piece of the code.

However my thoughts are why does it count the thicks for timer1 (it's real 1 sec, I used looong period of time and stopwatch to made myself sure) but it misses some thicks for timer0?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As i said, your lcd code probably takes too long. I wrote a tutorial on multi tasking. This might help you

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. It seems that's what I have been looking for.

PS: Are you speaking for FreeRTOS?
Could I ask you to put a link?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Could I ask you to put a link?

Just browse the listing for the Tutorials forum here at AVRfreaks. Locate a tutorial with 'Kartman' as author and the title containing "multitasking".

[Personally I am reluctant to supply a link since that will awaken the CAPTCHA beast.]

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"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]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dean you quoted:
"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?"
- Dean first of all great tutorial written with passion
My question to you if you want a short delay or high frequency. Let say if my frequency target is 1MHz=1000000Hz and my Input frequency is 4MHz or 12MHz.

After applying the math i ended up with:
Time Resolution=(1/Input Freq)
=(1/1000000)=0.000001sec

Target Timer Count= [(1/Target Frequency)/(1/Timer Clock Frequency)] – 1
=[(1/1000000)/(1/4000000)]-1
= [(0.000001)/(0.00000025)] – 1
= [4] -1
=3

# include
int main ( void )
{
DDRB |= (1 << 0); // Set LED as output
TCCR1B |= (1 << CS10 ); // Set up timer
for (;;)
{
// Check timer value in if statement , true when count matches 1/20 of a second
//if ( TCNT1 >= 49999)
if ( TCNT1 >= 3)
{
PORTB ^= (1 << 0); // Toggle the LED
TCNT1 = 0; // Reset timer value
}
}
}

I used my digital oscilloscope and did not get frequency target only got some 23khz

Sorry if this sound stupid!

Thank

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A tutorial thread is not the right place to be asking about this (it's only for adding to details of the tutorial). Anyway your question is basically:

Quote:

but what if we want a delay of a minute? An hour? A week or year?"

The answer is simply that you count compares/overflows.

Say you want to implement an RTC but you only have an 8 bit timer and at 20MHz you can't make it last longer than 13ms (20MHz/1024/256). Then what you do is put it in CTC mode and set the compare to interrupt every 10ms. Each time the interrupt occurs you increment a counter. When it reaches 100 a second has passed so you set that counter back to 0 and increment a seconds counter. When the increment of that counter takes it from 59 to 60 you set that one back to 0 and increment a minutes counter. When that one eraches the 59 to 60 increment you set that back to 0 and increment an hours counter. When that one reaches the 23 to 24 increment you set it back to 0 and increment a days counter. When that one reaches 365 to 366 you set it back to 0 and increment a year counter and so on.

Nothing stops a 10ms interrupt counting millenia.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
A tutorial thread is not the right place to be asking about this (it's only for adding to details of the tutorial). Anyway your question is basically:

Quote:

but what if we want a delay of a minute? An hour? A week or year?"

The answer is simply that you count compares/overflows.

Say you want to implement an RTC but you only have an 8 bit timer and at 20MHz you can't make it last longer than 13ms (20MHz/1024/256). Then what you do is put it in CTC mode and set the compare to interrupt every 10ms. Each time the interrupt occurs you increment a counter. When it reaches 100 a second has passed so you set that counter back to 0 and increment a seconds counter. When the increment of that counter takes it from 59 to 60 you set that one back to 0 and increment a minutes counter. When that one eraches the 59 to 60 increment you set that back to 0 and increment an hours counter. When that one reaches the 23 to 24 increment you set it back to 0 and increment a days counter. When that one reaches 365 to 366 you set it back to 0 and increment a year counter and so on.

Nothing stops a 10ms interrupt counting millenia.

Hi clawson, I am sorry for asking a question in TUT. What should I do? Should start a new question?

For my question it is not about a long delay: a delay of a minute? An hour? A week or year?" but for short delay in order to generate a 1MHz at one of the pin of the MCU.

Thank

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi clawson, I am sorry for asking a question in TUT. What should I do? Should start a new question?

For my question it is not about a long delay: a delay of a minute? An hour? A week or year?" but for short delay in order to generate a 1MHz at one of the pin of the MCU.

Thank

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The way you do that is to set up a timer in CTC mode with a very low OCR value and have it toggle a pin on the compare event. I seem to remember it's possible to generate F_CPU/2 by doing that.

But really you should start a new thread in AVR Forum about all this.

Cliff (moderator).

Pages