Because of the holidays, TI E2E™ design support forum responses will be delayed from Dec. 25 through Jan. 2. Thank you for your patience.

This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2340R5: ADC pin current consumption too high after ADC_close

Part Number: CC2340R5
Other Parts Discussed in Thread: SYSCONFIG, CC2640

My customer found that CC2340 current consumption is unexpectedly high after ADC_close. The issue can be reproduced with CC2340R5 LaunchPad and latest SDK8.10, using following steps:

1. Modify adcsinglechannel example from simplelink_lowpower_f3_sdk_8_10_00_55 to call ADC_open, ADC_convert and ADC_close every 4 seconds.

2. Disable the Display driver to make sure the device goes to sleep between every ADC sampling.

3. Connect the ADC pin to an AAA battery(input voltage 1.5V - 1.7V).

4. The average current consumption would be >100uA when input voltage is around 1.5V, but if input voltage is 0 or 3.3V, the average current is <10uA.

Looks the input voltage level has an impact of the current consumption, does the ADC driver not set the GPIO properly?

Please find the modified adcsinglechannel.c and syscfg file as below to reproduce this issue:

adcsinglechannel.c
/*
 * Copyright (c) 2016-2022, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form 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.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
 */

/*
 *  ======== adcsinglechannel.c ========
 */
#include <unistd.h>
#include <stdint.h>
#include <stddef.h>

/* POSIX Header files */
#include <pthread.h>

/* Driver Header files */
#include <ti/drivers/ADC.h>
#include <ti/drivers/GPIO.h>
// #include <ti/display/Display.h>

/* Driver configuration */
#include "ti_drivers_config.h"

/* ADC sample count */
#define ADC_SAMPLE_COUNT (10)

#define THREADSTACKSIZE (768)

/* Inputs to the ADC on the CC32XX launchpads are downscaled by a factor of 0.42
 * Multiplying the conversion output with 2.365 will provide compensated output.
 */
#if DeviceFamily_PARENT == DeviceFamily_PARENT_CC32XX
    #define COMPENSATION_FACTOR 2365
#else
    #define COMPENSATION_FACTOR 1000
#endif

/* ADC conversion result variables */
//uint16_t adcValue0;
//uint32_t adcValue0MicroVolt;
uint16_t adcValue1[ADC_SAMPLE_COUNT];
uint32_t adcValue1MicroVolt[ADC_SAMPLE_COUNT];

// static Display_Handle display;

/*
 *  ======== threadFxn0 ========
 *  Open an ADC instance and get a sampling result from a one-shot conversion.
 */
//void *threadFxn0(void *arg0)
//{
//    ADC_Handle adc;
//    ADC_Params params;
//    int_fast16_t res;
//
//    ADC_Params_init(&params);
//    adc = ADC_open(CONFIG_ADC_0, &params);
//
//    if (adc == NULL)
//    {
//        // Display_printf(display, 0, 0, "Error initializing CONFIG_ADC_0\n");
//        while (1) {}
//    }
//
//    /* Blocking mode conversion */
//    res = ADC_convert(adc, &adcValue0);
//
//    if (res == ADC_STATUS_SUCCESS)
//    {
//
//        adcValue0MicroVolt = (COMPENSATION_FACTOR * ADC_convertRawToMicroVolts(adc, adcValue0)) / 1000;
//
//        // Display_printf(display, 0, 0, "CONFIG_ADC_0 raw result: %d\n", adcValue0);
//        // Display_printf(display, 0, 0, "CONFIG_ADC_0 convert result: %d uV\n", adcValue0MicroVolt);
//    }
//    else
//    {
//        // Display_printf(display, 0, 0, "CONFIG_ADC_0 convert failed\n");
//    }
//
//    ADC_close(adc);
//
//    return (NULL);
//}

void doAdc() {
    uint16_t i;
    ADC_Handle adc;
    ADC_Params params;
    int_fast16_t res;

    ADC_Params_init(&params);
    adc = ADC_open(CONFIG_ADC_1, &params);

    if (adc == NULL)
    {
        // Display_printf(display, 0, 0, "Error initializing CONFIG_ADC_1\n");
        while (1) {}
    }

    for (i = 0; i < ADC_SAMPLE_COUNT; i++)
    {
        res = ADC_convert(adc, &adcValue1[i]);

        if (res == ADC_STATUS_SUCCESS)
        {

            adcValue1MicroVolt[i] = (COMPENSATION_FACTOR * (ADC_convertToMicroVolts(adc, adcValue1[i]))) / 1000;

            // Display_printf(display, 0, 0, "CONFIG_ADC_1 raw result (%d): %d\n", i, adcValue1[i]);
            // Display_printf(display, 0, 0, "CONFIG_ADC_1 convert result (%d): %d uV\n", i, adcValue1MicroVolt[i]);
        }
        else
        {
            // Display_printf(display, 0, 0, "CONFIG_ADC_1 convert failed (%d)\n", i);
        }
    }

    //GPIO_setConfig(CONFIG_GPIO_ADC_1_AIN, GPIO_CFG_INPUT);
    GPIO_setConfigAndMux(CONFIG_GPIO_ADC_1_AIN, GPIO_CFG_INPUT, GPIO_MUX_GPIO);
    ADC_close(adc);

}

/*
 *  ======== threadFxn1 ========
 *  Open a ADC handle and get an array of sampling results after
 *  calling several conversions.
 */
void *threadFxn1(void *arg0)
{
    while(1) {
        doAdc();
        sleep(4);
    }

    return (NULL);
}

/*
 *  ======== mainThread ========
 */
void *mainThread(void *arg0)
{
    pthread_t thread0, thread1;
    pthread_attr_t attrs;
    struct sched_param priParam;
    int retc;
    int detachState;

    /* Call driver init functions */
    ADC_init();

    // Display_init();

    /* Open the display for output */
    // display = Display_open(Display_Type_UART, NULL);
    // if (display == NULL)
    // {
    //     /* Failed to open display driver */
    //     while (1) {}
    // }

    // Display_printf(display, 0, 0, "Starting the acdsinglechannel example\n");

    /* Create application threads */
    pthread_attr_init(&attrs);

    detachState = PTHREAD_CREATE_DETACHED;
    /* Set priority and stack size attributes */
    retc        = pthread_attr_setdetachstate(&attrs, detachState);
    if (retc != 0)
    {
        /* pthread_attr_setdetachstate() failed */
        while (1) {}
    }

    retc |= pthread_attr_setstacksize(&attrs, THREADSTACKSIZE);
    if (retc != 0)
    {
        /* pthread_attr_setstacksize() failed */
        while (1) {}
    }

    /* Create threadFxn0 thread */
    priParam.sched_priority = 1;
    pthread_attr_setschedparam(&attrs, &priParam);

//    retc = pthread_create(&thread0, &attrs, threadFxn0, NULL);
//    if (retc != 0)
//    {
//        /* pthread_create() failed */
//        while (1) {}
//    }

    /* Create threadFxn1 thread */
    retc = pthread_create(&thread1, &attrs, threadFxn1, (void *)0);
    if (retc != 0)
    {
        /* pthread_create() failed */
        while (1) {}
    }

    return (NULL);
}

adcsinglechannel.syscfg

Best regards,

Shuyang

  • " If the I/O pin is in a tri-state condition and connected
    to a node with a different voltage potential, a small leakage current can go through the pin. The same applies to
    an I/O pin configured as input, where the pin is connected to a voltage source (for example VDD/2). The input is
    then an undefined value of either 0 or 1." (From the tech. ref)

    When the ADC closes the io gets set to input and becomes undefined, because the voltage on the pin is around vdd/2

  • Hi Marten,

    How to avoid the current leakage? Or should I use the BATMON module to sample the battery voltage to lower the current consumption?

    Best regards,

    Shuyang

  • Are you going to use the same battery to power the system? If so this should not be an issue since the voltage on the pin is not vdd/2 but equal to vdd. I haven't used the f3 sdk, but in the f2 sdk there is a dropdown to sample a internal signal in the sysconfig adc driver.

  • Hi Martin,

    You are correct, you can set the source as the battery channel in Sysconfig:

    Saves a pin as well as external traces and routing.

    Alternatively if you just want to monitor the battery voltage down to a certain level you can use BATMON and set a threshold level to trigger an interrupt.

    BR,

    Jake

  • Hi Jake,

    The pin is not connected to the power supply of the MCU, so ADC input cannot be set to battery channel for this case.

    After some experiments, the customer found that setting the pin to tri-state can bring the current consumption down when ADC_close is called:

            ADC_close(adc);
            GPIO_setConfig(CONFIG_GPIO_ADC_1_AIN, GPIO_CFG_NO_DIR);

    Obviously putting GPIO to input mode draws more current than tri-state when connecting to a mid-rail voltage(e.g. VDD/2).

    I also found a previous post saying that the leakage current is around 90nA for CC2640 but can reach a few hundred uA if in input mode:

    "When all input buffers are disabled the entire device including pins draw around 90nA typically. (room temp).
    All analog modules are disconnected from the pins when not used so they will not draw any current.
    If the digital input is enabled the leakage current will depend on input voltage. Mid-rail you can typically see 2-400uA leakage current. This should however be avoided as a digital input should be either VDDS or GND."

    Considering a mid-rail voltage as ADC input is actually a common case in real applications, should we consider adding this code to the ADC driver to put the pin in tri-state in ADC_close? The 90nA leakage is much more accpectable by customers than the leakage current in input mode.

    Best regards,

    Shuyang

  • Hi Shuyang,

    Fair point, I have opened a ticket to track this request.

    Best regards,