从USB Virtual Com Port设备检测打开的PC COM端口

Cli*_*ord 5 embedded usb device cdc stm32

我正在使用带有STM32_USB-FS-Device_Lib_V3.2.1 USB库的STM32F105微控制器,并根据我们的目的调整了VCP示例(与RTOS和串行API集成).

问题是如果连接了USB电缆,但是Windows主机上没有打开端口,几分钟后设备会永久重新进入USB ISR,直到端口打开然后一切正常开始工作.

我已经检测了中断处理程序并且可以看到当故障发生时,ISR处理程序退出然后立即重新进入.发生这种情况是因为在退出中断时,OTG_FS_GINTSTS中的IEPINT标志不清楚.此时OTG_FS_DAINT包含0x00000002(IEPINT1设置),而DIEPINT1包含0x00000080(TXFE).调用清除TXFE的OTGD_FS_Handle_InEP_ISR()中的行,但该位不清除或立即重新置位.当主机上的COM端口重新打开时,中断结束时OTG_FS_GINTSTS和OTG_FS_DAINT的状态始终为零,并且以正常速率发生进一步的中断.请注意,只有在输出数据但主机没有打开端口时才会出现此问题.如果端口打开或没有输出数据,系统将无限期运行.我相信输出的数据越多,问题就越早出现,但目前这是轶事.

VCP代码有一个状态变量,它接受以下枚举值:

  UNCONNECTED,
  ATTACHED,
  POWERED,
  SUSPENDED,
  ADDRESSED,
  CONFIGURED
Run Code Online (Sandbox Code Playgroud)

我们使用CONFIGURED状态来确定是否将数据放入驱动程序缓冲区以进行发送.但是,当连接电缆而不是主机打开端口并连接应用程序时,将设置CONFIGURED状态.我看到当Windows打开端口时,会出现一连串的中断,所以似乎在这个事件上发生了一些通信; 我想知道是否有可能检测主机是否打开了端口.

我或许需要两件事之一:

  1. 防止USB代码在第一个实例中卡在ISR中
  2. 确定主机是否从设备端打开端口,并且仅在打开时推送数据以进行发送.

Cli*_*ord 7

部分(1) - 防止中断锁定 - 来自ST支持的USB库错误修复; 它没有正确清除TxEmpty中断.

经过ST支持的一些研究和帮助,我已经确定了第(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 ;
}
Run Code Online (Sandbox Code Playgroud)

2)修改了对SET_CONTROL_LINE_STATE的Virtual_Com_Port_NoData_Setup()处理:

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;
}
Run Code Online (Sandbox Code Playgroud)

3)为了允许与不按常规操作DTR的应用程序一起使用,我还修改了对SET_LINE_CODING的Virtual_Com_Port_Data_Setup()处理:

  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's 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;
  }
Run Code Online (Sandbox Code Playgroud)