### Author Topic: Timer question  (Read 3687 times)

0 Members and 1 Guest are viewing this topic.

#### Resilient

• Full Member
• Posts: 111
##### Timer question
« on: February 15, 2009, 12:41:39 AM »
I am a little confused on how the time functions work on the axon.

Specifically this function

Code: [Select]
`To retrieve timer value://read timer0's overflow counter//255 is count before overflow, dependent on clockelapsed_time=timer0GetOverflowCount()*255+TCNT0;`
Pretty much everything right of the equals sign I am a little confused by and any clarification would be quite helpful.  And does this output time in second or ms?

On a related note, is there a way to test functions like this easily?  For example is there a test application where I can output console text via the USB port or something?  That would make finding out how functions like this work a lot easier.

Thanks!

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: Timer question
« Reply #1 on: February 15, 2009, 07:22:24 PM »
The timer in question counts repeatedly from 0 to 255. When it hits 255 it causes an interrupt, and the interrupt routine increments a variable.
So the stuff 'to the right of the equals', is getting this variable and also adding in the current timer value 0...255. So its getting the total time since the program started.

As to the units for the time value then it depends on what prescaler is used for the timer. Looking at the Axon library for Timer0 it is 1024. Given the Axon runs at 16Mhz then the stuff to the right of equals will increment once every 1024/16MHz = 1024 / (16 * 1024 * 1024) = 1  / (16 *1024) = 61us

Can you test this stuff out? Yes -use rprintf to send stuff out via the uart to your pc.
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

• Supreme Robot
• Posts: 11,703
##### Re: Timer question
« Reply #2 on: February 16, 2009, 08:52:31 AM »
Quote
On a related note, is there a way to test functions like this easily?  For example is there a test application where I can output console text via the USB port or something?  That would make finding out how functions like this work a lot easier.
Of course! Just do an rprintf command while having HyperTerminal running. I never program my Axon without HyperTerminal.

You can also try out SoR Scope:
http://www.societyofrobots.com/sor_scope.shtml

Also, Webbot sent me an email awhile back pointing out a bug in this code that will result in a 0.39% chance for an incorrectly reported time. We'll release corrected code soon . . .
« Last Edit: February 16, 2009, 08:54:13 AM by Admin »

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: Timer question
« Reply #3 on: March 04, 2009, 07:13:40 PM »
As Admin says - I've been looking at this stuff (mainly towards producing a more professional library suitable for newbies as well as advanced folk).

So here's the problem:-

Assuming that Timer0 is an 8 bit Timer running in 'Normal' mode ie from 0 to 255 then it will overflow when transitioning from 255 to 0. So the basic formula should actually be
Code: [Select]
`timer0GetOverflowCount()*256 + TCNT0;`
But there is still lots of things wrong.....
Code: [Select]
`timer0GetOverflowCount()` returns a value made of more than one byte. The micro therefore requires many cycles to 'copy' this return result. If a timer0 overflow interrupt occurs whilst this is happening then the 'timer0GetOverflowCount' routine will return a mixture of its old value and its new value. Either way it will be wrong.

You may think we cure this by temporarily disabling interrupts whilst reading the overflow counter. This will make sure that the value returned is the correct value.  This could be done by using the WinAVR utils/atomic functions or by using the CRITICAL_SECTION_START/END macros defined in AvrLib Buffer.h.

So thats a kind of advance - but still gives the wrong answer....

Assume you are in an interrupt service routine an you try to use the above function. Now what? Well TCNT0 still keeps counting and may overflow back to 0 but since interrupts are disabled then the timer0 overflow count variable never gets incremented.

Alternatively: assume you use the above function when interrupts are enabled. It may get as far as reading timer0GetOverflowCount() but then the timer overflows before it reads TCNT0. So now you have an old copy of the overflow count with the new version of the counter.

You may think I'm being fussy - 'arent these just once-in-a-while' kind of errors? NO....

Using the old code then try running the following in WinAVR simulator...

Code: [Select]
`uint16_t old = timer0GetOverflowCount()*256 + TCNT0;while(1){    uint16_t new = timer0GetOverflowCount()*256 + TCNT0;    //see if the 'timer' has gone backwards!    if(new<old){         int i=0;i++;     // crap code but set a BREAKPOINT HERE    }    old = new;}`
This code checks that each reading goes up which it should do (until the 'overflow' variable overflows - but this could take minutes)

You should find this code fails (at the breakpoint) occasionally. Each failure is an error.

Now see what happens if it was called during an interrupt service routine. We can simulate this by inserting the 'cli();' statement.
Code: [Select]
`cli(); // ******* Turn off interrupts to simulate being called in an interrupt service routine **uint16_t old = timer0GetOverflowCount()*256 + TCNT0;while(1){    uint16_t new = timer0GetOverflowCount()*256 + TCNT0;    //see if the 'timer' has gone backwards!    if(new<old){         int i=0;i++;     // crap code but set a BREAKPOINT HERE    }    old = new;}`
Try running again and you will probably find loads more errors.

WinAVR simulator shows a StopWatch timer so you can see how quickly/often these problems kick in.

So the expression 'timer0GetOverflowCount()*256 + TCNT0' is just NOT reliable. This shows the problem when the foreground task (your application) tries to share data updated in the background (under interrupts or by the hardware).

How do you fix it?

Well the first step is to put the expression into function/method call. This allows you to change/fix it one place.

Whats the best code?
Well it has to cope with the above issues and several more.

I've got it sorted and it's taken me forever to sort out for ANY timer eg Timer4 or 5 on an Axon vs Timer2 on an ATMega8, etc !!

Where's the code?

Good question! Its not in WinAVR nor in AVRlib.

Answer: well I'm being a control freak! I'm putting the finishing touches to my C library for (Axon/Roboduino/ATMega168/ATMega8). So for 'newbies' then 'you dont need to know - it just works' but for advanced folk then you'lll check out the source code and understand.

Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

#### Resilient

• Full Member
• Posts: 111
##### Re: Timer question
« Reply #4 on: March 15, 2009, 07:16:26 PM »
Ok, Im back to work on a new project and I am working on setting speeds and measuring distance using wheel encoders. So I really need a functioning timer and am not clear on what the current state of the timers is and how to get them to work.

For example, if while my program is running, I want to read a sensor every 1/4 of a second how would I do that? I cant delay_ms(250) because that would freeze everything else for 250ms.

For example, timer0GetOverflowCount()*255+TCNT0; should increment by 1 every 61us, so there should be 16393 in a second.

So it seems like

Code: [Select]
` int elapsed_time=timer0GetOverflowCount()*255+TCNT0; while(1) { if(((timer0GetOverflowCount()*255+TCNT0)-elapsed_time)>=16393) { rprintf("Tick!\n"); elapsed_time=timer0GetOverflowCount()*255+TCNT0; }                }`
should print "Tick!" once per second. But it prints it a lot more often than that! So I tried changing 16393 to 1,000,000 instead, then it didn't tick for a long time, then started ticking faster than I could see on the screen... so something is wrong.

So the timer is still my biggest enemy but I need to be better friends with it.

If someone could give me a couple snippets showing how to make something happen every x seconds and another piece of code showing how long between a set of events, I would really appreciate it!

Webbot, is that code you are working on in the beta build?

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: Timer question
« Reply #5 on: March 15, 2009, 10:23:52 PM »
You've got a few problems there. When switching to 1,000,000 then your 'int elapsed_time' variable cannot store a number that big.

You can work around it for short delays by reseting the timer at the start of each period. eg

Code: [Select]
`timer0Init();while(1){    if(  timer0GetOverflowCount()*256 + TCNT0 >= 16393){         timer0Init();         rprintf("Tick\n");    }}`
You may still get some slightly strange events if you happen to read the timer when the overflow is happening - as per my earlier email.

Still working on my 'lib' - wow its complex trying to make things easy!! But should have something in the next few weeks.

Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

#### Resilient

• Full Member
• Posts: 111
##### Re: Timer question
« Reply #6 on: March 15, 2009, 10:45:49 PM »
Thanks Webbot.  I am working on some solutions... is it possible to get get_timer4_counter() to return only positive numbers? It gets to 32700 then overflows, then starts at -32700. It would make my math world all kinds of easier if it got to 65535 then reset to 0.

I tried

Code: [Select]
`long unsigned int elapsed_time=get_timer4_counter()`
But that still goes negative. I am not exactly sure what is going on here. Been doing too much math and not enough programming the past quarter
« Last Edit: March 15, 2009, 11:01:17 PM by Resilient »

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: Timer question
« Reply #7 on: March 16, 2009, 10:01:46 AM »
You are storing the value into an unsigned long - so how do you know it has gone negative? Are you using rprintf to print it out? In which case you are probably telling rprintf it is a signed number so rprintf interprets it as if it was signed.
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

#### Resilient

• Full Member
• Posts: 111
##### Re: Timer question
« Reply #8 on: March 17, 2009, 03:49:29 PM »
Yeah, its rprintf... that is messing me up all over the place...

Thanks

#### Resilient

• Full Member
• Posts: 111
##### Re: Timer question
« Reply #9 on: April 17, 2009, 01:34:20 AM »
So, Webbot, whats the status of those timer functions?

It would help a lot if I stopped getting super stupid timer information that totally throws of my PI loop every once in awhile due to those damn overflows.

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: Timer question
« Reply #10 on: April 17, 2009, 04:26:04 AM »
So, Webbot, whats the status of those timer functions?

It would help a lot if I stopped getting super stupid timer information that totally throws of my PI loop every once in awhile due to those damn overflows.

My library is ready for a Beta release but I'm waiting to hear back from Admin as to whether he's happy or not to host it on this website or whether I should use SourceForge - because the library is quite big and I don't want to consume all of his bandwidth.
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

#### Resilient

• Full Member
• Posts: 111
##### Re: Timer question
« Reply #11 on: April 23, 2009, 11:29:46 PM »
Great. Let us know when you get it hosted somewhere!

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165