usbx icon indicating copy to clipboard operation
usbx copied to clipboard

USBX Dual composite CDC ACM not working on STM32WB5

Open navinreddy23 opened this issue 1 year ago • 0 comments

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 success.

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.

Best regards, Navin

navinreddy23 avatar Aug 13 '24 07:08 navinreddy23