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

Timer with two compared values

Hello all,

I try to trigger two events with two different periods, the first at 200ms, the second at 300ms. When I set the same period for the compared value, it works correctly, but when I set differents periods (respectively 200 and 300 ms) it didn't work. Bellow my code :

/* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 *
 */

/** @file
*
* @defgroup gpiote_example_main main.c
* @{
* @ingroup nrf_gpiote_example
* @brief GPIOTE Example Application main file.
*
* This file contains the source code for a sample application using GPIOTE.
*/

#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_gpiote.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_gpiote.h"
#include "app_error.h"

#ifdef BSP_LED_0
    #define GPIO_OUTPUT_PIN_NUMBER BSP_LED_0  /**< Pin number for output. */
#endif
#ifndef GPIO_OUTPUT_PIN_NUMBER
    #error "Please indicate output pin"
#endif

#define PERIOD_0 200
#define PERIOD_1 300

static nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(0);

void timer_dummy_handler(nrf_timer_event_t event_type, void * p_context)
{
      uint32_t compare_evt_addr_0, compare_evt_addr_1;
      uint32_t gpiote_task_addr_0, gpiote_task_addr_1;
      nrf_ppi_channel_t ppi_channel_0, ppi_channel_1;
      ret_code_t err_code;
      err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_0);
      APP_ERROR_CHECK(err_code);
      err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
      APP_ERROR_CHECK(err_code);

      compare_evt_addr_0 = nrf_drv_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE0);
      gpiote_task_addr_0 = nrf_drv_gpiote_out_task_addr_get(BSP_LED_0);

      compare_evt_addr_1 = nrf_drv_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE1);
      gpiote_task_addr_1 = nrf_drv_gpiote_out_task_addr_get(BSP_LED_1);

      err_code = nrf_drv_ppi_channel_enable(ppi_channel_0);
      APP_ERROR_CHECK(err_code);

      err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
      APP_ERROR_CHECK(err_code);
switch (event_type)
      {
        case NRF_TIMER_EVENT_COMPARE0:
        err_code = nrf_drv_ppi_channel_assign(ppi_channel_0, compare_evt_addr_0, gpiote_task_addr_0);
        APP_ERROR_CHECK(err_code);
        break;

        case NRF_TIMER_EVENT_COMPARE1:
          err_code = nrf_drv_ppi_channel_assign(ppi_channel_1, compare_evt_addr_1, gpiote_task_addr_1);
          APP_ERROR_CHECK(err_code);
        break;

        default:
        break;

      }
}

static void led_blinking_setup()
{

    ret_code_t err_code;
    nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);

    err_code = nrf_drv_gpiote_out_init(BSP_LED_0, &config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_gpiote_out_init(BSP_LED_1, &config);
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_extended_compare(&timer, (nrf_timer_cc_channel_t)0, PERIOD_0 * 1000UL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
    nrf_drv_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL1, PERIOD_1 * 1000UL, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);


    nrf_drv_gpiote_out_task_enable(BSP_LED_0);
    nrf_drv_gpiote_out_task_enable(BSP_LED_1);
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;

    err_code = nrf_drv_timer_init(&timer, &timer_cfg, timer_dummy_handler);
    APP_ERROR_CHECK(err_code);
#ifdef NRF51
    //Workaround for PAN-73.
    *(uint32_t *)0x40008C0C = 1;
#endif

    // Setup PPI channel with event from TIMER compare and task GPIOTE pin toggle.
    led_blinking_setup();

    // Enable timer
    nrf_drv_timer_enable(&timer);

    while (true)
    {
        // Do Nothing - GPIO can be toggled without software intervention.
    }
}


/** @} */
  • thank you so much for your help. It works, but for my basic application, I dont want to use ppi, it was only for debug, so now, i try to implement a simple program using timer and 3 compare events with different period (respectively 200, 300 and 400 ms), without using ppi (of corse). So, I implement this program which didn't work, and the events are triggered at the maximal period of these setted for each event (400 ms in my case). Bellow my code :

    /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
     *
     * The information contained herein is property of Nordic Semiconductor ASA.
     * Terms and conditions of usage are described in detail in NORDIC
     * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
     *
     * Licensees are granted free, non-transferable use of the information. NO
     * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
     * the file.
     *
     */
    
    /** @file
    *
    * @defgroup gpiote_example_main main.c
    * @{
    * @ingroup nrf_gpiote_example
    * @brief GPIOTE Example Application main file.
    *
    * This file contains the source code for a sample application using GPIOTE.
    */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf.h"
    #include "nrf_gpiote.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    #include "nrf_drv_gpiote.h"
    #include "app_error.h"
    
    #define PERIOD_0 200
    #define PERIOD_1 300
    #define PERIOD_2 400
    
    static nrf_drv_timer_t timer = NRF_DRV_TIMER_INSTANCE(0);
    
    void timer_dummy_handler(nrf_timer_event_t event_type, void * p_context)
    {
      if (event_type==NRF_TIMER_EVENT_COMPARE0)
      {
              nrf_drv_gpiote_out_toggle(BSP_LED_0);
      }
    
      if (event_type==NRF_TIMER_EVENT_COMPARE1)
      {
              nrf_drv_gpiote_out_toggle(BSP_LED_1);
      }
    
      if (event_type==NRF_TIMER_EVENT_COMPARE2)
      {
              nrf_drv_gpiote_out_toggle(BSP_LED_2);
      }
    }
    
    static void led_blinking_setup()
    {
    
        ret_code_t err_code;
    
        nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
    
        err_code = nrf_drv_gpiote_out_init(BSP_LED_0, &out_config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_gpiote_out_init(BSP_LED_1, &out_config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_gpiote_out_init(BSP_LED_2, &out_config);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_compare(&timer, NRF_TIMER_CC_CHANNEL0, PERIOD_0 * 1000UL, true);
        nrf_drv_timer_compare(&timer, NRF_TIMER_CC_CHANNEL1, PERIOD_1 * 1000UL, true);
        nrf_drv_timer_extended_compare(&timer, NRF_TIMER_CC_CHANNEL2, PERIOD_2 * 1000UL, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true);
    
    }
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        err_code = nrf_drv_timer_init(&timer, &timer_cfg, timer_dummy_handler);
        APP_ERROR_CHECK(err_code);
    #ifdef NRF51
        //Workaround for PAN-73.
        *(uint32_t *)0x40008C0C = 1;
    #endif
    
        // Setup PPI channel with event from TIMER compare and task GPIOTE pin toggle.
        led_blinking_setup();
    
        // Enable timer
        nrf_drv_timer_enable(&timer);
    
        while (true)
        {
            // Do Nothing - GPIO can be toggled without software intervention.
        }
    }
    
    
    /** @} */
    
  • Then I would rather recommend that you take a look at the application timer library. There is a great tutorial to get you started here at DevZone. The application timer library use RTC instead of timers, making it more low-power. Only 1 RTC is used. I have created an example that use three different periods: app_timer_three_periods.c

  • In the example file for two channels given above, if i change the time to 100ms and 2seconds for the two channels, looks like led0 blinks 100ms for every 2seconds. It does not keep blinking continuously every 100ms. Looks like the multiple channels is only for pwm/sequencing. It is not a solution for the problem below

    Event:          0   1       0   1       0   1     CC
            |---|---|---|---|---|---|---|---|---|---|
    Time:   0  100 200 300 400 500 600 700 800 900   [ms]
    

    Is my understanding correct?

  • @arjunhary: I'm not sure I understand your question, but the code I posted above was not a general example. You will have to modify the example to make it work for other periods. This method will not work for 100ms and 2 seconds, as there is not enough compare channels in the timer and GPIOTE/PPI channels in the chip. Can you solve your problem using app_timer, as suggested in my comment below, or the solution proposed by Torbjørn in this other question you posted?

Related