SAADC Offset Calibration not working?

Hello,

I am using the nRF52832 on a custom board, with SDK 15.2 and SD132 v6.1. My BLE application uses the SAADC to measure VCC voltage every 6 hours. I am using an app timer to initialize SAADC, kick off either an offset calibration or an ADC conversion, and then uninit SAADC once the NRF_DRV_SAADC_EVT_DONE/NRF_DRV_SAADC_EVT_CALIBRATEDONE  events fire. However, I am finding that SAADC offset calibration is not firing the SAADC_callback function at all:

Here is my SAADC init function:

void saadc_init(void)
{
    ret_code_t err_code;
    nrf_drv_saadc_config_t saadc_config;
    nrf_saadc_channel_config_t channel_config;


	
    //Configure SAADC
    saadc_config.low_power_mode = true;                                                   //Enable low power mode.
    saadc_config.resolution = NRF_SAADC_RESOLUTION_10BIT;                                 //Set SAADC resolution to 12-bit. This will make the SAADC output values from 0 (when input voltage is 0V) to 2^12=2048 (when input voltage is 3.6V for channel gain setting of 1/6).
    // saadc_config.oversample = NRF_SAADC_OVERSAMPLE_4X;                                           //Set oversample to 4x. This will make the SAADC output a single averaged value when the SAMPLE task is triggered 4 times.
    saadc_config.oversample = NRF_SAADC_OVERSAMPLE_32X;
    saadc_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;                               //Set SAADC interrupt to low priority.
	
    //Initialize SAADC
    err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);                         //Initialize the SAADC with configuration and callback function. The application must then implement the saadc_callback function, which will be called when SAADC interrupt is triggered                      //Initialize the SAADC with configuration and callback function. The application must then implement the saadc_callback function, which will be called when SAADC interrupt is triggered
    APP_ERROR_CHECK(err_code);
		
    //Configure SAADC channel
    channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;                              //Set internal reference of fixed 0.6 volts
    channel_config.gain = NRF_SAADC_GAIN1_6;                                              //Set input gain to 1/6. The maximum SAADC input voltage is then 0.6V/(1/6)=3.6V. The single ended input range is then 0V-3.6V
    channel_config.acq_time = NRF_SAADC_ACQTIME_40US;                                     //Set acquisition time. Set low acquisition time to enable maximum sampling frequency of 200kHz. Set high acquisition time to allow maximum source resistance up to 800 kohm, see the SAADC electrical specification in the PS. 
    channel_config.mode = NRF_SAADC_MODE_SINGLE_ENDED;                                    //Set SAADC as single ended. This means it will only have the positive pin as input, and the negative pin is shorted to ground (0V) internally.
    channel_config.pin_p = NRF_SAADC_INPUT_VDD;                                          //Select the input pin for the channel. AIN0 pin maps to physical pin P0.02.
    channel_config.pin_n = NRF_SAADC_INPUT_DISABLED;                                      //Since the SAADC is single ended, the negative pin is disabled. The negative pin is shorted to ground internally.
    channel_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;                              //Disable pullup resistor on the input pin
    channel_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;                              //Disable pulldown resistor on the input pin

	
    //Initialize SAADC channel
    err_code = nrf_drv_saadc_channel_init(0, &channel_config);                            //Initialize SAADC channel 0 with the channel configuration
    APP_ERROR_CHECK(err_code);
		
    //if(SAADC_BURST_MODE)
    {
        NRF_SAADC->CH[0].CONFIG |= 0x01000000;                                            //Configure burst mode for channel 0. Burst is useful together with oversampling. When triggering the SAMPLE task in burst mode, the SAADC will sample "Oversample" number of times as fast as it can and then output a single averaged value to the RAM buffer. If burst mode is not enabled, the SAMPLE task needs to be triggered "Oversample" number of times to output a single averaged value to the RAM buffer.		
    }

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],1);    //Set SAADC buffer 1. The SAADC will start to write to this buffer
    APP_ERROR_CHECK(err_code);


}

Here is the SAADC callback function:

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    ret_code_t err_code;
    uint8_t temp_arr[2];
    uint16_t temp_adc;

    // bsp_board_led_on(ADVERTISING_LED);
    //if (p_event->type == NRF_SAADC_EVENT_RESULTDONE)                                                        //Capture offset calibration complete event
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)                                                        //Capture offset calibration complete event
    {		
        temp_adc = 	m_buffer_pool[0][0];

        //memset(&temp_arr, 0, sizeof(temp_arr));
        
        temp_arr[0] = (uint8_t)((temp_adc & 0xFF00) >> 8);
        temp_arr[1] = (uint8_t)(temp_adc & 0x00FF);
        
        //if(!_isFastAdv && nrf_mtx_trylock(&adv_mutex))
        if(!_isFastAdv)
        {         
            //_isFastAdv = true;    
            send_adc_pkt(temp_arr, sizeof(temp_arr), 800);     //~500 ms    CHANGE FUNCTION NAME!!!!!!!!!!!!!!!!!
            APP_ERROR_CHECK(sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG)); //Restart advertising
            nrf_mtx_unlock(&adv_mutex);        
            app_timer_start(magic_word_timer_id, APP_TIMER_TICKS(2000), NULL); //start 2 second timer to go back to idle advertising
        }
        
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], 1);             //Set buffer so the SAADC can write to it again. 
        APP_ERROR_CHECK(err_code);
        nrf_drv_saadc_uninit();
    }
    else if(p_event->type == NRF_DRV_SAADC_EVT_CALIBRATEDONE)
    {
        bsp_board_led_on(ADVERTISING_LED);
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], 1);             //Set buffer so the SAADC can write to it again. 
        APP_ERROR_CHECK(err_code);
        nrf_drv_saadc_uninit();
    }
}

And here is how I am calling the calibrate_offset function from within an app_timer handler:

static void adc_timeout_handler(void * p_context)
{
    if(adc_counter==358)
    {
        saadc_init();
        nrf_drv_saadc_calibrate_offset();
        // NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;

        adc_counter++;
    }
    else if(adc_counter==359) // every 6 hours
    {
        adc_counter=0;
        if(!_isFastAdv && !_isConnected && nrf_mtx_trylock(&adv_mutex))
        {
            sd_ble_gap_adv_stop(m_adv_handle); //Stop advertising
            APP_ERROR_CHECK(app_timer_start(adc_delay_timer_id, APP_TIMER_TICKS(1000), NULL)); //kick off ADC conversion in 1000 ms. Allows voltage to settle
            //nrf_drv_saadc_sample(); //consider kicking off a ~20 ms timer that starts ADC conversion to make sure advertising has stopped
        }
    }
    else
    { 
        adc_counter++;
    }
        
}

I have the 2 following questions:

  1. When I call nrf_drv_saadc_calibrate_offset(), I expect to catch the NRF_DRV_SAADC_EVT_CALIBRATEDONE event in my SAADC_callback, however that event is not firing at all. I am using an LED to see if NRF_DRV_SAADC_EVT_CALIBRATEDONE event is occurring, and it does not seem to fire at all. Furthermore, I also tried turning on the LED when there is any call to the saadc_callback function, regardless of the adc event, and I am seeing that the only time LED comes on is when an ADC conversion finishes, not when a calibration happens. Am I missing something here?
  2. I am using 32x oversampling with burst mode enabled. I am using the NRF_DRV_SAADC_EVT_DONE event in my callback function to detect when the conversion is finished and ready for me to process. Can you clarify if NRF_DRV_SAADC_EVT_DONE fires when a single conversion takes place, or when all 32 oversample samples have taken place?

Thanks!

Related