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.

RTOS/TM4C1294NCPDT: Unable to read all 8 UARTs in TI-RTOS without dropping data

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: SYSBIOS, , ENERGIA

Tool/software: TI-RTOS

Hello,

I have tried multiple methods to be able to read all 8 UARTs using TI-RTOS but I can't get more than 3-4 at a time reading without dropping data. I would appreciate any suggestions to handle reading from all 8 UARTs using TI-RTOS (must be TI-RTOS).

Each UART receives 20-64 bytes of data at 19200 baud every 1 to 4 seconds. My goal is to be able to store each UART's data in a buffer until a terminating character is received to signify the end of the data packet, then the buffer is copied and used elsewhere.

I have tried the following with many variations:

1) Initially modified enet_s2e example which uses freeRTOS to use 8 UARTs. It works but due to USB/socket requirements TI-RTOS must be used.

2) Modified TI-RTOS example "uartecho" for multiple UARTs

a) One task per UART to read without callbacks

a1) Send character over queue to be aggregated by a separate task

a1) Copy characters into char[] buffer to be aggregated by a separate task

b) One task per UART to read with callback task

b1) In callback send character over queue to be aggregated by a separate task

b2) In callback copy characters into char[] buffer to be aggregated by a separate task

b3) Timers to call read

b4) Semaphores and buffers to minimize the time in the callback

Basically I have tried many methods and variations of options and the number of bytes read at a time and none gets close to all 8 reading with no missed data. Does anyone know of any method in TI-RTOS that can handle all 8 UARTs without issues? As far as scheduling we need to be able to run a few additional low priority tasks on the side like USB and sockets as well.

Thank you!

  • Hi,

    Could you attach a sample project? Are all the UARTs dropping data or only specific ones when you are trying to do 8 at once?

    Todd
  • Hello Todd,

    It appears that the UARTs initialized earlier in order have less issues with data corruption. When I only setup 1 to 3 UARTs all the data is received correctly. This works when using any combination of UARTs (ex: 1/2/3 or 2/5/6). When I setup more than 3 or 4 UARTs then characters start being dropped. At 8 UARTs setup only the first 5 setup will receive data and the last few will receive very little to none (UARTs 1-2 a few missed, 3-5 multiple missing characters, 6-8 very few characters received).

    I have also noticed when the tasks or callbacks run more code and take longer to execute that more data is dropped. After trying numerous methods I am currently trying to minimize the overhead of the read task and callback function. Not much difference (if any) is made when running the code in a project alone or with other tasks also running (ex: USB and Ethernet socket tasks).

    Below is an example of how I am currently setting up the UARTs in a loop and reading/processing the data. Hopefully you have some magic formula that works like "use callbacks and queues with XYZ set to ___". I feel I'm close!

    Thank you very much for your help!

    #define UART_READ_TASK_STACK_SIZE        1024
    #define MAX_NUM_RX_BYTES    8   // Maximum RX bytes to receive in one go
    
    // Structs and Stacks used in read task creation below Task_Struct uartReadTaskStruct[UART_COUNT]; Char uartReadTaskStack[UART_COUNT][UART_READ_TASK_STACK_SIZE];
    // UART params are the same except for callback function UART_Params UARTParams; UART_Params_init(&UARTParams); UARTParams.baudRate = UART_BAUD_RATE; // 19200 UARTParams.writeDataMode = UART_DATA_BINARY; UARTParams.readEcho = UART_ECHO_OFF; UARTParams.readMode = UART_MODE_CALLBACK; // sets up RX for callback mode UARTParams.readTimeout = 0; // don't wait to receive // Setup all UARTs and tasks to read them for (uartLoop = 0; uartLoop < UART_COUNT; uartLoop++) {

    // Callback function adds the port number to read callback task args UARTParams.readCallback = UARTRxCallbackFuncs[uartLoop]; UARTHandles[uartLoop] = UART_open(UARTsAvailable[uartLoop], &UARTParams); if (!UARTHandles[uartLoop]) { System_printf("UART%d did not open\n", uartLoop); // UARTs have always opened no issues } // Create tasks to periodically read UARTs taskParams.stackSize = UART_READ_TASK_STACK_SIZE; taskParams.priority = 3; taskParams.arg0 = uartLoop; taskParams.stack = &uartReadTaskStack[uartLoop]; Task_construct(&uartReadTaskStruct[uartLoop], (Task_FuncPtr)UARTReadTask, &taskParams, NULL); } // Callback function static void multipleByteReadCallback(UART_Handle handle, void *rxBuf, size_t size, uint8_t port) { //Copy rxBuf to txBuf memset(UARTRxBufCopy[port], 0, MAX_NUM_RX_BYTES); memcpy(UARTRxBufCopy[port], rxBuf, size); Semaphore_post(readSemaphore[port]); } // Read function static void UARTReadTask(UArg arg0, UArg arg1) { int port = (int) arg0; size_t charsReceivedSize; while (1) { UART_read(UARTHandles[port], UARTRxBuf[port], MAX_NUM_RX_BYTES); Semaphore_pend(readSemaphore[port], BIOS_WAIT_FOREVER); charsReceivedSize = strlen(UARTRxBufCopy[port]); // copy characters received to a partial data packet buffer // If end of data character is received, print data (or add to queue) Task_sleep(10); // Tried with and without sleep and various times, 5-25 appear to help } }

  • HI Select user name please,

    Have you configured M3 module or specific interrupt priorities for each UART? Does ROV indicate any kind of FIFO interrupt priority being assigned to each UART? How could we expect serial data would not be lost if the FIF0's are unconstrained or merely polled?

  • Hi User,

    You could also try looking at the CPU load to see if you have the cycles to process the data from 8 UARTs at that baud rate.
    Just add the following to your .cfg file:

    xdc.useModule('ti.uia.sysbios.LoggingSetup');

    Then use RTOS analyzer in CCS to look at the CPU load.

    Best regards,

    Janet

  • Hello Janet,

    I am currently traveling and unable to test the system. In general should CPU load be an issue at all when simply reading 8 UARTs?

    I understand that differences in code and settings may drastically change performance, but in general shouldn't the TM4C1294NCPDT have plenty of CPU to spare? Using an Arduino sketch I was able to get all 8 UARTs read perfectly and data stored in under 50 lines of code. We were also able to get it working with freeRTOS without any issues as well as run a full Ethernet web server.


    Thank you.

  • Hello BP101,

    I'm currently traveling and unable to test the system and look at ROV, but I'm pretty sure that UART_open creates a HWI (not sure about the priorities assigned). Recently I have been wondering if the issue is that trigger is using the default 7/8 full, where maybe 6/8 or 4/8 would be better.

    I have set the read task priority using the code "taskParams.priority = 3;" but that is it. Everything else (including RTOS settings) is the TI RTOS UART Echo example expanded to have 8 UARTs instead of one. I have tried using the same priority for all (sometimes combined with Task_yield) and also tried using different values without success. I'm trying to get a minimal code project that reads all 8 UARTs, but in the full project we intend to run the Ethernet and USB tasks at lower priorities than the UART tasks.

    Thank you.
  • Hi User,

    Since you have one task per UART, I was wondering if there was a lot of overhead due to Task switching.  That's why I thought looking at the CPU load might be useful.

    Best regards,

    Janet

  • Hello Janet,

    Thank you for the suggestion, having less tasks running made a big difference! I created a single read task and looped over each UART continuously. While looping over 6 UARTs about 90% of the characters are coming but it looks like from the data stream that the FIFO buffers are being overrun before being read.

    The 10% being misses result in partial packets being mixed with full packets like: <123456<1234567890> instead of <1234567890><1234567890>. About 10 packets come in fine, then a mixed up one. No apparent pattern to which UART it will be.

    The data is 64 characters sent every 4 seconds and the buffers are twice the size at 128 characters:

    unsigned char uartTivaRingBuffer[EK_TM4C1294XL_UARTCOUNT][128];
    
    /* UART configuration structure */
    const UARTTiva_HWAttrs uartTivaHWAttrs[EK_TM4C1294XL_UARTCOUNT] = {
    {
       .baseAddr = UART0_BASE,
       .intNum = INT_UART0,
       .intPriority = (~0),
       .flowControl = UART_FLOWCONTROL_NONE,
       .ringBufPtr  = uartTivaRingBuffer[EK_TM4C1294XL_UART0],
       .ringBufSize = sizeof(uartTivaRingBuffer[EK_TM4C1294XL_UART0])
    },
    {
       .baseAddr = UART1_BASE,
       .intNum = INT_UART1,
       .intPriority = (~0),
       .flowControl = UART_FLOWCONTROL_NONE,
       .ringBufPtr  = uartTivaRingBuffer[EK_TM4C1294XL_UART1],
       .ringBufSize = sizeof(uartTivaRingBuffer[EK_TM4C1294XL_UART1])
    },...

    I am using the following minimal code in a test project but still can't get the full data:

    UART_Params      UARTParams;
    UART_Params_init(&UARTParams);
    UARTParams.baudRate  = UART_BAUD_RATE;
    UARTParams.readReturnMode = UART_RETURN_NEWLINE;
    UARTParams.readEcho = UART_ECHO_OFF;
    
    static void UARTReadTask(UArg arg0, UArg arg1) {
        int port;
        int charsReceivedSize;
        uint8_t sizeLoop;
        char charReceived;
        while (1) {
            for (port = 0; port < UART_COUNT; port++) {
                if (!UARTsActivated[port]) {
                    continue;
                }
                charsReceivedSize = UART_read(UARTHandles[port], UARTRxBuf[port], MAX_NUM_RX_BYTES);
                for (sizeLoop=0; sizeLoop<charsReceivedSize; sizeLoop++) {
                    charReceived = ((char*)UARTRxBuf[port])[sizeLoop];
                    dataPacketRxBuffer[port][dataPacketRxBufferIndex[port]] = charReceived;
                    dataPacketRxBufferIndex[port] += 1;
                    if (charReceived == '>') {
                        System_printf("UART%d received %s\n", port, dataPacketRxBuffer[port]);
                        System_flush();
                        dataPacketRxBufferIndex[port] = 0;
                    }
                }
            }
        }
    }

    I tried getting the CPU logger working but couldn't get anything, even the Execution related items to work after looking at all the tips on the forums. I even tried with fresh examples from the Resource Explorer too and no luck. I guess I'm just used to using regular computers and Linux where things seem easier and to just work. These TI products seems to break at every opportunity.

    I appreciate your help and especially any help with some simple code as this seems like it should be trivially easy.

    Thank you.

  • I understand that TI-RTOS is much more complicated, but this is how easy it is with Arduino (how we prototyped on the TM4C1294NCPDT using Energia). TI just doesn't release the UART/USB/Ethernet drivers we needed to work with Arduino so we had to write it in C instead...

    char termChart = '>';
    char character;
    int baudRate = 19200;
    
    HardwareSerial *Serials[8] = {&Serial, &Serial1, &Serial2, &Serial3, &Serial4, &Serial5, &Serial6, &Serial7};
    String rxStrings[8];
    
    String completedRxString;
    String storedRxString = "";
    
    // Setup
    void setup() {
      Serial.begin(baudRate);
      Serial.println("Serial test begin");
      for (int i = 0; i < 8; i++) {
        rxStrings[i] = "";
        Serials[i]->begin(baudRate);
      }
    }
    
    void loop() {
      for (int i = 0; i < 8; i++) {
        while(Serials[i]->available()) {
          character = Serials[i]->read();
          rxStrings[i].concat(character);
          if (character == termChart) {
    //          Serial.print("Serial " + String(i) + ": ");
    //          Serial.println(rxStrings[i]);
              completedRxString = String(i)+":"+rxStrings[i]+";";
              storedRxString.concat(completedRxString);
              rxStrings[i] = "";
          }
        }
        if (storedRxString.length() > 2000) {
          Serial.println(storedRxString);
          storedRxString = "";
        }
      }
    }

  • Hi User,

    I think you could do something similar to what is done in the Arduino code, using just one task to read the UARTs.  There is a UART_control() command which you can use to check whether or not data is available on the uart.  Here is how I modified the uartecho example to use the UART_control() call:

        int         dataAvailable;

        ...

        /* Loop forever echoing */
        while (1) {
            if ((UART_control(uart, UART_CMD_ISAVAILABLE, &dataAvailable) == UART_STATUS_SUCCESS) &&
                        (dataAvailable != 0)) {
                UART_read(uart, &input, 1);
                UART_write(uart, &input, 1);
            }
        }

    There is also a UART_CMD_GETRXCOUNT control command that gives you the actual number of characters available to read.

    Best regards,

    Janet

  • Hello Janet,

    Your code worked better than any code so far, but still was only able to get 5 of the 8 UARTs working fine, with 6 dropping data sporadically.

    Our company has decided that TI-RTOS is not of sufficient quality and reliability so we are going with anything else. Basically everything but your hardware sucks: CCS, TI-cloud, TI-RTOS, drivers, licensing... So many things didn't work right.

    I have further suggested we ditch TI's hardware completely as there are plenty of better alternatives. We thought TI's reputation for good electronic components would extend beyond to their software and operating system but we found that like IBM and many other large companies TI doesn't really get it and is just too much of a hassle to deal with.

    Thank you for your help.

    PS: How about being able to select a username that isn't your first and last name with a number? Wouldn't of helped to not have had to register a second dummy account.