What is the right way to read a software extended timer?

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,
I have extended a timer in software, to have some more bits:

volatile uint8_t extension;
ISR(TIMER0_OVF_vect) {
  extension++;
}

Easy enough but how do we read this without glitches?

uint16_t time() {
  return TCNT0 + (extension<<8);
}

is ok but only as long as the timer doesnt overflow in the middle of evaluating the expression.

uint16_t time() {
  cli();
  uint16_t result = TCNT0 + (extension<<8);
  sei();
  return result;  
}

still has the problem that the timer may overflow just after reading it, missing the increment of extension.

Here is an attempt to compensate for that:

uint16_t time() {
  cli();
  uint16_t result = TCNT0 + (extension<<8);
  uint8_t damn = TIFR0;
  sei();
  if (damn & (1<<TOV0)) return (extension+1)<<8;
  return result;  
}

But I am still not sure I have found a correct and bullet proof way to read a software extended timer.
Any good ideas? Thanks.

Regards
Soren

[moderator note: the reason your code tags didn't work is that your phpBB profile has "disable BBcode by default" set to on - probably not a great idea or, if you want to keep it that way, remember to untick the "Disable BBCode in this post" box in the message editor when you do use BB tags]

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

Quote:

still has the problem that the timer may overflow just after reading it, missing the increment of extension.

Assuming the cli() and sei() work (they may not!) then surely in your 3rd code both the reading of TCNT0 and the extension is protected together?

Another approach would be to stop the timer (CS bits) while reading.

As it looks like you use avr-gcc consider:

http://www.nongnu.org/avr-libc/u...

BTW the timer and the extension add up to 16bits. Why not just use a 16bit timer?

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

Quote:

Any good ideas?

It is indeed tricky. I recall a thread a long time ago with extensive discussion on this.

Much depends on expected/max latency, and thus indirectly the speed of the timer. At higher prescalers, sometimes seeing if TCNT is a low number along with the TIF flag can help.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Hi,

Moderator, sorry to give you work there. I just thought I'd better disable all codes, as my code examples always turned into garbled masses of smileys in other fora.
Clawson, actually I have all timers in phase correct PWM mode and they must all run in phase with each other. So no more than 8 bits and no stopping allowed. The other problems of keeping multi byte values consistent and of correctly using the up and down counting PWM mode as a timer, I keep separate from this more general question.
Reading TCNTn in a cli() context still doesn't freeze the counter value although it does freeze the extension. It could roll from 0xff to 0 and my result would beoff by about 256. I wrote "just after reading it" but I really meant between the effect of cli() and reading it.

Thanks for the references to the old treads, will read!

Edit: Okay I found this code which is claimed to be working. It is almost the same as my final try, except it also checks the MSB of the counter value. I think I got it right or almost right then.

Regards
Soren

Last Edited: Tue. Apr 8, 2014 - 12:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The code from the link looks ok.

One should avoid having code like (extension<<8) inside the CLI()-SEI() block, as this may take quite a long time, depending on the compiler's optimization.