Detecting an open PC COM port from a USB Virtual Com Port device

I use the STM32F105 microcontroller with the STM32_USB-FS-Device_Lib_V3.2.1 USB library and adapted the VCP example for our purposes (integration with RTOS and serial API).

The problem is that if the USB cable is connected, but the port is not open on the Windows host, after a few minutes the device will automatically switch to the ISR USB interface until the port opens, and then everything starts working normally.

I have an interrupt handler and see that when an error occurs, the ISR handler exits and then returns immediately. This is because when I exit the interrupt, the IEPINT flag in OTG_FS_GINTSTS is not clear. OTG_FS_DAINT at this time contains 0x00000002 (set IEPINT1), while DIEPINT1 has 0x00000080 (TXFE). A line is called in OTGD_FS_Handle_InEP_ISR (), which clears the TXFE, but the bit is either not cleared or is immediately restored. When the COM port on the host is reopened, the state of OTG_FS_GINTSTS and OTG_FS_DAINT at the end of the interrupt is always zero, and further interrupts occur at normal speed. Note that the problem only occurs if data is output, but the host does not have a port. If the port is open or data is not output, the system starts endlessly. I believe,that the more data is output, the faster the problem arises, but at present it is anecdotal.

VCP code has a state variable that takes the following values:

  UNCONNECTED,
  ATTACHED,
  POWERED,
  SUSPENDED,
  ADDRESSED,
  CONFIGURED

and we use the CONFIGURED state to determine whether to put data in the driver buffer for sending. However, the CONFIGURED state is set when the cable is not connected when the host has a port, an open and connected application. I see that when Windows opens the port, there is an interrupt package, so it seems that there is some connection going on in this event; I wonder if it is possible, therefore, to determine whether a port host is open?

I may need one of two things:

  • To prevent the USB code from getting into the ISR in the first instance
  • To determine if the host has a port open from the end of the device, and only send data to send when it opens.
+5
7

(1) - - USB ST; TxEmpty.

ST Support (2) - , -. , , DTR. CDC, . DTR, , . , , , (, ). , , , , .

ST VCP, usb_prop.c:

1) ​​ :

#include <stdbool.h>
static bool host_port_open = false ;
bool Virtual_Com_Port_IsHostPortOpen()
{
    return bDeviceState == CONFIGURED && host_port_open ;
}

2) Virtual_Com_Port_NoData_Setup() SET_CONTROL_LINE_STATE, :

else if (RequestNo == SET_CONTROL_LINE_STATE)
{
  // Test DTR state to determine if host port is open
  host_port_open = (pInformation->USBwValues.bw.bb0 & 0x01) != 0 ;
  return USB_SUCCESS;
}

3) , DTR, Virtual_Com_Port_Data_Setup() SET_LINE_CODING :

  else if (RequestNo == SET_LINE_CODING)
  {
    if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
    {
      CopyRoutine = Virtual_Com_Port_SetLineCoding;

      // If line coding is set the port is implicitly open 
      // regardless of host DTR control.  Note: if this is 
      // the only indicator of port open, there will be no indication 
      // of closure, but this will at least allow applications that 
      // do not assert DTR to connect.
      host_port_open = true ;

    }
    Request = SET_LINE_CODING;
  }
+7

, . , CDC , - node, - In data Out. , , node, . , , . , , 0x21 0x22 . usb_cdc_if.c , ( , cmd - , ). - CDC_Control_FS. . , 0x22 0x21. , , .

+1

:

  • USB- ISR
  • , , .

1 2. Windows Linux COM- , , COM- .

, USB- ; , . , , USB-, . , , .

+1

, CDC_Transmit_FS. printf _write.

, USB- , , USB .

, dev_state USBD_STATE_CONFIGURED, USB- . , PuTTY VCP, .

RTOS CubeMX HAL. .

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
    uint8_t result = USBD_OK;


    // Check if USB interface is online and VCP connection is open.
    // prior to send:
    if ((hUsbDevice_0->dev_state != USBD_STATE_CONFIGURED)
            || (hUsbDevice_0->ep0_state == USBD_EP0_STATUS_IN))
    {
        // The physical connection fails.
        // Or: The phycical connection is open, but no VCP link up.
        result = USBD_FAIL;
    }
    else
    {

        USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);

        // Busy wait if USB is busy or exit on success or disconnection happens
        while(1)
        {

            //Check if USB went offline while retrying
            if ((hUsbDevice_0->dev_state != USBD_STATE_CONFIGURED)
                        || (hUsbDevice_0->ep0_state == USBD_EP0_STATUS_IN))
            {
                result = USBD_FAIL;
                break;
            }

            // Try send
            result = USBD_CDC_TransmitPacket(hUsbDevice_0);
            if(result == USBD_OK)
            {
                break;
            }
            else if(result == USBD_BUSY)
            {
                // Retry until USB device free.
            }
            else
            {
                // Any other failure
                result = USBD_FAIL;
                break;
            }

        }
    }

    return result;
}

CDC_Transmit_FS _write:

// This function is used by printf and puts.
int _write(int file, char *ptr, int len)
{
    (void) file; // Ignore file descriptor
    uint8_t result;

    result = CDC_Transmit_FS((uint8_t*)ptr, len);
    if(result == USBD_OK)
    {
        return (int)len;
    }
    else
    {
        return EOF;
    }
}

+1

/ . , :

:

  • DTR
  • - CDC

, :

  • DTR
  • USB "", ..

, -, , .

0

: , Cube, HAL. , , , . , .

CDC_Transmit_FS, , TxState 0. , . -:

uint16_t count = 0;
USBD_CDC_HandleTypeDef *hcdc =
        (USBD_CDC_HandleTypeDef*) USBD_Device.pClassData;

while (hcdc->TxState != 0) {
    if (++count > BUSY_TIMEOUT) { //number of cycles to wait till it makes decision
        //here it clear that port is not opened
    }
}

, , , , . , :

uint8_t waitForTransferCompletion(void) {

    uint16_t count = 0;
    USBD_CDC_HandleTypeDef *hcdc =
             (USBD_CDC_HandleTypeDef*) USBD_Device.pClassData;

    while (hcdc->TxState != 0) {
        if (++count > BUSY_TIMEOUT) { //number of cycles to wait till it makes decision
            USBD_Stop(&USBD_Device); // stop and
            MX_USB_DEVICE_Init(); //            init device again
            HAL_Delay(RESET_DELAY); // give a chance to open port
            return USBD_FAIL; // return fail, to send last packet again
        }
    }

    return USBD_OK;
}

, - , , . BUSY_TIMEOUT 3000, .

0
source

I fixed it by checking the variable . It is 5 if connected, and 4 if not connected or has not been disconnected. But. There are some problems in the HAL. It is 5 when the program starts. The following steps fixed it at the beginning of the program hUsbDeviceFS.ep0_state

        /* USER CODE BEGIN 2 */
            HAL_Delay(500);
            hUsbDeviceFS.ep0_state = 4;

...

I have no desire to learn HAL - I hope that the developers will see this post and they will fix the HAL. This helped me solve my problem.

0
source

All Articles