LP-EM-CC2340R5: Can UART2_write and UART2_read not be used in the same Task?

Part Number: LP-EM-CC2340R5
Other Parts Discussed in Thread: CC2340R5

Tool/software:

Hi,

I have an application that receives UART data and needs to resume the task. After the data is processed, it needs to reply to the user about whether the data is correct and then suspend the task. Why can't UART2_write and UART2_read be used together in the same task?

I have tried integrating the user_uart2callback example, but it seems not to work either.

full code

/*
 * Copyright (c) 2020, 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.
 */

/*
 *  ======== uart2callback.c ========
 */

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

/* For usleep() */
#include <unistd.h>

#include <stdint.h>
#include <stddef.h>
#include <string.h>
/* POSIX Header files */
#include <semaphore.h>

/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/UART2.h>

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

/* RTOS header files */
#include <FreeRTOS.h>
#include <task.h>
//#include <inc_task.h>
//INC_TASK_H

#define USER_STACK_SIZE  1024

#define UART_MAX_READ_SIZE 250

static sem_t sem;
static volatile size_t numBytesRead, UART_status = 0;


UART2_Handle uart;
UART2_Params uartParams;

TaskHandle_t user_xHandle;

pthread_mutex_t LEDBlink_mutex;//pthread_mutex_lock ,pthread_mutex_unlock

uint8_t uartReadBuffer[250] = {0};

void callbackFxn(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status);

void Open_UART_FUN()
{
    char input;
    const char echoPrompt[] = "Echoing characters:\r\n";

    uint32_t status = UART2_STATUS_SUCCESS;


    /* Create a UART in CALLBACK read mode */
    UART2_Params_init(&uartParams);

    uartParams.readMode     = UART2_Mode_CALLBACK;
    uartParams.readCallback = callbackFxn;
    uartParams.baudRate     = 115200;

    uart = UART2_open(CONFIG_UART2_0, &uartParams);

    if (uart == NULL)
    {
        /* UART2_open() failed */
        while (1) {}
    }

    /* Turn on user LED to indicate successful initialization */
    //GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);

    /* Pass NULL for bytesWritten since it's not used in this example */
    UART2_write(uart, echoPrompt, sizeof(echoPrompt), NULL);
    UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);


}

/*******************************************************************************
 */

/* Task to be created. */
void vTaskCode( void * pvParameters )
{
    /* The parameter value is expected to be 1 as 1 is passed in the
       pvParameters value in the call to xTaskCreate() below. */

    for( ;; )
    {
        /* Task code goes here. */
          GPIO_toggle(CONFIG_GPIO_LED_0);

//          UART2_write(uart, (char*)"OK\r\n", strlen("OK\r\n"), NULL);
          UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);

          vTaskSuspend(NULL);


    }
}

/* Function that creates a task. */
void vOtherFunction( void )
{
    BaseType_t xReturned;

    /* Configure the LED pin */
    GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    /* Turn on user LED to indicate successful initialization */
    GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);

    /* Create the task, storing the handle. */
    xReturned = xTaskCreate(
                    vTaskCode,       /* Function that implements the task. */
                    "user_app",          /* Text name for the task. */
                    USER_STACK_SIZE,      /* Stack size in words, not bytes. */
                    ( void * ) 1,    /* Parameter passed into the task. */
                    tskIDLE_PRIORITY,/* Priority at which the task is created. */
                    &user_xHandle );      /* Used to pass out the created task's handle. */
}

/*
 *  ======== callbackFxn ========
 */
void callbackFxn(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status)
{
    if (status != UART2_STATUS_SUCCESS)
    {
        /* RX error occured in UART2_read() */
        while (1) {}
    }

    numBytesRead = count;

   //thread_mutex_lock(&LEDBlink_mutex);
    UART_status = 1;
    //hread_mutex_unlock(&LEDBlink_mutex);

    memcpy(uartReadBuffer,buffer,numBytesRead);

    BaseType_t xYieldRequired; //xYieldRequired
    // Resume the suspended task.
    xYieldRequired = xTaskResumeFromISR(user_xHandle);

    // We should switch context so the ISR returns to a different task.
    // NOTE:  How this is done depends on the port you are using.  Check
    // the documentation and examples for your port.
    portYIELD_FROM_ISR(xYieldRequired);
}

UART2 LED success

void vTaskCode( void * pvParameters )
{
    /* The parameter value is expected to be 1 as 1 is passed in the
       pvParameters value in the call to xTaskCreate() below. */

    for( ;; )
    {
        /* Task code goes here. */
          GPIO_toggle(CONFIG_GPIO_LED_0);

//          UART2_write(uart, (char*)"OK\r\n", strlen("OK\r\n"), NULL);
          UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);

          vTaskSuspend(NULL);


    }
}

UART2  LED fail

void vTaskCode( void * pvParameters )
{
    /* The parameter value is expected to be 1 as 1 is passed in the
       pvParameters value in the call to xTaskCreate() below. */

    for( ;; )
    {
        /* Task code goes here. */
          GPIO_toggle(CONFIG_GPIO_LED_0);

          UART2_write(uart, (char*)"OK\r\n", strlen("OK\r\n"), NULL);
          UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);

          vTaskSuspend(NULL);


    }
}

  • Hello Anthony,

    Thanks for reaching out.

    What is exactly happening when UART2  LED fails? Does it just blink once? How have you configured the UART write mode?

    BR,

    David.

  • Hi  David,

    You are right; the LED only lights up once. I haven’t configured the UART write specifically. How should I set it up here?

    void Open_UART_FUN()
    {
        char input;
        const char echoPrompt[] = "Echoing characters:\r\n";
    
        uint32_t status = UART2_STATUS_SUCCESS;
    
    
        /* Create a UART in CALLBACK read mode */
        UART2_Params_init(&uartParams);
    
        uartParams.readMode     = UART2_Mode_CALLBACK;
        uartParams.readCallback = callbackFxn;
        uartParams.baudRate     = 115200;
    
        uart = UART2_open(CONFIG_UART2_0, &uartParams);
    
        if (uart == NULL)
        {
            /* UART2_open() failed */
            while (1) {}
        }
    
        /* Turn on user LED to indicate successful initialization */
        //GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
    
        /* Pass NULL for bytesWritten since it's not used in this example */
        UART2_write(uart, echoPrompt, sizeof(echoPrompt), NULL);
        UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);
    
    
    }

    Regards,
    Anthony

  • Hi  David,

    I referred to the information at e2e.ti.com/.../4684705 and modified the syscfg UART2 TX ring buffer size. I also added a few lines of code, which solved my issue.

        uartParams.readMode     = UART2_Mode_CALLBACK;
        uartParams.writeMode     = UART2_Mode_NONBLOCKING; // UART2_Mode_NONBLOCKING
        uartParams.readCallback = callbackFxn;
        uartParams.writeCallback = NULL;//NULL
    

     

    Regards,
    Anthony

  • Hello Anthony,

    Glad to hear it is working. Do you manage to write all the information then? What I would assume was happening is that the UART2 driver defaults to blocking mode if not configured otherwise. This last mode uses a semaphore to block while data is being sent to the TX pin. But then I would have expected is for it to hang before at the first write? Did that happened?

    BR,

    David.

  • Hi  David,

    Originally, I didn't set uartParams.writeMode. After many attempts, I later set writeMode to UART2_Mode_NONBLOCKING. I encountered issues with incomplete UART Tx transmission. After changing the default syscfg UART2 TX ring buffer size from 32 to 100, my Tx data was transmitted completely. I may not have fully understood the actual operation of using a semaphore to block. Here is my code; perhaps there are areas where I have concerns that we can discuss.

    /*
     * Copyright (c) 2020, 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.
     */
    
    /*
     *  ======== uart2callback.c ========
     */
    
    /* POSIX Header files */
    #include <pthread.h>
    
    /* For usleep() */
    #include <unistd.h>
    
    #include <stdint.h>
    #include <stddef.h>
    #include <string.h>
    /* POSIX Header files */
    #include <semaphore.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/UART2.h>
    
    /* Driver configuration */
    #include "ti_drivers_config.h"
    
    /* RTOS header files */
    #include <FreeRTOS.h>
    #include <task.h>
    //INC_TASK_H
    
    #define USER_STACK_SIZE  1024
    
    #define UART_MAX_READ_SIZE 250
    
    static sem_t sem;
    static volatile size_t numBytesRead;
    
    
    UART2_Handle uart;
    UART2_Params uartParams;
    
    TaskHandle_t user_xHandle;
    
    pthread_mutex_t LEDBlink_mutex;//pthread_mutex_lock ,pthread_mutex_unlock
    
    
    uint8_t uartReadBuffer[250] = {0};
    
    void callbackFxn(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status);
    
    
    void Open_UART_FUN()
    {
        char input;
        const char echoPrompt[] = "EMS BLE Peripheral start!!\r\n";
    
        uint32_t status = UART2_STATUS_SUCCESS;
    
    
        /* Create a UART in CALLBACK read mode */
        UART2_Params_init(&uartParams);
    
        uartParams.readMode     = UART2_Mode_CALLBACK;
        uartParams.writeMode     = UART2_Mode_NONBLOCKING; // UART2_Mode_NONBLOCKING
        uartParams.readCallback = callbackFxn;
        uartParams.writeCallback = NULL;//NULL
    
        uartParams.baudRate     = 115200;
    
        uart = UART2_open(CONFIG_DISPLAY_UART, &uartParams);
    
        if (uart == NULL)
        {
            /* UART2_open() failed */
            while (1) {}
        }
    
        /* Turn on user LED to indicate successful initialization */
        //GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
    
        /* Pass NULL for bytesWritten since it's not used in this example */
        UART2_write(uart, echoPrompt, sizeof(echoPrompt), NULL);
        UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);
    
    
    }
    
    /*******************************************************************************
     */
    
    /* Task to be created. */
    void vTaskCode( void * pvParameters )
    {
        /* The parameter value is expected to be 1 as 1 is passed in the
           pvParameters value in the call to xTaskCreate() below. */
    
        // Block for 500ms.
    //    const TickType_t xDelay = 20 / portTICK_PERIOD_MS;
    
        for( ;; )
        {
            /* Task code goes here. */
           if(strstr((char*)uartReadBuffer,(char*)"\r\n") != 0)
           {
               GPIO_toggle(CONFIG_GPIO_LED_RED);
               UART2_write(uart, (char*)uartReadBuffer, numBytesRead, NULL);
               UART2_write(uart, (char*)"OK\r\n", strlen("OK\r\n"), NULL);
           }
           else
           {
               UART2_write(uart, (char*)"fail_", strlen((char*)"fail_") , NULL);//fail_fjrifjrifjirfjrifjrijfrofjrofjrof
               UART2_write(uart, (char*)"OK\r\n", strlen("OK\r\n"), NULL);
           }
    
           memset(uartReadBuffer, 0, numBytesRead);
    
           UART2_read(uart, uartReadBuffer, UART_MAX_READ_SIZE, NULL);
    
    //       vTaskDelay( xDelay );
    
           vTaskSuspend(NULL);
        }
    }
    
    /* Function that creates a task. */
    void vOtherFunction( void )
    {
        BaseType_t xReturned;
    
        /* Configure the LED pin */
        GPIO_setConfig(CONFIG_GPIO_LED_RED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        /* Turn on user LED to indicate successful initialization */
        GPIO_write(CONFIG_GPIO_LED_RED, CONFIG_GPIO_LED_OFF);
    
        /* Create the task, storing the handle. */
        xReturned = xTaskCreate(
                        vTaskCode,       /* Function that implements the task. */
                        "user_app",          /* Text name for the task. */
                        USER_STACK_SIZE,      /* Stack size in words, not bytes. */
                        ( void * ) 1,    /* Parameter passed into the task. */
                        tskIDLE_PRIORITY,/* Priority at which the task is created. */
                        &user_xHandle );      /* Used to pass out the created task's handle. */
    
        vTaskSuspend(user_xHandle);
    }
    
    /*
     *  ======== callbackFxn ========
     */
    void callbackFxn(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status)
    {
        if (status != UART2_STATUS_SUCCESS)
        {
            /* RX error occured in UART2_read() */
            while (1) {}
        }
    
        numBytesRead = count;
    
    
        memcpy(&uartReadBuffer,buffer,numBytesRead);
    
        BaseType_t xYieldRequired; //xYieldRequired
        // Resume the suspended task.
        xYieldRequired = xTaskResumeFromISR(user_xHandle);
    
        // We should switch context so the ISR returns to a different task.
        // NOTE:  How this is done depends on the port you are using.  Check
        // the documentation and examples for your port.
        portYIELD_FROM_ISR(xYieldRequired);
    
    
    }
    


    Regards,
    Anthony

  • Hello Anthony,

    When using UART2_Mode_Nonblocking, the UART_write() function will copy as much data into the transmit buffer as space allows so that would explain why you needed to increase the buffer size. When you had the UART when it was set to blocking by default, if running in debug mode, where in the code would the program get stuck at?

    BR,

    David.

  • Hi  David,

    UART is set to blocking by default; the screenshot is as follows.


    If we go back to the original question about blocking mode, is there a correct way to use it? I can't get it to work no matter how I configure it. Perhaps you could provide an example for reference.

    Regards,
    Anthony

  • Hello Anthony,

    I will come up with an example and share it briefly.

    BR,

    David.

  • Hi  David,

    Thank you very much, this will be very helpful to me.

    Regards,
    Anthony

  • Hi David,

    I also encountered a similar problem, hope to continue to follow up

    My UART configuration is uartParams.readMode = UART2_Mode_CALLBACK; uartParams.readCallback = callbackFxn; write mode is the default mode

    My development environment version:

    SDK version : simplelink_lowpower_f3_sdk_7_40_00_64

    CCS version : 12.7.0.00007

    Example Project : basic_ble_LP_EM_CC2340R5_freertos_ticlang

    Regards,

    Ryan

  • Hello Ryan,

    Could you please provide more details about this issue? Does it get solved by modifying the UART write mode?

    BR,

    David.

  • Hi David,

    I have solved this problem

    thanks!

    Regard,

    Ryan

  • Hi  David,
    Thank you very much for your help. I really found the problem this time. I had set the task's priority too low, and by adding sem_post and sem_wait, it works great now.




    Tx blocking mode can be used.





    Regards,
    Anthony