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.

TMDSEMU110-U: XDS110 USB UART is bursty at high baud rates

Part Number: TMDSEMU110-U
Other Parts Discussed in Thread: UNIFLASH

I previously reported this issue in the Bluetooth forum as I've been working with the CC2652, though I didn't really get a solution. My issue is with the XDS110 debugger, and unrelated to the CC2652. See my previous post here: https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1009230/launchxl-cc26x2r1-xds110-uart-is-bursty-and-very-high-latency-under-certain-conditions

I've been using Launchpad boards with a built-in XDS110 debugger for development in my latency-sensitive application, and it's inconvenient to need to attach a separate FTDI cable for USB UART to achieve acceptable latency. At baud rates of 230400 and higher, the XDS110 appears to collect chunks of data over UART before sending to the USB host, and in some cases the USB host can end up needing to wait hundreds of milliseconds for UART data to be sent over. This burstiness/latency issue is most noticeable at moderate data throughput levels that are not saturating the UART but still fairly regularly sending data. The example code I gave in the previously linked E2E post is good at demonstrating such conditions, by sending around 16 bytes of data once every 15 ms. The latency testing Python script I made (in the linked post) shows the burstiness clearly, and I can still reproduce this issue on the latest XDS110 firmware (3.0.0.19) on Windows, Mac, and Linux.

As a temporary hack, to avoid the need for FTDI cables, I've lowered the baud rate in my application to 230399 as that is the highest baud rate where the XDS110 USB UART is not bursty. However, in some cases my application can saturate the UART throughput at this baud rate, hence why I was using a faster baud rate earlier.

Could you file a ticket with the XDS110 developers to improve the latency of the USB UART bridge under such conditions? This latency issue also impacts your SmartRF Sniffer 2 software which uses the XDS110 USB UART on development boards at 3M baud.

  • Hi Sultan,

    I'm sorry to hear that the last E2E thread did not fulfill your expectations.  I've contacted the Debugger Development Team and they are further looking into this issue.  Please allow them time to familiarize with the behavior described and discover the root cause.

    Regards,
    Ryan

  • Thanks, much appreciated.

  • The response from the Development Team is provided below:

    There is a loop which reads from the UART until no additional data is present, and before writing that data to USB. One possibility is there may be enough code in that loop that at high baud rates the Tiva core cannot keep up and thus does not get a chance to transmit the data over USB.  There are other possibilities though, and we wouldn’t really know without a more dedicated debug effort. Since there is a viable workaround for this use case, higher priority has not been given towards further investigating and prioritizing this behavior.

    Regards,
    Ryan

  • OK. It would be nice if the team could investigate this further some day, though I understand its not a high priority. 230400 baud is just 28 kilobytes per second, which should be very easy for a 120 MHz Cortex M4 to handle. This issue popping up at precisely 230400 baud (ie. setting 230399 baud avoids it) is also suspicious to me. In the interim, I'll continue using FTDI adapters, and I may look into writing my own minimal (USB-UART only) firmware for the XDS110 MCU (TM4C129) with better performance.

  • Through further investigation and examination of the XDS110 firmware, I discovered that for baud rates of 230400 and higher, it uses DMA for receiving data over UART instead of the CPU pulling data from the FIFO on UART interrupts. There must be something wrong with the DMA-based UART implementation causing the delays. I'm investigating further, and will update this thread if/when I discover the root cause of the latency issue. I'm hoping I can come up with a patch the XDS110 firmware binary to fix this, and then I'll share what I did to fix it so you can pass it onto the XDS110 firmware development team.

  • In further investigation, I see that in DMA UART mode (used for 230400 baud and higher), the XDS110 firmware sets up a DMA transfer size equal to the baud rate divided by 2000, up to a maximum of 1016 bytes. For example, at 230400 baud, the DMA transfer size is 230400 / 2000 = 115 bytes.

    The issue is that it seems to be waiting for this DMA buffer to be filled before sending the data over to the host, rather than sending the data over to the host immediately when ready. For example, in my sample code I gave earlier, I send 16 bytes every 15 milliseconds, so it takes 7 or 8 iterations (105 or 120 ms) to fill the DMA buffer. I'd appreciate if you forward this finding of mine over to the development team.

  • As an interim workaround, I modified the XDS110 firmware to only use UART DMA for baud rates >= 0x200000 (2,097,152) baud, instead of >= 230400 baud.

    For XDS110 firmware version 3.0.0.19 (shipped with Uniflash 7.1.0), I modified the firmware_3.0.0.19.bin file (located in deskdb/content/TICloudAgent/osx/ccs_base/common/uscif/xds110) in a hex editor. I changed the two bytes following offset 0x908 (2312) in the firmware from 61 3F to 00 1F. I then flashed my new modified firmware using xdsdfu. The TM4C129x microcontroller running at 120 MHz is more than fast enough to handle 2M baud in FIFO mode.

    For reference, the function that this change affects looks something like this (function and variable names guessed/made up):

    void uart_interrupt_setup(int cdc_index)
    {
      USBCDC_Config *cdc_conf = &cdc_configs[cdc_index];
    
      UARTIntClear(cdc_conf->uart_base, UARTIntStatus(cdc_conf->uart_base, 0));
      UARTIntEnable(cdc_conf->uart_base, 0x7E0);
      if ( cdc_conf->baudRate >= 230400 )
      {
        cdc_conf->uart_dma_enabled = 1;
        uart_dma_setup(cdc_index);
      }
      else
      {
        cdc_conf->uart_dma_enabled = 0;
        cdc_conf->field_40 = 0;
        IntRegister(cdc_conf->uart_interrupt_number, cdc_conf->uart_fifo_interrupt_handler);
        UARTIntEnable(cdc_conf->uart_base, 16);
        IntEnable(cdc_conf->uart_interrupt_number);
        UARTFIFOEnable(cdc_conf->uart_base);
        UARTEnable(cdc_conf->uart_base);
      }
    }

  • As one more follow up, using FIFO mode at 2M baud mostly works, and fixes my latency issues, but it can occasionally lose data (I'm guessing because of other ISRs in the XDS110 firmware taking priority and being slow to run). However, FIFO mode at baud rates up to 0x90000 (589824) baud appear to be reliable and free from data loss. To limit the patch to reliable baud rates, replace the two bytes I mentioned with hex 10 2F instead of 00 1F.

    For proper handling of higher baud rates, a fix would need to be made to the DMA-based operation to trigger received data to be sent over USB following a UART receive timeout interrupt (or periodically).

  • Thank you for sharing your findings, I will indeed pass this information along to the Debugger Development Team.

    Regards,
    Ryan

  • One more followup: the occasional (periodic) loss of a few bytes of UART data at high baud rates seems to happen even in DMA mode. It appears unrelated to my change regarding FIFO mode usage, as indeed the CPU is more than powerful enough to keep up with UART interrupts at 2M baud which occur once every 20 us (roughly 200,000 bytes per second, 4 bytes in UART FIFO per interrupt).

    My occasional data loss issue (unrelated, lets not muddle this) appears to occur when the number of bytes I send per UART transfer is not a multiple of 4. The reproduction test code I gave last time (sending 16 bytes once every 15 ms) does not trigger the data loss, nor does sending 20 or 24 bytes at a time, but sending say 17 bytes once every 15 ms at higher baud rates (800k baud and higher) intermittently causes a few bytes to be lost. My guess as to the cause of the data loss is that odd numbers of bytes don't always trigger the the FIFO interrupt (level set at 4 by XDS110 firmware), and something is periodically flushing the FIFO without taking the data out of it.

  • It also looks like there is some timer handling that flushes the UART DMA receive buffers to USB if nothing has been received over UART for 16+ milliseconds. However, my application (and test program) tend to trigger a worst case where they send small chunks of data less than 16 ms apart. These small chunks take a long time to fill the full DMA transfer buffer, however they occur frequently enough to keep delaying this periodic UART DMA buffer flushing to USB, wherever in the firmware it's happening.

  • I figured out why the the transfer gets delayed in DMA mode when small pieces of UART data are coming in once every 15 ms or less. The Timer 0 interrupt handler in the XDS110 firmware is triggered once every 5 ms. In this handler, if 3 or more timer interrupt cycles have occurred since the last check, it reads how many bytes are remaining in the uDMA transfer from UART, and compares it to the value read last time the check was performed. If (and only if) the number of bytes remaining in the uDMA transfer from UART is unchanged from last time (5*3=15 ms ago), it flushes whatever data is sitting in the DMA buffers to USB.

    My application (and test program) both send small pieces of data frequently (15 ms or less apart), and so the timer interrupt handler's check that nothing new has been transferred in the last 15 ms always fails. Thus, in my use case, it ends up waiting for the DMA buffer to be completely filled before sending the data to the USB host.

    My proposed solution is two fold:

    1. Modify the Timer 0 interrupt logic for DMA mode UART to flush the DMA buffer contents to USB even when data is frequently tricking in as small chunks. The current logic of waiting till the DMA buffer fills when new data has come in over the last 15 ms only makes sense when there's a continuous high throughput stream of data coming in that will promptly fill the DMA buffer.

    2. Increase the minimum baud rate for switching to DMA-based UART operation from 230400 baud to something higher like 0x200000 (2097152) baud. Even if the DMA-mode timer interrupt logic is improved, the FIFO based-mode is preferable because gives much lower latency than DMA mode as it doesn't have to wait for periodic timer interrupts to flush the buffers. The CPU is fast, so fairly frequent UART interrupts should be OK.

    The data loss issue at high baud rates for data sizes that are not multiples of 4 is a separate issue which we can deal with another time, and appears unrelated to the choice of DMA or FIFO interrupt based operation (since it happens with both).