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

How to use 16Mhz NRF_TIMER1 with softdevice? Source Code to review

Sorry for the silly question, but as it is mandatory to use sd_X function when it is possible to avoid collision, could you tell me if this code is the right way to use the 16MHz Timer 1?

Best regards

/** @brief Function for handling the Timer 1 interrupt.
 */
void TIMER1_IRQHandler(void)
{
    NRF_TIMER1->CC[0] += TIMER_INTERVAL;
  
    // Clear interrupt.
    if ((NRF_TIMER1->EVENTS_COMPARE[0] == 1) && 
        (NRF_TIMER1->INTENSET & TIMER_INTENSET_COMPARE0_Msk))
    {
        NRF_TIMER1->EVENTS_COMPARE[0] = 0;
    }
    
    if(toggle)
      kernel_led_test_on();
    else
      kernel_led_test_off();      
    
    toggle = !toggle;
}

static void timer1_init(void)
{
    uint32_t p_is_running;
    uint32_t err_code;
  
    // Configure timer
    NRF_TIMER1->MODE      = TIMER_MODE_MODE_Timer;
    NRF_TIMER1->BITMODE   = TIMER_BITMODE_BITMODE_16Bit;
    NRF_TIMER1->PRESCALER = 9;

    // Clear the timer
    NRF_TIMER1->TASKS_CLEAR = 1;

    NRF_TIMER1->CC[0] = TIMER_INTERVAL;

    NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;
    NRF_TIMER1->TASKS_START = 1;

    err_code = sd_nvic_SetPriority(TIMER1_IRQn,APP_IRQ_PRIORITY_LOW);
    APP_ERROR_CHECK(err_code);	
    err_code = sd_nvic_ClearPendingIRQ(TIMER1_IRQn);
    APP_ERROR_CHECK(err_code);	
    err_code = sd_nvic_EnableIRQ(TIMER1_IRQn);  
    APP_ERROR_CHECK(err_code);	
}
  • This seems to be ok, and I can't see any obvious problems with it, except that you may get some jitter in the CC events, due to the possibility of other interrupts interrupting the read-modify-write on the CC register.

    If you need a constant tick-like interrupt, I'd rather recommend you to use a short between the COMPARE event and the CLEAR task. If you do so, the interrupt will occur with a steady frequency, although the handler may have some jitter do to other interrupts, but this is simply unavoidable when being in a BLE connection.

    Is there a particular reason you're asking? Does it seem to behave unexpectedly in any way?

  • Thank you very much for your reply.

    As it is mandatory to use all softdevice functions like sd_clock_hfclk_request, I was not sure about the direct calls to the timer with NRF_TIMER1.

    Also as softdevice use NRF_TIMER0, can I stop the 16MHz using sd_clock_hfclk_release and start it when I need without disturbing the softdevice?

  • First, anything you can do through the softdevice APIs is safe to do.

    Secondly, it's useful to see the difference between the HFCLK, the external crystal and the different modules in the chip that uses the HFCLK.

    Each of the modules that are marked as requiring HFCLK in section 8.3 of the PS, will request the chip to start the HFCLK automatically, without you doing anything. This happens when you for example START a TIMER.

    By default, HFCLK will be sourced from an internal 16 MHz RC oscillator. However, some modules requires (or at least benefits) from having the HFCLK sourced from a crystal instead of the RC, due to the higher precision. For the RADIO, this is a strict requirement, and is handled internally for the softdevice. The ADC on the other hand is controlled entirely by the application, but is more precise with a crystal than with the RC.

    The softdevice therefore provides the sd_clock_hfclk_* API, so that you can request the crystal to be started for example for an ADC reading, and then release it afterwards. Beware that the crystal typically needs some milliseconds to start, so you may have to wait for it to be started before doing theNote the names of those APIs; you don't start it and stop it, you request it and release it. This aims to show that it is the softdevice that controls this, and if the softdevice needs the crystal for something, it will be started, independent of application requests.

    As you can see from the above, doing a release won't necessarily do anything else than tell the softdevice that the application won't mind if the crystal stops. Also, you can perfectly fine use the TIMER1 without requesting the HFCLK at all, and the only result from that will be that the timer will run of the RC instead of the crystal.

    Whether it makes sense to request the crystal depends on your application, but the run current of the crystal is actually lower than the RC. Hence, if you plan to run the timer for a long time (i.e. significantly longer than the crystal startup time), it reduce average current consumption.

Related