cancel
Showing results for 
Search instead for 
Did you mean: 

USB Dual VCOM Composite Device

DWeb_2
Associate III

Hi,

I managed to implement a dual VCOM composite device for an STM32H7. In principal the communication works, if both COM ports are actively used/open. One port is used for sending commands and receiving responses. The other one sends out unsolicited trace data and can be opened/closed arbitrarily.

The problem arises once I close the trace VCOM. It seems like after calling

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  /* USER CODE END 7 */
  return result;
}

hcdc->TxState stays true, which also stalls the communication on the other port. The code here was copied from a code example for an STM32H7 eval board, I think.

Only when the trace port is re-opened (in a generic terminal application)

static uint8_t USBD_CDC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)

is called again, which resets this state.

I see that there is the possibility to detect the start of the session with

static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)

where LINE CODING Request/Responses and CONTROL LINE STATE requests are exchanged.

However when a port is closed, the USB host just sends the exact same CONTROL LINE STATE to the device as when opening it (tested on multiple terminal applications). Is there any way to safely detect the closing? Or implement a timeout mechanism the remove the "lock" again?

Thanks in advance for your help.

1 REPLY 1
DWeb_2
Associate III

 I figured it out myself. This Cube extension gave the proper hints: https://github.com/alambe94/I-CUBE-USBD-Composite/tree/main

Essentially you need as many USBD_CDC_HandleTypeDef as you have VCOM instances, which means the driver has to be altered in a lot of places.

Example:

USBD_CDC_HandleTypeDef CDC_Class_Data[NUMBER_OF_CDC];

...

uint8_t CDC_Transmit_FS(uint8_t ch, uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = &CDC_Class_Data[ch];
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(ch, &hUsbDeviceFS, Buf, Len);
  result = USBD_CDC_TransmitPacket(ch, &hUsbDeviceFS);
  /* USER CODE END 7 */
  return result;
}