Timer interrupt don't work in ble_app_uart of SDK6.1.0

Hello everybody

I am working with the Raytac BLE Module "MDBT40", which is based on nrf51822.

And I am testing example project "ble_app_uart" in the SDK6.1.0 now.

But there are some problems when I add a new timer.

In the project "ble_app_uart", It contain only RTC timer.

However, I can't understand how the RTC interrupt work in the demo code.

So I add a timer2 in the project as below.

I hope it turn on LED once 100ms.

void start_timer2(void)
{		
  // Start 16 MHz crystal oscillator.
  NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;	
  NRF_CLOCK->TASKS_HFCLKSTART    = 1;	
	
  while(NRF_CLOCK->EVENTS_HFCLKSTARTED==0){}
	
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // Set the timer in Counter Mode
  NRF_TIMER2->TASKS_CLEAR = 1;               // clear the task first to be usable for later
  NRF_TIMER2->PRESCALER = 9;                             //Set prescaler. Higher number gives slower timer. Prescaler = 0 gives 16MHz timer. Prescaler = 9 gives 31250 Hz timer, 1tick 32us.
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;		 //Set counter to 16 bit resolution
  NRF_TIMER2->CC[0] = 3125;                              //Set value for TIMER2 compare register 0. Period is 32us * 3125 = 100ms.
		
  // Enable interrupt on Timer 2, for CC[0] 
  NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
  NVIC_EnableIRQ(TIMER2_IRQn);
		
  NRF_TIMER2->TASKS_START = 1;               // Start TIMER2
}
		
/** TIMTER1 peripheral interrupt handler. This interrupt handler is called whenever there it a TIMER1 interrupt
 */
void TIMER2_IRQHandler(void)
{
	if ((NRF_TIMER2->EVENTS_COMPARE[0] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE0_Msk) != 0))
  {
		NRF_TIMER2->EVENTS_COMPARE[0] = 0;           //Clear compare register 0 event	
		NRF_TIMER2->TASKS_CLEAR=1;

		// turn on LED
		nrf_gpio_pin_set(D03);
		while(1){};
  }
}

And I put "start_timer2();" after "timers_init();" in main function.

But it doesn't interrupt while running.

What I miss in the process?

Sorry for my poor English.

And thanks in advance!


More test information

this is my main function

int main(void)
{
	
	static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
	static uint8_t index = 0;
	uint8_t index_backup = 0;
	uint8_t newbyte;
		int i=0;
	
	// Initialize
	gpio_init();
	timers_init();
	start_timer2();	
	uart_init();
	ble_stack_init();
	gap_params_init();
	services_init();
	advertising_init();
	conn_params_init();
	sec_params_init();
	
	uart_putstring((const uint8_t *)START_STRING);

	advertising_start();
			
	// Enter main loop
	for (;;)
	{ 
		/*Stop reading new data if there are no ble buffers available */
		if(ble_buffer_available)
		{
			if(app_uart_get(&newbyte) == NRF_SUCCESS)
			{
				data_array[index] = newbyte;
				
				if (data_array[index] == '\n')
						{
					ble_buffer_available = ble_attempt_to_send(&data_array[0],index);
					index_backup = index;
					  if(ble_buffer_available) index = 0; 
						}
				else if (index == (BLE_NUS_MAX_DATA_LEN-1))
						{							 
					ble_buffer_available = ble_attempt_to_send(&data_array[0],index+1);
					index_backup = index+1;
					if(ble_buffer_available) index = 0;         	  	
						}
						else
						{
							index++;
						}
			}
		}
				
				
		/* Re-transmission if ble_buffer_available was set to false*/
		if(tx_complete)
		{
			tx_complete=false;
			index = index_backup;
			ble_buffer_available = ble_attempt_to_send(&data_array[0],index);
			if(ble_buffer_available) index = 0;
		}

		power_manage();
	}
}

For testing, I turn on LED to make sure when process get trouble.

And process stop between turnonLED1 and turnonLED2 which in ble_stack_init();

	static void ble_stack_init(void)
{
	uint32_t err_code;
  
	nrf_gpio_cfg_input(EXT_XTAL_MODE,NRF_GPIO_PIN_PULLUP);

	TurnonLED1();
	
	  if(nrf_gpio_pin_read(EXT_XTAL_MODE) == 1) 
	  {
		  // Initialize SoftDevice.
		SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_1000MS_CALIBRATION, false);
	  }
	  else
	  {
		  // Initialize SoftDevice.
		SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
	  }
	  
	TurnonLED2();	
	
	// Enable BLE stack 
	ble_enable_params_t ble_enable_params;
	memset(&ble_enable_params, 0, sizeof(ble_enable_params));
	ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
	err_code = sd_ble_enable(&ble_enable_params);
	APP_ERROR_CHECK(err_code);
	
	// Subscribe for BLE events.
	err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
	APP_ERROR_CHECK(err_code);
}

Then I change position of start_time2(); in main(); as below

	int main(void)
{
	
	static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
	static uint8_t index = 0;
	uint8_t index_backup = 0;
	uint8_t newbyte;
		int i=0;
	
	// Initialize
	//leds_init();
		gpio_init();
	timers_init();
	
		nrf_gpio_pin_clear(DIG3); 
	//buttons_init();
	uart_init();
	ble_stack_init();
	gap_params_init();
	services_init();
	advertising_init();
	conn_params_init();
	sec_params_init();
	
	uart_putstring((const uint8_t *)START_STRING);

		start_timer2();
		
	advertising_start();
	//skip...
}

Process stop between turnonLED3 and turnonLED4 which in start_timer2();

	void start_timer2(void)
{		
	turnonLED3();
	
	// Start 16 MHz crystal oscillator.
	NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;	
	NRF_CLOCK->TASKS_HFCLKSTART    = 1;	
	
	turnonLED4();
	
	while(NRF_CLOCK->EVENTS_HFCLKSTARTED==0){}
		
	NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // Set the timer in Counter Mode
	NRF_TIMER2->TASKS_CLEAR = 1;               // clear the task first to be usable for later
	NRF_TIMER2->PRESCALER = 9;                             //Set prescaler. Higher number gives slower timer. Prescaler = 0 gives 16MHz timer. Prescaler = 9 gives 31250 Hz timer, 1tick 32us.
	NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;		 //Set counter to 16 bit resolution
	NRF_TIMER2->CC[0] = 3125;                              //Set value for TIMER2 compare register 0. Period is 32us * 3125 = 100ms.
		
  // Enable interrupt on Timer 2, both for CC[0] and CC[1] compare match events
	NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
  NVIC_EnableIRQ(TIMER2_IRQn);
		
  NRF_TIMER2->TASKS_START = 1;               // Start TIMER2

}

Maybe it helpful to find problem?


Just more testing

I use app_timer instead of timer2.

It's working but "TIMER_INTERVAL" didn't perform as expected.(It take longer than 1ms to trigger interrupt.)

Are there higher priority interrupt cause it?(Bluetooth or Uart?)

And why timer2 can't work fine?

#define APP_TIMER_PRESCALER             0                                           /**< Value of the RTC1 PRESCALER register. */
#define APP_TIMER_MAX_TIMERS            2                                           /**< Maximum number of simultaneously created timers. */
#define APP_TIMER_OP_QUEUE_SIZE         4                                           /**< Size of timer operation queues. */

static app_timer_id_t  m_app_timer_id;
#define TIMER_INTERVAL  APP_TIMER_TICKS(1, APP_TIMER_PRESCALER) // Timer_interval is 1ms 

static void start_timer(void)
{
	uint32_t err_code;

	err_code = app_timer_start(m_app_timer_id, TIMER_INTERVAL, NULL);
	APP_ERROR_CHECK(err_code);
}

void display_timeout_handler(void * p_context)
{
		DriveXDig7Segment();
}

int main(void)
{
	
	static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
	static uint8_t index = 0;
	uint8_t index_backup = 0;
	uint8_t newbyte;

	// Initialize
	//leds_init();
		gpio_init();
	timers_init();
	//buttons_init();
	uart_init();
	ble_stack_init();
	gap_params_init();
	services_init();
	advertising_init();
	conn_params_init();
	sec_params_init();

	uart_putstring((const uint8_t *)START_STRING);
	
		start_timer();
		
	advertising_start();
	
	skip...
}
  • Have you configured the GPIO to be an output? nrf_gpio_cfg_output()? Are you sure that nrf_gpio_pin_set() will turn the LED on? Maybe you have to call nrf_gpio_pin_clear()? Have you tried to use the debugger? If you put a breakpoint in TIMER2_IRQHandler(), do you hit it?

  • Hi Petter. I am sure I have configured the GPIO to be an output. And function "TurnonLEDx" actually working. I don't know how to step by step debug with nrf51288 directly. I program with Keil5. I first build a hex file,then upload "S110 SoftDevice v7.0" and "hex file" by "nrfgo studio". I also put TurnonLEDx and delay in TIMER2_IRQHandler(),but it doesn't be trrigged.

  • Ok. I would recommend you to look into how to use the debugger.

    Maybe the problem is that you are accessing the NRF_CLOCK peripheral directly? This is a restricted peripheral when the SoftDevice is enabled, see Section 11.3 in the S110 SoftDevice specification 2.0 for more information. You can instead try to call sd_clock_hfclk_request().

  • Hi Petter.

    I fix code by calling "sd_clock_hfclk_request();" instead of "NRF_CLOCK->TASKS_HFCLKSTART = 1;" But it still work in trouble.

    1. It can work when "start_timer2();" is after "uart_putstring((const uint8_t *)START_STRING);", but not work when "start_timer2();" is after "timers_init();".

    2. Timer2 interrput is triggered with the same time, no matter NRF_TIMER2->CC[0] = 1 ,10, 100. Maybe the higher priority interrupt be triggered, and take long time.(I guess it's BLE or uart)

  • Ok. So what happens when put it after timers_init()? Are you able to execute the start_timer2() function? Do you get to ble_stack_init();? Please try to use the debug.

    Same time? How are you measuring this?