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.

LP-AM243: Uart Rx callback is not triggered second time

Part Number: LP-AM243
Other Parts Discussed in Thread: SYSCONFIG

Hi,

I am using ind_comms_sdk_am243x_09_02_00_24 for my development.

I am using UART in one of my applications where I need to transmit and receive 8 bytes of data every 20 ms. Initially, I configured both TX and RX in polling (blocking) mode, and the data transfer was working correctly.

I later modified the implementation so that UART transmission remains in blocking mode, while UART reception is handled using callback (non‑blocking) mode. After updating the configuration in SysConfig and implementing this change, transmission works as expected. However, the receive callback is triggered only once.

After the first callback invocation, no further RX callbacks occur, even though I continue sending data from the terminal. 

app_uart.c sysconfig.png

  • Hi,

    Let me check the UART driver and see if there has been bug fixes in it for this issue.

    Regards,

    Vaibhav

  • Not necessarily all bug fixes would apply to your use case, but I would have you integrate the following: https://github.com/TexasInstruments/mcupsdk-core/commit/19c69892091c4aeebfd4b95e230a81b869a9f43e

    It talks about FIFO Trigger level fix. Lets have this in your SDK and rebuild your libraries/drivers and then your application. Test it out and let me know.

    Also talk to me through how you are calling the second callback? How are your reads called, give me a sample code structure of how uart reads is called and how are you inputting data? (NOTE: Preffered way to input data would be via a Python script that rights to the COM PORT at the UART's configured baud rate)

  • The issue remains same after integrating uart drivers aswell. only first time I could see the data bytes.

    And we are using Terminal tool for sending data to TI for both blocking and callback method.

  • Also talk to me through how you are calling the second callback? How are your reads called, give me a sample code structure of how uart reads is called and how are you inputting data?

    Please answer the following question as well. Give me your code snippet of how its done.

  • i already attached in my first thread. however here is my code which we are using.

    /*!
     *  \file appUart.c
     *
     *  \brief
     *  EtherNet/IP™ Adapter Example Application, UART application.
     *
     *  \author
     *  Texas Instruments Incorporated
     *
     *  \copyright
     *  Copyright (C) 2024 Texas Instruments Incorporated
     *
     *  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.
     */
    
    #include <stdarg.h>
    #include <string.h>
    #include <stdio.h>
    
    #include "osal_error.h"
    
    #include "drivers/uart/v0/uart.h"
    
    #include "ti_drivers_config.h"
    
    #include "appUart.h"
    #include "appMutex.h"
    
    // ...existing code...
    #define APP_UART_TASK_STACK_SIZE             1024
    #define APP_UART_BUFFER_SIZE                 0x300
    #define APP_UART_MAX_INSTANCES               5 // Adjust as needed
    
    extern UART_Handle gUartHandle[CONFIG_UART_NUM_INSTANCES];
    
    typedef struct EI_APP_Uart {
        UART_Handle                        handle;
        uint32_t                           instance;
        void*                              uartTaskHandle;
        char                               aOutStream[APP_UART_BUFFER_SIZE];
        UART_Transaction                   transaction;
        void*                              uartSignal;
        uint32_t                           uartWritePos;
        uint32_t                           uartReadPos;
        bool                               isInitialized;
    
        /* --- ADD: RX support for PCB UART(1) --- */
        uint8_t                            rxByte[8];           /* persistent 1-byte RX buffer */
        UART_Transaction                   rxTransaction;    /* persistent RX transaction */
        uint8_t                            aInStream[APP_UART_BUFFER_SIZE]; /* RX store */
        uint32_t                           rxWritePos;
        uint32_t                           rxReadPos;
    
    } EI_APP_Uart_t;
    
    static EI_APP_Uart_t EI_APP_uart_s[APP_UART_MAX_INSTANCES] = {0};
    
    
    static void EI_APP_UART_task(void *pvTaskArg);
    
    static uint32_t EI_APP_UART_rx_read_1(uint8_t *dst, uint32_t maxLen)
    {
        EI_APP_Uart_t *u = &EI_APP_uart_s[1];
        uint32_t read = 0U;
        while (read < maxLen && u->rxReadPos != u->rxWritePos) {
            dst[read++] = u->aInStream[u->rxReadPos];
            u->rxReadPos = (u->rxReadPos + 1U) % APP_UART_BUFFER_SIZE;
        }
    
        return read;
    }
    
    void Uart_PCB_Rx_Cb(UART_Handle handle, UART_Transaction *t)
    {
        EI_APP_Uart_t *u = &EI_APP_uart_s[1];
        if (!u->isInitialized) {
            return;
        }
        if (t->status == UART_TRANSFER_STATUS_SUCCESS && t->count > 0U) {
            uint8_t *src = (uint8_t *)t->buf;
            for (uint32_t i = 0; i < t->count; i++) {
                uint32_t next = (u->rxWritePos + 1U) % APP_UART_BUFFER_SIZE;
                if (next != u->rxReadPos) {
                    u->aInStream[u->rxWritePos] = src[i];
                    u->rxWritePos = next;
                } else {
                    /* RX overflow: drop (optional: count it) */
                    break;
                }
            }
        }
        UART_Transaction_init(t);
        t->buf     = &u->rxByte[0];     
        t->count   = 8U;             
        t->args    = NULL;
        t->timeout = SystemP_WAIT_FOREVER;
        (void)UART_read(handle, t);
    }
    
    static void log_hex(const uint8_t *buf, size_t len)
    {
        DebugP_log("RX %u bytes: ", (unsigned)len);
        for (size_t i = 0; i < len; i++) {
            DebugP_log("%02X%s", buf[i], (i + 1 < len) ? " " : "");
        }
        DebugP_log("\r\n");
    }
    
    /*!
     * \brief
     *  uart print task
     *
     * \details
     * This function, is used to do printf on a low prio thread
     *
     */
    
    // Helper function to send a fixed string via UART task
    void EI_APP_UART_send_string(uint32_t uartInst, const char *str,uint32_t len)
    {
        if (uartInst >= APP_UART_MAX_INSTANCES || !EI_APP_uart_s[uartInst].isInitialized)
            return;
        EI_APP_MUTEX_EError_t mutexRetVal;
        uint32_t bytesToWrite = len;//strlen(str);
        mutexRetVal = EI_APP_Mutex_Lock(EI_APP_Mutex_UART, 50);
        if (EI_APP_MUTEX_eERR_NOERROR == mutexRetVal) {
            EI_APP_Uart_t *uart = &EI_APP_uart_s[uartInst];
            uint32_t availableSpace;
            if (uart->uartReadPos > uart->uartWritePos)
            {
                availableSpace = uart->uartReadPos - uart->uartWritePos - 1;
            }
            else
            {
                availableSpace = APP_UART_BUFFER_SIZE - uart->uartWritePos;
                if (uart->uartReadPos == 0)
                    availableSpace -= 1;
            }
            if (availableSpace > bytesToWrite)
            {
                memcpy(&uart->aOutStream[uart->uartWritePos], str, bytesToWrite);
                uart->uartWritePos = (uart->uartWritePos + bytesToWrite) % APP_UART_BUFFER_SIZE;
            }
            else if((uart->uartWritePos == uart->uartReadPos) && (0 != uart->uartWritePos))
            {
                uint32_t firstPart = availableSpace;
                uint32_t secondPart = bytesToWrite - availableSpace;
                memcpy(&uart->aOutStream[uart->uartWritePos], str, firstPart);
                memcpy(uart->aOutStream, &str[firstPart], secondPart);
                uart->uartWritePos = secondPart;
            }
            // else: Buffer is full
            EI_APP_Mutex_Unlock(EI_APP_Mutex_UART);
            OSAL_postSignal(uart->uartSignal);
        }
    }
    /*!
    *
    *  \brief
    *  Provides handle to UART driver.
    *
    *  \return     UART_Handle  Handle to UART driver.
    *
    *  \retval     NULL           Failed.
    *  \retval     Other          Success.
    *
    */
    UART_Handle EI_APP_UART_getHandle(uint32_t instanceId)
    {
        UART_Handle handle = NULL;
        if (CONFIG_UART_NUM_INSTANCES > instanceId)
        {
            handle = gUartHandle[instanceId];
        }
        return handle;
    }
    
    /*!
    *
    *  \brief
    *  Initialize UART application part.
    *
    *  \param[in]  UART initialization parameters.
    *
    *  \return     error code as uint32_t
    *
    *  \retval     #OSAL_NO_ERROR                Success.
    *  \retval     #OSAL_GENERAL_ERROR           Negative default value.
    *  \retval     #OSAL_UART_DRV_HANDLE_INVALID UART handle is NULL.
    *
    */
    uint32_t EI_APP_UART_init(const EI_APP_UART_SInit_t* pParams)
    {
        uint32_t result = OSAL_GENERAL_ERROR;
        uint32_t idx = pParams->uartInst;
        if(idx < APP_UART_MAX_INSTANCES && FALSE == EI_APP_uart_s[idx].isInitialized)
        {
            EI_APP_uart_s[idx].instance = idx;
            EI_APP_uart_s[idx].handle   = EI_APP_UART_getHandle(idx);
            char signalName[16];
            snprintf(signalName, sizeof(signalName), "uartSignal_%u", idx);
            EI_APP_uart_s[idx].uartSignal = OSAL_createSignal(signalName);
            EI_APP_uart_s[idx].uartWritePos = 0;
            EI_APP_uart_s[idx].uartReadPos = 0;
            if((NULL == EI_APP_uart_s[idx].handle) || (NULL == EI_APP_uart_s[idx].uartSignal))
            {
                result = OSAL_UART_DRV_HANDLE_INVALID;
                goto laError;
            }
            char taskName[16];
            snprintf(taskName, sizeof(taskName), "uart_task_%u", idx);
            // Start TX/print task for all instances
            EI_APP_uart_s[idx].uartTaskHandle = OSAL_SCHED_startTask(
                EI_APP_UART_task,
                (void *)&EI_APP_uart_s[idx],
                pParams->taskPrio,
                NULL,
                APP_UART_TASK_STACK_SIZE,
                OSAL_OS_START_TASK_FLG_NONE,
                taskName);
    
    //         Start dedicated RX task for UART PCB (instance 1)
    //        if (idx == 1) {
    //            char rxTaskName[20];
    //            snprintf(rxTaskName, sizeof(rxTaskName), "uart_pcb_rx_task_%u", idx);
    //            OSAL_SCHED_startTask(
    //                EI_APP_UART_pcb_rx_task,
    //                (void *)&EI_APP_uart_s[idx],
    //                pParams->taskPrio,
    //                NULL,
    //                APP_UART_TASK_STACK_SIZE,
    //                OSAL_OS_START_TASK_FLG_NONE,
    //                rxTaskName);
    //        }
    
            if(NULL == EI_APP_uart_s[idx].uartTaskHandle)
            {
                result = OSAL_GENERAL_ERROR;
                goto laError;
            }
    
            EI_APP_uart_s[idx].isInitialized = TRUE;
    
            /* --- ADD: RX init ONLY for PCB UART instance 1 --- */
            if (idx == 1U) {
                EI_APP_uart_s[idx].rxWritePos = 0U;
                EI_APP_uart_s[idx].rxReadPos  = 0U;
                memset(EI_APP_uart_s[idx].aInStream, 0, sizeof(EI_APP_uart_s[idx].aInStream));
    
                UART_Transaction_init(&EI_APP_uart_s[idx].rxTransaction);
                EI_APP_uart_s[idx].rxTransaction.buf     = &EI_APP_uart_s[idx].rxByte[0];  /* 1-byte persistent buffer */
                EI_APP_uart_s[idx].rxTransaction.count   = 8U;                          /* Partial mode: per byte */
                EI_APP_uart_s[idx].rxTransaction.args    = NULL;
                EI_APP_uart_s[idx].rxTransaction.timeout = SystemP_WAIT_FOREVER;        /* harmless in callback mode */
                (void)UART_read(EI_APP_uart_s[idx].handle, &EI_APP_uart_s[idx].rxTransaction);
            }
    
            result = OSAL_NO_ERROR;
        }
    
    laError:
        return result;
    }
    
    
    
    
    
        // This function has been removed as the UART handling is now generic.
    
    /*!
    *
    *  \brief
    *  De-initialize UART application part.
    *
    *  \return     error code as uint32_t
    *
    *  \retval     #OSAL_NO_ERROR                Success.
    *  \retval     #OSAL_GENERAL_ERROR           Negative default value.
    *  \retval     #OSAL_UART_DRV_HANDLE_INVALID UART handle is NULL.
    *
    */
    uint32_t EI_APP_UART_deInit(void)
    {
        uint32_t result = OSAL_GENERAL_ERROR;
    
        // Deinit all UART instances
        for (int i = 0; i < APP_UART_MAX_INSTANCES; ++i) {
            if (EI_APP_uart_s[i].handle != NULL) {
                UART_flushTxFifo(EI_APP_uart_s[i].handle);
            }
        }
    
        result = OSAL_NO_ERROR;
    
        return result;
    }
    
    // UART print task
    static void EI_APP_UART_task(void *pvTaskArg)
    {
        EI_APP_Uart_t *pDrvUart = (EI_APP_Uart_t *)pvTaskArg;
        EI_APP_MUTEX_EError_t mutexRetVal;
    
        while(1)
        {
            // TX handling
            uint32_t bytesToWrite;
            OSAL_waitSignal(pDrvUart->uartSignal, 100);
    
            mutexRetVal = EI_APP_Mutex_Lock(EI_APP_Mutex_UART, OSAL_WAIT_INFINITE);
    
            if( EI_APP_MUTEX_eERR_NOERROR == mutexRetVal)
            {
                if(pDrvUart->uartReadPos == pDrvUart->uartWritePos)
                {
                    EI_APP_Mutex_Unlock(EI_APP_Mutex_UART);
                    //   continue;
                }
    
    //              UART_flushTxFifo(pDrvUart->handle);
                UART_Transaction_init(&pDrvUart->transaction);
    
                // single write operation
                if(pDrvUart->uartWritePos > pDrvUart->uartReadPos)
                {
                    bytesToWrite = pDrvUart->uartWritePos - pDrvUart->uartReadPos;
                    if (bytesToWrite > 0) {
                        pDrvUart->transaction.count = bytesToWrite;
                        pDrvUart->transaction.buf = (void *)&pDrvUart->aOutStream[pDrvUart->uartReadPos];
                        pDrvUart->transaction.args = NULL;
    
                        (void)UART_write(pDrvUart->handle, &pDrvUart->transaction);
    
                        pDrvUart->uartReadPos = (pDrvUart->uartReadPos + bytesToWrite) % APP_UART_BUFFER_SIZE;
                    }
                }
                // two write operations
                else
                {
                    //first part
                    bytesToWrite =  APP_UART_BUFFER_SIZE -  pDrvUart->uartReadPos ;
                    if (bytesToWrite > 0) {
                        pDrvUart->transaction.count = bytesToWrite;
                        pDrvUart->transaction.buf = (void *)&pDrvUart->aOutStream[pDrvUart->uartReadPos];
                        pDrvUart->transaction.args = NULL;
    
                        (void)UART_write(pDrvUart->handle, &pDrvUart->transaction);
    
                        pDrvUart->uartReadPos = (pDrvUart->uartReadPos + bytesToWrite) % APP_UART_BUFFER_SIZE;
                    }
                    //second part
                    bytesToWrite = pDrvUart->uartWritePos;
                    if (bytesToWrite > 0) {
                        pDrvUart->transaction.count = bytesToWrite;
                        pDrvUart->transaction.buf = (void *)&pDrvUart->aOutStream[0];
                        pDrvUart->transaction.args = NULL;
    
                        (void)UART_write(pDrvUart->handle, &pDrvUart->transaction);
                        pDrvUart->uartReadPos = (pDrvUart->uartReadPos + bytesToWrite) % APP_UART_BUFFER_SIZE;
                    }
                }
                EI_APP_Mutex_Unlock(EI_APP_Mutex_UART);
    
    
                if(pDrvUart->instance == CONFIG_PCB_UART)
                {
    //                uint8_t data_transmit[8]= {0x4b,0x4c,0x4d,0x4b,0x4b,0x4b,0x4b,0x4b};
    //                EI_APP_UART_send_string(1,data_transmit,8);
    
                    uint8_t buf[8];
                    uint32_t n = EI_APP_UART_rx_read_1(buf, sizeof(buf));
                    if (n > 0U) {
    //                    DebugP_log("n value %d\r\n",n);
                        log_hex(buf, n);  // log from TASK, not from callback
                    }
                }
    
            }
    
            OSAL_SCHED_yield();
        }
        OSAL_SCHED_exitTask(NULL);
    }
    
    /*!
    *
    *  \brief
    *  UART printf output function.
    *
    *  \details
    *  Printing of specific string to UART output.
    *
    *  \param[in]  pContext      Call context
    *  \param[in]  pFormat       Format string.
    *  \param[in]  argptr        Parameter list.
    *
    *
    */
    void EI_APP_UART_printf(uint32_t uartIdx,void* pContext, const char* pFormat, va_list arg)
    {
        /* @cppcheck_justify{unusedVariable} false-positive: variable is used */
        //cppcheck-suppress unusedVariable
        EI_APP_MUTEX_EError_t mutexRetVal;
    
        OSALUNREF_PARM(pContext);
    
        int lengthWritten;
        static char localString[256] = {0};
    
        OSALUNREF_PARM(pContext);
    
        lengthWritten = vsnprintf(localString, sizeof(localString), pFormat, arg);
    
        if (lengthWritten > 0)
        {
            uint32_t bytesToWrite = (uint32_t)lengthWritten;
    
            mutexRetVal = EI_APP_Mutex_Lock(EI_APP_Mutex_UART, OSAL_WAIT_INFINITE);
            if (EI_APP_MUTEX_eERR_NOERROR == mutexRetVal) {
                uint32_t availableSpace;
                // Use first UART instance for printf (or make this configurable)
    //            int uartIdx = 0;
                if (EI_APP_uart_s[uartIdx].uartReadPos > EI_APP_uart_s[uartIdx].uartWritePos)
                {
                    availableSpace = EI_APP_uart_s[uartIdx].uartReadPos - EI_APP_uart_s[uartIdx].uartWritePos - 1;
                }
                else
                {
                    availableSpace = APP_UART_BUFFER_SIZE - EI_APP_uart_s[uartIdx].uartWritePos;
                    if (EI_APP_uart_s[uartIdx].uartReadPos == 0)
                      availableSpace -= 1;
                }
    
                // Single write operation
                if (availableSpace > bytesToWrite)
                {
                    memcpy(&EI_APP_uart_s[uartIdx].aOutStream[EI_APP_uart_s[uartIdx].uartWritePos], localString, bytesToWrite);
                    EI_APP_uart_s[uartIdx].uartWritePos = (EI_APP_uart_s[uartIdx].uartWritePos + bytesToWrite) % APP_UART_BUFFER_SIZE;
                }
                // Divide the write operation into two parts
                else if((EI_APP_uart_s[uartIdx].uartWritePos == EI_APP_uart_s[uartIdx].uartReadPos) && (0 != EI_APP_uart_s[uartIdx].uartWritePos))
                {
                    uint32_t firstPart = availableSpace;
                    uint32_t secondPart = bytesToWrite - availableSpace;
    
                    memcpy(&EI_APP_uart_s[uartIdx].aOutStream[EI_APP_uart_s[uartIdx].uartWritePos], localString, firstPart);
                    memcpy(EI_APP_uart_s[uartIdx].aOutStream, &localString[firstPart], secondPart);
    
                    EI_APP_uart_s[uartIdx].uartWritePos = secondPart;
                }
                else
                {
                    // Buffer is full
                }
    
                EI_APP_Mutex_Unlock(EI_APP_Mutex_UART);
                // Notify the UART task to write the data
                OSAL_postSignal(EI_APP_uart_s[uartIdx].uartSignal);
            }
        }
    }
    
    /*!
    *
    *  \brief
    *  DebugLog printf output function.
    *
    *  \details
    *  Printing of specific string to CCS console output.
    *
    *  \param[in]  pContext      Call context
    *  \param[in]  pFormat       Format string.
    *  \param[in]  argptr        Parameter list.
    *
    *
    */
    void EI_APP_UART_LOG_printf(uint32_t uartIdx, void* pContext, const char* pFormat, va_list argptr)
    {
        OSALUNREF_PARM(pContext);
    
        // Use first UART instance for log buffer (or make this configurable)
    
        OSAL_MEMORY_memset(EI_APP_uart_s[uartIdx].aOutStream, 0, sizeof(EI_APP_uart_s[uartIdx].aOutStream));
        (void)vsnprintf(EI_APP_uart_s[uartIdx].aOutStream, sizeof(EI_APP_uart_s[uartIdx].aOutStream), pFormat, argptr);
    
       // DebugP_log(EI_APP_uart_s[uartIdx].aOutStream);
    }
    

  • Hi,

    I see that the read is being called from the RX Callback API itself, which is what the current UART driver does not support.

    It is recommended to call the READ API from the task context itself.

    Regards,

    Vaibhav