schef gravatar image

Posted 2017-09-18 11:58:04 +0200

blogs->all

Using millis() like in Arduino.

Here are two simple functions to use when you want to use timestamps for time measurement.

uint32_t millis(void)
{
  return(app_timer_cnt_get() / 32.768);
}

and for comperison of current with given timestamp with rollover correction (thanks to Nicolas Brunner for the correction):

#define OVERFLOW ((uint32_t)(0xFFFFFFFF/32.768))

uint32_t compareMillis(uint32_t previousMillis, uint32_t currentMillis)
{
  if(currentMillis < previousMillis) return(currentMillis + OVERFLOW + 1 - previousMillis);
  return(currentMillis - previousMillis);
}

You can use it like:

uint32_t myTimeStamp = millis();
//... some code here
if(compareMillis(myTimeStamp, millis()) > 2000)
{
  printf("2 seconds have passed\n");
}

Here are unit tests https://github.com/schef/nrf_millis

10 comments

electronut gravatar image

Posted Sept. 19, 2017, 4:39 a.m.

Nice! Might be good to also show how the timer is started and stopped. Also app_timer_cnt_diff_compute can compute the diff taking overflow into account.

jfhaugh gravatar image

Posted Sept. 27, 2017, 6:03 p.m.

Please keep in mind that 1,000 does not go evenly into 32,768. The above solution can misbehave if the application expects each of the values modulo 1000 to be returned once, and only once, every wall-clock 1 millisecond.

schef gravatar image

Posted Sept. 28, 2017, 9:03 a.m.

What would be you solution to this idea then?

jfhaugh gravatar image

Posted Sept. 29, 2017, 8:41 p.m.

Not actually using milliseconds, but run a 1024Hz time-base. The time error isn't all that bad, there's no weirdness caused by imprecision and you're not using floating point on a part that may not include an FPU.

Nicolas Brunner gravatar image

Posted Oct. 2, 2017, 3:35 p.m.

millisPassed() is bugged because millis() doesn't overflow after 0xFFFFFFFF but after 0xFFFFFFFF/32.768. Here is my proposition (not tested):

#define OVERFLOW ((uint32_t)(0xFFFFFFFF/32.768))

uint32_t millisPassed(uint32_t localMillis) {
  uint32_t currentMillis = millis();
  if (currentMillis < localMillis) {
    return currentMillis + OVERFLOW + 1 - localMillis;
  } else {
    return currentMillis - localMillis;
  }
}
schef gravatar image

Posted Oct. 3, 2017, 1:32 p.m.

You are right. I will edit the post.

schef gravatar image

Posted Oct. 11, 2017, 3:48 p.m.

I had some more ploblems with #define OVERFLOW ((uint32_t)(0xFFFFFFFF/32.768)). It should have been something like #define OVERFLOW ((uint32_t)((512*32768)/32.768)) because of PRESCALER which is 32768.

Nicolas Brunner gravatar image

Posted Oct. 11, 2017, 4:12 p.m.

You won't be able to measure millisecond with a prescaler of 32768

Nicolas Brunner gravatar image

Posted Oct. 11, 2017, 4:19 p.m.

I made an error, the overflow should be #define OVERFLOW ((uint32_t)(0xFFFFFF/32.768)) because the app_timer_cnt_get() use the RTC who is a 24 bits counter.

schef gravatar image

Posted Oct. 12, 2017, 8:51 a.m.

Aha..i had problems yesterday thank God i connect the buzzer to beep on every startup and it was beeping every 8 minutes :)

The use-case was:

#define MINUTE 60*1000

uint32 millisPassed(uint32_t localMillis)
{
    return(compareMillis(localMillis, millis()));
}

This is what i used for help and the requirement was:

if(millisPassed(lastMessage) > 15 * MINUTE)
{
    sd_nvic_SystemReset();
}

Is there another solution for the OVERFLOW without using hardcoded number but the PRESCALER?

Sign in to comment.

User menu

    or sign up