Basic nRF timer usage

So what I understand from the lesson over here is that we have couple of timers available to us and each timer comprise of multiple compare/capture register which can be used to generate and service an interrupt when the value of CC register is equal to the set value. In the following code I am trying to implement this feature to toggle two different LEDs using two CC register. I have set the value in CC by converting ms to ticks. Essentially telling timer to service interrupts when values in CC register equals x milliseconds hence toggeling LEDs at different time intervals in correspondence to CC registers values . I am not sure what I am doing wrong. Would love to know if there is some concept I need to understand.

#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_drv_timer.h"
#include "bsp.h"
#include "app_error.h"

#define LED1 17
#define LED2 18

const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(0);

void timer0_handler(nrf_timer_event_t event_type, void *p_context)
{
  switch(event_type)
  {
    case NRF_TIMER_EVENT_COMPARE0:
    nrf_gpio_pin_toggle(LED1);     
    break;
    
    case NRF_TIMER_EVENT_COMPARE1:
    nrf_gpio_pin_toggle(LED2);    
    break;
    
    default:
      //nothing
    break;
  }
}


void timer_init(void)
{
  uint32_t err_code = NRF_SUCCESS;
  
  uint32_t time_ms = 100;
  uint32_t time_ms2 = 500;
  
  uint32_t time_ticks;
  uint32_t time_ticks2;
  
  nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; // Default timer config
  
  err_code = nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer0_handler); // init the timer with custom timer instance, config and handler for it
  APP_ERROR_CHECK(err_code);
  
  time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_LED, time_ms); // convert ms to ticks so that timer compare register can generate interprit
  time_ticks2 = nrf_drv_timer_ms_to_ticks(&TIMER_LED, time_ms2); // convert ms to ticks so that timer compare register can generate interprit
  
  nrf_drv_timer_extended_compare(&TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
  nrf_drv_timer_extended_compare(&TIMER_LED, NRF_TIMER_CC_CHANNEL1, time_ticks2, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
}

int main(void)
{
    nrf_gpio_cfg_output(LED1);
    nrf_gpio_cfg_output(LED2);
    
    nrf_gpio_pin_set(LED1);
    nrf_gpio_pin_set(LED2);
    
    timer_init();
    
    nrf_drv_timer_enable(&TIMER_LED);
    

    while (1)
    {
        __WFI();
    }
}


  • Hi Purvesh,

    Sorry for the late reply. The simple answer is that timmer reset on the first CC register so you never reach the second.

    See a similar case in this thread: (+) Nordic DevZone (nordicsemi.com)

    Best regards,

    Charlie

  • Hi Charlie,

    Thanks for the link. Do you have any example code which could help me understand this?

    Regards

  • How about the following code?

    #include "app_error.h"
    #include "bsp.h"
    #include "nrf.h"
    #include "nrf_drv_timer.h"
    #include <stdbool.h>
    #include <stdint.h>
    
    
    const nrfx_timer_t TIMER_LED = NRFX_TIMER_INSTANCE(0); // Timer 0 Enabled
    
    
    #define LED1 17
    #define LED2 18
        
    
    
    void timer0_handler(nrf_timer_event_t event_type, void *p_context)
    {
        switch (event_type)
        {
            case NRF_TIMER_EVENT_COMPARE0:
                nrf_gpio_pin_toggle(LED1);
                break;
    
            case NRF_TIMER_EVENT_COMPARE1:
                nrf_gpio_pin_toggle(LED2);
                nrfx_timer_clear(&TIMER_LED);
                break;
                
            default:
                break;
        }
              
    }
    
    
    void timer_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        uint32_t time_ms = 100;
        uint32_t time_ms1 = 1000;
    
        uint32_t time_ticks;
        uint32_t time_ticks1;
    
    
        nrfx_timer_config_t timer_cfg =
            NRFX_TIMER_DEFAULT_CONFIG; // Configure the timer instance to default settings
    
    
        err_code = nrfx_timer_init(&TIMER_LED, &timer_cfg, timer0_handler); // Initialize the timer0 with default settings
        APP_ERROR_CHECK(err_code);                   // check if any error occured
    
    
        time_ticks = nrfx_timer_ms_to_ticks(&TIMER_LED, time_ms); // convert ms to ticks
        time_ticks1 = nrfx_timer_ms_to_ticks(&TIMER_LED, time_ms1);
    
        // Assign a channel, pass the number of ticks & enable interrupt
        nrfx_timer_compare(&TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, true);
        nrfx_timer_compare(&TIMER_LED, NRF_TIMER_CC_CHANNEL1, time_ticks1, true);
    }
    
    /**
     * @brief Function for main application entry.
     */
    int main(void)
    {
    
        nrf_gpio_cfg_output(LED1); // Initialize the pin
        nrf_gpio_cfg_output(LED2); // Initialize the pin
    
        nrf_gpio_pin_set(LED1); // Turn off the LED
        nrf_gpio_pin_set(LED2); // Turn off the LED
    
        timer_init();
    
        nrfx_timer_enable(&TIMER_LED);
    
    
        while (1)
        {
            __WFI(); // GO INTO LOW POWER MODE
        }
    }
    

  • The codes have no issue, but I think this is not what you expected and you expect LED1 toggles every 100ms and LED2 toggles every 1000ms. In the above code, LED1 and LED2 will toggle every 1000ms, and LED1 toggles 900ms early than LED2. Keep in mind the two channels compare with the same value in Counter. 

    If your purpose is to generate PWM waves on multiple channels, I suggest you use PWM peripheral. It is possible to use Timer but I think PWM is a better solution. Timer comparison channels are more likely to handle different tasks in one of the repeating periods.

  • The codes have no issue, but I think this is not what you expected and you expect LED1 toggles every 100ms and LED2 toggles every 1000ms. In the above code, LED1 and LED2 will toggle every 1000ms, and LED1 toggles 900ms early than LED2. Keep in mind the two channels compare with the same value in Counter. 

    This is the thing which I am trying to implement. Not PWM. Can you please share an example code which might help me solve this issue?

    Thanks

    Regards

Related