How can I get more time from the millis function?

Hi,

I created a function like Arduino's millis which returns the number of milliseconds elapsed since the micro started executing the current program. Look down:

uint32_t millis(void)
{
    return (app_timer_cnt_get() / APP_TIMER_TICKS(1));
}

The problem is that the timer overflows every 17 minutes or so. The Arduino millis function instead overflows every 50 days.
Is there a way to increase the overflow time of my millis function?

Thank you

  • Hi,

    If you are using a recent SDK and the app_timer implementation is app_timer2.c, then this is quite straight-forward, but you need to do a small change in the app_timer. The app_timer2 implementation use a 64 bit counter internally, so what you could do is to make get_now() non-static, and add that to  app_timer.h as shown in this diff:

    diff --git a/components/libraries/timer/app_timer.h b/components/libraries/timer/app_timer.h
    index cd5b6d2..7d7b854 100644
    --- a/components/libraries/timer/app_timer.h
    +++ b/components/libraries/timer/app_timer.h
    @@ -311,6 +311,11 @@ void app_timer_pause(void);
      */
     void app_timer_resume(void);
     
    +/**
    + * @brief Return current 64 bit timestamp
    + */
    +uint64_t get_now(void);
    +
     #ifdef __cplusplus
     }
     #endif
    diff --git a/components/libraries/timer/app_timer2.c b/components/libraries/timer/app_timer2.c
    index dfafbcb..cfa28f7 100644
    --- a/components/libraries/timer/app_timer2.c
    +++ b/components/libraries/timer/app_timer2.c
    @@ -113,7 +113,7 @@ NRF_SORTLIST_DEF(m_app_timer_sortlist, compare_func); /**< Sortlist used for sto
     /**
      * @brief Return current 64 bit timestamp
      */
    -static uint64_t get_now(void)
    +uint64_t get_now(void)
     {
         uint64_t now = m_base_counter + drv_rtc_counter_get(&m_rtc_inst);
     
    

  • Thanks for the answer but I don't understand what get_now returns. Milliseconds like millis?
    How do I get milliseconds?

  • I'm using a NINA-B3 module where the nRF52840 microcontroller is present.

  • No, it returns the internal counter value. Essentially the same as app_timer_cnt_get(), but where that returns a uint32_t with the 24 bit counter directly from the COUNTER register of the RTC, get_now() returns a uint64_t that is always increasing. It comes from the COUNTER though and has the same frequency, so you can calculate the time in milliseconds just as you did with app_timer_cnt_get(). I suggest you try both, and you should see that before the 24 bit counter wraps around, you will get the same result with both.

    So that would be something like this:

    static uint64_t uptime_ms(void)
    {
        return (get_now() / (uint64_t)APP_TIMER_TICKS(1));
    }

    Note that here I return an uint64_t. You can cast it to uint32_t and use that, but note that counting milliseconds in a uint32_t will mean that it will overflow after a bit more than 49 days.

  • Hi Einar Thorsrud,

    thanks for the answer.

    Currently I use the following code to make timings:

    #define OVERFLOW			((uint32_t)(0xFFFFFF / APP_TIMER_TICKS(1)))
    
    uint32_t millis(void)
    {
        return (app_timer_cnt_get() / APP_TIMER_TICKS(1));
    }
    
    uint32_t ElapsedTime(uint32_t prevMillis)
    {
        uint32_t currMillis = millis();
    
    	// This statement is needed because millis() overflows approximately every 17 minutes.
        if (currMillis < prevMillis)
            return (currMillis + OVERFLOW + 1 - prevMillis);
        
        return (currMillis - prevMillis);
    }
    
    // Example:
    
    uint32_t timer1 = millis();
    
    while(1)
    {
    	if (ElapsedTime(timer1) >= 10000)
    	{
    		// Does something exactly after 10 seconds.
    	}
    }

    Can I change my code and use the following?

    uint32_t uptime_ms(void)
    {
        return (get_now() / (uint32_t)APP_TIMER_TICKS(1));
    }
    
    uint32_t ElapsedTime(uint32_t prev_ms)
    {
        uint32_t curr_ms = uptime_ms();
        
        return (curr_ms - prev_ms);
    }
    
    // Example:
    
    uint32_t timer1 = uptime_ms();
    
    while(1)
    {
    	if (ElapsedTime(timer1) >= 10000)
    	{
    		// Does something exactly after 10 seconds.
    	}
    }

    Specifically can I cast it to uint32_t?
    In this case there is no need to manage the overflow because the overflow time is very long (my device can stay on for max 2 days) right?

    Thanks for your time

Related