Multiple USB CDC ACM instances, different product strings

Hi,

I have an application that uses multiple CDC ACM instances, please see devicetree excerpt below:

&zephyr_udc0 {
	// NUS
	cdc_acm_uart0 {
		compatible = "zephyr,cdc-acm-uart";
	};

	// console
	cdc_acm_uart1: cdc_acm_uart1 {
		compatible = "zephyr,cdc-acm-uart";
	};

	// mcumgr
	cdc_acm_uart2: cdc_acm_uart2 {
		compatible = "zephyr,cdc-acm-uart";
	};
};

As can be seen I use the NUS (Nordic Uart Service) port for the first instance, general debug info for the second and Mcumgr for the third. All of the USB instances are working, my problem is to easily detect which is which. Then enumeration of the COM ports are not in order always so I cannot use that. Ideally if I could use different product strings for each port that will work great (ex. CONFIG_USB_DEVICE_PRODUCT="Pager Dongle"). Is there a way to assign different product strings to each COM port programmatically in Zephyr? I have also tried using the command in the cmdline (Windows 11): reg query HKLM\HARDWARE\DEVICEMAP\SERIALCOMM. Although I get USBSER000 to USBSER002 it is still not guarenteed to be in the order as my devicetree (differs between devices). Only thing that potential can work is the PID info, there seems to be an underscore _00,_03,_05, etc. But I have not checked if it works across multiple devices.

I know about inf files, but is there any other way to get the associated CDC port to a COM port? (Preferably somthing you can change in the firmware in Zephyr to identify which COM port is which, does not neccessarily have to be in the Device Manager string).

Thanks in advance.

Kind Regards

Julian

Parents Reply Children
  • Hi Sigurd,

    Hope you are doing well. Any update on the above?

    Kind Regards

    Julian

  • Hi,

    I forgot to set this case status back to "open" after answering previously, and forgot it. Sorry.

    So I had a look at the usb console sample, and see that it defines descriptors.
    Then it adds those for a DTS object using usbd_add_descriptor.

    I use linux and lsusb to test with, but I assume that you can see this with something equivalent in windows.

    First I added this to the console sample:

    CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor ASA"
    CONFIG_USB_DEVICE_VID=0x1915
    

    From "lsusb -v" after flashing the usb console sample:

    Bus 001 Device 019: ID 1915:0004 Nordic Semiconductor ASA 
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               2.00
      bDeviceClass            0 
      bDeviceSubClass         0 
      bDeviceProtocol         0 
      bMaxPacketSize0        64
      idVendor           0x1915 Nordic Semiconductor ASA
      idProduct          0x0004 
      bcdDevice            3.03
      iManufacturer           1 Nordic Semiconductor ASA
      iProduct                2 Zephyr USB console sample
      iSerial                 3 8385276BF7E8AF2C
      bNumConfigurations      1
      Configuration Descriptor:
        bLength                 9
        bDescriptorType         2
        wTotalLength       0x004b
        bNumInterfaces          2
        bConfigurationValue     1
        iConfiguration          0 
        bmAttributes         0xe0
          Self Powered
          Remote Wakeup
        MaxPower              100mA
        Interface Association:
          bLength                 8
          bDescriptorType        11
          bFirstInterface         0
          bInterfaceCount         2
          bFunctionClass          2 Communications
          bFunctionSubClass       2 Abstract (modem)
          bFunctionProtocol       0 
          iFunction               0 
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        0
          bAlternateSetting       0
          bNumEndpoints           1
          bInterfaceClass         2 Communications
          bInterfaceSubClass      2 Abstract (modem)
          bInterfaceProtocol      0 
          iInterface              0 
          CDC Header:
            bcdCDC               1.10
          CDC Call Management:
            bmCapabilities       0x02
              use DataInterface
            bDataInterface          1
          CDC ACM:
            bmCapabilities       0x02
              line coding and serial state
          CDC Union:
            bMasterInterface        0
            bSlaveInterface         1 
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x81  EP 1 IN
            bmAttributes            3
              Transfer Type            Interrupt
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0010  1x 16 bytes
            bInterval              10
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        1
          bAlternateSetting       0
          bNumEndpoints           2
          bInterfaceClass        10 CDC Data
          bInterfaceSubClass      0 
          bInterfaceProtocol      0 
          iInterface              0 
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x82  EP 2 IN
            bmAttributes            2
              Transfer Type            Bulk
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               0
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x01  EP 1 OUT
            bmAttributes            2
              Transfer Type            Bulk
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               0
    can't get device qualifier: Resource temporarily unavailable
    can't get debug descriptor: Resource temporarily unavailable
    Device Status:     0x0001
      Self Powered
    

    And as you can see here, it contains data that you can probably use to differenciate per cdc_acm:

      iProduct                2 Zephyr USB console sample
      iSerial                 3 8385276BF7E8AF2C

    Is this what you are looking for?

  • Hi Sigurd,

    No worries on the case status, we are all human. :-) I saw from your example that you can use the experimental CONFIG_USB_DEVICE_STACK_NEXT (-DCONF_FILE=usbd_next_prj.conf) to set the descriptor details, which is awesome, but how do I do this for multiple instances. Eg. I want a Mcumgr port and 2 CDC ACM port instances (one being the Console) all running from the same USB port.

    I tried having a go myself and when I don't have CONFIG_USB_DEVICE_STACK_NEXT enabled I can create a Mcumgr port and a Console port without issues. But as soon as I try it with CONFIG_USB_DEVICE_STACK_NEXT the Mcumgr port is not there. I have also tried using two different configs and setting it to the same usb context (sample_usbd) and also tried two different context without avail.

    So my question is how do I get multiple com ports going with CONFIG_USB_DEVICE_STACK_NEXT, preferably a usb Console, CDC ACM and Mcumgr and then how do I set the descriptors for these individually?

    Kind Regards

    Julian

  • From what I am able to find, this should be possible for USB, but is not supported in Zephyr.
    I say this because of the following reasons:

    If this was possible, it should prefferably be set by zephyr,cdc-acm-uart (on usb bus) dts binding, but that does not have any USB specific settings.

    The cdc_acm_configure() function does not seem to do anything in runtime either.

    Initialization of CDC ACM from this line and onwards looks very static.

    So if you need this feature, I think you need to add it manually to the cdc acm drivers.
    The hard but best way would be to improve the cdc-acm-uart binding to include descriptor information, and then get that to INITIALIZER_IF somehow.
    The less hard way would be to add some hack to the driver to change INITALIZER_IF in a more straight forward way.

    I can not add this feature for you, but if you want to try and do so yourself, I can help you on the way.

    Do you agree with my conclusions?

Related