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


/** @} */
Parents
  • Hi,

    You are using nrf_drv_timer_extended_compare() with a short, NRF_TIMER_SHORT_COMPAREx_CLEAR_MASK, to clear the timer. When the compare event of the first period happens, the timer will be cleared, resulting in the second period compare event never happening.

    You should use two different timers, or use the timers in a different way to get the functionality you want. Also, I don't think it is a good idea to configure the PPI channels inside the timer handler like you have done. I have rewritten your code to work in the way I think you intended:

    two_timers_example.c

    Best regards,

    Jørgen

  • It is possible to have different compare values, the problem is that you use a function that clears the timer on when the first compare value is matched. You can get these two events to happen on 200 and 300 ms by using:

    nrf_drv_timer_compare(&timer1, NRF_TIMER_CC_CHANNEL0, PERIOD_0 * 1000UL, true);
    nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL1, PERIOD_1 * 1000UL, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
    

    Then the first compare event will not clear the timer, allowing for the second timer event to happen. The problem with this method is that the timer will be cleared after the second timer event, so you will not get the second event for the first compare value befor 200 ms after the timer is cleared, i.e. at 500 ms:

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

    If I understand you correctly, you want the events to happen regularly, like this:

    Event:          0   1   0      0/1      0   1     CC
            |---|---|---|---|---|---|---|---|---|---|
    Time:   0  100 200 300 400 500 600 700 800 900   [ms]
    
Reply
  • It is possible to have different compare values, the problem is that you use a function that clears the timer on when the first compare value is matched. You can get these two events to happen on 200 and 300 ms by using:

    nrf_drv_timer_compare(&timer1, NRF_TIMER_CC_CHANNEL0, PERIOD_0 * 1000UL, true);
    nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL1, PERIOD_1 * 1000UL, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
    

    Then the first compare event will not clear the timer, allowing for the second timer event to happen. The problem with this method is that the timer will be cleared after the second timer event, so you will not get the second event for the first compare value befor 200 ms after the timer is cleared, i.e. at 500 ms:

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

    If I understand you correctly, you want the events to happen regularly, like this:

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