TM4C123GH6ZRB: USB CDC Device upstream flow-control signaling

Part Number: TM4C123GH6ZRB
Other Parts Discussed in Thread: EK-TM4C123GXL

Hello,

I am implementing a USB composite device with two CDC sub-devices using the TivaWare 2.1.4.178 USBLib.

The data flows from the CDC device, through a USBBuffer, and then out through UART1, using hardware flow control on the UART controller. And vice-versa.

If the flow control line CTS is asserted, the USBBuffer gets full and data flow stops. If this situation lasts a short period of time, when the CTS line is de-asserted, data-flow resumes normally. However, due to limitations of my implementation, there are big periods of time when the UART can have its CTS line asserted, therefore stopping the data flow IN through USB and OUT through UART.

When this situation happens, what I have discovered is that the USB host keeps resending the same data, while incrementing the size of the packet it tries to send. When the CTS line is finally released, and the data flow can continue, the USB stack can't handle the enormous packet it receives and the data output just keeps repeating the first part of the packet.

I wanted to know what is the API to send a signal to the host that the data flow has stopped, a.k.a. the CTS is asserted, hopefully stopping the Host from retrying the same packet over and over.

Kind regards,

Pedro Serra

  • Hi,

      I will let our USB expert comment on your question. 

  • Hello Pedro,

    Pedro Serra72 said:
    When this situation happens, what I have discovered is that the USB host keeps resending the same data, while incrementing the size of the packet it tries to send.

    This sounds like an issue with the USB Host. I have not heard of that happening.

    With USB, the device will NAK a package that is not able to the received yet. That should trigger the host to re-send the same packet, not add more data to it. The NAK is telling the host that it did not receive the packet and so the host should understand that they need to re-send it. I have not heard of host implementations which takes that NAK as a means to add more data to the packet. Also there should be a limit to size of the packet based on USB standards and it sounds to me like the host may be exceeding those. Usually for USB Full Speed, CDC data packets are sent over bulk endpoints that are configured to be 64 bytes max size. If the host is sending more than 64 bytes in one packet over a bulk endpoint, it is definitely not following USB protocol.

    There isn't an API to just tell the host to stop sending data and any other workaround I can think of really just amounts to restarting the USB connection from scratch.

    I think you need to resolve the strange behavior on the host and get it so that it does not queue more data on the USB bus.

  • Hello Ralph,

    Thank you for your reply.

    Usually for USB Full Speed, CDC data packets are sent over bulk endpoints that are configured to be 64 bytes max size. If the host is sending more than 64 bytes in one packet over a bulk endpoint, it is definitely not following USB protocol.

    My host is a Windows 7 or Windows 10 PC using the usbser.sys driver. I followed up on this maximum packet size of 64 bytes and confirmed this using usbview. I attached the descriptors so you can confirm too.

    usbview.txt
    Device Descriptor:
    bcdUSB:             0x0110
    bDeviceClass:         0xEF
    bDeviceSubClass:      0x02
    bDeviceProtocol:      0x01
    bMaxPacketSize0:      0x40 (64)
    idVendor:           0x1CBE
    idProduct:          0x0007
    bcdDevice:          0x0100
    iManufacturer:        0x01
    0x0409: "EID"
    iProduct:             0x02
    0x0409: "TWH-110 Interface Ports"
    iSerialNumber:        0x03
    0x0409: "00000001"
    bNumConfigurations:   0x01
    
    ConnectionStatus: DeviceConnected
    Current Config Value: 0x01
    Device Bus Speed:     Full
    Device Address:       0x0A
    Open Pipes:              6
    
    Endpoint Descriptor:
    bEndpointAddress:     0x81  IN
    Transfer Type:   Interrupt
    wMaxPacketSize:     0x0010 (16)
    bInterval:            0x01
    
    Endpoint Descriptor:
    bEndpointAddress:     0x82  IN
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x02  OUT
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x83  IN
    Transfer Type:   Interrupt
    wMaxPacketSize:     0x0010 (16)
    bInterval:            0x01
    
    Endpoint Descriptor:
    bEndpointAddress:     0x84  IN
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x04  OUT
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Configuration Descriptor:
    wTotalLength:       0x008D
    bNumInterfaces:       0x04
    bConfigurationValue:  0x01
    iConfiguration:       0x00
    bmAttributes:         0xC0 (Bus Powered Self Powered )
    MaxPower:             0x00 (0 Ma)
    
    Unknown Descriptor:
    bDescriptorType:      0x0B
    bLength:              0x08
    08 0B 00 02 02 02 01 00 
    
    Interface Descriptor:
    bInterfaceNumber:     0x00
    bAlternateSetting:    0x00
    bNumEndpoints:        0x01
    bInterfaceClass:      0x02
    bInterfaceSubClass:   0x02
    bInterfaceProtocol:   0x01
    iInterface:           0x00
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x05
    05 24 00 10 01 
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x04
    04 24 02 06 
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x05
    05 24 06 00 01 
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x05
    05 24 01 01 01 
    
    Endpoint Descriptor:
    bEndpointAddress:     0x81  IN
    Transfer Type:   Interrupt
    wMaxPacketSize:     0x0010 (16)
    bInterval:            0x01
    
    Interface Descriptor:
    bInterfaceNumber:     0x01
    bAlternateSetting:    0x00
    bNumEndpoints:        0x02
    bInterfaceClass:      0x0A
    bInterfaceSubClass:   0x00
    bInterfaceProtocol:   0x00
    iInterface:           0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x82  IN
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x02  OUT
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Unknown Descriptor:
    bDescriptorType:      0x0B
    bLength:              0x08
    08 0B 02 02 02 02 01 00 
    
    Interface Descriptor:
    bInterfaceNumber:     0x02
    bAlternateSetting:    0x00
    bNumEndpoints:        0x01
    bInterfaceClass:      0x02
    bInterfaceSubClass:   0x02
    bInterfaceProtocol:   0x01
    iInterface:           0x00
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x05
    05 24 00 10 01 
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x04
    04 24 02 06 
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x05
    05 24 06 02 03 
    
    Unknown Descriptor:
    bDescriptorType:      0x24
    bLength:              0x05
    05 24 01 01 03 
    
    Endpoint Descriptor:
    bEndpointAddress:     0x83  IN
    Transfer Type:   Interrupt
    wMaxPacketSize:     0x0010 (16)
    bInterval:            0x01
    
    Interface Descriptor:
    bInterfaceNumber:     0x03
    bAlternateSetting:    0x00
    bNumEndpoints:        0x02
    bInterfaceClass:      0x0A
    bInterfaceSubClass:   0x00
    bInterfaceProtocol:   0x00
    iInterface:           0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x84  IN
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    
    Endpoint Descriptor:
    bEndpointAddress:     0x04  OUT
    Transfer Type:        Bulk
    wMaxPacketSize:     0x0040 (64)
    bInterval:            0x00
    

    I sniffed the bus using Device Monitoring Studio during normal functioning (CTS not asserted). Even in this situation, the payload size I see in the sniffed packets is 100 bytes, not the 64 previously defined.

    Am I missing some configuration parameter to pass this "maximum packet size" information to the host? Or do you suspect a bug in the usbser.sys driver?

    Thanks for your help.

    Kind regards,

    Pedro

  • Hello Pedro,

    Sorry for my delay in reply. I've been mulling over this since your post but hadn't had a chance to dig into it until today. Based on what I've looked into, I wouldn't think that Windows has a bug like that. Honestly, the issue still doesn't make any sense to me and I haven't seen something like this before. Everything looks configured fine...

    Is there any way you can take what you've done and get it running on a LaunchPad where I can get the project to recreate it? I have a full USB analyzer to review the whole packet trace and see where the issue is stemming from. Beyond trying to do that, I am not really sure what to suggest right now.

  • Hello Ralph,

    Thank you for your support. I have prepared an example code based on the usb_dev_serial example from TivaWare for the EK-TM4C123GXL LaunchPad.

    Below is the CCS project folder that I created. As I've said, this project is based on the usb_dev_serial example with the only alterations being that I switch from UART0 to UART1 and enabled the Hardware RTS/CTS flow control in the UART1 controller.

    usb_dev_serial_ek.zip

    The following picture shows the connections from my setup. Afterwards, both the FTDI TTL-232R-3V3 and the USB CDC device are connected to the test computer (running Windows 7).

    I have also grabbed a screen recording demonstrating the problem: Screen capture video

    In the video I start a large transfer from Tera Term, through the USB CDC device, out the UART1 and into the FTDI TTL-232R-3V3 probe, displayed on the lower YAT terminal window.

    After a bit, I manually assert the FTDI RTS line (connected to the UART1 CTS pin) and stop data flow for a period of time.

    After said time, I re-enable communications (de-asserting the RTS line) and the problem arises. Data is repeating itself on the receiving end, and the Tera Term window doesn't show any progress.

    I have confirmed in the Wireshark capture that the data flowing to the USB CDC device is indeed repeating itself.

    In our testings, it seems that this problem doesn't occur with all aplications. If an application performs blocking writes to the serial COM interface, there is no problem. However, if an application performs assynchronous writes and then resends the packet after a timeout AND the packet is very large, then we have a problem.

    Thank you for your help.

    Kind regards,

    Pedro Serra

  • Hello Pedro,

    Thank you for the details here, that is very helpful to recreate the problem and understand the exact cases needed to trigger it.

    I will need to go into the office to get ahead of an FTDI Probe that I can use for this and I won't be able to do so until tomorrow afternoon. I will follow up with you early next week after doing testing on my end.

  • Hello Ralph,

    Thank you for all your support.

    Unfortunately I am leaving my current company and this project, today is my last day. Therefore, this thread will be followed by two of my coleagues that are working in the same project. Their names are Luís Oliveira and Nuno Ramos, they will be in touch.

    We are all looking forward to hear about your findings with the USB analyzer, and I will be sure to at least keep tabs on this thread on the count of my own curiosity.

    Thanks again.

    Hope to talk again soon,

    Pedro Serra

  • Hi Ralph,

    I following this project.

  • Hello Luis,

    I was able to get the hardware setup today but did not get around to loading the project and testing yet. I will see what initial results I can get for you tomorrow.

  • Hello Luis,

    I have been trying to replicate the issue but despite using multiple terminal software, I have not been able to observe the RTS/CTS lines toggling on the project Pedro sent and as a result I have not been able to recreate any failure case. Can you please check the project provided and see if it generates the CTS/RTS for your and if the failure case occurs with it?

  • Hi Ralph,

    To control and see flow control signals RTS/CTS I used Yat terminal. Configure terminal on manual hardware control. It´s works uart1 on the TM4C and FTDI flow control on.

    The manual mode control allows changed state RTS signal.

    Data Flow Diagram

  • Hi Ralph,

    If you is not control RTS line on RX device.

    Try to disconnect uart1 (FTDI probe), this is not open terminal (consumer). The RTS signal is high.

  • Hello Luis,

    I have tried multiple Terminal programs but do not see CTS toggle.

    When I use Docklight and swap to Manual Mode, I do get RTS high at that point. But it stays high, CTS stays low, and no toggling happens.

    The ports also don't seem to pass through. When I send on UART1, it echos back. And on USB CDC it is constantly outputting values though I see gaps with those values and I can't tell if that is intentional or not. Either way, I am not seeing a data flow from UART1 to USB CDC. If I disconnect one or the other, I can see they work independently and identically compared to when both are connected.

    This whole description really doesn't fit the project I have been given.

  • Hello Ralph,

    Please confirm our assert.

    TM4C FTDI
    PF1 (CTS) RTS (green)
    PF0 (RTS) CTS (brown)
    PC5 (U1TX) RXD (yellow)
    PC4 (U1RX) TXD (orange)

    See:

    https://imgur.com/siG8feb

     Check if is RTS green cable is down and up  signals in manual mode.

  • Tera Term configuration (open CDC serial device):

    buad rate: 115200

    data: 8 bit

    parity: none

    stop: 1 bit

    flow control: none

  • Hello Luis,

    Tera Term Configuration for USB port

    Docklight Configuration for FTDI port (replacing VAT)

    FTDI Cables verified connection. I've reviewed this multiple times.

    The data does not send across. I see data echoing on TeraTerm for USB. And on Docklight if I send, it loops back. There is no transmission from TeraTerm to Docklight.

  • Hi Ralph,

    CCS project:

    usb_device_serial_uart1_flowcontrol.zip

    See EK state of FTDI:

    Led RGB State
    Green Receiver data
    Red RTS high (stop) or FDTI not connect
    Blue Transmitter data
    Off FDTI connect

  • Hello Ralph,

    as Pedro mentioned I'm also following on this project.

    First and foremost, thank you for your time and effort so far on helping us resolve this issue!

    So far we noted that when the receiving buffer of the CDC class Driver (please see picture from tivaware lib) is full AND also if the Rx Buffer is not consumed (comunication is at full stop) when the PC is still trying to send in more data,  we saw through the "Device Monitoring" sofware that  tiva USB Driver sends back a message saying status "Cancelled" and that the PC was trying to transfer bursts of 16kB (after grown to this max size just as in Pedro's Video

    Screen capture video

    ), after each one of these Bulk In messages from Tiva. We were expecting that after the available data in the RxBuffer of the CDC Class Driver had been consumed that the communication would resume normally, but instead we see that the data keeps repeating itself.

    Pedro Serra72 said:
    Screen capture video

    I suspect that this happens because the PC keeps resend this huge burst of data and Tiva can not cope with it, so it signals back to the PC "cancelled"  and the PC keeps resending the same package. Note that with all the software we have tested so far far this only happens with TeraTerm.

    The previous test descriptions, were intended to fill out the receiving buffer in the CDC driver Class. As described, if the FTDI is not ready to receive any data it signals through the CTS line, and while the CTS line is asserted, the Uart on the Tiva will not send any data to the FTDI, In turn as the Uart is not capable of sending data its own buffer fills out, which finally also prevents that the available data in the Receiving buffer on the CDC Class Driver to be consumed.

    In order to replicate this problem without manually asserting the CTS/RTS, please follow these steps:
    1. please make sure that the code provided by Pedro is running in Tiva C Launchpad.
    2. Make the connections between Tiva's Uart1 and a FTDI USB/TTL device according to Pedro and/or Luis previous posts.
    3. start up TeraTerm, and setup the COM accordingly (COM#, 115200, hardware flow control, 8N1) for the Tiva connection. BUT do NOT start the FTDI connection just yet, leave it disconnected, even from the PC if desired.
    4. Transmit a long file (at least 100KB, a teste file is available "dataTest.txt"), simple drag and drop a file will do
    5. Wait about a minute the buffer to accumulate.
    6. Initiate the connection on the FTDI side following the same configuration of the Uart in Tiva.
    7. Confirm that the data is repeating itself.

    We also conducted another experiment, which was to eliminate any external hardware or connection and also any interface with any other peripheral, the Uart comunication. A loopback in the CDC Class Driver Buffers was made by simply copying Rx available data to Tx buffer through the Handler. As expected this results in echoing back any data sent to the CDC class driver. As no longer a CTS or Uart is controling the flow of data, additional control (software) was added to replicate the aforementioned problem. The Software controles now between each read access to the buffer and determines wether to apply a simple delay between each read, or simply stop reading until the user comands it to resume reading.
    The delays are intended to emulate the speed of data transfer, as for the stop condition is meant to replicate the above situation. With this experiment the results were the same as before, the data keeps repeating endlessly.
    When tried with delays it was concluded that for mean speeds below 2400 baud, the data would no longer be intact and data was repeated. The code for this experiment is attached (please try it out, its functionality is described in the readme file).

    It is also important to note that with other serial terminal softwares we noticed that the overall packet size is kept low, and the softwares keep waiting for the Tiva's "Ack" in order to send the next packet. And so this problem does not present it self.

    Kind Regards,
    Nuno Ramos

    0257.usb_dev_serial_loopback.zip

  • Hello Luis and Nuno,

    Thank you for all the added detail here and the two new projects. This is really helpful to read through. I haven't had a chance to run your projects attached today, I will see about getting that done tomorrow and reporting my findings.

    I think the project Pedro attached was the loopback version as I am seeing constant data on the USB port. It wasn't clear to how recreate the issue with that version.

    Understanding how to trigger the issue with the file transfer and having letting the buffer accumulate is very helpful for me so I will try that. I do use TeraTerm so that is simple for me to test with that terminal software specifically.

  • Hi Ralph,

    I forgot to mention in my previous post, that when performing the usb loopback experiment, we noticed that if the comunication is held off (simply by not accessing Rx Buffer in the CDC class driver), and then start consuming available data in Rx buffer at full speed, as fast as it  can (with no delays), the comunication eventually recovers itself and data transmission is normal again.

    Kind Regards,
    Nuno Ramos

  • Hello Nuno,

    I will be trying the loopback more tomorrow as I don't see the CTS shifting on the UART1 Flow Control projects. I think I had that one already hang once so it should work decently.

    It took me a bit to get the other projecting going as you described as it wasn't clear the Send File had to be from the USB CDC Tera Term but once I did that, at least now I saw the data transfer from USB to UART that I was expecting to see on the original project I got. I think looking at behavior with terminals of the projects, the one Pedro sent may have been a loopback project.

    Unfortunately, I haven't been able to re-create the failure yet with that project so that is why I will focus on loopback.

    What I have done:

    • Verified hardware connection to FTDI
    • Loaded the uart_dev_serial project that Luis provided
    • One USB connection from LaunchPad to PC is for Stellaris ICDI to program LaunchPad
    • One USB connection from LaunchPad to PC is for the USB CDC port
    • One USB connection from LaunchPad to PC is the UART1 FTDI connector which I am using a TTL-232R-3V3-WE from FTDI Chip.
    • TeraTerm Connections for both USB CDC Port, and UART1 FTDI
      • Hardware Flow Control enabled on both terminals
    • Send file over USB CDC port with FTDI unplugged, wait 1-2 minutes then plug in
      • In this case, I do see RTS shifting, but not CTS shifting
      • Data being sent from USB to UART1

    So I don't know if I am not waiting long enough on the USB side for the buffer to fill or if there is something else going on that I am not aware of with this setup.

    Anyways, if the loopback continues to work well - or, well, NOT work well as intended, that should give me what I need to debug further about why the USB comms is hanging.

  • Hi Ralph,

    were you able to  re-create the failure, with the usb loopback program on tiva?

    Kind Regards,
    Nuno Ramos

  • Hello Nuno,

    I have been trying to get it fail at various frequencies from your button configurations, some of which are very long tests, but I have not seen a failure yet.

    I have been using TeraTerm for all of these on a Windows 10 Professional laptop. TeraTerm version is V4.95.

    I tried a lot to trigger that one failure I saw before because there was one time amidst all the testing that I saw the transfers hang but I couldn't recreate it.

    Since this only occurs with TeraTerm and I haven't been able to replicate it, I wonder how system specific this is. On how many PCs is this occurring? With what version of TeraTerm? What version of Windows 10?

  • Hello Ralph,

    the TeraTerm version that I was running was V4.93, nut I have updated also to V4.95 and the results were the same.

    We also tested and confirmed this behaviour on 5 different PCs running either Windows 7 PRO 64bit or Windows 10 PRO 64bit.

    The only thing left to cover is the driver, but I've also tried two drivers and the results were also the same. One driver was the one available in the Tivaware folder, and the other windows generic CDC driver. But then I noticed in "usb_dev_serial.inf" file (available at Tivaaware windows drivers folder) that in practice they should be the same, as they both use the windows "usbser.sys" serial driver, correct me if wrong here.

    Please consider running the updated code attached in this post to replicate this fault, and follow this procedure:

    1.Connect Tiva load and run program attached,
    2. Once the program is running on Tiva, open TeraTerm, and open the COM, the terminal should now be ready to input data. 
    3. Type anything in keyboard and check that the data typed in is echoed back.
    4. Drag a file (you can use the TestFile.txt in the attached zip file) in the Teraterm window to start data transferring.
    5. 10 seconds after initiating data transfer click SW1 on Tiva, and check that the LED ont TIVA turns Red, if not keep clicking until it does :-)
    6. While the LED is RED check that the data transfer is stalled/paused/stopped, and check that Terterm still indicates that the file is still being transffered although, the data rate is slowing down.
    7. Wait for about 1 minute after the LED turned RED.
    8. Now click SW1 on Tiva to turn the LED back BLUE again if not keep clicking until it does :-)
    9. By this point the data seen on TeraTerm should already be repeating itself endlessly.

    I hope that this helps you to recreate our problem.

    Many Thanks
    Kind Regards
    Nuno Ramos

    8510.usb_dev_serial_loopback.zip

  • Hello Nuno,

    I have been able to recreate the problem as you described now but I have not been able to debug it in detail yet - I will be reserving time next week to do so as we have a holiday day tomorrow. Thank you for the latest example and clear instructions, this should give me what I need to investigate deeper.

  • Hello Nuno,

    So good and bad news though I think you'll primarily find this to be the latter.

    The good news is that the USB interface does not seem to have errors associated and my USB analyzer is not picking up any violations of USB protocol nor any occurrences of 100 byte long packets being transmitted.

    The bad news is that I have not been able to track down the root cause of the loop issue, though I suspect strongly at this point that it is specific to your application implementation. I just am not familiar enough with what has been put together to really sniff out the root cause.

    Regarding the whole issue being related to the CTS signals stalling the transmissions, that definitely seems to be impacting this and it is doing so in a way I don't really understand. The USB analyzer capture I took with a Lecroy USB analyzer will be useful for you I think. I am attaching it here. Make sure to hide SOF packets when viewing it.

    USB Analyzer Capture: USB_UART_Loopback_CTS_Test_1.usb

    So what you will see is the first 11 seconds of transmissions, the loop back is pinging back and forth. It seems almost like one side was sending more than the other though. I would see IN transactions from the host that were larger than the OUT transaction that followed from the device. And that makes me wonder if there was a backlog being built up in the application.

    The reason I wonder this is because of Transfer 440. Up until that point, the transfers were a range of 575 bytes or less typically. But then suddenly for #440, it transferred 2752 bytes from the device to the host. That was a huge transaction and I don't think the application even has that much data stored.

    Then after that transfer, when the sending resumes, the device only ever sends these large 2400+ byte packets back. And that just doesn't make any sense to me as to what is causing that - but whatever it was, it started with that first transmission at #440 on the capture. Something there hosed up the application code and it seems to get stuck in a bad state, but I don't really know how to delve through your custom setup to really figure out what exactly is going on.

    It is definitely something in the TivaWare code though, and I don't believe it is related to the USB driver. This feels like something where an array overflowed or a counter exceeded what it was supposed to or something that just sent things off the rails.

    I hope the USB analyzer capture will prove to be useful for you, and if you can narrow down the issue further let me know so we can brainstorm on how to better setup your software to do what you want. If you can identify the problem location I can debug further as well.