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.

USB stalls request with data > 64 bytes

Greetings,

I am implementing a USB device which requires the device to respond to a class specific request on EP0 with a block of data. 

If the block is <64 bytes, all is well.  If the block is > 64 bytes, the host sees a stall.

I have implemented a HandleRequest callback to create the block and send it to  USBDCDSendDataEP0() in the library file usbdenum.c

That then calls USBDEP0StateTx(). 

That saves the count of bytes over 64, and a pointer, then calls USBEndpointDataSend() without the 'last'.

But I get a stall instead of all my data.

How are the bytes over 64 sent?  Do I have to implement another custom callback to handle them so I don't get a stall?

Gerry Belanger

  • Hello Gerard,

    The 64 bytes is the maximum number of bytes that can be transmitted by the USB at one time.  Large data blocks are generally divided up into 64 byte blocks and transmitted.

    I have not looked at the files you mentioned, but as a general rule, a pointer to you data should automatically divide it up into 64 byte transfers.

  • The usbdhid.c is reasonable example to follow. With C6748 StarterWare code as a base , something like this:

    #define MAX_DATA_SIZE 142
    unsigned char pucData[MAX_DATA_SIZE];

    static void HandleRequest(void *pvInstance, tUSBRequest *pUSBRequest)
    {
      unsigned int  ulSize = pUSBRequest->wLength;

      /* Send the smaller of the two sizes. */
      if(MAX_DATA_SIZE < ulSize)
        ulSize = MAX_DATA_SIZE;

      /* Ack the request and not data end */
      USBDevEndpointDataAck(ulUSBBase, USB_EP_0, false);
      USBDCDSendDataEP0(0, pucData, ulSize);
    }

    It works for me on the C6747. The usbdenum.c code should handle the splitting up your data into 64 packets for you. Not sure about the AM335x as it has a different USB controller.

    See the following post for possible zero length packet problems.
    http://e2e.ti.com/support/embedded/starterware/f/790/t/187908.aspx

  • Norman,

    I derived my code from the bukk device example.  The request handler was based on the HID code.  In my case, the device class request is for up to 1009 bytes.  In my HandleRequest routine, I do:

    Create the data response

    send  USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);

    then send the data:

    USBDCDSendDataEP0(0, (unsigned char *)ResponseBuf, ulSize);

    As I mentioned previously, this works fine if the response data is < 64 bytes.  My real data buffer is 92 bytes.  So the stack has to split it into chunks.

    USBDCDSendDataEP0 (in usbenum.c) saves it's parameters in a table then calls USBDEP0StateTx.  This is where the 64 byte blocking happens.

    It then calls a function to put the data in the FIFo, then calls the send function with either a tag which says whether or not this is the last packet.

    What happens i the stack after that, I am not sure.  But my 92 bytes do not get transferred, and the host detects a stall.  So at this point, I am at a loss as to how to determine whether it is something I'm doing wrong, or whether there is a bug in the stack, and if so, how to fix it.

    Gerry Belanger

  • I'd suggest trying "false" instead of "true" in the last parameter to USBDevEndpointDataAck(). If I understand the driver correctly, the flag should always be "false' as a subsequent data phase is expected and data end should be false. For some reason "true" is okay with packets 64 bytes and less.

  • Thanks Norman, that did it!

    I read the function description a couple of times, and it still makes me think receive data FIFO, not data yet to be transmitted.

    But regardless, I can now move on.

    Thanks again,

    Gerry Belanger

  • By the way, the same flag problem is in both directions for the StarterWare HID code, get or set report. I believe USBDevEndpointDataAck() ankowledges the setup packet already received and also adds a data end "hint" for data yet to be transmitted or received. In a generic driver, where a set of get request cannot be fulfilled, you'd stall endpoint instead of ack'ing it. The StarterWare HID code doesn't quite handle that.

  • Based on: StarterWare 02.00.00.07

    PROBLEM:

    When receiving a GET_REPORT request on EP0 and using a modified version of the usblib/device/usbdhidmouse.c the request stalls if the response is >64bytes (similar to the situation described above). The reason for the requests is that Linux (at least the kernels in Debian Squeeze/Wheezy) perform a GET_REPORT request on all the reports defined in the HID Report Descriptor when connecting the device to the host.

    SOLUTION:

    In usblib/device/usbdhid.c:HandleRequest, comment out the lines below to enable >64byte responses to GET_REPORT requests on EP0  as just changing the last parameter in USBDevEndpointDataAck to false did not solve the situation.

    -            USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);

    +            //USBDevEndpointDataAck(psInst->ulUSBBase, USB_EP_0, true);
     
                 //
                 // ..then send back the requested report.
                 //
    -            psInst->bGetRequestPending = true;
    +            //psInst->bGetRequestPending = true;

    QUESTION:

    Does this seem like a valid solution? It works for all response sizes, but can this break something else that I have not come across yet?