views:

218

answers:

11

Hi Guys,

I need to deal with a counter that gives me ticks for my application. The counter is 32bits so what i need to know is how to deal with it when it wraps. for example:

I have a function that returns a (timestamp + shifttime) and i have another function that will return 1 or 0 depending whether or not the time has elapsed, but there could a possibility that that my counter will wrap how do I deal with this ?.

Thanks

Thanks a lot for all the responses guys. I will give more detail in this edit.

I am using the STM32 Cortex-M3. I wanna use the RTC counter to use it as the tick for my application to schedule tasks that need to happen at certain intervals. The RTC can generate an overflow interrupt so it's not a problem to detect the interrupt. the main problem that I have(or at least I think is a problem) is when certain tasks gets a (timestamp+shift) ie.


int main( void )
{
FlashLedTimeStamp = ReturnCounter( 20 );  // currentcounter value + a shift of 20
StatusLedTimeStamp = ReturnCounter( 3 );  // currentcounter value + a shift of 3

//then later on ....
while(1)
{
    /* other tasks could go here */

    if( HasTimeElapsed( FlashLedTimeStamp );
    {
       /* do something and get another timestamp value */
       FlashLedTimeStamp = ReturnCounter( 20 );  // currentcounter value + a shift of 20
    }

    if( HasTimeElapsed( StatusLedTimeStamp );
    {
       /* do something and get another timestamp value */
       FlashLedTimeStamp = StatusLedTimeStamp( 3 );  // currentcounter value + a shift of 3
    }
}   
}

lets assume that my RTC counter is only 8 bits long to make the math easy.

if my current counter is at 250 when I get my timestamps that means that FlashLedTimeStamp = 14 and StatusLedTimeStamp = 253 how would i check to see that FlashLedTimeStamp has expired ??

keep in mind that I dont necessarily check all the time to see what the current counter is and whether or not certain timestamp has expired. I hope this makes it clear what the problem I have is thanks to all in advanced.

A: 

Assuming you're dealing with unsigned types, you can check for wrapping pretty easily --

if (timestamp + shifftime < timestamp) 
    it_wrapped();
Jerry Coffin
What if shiftime is negative?
Pmod
might consider formatting that as a Markdown code block rather than an in-line, the line-wrap (ironic, I know) is in a really unfortunate place
Mark E
+2  A: 

The question is a bit vague. One possibility is to set a flag when you first notice that the time has elapsed. A surefire way would be add a second counter which is incremented when the first counter overflows. This will in effect create a 64 bit counter which won't overflow.

Peter G.
That's just delay of execution. Eventually, the second counter will overflow as well.
Job
@Job: Yeah, but it's one hell of a delay. Two to the power of 64 allows for 18,446,744,073,709,551,616 ticks. If each tick is a milisecond then that comes to a little over a 580 million year time span.
torak
Sure, all I was trying to say is that this isn't a real solution to the problem.
Job
A solution that works for time periods less than 580 million years is not a "real" solution to the problem? Why not?
Mike Pelley
I know code life tends to be longer than any of us realize when writing it, but I would safely assume that no code I write will get used in 500 million years
Chimmy
That's all very true: this solution *will* work. All I'm saying is that this is not a *real* solution to the problem: you still cannot detect a wraparound. Because if you find such a solution, it doesn't matter if your clock gets faster and ticks every picosecond (in which case the time before the counter wraps is only half a year!).
Job
+1  A: 

The simplest way to do this is to make an "epoch counter", that explicitly counts rollovers. (Example: you have a hardware counter that counts seconds 0..59. Your epoch counter would count minutes, by incrementing each time it noticed that the seconds counter had rolled over.)

Your future_scheduler function then reads the current epoch and time,and computes a new epoch and time for your event.

Alternatively, you could just punt, and make your timing function count your event schedules down to zero on each timer tick.

John R. Strohm
+1  A: 

One of the possibilities is to cast both variables to 64-bit long and then do sum. After that compare with maximum 32-bit value to identify if it's wrapped.

Pmod
Most embedded targets don't support 64-bit integers.
tomlogic
In this case a simple wrapper that emulates operations with 64-bit with the help of 2 x 32-bit can be employed (I suppose there are a lot of ready-made implementations can be found).
Pmod
+7  A: 

If you take two timestamp readings and your first reading is greater than the second, then your counter has wrapped. That is the basic way to detect a wrapping counter.

This, however, won't detect if a counter has wrapped multiple times, or the case where a counter has wrapped and happens to be greater than the first reading. Since you said this was an embedded system and your description makes your "counter" sound like a clock, see if you can set an interrupt to fire whenever the clock reaches zero (so that you will get an interrupt every time the clock resets). When this interrupt fires, increment a separate counter. This should effectively add extra precision to your clock and allow your counter to wrap without causing problems.

bta
Maybe edit to say: "If you take two timestamp readings *of an incrementing counter/timer*..." -- the last 3 (embedded) projects I worked on used a *countdown* timer, so wraparound is when the 2nd value is greater than the first. For example, the ARM Cortex M3's built-in SYSTICK timer counts down to 0 and then reloads with a specific value before counting down again. Good answer though.
Dan
@Dan- Good point. Perhaps it would be clearer to say "if you calculate the (signed) difference between two timestamps and the result has the opposite sign from what you'd expect, then the counter wrapped".
bta
you need to compute or determine experimentally the time it takes to wrap and insure that you are sampling faster than that.
dwelch
A: 

As you are embedded, you may have access to a CPU overflow bit. This would be set when an add overflows it's register. Useful for add AddCarry chaining.

Michael Dorgan
+2  A: 

It will not matter if the difference between the start and end count is less than (2^32)/2, and assuming 2's complement 32bit arithmetic is performed (almost universally true), even if the count value spans the wrap-point. For example:

Start count: 0xfffffff
End Count:   0x00000002 (incremented through 0,1,2 - i.e. three counts)

End - Start == 0x00000002 - 0xfffffff == 0x00000003

So the right answer is achieved so long as the counter is the bit width of a built-in integer type, and that type is used. Where perhaps a counter register is not the width of a built-in integer type, you can achieve the same effect by masking the higher order "overflow" bits.

If you need the larger count for other reasons or if the difference between successive timestamps is too large, then you can simply use another integer that is incremented when the lower-order counter wraps. This integer will form the high order bits of a larger integer, so the LSB of the second integer is the 33rd bit of this larger integer.

Clifford
A: 

Cast the result of unsigned subtraction to signed and compare to zero. Should handle overflow when you check it often enough (and your timeout is less than half the range of your timer).

uint32_t timer( void);             // Returns the current time value
uint32_t timeout;

timeout = timer() + offset;

// wait until timer() reaches or exceeds timeout value
while ((int32_t)(timeout - timer()) > 0);
tomlogic
See @caf's answer as well.
tomlogic
+2  A: 

If you use unsigned variables to store your counter and timer expiry time, then you can simply use this test:

if (current_time - expiry_time < 0x80000000UL)
    /* timer has expired */

This assumes that you test for expiry at least once every 0x80000000 ticks, and that your longest timer is set to expire less than 0x80000000 ticks into the future.

caf
A: 

I think one of the easiest ways to do this, would be to have another counter (lets call it Wrap counter, let this be a static global for the timer module), count up each time your original 32 bits counter wrapped.

In the function where your counter is ticking away, everytime this counter reaches its maximum count, you have your Wrap counter increment. So when you are reading the function which returns whether or not the timer has elapsed, you also read the Wrap counter, to check how many times it wrapped over. The important thing is, to also do this: everytime you read the wrap counter, you want to clear it, for your next reading.

IntelliChick
You need not clear the wrap counter if you simply regard it as the high-order bits of a larger counter.
Clifford
A: 
dwelch