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

Low Power SAADC

Hi Everyone,

I have been experimenting around with the low power SAADC example in SDK13.

I am using PCA10040 dev board and I have programmed it to start/stop ADC sampling when any of the 4 buttons is pressed. 

I have found that the current consumption before sampling starts is on average around 0.3mA with DCDCEN = 1 and __WFE in the main loop. 

With only one channel initialised the current doesn't increase much when sampling is enabled and returns to 0.3mA when it is disabled.

However with more than one channels initialised the current increases from 0.3 to 1.5mA ( which I am assuming is due to the easy DMA) when sampling has been enabled.

Even after disabling sampling the current doesn't return to 0.3mA.

Does anyone know why this is the case?

/* 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 "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf_drv_gpiote.h"
#include "app_util_platform.h"
#include <string.h>

#define NRF_LOG_MODULE_NAME "APP"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"

#define SAMPLES_IN_BUFFER 4
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;
static bool sampling_enabled = false;

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}


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_sampling_event_disable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_disable(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);

        int i;
        NRF_LOG_INFO("ADC event number: %d\r\n", (int)m_adc_evt_counter);

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
            NRF_LOG_INFO("%d\r\n", 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);
	
	nrf_saadc_channel_config_t channel_config2 =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);

    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_channel_init(1, &channel_config2);
    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);

}

static void start_sampling( nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
	sampling_enabled = sampling_enabled ? false : true;
	if( sampling_enabled == true )
	{
		saadc_sampling_event_enable();
		bsp_board_led_on( 2 );
	}
	else if ( sampling_enabled == false )
	{
		saadc_sampling_event_disable();
		bsp_board_led_off( 2 );
	}
}	



static void buttons_init(void)
{
	nrf_drv_gpiote_init();
	nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
	in_config.pull = NRF_GPIO_PIN_PULLUP;
	
	nrf_drv_gpiote_in_init( BUTTON_1, &in_config, start_sampling );
	nrf_drv_gpiote_in_event_enable( BUTTON_1, true );
	
	nrf_drv_gpiote_in_init( BUTTON_2, &in_config, start_sampling );
	nrf_drv_gpiote_in_event_enable( BUTTON_2, true );
	
	nrf_drv_gpiote_in_init( BUTTON_3, &in_config, start_sampling );
	nrf_drv_gpiote_in_event_enable( BUTTON_3, true );
	
	nrf_drv_gpiote_in_init( BUTTON_4, &in_config, start_sampling );
	nrf_drv_gpiote_in_event_enable( BUTTON_4, true );
	
}



/**
 * @brief Function for main application entry.
 */
int main(void)
{	
	
		NRF_POWER->DCDCEN = 1;
    uint32_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);
		bsp_board_leds_init();
    NRF_LOG_INFO("SAADC HAL simple example.\r\n");
		buttons_init();
    saadc_init();
    saadc_sampling_event_init();
    //saadc_sampling_event_enable();

    while (1)
    {
        __WFE();
        NRF_LOG_FLUSH();
    }
}


/** @} */

Thanks for the help.

Bryan

Parents
  • Hey Bryan,

    The 300mA static current consumption might be a pull-up connected directly to ground. The pull-ups are typically 13Kohm. At 3V the current consumption of a 13K resistor bettween VDD and GND is 3V/13Kohm = ~230µA.

    It can also be a HFCLK constantly running, ie PPI is set to 'constant latency'.

    The additional 1mA is probably the SAADC + EasyDMA. 

    Do you have a scope of the current consumption?

    Cheers,

    Håkon.

  • Hi Hakon,

    Thanks for the prompt response.

    Why does the additional 1mA only appear when more than one channel is initialised?

    Here is the current consumption from a DC power analyser ( units amps and seconds, sampling freq = 200Hz ),  SPI is also on to send data to external NAND memory, I have worked out the main cause of the high idle current is due to the SAADC.

    The power consumption is affected by the mains noise as shown in the graph but there is a DC current of around 2mA when this should be around 0.3mA?

    Thanks,

    Bryan

Reply
  • Hi Hakon,

    Thanks for the prompt response.

    Why does the additional 1mA only appear when more than one channel is initialised?

    Here is the current consumption from a DC power analyser ( units amps and seconds, sampling freq = 200Hz ),  SPI is also on to send data to external NAND memory, I have worked out the main cause of the high idle current is due to the SAADC.

    The power consumption is affected by the mains noise as shown in the graph but there is a DC current of around 2mA when this should be around 0.3mA?

    Thanks,

    Bryan

Children
  • A decent Power analyser should not have a 50Hz hum of that magnitude, I believe three might be a measurement error. 

    I need you to describe your measurement set-up, and please be specific. ie what is the brand and model of the instruments used, and how are they connected to the DK. Have you followed the steps in Measuring current? etc.

    You should disable your SPI code until you have been able to verify that the current measurements with the SAADC code are as expected, or else it will be difficult to analyse the measurements. 

Related