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!