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

Soft Device and Timers - how do they work together?

Hi all, I'm using Timer2 while having the SD enabled, and I'm having some problems. I don't seem to be able to reliably set the periodicity of the timer. No matter what I load in the CC[] register, the interrupt always triggers at the same frequency. Here's what I'm doing:

In main(), to initialize I have: sd_clock_hfclk_request(); do { sd_clock_hfclk_is_running(&p_is_running); } while (p_is_running == 0);

NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode NRF_TIMER2->PRESCALER = 0; // Prescaler 0 produces 1 MHz timer freq => 1 tick = 1 us NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16-bit mode

// Enable interrupt
NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;

// Set up interrupt handler
sd_nvic_ClearPendingIRQ(TIMER2_IRQn);
sd_nvic_SetPriority(TIMER2_IRQn, APP_IRQ_PRIORITY_LOW);
sd_nvic_EnableIRQ(TIMER2_IRQn);

Then, when a button is pressed, I have: NRF_TIMER2->TASKS_CLEAR = 1; // Clear the task first to be usable for later NRF_TIMER2->CC[0] = delay; NRF_TIMER2->TASKS_START = 1; // Start clocks

In the interrupt handler, where code execution goes next, I have: if (((NRF_TIMER2->EVENTS_COMPARE[0] == 1) && (NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE0_Msk))) { NRF_TIMER2->EVENTS_COMPARE[0] = 0;

... my specific code here... }

And finally when I'm done I do:

NRF_TIMER2->EVENTS_COMPARE[0] = 0; NRF_TIMER2->TASKS_STOP = 1; // Stop clocks

Did anybody run into this problem with Timers and the soft device? Maybe I have to call another SD API function that I'm not aware of?

Can someone provide an example of the Timers and the SD working together?

Thank you!

Gil

  • In other words, I change "delay" but the frequency is still the same. I doesn't make sense. What am I doing wrong?

    Thank you! Gil

  • Some more information:

    When the timer is running our device will not be advertising nor connected.

    Thanks!

  • If you want to trigger the timer periodically with a given frequency, you can use shortcuts to clear the timer when getting a compare event.

    For instance, if you insert this before starting the timer:

    NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos) & TIMER_SHORTS_COMPARE0_CLEAR_Msk;

    The timer should count up to the value in NRF_TIMER2->CC[0], then it will give the compare event, clear the internal counter and start again.

    If you don't have this shortcut, then the timer will simply wrap around and give a frequency depending on the width of the CC register (which is 16bit in this case). Changing the CC will then only change when you get the first compare event.

    Sidenote, PRESCALER of 0 is not 1MHz, it's 16MHz. To get a 1MHz timer, use a prescaler of 4.

    -Anders

  • Thank you Anders!

    I will try that.

    I also had to use: hb_timer->TASKS_CLEAR = 1; in the interrupt handler to make it work more reliably.

    Gil

  • I'm sorry for the extremely long delay in answering this, but I believe Anders is spot on on his recommendation here; use a shortcut between your COMPARE event and the CLEAR task to make sure that the timer is always cleared before you start over again.

    Also, remember that TIMER2 only is a 8/16 bit timer, so if you try to set the CC value to something bigger than 65535, you will see very weird timeouts. As Anders also says, you should be aware that the PRESCALER register is defined so that the frequency of the timer is 16 MHz / 2^PRESCALER. As you can see, if you need a 1 MHz timer you must set this register to 4.

    If you still have trouble, can you please share your complete code, so that I can test it here? That makes it so much easier to help you. If you can't share it here in the open, feel free to create a support case for it.

Related