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: Different current consumption while opening UART driver.

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

Tool/software:

Hi teams,

In basic_ble demo, I start a open-and-reopen(period of 1s) UART driver loop at the App_StackInitDoneHandler. Then I use ET to trace the current and find that the current consumption at the first round openning  UART driver is a slightly higher the subsequent rounds, as shown below.

Why does this happen? Please help with this.

Thanks.

BR

Connor

  • Hi Connor,

    Can you check if the same behavior is seen if some delay is added after power up? Could you wait 5 seconds before turning on the UART to see if the same increase is still seen?

    Best Regards,

    Jan

  • Hi Jan,

    Sure, I did this and it works. 500ms delay after power up.

    But I want to figure out why this happens? I need to explain this to the customer. 

    Thanks

  • Hello Connor,

    Could you please share how (code-snipped) you are testing the UART insid ethe App_StackInitDoneHandler() function? Are you using the MenuModule_printf or have you disable it?

    In addition, could you please check the differences between UART register values between the first and second UART operation? You can do this while in debug mode.

    BR,

    David.

  • Hi Jan,

    May I ask why you recommend wait 5 seconds? Is there any related issue before?

  • Hi David,

    The code-snipped is quite simple.

    #include <ti/drivers/UART2.h>
    #include <util.h>
    void uart_init(void);
    UART2_Handle _uartHandle = NULL;
    Clock_Struct clkOpenUart;
    Clock_Struct clkCycleUart;
    #define UART_RX_BUFF_SIZE           (256 * 4 + 128)
    uint8_t uart_buf[UART_RX_BUFF_SIZE];
    
    void _uart_deint(void)
    {
        UART2_close(_uartHandle);
    
        Util_constructClock(&clkOpenUart, (void*) uart_init,
                            1000, 0,
                            false,
                            0);
    
    //    Util_constructClock(&clkOpenUart, (void*) BLEAppUtil_invokeFunctionNoData,
    //                        1000, 0,
    //                        false,
    //                        (uint32_t)ttm_usart_init);
    
    
        Util_startClock(&clkOpenUart);
    
    }
    
    void uartReadCallBack(UART2_Handle handle, void *buf, size_t count,
                               void *userArg, int_fast16_t status)
    {
    
    }
    void uartWriteCallBack(UART2_Handle handle, void *buf, size_t count,
                                void *userArg, int_fast16_t status)
    {
    
    }
    
    void uart_init(void)
    {
        UART2_Params uartParams;
        UART2_Params_init(&uartParams);
        UART2_Params_init(&uartParams);
        uartParams.readMode = UART2_Mode_CALLBACK;
        uartParams.writeMode = UART2_Mode_CALLBACK;
        uartParams.readReturnMode = UART2_ReadReturnMode_PARTIAL;
        uartParams.baudRate = 115200;
        uartParams.readCallback = uartReadCallBack;
        uartParams.writeCallback = uartWriteCallBack;
    
        _uartHandle = UART2_open(CONFIG_UART2_0, &uartParams);
    
        UART2_read(_uartHandle, uart_buf, 244, NULL);
    
        Util_constructClock(&clkCycleUart, (void*) _uart_deint,
                                1000, 0,
                                false,
                                0);
    
    
        Util_startClock(&clkCycleUart);
    
    }
    /******************************************************************************
    
     @file  util.c
    
     @brief This file contains utility functions commonly used by
            BLE applications for CC26xx with TIRTOS.
    
     Group: WCS, BTS
     Target Device: cc23xx
    
     ******************************************************************************
     
     Copyright (c) 2014-2023, 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.
    
     ******************************************************************************
     
     
     *****************************************************************************/
    
    /*********************************************************************
     * INCLUDES
     */
    #ifdef FREERTOS
    #include <pthread.h> // Only for timer init - NOT FOR thread creation
    #include <mqueue.h>
    #include <stdbool.h>
    #include <time.h>
    #include <string.h>
    #include <mqueue.h>
    #else
    #include <ti/sysbios/knl/Event.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Queue.h>
    #include <ti/sysbios/hal/Hwi.h>
    #endif
    
    
    #ifdef USE_ICALL
    #include <icall.h>
    #else
    #include <stdlib.h>
    #endif
    
    #include "bcomdef.h"
    #include "util.h"
    
    #ifdef FREERTOS
    #ifndef ICALL_TIMER_TASK_STACK_SIZE
    /**
     * @internal
     * Timer thread stack size
     */
    #define ICALL_TIMER_TASK_STACK_SIZE (512)
    #endif //ICALL_TIMER_TASK_STACK_SIZE
    #endif//FREERTOS
    
    #ifdef FREERTOS
    extern mqd_t g_EventsQueueID;
    #endif
    /*********************************************************************
     * TYPEDEFS
     */
    
    #ifndef FREERTOS
    // RTOS queue for profile/app messages.
    typedef struct _queueRec_
    {
      Queue_Elem _elem;          // queue element
      uint8_t *pData;            // pointer to app data
    } queueRec_t;
    #endif
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    
    #ifdef FREERTOS
    typedef void (*UtilTimerCback)(uint32_t arg);
    void Util_stopClock(Clock_Struct *pClock);
    
    /**
     * @internal
     * Clock event handler function.
     * This function is used to implement the wakeup scheduler.
     *
     * @param arg  an @ref ICall_ScheduleEntry
     */
    static void UtilclockFunc(union sigval sv)
    {
        Clock_Struct *entry = (Clock_Struct *) (sv.sival_ptr);
    
        /* this means that this timer is not periodic so we set the isActive to 0 */
        if((entry->timeVal.it_interval.tv_nsec == 0) && (entry->timeVal.it_interval.tv_sec == 0))
        {
            entry->isActive = 0;
        }
    
        ((UtilTimerCback)(entry->cback))(entry->arg);
    }
    #endif
    
    
    /*********************************************************************
     * EXTERNAL VARIABLES
     */
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    
    /*********************************************************************
     * @fn      Util_constructClock
     *
     * @brief   Initialize a TIRTOS Clock instance.
     *
     * @param   pClock        - pointer to clock instance structure.
     * @param   clockCB       - callback function upon clock expiration.
     * @param   clockDuration - longevity of clock timer in milliseconds
     * @param   clockPeriod   - if set to a value other than 0, the first
     *                          expiry is determined by clockDuration.  All
     *                          subsequent expiries use the clockPeriod value.
     * @param   startFlag     - TRUE to start immediately, FALSE to wait.
     * @param   arg           - argument passed to callback function.
     *
     * @return  Clock_Handle  - a handle to the clock instance.
     */
    
    #ifdef FREERTOS
    void* Util_constructClock(Clock_Struct *entry, void *clockCB,
                              uint32_t clockDuration, uint32_t clockPeriod,
                              uint8_t startFlag, uint32_t arg)
    {
    
        int ret;
       // entry = ICall_malloc(sizeof(Clock_Struct));
        if (entry == NULL)
        {
            return (void *)(ICALL_ERRNO_NO_RESOURCE);
        }
    
        memset(entry, 0, sizeof(Clock_Struct));
    
        //Clock_Params params
        pthread_attr_init(&(entry->timerThrdAttr));
    
        entry->timerThrdAttr.stacksize = ICALL_TIMER_TASK_STACK_SIZE;
    
        entry->evnt.sigev_notify = SIGEV_THREAD;
        entry->evnt.sigev_notify_function = &UtilclockFunc;
        entry->evnt.sigev_notify_attributes = &(entry->timerThrdAttr);
    
        entry->arg = arg;
        entry->cback = clockCB;
    
        entry->evnt.sigev_value.sival_ptr = entry;
    
        ret = timer_create(CLOCK_MONOTONIC, &(entry->evnt), &(entry->clock));
    
        if (ret < 0)
        {
            return (void*)-1;
        }
    
        if (clockDuration == 0)
        {
            return (void *)(ICALL_ERRNO_INVALID_PARAMETER);
        }
    
        entry->timeVal.it_value.tv_sec = clockDuration / 1000;
        entry->timeVal.it_value.tv_nsec = 1000000 * (clockDuration % 1000);
        entry->timeVal.it_interval.tv_sec = clockPeriod / 1000;
        entry->timeVal.it_interval.tv_nsec = 1000000 * (clockPeriod % 1000);
    
        if (startFlag)
        {
            entry->isActive = 1;
            ret = timer_settime(entry->clock, 0, &(entry->timeVal), NULL);
            if (ret < 0)
            {
                return (void *)(ICALL_ERRNO_NO_RESOURCE);
            }
        }
    
        return (&(entry->clock));
    }
    
    void Clock_destruct(Clock_Struct *structP)
    {
        Util_stopClock(structP);
        timer_delete(structP->clock);
    
        structP->clock = 0;
    }
    
    #else
    Clock_Handle Util_constructClock(Clock_Struct *pClock,
                                     Clock_FuncPtr clockCB,
                                     uint32_t clockDuration,
                                     uint32_t clockPeriod,
                                     uint8_t startFlag,
                                     UArg arg)
    {
      Clock_Params clockParams;
    
      // Convert clockDuration in milliseconds to ticks.
      uint32_t clockTicks = clockDuration * (1000 / Clock_tickPeriod);
    
      // Setup parameters.
      Clock_Params_init(&clockParams);
    
      // Setup argument.
      clockParams.arg = arg;
    
      // If period is 0, this is a one-shot timer.
      clockParams.period = clockPeriod * (1000 / Clock_tickPeriod);
    
      // Starts immediately after construction if true, otherwise wait for a call
      // to start.
      clockParams.startFlag = startFlag;
    
      // Initialize clock instance.
      Clock_construct(pClock, clockCB, clockTicks, &clockParams);
    
      return Clock_handle(pClock);
    }
    
    
    #endif // FREERTOS
    
    /*********************************************************************
     * @fn      Util_startClock
     *
     * @brief   Start a clock.
     *
     * @param   pClock - pointer to clock struct
     *
     * @return  none
     */
    void Util_startClock(Clock_Struct *pClock)
    {
    #ifdef FREERTOS
    
      pClock->isActive = 1;
      timer_settime(pClock->clock, 0, &(pClock->timeVal), NULL);
    
    #else
      Clock_Handle handle = Clock_handle(pClock);
    
      // Start clock instance
      Clock_start(handle);
    #endif
    }
    
    /*********************************************************************
     * @fn      Util_restartClock
     *
     * @brief   Restart a clock by changing the timeout.
     *
     * @param   pClock - pointer to clock struct
     * @param   clockTimeout - longevity of clock timer in milliseconds
     *
     * @return  none
     */
    #ifndef FREERTOS
    void Util_restartClock(Clock_Struct *pClock, uint32_t clockTimeout)
    {
      uint32_t clockTicks;
      Clock_Handle handle;
    
      handle = Clock_handle(pClock);
    
      if (Clock_isActive(handle))
      {
        // Stop clock first
        Clock_stop(handle);
      }
    
      // Convert timeout in milliseconds to ticks.
      clockTicks = clockTimeout * (1000 / Clock_tickPeriod);
    
      // Set the initial timeout
      Clock_setTimeout(handle, clockTicks);
    
      // Start clock instance
      Clock_start(handle);
    }
    #endif
    /*********************************************************************
     * @fn      Util_isActive
     *
     * @brief   Determine if a clock is currently active.
     *
     * @param   pClock - pointer to clock struct
     *
     * @return  TRUE if Clock is currently active
                FALSE otherwise
     */
    bool Util_isActive(Clock_Struct *pClock)
    {
    #ifdef FREERTOS
      if(pClock->isActive == 1)
      {
        return TRUE;
      }
    
      // Start clock instance
      return FALSE;
    #else
      Clock_Handle handle = Clock_handle(pClock);
    
      // Start clock instance
      return Clock_isActive(handle);
    #endif
    }
    
    /*********************************************************************
     * @fn      Util_stopClock
     *
     * @brief   Stop a clock.
     *
     * @param   pClock - pointer to clock struct
     *
     * @return  none
     */
    void Util_stopClock(Clock_Struct *pClock)
    {
    #ifdef FREERTOS
        struct itimerspec timeVal;
    
        memset(&timeVal,0,sizeof(struct itimerspec));
    
        /* stop the timer */
        timer_settime(pClock->clock, 0, &(timeVal), NULL);
    
        pClock->isActive = 0;
    
    #else
      Clock_Handle handle = Clock_handle(pClock);
    
      // Stop clock instance
      Clock_stop(handle);
    #endif
    }
    
    /*********************************************************************
     * @fn      Util_rescheduleClock
     *
     * @brief   Reschedule a clock by changing the timeout and period values.
     *
     * @param   pClock - pointer to clock struct
     * @param   clockPeriod - longevity of clock timer in milliseconds
     * @return  none
     */
    void Util_rescheduleClock(Clock_Struct *pClock, uint32_t clockPeriod)
    {
      bool running;
    
    #ifdef FREERTOS
      running = Util_isActive(pClock);
    
      if (running)
      {
          Util_stopClock(pClock);
      }
    
      pClock->timeVal.it_interval.tv_sec = clockPeriod / 1000;
      pClock->timeVal.it_interval.tv_nsec = 1000000 * (clockPeriod % 1000);
      pClock->timeVal.it_value.tv_sec = clockPeriod / 1000;
      pClock->timeVal.it_value.tv_nsec = 1000000 * (clockPeriod % 1000);
    
      timer_settime(pClock->clock, 0, &(pClock->timeVal), NULL);
    
    #else
      uint32_t clockTicks;
      Clock_Handle handle;
    
      handle = Clock_handle(pClock);
      running = Clock_isActive(handle);
    
      if (running)
      {
        Clock_stop(handle);
      }
    
      // Convert period in milliseconds to ticks.
      clockTicks = clockPeriod * (1000 / Clock_tickPeriod);
    
      Clock_setTimeout(handle, clockTicks);
      Clock_setPeriod(handle, clockTicks);
    
      if (running)
      {
        Clock_start(handle);
      }
    #endif
    }
    
    /*********************************************************************
     * @fn      Util_constructQueue
     *
     * @brief   Initialize an RTOS queue to hold messages to be processed.
     *
     * @param   pQueue - pointer to queue instance structure.
     *
     * @return  A queue handle.
     */
    #ifdef FREERTOS
    
    void Util_constructQueue(mqd_t *pQueue)
    {
        struct mq_attr MRattr;
    
        MRattr.mq_flags = O_NONBLOCK; //Blocking
        MRattr.mq_curmsgs = 0;
        MRattr.mq_maxmsg = 32;
        MRattr.mq_msgsize = sizeof(uint8_t*);
        /* Open the reply message queue */
        *pQueue = mq_open("/AppQueue", O_CREAT | O_NONBLOCK , 0, &MRattr);
        if (pQueue == (mqd_t *) -1)
        {
            //handle_error("mq_open");
    
            while(1);
        }
    }
    #else // FREERTOS
    Queue_Handle Util_constructQueue(Queue_Struct *pQueue)
    {
      // Construct a Queue instance.
      Queue_construct(pQueue, NULL);
    
      return Queue_handle(pQueue);
    }
    #endif // FREERTOS
    
    /*********************************************************************
     * @fn      Util_enqueueMsg
     *
     * @brief   Creates a queue node and puts the node in RTOS queue.
     *
     * @param   msgQueue - queue handle.
     * @param   event - thread's event processing handle that queue is
     *                associated with.
     * @param   pMsg - pointer to message to be queued
     *
     * @return  TRUE if message was queued, FALSE otherwise.
     */
    #ifdef FREERTOS
    
    typedef struct {
        uint8_t * pData;
    }queueMSG;
    
    uint8_t Util_enqueueMsg(mqd_t msgQueue,
                            Event_Handle event,
                            uint8_t *pMsg)
    {
        queueMSG myMsg;
    
        myMsg.pData = pMsg;
        mq_send(msgQueue, (char*)&myMsg, sizeof(queueMSG), 1);
    
        // Wake up the application thread event handler.
        if (event)
        {
    
            uint32_t msg_ptr = UTIL_QUEUE_EVENT_ID;
            mq_send(event, (char*)&msg_ptr, sizeof(msg_ptr), 1);
        }
    
        return TRUE;
    
    }
    #else
    
    
    uint8_t Util_enqueueMsg(Queue_Handle msgQueue,
                            Event_Handle event,
                            uint8_t *pMsg)
    {
      queueRec_t *pRec;
    
      // Allocated space for queue node.
    #ifdef USE_ICALL
      if ((pRec = ICall_malloc(sizeof(queueRec_t))))
    #else
      if ((pRec = (queueRec_t *)malloc(sizeof(queueRec_t))))
    #endif
      {
        pRec->pData = pMsg;
    
        // This is an atomic operation
        Queue_put(msgQueue, &pRec->_elem);
    
        // Wake up the application thread event handler.
        if (event)
        {
          Event_post(event, UTIL_QUEUE_EVENT_ID);
        }
        return TRUE;
      }
    
      // Free the message.
    #ifdef USE_ICALL
      ICall_free(pMsg);
    #else
      free(pMsg);
    #endif
    
      return FALSE;
    }
    #endif
    
    /*********************************************************************
     * @fn      Util_dequeueMsg
     *
     * @brief   Dequeues the message from the RTOS queue.
     *
     * @param   msgQueue - queue handle.
     *
     * @return  pointer to dequeued message, NULL otherwise.
     */
    #ifdef FREERTOS
    extern ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
                              unsigned int *msg_prio);
    uint8_t *Util_dequeueMsg(mqd_t msgQueue)
    {
        uint32_t msg_prio;
        queueMSG myMsg;
        uint8_t *pData = NULL;
        //* Non blocking queue */
        int msgSize = mq_receive(msgQueue,(char *)&myMsg, sizeof(queueMSG),(void*) &msg_prio);
    
        if(msgSize == (-1))
        {
            /*  The queue is empty which it's Ok*/
            return NULL;
        }
        pData = myMsg.pData;
        return pData;
    }
    
    #else
    
    
    uint8_t *Util_dequeueMsg(Queue_Handle msgQueue)
    {
      queueRec_t *pRec = Queue_get(msgQueue);
    
      if (pRec != (queueRec_t *)msgQueue)
      {
        uint8_t *pData = pRec->pData;
    
        // Free the queue node
        // Note:  this does not free space allocated by data within the node.
    #ifdef USE_ICALL
        ICall_free(pRec);
    #else
        free(pRec);
    #endif
    
        return pData;
      }
    
      return NULL;
    }
    #endif
    
    /*********************************************************************
     * @fn      Util_isBufSet
     *
     * @brief   Check if contents of buffer matches byte pattern.
     *
     * @param   pBuf    - buffer to check
     * @param   pattern - pattern to match
     * @param   len     - len of buffer (in bytes) to iterate over
     *
     * @return  TRUE if buffer matches the pattern, FALSE otherwise.
     */
    uint8_t Util_isBufSet(uint8_t *pBuf, uint8_t pattern, uint16_t len)
    {
      uint8_t result = FALSE;
      uint16_t i = 0;
    
      if (pBuf)
      {
        result = TRUE;
    
        for(i = 0; i < len; i++)
        {
          if (pBuf[i] != pattern)
          {
            // Buffer does not match pattern.
            result = FALSE;
            break;
          }
        }
      }
    
      return (result);
    }
    
    #ifdef FREERTOS
    /*********************************************************************
     * @fn      Event_post
     *
     * @brief   DPL that is used to signal events. If a task is waiting
     *          for the event and the event conditions are met, post()
     *          unblocks the task. If no tasks are waiting, post() simply
     *          registers the event with the event object and returns.
     *
     * @param   eventQueue - handle of a event queue
     * @param   msg - mask of eventIds to post (must be non-zero)
     */
    void Event_post(mqd_t eventQueue, uint32_t msg)
    {
      mq_send(eventQueue, (char*)&msg, sizeof(uint32_t), 1);
    }
    #endif
    
    /*********************************************************************
    *********************************************************************/
    
    8176.util.h

  • The registers are of the same value.

  • Hello Connor,

    Thanks for the info. And you are calling uart_init() from App_StackInitDoneHandler? I suspect the power policies might be different here. Could you please share the return of the Power_getConstraintMask()? You can look at the details of the power driver here inside <SDK>/docs/drivers/doxygen/html/_power_8h.html.

    BR,

    David.

  • Hi David,

    Thanks for the info. And you are calling uart_init() from App_StackInitDoneHandler?

    Yes, I call the uart_init() before end of the App_StackInitDoneHandler.

    As shown in the figure. The return of Power_getConstraintMask are of the same value.

    I am wondering whether this issue related to the context? But it is weird that before calling the uart_init(), I call sleep(1) to wait for a second and this issue will not produce.

    Attached my project.basic_ble_connor.zip

    Thanks.

    BR

    Connor

  • Hello Connor,

    I will take a look at the project. Please allow me until tomorrow. However I would suggest to take a look at where in the example projects the UART is initialized and opened to follow that lead.

    BR,

    David.

  • Hi David,

    Is there any progress?

    Thanks.

    BR

    Connor

  • Hello Connor,

    Apologies, I haven't been able to take look further into this. Allow me until the start of next week please. Have you been able to get some leads based on how/when we implement this in the examples?

    BR,

    David.

  • Hi David,

    Thank you for your support; I understand that you have a busy schedule.

    Below is the UART Driver initialization code. Is it possibly related to other driver(maybe DMA) while opening the UART?

    I hope it helps.

    Thanks.

    BR

    Connor

  • Hi David,

    Any progress?

    Thanks.

    BR

    Connor

  • Hello Connor,

    Thank for the patience here. I have used the files (UART and clock setup) you shared to try to reproduce the behaviour you see. However I do not have the same UART extra current draw during the first UART event. May I ask if you already modified the files with the extra delay (500ms) that Jan suggested at the beginning (although from the code it doesn't seem like)?  Is there any other modification to the project we are missing?

    By the way, I am using the basic_ble example (SDK version 8.10), selected the option of "Disable The Display Module" in SysConfig -> Advanced Settings, and modifying the appMain() function as follows:

    void appMain(void)
    {
        // Call the BLEAppUtil module init function
        BLEAppUtil_init(&criticalErrorHandler, &App_StackInitDoneHandler,
                        &appMainParams, &appMainPeriCentParams);
    
        uart_init();
    }

    Let me know your thoughts.

    BR,

    David.

  • Hi David,

    Thanks for your attempt!

    Actually, the key of this issue is the following steps: Power up --> Uart Open(with higher current consumption) --> Uart Close --> Uart Open(with lower(normal) current consumption) --> Uart Open -->........

    I hope the following figure help understand.

    In conclusion, "1st UART open" consumes higher current than the "2nd UART Open" and refering the "1st UART open" current consumption after powering up is the key to reproduce the issue.

    It is quite weird.....

    Therefore, could you please to figure out  what causes the various current consumption?

    Thanks.

    BR,

    Connor.

  • Hello Connor,

    Thank you for the detail in the steps, I see what you mention now. I would try the same with a non BLE example, such as empty and see if this reproduces, just to make sure it is not BLE related. Are you using DCDC or GLDO?

    BR,

    David.

  • Hi David,

    DCDC, only with the below modifications of syscfg. Hardware is LP-EM-CC2340R5.

    BR,

    Connor.

  • Hi David,

    Any progress?

    Thanks.

  • Hello Connor,

    I have tested the initialization/close/reopen sequence using the empty example (no BLE) and although there is slightly more current draw, it is not as harsh as in the ble example. I think there are definitively routines that are executing right after booting/resetting that are consuming more power, radio related could be one of them that would explain more power consumption for ble enabled examples. Anyways, I am waiting the experts on the Power domain for further details on this routines.

    BR,

    David.

  • Hello Connor,

    Discussing further with the team, it could be that this might be unrelated to UART. The UART driver will disallow standby while UART RX is happening. So to discard the issue coming from UART, and rather it being an issue of increased current before the first standby entry. Could you try to replace your UART2_open() -> UART2_read() -> UART2_close() sequence, with just something like below: Power_setConstraint(PowerLPF3_DISALLOW_STANDBY); wait a period of time (clock timer) and then Power_releaseConstraint(PowerLPF3_DISALLOW_STANDBY); 

    BR,

    David.

  • Hi David,

    Thanks a lot for your and the team's hard work.

    I have tested the mentioned sequence: Power_setConstraint(PowerLPF3_DISALLOW_STANDBY); wait a period of time (clock timer) and then Power_releaseConstraint(PowerLPF3_DISALLOW_STANDBY). Please see the picture below.

    Just like what you have mentioned, It seems this issue is unrelated to the UART driver.

    Could you please figure out why the increased current happened before the first standby entry? 

    Looking forward to your reply.

    Thanks,

    BR,

    Connor.

  • Hello Connor,

    Alright, interesting. Could you please help me with one last register status check?

    Please take a look at the CMKD registers for the first UART/Standby event and after lets say 30 seconds. Specifically the CKMD.HFXTTARG.IREF which will give us info about the current status. The CKMD.HFXTTARG.IREF value should start up at 8 (after Power_init()) and then decrease by 1 for each standby entry until the amplitude settles.

    BR,

    David.

  • Hi David,

    Glad to get your quick reply.

    I have check the CKMD.HFXTTARG.IREF, please refer to the picture below.

    It seems relate to this issue. 

    Could this explain the issue?

    Thanks!

    BR,

    Connor.

  • Hello Connor,

    Thanks for the extra info. Lets try enabling the Initial HFXT Amplitude Compensation through SysConfig.

    If the application requires that the HFXT amplitude is already in the optimal range after boot, then Initial HFXT Amplitude Compensation can be enabled with PowerCC23X0_Config.startInitialHfxtAmpCompFxn. If initial HFXT amplitude compensation is enabled, the optimal amplitude will be found at/after boot, meaning it will take longer before HFXT is ready after boot, but when it is ready the amplitude will already be in the optimal range. Please be aware of the timing trade-off mentioned here.

    BR,

    David.

  • Hi David,

    Thank you very much for your help.

    Enabling the Initial HFXT Amplitude Compensation seems work, picture below.

    But I have noticed “Enabling initial HFXT amplitude compensation will result in more flash usage and longer time from boot to the first RF operation.” this sentence was described in the PowerCC23X0.h.

    The more flash usage could easily get by CCS. My question is how to measure the time from boot to the first RF operation. Is there any description in any doc? Or what is the recommended method to measure via  "basic_ble"?

    Thanks!

    BR,

    Connor.

  • Hello Connor,

    Great to see the progress.

    I would suggest to take a look at this section of the users guide: https://software-dl.ti.com/simplelink/esd/simplelink_lowpower_f3_sdk/8.10.00.55/exports/docs/ble5stack/ble_user_guide/html/ble-stack-5.x-guide/debugging-index-cc23xx.html#debugging-rf-output. If you enable the RF output pins (RX, TX), then it should be easy to spot the time between boot (you can use another GPIO here) and first RF operation with a logic analyzer.

    BR,

    David.

  • Hi David,

    Thanks for your support.

    BR,

    Connor.