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

SAADC done event not occurring

I'm using SAADC like this:

nrfx_saadc_config_t config = NRFX_SAADC_DEFAULT_CONFIG;

config.resolution = NRF_SAADC_RESOLUTION_14BIT;
config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
config.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
config.low_power_mode = true;

err_code = nrfx_saadc_init(&config, adc_event_handler);
APP_ERROR_CHECK(err_code);

nrf_saadc_channel_config_t config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(0);
config.reference = NRF_SAADC_REFERENCE_INTERNAL;
config.gain = NRF_SAADC_GAIN1_3;
config.resistor_p = NRF_SAADC_RESISTOR_VDD1_2;
err_code = nrfx_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code);

nrfx_saadc_buffer_convert(m_adc_buffer, sizeof(nrf_saadc_value_t) * 1);

nrfx_err_t err_code = nrfx_saadc_sample();
APP_ERROR_CHECK(err_code);

And I'm not getting the done event. I've also tried not low power mode.

If I place a breakpoint in nrfx_saadc.c nrfx_saadc_irq_handler, after nrfx_saadc_sample is called it gets hit. But then stepping through the code, 

if (nrf_saadc_event_check(NRF_SAADC_EVENT_END))

Is false (along with all the other event checks, so it goes to the limit section, but none are enabled).

  • Hi Nick, it is possible that the initialization NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(0); is incorrect

    0 meaning:

    #define SAADC_CH_PSELP_PSELP_NC (0UL) /*!< Not connected */

    The following code seemed to work fine on my desk.

    (To test this easily, replace the main file of \examples\peripheral\saadc with the code below)

    /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved.
     *
     * The information contained herein is property of Nordic Semiconductor ASA.
     * Terms and conditions of usage are described in detail in NORDIC
     * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
     *
     * Licensees are granted free, non-transferable use of the information. NO
     * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
     * the file.
     *
     */
    
    /** @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 "nrf.h"
    #include "nrf_drv_saadc.h"
    #include "boards.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include <string.h>
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define SAMPLES_IN_BUFFER 1
    
    static nrf_saadc_value_t m_buffer[SAMPLES_IN_BUFFER];
    
    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);
            
            NRF_LOG_INFO("%d\r\n", p_event->data.done.p_buffer[0]);
        }
    }
    
    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);
    
        nrfx_saadc_config_t config = NRFX_SAADC_DEFAULT_CONFIG;
        config.resolution = NRF_SAADC_RESOLUTION_14BIT;
        config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
        config.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
        config.low_power_mode = true;
    
        err_code = nrf_drv_saadc_init(&config, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
    
        channel_config.reference = NRF_SAADC_REFERENCE_INTERNAL;
        channel_config.gain = NRF_SAADC_GAIN1_3;
        channel_config.resistor_p = NRF_SAADC_RESISTOR_VDD1_2;
        err_code = nrf_drv_saadc_channel_init(0, &channel_config);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_buffer_convert(m_buffer, 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();
    
        NRF_LOG_INFO("SAADC HAL simpler example.");
        saadc_init();
    
        while (1)
        {
            nrf_drv_saadc_sample();
            nrf_delay_ms(100);
            NRF_LOG_FLUSH();
        }
    }
    
    /** @} */

  • Ok thanks I had missed that, that helps. It seems the SAADC driver should check that. Also there is no reference to the nrf_saadc_input_t enum in NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE, and the parameters for nrfx_saadc_channel_init are not documented in the header comment.

    But I'm trying to read VDD voltage. I saw 

    NRF_SAADC_INPUT_VDD

    so I switched my code to use that:

    nrfx_saadc_config_t config = NRFX_SAADC_DEFAULT_CONFIG;
    
    config.resolution = NRF_SAADC_RESOLUTION_14BIT;
    config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
    config.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
    config.low_power_mode = true;
    
    err_code = nrfx_saadc_init(&config, adc_event_handler);
    APP_ERROR_CHECK(err_code);
    
    nrf_saadc_channel_config_t config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
    config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    config.gain = NRF_SAADC_GAIN1_5;
    err_code = nrfx_saadc_channel_init(NRF_SAADC_INPUT_VDD, &config);
    APP_ERROR_CHECK(err_code);
    
    nrfx_saadc_buffer_convert(m_adc_buffer, sizeof(nrf_saadc_value_t) * 1);
    
    nrfx_err_t err_code = nrfx_saadc_sample();
    APP_ERROR_CHECK(err_code);

    However, this doesn't work, because 

    NRF_SAADC_CHANNEL_COUNT

    Is defined as 8, but the value of 

    NRF_SAADC_INPUT_VDD

    is 9, so in nrfx_saadc_channel_init, m_cb.psel[channel].pselp is garbage in 

    if (m_cb.psel[channel].pselp == NRF_SAADC_INPUT_DISABLED)
    {
        ++m_cb.active_channels;
    }

    , so the read doesn't occur. I see there is an assertion for the channel parameter at the top of nrfx_saadc_channel_init, but for some reason this isn't hit.

    How can I read VDD?

  • I see now that the pin input and channel number are different. Also the size of the buffer is the number of samples expected, not the size in bytes. (The header comment uses "words", but the size of a value is 16 bits, not sure if "words" is appropriate?). Correcting my code to work:

    nrfx_saadc_config_t config = NRFX_SAADC_DEFAULT_CONFIG;
    
    config.resolution = NRF_SAADC_RESOLUTION_14BIT;
    config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED;
    config.interrupt_priority = NRFX_SAADC_CONFIG_IRQ_PRIORITY;
    config.low_power_mode = true;
    
    err_code = nrfx_saadc_init(&config, adc_event_handler);
    APP_ERROR_CHECK(err_code);
    
    nrf_saadc_channel_config_t config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
    config.reference = NRF_SAADC_REFERENCE_INTERNAL;
    config.gain = NRF_SAADC_GAIN1_5;
    err_code = nrfx_saadc_channel_init(0, &config);
    APP_ERROR_CHECK(err_code);
    
    nrfx_saadc_buffer_convert(m_adc_buffer, 1);
    
    nrfx_err_t err_code = nrfx_saadc_sample();
    APP_ERROR_CHECK(err_code);

Related