This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

USB throughput for nRF52840

I have developed USB firmware for the 840 based on the USBD example so that we can use WINUSB (WCID) for the host.  The design is for USB 2.0 full speed with EPIN1 for device to host transfers and EPOUT1 for host to device transfers The firmware passes test for 60, 64 and 192 byte tests when they are manually triggered from a Windows test tool we wrote.  I just moved onto loop testing to validate throughput and the device seems unable to work at speed with more than 64 bytes in a transfer (tested at 1 , 10 and 100 MS rates).  I've examined the descriptor file (usbd_desc.c) and the USB code (usbd.c) but can't find an issue.  I am suspicious of how I handle receive packet for NRF_DR_USBD_EPOUT2 in the event handler but it does work with the manually triggered testing.  attached is a zip of my project (I am using the template example as a base).g4_boost_snapshot_041320_0912AM_start of day.zip

  • Hi,

     

    Could you share a updated .zip file of your project, including the sdk_config? Is your printf routed to UART (this will increase latency)?

    Which SDK version are you using?

     

    Kind regards,

    Håkon

  • This problem has been mostly resolved but there are a couple of questions still.  The throughput issue is related to how packet are handled by the test tool and we have had some success in fixing it.  On the Nordic side, I was using the nrfx_usbd_ep_transfer() function incorrectly, slicing transfers up instead of just calling the function with a stable transfer buffer and blocking until the transfer completes.  In the future I may move this to a handled function to avoid blocking but the simpler implementation will do for now in this application.  I have been able to get reasonable transfer times (1.28 MS for 512 byte packets @ 4 MS; the "transfer time" is elapsed time for the stack to go back to idle after calling nrfx_usbd_ep_transfer() ).

    The delays we have been seeing seem to be related to packets falling on the EP size (ZLP?) and maybe short packets.  I noticed that ZLP handling can be enabled using a flag in the transfer data structure.  Is this normally enabled?  We also use some Atmel products and noted an improvement in performance when short packet handling was enabled.  Is there a related issue with short packets when using the Nordic USB library? 

  • Hi,

     

    I'm glad to hear that some of the issues are resolved. 

    henryh said:
    The delays we have been seeing seem to be related to packets falling on the EP size (ZLP?) and maybe short packets.  I noticed that ZLP handling can be enabled using a flag in the transfer data structure.  Is this normally enabled? 

    Zero length packets (ZLP) depends on how you send data. If your application sends larger frames, and set the packet size to be bMaxPacketSize=512, but you want to send 1024 bytes of data (1024 modulo 512 = 0), then you send a ZLP at the end to state that the transfer is finished. In the case you send 513 bytes, the next transfer is 1 byte (a short packet), so no ZLP needed in that scenario.

    If you send packets that are equal or less than bMaxPacketSize, no ZLP is needed. If larger, then yes, but only sent if size % bMaxPacketSize == 0.

    If no ZLP is sent to indicate that the transfer is complete, you'll see a "lag" in the data on the host side, where you get the former data on the current transfer, etc. It will not look as "seamless" as it should be if you are inspecting the data. Example: If you're sending data over CDC (usb serial port) and looking at it, then it looks a bit strange if you send strings with length of 2*bMaxPacketSize without ZLP.

     

    henryh said:
    We also use some Atmel products and noted an improvement in performance when short packet handling was enabled.  Is there a related issue with short packets when using the Nordic USB library? 

    Short packets should be handled. Which SDK version are you using?

     

    Kind regards,

    Håkon

  • Hi,

      

    henryh said:
    I am using v16

    That is good.

    Do you have performance issues with sizes ending up in a short packet or ZLP?

    By looking at usbd.c::usbd_send_data_to_host(), it seems that ZLP isn't handled.

    Try implementing something like this when sending:

        else
        {
          // Send data
          usb_tx_xfer.p_data.tx = buff;
          usb_tx_xfer.size = size;
    
          tx_flag = true;
          /* Check if ZLP flag should be set */
          if ((size > NRF_DRV_USBD_EPSIZE) && (size % NRF_DRV_USBD_EPSIZE == 0)) 
          {
            usb_tx_xfer.flags |= NRFX_USBD_TRANSFER_ZLP_FLAG;
          } else {
            /* ZLP not needed, in case your structure is using global memory and not stacked, we clear the .flags */
            usb_tx_xfer.flags = 0;
          }
          ret_val=nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN1,&usb_tx_xfer);
        
          ret_val=NRF_SUCCESS;
        }

     

    Kind regards,

    Håkon

Related