This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Measuring Microsecond Time

Hi, I am trying to expand on the ESB PRX example and want to recreate functions with the same functionality as Arduino's micros() and millis() functions. I'd like the following:

a) 1 μs resolution

b) Low latency time read

c) Safe to use from either a normal or interrupt context

My understanding is that the RTC module is not suitable as it has a low resolution. The Time API of the IEEE 802.15.4 stack appears to have the right functionality, especially as it returns the microsecond time as a 64-bit number. I don't want to overcomplicate the issue by trying to include the IEEE 802.15.4 stack when all I want from it is the time.

What is the best way to achieve this?

[Mac OS, Segger, SDK 17.0.2]

Kind regards,

Microderm

  • It should be possible to use a TIMER for this:
    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/timer.html#concept_xbd_hqp_sr

    If you set PRESCALER=4, then the TIMER will run on 1MHz, so every tick increment would be 1us. To read the timer you would need to execute a TASKS_CAPTURE followed by reading CC register. If you are using BITMODE=3 (32-bit mode), then the TIMER will overflow after 1us * 2^32 = 1.2hours, so you need to also add a global variable to keep track of overflows, but as long as you read the timer more frequently than 1.2hours, then it should be possible to compare previous value with latest, and then also keep track of the number of overflows (e.g. n * 1.2hours).

    Kenneth

  • Thanks, that worked for me. Here is what I did:

    1) Added the code below.

    2) Copied the TIMER block from the sdk_config.h file of a TIMER example and set TIMER1_ENABLED 1.

    static uint32_t curr_sys_micros_32 = 0;
    static uint64_t curr_sys_micros_64 = 0;
    
    /**
     * Initialises the timer.
     */
    void micros64_init() {
        NRF_TIMER1->TASKS_STOP = 1;   // Stop timer  //
        NRF_TIMER1->MODE = 0;         // Timer mode //
        NRF_TIMER1->BITMODE = 3;      // 32-bit counter //
        NRF_TIMER1->PRESCALER = 4;    // Prescalar 2^4 //
        NRF_TIMER1->TASKS_CLEAR = 1;  // Clear counter //
        NRF_TIMER1->TASKS_START = 1;  // Start timer //
    }
    
    /**
     * Returns the current 64-bit microsecond system time. Must be called within 71 minutes of previous call.
     * @return the current 64-bit microsecond system time.
     */
    uint64_t micros64() {
        NRF_TIMER1->TASKS_CAPTURE[0] = 1; // Capture current value //
        uint32_t prev_value = curr_sys_micros_32;
        curr_sys_micros_32 = NRF_TIMER1->CC[0]; // Store value //
        curr_sys_micros_64 += curr_sys_micros_32 - prev_value;
        return curr_sys_micros_64;
    }

    The code accounts for the 32-bit overflow to give the correct 64-bit timestamp in microseconds, so long as micros64() is called periodically with period less than 71 minutes.

Related