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

SAADC V2 Sample Values Low

I am in the process of integrating the latest SAADC driver into my project and have noticed an issue after adding the errata 122 workaround to my saadc event handler per the example here. Without the workaround I am seeing expected values from two channels (VDD and a thermistor) and as expected, current consumption never returns to normal. With the workaround added to my event handler I am getting value that are quite a bit lower than they should be. VDD seems to be slightly low but the value is also within a reasonable range of the actual voltage that makes it difficult to tell. The value I am getting back from my thermistor is significantly lower however.  Has anyone noticed this behavior in the V2 driver?

I am using a Rev2 nrf52840 with the thread and zigbee SDK 4.1 and the drivers from SDK 17.0.2.

Relevant code:

void saadc_callback(nrfx_saadc_evt_t const *p_event)
{
    ret_code_t err_code = NRF_SUCCESS;

    if (p_event->type == NRFX_SAADC_EVT_DONE)
    {
        nrf_gpio_pin_clear(SENSOR_1_EN);

//        err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, samples_in_buffer);
//        APP_ERROR_CHECK(err_code);

        //update_temperature_attribute(MULTI_SENSOR_ENDPOINT, convertTemp(p_event->data.done.p_buffer[0]));
        zb_schedule_app_callback((zb_callback_t)(process_temperature), MULTI_SENSOR_ENDPOINT, ZB_TRUE, p_event->data.done.p_buffer[0], ZB_FALSE);        // Param 1 = endpoint (10), CB_Param = SAADC buffer value

        // Need to eventually determine why either not allowing the SAADC to calibrate (commenting the below block out) or only calibrating at any conditional interval (m_adc_evt_counter % 10 == 0) causes power consumption to be stuck in the 1.2mA range.
        if(m_adc_evt_counter)
        {
            nrfx_saadc_abort();
            zb_schedule_app_callback(calibrate_adc, 0, ZB_FALSE, 0, ZB_FALSE);
        }

        m_adc_evt_counter++;
        
        NRF_LOG_INFO("VDD: %d", p_event->data.done.p_buffer[1]);
    }
    else if(p_event->type == NRFX_SAADC_EVT_CALIBRATEDONE)
    {            
        NRF_LOG_INFO("SAADC Calibration Complete");
    }

    // Workaround from Errata 122
    volatile uint32_t temp1;
    volatile uint32_t temp2;
    volatile uint32_t temp3;

    temp1 = *(volatile uint32_t *)0x40007640ul;
    temp2 = *(volatile uint32_t *)0x40007644ul;
    temp3 = *(volatile uint32_t *)0x40007648ul;

    *(volatile uint32_t *)0x40007FFCul = 0ul; 
    *(volatile uint32_t *)0x40007FFCul; 
    *(volatile uint32_t *)0x40007FFCul = 1ul;

    *(volatile uint32_t *)0x40007640ul = temp1;
    *(volatile uint32_t *)0x40007644ul = temp2;
    *(volatile uint32_t *)0x40007648ul = temp3;
}

static void init_saadc()
{
    ret_code_t err_code = NRF_SUCCESS;
    
    std::array <nrfx_saadc_channel_t, 2> channels = {
    { 
        { .channel_config = { .resistor_p = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED, .gain = NRF_SAADC_GAIN1_4, .reference = NRF_SAADC_REFERENCE_VDD4, .acq_time = NRF_SAADC_ACQTIME_10US, .mode = NRF_SAADC_MODE_SINGLE_ENDED, .burst = NRF_SAADC_BURST_ENABLED, .pin_p = NRF_SAADC_INPUT_AIN5, .pin_n = NRF_SAADC_INPUT_DISABLED }, .pin_p = NRF_SAADC_INPUT_AIN5, .pin_n = NRF_SAADC_INPUT_DISABLED, .channel_index = 0 },
        { .channel_config = { .resistor_p = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED, .gain = NRF_SAADC_GAIN1_6, .reference = NRF_SAADC_REFERENCE_INTERNAL, .acq_time = NRF_SAADC_ACQTIME_10US, .mode = NRF_SAADC_MODE_SINGLE_ENDED, .burst = NRF_SAADC_BURST_ENABLED, .pin_p = NRF_SAADC_INPUT_VDD, .pin_n = NRF_SAADC_INPUT_DISABLED }, .pin_p = NRF_SAADC_INPUT_VDD, .pin_n = NRF_SAADC_INPUT_DISABLED, .channel_index = 1 }
    }
    };
    
    err_code = nrfx_saadc_init(NRFX_SAADC_CONFIG_IRQ_PRIORITY);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrfx_saadc_channels_config(channels.data(), channels.size());
    APP_ERROR_CHECK(err_code);

    while (nrfx_saadc_offset_calibrate(saadc_callback) != NRF_SUCCESS)
    {
        __WFE();
        __SEV();
        __WFE();
    }
}

void zb_app_timer_handler(zb_uint8_t param)
{
    ret_code_t err_code = NRF_SUCCESS;
    
    nrf_gpio_pin_set(SENSOR_1_EN);
    
    err_code = nrfx_saadc_simple_mode_set((1 << 0 | 1 << 1), NRF_SAADC_RESOLUTION_14BIT, NRF_SAADC_OVERSAMPLE_32X, saadc_callback);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrfx_saadc_buffer_set(m_buffer_pool.data(), m_buffer_pool.size());
    APP_ERROR_CHECK(err_code);   
    
    err_code = nrfx_saadc_mode_trigger();
    APP_ERROR_CHECK(err_code);
    
    zb_ret_t zb_err_code = zb_schedule_app_alarm(zb_app_timer_handler, 0, 60 * ZB_TIME_ONE_SECOND);
    APP_ERROR_CHECK(zb_err_code);
}

Parents
  • Hi,

    I have not seen this issue before, it sounds almost like the channels are not set correctly again after applying the workaround (it will power-cycle the peripheral, removing all configurations). Can you set a breakpoint when your code enters the saadc_callback, and check that the PSEL pins are set correctly in the peripheral registers?

    Best regards,
    Jørgen

  • Hi Jørgen,

    The PSEL pin is correct after letting the workaround run. I did not check the VDD channel, but channel 0 at 0x40007510 has a value of 6 (AIN5) after several samples are taken.

    Just for clarification, the value that is returned from the input channel is never the correct value when the workaround is in place, it always reads a low value.

    Edit:

    It looks like the value of the PSEL register is reset to 0 up to the moment the callback is entered. Upon entering the callback the value changes to the correct input and is then reset to 0.

Reply
  • Hi Jørgen,

    The PSEL pin is correct after letting the workaround run. I did not check the VDD channel, but channel 0 at 0x40007510 has a value of 6 (AIN5) after several samples are taken.

    Just for clarification, the value that is returned from the input channel is never the correct value when the workaround is in place, it always reads a low value.

    Edit:

    It looks like the value of the PSEL register is reset to 0 up to the moment the callback is entered. Upon entering the callback the value changes to the correct input and is then reset to 0.

Children
No Data
Related