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.

TI-RTOS UART driver issue

MCU: TM4C1294NCPDT

TI-RTOS: v2.01.00.03

CCS: v6.0.1.0040

-

Hello,

    I am using the UART driver integrated with TI-RTOS. I have connected a GPS mouse (outputting text data in its UART port) to UART1 of Tiva C MCU. I have a task, the code of which is provided below. The GPS will send a burst of some 100 to 400 bytes of UART data once every second (the exact number of bytes depends on the GPS info). When the GPS mouse is transmitting this entire data packet it takes (generally) some 200 milli Second to 500 milli Second to complete transmission of the entire data packet. By using the code provided below, I am never able to get the entire data in a single shot. Sometimes the data is broken; for example, I am getting data where a section (say 16 bytes) of the starting section of the data packet is lost. Sometimes, even sections of the end of the data packet is not received. How can I overcome this issue?

I think the parameter ".readTimeout" plays a crucial role in this issue; hence, I have tried different values but didn't get the desired result. I would prefer that the function UART_read returns when there is NO incoming data in the UART RX line for 200 milli seconds, how to achieve this?

Void gpsTaskFxn(UArg arg0, UArg arg1)
{
char rxBuffer[512];
int ret, i;

UART_Handle handle;
UART_Params params;

Task_sleep(1000);

UART_Params_init(&params);
params.baudRate = 9600;
params.readDataMode = UART_DATA_BINARY;
params.readReturnMode = UART_RETURN_FULL;
params.readEcho = UART_ECHO_OFF;
params.readTimeout = 800;
handle = UART_open(UART_GPS, &params);
if (!handle) {
System_abort("GPS UART did not open");
}

System_printf("GPS_UART_initialised\n");

GPIO_write(GPS_PWR_CTRL_OUT, PIN_LOW); // De-activate GPS reset circuit


while(1)
{

  // System_printf("-------------------------\n");
  // System_printf("UART_read called.\n");
  ret = UART_read(handle, rxBuffer, 500);
  System_printf("UART_read returned %d bytes.\n", ret);
  if(ret > 0)
  {
    rxBuffer[ret-1] = '\0';
  }
  else
  {
    rxBuffer[ret] = '\0';
  }
  System_printf("GPS:%d:%s\n", ret, rxBuffer);
}
}

-

Thanks

-

Regards

Soumyajit

  • Hi Soumyajit --

    Does the data stream contain a header that indicates the size of the record?   If so, you should break the read into 2 chunks.  

    Something like this:

    UART_read(handle, headerBuf, headerSize);

    payloadSize = 'get size from headerBuf'

    UART_read(handle, rxBuffer, payLoadSize);

    -Karl-

  • Hi Karl,

     Thanks for your reply. The data packet does contain headers (multiple headers) notifying the start of the packet but not the size of the packet. The header is a single character ('$' dollar sign). An example packet is shown below:

    -

    $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

    $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

    $GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39

    $GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45*75

    You will find that the data packet contains multiple small data chunks each starting with '$' sign. Depending on geographical location & other environmental status, the number of such data chunks & their size will vary.

    -

     I have also noticed another issue (may be this is due to some read bug in the UART driver) that is whenever the receive buffer array 'rxBuffer' is filled by UART data by 'UART_read' function, the data packet is coming something like:

    -

    $GPRMC,123519,A$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

    $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

    $GPGSA,A,3,0

    -

    By this, I mean that section of the starting of the data packet is repeated by the driver. I am sure that its NOT something that the external GPS mouse is sending because I have connected it (GPS mouse) directly to the computer's COM port & found no such anomaly.

    -

    Thanks

    -

    Regards

    Soumyajit

  • Soumyajit,

    Did you figure out the solution? Or is it still an open issue?

    Vikram
  • Hello Vikram,
    I am still stuck with the issue!! Can you please suggest a workaround?
    -
    Thanks
    -
    Regards
    Soumyajit Das
  • Hi Soumyajit,

    I spoke to an expert here on UART driver. Here is what I found out.

    The GPS data format you are specifying is NMEA 0183. From Wikipedia, I found out that the data format ends with a carriage return and a line feed. In the UART driver, there is an option "UART_RETURN_NEWLINE" that allows the UART_read() to return on a newline. Use this option instead of UART_RETURN_FULL in the params.readReturnMode in your code.

    Regarding the readTimeout value, the value is in clock ticks. So to calculate the read timeout value in seconds you will need multiply the timeout value by clock tick period set in your configuration.


    Hope this helps,


    Vikram

  • Hello Vikram,
    Thanks for your support. I have already tried the NEW LINE mode of configuring the UART driver. The problem that I am facing in that case is explained as follows:
    -
    Each GPS data packet consists of multiple lines of data (each ending with CR & LF, ASCII 13 & 10 respectively). Now, how many lines of data will be transmitted (by the GPS mouse) depends on the GPS locking state & the number of satellites in view. So, sometimes the GPS data packet will contain 5 lines, sometimes 7. This creates a problem, i.e. in UART_read function (if I use it in NEW LINE mode as suggested by you), I don't know ho many times I should call this function, whether 5 times or 7 times or 6.
    -
    This problem could have been easily solved if the UART driver could be dynamically updated to change the readTimeout parameter. But I found that it is NOT possible in the current way of the UART driver implementation. What I mean is that, once the UART driver is started, the readTimeout cannot be changed unless UART driver is stopped & restarted again. The implementation of the UART driver of the TI-RTOS should have allowed us to change the readTimeout without stopping the UART driver. [starting the driver = UART_open & stopping the driver = UART_close]
    -
    The point is that, I need some kind of trigger when the UART data starts appearing on the RX pin of the Tiva C MCU. I could have done it if I could change readTimeout on the go to BIOS_NO_WAIT or some finite value like 1200.
    -
    Currently, a very crude & wrong way I have used to implement the GPS data collection by the Tiva C MCU is "UART_read(handle, rxBuffer, 1000);" where the readTimeout have been set to BIOS_WAIT_FOREVER. So, I will get more than one GPS packet at a time (because the function will not return untill 1000 bytes of UART data have been received) & I need to use string manipulation to separate out the required GPS info from repetitions of GPS info. This is a wrong method in my opinion as it introduces latency in the data the Tiva C MCU is receiving from the GPS mouse. It will create problem during GPS based time synchronisation in the Tiva C MCU.
    -
    I request you to please check & inform me how can I change the readTimeout without restarting the UART driver.
    -
    Thanks
    -
    Regards
    Soumyajit
  • Soumyajit,

    I looked at the driver implementation (<ti-rtos_dir>/packages/ti/drivers/uart/UARTTivac.c). With the current design, I don't see any option to change the readTimeout without closing and opening again. But, I don't think I fully understand why you need to change on the go? Why can't you set a finite value for all the calls when you first open the UART driver?

    However, if you have to change timeout on the go, a workaround would be to use the combination of UART_MODE_CALLBACK and your own semaphore that pends for a timeout value. In your application, you could setup a callback function that would transfer the data received into its internal buffer. A semaphore can be set up every 1 sec for say 300ms. On semaphore timeout you can go and read the internal buffer for processing. This way you can control the timeout value on the go. (A timer instead of a semaphore can also be used).

    Vikram

  • Hi Vikram,
    I'll try the callback method soon.... Will update if it turns out to be a viable solution.
    -
    Thanks
    -
    Regards
    Soumyajit