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.

TM4C129CNCPDT: PC reboot with "Always On" USB power causes USB-Serial to get stuck in a bad state

Part Number: TM4C129CNCPDT

We are using the TI provided USBLib to create a USB CDC Serial device (based on the example code for the TI-RTOS).  The device is powered by the USB Bus and I am forcing the USB peripheral to operate in Device Mode.  When we use this device on PCs that have "Always On" USB power, the USB stack seems to get stuck in a bad state after a PC reboot where the device will enumerate as a USB Serial device, but it won't send or receive any data.  When the device is physically removed from USB and re-inserted, everything works properly again without another reboot on the PC.  I spent all of last week debugging this, without much luck.

Does the Tiva USB ecosystem support reconnecting/re-enumerating to a PC that has rebooted like this?  If so, what am I missing?  I imagine that this would be supported since self-powered devices (like 3D and 2D printers) are common, but I could be wrong.

Thank you,

David

  • Hi David,
    Sorry that I'm not an expert in USB. Our USB expert is on travel and won't be back until next week.
    I would have expected the PC to send some type of USB RESET command to the device after it reboots. Once the RESET command is received the device will go through the enumeration handshake process with the host again. Did you see this happening if you debug the code. Can you tell if the RESET command was properly sent by the host and if the device even received it.
  • A Reset command is being sent to the Tiva from the PC when the device re-enumerates, and the Suspend interrupt is also firing while the PC is shutting down. However, after some deep digging during debugging I found that the USB Reset interrupt callback function pointer was set to NULL (0x00000000). I haven't found a USBLib API for setting that callback myself, so I assume that I'm not supposed to touch that while using the USBCDCD library.

    To clarify, I do see the device enumerating on both Windows and Linux PCs when the USB device gets into a bad state. However, I haven't found the code that handles enumeration yet. I also know (according to the datasheet) that some of the USB peripheral details are protected under NDA, so it's possible that I won't be able to debug that process.

    Thanks for your quick reply. I hope that helps.
  • Hi,
    When you receive the RESET command from the host, have you also reset your serial device (i.e. the UART)? Will that make a difference?
  • I'm not sure which Serial device you mean, but I am not resetting any of the hardware UARTS. I also tried resetting (terminating and re-initializing) the USB Serial device, but that causes the CPU to freeze and the Watchdog to reset it 2 seconds later.
  • Hi,
    Since you use CDC class, I was under the impression that you might be creating a USB to UART converter type of application and hence suggest that you also do a peripheral reset of the UART when you receive the RESET command from the USB host.
  • Oh, I see what you mean.  One of the many functions of this device is to generate its own USB Serial output.  Even the internally generated data stops transmitting correctly after reboot.  The USB Serial wrapper that I wrote uses mailboxes to queue up data, and I don't see anything bad happening in that code (except the fact that the USB Serial driver hasn't reported a successful transmit of the last message).

  • Hello David,

    I've been trying to come up with some ideas on what could be occurring, but I am not too certain myself yet. I'd like to get a bit more fleshed out baseline to work from though.

    You mentioned using the TI-RTOS example, would it be possible to use a TivaWare based non-RTOS example to test this further? I am not familiar with RTOS and while it should leave the USB alone for the most part, I would have to dig into unfamiliar code to confirm where the enumeration occurs and what gets passed in for enumeration.

    I have a TivaWare example for a single CDC device you can use instead, if that is okay: 1882.usb_dev_cdcserial.zip

    If the problem repeats with this, I can try and see if I can replicate the issue somehow. Do you happen know if BIOS can be set to make a PC be always on for USB? Or is this just done by the Windows setting of "Allow the computer to turn off this device to save power"? The latter would be easy for me to test with!

    I'm hoping this isn't a Windows issue where because the PC wasn't running the OS when the device remained plugged in that the enumeration caused Windows to not properly recognize.

  • Thank you for the response. I imported the code you provided, and I made the necessary adaptations to make it work with my setup.  I'm using the TM4C129C series with a different external crystal instead of the TM4C1294. I'm also not using VBus to detect the USB connection, so I added:

    USBStackModeSet(0, eUSBModeForceDevice, 0);

    After trying a reboot on the same setup as before, I was both able to reproduce the issue and avoid the issue. While the test PC was in the process of rebooting, I typed into the console of UART0 on a separate PC with the debugger running. If I typed too much (more than 100 characters, not sure exactly how many) while the PC was rebooting, the USB device would stop flashing the RX activity light and the USB Serial functionality did not allow text to go back and forth. The device would still enumerate, though. However, if I only typed a few characters or no characters at all during the reboot, the USB device would work without a problem when the system came back up.


    The above steps were only in an effort to reproduce the issue, and it is not exactly similar to how our software is using the USB Serial device. However, this does help me come to two conclusions: either the TI-RTOS example has some differences that are causing issues, or my code isn't blocking itself from attempting to transmit while the PC is rebooting. I will dig deeper into the code tomorrow. I will post any further details as I find them.

    As for testing the "Always On" feature of a PC on your end, it really depends on the motherboard that you are using. Some PCs support it through the BIOS and some don't even offer it, others are just wired in such a way that the PC has no control over the Bus Voltage. However, the easiest way to test this on any computer is to use an external power source (in my case I could use the debugging PC to power the device while using another PC to do the rebooting).

  • Success!!!

    After comparing the differences between the code you sent me and the code in the TI-RTOS example, I found the issue.  There is a major difference between the way the non-RTOS and RTOS examples handle TX data.  The non-RTOS example doesn't handle any data loss while transmitting data.  It just puts data in the TX buffer if the new data fits, otherwise the data get thrown out and the code moves on.  However, the RTOS example buffers the data and waits for a semaphore to be posted by the TX interrupt.  This semaphore isn't getting posted when the PC reboots.

    The fix:

    My code was calling the following function from USBCDCD.c in the RTOS USB Serial Example

    USBCDCD_sendData(packet, length, BIOS_WAIT_FOREVER);

    Since I wasn't using a timeout, the code would block execution there, and yield the task forever.

    By adding a timeout to the function call and handling the return status I was able to queue up the outgoing data until the computer reconnected to the USB CDC device.  Here's a quick and dirty example of how I was able to get it working:

    do {} while (!USBCDCD_sendData(packet, length, 5000L));

    This causes the task to yield for up to 5 seconds before it cancels the attempt and tries again.

    This solution doesn't feel as elegant as I would like, and it would be nice to have something in USBLib that could handle the system disconnecting and reconnecting a bit better than this.  However, this allows me to get back up and running for now.  Thank you for sending that example.  It allowed to to find the differences more easily.

  • Hello David,

    Excellent to hear that you were able to mostly get this solved! I am not an RTOS expert so I am not sure of a more elegant solution, but if you would like, I can try and reach out to the RTOS team experts and see if anyone would like to offer up ideas on how to better handle that.

    I'll mark your post as the suggested resolution so the community is aware of what to do if any other users come across a similar issue.
  • I think this should give us what we need for now, but I am interested in finding a better way to do this in the future since we will be using USB for other devices. It could also be beneficial to the community to update the USB example if there is a better solution.

    Thanks in advance for passing this along!
  • It's been several years, but I seem to remember we had a similar issue when we first tried running the USB stack with TI-RTOS. We worked with the original TivaWare software engineers on this, but without a major modification to their USB stack, the timeout was the best we could do.
  • Thank you for your feedback. This at least lets me know that I am on the right track.