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,
    Sorry it was typo error. The count_trig in saadc_callback_1() should be actually count_cb. As I mentioned,I can see the prints in sequence for every count_tri of 2, count_cb is incremented once.
    void saadc_callback_1(nrf_drv_saadc_evt_t const * p_event){
    count_cb ++;
    }

    As per our undersatnding, once we call saadc_sampling_trigger(), SAADC driver should take ~48Us ((10Us+2Us)*4) before giving EVNT_DONE event on callback. Which is not happening in this case.

    For now, I have customized project. But as I mentioned, this is my simple code which periodically triggers every 10sec and we are reading ADC oversampled value.

    Can you please help me to understand, are their any timers internally used by the SAADC driver? Any more information you can share?

  • Hi,

    Tajpeer said:
    For now, I have customized project. But as I mentioned, this is my simple code which periodically triggers every 10sec and we are reading ADC oversampled value.

    I see. The thing is that I cannot see how this fails. Can you put your code in a a minimal example that still fails and upload the full project here so that I can test on a DK? I think this is key as I am not able to spot anything fundamentally wrong in the code you have posted.

    Tajpeer said:
    Can you please help me to understand, are their any timers internally used by the SAADC driver? Any more information you can share?

    The ADC has an internal timer that can be used for regular sampling but that is not used in your code. There are no other  internal timers in the SAADC (well, time plays a role in the ADC conversion, but that is handled entirely in the HW). For the driver, that does not use any timers or RTCs to keep track of time, it is purely event driven.

  • Hello Einar, This is Sanjay, i am same as Tajpeer team thanks for supporting.

             We are seen the different observation, If we set the oversampling as 2x every two trigger its calling a time callback.

    count_trig = 1
    count_trig = 2
    count_cb = 1
    avg_sample = 1706
    count_cb = 1
    count_trig = 3
    count_trig = 4
    count_cb = 2
    avg_sample = 1710
    count_cb = 2

    If we set the oversampling as 4x every four trigger its calling a time callback.

    count_trig = 1
    count_trig = 2
    count_trig = 3
    count_trig = 4
    count_cb = 1
    avg_sample = 1702

    count_trig = 5
    count_trig = 6
    count_trig = 7
    count_trig = 8
    count_cb = 2
    avg_sample = 1721

    If we set the oversampling as 8x every four trigger its calling a time callback.

    count_trig = 1
    count_trig = 2
    count_trig = 3
    count_trig = 4
    count_trig = 5
    count_trig = 6
    count_trig = 7
    count_trig = 8
    count_cb = 1
    avg_sample = 1715
    count_cb = 1
    count_trig = 9
    count_trig = 10
    count_trig = 11
    count_trig = 12
    count_trig = 13
    count_trig = 14
    count_trig = 15
    count_trig = 16
    count_cb = 2
    avg_sample = 1701
    count_cb = 2
    count_trig = 17

    we are periodically trigger every 10 sec delay but its not calling callback every trigger so will you please suggest how to fix this.

    if we not abled to fix this i will send you the code. 

  • Hi,

    That is odd... Which SDK version do you use?

    For reference, here I have modified the SAADC example in SDK 17 so that it looks like what you do. Instead of triggering with PPI, the timer triggers an interrupt that calls nrf_drv_saadc_sample() regularly. I tested with setting SAADC_CONFIG_OVERSAMPLE to 2 in sdk_config.h, but any value should give the same result (just more accurate the more oversampling).

    This seems to work as expected, and is essentially the same as you do.

    /**
     * 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 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)
    {
        ret_code_t err_code = nrf_drv_saadc_sample();
        APP_ERROR_CHECK(err_code);
    }
    
    
    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)
        {
            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);
    
            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_AIN0);
    
        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 Einar,

    1. how we know, oversampling is happening? 

    because we observed every trigger it will taking same time, means if we change the oversampling 2x,4x,...256x it taking same time.  

    As per our understanding, once we call saadc_sampling_trigger(), SAADC driver should take ~48Us ((10Us+2Us)*4) before giving EVNT_DONE event on callback. Which is not happening in this case.

    Even 2x,4x,...256x. for all the oversampling it taking same delay for conversion i didn't see any delay taken for different sampling, then its not work for oversampling right?  

    2. making enabled only NRFX_SAADC_CONFIG_OVERSAMPLE oversampling is happening ?
Reply
  • Hi Einar,

    1. how we know, oversampling is happening? 

    because we observed every trigger it will taking same time, means if we change the oversampling 2x,4x,...256x it taking same time.  

    As per our understanding, once we call saadc_sampling_trigger(), SAADC driver should take ~48Us ((10Us+2Us)*4) before giving EVNT_DONE event on callback. Which is not happening in this case.

    Even 2x,4x,...256x. for all the oversampling it taking same delay for conversion i didn't see any delay taken for different sampling, then its not work for oversampling right?  

    2. making enabled only NRFX_SAADC_CONFIG_OVERSAMPLE oversampling is happening ?
Children
  • Hi,

    Now I see.

    Fir of all, there was a typo in my previous reply. It should be SAADC_CONFIG_OVERSAMPLE and not NRFX_SAADC_CONFIG_OVERSAMPLE (the latter gets the value of the former). I will update my previous reply.

    The over sampling feature essentially only averages the sample values in WH. You will still need to trigger sampling for each sample. So you will get a DONE event for each sample. However, you only get the RESULTDONE event when all samples have been collected. This is when the driver reports the value, and is why you see this less frequently the more oversampling you use.

    You could for instance trigger sampling (either via PPI or using SW) after a DONE event to sample continuously. However, very rapid sampling may not be a good idea, depending on the time constant of the circuitry you are sampling (see part of this blog post).

Related