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.