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.

TM4C129XNCZAD: USBHCDControlTransfer() hangs with 64-byte transfers, smaller is OK.

Part Number: TM4C129XNCZAD

I'm adding DFU Host support to a project.

DFU uses control transfers for data delivery.   USBHCDControlTransfer() supports writes to USB devices, and its working fine for small transfers.  If I write 63 bytes or less to my device, the  USBHCDControlTransfer() returns valid data.

USBHCDControlTransfer() (in usbhostenum.c)  locks out USB interrupts and then spins on the INT_EVENT_ENUM | INT_EVENT_SOF interrupt bits.   When these bits are both set, it  calls USBHCDEnumHandler(), which then calls  USBHCDEP0StateTx().   That routine sends at most 64bytes at a time to the  device.  

I need to write kilobytes of data to to the USB device. 

System Setup:

The USB interrupt is priority 0x20

Systick calls  USBHCDMain(), at priority 0x40 (lower)

I'm calling USBHCDControlTransfer() from main().   Before I call it, I disable the sytick call to USBHCDMain().    One thing I see that seems a bit odd is this code from

USBHCDControlTransfer():

USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,

                          (USB_EP_MODE_CTRL | psDevice->ui32Speed |

                           USB_EP_HOST_OUT));

Thats setting  ui32NAKPollInterval to 0.   I know from looking at USB traces that my USB device does NAK some frames.  I don't see any code that handles the timeout case.

 

 

  • Hello R Sexton,

    To piggy back off the line of code you already posted which is:

            USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
                                  (USB_EP_MODE_CTRL | USB_EP_SPEED_FULL |
                                   USB_EP_HOST_OUT));
    

    That is setting the Endpoint configuration for communication with Endpoint 0 (which is what the USBHCDControlTransfer should be attempting to send data to) to be limited to 64 bytes. This is the limit you are seeing.

    Now then the core issue here is likely that you aren't using the right API for your intended application.

    The USBHCDControlTransfer function should only be used to read/write Endpoint 0 which is the control endpoint. You shouldn't be writing kB of data to the control endpoint.

    What you likely need to be using for your application is the USB Pipes functionality. That system requires you to allocate (and free when done) pipes which communicate with specific device endpoints. From there, you can use the API's for USBHCDPipeWrite() and USBHCDPipeRead() to transfer data to endpoints.

    These details are covered in Section 3.2.3 of the TivaWare USB Library User's Guide found at [Install Path]\TivaWare_C_Series-2.1.4.178\docs and titled "SW-TM4C-USBL-UG-2.1.4.178.pdf" for the latest version of TivaWare.

  • I don't think the Pipe API is a solution. It doesn't seem to support writes to control endpoints - I need to specify the control frame contents, and supply the data payload for the data phase.

    The USB DFU protocol does all of its work with the device control endpoints, and transfer data in the control transfer data phase. Thats documented in the DFU spec ( DFU_1.1.pdf), section 4.1.2. I've got USB analyzer traces of normal behavior and I can see this. USBHCDControlTransfer() appears to support arbitrarily sized data transfers in control packets - it keeps state, counts packets, etc. It just doesn't work for more than 63 bytes.

    What I can't tell is if this code does the right thing under error conditions or NAKs. There is an event defined in usb.h - USB_HOST_EP0_NAK_TO that seems to apply, but its never used within the usblib code. I see from my traces that lots of frames get NAK'd and re-transmitted under normal operation, so setting ui32NAKPollInterval to 0 in USBHostEndpointConfig() doesn't seem like the right thing to do.
  • Also, from the datasheet, 25.3.2.3 ( OUT Transactions as a Host):

    -----------
    If the target Device responds to the OUT token with a NAK, the USB Host controller keeps retrying the transaction until the NAK Limit that has been set has been reached. However, if the target Device responds with a STALL, the USB controller does not retry the transaction but interrupts the main processor by setting the STALLED bit in the USBTXCSRLn register. If the target Device does not respond to the OUT token within the required time, or the packet contained a CRC or bit-stuff error, the USB Host controller retries the transaction. If after three attempts the target Device has still not responded, the USB controller flushes the FIFO and sets the ERROR bit in the USBTXCSRLn register.
    -------

    I can't see any evidence that the usb host code handles this case. The code spins on SOF, and stuffs more data into the FIFO, whether or not the prior attempt succeeded or is being retried.
  • More data: 

    The heart of the problem appears to be this bit of code in  USBHCDEP0StateTx():

        // If this is exactly 64 then don't set the last packet yet.

        //

        if(ui32NumBytes == 64)

        {

            // There is more data to send or exactly 64 bytes were sent, this

            // means that there is either more data coming or a null packet needs

            // to be sent to complete the transaction.

            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_OUT);

        }

        else

        {

            // Send the last bit of data.

            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_OUT);

            // Now go to the status state and wait for the transmit to complete.

            g_sUSBHEP0State.iState = eEP0StateStatusIN;

        }

    It wrongly assumes that a 64-byte transmission isn't the last.   

    This works:  

      if(g_sUSBHEP0State.ui32BytesRemaining)  // Don't send the last packet yet.

    else // Send the last packet.

  • Hello R Sexton,

    Now that I better understand your application, I looked for any past situations where there was a need to send greater than 64 bytes to a Control Endpoint for an application like yours, and haven't found anything. Not to say that such a need can't exist, but just that we haven't had such a topic come up before as it looks like no applications were done with Host mode using a Run-Time DFU Interface configuration as outlined in the DFU 1.1 spec you shared.

    There is firmware support for DFU Runtime as a USB device, in the file usbddfu-rt.c within the devices subfolder of usblib, but I don't see the same for host mode so it looks like that feature is not offered with TivaWare's USBlib.

    Also as far as the USBlib API for USBHCDControlTransfer goes, it was written to have that byte limit. I can only assume those who wrote the USBlib at the time saw no need to allow for larger packets to be sent, and also that probably was because there was a clear separation for Run-time DFU in the file system for USBlib. And yes, you are right that the Pipe API's don't support writes to Control Endpoints.

    Now that all said, I was not involved in the development of the USBlib, so I can't comment with confidence on why certain choices were made or what justification there was to them, only speculate based on what I see. At this point for the most part I just look at the code as written & documented, and try to provide guidance on what it does and how to use it. I just don't have a detailed background to explain exactly why certain decisions were made.

    And yes, I agree that the code snippet you have posted seems to be flawed with the specific case of 64 bytes.

    If you see further modifications that you feel are needed for your application, such as expanding the 64 byte limit, or adding error handling in for specific cases, I would say you are free to do so as needed, since it doesn't like like Host mode Run-Time DFU is supported.
  • Hi RS,

    R Sexton said:
    I need to write kilobytes of data to to the USB device.

    Is it possible for you to use the USB bulk device driver to accomplish large data transfers to a host in device mode?

    Tivaware USB bulk device client example project includes a MSVS2k project (Echo client) with source lines, easily modified for high speed data transfers from target GTO port up to host USB reaching 480Kbps.