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

9 SAADC Channels Yielding Strange Readings

Hi,

I was trying to get SAADC readings from AIN0 to AIN7 and also from VDD but I'm getting strange results. There is nothing connected to the pins but the measured value including VDD is jumping around.

I'm guess I'm handling the measured data wrong but I don't see the problem, any suggestions?

Thanks.

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.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 9
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 nrf_ppi_channel_t     m_ppi_channel;
static uint32_t              m_adc_evt_counter;

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}


// Initialise the GPIO pins
void gpio_init(void)
{
nrf_gpio_cfg_output(27);
nrf_gpio_cfg_output(26);
nrf_gpio_cfg_output(25);
nrf_gpio_cfg_output(17);
nrf_gpio_cfg_output(21);
}

// ADC Functions

void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(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,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}


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("ADC event number: %d", (int)m_adc_evt_counter);

        NRF_LOG_INFO("AIN0 = %d mV", p_event->data.done.p_buffer[0] * 3600 / 1024);
        NRF_LOG_INFO("AIN1 = %d mV", p_event->data.done.p_buffer[1] * 3600 / 1024);
        NRF_LOG_INFO("AIN2 = %d mV", p_event->data.done.p_buffer[2] * 3600 / 1024);
        NRF_LOG_INFO("AIN3 = %d mV", p_event->data.done.p_buffer[3] * 3600 / 1024);
        NRF_LOG_INFO("AIN4 = %d mV", p_event->data.done.p_buffer[4] * 3600 / 1024);
        NRF_LOG_INFO("AIN5 = %d mV", p_event->data.done.p_buffer[5] * 3600 / 1024);
        NRF_LOG_INFO("AIN6 = %d mV", p_event->data.done.p_buffer[6] * 3600 / 1024);
        NRF_LOG_INFO("AIN7 = %d mV", p_event->data.done.p_buffer[7] * 3600 / 1024);
        NRF_LOG_INFO("VDD = %d mV", p_event->data.done.p_buffer[8] * 3600 / 1024);

        m_adc_evt_counter++;

    }
}


void saadc_init(void)
{
    ret_code_t err_code;


    nrf_saadc_channel_config_t channel_0_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_1_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_2_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_3_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_4_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_5_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_6_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_7_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7); // set VDD as input, you can use AIN0~AIN7 instead.

    nrf_saadc_channel_config_t channel_VDD_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD); // set VDD as input, you can use AIN0~AIN7 instead.

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

	    err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(4, &channel_4_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(5, &channel_5_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(6, &channel_6_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(7, &channel_7_config);
	    APP_ERROR_CHECK(err_code);

	    err_code = nrf_drv_saadc_channel_init(8, &channel_VDD_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)
{
 	gpio_init();

    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();
    saadc_sampling_event_enable();
    NRF_LOG_INFO("SAADC HAL simple example started.");

    while (1)
    {
        for (int i = 0; i < LEDS_NUMBER; i++)
		        {
		            bsp_board_led_invert(i);
		            nrf_delay_ms(250);

		            if(i==0){
		            nrf_gpio_pin_toggle(27);
		            nrf_gpio_pin_toggle(21);
		            nrf_gpio_pin_toggle(25);
				}
				else if(i==1){
				nrf_gpio_pin_toggle(26);
				nrf_gpio_pin_toggle(17);
				}

        }
        nrf_pwr_mgmt_run();
        NRF_LOG_FLUSH();
    }
}


/** @} */

  • The nRF52 product spec is a little deceiving in that you can only sample 8 channels with the SADDC not 9.  The block diagram makes it look like you can do this but you can't.  If you look at the channel selection registers CH[X].PSELP and CH[X].PSELN that control the MUX there are only 8 registers. So you can only sample 8 channels.  If you want to sample all 8 channels VDD must be one of them, I know because I tried this as at one point.

    Lines 176 in your code should cause an assert when called.  What version of the SDK are you using?

  • Thanks for the advice, I've commented out one of the AIN pins and now the VDD looks to be correct at just over 3.3V but the others are still jumping around 200mV.   

    I've just tried measuring AIN4 with a multimeter and I get around 150mV. I also scoped it and this is the result, Vpp:180mV.

    Also, in my first comment the values were around 2V but I discovered if I take the foam which came on the pins off it drops to the 200mV range so I guess that foam was slightly conductive. 

    I'm using a makerdiary nRF52840-MDK IoT Development Kit with nRF5_SDK_15.0.0_a53641a.

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <string.h>
    #include "nrf.h"
    #include "nrf_drv_saadc.h"
    #include "nrf_drv_ppi.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 8
    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 nrf_ppi_channel_t     m_ppi_channel;
    static uint32_t              m_adc_evt_counter;
    
    void timer_handler(nrf_timer_event_t event_type, void * p_context)
    {
    
    }
    
    
    // Initialise the GPIO pins
    void gpio_init(void)
    {
    nrf_gpio_cfg_output(27);
    nrf_gpio_cfg_output(26);
    nrf_gpio_cfg_output(25);
    nrf_gpio_cfg_output(17);
    nrf_gpio_cfg_output(21);
    }
    
    // ADC Functions
    
    void saadc_sampling_event_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(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,
                                       false);
        nrf_drv_timer_enable(&m_timer);
    
        uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                    NRF_TIMER_CC_CHANNEL0);
        uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();
    
        /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                              timer_compare_event_addr,
                                              saadc_sample_task_addr);
        APP_ERROR_CHECK(err_code);
    }
    
    
    void saadc_sampling_event_enable(void)
    {
        ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
    
        APP_ERROR_CHECK(err_code);
    }
    
    
    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("ADC event number: %d", (int)m_adc_evt_counter);
    
            NRF_LOG_INFO("AIN0 = %d mV", p_event->data.done.p_buffer[1] * 3600 / 1024);
            NRF_LOG_INFO("AIN1 = %d mV", p_event->data.done.p_buffer[2] * 3600 / 1024);
            NRF_LOG_INFO("AIN2 = %d mV", p_event->data.done.p_buffer[3] * 3600 / 1024);
            NRF_LOG_INFO("AIN3 = %d mV", p_event->data.done.p_buffer[4] * 3600 / 1024);
            NRF_LOG_INFO("AIN4 = %d mV", p_event->data.done.p_buffer[5] * 3600 / 1024);
            NRF_LOG_INFO("AIN5 = %d mV", p_event->data.done.p_buffer[6] * 3600 / 1024);
            NRF_LOG_INFO("AIN6 = %d mV", p_event->data.done.p_buffer[7] * 3600 / 1024);
            //NRF_LOG_INFO("AIN7 = %d mV", p_event->data.done.p_buffer[7] * 3600 / 1024);
            NRF_LOG_INFO("VDD = %d mV", p_event->data.done.p_buffer[0] * 3600 / 1024);
    
            m_adc_evt_counter++;
    
        }
    }
    
    
    void saadc_init(void)
    {
        ret_code_t err_code;
    
        nrf_saadc_channel_config_t channel_VDD_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_0_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_1_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_2_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_3_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_4_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_5_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5); // set VDD as input, you can use AIN0~AIN7 instead.
    
        nrf_saadc_channel_config_t channel_6_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6); // set VDD as input, you can use AIN0~AIN7 instead.
    
        /*nrf_saadc_channel_config_t channel_7_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7); // set VDD as input, you can use AIN0~AIN7 instead.*/
    
    	    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(0, &channel_VDD_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(1, &channel_0_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(2, &channel_1_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(3, &channel_2_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(4, &channel_3_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(5, &channel_4_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(6, &channel_5_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    err_code = nrf_drv_saadc_channel_init(7, &channel_6_config);
    	    APP_ERROR_CHECK(err_code);
    
    	    /*err_code = nrf_drv_saadc_channel_init(8, &channel_7_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)
    {
     	gpio_init();
    
        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();
        saadc_sampling_event_enable();
        NRF_LOG_INFO("SAADC HAL simple example started.");
    
        while (1)
        {
            for (int i = 0; i < LEDS_NUMBER; i++)
    		        {
    		            bsp_board_led_invert(i);
    		            nrf_delay_ms(250);
    
    		            if(i==0){
    		            nrf_gpio_pin_toggle(27);
    		            nrf_gpio_pin_toggle(21);
    		            nrf_gpio_pin_toggle(25);
    				}
    				else if(i==1){
    				nrf_gpio_pin_toggle(26);
    				nrf_gpio_pin_toggle(17);
    				}
    
            }
            nrf_pwr_mgmt_run();
            NRF_LOG_FLUSH();
        }
    }
    
    
    /** @} */
    

    Is this some sort of hardware issue maybe or have I configured the inputs incorrectly somehow? I have tried this on two of these board to rule out one being faulty.

  • Hi,

    You write that "There is nothing connected to the pins". You should expect to get varying measurements with floating pins, as all you are measuring is really noise (and the effect the measuring equipment itself has). You need to connect your pins on order to get sensible measurements.

  • Of course, that makes sense. Sure enough if I connect to gnd or 3.3V I get perfect readings. Thanks for all the help.

Related