LAUNCHXL-CC26X2R1: Scheduling Simultaneous UART2 Instances

Part Number: LAUNCHXL-CC26X2R1
Other Parts Discussed in Thread: SYSCONFIG

Hi Folks,

I can't seem to communicate simultaneously with two UART devices attached to the native UART ports. The CC26X2R1 series features two native UART ports as well as the sensor controller which can be used a UART emulator. In my application, a 115200 and a 9600 bps device are mapped to the UART0 and UART1 through SysConfig. I send one way and call-response style messages periodically to both devices.

I suspect my simultaneous UART2 driver instances are causing problems because of the significant difference in baud rate. HWI generated by full RX buffers to execute callbacks likely interrupts the behavior of the other UART2 instance.

  • A 70 byte long RX received at 115200 bps takes (560 [bits]/11500 [bits/sec]) 4.8611 milliseconds under ideal conditions.
    • TX (One Way) every 20 ms
    • TX (Call/Response) every 50ms
  • A 20 byte long RX received at 9600 bps takes (160 [bits]/9600 [bits/sec])  16.667 milliseconds under ideal conditions.
    • TX (One Way) every 200ms
    • TX (Call/Response) every 100ms

When only clocks associated with UART0 are running, the behavior of UART0 is as expected.

[Cortex_M4_0] 
Host Display Initialized
Tasks Initializing: 

SERIAL: UART0 Initialized Successfully
SERIAL: UART1 Initialized Successfully

UART0: TX - Request
UART0: RX - Processing Callback Executed!
UART0: PASS Packet (70) Length Received (70)
UART0: PASS Packet Termination
UART0: Completed RX Parsing

UART0: TX - Request
UART0: RX - Processing Callback Executed!
UART0: PASS Packet (70) Length Received (70)
UART0: PASS Packet Termination
UART0: Completed RX Parsing

When only clocks associated with UART1 are running, the behavior of UART1 is as expected.

[Cortex_M4_0] 
Host Display Initialized
Tasks Initializing: 

SERIAL: UART0 Initialized Successfully
SERIAL: UART1 Initialized Successfully

UART1: TX - Request 0x08
UART1: RX - Processing Callback Executed!
UART1: Completed RX Parsing

UART1: TX - Request 0x09
UART1: RX - Processing Callback Executed!
UART1: Completed RX Parsing

When scheduling clocks associated with both UART0 and UART1, the one or both peripherals stops receiving or transmitting correctly. Here, UART0 is unable to handle RX correctly and UART1 is unaffected.

[Cortex_M4_0] 
Host Display Initialized
Tasks Initializing: 

SERIAL: UART0 Initialized Successfully
SERIAL: UART1 Initialized Successfully

UART0: TX - Request
UART0: RX - Processing Callback Executed!
UART0: PASS Packet (70) Length Received (70)
UART0: PASS Packet Termination
UART0: Completed RX Parsing

UART0: TX - Request

UART1: TX - Request 0x08
UART1: RX - Processing Callback Executed!
UART1: Completed RX Parsing

UART0: TX - Request
UART0: RX - Processing Callback Executed!
UART0: PASS Packet (70) Length Received (70)
UART0: FAIL Packet Termination

UART0: TX - Request

UART1: TX - Request 0x09
UART1: RX - Processing Callback Executed!
UART1: Completed RX Parsing

Ultimately, it could be a driver limitation or flawed RTOS Task Design. Either way, I would appreciate a second set of eyes - I would like to share my project code privately for some help. 

Thanks,

Ken

  • Ken,

    Can you share your UART2 setup code and RTOS task configuration?

    It might also be useful to use the TI-RTOS execution graph (see Task 2 - Debugging tools in the TI-RTOS SimpleLink Academy lab for more information). This might help determine if your UART tasks are interfering with each other.

    When UART0 fails, are you able to see the status returned by UART2_read() or UART2_write()?

    Regards,

    Daniel

  • Hi Daniel,

    Thank you for the advice! Regarding the status of the UART2_read/write(), the "UARTX - Processing Callback Executed!" is associated with UART2 success, so no errors are posted by the driver because a separate message is printed when such an error occurs.

    I setup the project for execution analysis by (1) opening CFG and setting the SYS/BIOS to fully instrumented, (2) Commented out the ROM so that execution is performed from flash, and (3) added logging configuration at the bottom of the same CFG.

    I realized I did not have UIA installed. I grabbed "uia_2_30_01_02.zip" from here and unpacked it to C:/ti and installed it within CCS10.3.0. I debugged the project after restarting CCS and clean building the project. I opened Execution Analysis from Tools → RTOS Analyzer → Execution Analysis, reviewed the following information before hitting Start

    I captured the following Execution Analysis alongside the behavior with a breakpoint at the events = Event_Pend starting the motor_task:

    [Cortex_M4_0]
    Host Display Initialized
    Tasks Initializing: 
    
    SERIAL: UART0 Initialized Successfully
    SERIAL: UART1 Initialized Successfully
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x08
    UART1: RX - Processing Callback Executed!
    UART1: Completed RX Parsing
    
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x09
    UART1: RX - Processing Callback Executed!
    UART1: Completed RX Parsing
    
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x0a
    UART1: RX - Processing Callback Executed!
    UART1: Completed RX Parsing
    
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x0a
    UART1: RX - Processing Callback Executed!
    UART1: Completed RX Parsing
    
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x0d
    UART1: RX - Processing Callback Executed!
    UART1: Completed RX Parsing
    
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x0e
    UART1: RX - Processing Callback Executed!
    UART1: Completed RX Parsing
    
    UART0: TX - Request
    UART0: TX - Request
    UART0: RX - Processing Callback Executed!
    UART0: PASS Packet (65) Length Received (65)
    UART0: FAIL Packet Termination
    
    UART1: TX - Request 0x0f

    If you ask me, the HWI looks pretty suspicious. I was under the impression that the HWIs should be fairly short lived - these seem somewhat long. While a DMA transfer for 70 bytes for UART0 takes up to 385us to handle, perhaps the HWI from the second RX from UART1 interrupts the transfer. But I also can't claim that I can interpret this information to a professional level.


    I am attaching the exported UIA logs for anyone and everyone to explore.

    EA_29042021_Serial_Peripheral.csv

    I would love to share the code, but I would prefer to do so via DM/email ().


    Best,
    Ken

  • Hi Ken,

    Thank you for your patience and the data you provided, I was able to setup a simple project with to communicate simultaneously with two UART devices attached to the native UART ports with different baudrates, and verify the data for both ports without seeing the same issue as you. This makes more inclined to believe that the issue could as a result of the Uart2 initialization and or sysconfig setup, or something else in your source code interfering with the UART2 tasks. I’d suggest first setting up a simple 2 Uart2 callback project and verifying first if you can simultaneously communicate with the 2 UART2 devices on the same and then different baudrates. And if that seems successful on you end, slowly integrate the rest of your code into the project.

    Best,

    Tariq

  • Hi Tariuq,

    I actually started with the UART2 callback project. You are probably correct that it is it my task code that is at fault rather than the SysConfig or UART2 Initialization. This is a one-time-download link to a ZIP archive of the relevant project source.

    From an RTOS design perspective, does it make sense to designate a task to handle Serial RX/TX when UART2 features integrated ring buffers?

    Best,

    Ken

  • Hi Ken,

    I’d say it depends on the project details, for instance if low latency was a high priority, it be good to have a task setup to read and process the data; however, if not the case, like you have mentioned it would also be trivial to check the buffer data during another task’s execution and process then. Furthermore, the amount of data needed could be another factor pushing it to the 2nd option to avoid spontaneous/random events and look over and average. I am more inclined to prefer the not having a designated task since it could come off as redundant since the data will probably be processed in another task, but that also depends on the use case for it. I hope this perspective helps you come to a conclusion.

    Best,

    Tariq

  • Hi Tariq,

    Would you be open to sharing the source you used for a 2x UART2 callback project? If there is another approach for implementing simultaneous UART2 connections, I would love to see it.

    I have developed three solutions with mixed results:

    1. Serial Thread (UART0 and Sensor Controller Emulator) with Scheduling Thread (worked, but SC adds project complexity)
    2. Separate Threads for the UART0 and UART1 peripherals (worked independently, but not simultaneously).
    3. Serial Thread (UART0 and UART1) with Scheduling Thread (works simultaneously, but RX is non-functional).

    Reproduced below is my Serial Thread which uses an event structure and callbacks to rescheduled RX events after a RX is posted and externally visible serial write functions to handle TX buffering.

    Best,

    Ken


    /*
     *  ===========================================================================
     *  Preprocessor Includes
     *  ===========================================================================
     */
    
        // Texas Instruments
        #include <ti/sysbios/knl/Task.h>
        #include <ti/sysbios/knl/Event.h>
        #include <xdc/runtime/Error.h>
    
        /* Driver configuration */
        #include "ti_drivers_config.h"
        #include <ti/drivers/UART2.h>
    
        // Display Configuration
        #include <ti/display/Display.h>
        extern Display_Handle dispHost;
    
        // Bluetooth Stack
        #include <icall.h>
        #include "util.h"
    
        // Standard C Libraries
        #include <stdint.h>
        #include <string.h>
        #include <stdio.h>
    
        // Additional Project Source
        #include "serial_thread.h"
        #include "RingBuffer.h"
        #include "../Thread_Motor/UART_Protcol1.h"
        #include "../Thread_Motor/UART_Protocol2.h"
    
    /*
     *  ===========================================================================
     *  Function Prototypes
     *  ===========================================================================
     */
    
        // RTOS Task
        void serialTaskFxn(UArg a0, UArg a1);
    
        // UART Initialization Functions
        static void UART_0_init();
        static void UART_1_init();
    
        // UART0 Callback Handlers
        static void callbackFxn_readUART0(UART2_Handle, void*, size_t, void*, int_fast16_t);
        static void callbackFxn_writeUART0(UART2_Handle, void*, size_t, void*, int_fast16_t);
        static void eventHandler_UART0_TX();
    
        // UART1 Callback Handlers
        static void callbackFxn_readUART1(UART2_Handle, void*, size_t, void*, int_fast16_t);
        static void callbackFxn_writeUART1(UART2_Handle, void*, size_t, void*, int_fast16_t);
        static void eventHandler_UART1_TX();
    
    /*
     *  ===========================================================================
     *  Internal Variables and Definitions
     *  ===========================================================================
     */
    
        // Error Blocks
        static Event_Handle syncEvent;
        static Error_Block eb;
    
        // Serial Task Events
        #define COM0_TX_EVT                            Event_Id_01
        #define COM0_RX_EVT                            Event_Id_02
        #define COM1_TX_EVT                            Event_Id_03
        #define COM1_RX_EVT                            Event_Id_04
    
        #define SERIAL_ALL_EVENTS                      (COM0_TX_EVT                    | \
                                                        COM0_RX_EVT                    | \
                                                        COM1_TX_EVT                    | \
                                                        COM1_RX_EVT)
    
        // State Tracking
        static uint8_t serial_thread_ready = 0;
        static uint8_t COM0_TX_busy = 0;
        static uint8_t COM1_TX_busy = 0;
    
    /*
     *  ===========================================================================
     *  UART COM 0 Configuration
     *  ===========================================================================
     */
        // Variables for COM Port
        static UART2_Handle    COM_0;
        static UART2_Params    COM_0_Params;
        static volatile size_t COM_0_BytesRead;
        static int_fast16_t    COM_0_Status = UART2_STATUS_SUCCESS;
    
        // Variables for Buffer
        static RingBuffer_t COM0_TX_Buffer;            // Buffer TX Structure
        static uint8_t      COM0_TX_Buffer_Data[256];  // Buffer TX Storage Array
    
        // Read Buffers
        static uint8_t  RX_COM0 [70];
    
    /*
     *  ===========================================================================
     *  UART COM 1 Configuration
     *  ===========================================================================
     */
    
        // Variables for COM Port
        static UART2_Handle    COM_1;
        static UART2_Params    COM_1_Params;
        static volatile size_t COM_1_BytesRead;
        static int_fast16_t    COM_1_Status = UART2_STATUS_SUCCESS;
    
        // Variables for Buffer
        static RingBuffer_t COM1_TX_Buffer;            // Buffer TX Structure
        static uint8_t      COM1_TX_Buffer_Data[256];  // Buffer TX Storage Array
    
        // Read Buffers
        static uint8_t RX_COM1[32]; // Buffer where read bytes are stored.
    
    /*
     *  ===========================================================================
     *  RTOS Task Initialization
     *  ===========================================================================
     */
    
        // Task configuration
        Task_Struct serialTask;
        #define SERIAL_TASK_PRIORITY    2
        #define SERIAL_TASK_STACK_SIZE  1024
    
        #if defined __TI_COMPILER_VERSION__
            #pragma DATA_ALIGN(serialTaskStack, 8)
        #else
            #pragma data_alignment=8
        #endif
        uint8_t serialTaskStack[SERIAL_TASK_STACK_SIZE];
    
        void serial_createTask(void) {
            Task_Params taskParames;
    
            // Create the task for the state machine
            Task_Params_init(&taskParames);
            taskParames.stack = serialTaskStack;
            taskParames.stackSize = SERIAL_TASK_STACK_SIZE;
            taskParames.priority = SERIAL_TASK_PRIORITY;
    
            Task_construct(&serialTask, serialTaskFxn, &taskParames, NULL);
        }
    
    /*
     *  ===========================================================================
     *  Serial Task Processing
     *  ===========================================================================
     */
    
        void serialTaskFxn(UArg a0, UArg a1) {
            Error_init(&eb);
            /* Default instance configuration params */
            syncEvent = Event_create(NULL, &eb);
    
            // Prepare Buffers
            RingBuffer_InitBuffer(&COM0_TX_Buffer, COM0_TX_Buffer_Data, sizeof(COM0_TX_Buffer_Data));
            RingBuffer_InitBuffer(&COM1_TX_Buffer, COM1_TX_Buffer_Data, sizeof(COM1_TX_Buffer_Data));
    
            // Initialize UART COMs
            UART_0_init();
            UART_1_init();
    
            // First Event Posted is always RX
            uint32_t events = 0;
            Event_post(syncEvent, COM0_RX_EVT);
            Event_post(syncEvent, COM1_RX_EVT);
            
            // Serial Is Initialized
            serial_thread_ready = 1;
    
            while(1) {
                // Waits for an event to be posted associated with the calling thread.
                // Note that an event associated with a thread is posted when a
                // message is queued to the message receive queue of the thread
                events = Event_pend(syncEvent, Event_Id_NONE, SERIAL_ALL_EVENTS, ICALL_TIMEOUT_FOREVER);
    
                if (events & COM0_RX_EVT) {
                    // Clear FIFO Buffer
                    UART2_flushRx(COM_0);
                    memset(RX_COM0, 0x00, sizeof(RX_COM0));
                    // Read Data
                    COM_0_Status = UART2_read(COM_0, RX_COM0, 70, NULL);
                }
    
                if (events & COM1_RX_EVT) {
                    // Clear FIFO Buffer
                    UART2_flushRx(COM_1);
                    memset(RX_COM1, 0x00, sizeof(RX_COM1));
                    // Read Data
                    COM_1_Status = UART2_read(COM_1, RX_COM1, 32, NULL);
                }
    
                if (events & COM0_TX_EVT) {
                    // Send Data
                    eventHandler_UART0_TX();
                }
    
                if (events & COM1_TX_EVT) {
                    // Send Data
                    eventHandler_UART1_TX();
                }
    
                events = 0;
            }
        }
    
    /*
     *  ===========================================================================
     *  Serial Functions
     *  ===========================================================================
     */
    
        bool serial_write(uint8_t port, uint8_t* buffer, uint8_t size) {
            bool returnValue;
    
            if(serial_thread_ready == 0) {
                Display_printf(dispHost, 0, 0, "SERIAL: Task is not Ready");
                returnValue = false;
            } else{
                if (port == COM0_Dev){
                    if(RingBuffer_GetFreeCount(&COM0_TX_Buffer) >= size) {
                        for(uint8_t i = 0; i < size; i++) {
                            if(!RingBuffer_IsFull(&COM0_TX_Buffer)) {
                                RingBuffer_Insert(&COM0_TX_Buffer, buffer[i]);
                            }
                        }
                        if(COM0_TX_busy == 0) {
                            Event_post(syncEvent, COM0_TX_EVT);
                        }
                        returnValue = true;
                    }
                    else {
                        returnValue = false;
                    }
                } else if (port == COM1_Dev){
                    if(RingBuffer_GetFreeCount(&COM1_TX_Buffer) >= size) {
                        for(uint8_t i = 0; i < size; i++) {
                            if(!RingBuffer_IsFull(&COM1_TX_Buffer)) {
                                RingBuffer_Insert(&COM1_TX_Buffer, buffer[i]);
                            }
                        }
                        if(COM1_TX_busy == 0) {
                            Event_post(syncEvent, COM1_TX_EVT);
                        }
                        returnValue = true;
                    }
                    else {
                        returnValue = false;
                    }
                } else {
                    returnValue = false;
                }
            }
    
            return returnValue;
        }
    
    /*
     *  ===========================================================================
     *  UART Initialization Functions
     *  ===========================================================================
     */
    
        static void UART_0_init() {
    
            // Create a UART with data processing off.
            UART2_Params_init(&COM_0_Params);
            COM_0_Params.baudRate = 115200;
            COM_0_Params.dataLength = UART2_DataLen_8;
            COM_0_Params.stopBits = UART2_StopBits_1;
            COM_0_Params.parityType = UART2_Parity_NONE;
            COM_0_Params.readMode = UART2_Mode_CALLBACK;
            COM_0_Params.readReturnMode = UART2_ReadReturnMode_FULL;
            COM_0_Params.writeMode = UART2_Mode_CALLBACK;
            COM_0_Params.readCallback = callbackFxn_readUART0;
            COM_0_Params.writeCallback = callbackFxn_writeUART0;
    
            // Open an instance of the UART driver
            COM_0 = UART2_open(UART2_DEV115200, &COM_0_Params);
    
            if (COM_0 == NULL) {
                 Display_printf(dispHost, 0, 0, "SERIAL: 115200 Device Failed to Initialize");
            } else {
                 Display_printf(dispHost, 0, 0, "SERIAL: 115200 Device Initialized Successfully");
            }
        }
    
        static void UART_1_init() {
    
            // Create a UART with data processing off.
            UART2_Params_init(&COM_1_Params);
            COM_1_Params.baudRate = 9600;
            COM_1_Params.dataLength = UART2_DataLen_8;
            COM_1_Params.stopBits = UART2_StopBits_1;
            COM_1_Params.parityType = UART2_Parity_NONE;
            COM_1_Params.readMode = UART2_Mode_CALLBACK;
            COM_1_Params.writeMode = UART2_Mode_CALLBACK;
            COM_1_Params.readCallback = callbackFxn_readUART1;
            COM_1_Params.writeCallback = callbackFxn_writeUART1;
    
            // Open an instance of the UART driver
            COM_1 = UART2_open(UART2_DEV9600, &COM_1_Params);
    
            if (COM_1 == NULL) {
                Display_printf(dispHost, 0, 0, "SERIAL: 9600 Device Failed to Initialize");
            } else {
                Display_printf(dispHost, 0, 0, "SERIAL: 9600 Device Initialized Successfully");
            }
        }
    
        
    /*
     *  ===========================================================================
     *  UART 0 Callback & Event Handler Functions
     *  ===========================================================================
     */
    
        static void callbackFxn_readUART0(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status){
            if (COM_0_Status == UART2_STATUS_SUCCESS) {
                Display_printf(dispHost, 0, 0, "115200: RX - Processing Callback Executed!");
                a115200_Packet_Validation(buffer,count);
            } else if (COM_0_Status == UART2_STATUS_ECANCELLED){
                Display_printf(dispHost, 0, 0, "115200: RX - Cancelled\n");
            } else {
                Display_printf(dispHost, 0, 0, "115200: RX - Error #%d\n",COM_0_Status);
            }
            Event_post(syncEvent, COM0_RX_EVT);
        }
    
        static void callbackFxn_writeUART0(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status) {
            Event_post(syncEvent, COM0_TX_EVT);
        }
    
        static void eventHandler_UART0_TX() {
            uint8_t buffer[8];
            uint8_t i = 0;
    
            if(!RingBuffer_IsEmpty(&COM0_TX_Buffer) && COM_0 != NULL) {
                while(!RingBuffer_IsEmpty(&COM0_TX_Buffer) && (i < sizeof(buffer))) {
                    buffer[i++] = RingBuffer_Remove(&COM0_TX_Buffer);
                }
                COM_0_Status = UART2_write(COM_0, buffer, i, NULL);
                COM0_TX_busy = 1;
            }
            else {
                COM0_TX_busy = 0;
            }
        }
    
    /*
     *  ===========================================================================
     *  UART 1 Callback & Event Handler Functions
     *  ===========================================================================
     */
    
        static void callbackFxn_readUART1(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status){
            if (COM_1_Status == UART2_STATUS_SUCCESS) {
                Display_printf(dispHost, 0, 0, "9600: RX - Processing Callback Executed!");
                a9600_RX_Handler(buffer);
            } else if (COM_1_Status == UART2_STATUS_ECANCELLED){
                Display_printf(dispHost, 0, 0, "9600: RX - Cancelled\n");
            } else {
                Display_printf(dispHost, 0, 0, "9600: RX - Error #%d\n",COM_1_Status);
            }
            Event_post(syncEvent, COM1_RX_EVT);
        }
    
        static void callbackFxn_writeUART1(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status) {
            Event_post(syncEvent, COM1_TX_EVT);
        }
    
        static void eventHandler_UART1_TX() {
            uint8_t buffer[8];
            uint8_t i = 0;
    
            if(!RingBuffer_IsEmpty(&COM1_TX_Buffer) && COM_1 != NULL) {
                while(!RingBuffer_IsEmpty(&COM1_TX_Buffer) && (i < sizeof(buffer))) {
                    buffer[i++] = RingBuffer_Remove(&COM1_TX_Buffer);
                }
                COM_1_Status = UART2_write(COM_1, buffer, i, NULL);
                COM1_TX_busy = 1;
            }
            else {
                COM1_TX_busy = 0;
            }
        }
    

  • Hi Tariq,

    I had some time to allocate to this problem again, so I went back to my uart2callback project. Source below:

    /*
     * 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 ========
     */
    #include <stdint.h>
    #include <stddef.h>
    
    /* Driver Header files */
    #include <ti/drivers/UART2.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Event.h>
    #include <xdc/runtime/Error.h>
    
    /* Driver configuration */
    #include "ti_drivers_config.h"
    #include "util.h"
    #include <icall.h>
    
    // Display Configuration
    #include <ti/display/Display.h>
    Display_Handle dispHost;
    #include <string.h>
    
    /* Error Block for Events */
    static Event_Handle syncEvent;
    static Error_Block eb;
    
    /* Serial Event */
    #define COM0_TX_EVT                            Event_Id_01
    #define COM0_RX_EVT                            Event_Id_02
    #define COM0_Parse_EVT                         Event_Id_03
    #define COM1_TX_EVT                            Event_Id_04
    #define COM1_RX_EVT                            Event_Id_05
    #define COM1_Parse_EVT                         Event_Id_06
    
    #define SERIAL_ALL_EVENTS                      (COM0_TX_EVT                    | \
                                                    COM0_RX_EVT                    | \
                                                    COM0_Parse_EVT                 | \
                                                    COM1_TX_EVT                    | \
                                                    COM1_RX_EVT                    | \
                                                    COM1_Parse_EVT)
    
    /* UART2 COM0 */
    UART2_Handle           COM0;
    const  uint8_t         COM0_RX_Size = 70;
    static bool            COM0_RX_Pending = false;
    static volatile size_t COM0_BytesRead;
    static uint8_t         COM0_RX_Buffer[COM0_RX_Size];
    
    /* UART2 COM1 */
    UART2_Handle           COM1;
    const  uint8_t         COM1_RX_Size = 32;
    static bool            COM1_RX_Pending = false;
    static volatile size_t COM1_BytesRead;
    static uint8_t         COM1_RX_Buffer[COM1_RX_Size];
    
    /*
     *  ======== TX Clock =========
     */
    #define COM0_Start_Delay 00
    #define COM1_Start_Delay 00
    
    #define REQUEST_DATA_T   20
    static Clock_Struct clock_Request_COM0;
    static void clockhandler_COM0_requestData(UArg arg);
    static Clock_Struct clock_Request_COM1;
    static void clockhandler_COM1_requestData(UArg arg);
    
    /*
     *  ======== callbackFxn ========
     */
    void COM0_callbackFxn(UART2_Handle handle, void *buffer, size_t count,
            void *userArg, int_fast16_t status)
    {
        if (status == UART2_STATUS_SUCCESS) {
            //Display_printf(dispHost, 0, 0, "COM0: RX - Callback Success!");
        } else {
            Display_printf(dispHost, 0, 0, "COM0: RX - Error #%d\n",status);
        }
    
        COM0_BytesRead = count;
        UART2_flushRx(COM0);
    
        Event_post(syncEvent, COM0_Parse_EVT);
        Event_post(syncEvent, COM0_RX_EVT);
        COM0_RX_Pending = false;
    }
    
    void COM1_callbackFxn(UART2_Handle handle, void *buffer, size_t count,
            void *userArg, int_fast16_t status)
    {
        if (status == UART2_STATUS_SUCCESS) {
            //Display_printf(dispHost, 0, 0, "COM0: RX - Callback Success!");
        } else {
            Display_printf(dispHost, 0, 0, "COM0: RX - Error #%d\n",status);
        }
    
        COM1_BytesRead = count;
        UART2_flushRx(COM1);
    
        Event_post(syncEvent, COM1_Parse_EVT);
        Event_post(syncEvent, COM1_RX_EVT);
        COM0_RX_Pending = false;
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        /* Initialize Display */
        Display_init();
        dispHost = Display_open(Display_Type_HOST, NULL);
        Display_printf(dispHost, 0, 0, "\nuart2callback Initialized:");
    
        /* Initialize COM0 */
        UART2_Params      COM0Params;
        uint32_t          COM0_status = UART2_STATUS_SUCCESS;
        UART2_Params_init(&COM0Params);
        COM0Params.readMode = UART2_Mode_CALLBACK;
        COM0Params.readCallback = COM0_callbackFxn;
        COM0Params.baudRate = 115200;
        COM0 = UART2_open(CONFIG_UART2_0, &COM0Params);   // Set "CONFIG_UART2_1" in SysConfig
        //UART2_flushRx(COM0);
        if (COM0 == NULL) {
            Display_printf(dispHost, 0, 0, "COM0: FAILED TO OPEN");
            while (1);
        } else {
            Display_printf(dispHost, 0, 0, "COM0: Opened Successfully");
        }
    
        /* Initialize COM0 */
        UART2_Params      COM1Params;
        uint32_t          COM1_status = UART2_STATUS_SUCCESS;
        UART2_Params_init(&COM1Params);
        COM1Params.readMode = UART2_Mode_CALLBACK;
        COM1Params.readCallback = COM1_callbackFxn;
        COM1Params.baudRate = 9600;
        COM1 = UART2_open(CONFIG_UART2_1, &COM1Params);  // Set "CONFIG_UART2_1" in SysConfig
        //UART2_flushRx(COM1);
        if (COM1 == NULL) {
            Display_printf(dispHost, 0, 0, "COM1: FAILED TO OPEN");
            while (1);
        } else {
            Display_printf(dispHost, 0, 0, "COM1: Opened Successfully");
        }
    
        /* Create Event */
        Error_init(&eb);
        syncEvent = Event_create(NULL, &eb);
    
        uint32_t events = 0;
        Event_post(syncEvent, COM0_RX_EVT);
        Event_post(syncEvent, COM1_RX_EVT);
    
    
        /* Schedule TX Messages to devices */
        Util_constructClock(&clock_Request_COM0, clockhandler_COM0_requestData, COM0_Start_Delay, REQUEST_DATA_T, true,  NULL);
        Util_constructClock(&clock_Request_COM1, clockhandler_COM1_requestData, COM1_Start_Delay, REQUEST_DATA_T, true,  NULL);
    
        uint32_t Total_Execs = 0;
        uint32_t Max_Execs = 250; //65536
        uint16_t COM0_Ratio[2] = {0};
        uint16_t COM1_Ratio[2] = {0};
    
        while (1) {
    
            // Waits for an event to be posted associated with the calling thread.
            // Note that an event associated with a thread is posted when a
            // message is queued to the message receive queue of the thread
            events = Event_pend(syncEvent, Event_Id_NONE, SERIAL_ALL_EVENTS, ICALL_TIMEOUT_FOREVER);
    
            if (events & COM0_Parse_EVT){
                // Increment Total Processed
                COM0_Ratio[1]++;
                // Check Expected Reply
                uint8_t       COM0_CorrectBytes = 0;
                if (COM0_RX_Buffer[0]  == 0x01){ // Check Start Byte
                    COM0_CorrectBytes++;
                }
                if (COM0_RX_Buffer[69] == 0x02){ // Check End Byte
                    COM0_CorrectBytes++;
                }
    
                if (COM0_CorrectBytes == 2){
                    COM0_Ratio[0]++;
                }
    
                COM0_RX_Pending = false;
            }
    
            if (events & COM1_Parse_EVT){
                // Increment Total Processed
                COM1_Ratio[1]++;
                // Check Expected Reply
                const uint8_t COM1_CorrectReply[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x8,0x09};
                uint8_t       COM1_CorrectBytes = 0;
                uint8_t loop;
                for (loop = 0; loop < COM1_BytesRead+1; loop++){
                    if (COM1_RX_Buffer[loop] == COM1_CorrectReply[loop]){
                        COM1_CorrectBytes++;
                    }
                }
    
                if (COM1_CorrectBytes == 9){
                    COM1_Ratio[0]++;
                }
    
                COM1_RX_Pending = false;
            }
    
            if (events & COM0_RX_EVT){
                //Display_printf(dispHost, 0, 0, "COM0: RX - Start Read!");
                /* Pass NULL for bytesRead since it's not used in this example */
                COM0_status = UART2_read(COM0, &COM0_RX_Buffer, COM0_RX_Size, NULL);
    
                if (COM0_status != UART2_STATUS_SUCCESS) {
                    Display_printf(dispHost, 0, 0, "COM0: RX - Error #%d\n",COM0_status);
                    while (1);
                }
            }
    
            if (events & COM1_RX_EVT){
                //Display_printf(dispHost, 0, 0, "COM1: RX - Start Read!");
                /* Pass NULL for bytesRead since it's not used in this example */
                COM1_status = UART2_read(COM1, &COM1_RX_Buffer, COM1_RX_Size, NULL);
    
                if (COM1_status != UART2_STATUS_SUCCESS) {
                    Display_printf(dispHost, 0, 0, "COM1: RX - Error #%d\n",COM1_status);
                    while (1);
                }
            }
    
            if (events & COM0_TX_EVT){
                //Display_printf(dispHost, 0, 0, "COM0: TX - Send Command!");
                const char        UART0Prompt[] = {0x01,0x02,0x03,0x04,0x05,0x06};
                UART2_write(COM0, UART0Prompt, sizeof(UART0Prompt), NULL);
                COM0_RX_Pending = true;
            }
    
            if (events & COM1_TX_EVT){
                //Display_printf(dispHost, 0, 0, "COM1: TX - Send Command!");
                const char        UART1Prompt[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};
                UART2_write(COM1, UART1Prompt, sizeof(UART1Prompt), NULL);
                COM1_RX_Pending = true;
            }
    
            if ((COM1_Ratio[1] == Max_Execs) || (COM0_Ratio[1] == Max_Execs)){
                Display_printf(dispHost, 0, 0, "COM0 Start Delay: %d\nCOM1 Start Delay: %d",COM0_Start_Delay,COM1_Start_Delay);
                Display_printf(dispHost, 0, 0, "COM0: RX(%02u) - Success/Total [%u/%u]",COM0_BytesRead,COM0_Ratio[0],COM0_Ratio[1]);
                Display_printf(dispHost, 0, 0, "COM1: RX(%02u) - Success/Total [%u/%u]",COM1_BytesRead,COM1_Ratio[0],COM1_Ratio[1]);
                while(1);
            }
            Total_Execs++;
    
        }
    }
    
    static void clockhandler_COM0_requestData(UArg arg) {
        if (!COM0_RX_Pending){
            Event_post(syncEvent, COM0_TX_EVT);
        }
    }
    
    static void clockhandler_COM1_requestData(UArg arg) {
        if (!COM1_RX_Pending){
            Event_post(syncEvent, COM1_TX_EVT);
        }
    }
    

    This code runs for until one of the two UART coms reaches the number of communications prescribed by "Max_Execs."

    I originally observed that when the start delay for the TX clocks was equal, one of the UART COMs would not parse any data. Only by adding a 20ms offset to the start time of the second UART COM did both UART COMs return successfully. This problem seems to happen every once in a while, but not consistently. See below:

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 0
    COM0: RX(70) - Success/Total [250/250]
    COM1: RX(09) - Success/Total [0/0]

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 0
    COM0: RX(70) - Success/Total [250/250]
    COM1: RX(09) - Success/Total [125/125]

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 20
    COM0: RX(70) - Success/Total [250/250]
    COM1: RX(09) - Success/Total [125/125]

    So my question really should have been,

    1. If two clocks are created one after another with zero delay and instant start with equal periods, will the interrupts cause deleterious collisions?
    2. What kind of offset or modification to my clock method should be applied to prevent the clocks from triggering in a way that causes deleterious collisions?

    Best,

    Ken

  • Hi Ken,

    Yes, I don't mind, I used the uart2callback project and made another copy of the uart thread for the different baudrate, my goal was just to verify communication with 2 UARTs at different baudrates so I did not make any more changes than necessary to run the project. From your list, this version would be the 2nd implementation, separate threads for the UART0 and UART1 peripherals. And just to clear any misunderstandings, can you clarify independently vs simultaneously. I have attached the source code I was using below:

    main_tirtos.c

    /*
     * Copyright (c) 2016-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.
     */
    
    /*
     *  ======== main_tirtos.c ========
     */
    #include <stdint.h>
    
    /* POSIX Header files */
    #include <pthread.h>
    
    /* RTOS header files */
    #include <ti/sysbios/BIOS.h>
    
    #include <ti/drivers/Board.h>
    
    extern void *mainThread(void *arg0);
    extern void *mainThread2(void *arg0);
    
    /* Stack size in bytes */
    #define THREADSTACKSIZE    1024
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        pthread_t           thread;
        pthread_attr_t      attrs;
        struct sched_param  priParam;
        int                 retc;
    
        Board_init();
    
        /* Initialize the attributes structure with default values */
        pthread_attr_init(&attrs);
    
        /* Set priority, detach state, and stack size attributes */
        priParam.sched_priority = 1;
        retc = pthread_attr_setschedparam(&attrs, &priParam);
        retc |= pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
        retc |= pthread_attr_setstacksize(&attrs, THREADSTACKSIZE);
        if (retc != 0) {
            /* failed to set attributes */
            while (1) {}
        }
    
        retc = pthread_create(&thread, &attrs, mainThread, NULL);
        if (retc != 0) {
            /* pthread_create() failed */
            while (1) {}
        }
    
    
    
        pthread_t           thread2;
        pthread_attr_t      attrs2;
        struct sched_param  priParam2;
        int                 retc2;
    
        /* Initialize the attributes structure with default values */
        pthread_attr_init(&attrs2);
    
        /* Set priority, detach state, and stack size attributes */
        priParam2.sched_priority = 1;
        retc2 = pthread_attr_setschedparam(&attrs2, &priParam2);
        retc2 |= pthread_attr_setdetachstate(&attrs2, PTHREAD_CREATE_DETACHED);
        retc2 |= pthread_attr_setstacksize(&attrs2, THREADSTACKSIZE);
    
        if (retc2 != 0) {
            /* failed to set attributes */
            while (1) {}
        }
    
        retc2 = pthread_create(&thread2, &attrs2, mainThread2, NULL);
        if (retc2 != 0) {
            /* pthread_create() failed */
            while (1) {}
        }
    
    
        BIOS_start();
    
        return (0);
    }
    

    uart2callback.c

    /*
     * 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 ========
     */
    #include <stdint.h>
    #include <stddef.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"
    
    static sem_t sem;
    static volatile size_t numBytesRead;
    
    /*
     *  ======== 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;
        sem_post(&sem);
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        char              input;
        const char        echoPrompt[] = "Echoing characters:\r\n";
        UART2_Handle      uart;
        UART2_Params      uartParams;
        int32_t           semStatus;
        uint32_t          status = UART2_STATUS_SUCCESS;
    
        /* Call driver init functions */
        GPIO_init();
    
        /* Configure the LED pin */
        GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* Create semaphore */
        semStatus = sem_init(&sem, 0, 0);
    
        if (semStatus != 0) {
            /* Error creating semaphore */
            while (1);
        }
    
        /* 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);
    
        /* Loop forever echoing */
        while (1) {
            numBytesRead = 0;
    
            /* Pass NULL for bytesRead since it's not used in this example */
            status = UART2_read(uart, &input, 1, NULL);
    
            if (status != UART2_STATUS_SUCCESS) {
                /* UART2_read() failed */
                while (1);
            }
    
            /* Do not write until read callback executes */
            sem_wait(&sem);
    
            if (numBytesRead > 0) {
                status = UART2_write(uart, &input, 1, NULL);
    
                if (status != UART2_STATUS_SUCCESS) {
                    /* UART2_write() failed */
                    while (1);
                }
            }
        }
    }
    

    uartcallback.c

    /*
     * 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 ========
     */
    #include <stdint.h>
    #include <stddef.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"
    
    static sem_t sem;
    static volatile size_t numBytesRead;
    
    /*
     *  ======== callbackFxn ========
     */
    void callbackFxn2(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;
        sem_post(&sem);
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread2(void *arg0)
    {
        char              input;
        const char        echoPrompt[] = "Uart 2: Echoing characters:\r\n";
        UART2_Handle      uart;
        UART2_Params      uartParams;
        int32_t           semStatus;
        uint32_t          status = UART2_STATUS_SUCCESS;
    
        /* Call driver init functions */
        GPIO_init();
    
        /* Configure the LED pin */
        GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* Create semaphore */
        semStatus = sem_init(&sem, 0, 0);
    
        if (semStatus != 0) {
            /* Error creating semaphore */
            while (1);
        }
    
        /* Create a UART in CALLBACK read mode */
        UART2_Params_init(&uartParams);
        uartParams.readMode = UART2_Mode_CALLBACK;
        uartParams.readCallback = callbackFxn2;
        uartParams.baudRate = 9600;
    
        uart = UART2_open(CONFIG_UART2_1, &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);
    
        /* Loop forever echoing */
        while (1) {
            numBytesRead = 0;
    
            /* Pass NULL for bytesRead since it's not used in this example */
            status = UART2_read(uart, &input, 1, NULL);
    
            if (status != UART2_STATUS_SUCCESS) {
                /* UART2_read() failed */
                while (1);
            }
    
            /* Do not write until read callback executes */
            sem_wait(&sem);
    
            if (numBytesRead > 0) {
                status = UART2_write(uart, &input, 1, NULL);
    
                if (status != UART2_STATUS_SUCCESS) {
                    /* UART2_write() failed */
                    while (1);
                }
            }
        }
    }
    

    Best,

    Tariq

  • HI Tariq,

    Thank you for sharing! I suspect that there were additional errors in my code. By designing the thread to act as the serial interface, I pretty much gave up all the benefits of UART2 anyway. The simplest solution is usually the best place to start from. 

    A project wherein commenting out the TX clock (for a call/response UART message) for one UART COM would allow the other UART COM to work correctly as "Independently" working. 

    A project wherein all TX clocks (for a call/response UART message) for both UART COMs does not interfere with the operational behavior or performance as "Simultaneously" working.

    Below are the latest results of my test code. I have been unable to reproduce my previous error with different clock settings. If it emerges again, I can probably rule out the UART code.

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 0
    COM0: RX(70) - Success/Total [50000/50000]
    COM1: RX(09) - Success/Total [25000/25000]

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 5
    COM0: RX(70) - Success/Total [50000/50000]
    COM1: RX(09) - Success/Total [24999/24999]

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 10
    COM0: RX(70) - Success/Total [50000/50000]
    COM1: RX(09) - Success/Total [24999/24999]

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 15
    COM0: RX(70) - Success/Total [50000/50000]
    COM1: RX(09) - Success/Total [24999/24999]

    [Cortex_M4_0] 
    uart2callback Initialized:
    COM0: Opened Successfully
    COM1: Opened Successfully
    COM0 Start Delay: 0
    COM1 Start Delay: 20
    COM0: RX(70) - Success/Total [50000/50000]
    COM1: RX(09) - Success/Total [24999/24999]

    Best,

    Ken