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.

Simultaneous uart transmit and receive in DSP/BIOS

Hi,

I have an application that should receive control commands over UART. One of these commands is a 'start' command, and upon receiving that, the application will regurlarly transmit large amounts of data over the same UART.

I have solved this by creating separate input and output handles for the UART (hUart_IN and hUart_OUT) and having separate receive and transmit threads.

The receive thread calls GIO_submit() with IOM_READ command and is always blocking on that call unless data is received.

The transmit thread calls GIO_submit() with IOM_WRITE command whenever it has data to transmit.

It seems now, that this works fine as long as I transmit only short amounts of data. Control commands are received and processed correctly.

However, when I transmit large amounts and then send control commands to the system, it sometimes 'locks up'.

My questions now are:

  1. Is sharing of a UART resource for transmission and reception possible?
  2. Is this method (separate input and output handles, separate receive and transmit threads) the correct solution for that? If not: how should it be done?

The details of the system are:

  • TMS302C6742
  • DSP/BIOS 5.41.09.34
  • CGT 7.04
  • PSP 01.30.00.05
Best regards
Admar
  • Admar,

    Thanks for the details.

    First of all, I would prefer you to use the latest release 1.30.01

    I need some more details, like,

    1. What the data size for which transmit does not work?

    2 .Have you configured UART in DMA mode?

    3. Is there any error interrupt being generated?

    4 .What is the baudrate in which the UART is configured?

    5. Have you tried same amount of data in the sample application which comes with the PSP?

    Regards,

    Sandeep K

  • Admar,

    I am using a C6747 to do the same successfully.  I also have separate threads for RX and TX.  Just make sure:

    1) DMA rather than interrupt driven or polled.  The DSP can get bogged down in polled mode.

    2) RX thread has higher priority than TX.

    3) Keep an eye on the errors like overrun on the RX.  If you can't service the RX interrupt in time the whole UART needs to be reset and restarted again.

    What speed are you running the UART?  I am at 115200 baud.

    Fawad

  • Hi Fawad

    Thank you so much for your answer. I am so glad to hear that the approach that I initially took should work. This issue has been giving me way too much headaches.

    I saw that TI has basically rewritten the UART driver in PSP 1.30.1 (compared with 1.30.05), and the release note of 1.30.1 also describes a bug that sounds very similar to what I'm facing now. I'm now porting the 1.30.1 UART driver over to 1.30.05 (switching the whole project to 1.30.1 takes too much time and is too much risk for now, when the product is 99% approved and finished).

    For the record: I'm using the UART in interrupt mode. I'll switch to DMA and see what happens.

    The baud rate is 781250, which otherwise seems stable. The problem also occurs at 115200.

    It seems now that I've messed up the workspace in CCS, so I'll have to fix that first. After that, I'll come back to your suggestions.

    Best regards,

    Admar

  • Hi

    I've dug a little deeper, and it seems that the call to GIO_submit() for a write operation never returns (timeout in GIO_Attrs struct was set to SYS_FOREVER).

    The data size is 200 bytes. This is usually transmitted in 2 or 3 ticks. I've added a timeout of 1000 ticks, and then saw that the GIO_submit() call returns with error code -11 (IOM_ETIMEOUTUNREC).

    The GIO_submit() call is furthermore protected by a semaphore:

    Int uartTxNBytes(Ptr buf, size_t len) {
    Int status;

    SEM_pendBinary(&UartSem, SYS_FOREVER);
    status = GIO_submit(hUart_OUT,IOM_WRITE, buf, &len, NULL);
    SEM_postBinary(&UartSem);

    return status;

    There are no other functions that use this semaphore and all functions that need to transmit something over the UART call the above function.

    My workaround for now, is to automatically restart the system when it detects that an error has occurred in the uartTxNBytes() function. This is a very ugly workaround, but it is acceptable as a short term solution, since no important data will be lost.

    A better solution would be to properly reset the UART, but I don't know how to do that. I've tried calling GIO_abort() for the input and output handles, followed by GIO_delete() for those handles, but that doesn't work (system becomes stuck in the UTL_halt() function when calling GIO_abort() for the input handle).

    Could someone tell me how to properly reset the UART and its drivers? Or even better: how to avoid this situation at all?

    For the record:

    • I've ported the UART driver from PSP 1.30.1 to my application, but this gave me the same result.
    • Data size in my application is 200 bytes, but I often test in a terminal application with just 4 or 33 bytes to prevent flooding the terminal app. Problem also occurs with these smaller sizes, but less frequently.
    • UART is in interrupt mode, since I've had issues with DMA mode. Besides that, the protocol I have to parse is variable length, so I have to parse each byte when it is received.
    • At first I did not see any error. After adding the timeout to the GIO_submit() write call, I see error code -11 (IOM_ETIMEOUTUNREC).
    • Uart settings: baud rate is 781250, 8N1, RTS/CTS flow control.
    • Sample application works fine, but that application does not simultaneously try to transmit and receive (no separate TX and RX threads).
    • RX thread has higher priority (15) than TX thread (7). I've also tried the RX with a lower priority (6), but this gave the same result.
    Please note that I'll be on holiday from April 23 until May 7, so I won't be able to respond to e-mails or this forum. This is also why I've chosen to just restart the system when it encounters this error state. Hopefully this solution is only for the next few weeks.
    Best regards
    Admar
  • Admar,

    Look at this thread in which the same issue of time out occurs

    http://e2e.ti.com/support/embedded/bios/f/355/t/111541.aspx

    Fawad

  • Hi Fawad,

    Sorry for my late response, but I was on a holiday.

    Thank you for your suggestion. Unfortunately, it did not work.

    The GIO_submit(hUart_IN, IOM_READ, ...) call is invoked with timeout set to SYS_FOREVER. This is necessary, since the system cannot know if / when data will be received.

    Thus, I can only detect this error state in the thread that performs the GIO_submit(hUart_OUT, IOM_WRITE, ...) call, by setting a timeout (1000u) and checking the return status. If the return status is not IOM_COMPLETED or IOM_PENDING, something is wrong. It seems that in those cases, the status is IOM_ETIMEOUTUNREC.

    I tried the answer in the thread you referred to (resetting RX FIFO and cancelling current IO for input channel), but then I keep getting IOM_ETIMEOUTUNREC in the subsequent write calls to the output channel after that.

    I've also tried resetting TX FIFO and current IO for output channel, resetting FIIFOs and cancelling for both input and output channels and calling GIO_abort() before resetting FIFOs and cancelling IO. Unfortunately, all in vain.

    So, my current solution is still the very ugly and undesirable call c_int00() (system restart).

    Do you have any other solutions I could try?

    Best regards,

    Admar

    PS: what is the difference between GIO_abort(hUart_IN) and GIO_control(hUart_IN, Uart_IOCTL_CANCEL_CURRENT_IO, 0)? And how exactly does it differ from GIO_flush(hUart_IN)?

  • Hi Admar,

    I see that, you are running UART at 781250 baud with 8N1and RTS/CTS flow control enabled.

    It is also mentioned that the UART(read/write) works fine until any timeout is provided. i.e, with timeout = default (SYS_FOREVER)

    Is my understanding correct? Please confirm.

    Since you are getting a timeout from the driver and unable to recover from it, you can try doing something like this -

    - Do not provide a timeout during channel creation.

    - Register a callback function and call GIO_submit (hUart_IN, IOM_WRITE, &WriteBuffer[0], &size, &CallBackFunc) with the appropriate callback function. Then, pend on a semaphore(provide a timeout for this semaphore). When the callback is called, just release this semaphore.

    NOTE: By doing so, GIO_submit(...) will be an asynchronous call.

    The advantage here is that, the control will be with the application. This is just a suggestion that can be tried. Try this and let us know the results.

    Admar Schoonen said:
    what is the difference between GIO_abort(hUart_IN) and GIO_control(hUart_IN, Uart_IOCTL_CANCEL_CURRENT_IO, 0)? And how exactly does it differ from GIO_flush(hUart_IN)?

    The UART driver implementation is such that, the GIO_flush(...) and GIO_abort(...) have the same functionality. Both call uartCancelAllIO(...) wherein all the IO requests are cancelled.

    Since GIO_submit(..) which you are using is a synchronous call, at any given point of time there will be only one request active. Hence, it is not needed to cancel all IO requests. So calling GIO_control(...) with "Uart_IOCTL_CANCEL_CURRENT_IO" IOCTL should be just fine.

    One more  suggestion -

    Try running the UART at 115200 baud with RTS/CTS Flow control disabled. if this works for your present setup, then you can move to higher baud rates.

    Hope this helps..

    Best Regards,

    Raghavendra