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

Timer0 and Timer 1, inconsistent operation

I am using Timer0 and Timer with GPIOTE and PPI to output 2 clocks on 2 pins.

Both timer settings are identical (for troubleshooting). Only timer-0 can be generated at the output pins (pin-1 and pin-2). While timer-1 does not produce any output.

(after spending 10+ hours of testing, and missing a deadline, and checking that both timers are enabled in the sdk_config.h)

any clue what can be the reason ?

/*
  Use Timer with PPI and GPIOTE
  Generates 4MHz timer on output pin
  Timer1 is not outputting
*/

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

#include "boards.h"
#include "nrf_drv_gpiote.h"

#define I2S_SCK     NRF_GPIO_PIN_MAP(0,13)
#define I2S_LRCLK   NRF_GPIO_PIN_MAP(0,3)
#define LED_Power   NRF_GPIO_PIN_MAP(1,9)

// Create variable to hold error values
ret_code_t err_code;

// Create timer instance
const nrf_drv_timer_t Timer_0 = NRF_DRV_TIMER_INSTANCE(0);
const nrf_drv_timer_t Timer_1 = NRF_DRV_TIMER_INSTANCE(1);

// Create Timer ISR handler
void Timer_0_handler(nrf_timer_event_t event_type, void* p_context)
{
}

void Timer_1_handler(nrf_timer_event_t event_type, void* p_context)
{
}

// A function to initialize and set everything for the timers with PPI and GPIOTE
static void Initialize_Timer_PPI_GPIOTE(void)
{
//NRF_CLOCK->TASKS_HFCLKSTART = 1;
//    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
//    {
//        // Wait for clock to start
//    }

    // Configure timer as counter, 64 counts at 4MHz
    nrf_drv_timer_config_t Timer_0_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    Timer_0_cfg.frequency = NRF_TIMER_FREQ_8MHz;
    //Timer_0_cfg.mode = NRF_TIMER_MODE_COUNTER;
    //Timer_0_cfg.bit_width = TIMER_BITMODE_BITMODE_32Bit;
    // Set up timer
    NRF_TIMER0->PRESCALER = 1;
    NRF_TIMER0->CC[0] = 1; // Adjust the output frequency by adjusting the CC.
    //NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
    NRF_TIMER0->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled;
    //NRF_TIMER0->TASKS_START = 1;

  // Configure timer as counter, 2 counts at 62.5KHz
    nrf_drv_timer_config_t Timer_1_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    Timer_1_cfg.frequency = NRF_TIMER_FREQ_4MHz;
    //Timer_1_cfg.mode = NRF_TIMER_MODE_COUNTER;
    //Timer_1_cfg.bit_width = TIMER_BITMODE_BITMODE_32Bit;
    // Set up timer
    NRF_TIMER1->PRESCALER = 0;
    NRF_TIMER1->CC[1] = 1; // Adjust the output frequency by adjusting the CC.
    //NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos;
    NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled;
    //NRF_TIMER1->TASKS_START = 1;
   
    // Initialize timers
    err_code = nrf_drv_timer_init(&Timer_0, &Timer_0_cfg, Timer_0_handler);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_timer_init(&Timer_1, &Timer_1_cfg, Timer_1_handler);
    APP_ERROR_CHECK(err_code);

    // Create variables to hold event and task addresses. They will connect with PPI TEP (Task End Point) and PPI EEP (Event End Point)
    uint32_t compare_event_addr_1;
    uint32_t compare_event_addr_2;
    uint32_t gpiote_task_addr_1;
    uint32_t gpiote_task_addr_2;

    // Create structure to hold PPI channel values
    nrf_ppi_channel_t ppi_channel_1;
    nrf_ppi_channel_t ppi_channel_2;
    
    // Initialize GPTIOTE module
    if(!nrf_drv_gpiote_is_init())
    {
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    }
    
    // Initialize PPI module, make sure it is only enabled once in the code
    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);
    
    // Allocate a channel from available PPI channels
    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_1);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_alloc(&ppi_channel_2);
    APP_ERROR_CHECK(err_code);
    
    // Enable and configure the pin (high/low/toggle). True ? Initial high state, False ? Initial low state
    nrf_drv_gpiote_out_config_t out_config_1 = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
    err_code = nrf_drv_gpiote_out_init(I2S_SCK, &out_config_1);
    APP_ERROR_CHECK(err_code);
    nrf_drv_gpiote_out_config_t out_config_2 = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
    err_code = nrf_drv_gpiote_out_init(I2S_LRCLK, &out_config_2);
    APP_ERROR_CHECK(err_code);

    // Get address of respective event and tasks from the respective peripherals
    compare_event_addr_1 = nrf_drv_timer_event_address_get(&Timer_0, NRF_TIMER_EVENT_COMPARE0);
    gpiote_task_addr_1 = nrf_drv_gpiote_out_task_addr_get(I2S_SCK);
    compare_event_addr_2 = nrf_drv_timer_event_address_get(&Timer_1, NRF_TIMER_EVENT_COMPARE1);
    gpiote_task_addr_2 = nrf_drv_gpiote_out_task_addr_get(I2S_LRCLK);
    
    // Connect EEP & TEP with Peripheral Events and Tasks using their addresses and assign them to an allocated channel
    err_code = nrf_drv_ppi_channel_assign(ppi_channel_1, compare_event_addr_1, gpiote_task_addr_1);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_assign(ppi_channel_2, compare_event_addr_2, gpiote_task_addr_2);
    APP_ERROR_CHECK(err_code);
    
    // Enable channel to start receiving events and route them to tasks
    err_code = nrf_drv_ppi_channel_enable(ppi_channel_1);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_ppi_channel_enable(ppi_channel_2);
    APP_ERROR_CHECK(err_code);
    
    // Enable pin task to be executed when called by any event via PPI
    nrf_drv_gpiote_out_task_enable(I2S_SCK);
    nrf_drv_gpiote_out_task_enable(I2S_LRCLK);
}


int main(void)
{
    nrf_gpio_cfg_output(I2S_SCK);
    nrf_gpio_cfg_output(I2S_LRCLK);
    nrf_gpio_cfg_output(LED_Power);
    nrf_gpio_pin_clear(I2S_SCK);
    nrf_gpio_pin_clear(I2S_LRCLK);
    nrf_gpio_pin_set(LED_Power);

    Initialize_Timer_PPI_GPIOTE();

      // Start timer
      nrf_drv_timer_enable(&Timer_0);
      nrf_drv_timer_enable(&Timer_1);

    while (1)
    {
//        __WFI();
    }
}

Parents
  • This line is incorrect:

    NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled;

    You mention that both timer settings are identical, but they are not as Compare 0 is used on Timer 0 but Compare 1 is used on Timer 1. The best solution is to use Compare 0 on both timers as each timer has independent compare registers. However a quick fix is to simply left shift the clear bit mentioned above by 1 place; that was what the line above in the original post was doing. The #defines can be somewhat confusing, and causes misunderstandings such as this.

    NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos;

  • Hi

    First, thank you so much for replying promptly on a friday. The code I uploaded had a wrong line, I have tried several combinations, including identical variable except for the timer instance. Sorry about the confusion.

    So, does each timer her its own 5 CC[n] registers ? or is it a single set of CC[n] registers that are shared among all ?

    Second question. I have been trying to find a way to assign a functions to the timer. I need to trigger a line when the timer produces 32 pulses with minimum delay. I have to manually implement 2 clock signals for I2S interface, one at 4MHz and another at 62.5KHz. So Using one timer to produce the 4MHz then it will trigger another line every 32 counts to produce the 62.5KHz. Is there any resource to read about writing interrupts for timers ?

    thanks

Reply
  • Hi

    First, thank you so much for replying promptly on a friday. The code I uploaded had a wrong line, I have tried several combinations, including identical variable except for the timer instance. Sorry about the confusion.

    So, does each timer her its own 5 CC[n] registers ? or is it a single set of CC[n] registers that are shared among all ?

    Second question. I have been trying to find a way to assign a functions to the timer. I need to trigger a line when the timer produces 32 pulses with minimum delay. I have to manually implement 2 clock signals for I2S interface, one at 4MHz and another at 62.5KHz. So Using one timer to produce the 4MHz then it will trigger another line every 32 counts to produce the 62.5KHz. Is there any resource to read about writing interrupts for timers ?

    thanks

Children
No Data
Related