cancel
Showing results for 
Search instead for 
Did you mean: 

USBX Dual Composite CDC ACM not working

NRedd.2
Associate III

Hello all,

 

I am trying to add two virtual COM ports on STM32WB5MMHGx device. The initial code is based out of STM32Cube example: Ux_Device_CDC_ACM.

I initially added this piece of code to register the class.

 

 

 

  cdc_acm_parameter2.ux_slave_class_cdc_acm_instance_activate   = USBD_CDC_ACM_Activate2;
  cdc_acm_parameter2.ux_slave_class_cdc_acm_instance_deactivate = USBD_CDC_ACM_Deactivate2;
  cdc_acm_parameter2.ux_slave_class_cdc_acm_parameter_change    = USBD_CDC_ACM_ParameterChange2;

  uint32_t code;
  if ( code = ux_device_stack_class_register("ACM2",
                                   ux_device_class_cdc_acm_entry,
                                   cdc_acm_configuration_number,
                                   cdc_acm_interface_number,
                                   &cdc_acm_parameter2) != UX_SUCCESS )
  {
    UNUSED(code);
    /* USER CODE BEGIN USBX_DEVICE_CDC_ACM_REGISTER_ERORR */
    return UX_ERROR;
    /* USER CODE END USBX_DEVICE_CDC_ACM_REGISTER_ERORR */
  }

 

 

 

 Memory pool and USB stack sizes were increased so that this registration process succeds.

That did not show up as two ACM devices on linux. After digging around, I found that there is a bug in the ux_device_descriptors.c. 

 

This piece of code is needed to enumerate and add two classes.

 

 

 

uint8_t UserClassInstance[USBD_MAX_CLASS_INTERFACES] = {
  CLASS_TYPE_CDC_ACM,
  CLASS_TYPE_CDC_ACM
};

 

 

 

 But that does not add proper descriptors and endpoint addresses. I solved this by comparing with NXP device descriptors

 

The changes made to get two devices listed as ttyACM1 and ttyACM2 are:

 

 

 

uint8_t  USBD_FrameWork_AddToConfDesc(USBD_DevClassHandleTypeDef *pdev, uint8_t Speed,
                                      uint8_t *pCmpstConfDesc)
{
.
.
.

  switch (pdev->tclasslist[pdev->classId].ClassType)
  {

#if USBD_CDC_ACM_CLASS_ACTIVATED == 1

    case CLASS_TYPE_CDC_ACM:

      /* Find the first available interface slot and Assign number of interfaces */
      interface = USBD_FrameWork_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].InterfaceType = interface; //! Assign missing interface number.
      pdev->tclasslist[pdev->classId].NumIf = 2U;
}

 

 

 

 And the address was incremented by InterfaceType.

 

 

 

 

static void  USBD_FrameWork_AssignEp(USBD_DevClassHandleTypeDef *pdev,
                                     uint8_t Add, uint8_t Type, uint32_t Sze)
{
  uint32_t idx = 0U;

  /* Find the first available endpoint slot */
  while (((idx < (pdev->tclasslist[pdev->classId]).NumEps) && \
          ((pdev->tclasslist[pdev->classId].Eps[idx].is_used) != 0U)))
  {
    /* Increment the index */
    idx++;
  }

  /* Configure the endpoint */
  uint8_t address = Add + pdev->tclasslist[pdev->classId].InterfaceType;
  pdev->tclasslist[pdev->classId].Eps[idx].add = address;
  pdev->tclasslist[pdev->classId].Eps[idx].type = Type;
  pdev->tclasslist[pdev->classId].Eps[idx].size = (uint16_t) Sze;
  pdev->tclasslist[pdev->classId].Eps[idx].is_used = 1U;
}

 

 

 

This fixed the issue. Now I see two VCOMs.

 

 

[  +0.300216] usb 1-4.3.4: new full-speed USB device number 89 using xhci_hcd
[  +0.190420] usb 1-4.3.4: New USB device found, idVendor=0483, idProduct=5740, bcdDevice= 2.00
[  +0.000005] usb 1-4.3.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0.000002] usb 1-4.3.4: Product: STM32 Virtual ComPort
[  +0.000002] usb 1-4.3.4: Manufacturer: STMicroelectronics
[  +0.000001] usb 1-4.3.4: SerialNumber: CDC_ACM001
[  +0.016028] cdc_acm 1-4.3.4:1.0: ttyACM1: USB ACM device
[  +0.000428] cdc_acm 1-4.3.4:1.2: ttyACM2: USB ACM device

 

 

 

Also, I added the addresses to the init function:

 

 

  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x00 , PCD_SNG_BUF, 0x14);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x80 , PCD_SNG_BUF, 0x54);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x81, PCD_SNG_BUF, 0x94);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x01, PCD_SNG_BUF, 0xD4);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x82, PCD_SNG_BUF, 0x114);

  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x02 , PCD_SNG_BUF, 0x154);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x82 , PCD_SNG_BUF, 0x194);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x83, PCD_SNG_BUF, 0x1D4);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x03, PCD_SNG_BUF, 0x214);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x84, PCD_SNG_BUF, 0x254);

 

 

I am not sure if the above is configuration is correct. I have simply followed the pattern.

 

Issue: 

When two CDC ACM classes are added to device_framework_full_speed, I get gibberish on the COM port.

Simply removing CLASS_TYPE_CDC_ACM from UserClassInstance makes a single COM port and UART work as per the initial example.

 

I am definitely missing something. Can anyone help me out? 

Here is a link to the complete project on GitHub

 

1 REPLY 1
NRedd.2
Associate III
Bus 001 Device 032: ID 0483:5740 STMicroelectronics Virtual COM Port
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2 [unknown]
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x0483 STMicroelectronics
  idProduct          0x5740 Virtual COM Port
  bcdDevice            2.00
  iManufacturer           1 STMicroelectronics
  iProduct                2 STM32 Virtual ComPort
  iSerial                 3 CDC_ACM001
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x008d
    bNumInterfaces          4
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower               50mA
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         0
      bInterfaceCount         2
      bFunctionClass          2 Communications
      bFunctionSubClass       2 Abstract (modem)
      bFunctionProtocol       1 AT-commands (v.25ter)
      iFunction               0 
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      1 AT-commands (v.25ter)
      iInterface              0 
      CDC Header:
        bcdCDC               1.10
      CDC Call Management:
        bmCapabilities       0x00
        bDataInterface          1
      CDC ACM:
        bmCapabilities       0x02
          line coding and serial state
      CDC Union:
        bMasterInterface        0
        bSlaveInterface         1 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               5
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 [unknown]
      bInterfaceProtocol      0 
      iInterface              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
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         2
      bInterfaceCount         2
      bFunctionClass          2 Communications
      bFunctionSubClass       2 Abstract (modem)
      bFunctionProtocol       1 AT-commands (v.25ter)
      iFunction               0 
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass      2 Abstract (modem)
      bInterfaceProtocol      1 AT-commands (v.25ter)
      iInterface              0 
      CDC Header:
        bcdCDC               1.10
      CDC Call Management:
        bmCapabilities       0x00
        bDataInterface          3
      CDC ACM:
        bmCapabilities       0x02
          line coding and serial state
      CDC Union:
        bMasterInterface        2
        bSlaveInterface         3 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               5
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        3
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass        10 CDC Data
      bInterfaceSubClass      0 [unknown]
      bInterfaceProtocol      0 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x03  EP 3 OUT
        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     0x83  EP 3 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0001
  Self Powered

Here is the configuration extracted from lsusb.

 `lsusb -d 0483:5740 -v`

 

I have also modified the config to match the endpoint address.

VOID USBX_APP_Device_Init(VOID)
{
  /* USER CODE BEGIN USB_Device_Init_PreTreatment_0 */

  /* USER CODE END USB_Device_Init_PreTreatment_0 */

  /* USB_FS init function */
  /* Enable USB power */
  HAL_PWREx_EnableVddUSB();  MX_USB_PCD_Init();

  /* USER CODE BEGIN USB_Device_Init_PreTreatment_1 */
  /* USER CODE BEGIN EndPoint_Configuration */
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x00 , PCD_SNG_BUF, 0x14);

  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x80 , PCD_SNG_BUF, 0x54);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x81, PCD_SNG_BUF, 0x94);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x01, PCD_SNG_BUF, 0xD4);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x82, PCD_SNG_BUF, 0x114);

  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x02 , PCD_SNG_BUF, 0x154);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x83, PCD_SNG_BUF, 0x194);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x03, PCD_SNG_BUF, 0x1D4);
  HAL_PCDEx_PMAConfig(&hpcd_USB_FS, 0x84, PCD_SNG_BUF, 0x214);
  /* USER CODE END EndPoint_Configuration */
  /* USER CODE END USB_Device_Init_PreTreatment_1 */

  /* Initialize and link controller HAL driver */
  ux_dcd_stm32_initialize((ULONG)USB, (ULONG)&hpcd_USB_FS);
  /* Start the USB device */
  HAL_PCD_Start(&hpcd_USB_FS);
  /* USER CODE BEGIN USB_Device_Init_PostTreatment */

  /* USER CODE END USB_Device_Init_PostTreatment */
}