This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Flow control of BULK OUT endpoint

Hi All,

I've got an issue with flow control of a bulk OUT endpoint I'm struggling with. I'm using the NXP LPC1343, and the device code is based on their CDC class example. On the Host side, I'm using linux with libusb to do usb_bulk_write().

When there is data available on the endpoint, I USB_ReadEP() it out into a circular buffer IF I've got room in that buffer. If there's no room (ie the device is still processing old data), I don't do the USB_ReadEP() and hence the CMD_CLR_BUF bit does not get set in the peripheral. I would have expected the Host to retry sending that packet some time later, at which point I would have room and read the endpoint and everyone would be happy.

In the case where I dont read the endpoint on the device, the Host call to usb_bulk_write() function times out (even when I set the timeout to many seconds), and when I try to retry sending the packet again, it will always timeout. I can see at this time there are no interrupts being generated from the USB peripheral...

Am I going about flow control the wrong way here? Any advice would be greatly appreciated.

Thanks,
Peter

  • > When there is data available on the endpoint, I USB_ReadEP() it out into a circular buffer IF I've got room in that buffer. If there's no room (ie the device is still processing old data), I don't do the USB_ReadEP() and hence the CMD_CLR_BUF bit does not get set in the peripheral.

    It's right on the rail, so far. But,

    > I would have expected the Host to retry sending that packet some time later, at which point I would have room and read the endpoint and everyone would be happy. ... I can see at this time there are no interrupts being generated from the USB peripheral

    This is a wrong assumption.
    On the device side, the endpoint interrupt occurs just when a transaction completes successfully. But as the endpoint buffer is still occupied by the last transaction, the endpoint keeps NAKing to the OUT transactions. You have to call USB_ReadEP() to unload the data from the endpoint buffer, to receive the next transaction. The bulk endpoint has double buffer. It may keep two transactions, at most, pending on the buffer.

    The outline of the code flow is as follows, based on USBCDC example of this samples.

    Sample Code Bundle for LPC13xx Peripherals using Keil's MDK-ARM V1.06 (Jun 8, 2011)
    ics.nxp.com/.../code.bundle.lpc13xx.keil.zip

    1) A global variable, say U8 bulk_out_count, is declared and initialized to 0.
    2) bulk_out_count is cleared in Set_Configuration handler

    usbuser.c
    
    #if USB_CONFIGURE_EVENT
    void USB_Configure_Event (void) {
    
      if (USB_Configuration) {                  /* Check if USB is configured */
        /* add your code here */
        bulk_out_count = 0;      // <---------
      }
    }
    #endif
    

    3) Read out bulk transaction in CDC_BulkOut(), when there is enough room for the packet. Else, count up bulk_out_count.

    cdcuser.c
    
    void CDC_BulkOut(void) {
      int numBytesRead;
    
      if ( _there_is_room_on_the_buffer_ ) {
        // read out the data to the buffer using USB_ReadEP()
      } else {
        ++bulk_out_count;
      }
    }
    

    4) The buffer is periodically checked in SOF handler.

    usbcfg.h
    
    #define USB_SOF_EVENT       1
    
    usbuser.c
    
    #if USB_SOF_EVENT
    void USB_SOF_Event (void) {
      if ( bulk_out_count ) {
        // check the room on the buffer
        // if there is enough room, read a packet using USB_ReadEP()
        // and decrement bulk_out_count by one
      }
    }
    #endif
    

    Tsuneo

  • Hi Tsuneo,

    Thanks very much for the reply, nice idea putting the check in the SOF event handler.

    By doing bulk_out_count++ it seems I get 1 more bulk_out_count than necessary, and get stuck in USB_ReadEP() in this loop:

    
        do
        {
            cnt = LPC_USB->RxPLen;
        }
        while ((cnt &PKT_DV) == 0);
    
    

    By changing bulk_out_count++ to bulk_out_count=1 in CDC_BulkOut() things are working really well.

    Thanks again,
    Peter