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

Possible hardfault when using APP_TIMER with GPIOTE over S120?

I've modified the ble_app_uart example by adding GPIOTE so that the transmitter sends a character to the receiver when a GPIO pin is toggled. This part is working well.

Then, I added another handler that counted the number of falling edge occurring in another GPIO pin. I followed the advice in this thread to use the application timer.

The timer setup in main is

    APP_TIMER_DEF(timer_stim_freq_id);
    ....    
    err_code = app_timer_create(&timer_stim_freq_id, APP_TIMER_MODE_REPEATED, timer_stim_freq_handler);
    APP_ERROR_CHECK(err_code);

The GPIOTE initialisation is

  err_code = nrf_drv_gpiote_in_init(AUDIO_STIM_PIN, &fall_event_config, audio_stimulus_handler);
  NVIC_SetPriority(GPIOTE_IRQn, APP_IRQ_PRIORITY_LOW); // Otherwise, hardfault will occur.

The handler essentially gets the number of ticks elapsed in the application timer at each falling edge. It starts the timer for AUDIO_STIM_MARKER_WINDOW ms after detecting the first falling edge. It gets the number of ticks elapsed for each falling edge until the timer is timeout and calls the timeout handler, timer_stim_freq_handler. Then, this handler processes the ticks and restarts the timer with a different timeout, AUDIO_STIM_DEADZONE ms. And the cycle restarts.

void audio_stimulus_handler(void) 
{
	uint32_t err_code;
	//printf("%d\n",audio_stim_case);
	switch (audio_stim_case)
	{
		case AUDIO_STIM_STATE_IDLE:
		{
			// Start the timer
			err_code = app_timer_start(timer_stim_freq_id, APP_TIMER_TICKS(AUDIO_STIM_MARKER_WINDOW, APP_TIMER_PRESCALER), NULL);
      APP_ERROR_CHECK(err_code);
      err_code = app_timer_cnt_get(&start_tick);
      APP_ERROR_CHECK(err_code);			
			prev_tick = start_tick;
			audio_stim_sample_count = 0;
			// Move to the next state where the frequency starts being estimated
			audio_stim_case = AUDIO_STIM_STATE_EVAL_FREQ;
			break;
		}
		case AUDIO_STIM_STATE_EVAL_FREQ:
		{
			// Get the current tick
			err_code = app_timer_cnt_get(&curr_tick);
      APP_ERROR_CHECK(err_code);
			// Evaluate the difference in ticks
			uint32_t diff_tick;
			err_code = app_timer_cnt_diff_compute(curr_tick, prev_tick, &diff_tick);
			APP_ERROR_CHECK(err_code);
			audio_stim_timer_tick_array[audio_stim_sample_count++] = diff_tick;
			// Update the previous tick value
			prev_tick = curr_tick;

			break;
		}
		case AUDIO_STIM_STATE_DONE:
		{
			
			break;
		}
	}

static void timer_stim_freq_handler(void * p_context)
{
	uint32_t err_code, diff_tick;
	   	
	switch (audio_stim_case)
	{
		case AUDIO_STIM_STATE_EVAL_FREQ:
		{
			// Update the state
			audio_stim_case = AUDIO_STIM_STATE_DONE;
			// Stop the timer and start again with a different timeout
			err_code = app_timer_stop(timer_stim_freq_id);
      APP_ERROR_CHECK(err_code);
      err_code = app_timer_start(timer_stim_freq_id, APP_TIMER_TICKS(AUDIO_STIM_DEADZONE, APP_TIMER_PRESCALER), NULL);
      APP_ERROR_CHECK(err_code);
			// Display the ticks
			printf("START: %d\n", start_tick);
			// Estimate the frequency
			uint32_t ave_tick = average_tick(audio_stim_timer_tick_array, audio_stim_sample_count);
			uint32_t audio_freq = AUDIO_STIM_CLK_FREQ/ave_tick;
			// Send the frequency to the receiver
			uint8_t audio_data_array[BLE_NUS_MAX_DATA_LEN];
			audio_data_array[0] = (uint8_t)((audio_freq+50)/100)*10;
			audio_data_array[1] = '\n';
			printf("PULSE FREQ: %d\n", audio_data_array[0]);
			//uint32_t nrf_stat = ble_nus_c_string_send(&m_ble_nus_c, audio_data_array, 1);
			//printf("NRF: %d\n", nrf_stat);
			// Reset the array
			for (int i=0; i<AUDIO_STIM_MAX_SAMPLES; ++i)
			  audio_stim_timer_tick_array[i] = 0;
			break;
		}
		case AUDIO_STIM_STATE_DONE:
		{
			audio_stim_case = AUDIO_STIM_STATE_IDLE;
			err_code = app_timer_stop(timer_stim_freq_id);
      APP_ERROR_CHECK(err_code);
			break;
		}
		
	}
}

The code above worked and could detect the falling edges produced by an external waveform generator.

Then, the receiver unit was powered and the BLE connection was established. When the waveform generator was switched on, the transmitter kind of detected the first set of pulse and then crashed. (No data was sent over the BLE yet.)

I suspected something weird was occurring with the application timer. Without the receiver unit, start_tick was assigned correct values (see below). The interval between two starts was about 65000 ticks = 2 seconds.

START: 10501
PULSE FREQ: 1000
START: 76037
PULSE FREQ: 1000
START: 141574

With the receiver unit, start_tick was always 0. But somehow, it could detect the pulse frequency correctly until it crashed.

START: 0
PULSE FREQ: 1000
START: 0
PULSE FREQ: 1000
S

Is there any suggestion on why this combination of BLE and application timer could crash?

Is there any other solution apart from using the application timer?

I also increased APP_TIMER_OP_QUEUE_SIZE to 10, and even 30. But it did not solve the problem.

Related