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.

TM4C123GE6PM: Issue with USB HID Handler for Endpoint 0

Part Number: TM4C123GE6PM

Hello,

I recently upgraded to the Tiva C driver library 2.1.4.178 and it seems to have broken my product's USB interface that was based on the 1.0.x USB driver library.  I'm trying to debug this issue and cannot find the source file usbdevice.c.  I go from

USBDHIDInit(0, &g_sHIDDataPipeDevice);

which is in my main.c file (main c code file of my project) to the below

    //
    // All is well so now pass the descriptors to the lower layer and put
    // the HID device on the bus.
    //
    USBDCDInit(ui32Index, &psHIDDevice->sPrivateData.sDevInfo,
               (void *)psHIDDevice);

I then try to view the USBDCDInit(); function and get stuck at usbdevice.h header file and cannot find the source file anywhere in the driver library.  Does anyone know what is going on here?

Note: I accidentaly flagged this as spam when I tried to edit it.  Please disregard as this is NOT spam.

  • The source for USBDInit() is in the file: C:\ti\TivaWare_C_Series-2.1.4.178\usblib\device\usbdenum.c
  • Hello Robbie,

    Not sure what your specific issue is, but if it's related to recognition of your USB device with Windows machines (particularly Windows 10) then you need to make sure to use the patch drivers we supplied outside of the main TivaWare install. They can be downloaded from: software-dl.ti.com/.../SW-TM4C-2.1.4.178.PATCH-1.0.zip

    Also the reason that you can't trace beyond the .h file is because of how .lib files are used for the driver libraries, so CCS doesn't have a route beyond the .h file to follow based on that. You will have to navigate through the C:\ti\TivaWare_C_Series-2.1.4.178\usblib folder to find various files to read the source, but you won't be able to place breakpoints etc. into them unless you unlink the .lib file and then include the whole folder for the library into your project.
  • Hi guys,

    Thank you for the quick response! As for where the usbdevice.c file is yes. I will test those drivers tonight or this weekend and get back to you. I didn't realize I needed this driver patch.

    Does this mean all of my customers need to install this patch as well? I initially chose the HID device route because it alleviated any need for software driver fiddling.
  • Hi Robbie,

    It may depend on how your descriptors are set up. The default method we used for TI examples for TivaWare didn't work well with Windows 10 for some applications, so that is what the patch driver fixes (for the most part, the composite example is having a separate application related issue).

    If your descriptors are made in a way that Windows 10 accept them correctly, then you shouldn't have any issues.

    As a HID device, I think you have low risk of being impacted by the Windows 10 changes, but again if there is an issue with Windows actually recognizing the device because of descriptors etc. - then I would suggest to try the updated patch drivers and find out if that resolves the issue or not.

    Even if it does, you may be able to modify your HID Device application to properly output the descriptors that Windows 10 is expecting, and thus avoid needing to push a driver update out.
  • Hi Ralph,

    Thank you for the response.  I actually seem to enumerate ok on Windows 10.  I can successfully send the first his report correctly to the mcu and I see the data is received correctly by viewing it in the debugger.    When I resend this message a second or third time I see the usb rx interrupt handler trigger but I get no response and eventually the link dies.  If I plug in a product that was not upgraded to the 2.0 tivaware library but was programmed on a different computer using 1.x (I don't remember the exact number)  this link works fine, all data is transferred correctly and my usb link never locks up no matter how much I spam the device.

    Due to this, I'm trying to trace through the driver library api and figure out what has changed.  It doesn't look like this is a Windows problem as much as a driver library problem since my old products built on the old old driver library work great.  

    I noticed also whem upgrading that some of my peripheral driver calls changed and I had to fix them so this leads me to believe that the same issue (although more subtle) exists in the usb driver code in this driver library version/upgrade.

  • Hi Robbie,

    If that's the case then I agree that the issue is beyond a Windows 10 driver snag. I never worked with the prior versions of the USB library so I can't comment on all the changes made, but I would recommend you read through the Release Notes documentation we have if you haven't done so already.

    It can be found in the docs folder of the TivaWare install, titled SW-TM4C-RLN-2.1.4.178.pdf

    Searching for "USB Library" would bring up most if not all the USB library changes. Perhaps that would help you track down what you need to solve the issue since I do agree that it seems to be related to a modification to the USB library.
  • What code to the RX and TX USB hid handlers get passed to? How do I find the code that is handling the USB receive messages. I'm seeing the RXHandler hit the USBD_HID_EVENT_GET_REPORT_BUFFER case every time and then the USBD_HID_EVENT_SET_REPORT case. Unfortunately after a few messages my RXHandler only hits the USBD_HID_EVENT_GET_REPORT_BUFFER and then hangs.

    For the HID device class TI's documentation says it should request the buffer with the USBD_HID_EVENT_GET_REPORT_BUFFER, store the data in the buffer i return and then call the USBD_HID_EVENT_SET_REPORT case which will tell my main program that data is available in the buffer. I need to figure out why the USBD_HID_EVENT_SET_REPORT case gets dropped.

    I'm confused as to where the source code is that is handling all this.
  • Hello Robbie,

    I think the following comment block fromt he usbdhid.c file will be helpful for you in understanding the architecture of the TX and RX and also where the status' you are seeing originate from:

    //*****************************************************************************
    //
    //! Initializes HID device operation for a given USB controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized for HID device operation.
    //! \param psHIDDevice points to a structure containing parameters customizing
    //! the operation of the HID device.
    //!
    //! An application wishing to offer a USB HID interface to a host system
    //! must call this function to initialize the USB controller and attach the
    //! device to the USB bus.  This function performs all required USB
    //! initialization.
    //!
    //! On successful completion, this function will return the \e psHIDDevice
    //! pointer passed to it.  This must be passed on all future calls from the
    //! application to the HID device class driver.
    //!
    //! The USB HID device class API offers the application a report-based transmit
    //! interface for Input reports.  Output reports may be received via the
    //! control endpoint or via a dedicated Interrupt OUT endpoint.  If using the
    //! dedicated endpoint, report data is delivered to the application packet-by-
    //! packet.  If the application uses reports longer than \b USBDHID_MAX_PACKET
    //! bytes and would rather receive full reports, it may use a USB buffer above
    //! the receive channel to allow full reports to be read.
    //!
    //! Transmit Operation:
    //!
    //! Calls to USBDHIDReportWrite() pass complete reports to the driver for
    //! transmission.  These will be transmitted to the host using as many USB
    //! packets as are necessary to complete the transmission.
    //!
    //! Once a full Input report has been acknowledged by the USB host, a
    //! \b USB_EVENT_TX_COMPLETE event is sent to the application transmit callback
    //! to inform it that another report may be transmitted.
    //!
    //! Receive Operation (when using a dedicated interrupt OUT endpoint):
    //!
    //! An incoming USB data packet will result in a call to the application
    //! callback with event \b USB_EVENT_RX_AVAILABLE.  The application must then
    //! call USBDHIDPacketRead(), passing a buffer capable of holding the received
    //! packet.  The size of the packet may be determined by calling function
    //! USBDHIDRxPacketAvailable() prior to reading the packet.
    //!
    //! Receive Operation (when not using a dedicated OUT endpoint):
    //!
    //! If no dedicated OUT endpoint is used, Output and Feature reports are sent
    //! from the host using the control endpoint, endpoint zero.  When such a
    //! report is received, \b USBD_HID_EVENT_GET_REPORT_BUFFER is sent to the
    //! application which must respond with a buffer large enough to hold the
    //! report.  The device class driver will then copy the received report into
    //! the supplied buffer before sending \b USBD_HID_EVENT_SET_REPORT to indicate
    //! that the report is now available.
    //!
    //! \note The application must not make any calls to the low level USB device
    //! interface if interacting with USB via the USB HID device class API.  Doing
    //! so will cause unpredictable (though almost certainly unpleasant) behavior.
    //!
    //! \return Returns NULL on failure or the \e psHIDDevice pointer on success.
    //
    //*****************************************************************************

  • Sorry, ended up hitting post too early on accident, more details I meant to add:

    Depending on the device you are acting as, you may need to make your own RXHandler for all the cases described. The documentation comments guide you on what is needed, but not all of that is handled by the USB Stack.

    For example, we do have an RXHandler for the Keyboard application which is within the API HIDKeyboardRxHandler. That might be an important resource for you to reference. There are also handler's for the Mouse and Gamepad examples too, but the Keyboard one has the most meat to it.

    Lastly, the HandleRequest API in usbdhid.c also uses the USBD_HID_EVENT_GET_REPORT_BUFFER status, though that API is for non-standard requests so it may not be applicable for your use case.

  • Hi Ralph,

    Thank you for the response.  I have gone through what you recommended actually.  My situation is strange in that my firmware worked fine with the usbdriverlib 1.0 but upon upgrading to driver library 2.1 it broke.  I've checked the release notes and don't see anything suspect in there.

    I'm sending a message from my software application over control endpoint 0 (hid device) to the tiva part.  The tiva/ firmware should respond on endpoint 1 with the response to that message.

    I recorded the traffic last night and found that  when I send the message now, the driver library automatically responds to the message from software on endpoint 0.  The firmware then responds with the valid data on endpoint 1 as well.  When the link dies it looks like it is because the response on endpoint 0 (which I'm not intending to send) takes too long and times out.  

    I guess my first question is: should I make a new post for this as I think I've honed in on the issue?

    Second,  why would the driver library be responding to a set report event in my RXhandler() when I'm not actually using a send packet or usbwrite() function on endpoint 0.  If the host does a set report buffer /set report on endpoint 0 does the device have to respond to that on endpoint 0?

  • Hello Robbie,

    Hmm, interesting you bring up Endpoint 0 specifically. When I was going through the code I noticed something regarding that but I didn't think it was a fair assumption to make that you were specifically dealing with Endpoint 0.

    Take a look at the HandleEP0DataReceived API within usbdhid.c, that is called by the USB stack when concerning data received on endpoint zero. At the end of the API, it has the following code block:

        //
        // The only things we ever request via endpoint zero are reports sent to
        // us via a Set_Report request.  Pass the newly received report on to
        // the client.
        //
        psHIDDevice->pfnRxCallback(psHIDDevice->pvRxCBData,
                                   USBD_HID_EVENT_SET_REPORT,
                                   psInst->ui16OutReportSize,
                                   psInst->pui8OutReportData);

    Perhaps that could be what is causing your issue?

    As far as thread goes... I can edit the topic title for this thread to better reflect the core discussion.

  • Ralph,

    Thank you for updating the title and thanks for the reply! 

    This is the source I was looking for.  It seems to make sense though.  Per TI's documentation, when I send a message over endpoint 0 I should see an interrupt on my callback with this event type USBD_HID_EVENT_GET_REPORT_BUFFER.  Once this happens I should immediately see my RxHandler get called again with this event USBD_HID_EVENT_SET_REPORT.  I believe the code you found is the code that calls my RxHandler the second time to return the data in endpoint 0.  I will spend some more time digging into usbhid.c and see if I can make some more progress.

    In the mean time I logged the traffic on the USB hub the Tiva part is connected too.  I have one Tiva running version1.x of the USB driver library.  I have a second devie that is the same hardware design, but running the updated driver library 2.1.4.178.  I have attached the two logs in case you want to check them out.  I dont' know if they uploaded correctly.  I tried the paper clip link, but they were inserted with huge folder images.

    Log4.pcap

    log4.zip

    Log5.pcap

    log5.zip

    Anyways, you can open those log files up in wire shark and see the traffic.  In the filter section you can use the usb.device_address == 11 for log5 to get rid of all the other traffic and see the traffic from the working device.  Log5 is the setup that works fine and the usb link never crashes.  The device sends a message back to software/PC constantly that is a 0x3f08.....packet.  This is irrelevant.  The relevant packet starts with 0x3f02.  The message works as follows:

    Software sends a 0x3f02 packet to the tiva part.  The tiva part is supposed to respond with a 0x3f02 [bytes of data] on endpoint 1.  This is a response from my main software loop in the Tiva part on ep1.  For some reason though, the tiva part actually responds with a 0x3f02fffffff... packet on ep0 and then the expected packet 0x3f02[data] on ep1.  With the old driver library this is consistent and works all day long.  Here is a screen shot of one of the messages in the log.

    I hope that is readable :/

    For log4 use usb.device_address == 17 as the filter option shown in screenshot below:

    Log 4 shows the device that is running the latest driverlib using the latest usb driver library.  This device has a USB link timeout after I send a couple (2-15) messages back to back.  The messages in these two examples are exactly the same.  I've noticed that there is a point where there is no automatic response on ep0 and I'm thinking that causes the USB link to lock up. 

    Here is a screen shot showing the traffic and the missing ep0 response.

    When looking at the traffic with the old driverlib (v1.x) it looks like - when my software app sends the Tiva a message on ep0 the Tiva driver responds with an echo or something on that end point AND the call back works as expected allowing me to throw a flag in my RxHandler and tell my main loop to send a packet of data over ep1 in response to the message as well.

    When looking at the traffic with the latest driverlib (version number above), after a few messages the Tiva driver no longer responds on ep0 and the usb link times out. 

    This is my RxHandler() funciton that I pass to the driver as a receive data handler.

    // Receive handler
    uint32_t
    RXHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData,
                    void *pvMsgData)
    {
    
    	//WTimer0_Set_Counter(/*counter*/ 80000000/10);		// Attempt to fix rate problem with deepsleep() mode
    
        // Debug info
        static int countRXAvailable=0;
        // static int countTXAvailable=0;
        static int countIdleTimeout=0;
        static int countGetReportBuffer=0;
        static int countGetReport=0;
        static int countSetReport=0;
        static int countDefault=0;
        //static uint32_t eventList[20];
        static int eventListIdx=0;
        // End debug vars
        uint32_t readPacketSize;
        //uint32_t writePacketSize;
        //uint32_t retCode;
        //tDataBuffer * myData = pvCBData;
    
        //Debug info
        //eventList[eventListIdx++]=ui32Event;
        if(eventListIdx==20)
            {
                eventListIdx=0;
            }
    
        switch(ui32Event)
        {
        case USB_EVENT_CONNECTED:
            USBState|=1;
    
            // Change USB priority level so it doesn't interfere with ADC when running
            IntPrioritySet(INT_USB0, 0x60);
            USB_Enumerated = 1; // Flag showing USB connected or disconnected
    
            break;
        case USB_EVENT_DISCONNECTED:
            USBState&=0xfe;
            USB_Enumerated = 0;	// Flag showing USB connected or disconnected
    
            break;
        case USB_EVENT_RX_AVAILABLE:
            countRXAvailable++;
            // Untested code
    #if 0
            // Handle set report on the OUT endpoint
            readPacketSize=USBDHIDRxPacketAvailable(&g_sHIDDataPipeDevice);
            if(readPacketSize==0)
            {
                    _nop();//Shouldn't happen
            }
            writePacketSize=USBDHIDPacketRead(&g_sHIDDataPipeDevice,
                    myData->buffer,
                    MAX_PACKET_SIZE
                    ,1);
            if(writePacketSize==0)
            {
                _nop();//Shouldn't happen
            }else if (writePacketSize!=readPacketSize)
            {
                _nop();//Shouldn't happen
            }
            // TODO, may need to wait here for tx available.
            retCode=USBDHIDTxPacketAvailable(&g_sHIDDataPipeDevice);
            if(writePacketSize==0)
            {
                _nop();//Shouldn't happen
            }
            // Echo it out
            retCode=USBDHIDReportWrite(&g_sHIDDataPipeDevice, myData->buffer, writePacketSize,1);
            if (writePacketSize!=readPacketSize)
            {
                _nop();//Shouldn't happen
            }
            return 0;
    #endif
            break;
        case USBD_HID_EVENT_IDLE_TIMEOUT:
            // Not defining a timeout.
            countIdleTimeout++;
            break;
    
        case USBD_HID_EVENT_GET_REPORT_BUFFER:
        	// Return Rx buffer to usb driverlib so
        	// the report can be stored
            countGetReportBuffer++;
            // TODO: Check report id
    
            readPacketSize=(uint32_t)pvMsgData;
            if(readPacketSize>MAX_PACKET_SIZE)
                {
                    _nop(); //Shouldn't happen
                }
    
            return((uint32_t)RXData.buffer);
            break;
        case USBD_HID_EVENT_GET_REPORT:
        	// Host is requesting a particular report
            countGetReport++;
            break;
        case USBD_HID_EVENT_SET_REPORT:
        	// Report receive buffer is ready to
        	// be read.
            countSetReport++;
            // TODO: check report ID
            //set size to let the application know that there is data.
            RXData.size=(uint16_t) (ui32MsgData&0xffff);
            RXData.state=1;
    
            if(RXData.buffer[1] == 0x03){
    
            	BurstMode_Unlock = 1;
    
            }
            break;
    
        // sounds like this is required by the new driver
        case USB_EVENT_SUSPEND:
            break;
    
        // sounds like this is required by the new driver
        case USB_EVENT_RESUME:
            break;
    
        // added this trying to debug new USB comm bug - 1/15/2018
        case USB_EVENT_ERROR:
                while(1);
    
            break;
    
        default:
            countDefault++;
            break;
        }
    
        // Pretty sure default return should be 0. Need to verify
        return 1;
    
    }

    This problem is also not consistent regarding number of messages sent.  It changes so sometimes it fails after 2, 5, 7, 11 etc...  It does seem like spamming them faster brings the issue out faster, but I can't really verify as this is too inconsistent.

    I've attached a zip of the screenshots I inserted in case the quality is bad.

    TrafficScreenShots.zip

    I'll continue digging, but I thought maybe you guys could glean something out of the traffic and responses of the part.

    Thanks again for you support Ralph, I really appreciate it!

  • For future reference to someone having this same problem - I could not figure out how to send data over the EP0 so I had to support 3 endpoints. ep0 for configuration, ep1 in, ep2 out.