USB driver : setting 'high-speed' causes assert to fail for MSC subsys as NRF_USBD_COMMON_EPSIZE is fixed at 64!

Using NCS 2.9.0, Zephyr 3.7.99 on a custom nrf5340 board, I want to have multiple functions enabled on the USB interface : zephyr supplied MassStorage (msc), virtual UART (CDC-ACM), and my own custom CCID class for smartcard access.

I have managed to navigate the endpoint address maze (hint : the zephyr usb stack ALWAYS fixes up the endpoint addresses to avoid conflict between classes as per https://docs.zephyrproject.org/3.7.0/connectivity/usb/device/usb_device.html#implementing-a-non-standard-usb-class), and avoided running out of endpoints by configuring  num-in-endpoints/num-out-endpoints for the usbd device in the DTS (see below). And to get the usb_transfer() function not to run of 'slots' by setting CONFIG_USB_MAX_NUM_TRANSFERS=8 instead of 4 (would have been nice to put that info in the doc guys...)...

However, in the same device config I also set the USB speed to be 'high-speed':

zephyr_udc0: &usbd {
    compatible = "nordic,nrf-usbd";
    /* IN : 2 per uart =4 + 1 per MSC + 2 per CCID = 7 + spare = 8*/
    num-in-endpoints = <8>;
    /* OUT : 1 per uart = 2 + 1 per MSC + 1 per CCID = 4 + spare = 5 */
    num-out-endpoints = <5>;
    maximum-speed = "high-speed";
    status = "okay";
};

The aim is get the MSC and ACM operations to be faster (eg file copies, or doing DFU using mcuboot over usb serial) by having the USB MPS to be 512 bytes intead of default 64. The KConfig keys for these are not settable in prj.conf, but set depending on the USB bus speed in Kconfig.cdc/Kconfig.msc (conditioned by USB_DC_HAS_HS_SUPPORT)
So, I set  CONFIG_USB_DC_HAS_HS_SUPPORT=y  to enable this.
However, this then causes the usb setup to assert in
zephyr/drivers/usb/common/nrf_usbd_common/nrf_usbd_common.c :nrf_usbd_common_ep_max_packet_size_set()
as the MSC packet size of 512 is greater than the hardcoded value of NRF_USBD_COMMON_EPSIZE in the header file.
I don't see any mechanism to configure NRF_USBD_COMMON_EPSIZE based on the bus speed? How can I enable high-speed for the nrf USB driver and set CONFIG_USB_DC_HAS_HS_SUPPORT to use the MSC/CDC-ACM classes with the bigger buffers? 
Any ideas other than just hacking the nrf_usbd_common.h?
Parents Reply Children
  • Hi

    Ok... My device is supposed to be in mass production (just blocked by firmware issues like this...), so not an option to switch to a new chip, especially one that is 'experimentally supported'....

    So then can you tell me:

    - why doesn't the DTS config fail when I set 'high-speed' as this is not supported on nrf5340?

    - why doesn't the Kconfig check fail for CONFIG_USB_DC_HAS_HS_SUPPORT=y (its usually not shy about complaining about config values it feels are in conflict)

    - without setting HAS_HS_SUPPORT, how can I set the Kconfig values to get more efficient USB transfers

    CONFIG_MASS_STORAGE_BULK_EP_MPS=512
    and
    CONFIG_CDC_ACM_BULK_EP_MPS=512
    - what would be the 'right' way to set NRF_USBD_COMMON_EPSIZE?
    thanks
  • USB full speed only supports up to 64 bytes bulk endpoint size, and those are AFAIK not double-buffered on NRF5340.

    I can read about 100kByte/sec from an SD card with a direct USB connection to a PC. Speed increases to ~300kB/sec with an USB hub in between host and device (USB 2.0 hub). 

  • USB full speed only supports up to 64 bytes bulk endpoint size

    Ah ok, thanks! I'm new to implementing custom USB devices as I've only used the existing ACM and MSC classes up to now.

    I had previously applied a patch for cdc_adm in zephyr as recommended for faster serial download in mcuboot:

    - USB CDC_ACM buffer size (for optimal serial download as recommendant in the mcumgr client) : update zephyr/subsys/usb/device/class/cdc_acm.c line 74:
    //#define CDC_ACM_BUFFER_SIZE (CONFIG_CDC_ACM_BULK_EP_MPS)
    #define CDC_ACM_BUFFER_SIZE (512)
    which had led me into error of confusing the EP bulk size and the internal buffer size... I was hoping upping the size would speed up the MSC speed...
  • Hi BrianW,

    BrianW said:

    - why doesn't the DTS config fail when I set 'high-speed' as this is not supported on nrf5340?

    - why doesn't the Kconfig check fail for CONFIG_USB_DC_HAS_HS_SUPPORT=y (its usually not shy about complaining about config values it feels are in conflict)

    Both are very valid questions. Those facts bugged me too when I looked into the case yesterday.

    Let me try to ask our developers who work with Zephyr to see if they have any insight.

    BrianW said:

    - without setting HAS_HS_SUPPORT, how can I set the Kconfig values to get more efficient USB transfers

    CONFIG_MASS_STORAGE_BULK_EP_MPS=512
    and
    CONFIG_CDC_ACM_BULK_EP_MPS=512
    - what would be the 'right' way to set NRF_USBD_COMMON_EPSIZE?

    It is simply not possible, and 64 is the maximum for USB Full Speed, like Turbo J pointed out.

    This is specified in the USB 2.0 Specifications, section 5.8.3, Bulk Transfer Packet Size Constraints:

    An endpoint for bulk transfers specifies the maximum data payload size that the endpoint can accept from or transmit to the bus. The USB defines the allowable maximum bulk data payload sizes to be only 8, 16, 32, or 64 bytes for full-speed endpoints and 512 bytes for high-speed endpoints.

  • Hi BrianW,

    Hieu said:
    BrianW said:

    - why doesn't the DTS config fail when I set 'high-speed' as this is not supported on nrf5340?

    - why doesn't the Kconfig check fail for CONFIG_USB_DC_HAS_HS_SUPPORT=y (its usually not shy about complaining about config values it feels are in conflict)

    Both are very valid questions. Those facts bugged me too when I looked into the case yesterday.

    Let me try to ask our developers who work with Zephyr to see if they have any insight.

    I have some explanations from our developer. It turns out that the high-speed support in the legacy USB stack is... inadequate; and what we are seeing is a part of the several problems.

    That is why we invest effort into the USB Next stack to support USB High Speed with the newer devices instead.


    Regarding optimizing transfer speed, our developer recommends maximizing the CDC_ACM buffer size like you are already doing (CONFIG_USB_CDC_ACM_RINGBUF_SIZE); and use the UART Interrupt API instead of the Async API.

Related