I'm using the nRF52832 with softdevice s132 and SDK14 with ARM GCC
I'm trying to set up the SAADC peripheral to read battery voltage, and I can get everything working as expected except periodic calibration. At boot, I call my initialization function, and then the application starts a timer for some number of seconds or minutes. When that timer expires, before trying to start a reading, my code checks to see if I should do calibration first. Due to the way it's set up, it always calibrates on the first timer expiration after boot, and this is where it fails. Here's a simplified version of my logic, which I have confirmed reproduces the issue without any timers or anything. There's more context in the code snippet comments. What am I doing wrong?
I've also tried setting it up like one of the examples where I don't actually check to see if I should calibrate until I get a NRF_DRV_SAADC_EVT_DONE event in the SAADC event handler in case that made a difference for some reason, but it doesn't. I skip the calibration check, start a reading, get the DONE event, check if calibration is needed, and then try to abort, but the abort call still locks up.
ret_code_t err_code;
/*
* Another configuration I've been testing uses AIN3 and 1/2 gain.
*/
nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
channel_config.gain = NRF_SAADC_GAIN1_6;
channel_config.burst = NRF_SAADC_BURST_ENABLED;
channel_config.acq_time = NRF_SAADC_ACQTIME_40US;
/*
* sdk_config.h settings
* #define SAADC_CONFIG_RESOLUTION 3 // 14-bit
* #define SAADC_CONFIG_OVERSAMPLE 3 // 8
* #define SAADC_CONFIG_LP_MODE 1 // low power enabled
* #define SAADC_CONFIG_IRQ_PRIORITY 7
*/
err_code = nrf_drv_saadc_init(NULL, battery_saadc_callback);
APP_ERROR_CHECK(err_code);
// Initialize SAADC channel 0 with the specified channel configuration
err_code = nrf_drv_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
// SAMPLES_IN_BUFFER set to 1
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
/* do some stuff to set up application logic */
/*
* Based on examples and forum posts, I call this to try to abort any pending
* actions before trying to start calibration. But this call always times out
* at nrf_drv_saadc.c line 604:
* (ERR0204) /source/firmware/nrf5-sdk/components/drivers_nrf/saadc/nrf_drv_saadc.c:604
*/
nrf_drv_saadc_abort();
/*
* Alternatively, I've tried uninitializing and then reinitializing the SAADC
* and the channel without aborting. When reinitializing, I make sure _not_ to
* set up the buffers since registration of the buffers seems to be related to
* the problem. This actually does allow calibration to start and complete, but
* the next time after that that I call nrf_drv_saadc_sample(), it always fails
* with NRF_ERROR_INVALID_STATE.
*/
//nrf_drv_saadc_uninit();
//err_code = nrf_drv_saadc_init(NULL, battery_saadc_callback);
//APP_ERROR_CHECK(err_code);
//err_code = nrf_drv_saadc_channel_init(0, &channel_config);
//APP_ERROR_CHECK(err_code);
while(nrf_drv_saadc_calibrate_offset() != NRF_SUCCESS);
/*
* After this, the SAADC event handler expects a NRF_DRV_SAADC_EVT_CALIBRATEDONE.
* When that is received, I call nrf_drv_saadc_buffer_convert() on my two buffers
* and then call nrf_drv_saadc_sample(). As described above, if I replace the abort call
* with the uninit/reinit code commented out above, it does actually get to this point
* but nrf_drv_saadc_sample() always returns NRF_ERROR_INVALID_STATE.
*/
Edit: Here's the relevant code for the follow-up issue where calibration completes correctly but the subsequent sample doesn't generate any events. This is the CALIBRATEDONE part of my SAADC event handler and the corresponding function that gets scheduled:
static void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
ret_code_t err_code;
switch(p_event->type)
{
case NRF_DRV_SAADC_EVT_CALIBRATEDONE:
ret_code_t err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
// same for m_buffer_pool[1]
err_code = app_sched_event_put(NULL, 0, on_cal_complete_handler);
APP_ERROR_CHECK(err_code);
nrf_delay_us(500); //delay avoids the issue
break;
}
}
static void on_cal_complete_handler(void * p_event_data, uint16_t event_size)
{
ret_code_t err_code = nrf_drv_saadc_sample();
APP_ERROR_CHECK(err_code);
}