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

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,

    This is not an issue. It is just how the timer compare channels interrupt events work. It fits for applications that have different events happen in the same repeating interval. You should use two timers if the two events have different repeating frequencies.

  • Ok so my understanding is that we can have two different values in two different compare registers in that timer and the interrupt handler would executed. Having different cases in the interrupt handler for each compare event. we can have two led toggled at different frequencies taking into account that the we reset the timer only after the event which takes larger time. 

    This issue was solved by using app timer as shown in the following code.

    #include "nrf.h"
    #include "nordic_common.h"
    #include "boards.h"
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #include "nrf_gpio.h"
    
    // LED pin 
    #define LED_Pin1 17
    #define LED_Pin2 18
    
    // use a function to calculate the number of tick needed to 
    // create a delay of 100 millisec and store this value in LED_INTERVAL constant
    #define LED_INTERVAL APP_TIMER_TICKS(20)
    #define LED1_INTERVAL APP_TIMER_TICKS(50)
    
    
    
    // For each application timer we need to create a handle which points to that instance
    // so for evey application timer (Software timer) you create, you need to define a handle
    // create a handle and name it as:  m_app_timer_id 
    APP_TIMER_DEF(m_app_timer_id);
    APP_TIMER_DEF(m_app_timer_id1);
    
    
    
    // its really important to initialize the clock other wise the app timer will not work
    // so make sure you initialize it once in your code and if you are using a soft device
    // then you don't need to initialize the clock as the soft device automatically initializes it.
    static void lfclk_config(void)
    {
    	// initialize the low power low frequency clock
      ret_code_t err_code = nrf_drv_clock_init();
      APP_ERROR_CHECK(err_code);
    
    	// request the lf clock to not to generate any events on ticks
    	// One tick =  1 value increment in the counter register
      nrf_drv_clock_lfclk_request(NULL);
    
    }
    
    
    
    
    
    
    // create a simple handler function which will be called once the timer reaches its 
    // desired number of ticks value
    static void app_timer_handler(void * p_context)
    {
    	// Toggle the LED 
        nrf_gpio_pin_toggle(LED_Pin1);
    }
      
      static void app_timer_handler1(void * p_context)
    {
    	// Toggle the LED 
        nrf_gpio_pin_toggle(LED_Pin2);
    }
    
    
    
    // a function to initialize the Application timers
    static void timers_init(void)
    {
    	// a variable to hold error value
        ret_code_t err_code;
    
    	// Initialize the timer 
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
    	// Create an application timer with the handle, mode and interrupt event handle function
        err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, app_timer_handler);
        APP_ERROR_CHECK(err_code);
        
        err_code = app_timer_create(&m_app_timer_id1, APP_TIMER_MODE_REPEATED, app_timer_handler1);
    }
    
    
    
    
    
    int main(void)
    {
    
    // initialize the gpio for led
        nrf_gpio_cfg_output(LED_Pin1);
        nrf_gpio_cfg_output(LED_Pin2);
    
    // call the function to initialize the clock
        lfclk_config();
    // initialize the timer by calling this function which is performing all the basic steps
        timers_init();
    
    // start the timer so that it can generate events on the desired tick value
        uint32_t err_code = app_timer_start(m_app_timer_id, LED_INTERVAL, NULL);
        uint32_t err_code1 = app_timer_start(m_app_timer_id1, LED1_INTERVAL, NULL);
    
    
        while (true)
        {
            // Do nothing.
        }
    }
    
    
    
    
    
    

    The app timer uses only single timer to toggle to LEDs on different frequencies. My aim is to achieve this same functionality without using app timer but by using timer library.

  • The app timers are generated from RTC ticks, so it is different from the timer peripherals. Even so, your example still uses two app timer instances because the two led toggle at two different frequencies.

    If you have an application that two led toggle at the same frequency but have different duties, you can use one timer with two different comparison value. 

  • So while using app timer and creating two instances do we initialize two different RTCs or two different timing peripheral?

  • There is only RTC1 used for ticks generation. You can refer to discussion timer-vs-app_timer to learn more about their difference.

Related