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.

Delfino 28377D USB interrupts stop firing at seemingly random times.

Other Parts Discussed in Thread: CONTROLSUITE

The USB driver works great until I have to send large packets of data to the USB device I am developing.  It will get a random number of large packets successfully, and then halfway through one of the large packets, the interrupts will stop firing, and I cannot recover.  I need to get to the bottom of why this is happening and I am having a heck of a time.  

I will attach a picture showing that data reception randomly stops.  On the top, you can see the full packet that our PC tool sent, the bottom left is our custom buffer for the data and on the right is the buffer supplied to the USB device when we set up the USB CDC object.   You can see that where it is highlighted is where it breaks down.  The disconnect seems to happen between the wire, and the USB device Rx buffer (g_pi8USBRxBuffer); data acquisition appears to stall because interrupts stopped. 

  • Anyone have any ideas on why the Rx and TX interrupts stop firing? It seems that the whole USB stops working, as an unplug and re-plug of the cable doesn't re-enumerate the device.
  • I have found that rapidly sending packets of 65+ will cause the USB driver to hang and the Rx and Tx interrupts stop firing. If I limit my packets to 64 bytes or less and rapidly send those, the driver never hangs.
  • Hi Michael, We are seeing similar behavior on the F28377D. We are working on correctly identifying the issue and finding a solution. sal
  • Michael,

    Are you still getting SOF interrupts? Is the interrupt handler being triggered still?
  • After it seems to stall, I get zero interrupts. I put a break-point in "f28x_USB0DeviceIntHandler" which is the lowest level I can see. it never breaks there after it stalls.
  • It seems to be related to the amount of time in my interrupt handler. I rewrote my code to try and cut down on the processing done in the handler. This seems to have worked so far.
  • Michael,

    We have identified the problem and are working on updating the USBLIB. For now, you can make a few changes in your project...

    There are three registers in the USB that are being used to generate USB interrupts to the PIE. USBIS, USBTXIS, USBRXIS. When any of these registers are set with values, the interrupt is flagged. All of these registers are cleared by reading the values from the registers.

    When a SOF (start of frame) packet comes into the USB, the USBIS register is set. When OUT or IN packets come into the USB, the RXIS and TXIS registers are set.

    Previous Fail Case:
    An OUT packet is sent to the USB and an RXIS interrupt is generated. In the interrupt handler, the USBIS is read first, then some more work is done before reading RXIS and TXIS. So, after USBIS is read and cleared, another SOF packet comes in before RXIS and TXIS are read and cleared. This causes the interrupt level to stay high. The SOF packet is never serviced properly and was causing a hang in the USB.

    Patch:
    Shortened the time between reading the USBIS and the RXIS/TXIS reads. Modify your project so USBIntStatusControl() in usb.c also gets the status RXIS/TXIS registers (like USBIntStatusEndpoint() does) and pass that status to a USB0IntHandlerInternal(), and use that value instead of calling USBIntStatusEndpoint() again. You may need to create your own functions with these modifications and call them from USB0DeviceIntHandler().

    sal
  • Very good explanation! The solution worked!
  • Michael, Do you have any feedback? Have you experienced any hanging since the update to the USB driver and usblib??
  • It used to hang all the time when we sent data over the USB. After your update it rarely hangs, but it still seems to do it from time to time. I am interested to see if you guys do any further updates to the library.

  • We have experienced similar behavior along with some other customers. We hope to push an update to the library but first want to make sure we completely resolve the issue.

    Thank you.
  • It hung again today once out of about 10 times I used our data transfer stuff.
  • The problem is found in the usb.c driver. We will provide an update soon to the library incorporating this fix to the driverlib and usblib.


    The Problem:
    For now, I assume you have modified your code (described above) so that the USBIS, RXIS, and TXIS, registers are read from the same function and the status is stored and return from that function to be used later in the library. By doing this, we have limited the chances of a race condition setting the Flags or Status Registers. However, there is still a race condition causing the USB interrupts to stop which is causing the apparent USB hanging.


    For example, USBIS is read and cleared. Then before RXIS and TXIS are read and cleared, which would clear the USBINT in the Pie, the USBIS status register is set high again due to a SOF packet. Therefore, the USBINT is never completely cleared and thus never triggered again because there is no edge to trigger the interrupt.

    The Fix:
    Read USBIS, TXIS, and RXIS in a while or do-while loop until they are all three 0x0. This means they are all cleared before moving on in the library. Make sure to OR the status of registers when iterating through the loop in order to save the status which will be handle latter. This loop should iterate at most 3 times so the overhead is not great, especially considering eliminating the need to call USBIntStatusControl later.

    I did this in a function I called USBIntStatus which is a combination of USBIntStatusControl and USBIntStatusEndpoint.

    sal
  • Sal,
    Do you think you could send me the modified C file so I can look over the changes you made?
  • Hello, I'm interested too for an update of the usb library.

    I'm working with a Delfino TMS320F28337D and I've found the same problem with the USB communication.

    I'm working with the example USB_dev_serial CDC. When I send more than 64 bytes through the USB,

    seems interrupts to be disabled and USB communications does not recover.

    Dani.

    Regards.

  • I will describe here a solution that should be made to the existing usblib for the C28x. I will do this in a way the requires the least amount of code modification.

    1) -- Create a function called USBIntStatus() in usb.c/usb.h. This function should be called from the USB0DeviceIntHandler() in usbdhanlder.c instead of calling USBIntStatusControl().

    Here is the code for USBIntStatus...

    uint32_t
    USBIntStatusControl(uint32_t ui32Base, uint32_t * pui32EPStatus)
    {
    uint32_t ui32Status = 0;
    *pui32EPStatus = 0;
    uint32_t usbis = 0;
    uint32_t rxis = 0;
    uint32_t txis = 0;

    //
    // Check the arguments.
    //
    ASSERT(ui32Base == USB0_BASE);
    //
    // Do-While to make sure that all status registers are cleared simultaneously.
    // This eliminates the race condition which can cause the USB interrupt to stay high
    // and never get triggered again.
    //
    do
    {
    // Get the general interrupt status.
    usbis = (uint32_t)HWREGB(ui32Base + USB_O_IS);
    // Get the transmit interrupt status.
    txis = (uint32_t)HWREGH(ui32Base + USB_O_TXIS);
    // Get the receive interrupt status.
    rxis = (uint32_t)HWREGH(ui32Base + USB_O_RXIS);

    // Get the general interrupt status, these bits go into the upper 8 bits
    // of the returned value.
    ui32Status |= usbis;
    // Get the transmit interrupt status.
    *pui32EPStatus |= txis;
    // Get the receive interrupt status, these bits go into the second byte of
    // the returned value.
    *pui32EPStatus |= ((uint32_t)rxis SHIFTED LEFT BY 16); //*******Sorry, I cannot get the editor to work well
    } while(usbis != 0x0000 || txis != 0x0000 || rxis != 0x0000);

    //
    // Add the power fault status.
    //
    if(HWREG(ui32Base + USB_O_EPCISC) & USB_EPCISC_PF)
    {
    //
    // Indicate a power fault was detected.
    //
    ui32Status |= USB_INTCTRL_POWER_FAULT;

    //
    // Clear the power fault interrupt.
    //
    HWREGB(ui32Base + USB_O_EPCISC) |= USB_EPCISC_PF;
    }

    if(HWREG(USB0_BASE + USB_O_IDVISC) & USB_IDVRIS_ID)
    {
    //
    // Indicate an id detection.
    //
    ui32Status |= USB_INTCTRL_MODE_DETECT;

    //
    // Clear the id detection interrupt.
    //
    HWREG(USB0_BASE + USB_O_IDVISC) |= USB_IDVRIS_ID;
    }

    return(ui32Status);
    }

    2) -- Inside of USB0DeviceIntHandler() you need to create a variable 'uint32_t ui32EPStatus' and pass its address to the second parameter of USBIntStaus().

    3) -- Then, I suggest creating a copy of USBDeviceIntHandlerInternal() in usbdenum.c, naming it something different, and making the below changes to the function...

    void my_USBDeviceIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status, uint32_t ui32EPStaus)
    {
    ...
    // Make this change. Assign 'ui32EPStatus' to 'ui32Status' instead of the return value from USBIntStatusEndpoint().
    // Get the controller interrupt status.
    //
    //ui32Status = MAP_USBIntStatusEndpoint(USB0_BASE);
    ui32Status = ui32EPStatus;
    ...
    }


    Best Regards,
    sal
  • Sorry for the bad formatting. Also, be aware of the line above the While condition. I could not format correctly the left shift.

    sal
  • Thank you for your quick answer,


    I've implemented this solution but I will test it tomorrow because I don't have the device now.


    I have a question about this implementation.
    You create a variable ui32EPStaus to pass its address to the functions, MAP_USBIntStatus() and USBDeviceIntHandlerInternal().
    what address contains this variable?

    Regards.

    Dani

  • ui32EPStatus is just a local variable to USBDeviceIntHandler()... See point Number 2 above.

    You should pass the address to USBIntStatus(), but pass the value to USBIntHandlerInternal().

    Basically, ui32EPStatus is used as a second return value from USBIntStatus(). This variable holds the values of RXIS and TXIS of Endpoint 1, and then is passed by value to USBIntHandlerInternal(). I changed the variable name to pui32EPStatus above in the USBIntStatus function to make it more clear.
  • Thank you,
    Now I understand it.
  • Hi,

    I've implemented the solution you have proposed, in the original example USB_dev_serial
    with a Delfino TMS320F28337D and seems to work fine.
    I’ve let it running all the night sending and receiving large packets and it doesn't hang.

    Dani.

    Regards.

  • HI Sal,
    I am working on Hid Hsb communication for Piccolo F28069. I am using driver’s v141 where I have triggered the same bug. After workaround from you post, usb communication works better (longer without error) but still I can trigger an error but now only on Tx transition. Before workaround, usb communication “hanging” on Rx transmit (most of the cases) -> eEP0State = USB_STATE_RX and eHIDRxState = HID_STATE_WAIT_DATA.
    Now stop on the Tx transmit -> eEP0State = USB_STATE_STATUS and eHIDTxState = HID_STATE_WAIT_DATA, moreover sometimes communication stops, where even g_ulUSBSOFCount do not count, and another time SOFCount count the incoming frames but communication doesn’t work (USBTXIS is always 0).
    Have you found also that bug? In addition, when is plan the next release of the drivers without this bugs?
    Thanks
    Darek
  • HI Sal,

    I am working on Hid Hsb communication for Piccolo F28069. I am using driver’s v141 where I have triggered the same bug. After workaround from you post, usb communication works better (longer without error) but still I can trigger an error but now only on Tx transition. Before workaround, usb communication “hanging” on Rx transmit (most of the cases) -> eEP0State = USB_STATE_RX and eHIDRxState = HID_STATE_WAIT_DATA.

    Now stop on the Tx transmit -> eEP0State = USB_STATE_STATUS and eHIDTxState = HID_STATE_WAIT_DATA, moreover sometimes communication stops, where even g_ulUSBSOFCount do not count, and another time SOFCount count the incoming frames but communication doesn’t work (USBTXIS is always 0).

    Have you found also that bug? In addition, when is plan the next release of the drivers without this bugs?

    Thanks

    Darek

  • Hi Darek,

    Have you used the updated USBIntStatus that was implemented with a while loop in a previous post?  

    That implementation should have corrected the issue with reading and cleaing all usbis, usbrxis, and usbtxis registers so that the USBINT would reset in order that it could again be triggered and trigger the PIE.

    We are in the process of aligning the F2806x library and drivers with F2837xD.  We will have a controlSUITE release on June 17, 2015 that will update the USBLIB and usb examples in controlSUITE for F2806x so that it is consistent with the library and examples for the F2837xD.

    Hope this helps, and please continue to let us know of any bugs you may find and ask us any questions you may have?

    sal

  • Thank Sal for workaround, so far working properly.
    But I think this can be implemented even simpler. I did this like this:
    Use the same ulStatus variable to store information about TXIS and RXIS using bit15 and bit16, and later use right flag (0x8000) to read that information.

    Usb.c

    unsigned long
    USBIntStatusControl(unsigned long ulBase)
    {
    unsigned long ulStatus = 0;
    unsigned long usbis = 0;
    unsigned long rxis = 0;
    unsigned long txis = 0;

    // Check the arguments.
    ASSERT(ulBase == USB0_BASE);

    //
    // Do-While to make sure that all status registers are cleared simultaneously.
    // This eliminates the race condition which can cause the USB interrupt to stay high
    // and never get triggered again.
    //
    do
    {
    // Get the general interrupt status.
    usbis = (unsigned long)HWREGB(ulBase + USB_O_IS);
    // Get the transmit interrupt status.
    txis = (unsigned long)HWREGH(ulBase + USB_O_TXIS);
    // Get the receive interrupt status.
    rxis = (unsigned long)HWREGH(ulBase + USB_O_RXIS);

    // Get the general interrupt status, these bits go into the upper 8 bits
    // of the returned value.
    ulStatus |= usbis;
    // Get the transmit interrupt status.
    ulStatus |= ((unsigned long)txis << USB_INTEP_TX_SHIFT); //shift 15bits
    // Get the receive interrupt status
    ulStatus |= ((unsigned long)rxis << USB_INTEP_RX_SHIFT); //shift 16bits

    } while(usbis != 0x0000 || txis != 0x0000 || rxis != 0x0000);
    ……..

    And another changes for usbdenum.c in

    void
    USBDeviceIntHandlerInternal(unsigned long ulIndex, unsigned long ulStatus)
    {
    ………

    //
    // Get the controller interrupt status.
    //
    // ulStatus = USBIntStatusEndpoint(USB0_BASE);

    //
    // Handle end point 0 interrupts.
    //
    // if(ulStatus & USB_INTEP_0)
    if (ulStatus & USBTXIS_EP0_SET) // USBTXIS_EP0_SET = 0x8000
    {
    USBDeviceEnumHandler(&g_psUSBDevice[0]);
    ulStatusOK +=1;
    }
    else {
    ulStatusNotOK +=1;
    }
    ……

    This is for USB device mode EP0 and for host mode need to be done the same.
  • Hi Darek,

    Good to hear it is working.  

    I would not suggest using one variable to store all the information.  USBRXIS and USBTXIS are 16 bit registers and hold the interrupt status for multiple endpoints.  In your implementation you can easily loose data from USBTXIS that may be necessary.  If you do not have any callback function when a transmit interrupt is fired, then it could work. But this would not work as a general solution for usb.c and the usblib.

    Best Regards,

    sal