Skip to main content
Graduate
February 8, 2024
Question

How to detect if usb connection is established

  • February 8, 2024
  • 5 replies
  • 7147 views

Hey. I'm trying to use my H7's usb interface and i've currently set it up as a cdc device.
What i'm trying to implement though is the following. 

The stm is supposed to create a virtual connection with either a python app or a tera term terminal.

Is there a function or a variable that detects if this kind of a connection is established ? For example, the pico equivalent is tud_cdc_connected()

 What i want to build is this

while(!exampleCOnnectionVariable)
{
 HAL_DELAY(500)
}

Meaning that my stm would wait during initialization, until a connection is established and then proceed with the super loop.

    This topic has been closed for replies.

    5 replies

    Graduate
    February 8, 2024

    With classic ST USB stack, you need to implement CDC_SET_CONTROL_LINE_STATE request in usbd_cdc_if.c. When ControlLineState value changes from anything different from 3 to 3, the connection is established. You may start transmitting data no sooner than 50 ms after that change.

    Super User
    February 8, 2024

    Check dev_state for configured status.

    if (hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED) {
     ...
    }

     

    This doesn't mean the program has the port open, just that the computer is connected. No way to detect when a program opens the serial port.

    Graduate
    February 8, 2024

    dev_state remains at CONFIGURED even after you disconnect the USB cable...

    Super User
    February 9, 2024

    If your device is bus-powered, disconnecting the cable stops the program. No problems there.

    If your device is self-powered, you are required (per USB standard) to monitor VBUS and de-initialize the peripheral when VBUS drops by calling MX_USB_DEVICE_DeInit(). This will reset the state machine back to USBD_STATE_DEFAULT.

    Edit: If you ignore the standard, there's probably a state variable you could check somewhere. I may look into it.

    Technical Moderator
    February 8, 2024

    Hello @AlexandrosAA 

    If I understand your request correctly, in usbd_conf.c, you can check device connection from ISR through USBD_LL_DevConnected in callback.

    Graduate
    February 9, 2024

    I tried something like this

    while(CDC_Transmit_HS(messageOk,sizeof(messageOk))!=USBD_OK)
    {
    
    }

    but it seems that the message is transmitted, even if the port is not open. Is there a similar approach to this ? The while loop should end only if the data are accepted by my computer.

    Technical Moderator
    February 9, 2024

    @AlexandrosAA When stepping in debug, and you reach this line as previously mentioned.

    if (hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED) {

     You are pretty sure your host is connected.

    Visitor II
    April 2, 2025

    Here is the solution I found. It blocks execution until a terminal is connected (DTR on). It also includes a fix for Windows, where the Virtual COM port doesn’t work.

    File `main.c`

     /* USER CODE BEGIN 2 */
     while (CDC_Get_DTR_State() == 0) {
    	 HAL_Delay(10); // Wait 10 ms before re-check
     }
     /* USER CODE END 2 */

    File `usbd_cdc_if.h`

    /* USER CODE BEGIN EXPORTED_FUNCTIONS */
    uint8_t CDC_Get_DTR_State(void);
    uint8_t CDC_Get_RTS_State(void);
    /* USER CODE END EXPORTED_FUNCTIONS */

    File `usbd_cdc_if.c`

    /* USER CODE BEGIN PV */
    /* Private variables ---------------------------------------------------------*/
    // For the CDC driver to work on Windows
    USBD_CDC_LineCodingTypeDef LineCoding =
    {
    		115200, /* baud rate */
    		0x00, /* stop bits-1 */
    		0x00, /* parity - none */
    		0x08 /* nb. of bits 8 */
    };
    
    volatile uint8_t dtr_state = 0; // Global variable to store DTR state
    volatile uint8_t rts_state = 0; // Global variable to store RTS state
    /* USER CODE END PV */
    
    ...
    
    static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
    {
     /* USER CODE BEGIN 5 */
     switch(cmd)
     {
     case CDC_SEND_ENCAPSULATED_COMMAND:
    
     break;
    
     case CDC_GET_ENCAPSULATED_RESPONSE:
    
     break;
    
     case CDC_SET_COMM_FEATURE:
    
     break;
    
     case CDC_GET_COMM_FEATURE:
    
     break;
    
     case CDC_CLEAR_COMM_FEATURE:
    
     break;
    
     /*******************************************************************************/
     /* Line Coding Structure */
     /*-----------------------------------------------------------------------------*/
     /* Offset | Field | Size | Value | Description */
     /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
     /* 4 | bCharFormat | 1 | Number | Stop bits */
     /* 0 - 1 Stop bit */
     /* 1 - 1.5 Stop bits */
     /* 2 - 2 Stop bits */
     /* 5 | bParityType | 1 | Number | Parity */
     /* 0 - None */
     /* 1 - Odd */
     /* 2 - Even */
     /* 3 - Mark */
     /* 4 - Space */
     /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
     /*******************************************************************************/
     case CDC_SET_LINE_CODING:
     	LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) | (pbuf[2] << 16) | (pbuf[3] << 24));
     	LineCoding.format = pbuf[4];
     	LineCoding.paritytype = pbuf[5];
     	LineCoding.datatype = pbuf[6];
     	break;
    
     case CDC_GET_LINE_CODING:
     	pbuf[0] = (uint8_t)(LineCoding.bitrate);
     	pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8);
     	pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16);
     	pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24);
     	pbuf[4] = LineCoding.format;
     	pbuf[5] = LineCoding.paritytype;
     	pbuf[6] = LineCoding.datatype;
     	break;
    
     case CDC_SET_CONTROL_LINE_STATE:
     	// DTR is in bit 0 (LSB) of first byte
     	dtr_state = pbuf[0] & 0x01; // Bit 0 = DTR
     	rts_state = (pbuf[0] & 0x02) >> 1; // Bit 1 = RTS
     break;
    
     case CDC_SEND_BREAK:
    
     break;
    
     default:
     break;
     }
    
     return (USBD_OK);
     /* USER CODE END 5 */
    }
    
    ...
    
    /* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
    uint8_t CDC_Get_DTR_State(void) {
    	return dtr_state;
    }
    
    uint8_t CDC_Get_RTS_State(void) {
    	return rts_state;
    }
    /* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
    Visitor II
    December 13, 2025

    @overlaine thanks for sharing your solution. Could you please specify more detail about "the Virtual COM port doesn’t work in windows", I wonder if we encountered same problem of a serious bug in usbser.sys.

    Visitor II
    December 14, 2025

    Hello,

    From what I remember (as this goes back several years), the serial port was correctly enumerated under Windows, but communication between the devices (the PC and the MCU) did not work.
    I tested it again today without the fix, and it now works under Windows.

    Most likely this is due to a driver update, if I am to believe this post:
    post_link