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

SAADC oversampling callback is not working as expected

Hello All,

I have referred the reference example code to suit my needs. Below is my code,

saadc_evnt_done_flag = false;

saadc_init();

Periodic_func()
{
    saadc_sampling_trigger();
    while(!saadc_evnt_done_flag)

    {
        __WFE();
    }

    /* Some code to use the oversampled value */
}

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;

        saadc_evnt_done_flag = true;

        m_adc_evt_counter++;
        printf("saadc_callback: adc-m_adc_evt_counter = %d\r\n", m_adc_evt_counter);
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
    }
}

Code is stuck at waiting for event. Didn't get callback with oversamping of 4x.

But in the same code, if I add 1 sec delay, callback is getting triggered after some time delay. Can someone help here.

Parents
  • Hello Einar,
    Thanks for supporting us continuously. Here are our main.c file and sdk_config.h file.

    Here are our observation,
    1. As per your suggestion, we have kept below settings in sdk_config.h file,
    #define NRFX_SAADC_ENABLED 1
    #define NRFX_SAADC_CONFIG_OVERSAMPLE 0
    #define SAADC_ENABLED 1
    #define SAADC_CONFIG_OVERSAMPLE 2 (4x)

    Observation: we are observing, for every 4 sample triggers, 1 time callback is getting called.
    Our understanding: We are expecting, SAADC driver will take samples and take average of that and copy to RAM. Raise NRF_DRV_SAADC_EVT_DONE once done. which should take ~48Us.

    2. But if we keep below settings,
    #define NRFX_SAADC_ENABLED 1
    #define NRFX_SAADC_CONFIG_OVERSAMPLE 2 (4x)
    #define SAADC_ENABLED 1
    #define SAADC_CONFIG_OVERSAMPLE 0

    Observation: we are observing, for every 1 sample triggers, 1 time callback is getting called. And also time taken between trigger and callback is not varying w.r.t oversampling value.
    Our understanding: This is not correct. Here oversampling itself is not happening because SAADC_CONFIG_OVERSAMPLE is 0.

    But if we look all over the SAADC driver, NRF_DRV is directly linked to NRFX. Then why are seeing different observation?

    In order to achieve, SAADC driver should give us the 1 averaged value depending on the oversampling setting once we trigger sampling. What should be our configuration and code flow?
    We are getting very much confused here?

    /**
     * Copyright (c) 2014 - 2020, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     * @defgroup nrf_adc_example main.c
     * @{
     * @ingroup nrf_adc_example
     * @brief ADC Example Application main file.
     *
     * This file contains the source code for a sample application using ADC.
     *
     * @image html example_board_setup_a.jpg "Use board setup A for this example."
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #include "nrf.h"
    #include "nrf_drv_saadc.h"
    #include "nrf_drv_timer.h"
    #include "boards.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "nrf_pwr_mgmt.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define SAMPLES_IN_BUFFER 1
    volatile uint8_t state = 1;
    static uint8_t count_trig = 0;
    static uint8_t count_cb = 0;
    uint32_t time_1 = 0, time_2 = 0, compute = 0; 
    
    static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
    static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
    static uint32_t              m_adc_evt_counter;
    
    
    void timer_handler(nrf_timer_event_t event_type, void * p_context)
    {
        //time_1 = app_timer_cnt_get();
        count_trig++;
        ret_code_t err_code = nrf_drv_saadc_sample();
        APP_ERROR_CHECK(err_code);
        printf("count_trig = %d\n",count_trig);
    
    }
    
    
    void saadc_sampling_event_init(void)
    {
        ret_code_t err_code;
    
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
        err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        /* setup m_timer for compare event every 400ms */
        uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
        nrf_drv_timer_extended_compare(&m_timer,
                                       NRF_TIMER_CC_CHANNEL0,
                                       ticks,
                                       NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                       true);
        nrf_drv_timer_enable(&m_timer);
    }
    
    
    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
           
            count_cb++;
            //time_2 = app_timer_cnt_get();
            //compute = app_timer_cnt_diff_compute(time_2,time_1);
            printf("compute =  %d\n", compute);
            time_1 = 0;time_2 = 0;
            ret_code_t err_code;
    
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
            printf("%d\n", p_event->data.done.p_buffer[0]);
            printf("count_cb = %d\n",count_cb);
    
    
    
            //int i;
            //NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
    
            //for (i = 0; i < SAMPLES_IN_BUFFER; i++)
            //{
            //    NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
            //}
            //m_adc_evt_counter++;
        }
    }
    
    
    void saadc_init(void)
    {
        ret_code_t err_code;
        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(0, &channel_config);
        APP_ERROR_CHECK(err_code);
    
        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);
    
    }
    
    
    /**
     * @brief Function for main application entry.
     */
    int main(void)
    {
        uint32_t err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        ret_code_t ret_code = nrf_pwr_mgmt_init();
        APP_ERROR_CHECK(ret_code);
    
        saadc_init();
        saadc_sampling_event_init();
        
        //err_code = nrf_drv_saadc_sample();
        //APP_ERROR_CHECK(err_code);
    
        NRF_LOG_INFO("SAADC HAL simple example started.");
    
        while (1)
        {
            nrf_pwr_mgmt_run();
            NRF_LOG_FLUSH();
        }
    }
    
    
    /** @} */

  • Hi,

    Tajpeer said:
    Observation: we are observing, for every 4 sample triggers, 1 time callback is getting called.

    Yes, that is correct when 4 x oversampling is selected.

    Tajpeer said:
    Our understanding: We are expecting, SAADC driver will take samples and take average of that and copy to RAM. Raise NRF_DRV_SAADC_EVT_DONE once done. which should take ~48Us.

    That is not the case. You are always measuring the time of making a single sample. The SAADC will only sample once per time sampling is triggered. If you want to do 4 times over sampling you must trigger sampling 4 times before you get a result (RESULTDONE), which is the average of the 4 samples. You will get a DONE event for each sample, so if you do 4 times over sampling you get 4 DONE events and 1 RESULTDONE event. 

    Tajpeer said:
    But if we look all over the SAADC driver, NRF_DRV is directly linked to NRFX. Then why are seeing different observation?

    The split between the nrf_drv and nrfx drivers are historic. the nrf_drv API is mostly just a frontend for the nrfx driver. For legacy reasons/backwards compatibility, in the nRF5 SDK you use the legacy driver API and that takes precedence. Specifically, apply_old_config.h will overwrite the NRFX definitions with the legacy definitions. So no matter what you set NRFX_SAADC_CONFIG_OVERSAMPLE to,  SAADC_CONFIG_OVERSAMPLE is being used.

    Tajpeer said:
    What should be our configuration and code flow?

    That depends on y our use case. Do you need more accurate samples every 10 seconds? If so, you could start sampling every 10 seconds, and then for instance use 4 times oversampling and call nrf_drv_saadc_sample() fore times for every sample with a sensible delay in between (at least taking into account the time constant of the circuit you are sampling)

    FYI: I will be out of office for the next three weeks so it may be sensible to open a new case if you have further questions.

  • Hi Einar,

    we are facing some issue after adding oversampling code. we re sending the date to BLE every 10 sec if we run or execute through IDE, BLE receiving data continuously, if we restart the controller (power off and power on) we reading only some iteration after that BLE not showing data. if we flash directly .hex file also facing same issue.

    1. is there any dependency in oversampling or BLE?

    2. what is happened it's working in IDE execution but not in after reset the board.

    if we use blocking mode its working fine, why only non blocking mode facing issue. 

    hal_adc_init(bus_conf->AdcSample, saadc_callback);   //init function
    hal_adc_sampling_trigger();                                            //trigger function

    void saadc_callback(nrfx_saadc_evt_t const * p_event)  //callback
    {
    uint16_t vsense_12v_mv;
    if (p_event->type == NRFX_SAADC_EVT_DONE)
    {
    ret_code_t err_code;
    #if 1
    err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
    vsense_12v_mv_tmp = p_event->data.done.p_buffer[0];


    printf("vsense_12v_mv = %d\n", vsense_12v_mv_tmp);
    seq_send(VOLTMEASURE_SEQ_ID, VALUE_ADC_12V, &vsense_12v_mv_tmp, sizeof(vsense_12v_mv_tmp));    //calling BLE
    #endif
    }
    }

    Note: this issue mainly got after adding callback function. 

  • Hi,

    I am sorry for the late reply. Did you resolve the issue? If not, I have some comments and questions.

    sanjay_123 said:
    1. is there any dependency in oversampling or BLE?

    No, not directly. (But depending on your application change of timing could cause some side effects by somehow triggering some other issue.)

    sanjay_123 said:

    2. what is happened it's working in IDE execution but not in after reset the board.

    if we use blocking mode its working fine, why only non blocking mode facing issue. 

    I do not immediately see how this matches the IDE execution having an effect, but a important point is that you cannot make SoftDevice calls from a interrupt priority that is higher than the lowest SoftDevice interrupt priority. So I would try to reduce the interrupt priority of the SAADC or alternatively avoid making SoftDevice calls from within the SAADC interrupt / event handler.

Reply
  • Hi,

    I am sorry for the late reply. Did you resolve the issue? If not, I have some comments and questions.

    sanjay_123 said:
    1. is there any dependency in oversampling or BLE?

    No, not directly. (But depending on your application change of timing could cause some side effects by somehow triggering some other issue.)

    sanjay_123 said:

    2. what is happened it's working in IDE execution but not in after reset the board.

    if we use blocking mode its working fine, why only non blocking mode facing issue. 

    I do not immediately see how this matches the IDE execution having an effect, but a important point is that you cannot make SoftDevice calls from a interrupt priority that is higher than the lowest SoftDevice interrupt priority. So I would try to reduce the interrupt priority of the SAADC or alternatively avoid making SoftDevice calls from within the SAADC interrupt / event handler.

Children
No Data
Related