2024-08-12 01:43 PM - last edited on 2024-08-16 02:44 AM by Amel NASRI
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.
2024-08-13 03:49 AM
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 */
}