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

Correct implementation of a 1ms counter using NRF_TIMER

Hello,

at the moment I am trying to implement a counter that increments every 1ms. I wrote the following code for this:

uint32_t counter = 0;

void init_sync_timer(void)
{
    NRF_TIMER3->MODE = TIMER_MODE_MODE_Timer;
    NRF_TIMER3->BITMODE =  TIMER_BITMODE_BITMODE_16Bit;
    NRF_TIMER3->PRESCALER = 4;
    NRF_TIMER3->CC[0] = 1000;
    NRF_TIMER3->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
    NVIC_EnableIRQ(TIMER3_IRQn);
    NRF_TIMER3->TASKS_START = 1;
}

void TIMER3_IRQHandler(void)
{    
  if(NRF_TIMER3->EVENTS_COMPARE[0])
  {
      counter++;
      NRF_TIMER3->EVENTS_COMPARE[0] = 0;
      NRF_TIMER3->CC[0] += 1000;
  }
}

int main(void)
{
    ...
    init_sync_timer();
    ...
}

Regarding to the documentation (https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Ftimer.html) this should increment my variable "counter" every 1ms. 

Unfortunately this is not the case. My variable "counter" increases every ~8.3ms.

So here are my questions:

1. Do I miss something here?

2. Can anybody tell me, how to fix this issue?

Thank you very much in advance.

  • Hello,

    Looking at your snippet, you set the prescaler = 4, so the tick rate is 16MHz / 2^4 = 1MHz. When the counter reaches 1000, 1ms has passed, so that looks correct. Are you sure that you have time to handle these interrupts in your application? If you are running the softdevice, and e.g. are advertising or in a connection, you will see that sometimes, these interrupts are not reached. You should look into enabling the shorts register:

    uint32_t counter = 0;
    
    void init_sync_timer(void)
    {
        NRF_TIMER3->MODE = TIMER_MODE_MODE_Timer;
        NRF_TIMER3->BITMODE =  TIMER_BITMODE_BITMODE_16Bit;
        NRF_TIMER3->PRESCALER = 4;
        NRF_TIMER3->CC[0] = 1000;
        NRF_TIMER3->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
        NRF_TIMER3->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos; // This will reset the TIMER counter register every time compare0 is reached.
        NVIC_EnableIRQ(TIMER3_IRQn);
        NRF_TIMER3->TASKS_START = 1;
    }
    
    void TIMER3_IRQHandler(void)
    {    
      if(NRF_TIMER3->EVENTS_COMPARE[0])
      {
          counter++;
          NRF_TIMER3->EVENTS_COMPARE[0] = 0;
          //NRF_TIMER3->CC[0] += 1000;  //timer register is cleared by short.
      }
    }
    
    int main(void)
    {
        ...
        init_sync_timer();
        ...
    }

    But if the CPU still can't keep up with every interrupt, you will see that it is not counting steadily, at least if you enable the softdevice. Try it and see how it goes. If it doesn't work, you would have to use PPI and a second timer in counter mode, and short the event generated by TIMER3 to increase the counter of the other timer, which you then can read out at any time.

    If you need this counter at 1ms, have you looked into using the app_timer? I suspect that it is more suited for your need.

    Best regards,

    Edvin

  • Hello Edvin,

    sorry for my late response. I fixed the issue. You were right. In my application there was not enough time for handling the interrupts.

    Michael

Related