SAADC doesn't raise DONE task unless connected with debugger

I am working on an application where I am using 3 SAADC channels all with the same reference pin.

Upon startup, I will call app_sensor_init() to initialize my SAADC, timer and PPI to measure at 80Hz over 6.4s.

#define SAMPLING_RATE_US            (12500)  // 80Hz = 1e6/80 = 12500us
#define MAX_SAMPLE_COUNT            (512)    // duration = 6.4 seconds @ 80Hz -- 80 * 6.4 = 512

#define SAADC_PRIMARY_DATA_BUFFER_IDX   (0)
#define SAADC_SECONDARY_DATA_BUFFER_IDX (1)
#define SAADC_DATA_BUFFER_NB            (2)  // allows 2 buffers, one for data and one for backup

// The size of the data buffer dictates when a SAADC DONE task is raised given the frequency of the clock
#define SAADC_DATA_BUFFER_SIZE          (MAX_SAMPLE_COUNT * SENSOR_SAADC_CHANNEL_MAX)
static nrf_saadc_value_t saadc_data_buffer[SAADC_DATA_BUFFER_NB][SAADC_DATA_BUFFER_SIZE] = { 0 };

void app_sensor_init(nrf_drv_saadc_event_handler_t saadc_handler)
{
  NRF_LOG_INFO("%s()", __func__);

  ret_code_t ret = NRF_SUCCESS;

  /// Initialize signal handler
  errno_t err = sys_signal_module_init(SIGNAL_MOD_SENSOR, app_sensor_signal_handler);
  APP_ERROR_CHECK_BOOL(ERR_NONE == err);

  // Optional parameter for testing
  nrf_drv_saadc_event_handler_t handler = saadc_event_handler;
  if (saadc_handler != NULL)
  {
    handler = saadc_handler;
  }

  /// Initialize SAADC peripheral
  const nrf_drv_saadc_config_t saadc_config = {
    .resolution = NRF_SAADC_RESOLUTION_12BIT,     // Resolution configuration.
    .oversample = NRF_SAADC_OVERSAMPLE_DISABLED,  // Oversampling configuration.
    .interrupt_priority = SAADC_IRQ_PRIORITY,     // Interrupt priority.
    .low_power_mode = true                        // Indicates if low power mode is active.
  };
  ret = nrf_drv_saadc_init(&saadc_config, handler);
  APP_ERROR_CHECK(ret);

  /// Enable SAADC channels
  for (sensor_saadc_channel_e ch = (sensor_saadc_channel_e)0; ch < SENSOR_SAADC_CHANNEL_MAX; ch++)
  {
    ret = nrf_drv_saadc_channel_init(ch, &channel_configs[ch]);
    APP_ERROR_CHECK(ret);
  }

  /// Configure SAADC EasyDMA buffers
  ret = nrf_drv_saadc_buffer_convert(saadc_data_buffer[SAADC_PRIMARY_DATA_BUFFER_IDX], SAADC_DATA_BUFFER_SIZE);
  APP_ERROR_CHECK(ret);

  ret = nrf_drv_saadc_buffer_convert(saadc_data_buffer[SAADC_SECONDARY_DATA_BUFFER_IDX], SAADC_DATA_BUFFER_SIZE);
  APP_ERROR_CHECK(ret);

  /// Initialize PPI peripheral
  ret = nrf_drv_ppi_init();
  APP_ERROR_CHECK(ret);

  /// Initialize sampling timer
  nrf_drv_timer_config_t timer_config = {
    .frequency = NRF_TIMER_FREQ_500kHz,                 // Frequency.
    .mode = NRF_TIMER_MODE_TIMER,                       // Mode of operation.
    .bit_width = NRF_TIMER_BIT_WIDTH_32,                // Bit width.
    .interrupt_priority = SAMPLING_TIMER_IRQ_PRIORITY,  // Interrupt priority.
    .p_context = NULL                                   // Context passed to interrupt handler.
  };
  // nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
  ret = nrf_drv_timer_init(&sampling_timer_id, &timer_config, sampling_timer_event_handler);
  APP_ERROR_CHECK(ret);

  /// Configure sampling timer's rate
  nrf_drv_timer_extended_compare(
    &sampling_timer_id,
    NRF_TIMER_CC_CHANNEL0,
    nrf_drv_timer_us_to_ticks(&sampling_timer_id, SAMPLING_RATE_US),
    // shortcut between the compare event on the channel and the timer task (STOP or CLEAR).
    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
    // leave interrupt disabled to connect with PPI
    false);

  /// Configure PPI channel so timer compare event is triggering sample task in SAADC
  const uint32_t sampling_timer_compare_event_addr =
    nrf_drv_timer_compare_event_address_get(&sampling_timer_id, NRF_TIMER_CC_CHANNEL0);
  uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get();

  ret = nrf_drv_ppi_channel_alloc(&sampling_ppi_channel);
  APP_ERROR_CHECK(ret);

  ret = nrf_drv_ppi_channel_assign(sampling_ppi_channel, sampling_timer_compare_event_addr, saadc_sample_task_addr);
  APP_ERROR_CHECK(ret);
}

This doesn't start sampling, rather I have a BLE command that I use to trigger sampling via:

/// Reset sampling timer
nrf_drv_timer_clear(&sampling_timer_id);

/// Start/enable sampling timer
nrf_drv_timer_enable(&sampling_timer_id);

/// Enable sampling PPI events
ret = nrf_drv_ppi_channel_enable(sampling_ppi_channel);

// All error codes bad
if (NRF_SUCCESS != ret)
{
  NRF_LOG_ERROR("%s(): Failed to enable sampling PPI channel! Error 0x%02X", __func__, ret);
}

What I expect is upon the DONE task in the saadc_interrupt_handler, my saadc_data_buffer will have filled up indicating my measurement sequence is complete. In testing this, my thoughts are correct WHEN AND ONLY WHEN I am attached with my debugger. However, when I do not have a debugger attached, I'm not observing my RTT output from the saadc_interrupt_handler which also sends a stop signal to stop my PPI and timer from sampling the SAADC.

Why is this only working when I have my debugger attached? I'm thinking it might have something to do with the IDLE state when no activity is occurring on BLE? My project originally was based off ble_app_template example if that means anything.

Any thoughts would be appreciated!

Related