0
votes

I have in a project of mine a small delay function that I have written myself by making use of a timer peripheral of my MCU:

static void delay100Us(void)

{
  uint_64 ctr = TIMER_read(0); //10ns resolution
  uint_64 ctr2 = ctr + 10000;
  while(ctr <= ctr2) //wait 100 microseconds(10000)
  {
      ctr = TIMER_read(0);
  }
}

The counter is a freerunning hw counter with 10ns resolution so I wrote that function as to give approximately 100us delay. I think this should work in principle however there could be the situation where the timer is less than 10000 from overflowing and so ctr2 will get assigned a value which is more than ctr can actually reach and therefore I would end up getting stuck into an infinite loop.

I need to generate a delay using this timer in my project so I need to somehow make sure that I always get the same delay(100us) while at the same time protect myself from getting stuck there.

Is there any way I can do this or is this just a limitation that I can't get passed?

Thank you!

Edit:

ctr_start = TimerRead(); //get initial value for the counter
interval = TimerRead() - ctr_start;
while(interval <= 10000)
{
  interval = ( TimerRead() - ctr_start  + countersize ) % countersize;
}

Where countersize = 0xFFFFFFFFFFFFFFFF;
1
If the counter is unsigned then it should wrap. Look at the elapsed interval mod the max counter value. Time is up when the interval is (here) > 10000. interval = (timer - ctr + countersize) % countersize If it's a 64-bit counter then interval = timer - ctr. Do the arithmetic before checking the interval (to allow the arithmetic to wrap). - Weather Vane
The maximum value of 64 bits is 0xFFFFFFFFFFFFFFFF. IMO it's best to use a free-run counter with a total period in excess of the max you'll ever need. If the counter is 64-bit it is simple. Mark the start value, then compute the elapsed interval and compare it. Use >= so you don't need to catch an exact value. If it is a 32-bit counter then use uint32_t types, etc. - Weather Vane
...so don't compute a target as you have done, work with the elapsed interval. - Weather Vane
Ok, thanks, I have modified it like this: see original post edit. - Cantaff0rd
@WeatherVane I think I understood your solution if it's correct what I edited in the main post can you make a reply so I can accept it as answer? - Cantaff0rd

1 Answers

0
votes

It can be dangerous to wait for a specific timer value in case an interrupt happens at just that moment and you miss the required count. So it is better to wait until the counter has reached at least the target value. But as noticed, comparing the timer with a target value creates a problem when the target is lower than the initial value.

One way to avoid this problem is to consider the interval that has elapsed with unsigned variables and arithmetic. Their behaviour is well defined when values wrap.

A hardware counter is almost invariably of size 8, 16, 32 or 64 bits, so choose a variable type to suit. Suppose the counter is 32-bit:

void delay(uint32_t period)
{
    uint32_t mark = TIMER_read(0);
    uint32_t interval;
    do {
        interval = TIMER_read(0) - mark;    // underflow is well defined
    } while(interval < period);
}

Obviously, the required period must be less than the counter's period. If not, either scale the timer's clock, or use another method (such as a counter maintained by interrupt).

Sometimes a one-shot timer is used to count down the required period, but using a free-run counter is easy, and using a one-shot timer means it can't be used by another process at the same time.