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();
    }
}


Parents
  • 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

  • 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. 

    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

  • 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?

Reply Children
Related