This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Problems when counting pulses using GPIOTE and TIMER via PPI in the presence of SoftDevice

I am trying to implement frequency counting on nRF51822 by counting number of pulses in a given period. I create a PPI channel with a GPIOTE event on rising edge linked to TIMER counting task. The relevant code is as follows:

#define USE_WITH_SOFTDEVICE     1

#define FC_GPIO   2
#define FC_TIMER  NRF_TIMER0 
#define FC_GPIOTE_CH  0 
#define FC_PPI_CH  0

static void ppi_enable_channel(uint32_t ch_num, volatile uint32_t *event_ptr, volatile uint32_t *task_ptr)
{
    if(ch_num >= 16) return;
    else
    {
#if(USE_WITH_SOFTDEVICE == 1)
        sd_ppi_channel_assign(ch_num, event_ptr, task_ptr);
        sd_ppi_channel_enable_set(1 << ch_num);
#else
        // Otherwise we configure the channel and return the channel number
        NRF_PPI->CH[ch_num].EEP = (uint32_t)event_ptr;
        NRF_PPI->CH[ch_num].TEP = (uint32_t)task_ptr;    
        NRF_PPI->CHENSET = (1 << ch_num);   
#endif
    }
}


// Create a PPI channel: GPIOTE event from low to high --> FC_TIMER count up by 1 
static void counting_init(void)
{ 
	nrf_gpio_cfg_input(FC_GPIO, NRF_GPIO_PIN_NOPULL);   // frequency counting input
	
	// Init timer
  FC_TIMER->TASKS_CLEAR = 1;
  FC_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
	FC_TIMER->MODE = TIMER_MODE_MODE_Counter;
	FC_TIMER->PRESCALER = 0; 
	FC_TIMER->TASKS_CAPTURE[0] = 0;
	
	// Init GPIOTE
	nrf_gpiote_event_config(FC_GPIOTE_CH, FC_GPIO, NRF_GPIOTE_POLARITY_LOTOHI);
	
	// enable PPI
	ppi_enable_channel(FC_PPI_CH, &NRF_GPIOTE->EVENTS_IN[FC_GPIOTE_CH], &FC_TIMER->TASKS_COUNT);
	
}

// Destructor 
static void counting_deinit(void)
{
	FC_TIMER->TASKS_STOP = 1;
	FC_TIMER->TASKS_SHUTDOWN = 1;
	nrf_gpiote_unconfig(FC_GPIOTE_CH);
	nrf_gpio_cfg_output(FC_GPIO);
	nrf_gpio_pin_clear(FC_GPIO);
}

static uint16_t count_get(void)
{
	uint16_t count;
	counting_init();
	FC_TIMER->TASKS_START = 1;
	nrf_delay_ms(1);  // try busy wait
	FC_TIMER->TASKS_CAPTURE[0] = 1;
  count = FC_TIMER->CC[0];
	counting_deinit();
	return count;
}

The last function count_get() returns the number of counts. However, when I call the function in the code, the program results in hard default. If I don't call the function, the code runs fine. So there should be something wrong with the way I implement in. Please advise.

  • @RK just curious, what toolchain are you using?

  • I use crossworks - mostly because I'm on OSX but even if I was on windows I'd probably still use it because I prefer it, it's cheaper and it supports most of the other chips I work on as well (as long as they are ARM). Like all IDEs you have to spend time working with it to learn all the ins and outs but it doesn't try to be too clever and hide all the details from you behind packs and clever plugins. The worst for that is probably TI's code composer studio which has so many clever bits of script and behind-the-scenes tools it's just about impossible to figure out what was compiled and linked with what.

    If you have Keil however, use Keil. You just need to take a little development time to sort out issues like the one you mentioned above and give yourself a rock solid debug environment -the time put into it now pays dividends later.

  • Timer0 is used by the SoftDevice, accessing it may lead to a hardfault. Switching to timer1 or timer2 should fix the problem. See here for which type of access you have to the resources while the SoftDevice is enabled.

  • @Ole I change from NRF_TIMER0 to NRF_TIMER1, and the code runs without a hard default. Now I have a ~300kHz square wave between 0V and VCC (2.8V) going to GPIO pin 2 (FC_GPIO defined in the code), and call count_get() in the main function. It always return 0x0000 but it shouldn't. I set a breakout and check the value of NRF_TIMER1->CC[0] register. It is indeed 0. I can also see BITMODE, MODE, and PRESCALER registers of NRF_TIMER1 are set to correct values, which means the NRF_TIMER1 is initiated correctly. I am suspecting there may be something wrong with the PPI configuration. I checked the PPI registers after calling PPI_enable_channel(), and the results are here. Do you know where I get it wrong?

  • @Ole The code is actually working now after I correct a bug elsewhere.

Related