cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 USB HID Packet Loss

justinwoolich
Associate III
Posted on February 04, 2014 at 16:48

Hi,

I have a STM32F107 and i have implemented a USB HID application to send data back to the host computer. The data transfers are working well for periodic transfers but when i try to send a lot of packets one after the other in a tight loop packets are being lost on the host side.

I have tried implementing a delay between sending packets, and this works but it causes problems as i have to wait 5ms between each packet to avoid data loss.

Has anyone come across this issue or would you have any ideas on what i could try to resolve this issue?

#usb #hid
4 REPLIES 4
chen
Associate II
Posted on February 04, 2014 at 17:46

Hi

I just googled ''windows max USB HID rate'' to find out just how fast you can send HID data.

It appears it is 125Hz (if you believe some random URL about gamers)

''I have tried implementing a delay between sending packets, and this works but it causes problems as i have to wait 5ms between each packet to avoid data loss.''

Even with this delay - you are on the limits of what is possible for HID device.

jzawadzk
Associate II
Posted on February 04, 2014 at 20:10

Do you wait with putting new data into endpoint until you are sure that host has successfully received previous packet (= when EPX_IN_Callback is called)?

Windows can poll interrupt endpoint at 1ms rate (at least in case of USB Keyboard class)

justinwoolich
Associate III
Posted on February 05, 2014 at 03:18

Thanks for your responses, i thought the endpoint polling happened every 1ms as well, i tried adding the EPX_TxSent call back to the USBD_Class_cb_TypeDef structure for the HID class but it only seems to get called for multi packet transfers

from usbd_core.c

static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum)

{

  USB_OTG_EP *ep;

  

  if(epnum == 0) 

  {

    ep = &pdev->dev.in_ep[0];

    if ( pdev->dev.device_state == USB_OTG_EP0_DATA_IN)

    {

      if(ep->rem_data_len > ep->maxpacket)

      {

        ep->rem_data_len -=  ep->maxpacket;

        if(pdev->cfg.dma_enable == 1)

        {

          /* in slave mode this, is handled by the TxFifoEmpty ISR */

          ep->xfer_buff += ep->maxpacket;

        }

        USBD_CtlContinueSendData (pdev, 

                                  ep->xfer_buff, 

                                  ep->rem_data_len);

      }

      else

      { /* last packet is MPS multiple, so send ZLP packet */

        if((ep->total_data_len % ep->maxpacket == 0) &&

           (ep->total_data_len >= ep->maxpacket) &&

             (ep->total_data_len < ep->ctl_data_len ))

        {

          

          USBD_CtlContinueSendData(pdev , NULL, 0);

          ep->ctl_data_len = 0;

        }

        else

        {

          if((pdev->dev.class_cb->EP0_TxSent != NULL)&&

             (pdev->dev.device_status == USB_OTG_CONFIGURED))

          {

            pdev->dev.class_cb->EP0_TxSent(pdev); 

          }          

          USBD_CtlReceiveStatus(pdev);

        }

      }

    }

  }

  else if((pdev->dev.class_cb->DataIn != NULL)&& 

          (pdev->dev.device_status == USB_OTG_CONFIGURED))

  {

    pdev->dev.class_cb->DataIn(pdev, epnum); 

  }  

  return USBD_OK;

}

krutecki
Associate II
Posted on February 07, 2014 at 13:56

Hi guys

I was fighting with the same issue for few days. Now it`s working well. Maybe I can help.

1. First of all How do you received reports on PC? Here can be an issue (HidD_SetNumInputBuffers) - look

https://github.com/signal11/hidapi/issues/159

if you are using HIDAPI like me. It was my case.

2. Sending side I`ve build the same way how CDC is done - first packet kick out manually, the rest in callbacks. Data to send I`m having in simple FIFO.

My Custom HID work like CDC but driverless. Speed is limited by interrupt endpoint only. Firmware runs under FreeRTOS so semaphores do the job. The same functions can be call over HID as well as CDC (simple shell on the top). Simple and elegant solution 🙂

Chris