This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Porting Project from SDK12.2 to SDK14.1, SAADC issue

I had the following setup, two app_timers triggering blocking SAADC reads in the callback functions

app_timer 1000ms triggering 1 Blocking SAADC read (For battery service, default Bluetooth SIG battery service)

ret_code_t err_code;
nrf_saadc_value_t  data_buffer = 0;

nrf_saadc_channel_config_t  channel_config1 =
    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);

err_code = nrf_drv_saadc_init(NULL,battery_level_adc_event_handler );
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_channel_init(SAADC_CHANNEL_BAS, &channel_config1);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_sample_convert(SAADC_CHANNEL_BAS, &data_buffer);
APP_ERROR_CHECK(err_code);

nrf_drv_saadc_channel_uninit(SAADC_CHANNEL_BAS);
nrf_drv_saadc_uninit();

//static nrf_saadc_value_t prev_data_buffer = 500;
float battery_in_percent = 0.0;

if(data_buffer > 145)
{
	battery_in_percent = slope * (data_buffer-147);
	if(battery_in_percent > 100)
	{
		battery_in_percent = 100;
	}
	NRF_LOG_RAW_INFO("Battery in percent %d\n", (uint8_t)battery_in_percent);
	//prev_data_buffer = data_buffer;
}
else
{
	battery_in_percent = 0;
}

err_code = ble_bas_battery_level_update(m_bas, (uint8_t)battery_in_percent);           //Send the battery level over BLE

if ((err_code != NRF_SUCCESS) &&
    (err_code != NRF_ERROR_INVALID_STATE) &&
    (err_code != NRF_ERROR_RESOURCES) &&
    (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
   )
{
    NRF_LOG_ERROR("Battery Service Error: %u\n", err_code);
	APP_ERROR_HANDLER(err_code);                                               //Assert on error
}

app_timer 1000ms triggering 5 Blocking SAADC reads (custom service characteristic), 5 IR sensor connected to multiplexer connected to AIN5, write_linear_array() selects which pin on the multiplexer is being used

    ret_code_t err_code;
enable_linear_array();

nrf_saadc_channel_config_t	channel_config =
	NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);

err_code = nrf_drv_saadc_init(NULL, saadc_callback);
APP_ERROR_CHECK(err_code);

err_code = nrf_drv_saadc_channel_init(SAADC_CHANNEL, &channel_config);
APP_ERROR_CHECK(err_code);

config_linear_array_out();
uint8_t sample_counter = 0;
nrf_saadc_value_t  data_buffer=0 ;
uint8_t readINflags = 0;

/* Sample 1 */
write_linear_array(sample_counter);
err_code = nrf_drv_saadc_sample_convert(0, &data_buffer);
APP_ERROR_CHECK(err_code);
if(err_code)
	return err_code;

if(data_buffer > IR_SENSOR_THRESHOLD){
	readINflags |= 0b00000001;
}

/* Sample 2*/
sample_counter++;
write_linear_array(sample_counter);
err_code = nrf_drv_saadc_sample_convert(0, &data_buffer);
APP_ERROR_CHECK(err_code);

if(data_buffer > IR_SENSOR_THRESHOLD){
	readINflags |= 0b00000010;
}

/* Sample 3 */
sample_counter++;
write_linear_array(sample_counter);
err_code = nrf_drv_saadc_sample_convert(0, &data_buffer);
APP_ERROR_CHECK(err_code);

if(data_buffer > IR_SENSOR_THRESHOLD){
	readINflags |= 0b00000100;
}

/* Sample 4 */
sample_counter++;
write_linear_array(sample_counter);

err_code = nrf_drv_saadc_sample_convert(0, &data_buffer);
APP_ERROR_CHECK(err_code);

if(data_buffer > IR_SENSOR_THRESHOLD){
	readINflags |= 0b00001000;
}

/* Sample 5 */
sample_counter++;
write_linear_array(sample_counter);

err_code = nrf_drv_saadc_sample_convert(0, &data_buffer);
APP_ERROR_CHECK(err_code);

if(data_buffer > IR_SENSOR_THRESHOLD){
	readINflags |= 0b00010000;
}

disable_linear_array();
nrf_drv_saadc_channel_uninit(SAADC_CHANNEL);
nrf_drv_saadc_uninit();

The battery measurement app_timer is always running, the other one is on demand (if notify happens on custom characteristic) Both characteristics have read and notify properties. For the custom characteristic a read will the code above directly outside the app_timer.

These worked fine with SDK12.2 and SDK13, however recently I started porting the project to SDK14.1 and the following is happening. When debugging there are no errors and I can read the characteristics fine via BLE or occasionally I get an unknown fault at 0x000128A0 or 0x00014CCC. When compiled with -O3 and not in debug, it runs for a while then goes into a reset loop (keeps resetting) after running for a while or after trying to read the custom characteristic.

With app_timers still running and the SAADC portions completely commented out [and the SAADC disabled as module] I have no issues.

  • I think I figured it out. I was using the GPIOTE peripheral to handle the power off button. I turned the log for the GPIOTE peripheral on, and saw that as soon as I initialized it would detect the power button event right away. My PWR_OFF line on the device has a capacitor that keeps the unit on for a 6+ seconds, this was probably keeping my unit alive and the SAADC acting strange.

    This was my original code

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
    in_config.pull = NRF_GPIO_PIN_PULLUP;
    
    err_code = nrf_drv_gpiote_in_init(PWR_SW, &in_config, power_button_interrupt_handler);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_gpiote_in_event_enable(PWR_SW, true);
    

    I set the GPIOTE to high accuracy and it stopped registering the power button event at initialization.

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    in_config.pull = NRF_GPIO_PIN_PULLUP;
    
    err_code = nrf_drv_gpiote_in_init(PWR_SW, &in_config, power_button_interrupt_handler);
    APP_ERROR_CHECK(err_code);
    
    nrf_drv_gpiote_in_event_enable(PWR_SW, true);
    

    This is my power_button_interrupt_handler, I also started calling the sd_power_system_off from here after setting the PWR_OFF line which wasn't done before

    void power_button_interrupt_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
    greenLED_blink_stop();
    NRF_LOG_INFO("POWER_BUTTON_HANDLER");
    nrf_gpio_pin_write(LED_RED,LED_ON);
    NRF_LOG_FINAL_FLUSH();
    nrf_drv_gpiote_out_set(PWR_OFF);
    
    ret_code_t err_code;
    // Go to system-off mode (this function will not return; wakeup will cause a reset).
    err_code = sd_power_system_off();
    APP_ERROR_CHECK(err_code);
    }
    
Related