cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 SPL USB library example CDC/VPC: how to determine if PC serial port is open?

fbar
Senior

I managed to get an old version of the USB CDC/VCP SPl library working

https://www.st.com/en/embedded-software/stsw-stm32046.html and modified the VCP example to send/receive data to a PC via USB serial port. I edited syscalls.c so that the printf() function sends data to the USB.

It all works well if the PC is connected to my board and I have a USB serial session open in, say, PuTTY. If there's no connection, though, the USB buffer fills immediately and the code stops executing, until a new USB Serial session is opened. Which is usually desirable, since it will prevent missing characters if too much data is sent at once and the USB serial port is still catching up. But if I want to use the USB serial port as a debug print, it must work if connected or not

How can I determine programmatically if the USB serial port is opened ? I know how to determine if the USB is connected to the PC or not, but that's not enough, since the board is also powered by USB, and always connected to a PC, even if the serial port is not open

I could not find a status function nor a register to read, and I got lost in the nested interrupts handling trying to figure out where to set a global flag. Thanks in advance for any suggestion

2 REPLIES 2
Kraal
Senior III

Hi,

What you can do is to have a global flag that is set when the serial port settings are modified. Usually upon opening the port, the PC soft will set the baudrate, parity, etc... When your code goes through this section you know that the serial port has been opened.

I don't remember at the moment if there is a way to know when the port is closed.

fbar
Senior

Thanks Kraal for the answer. I actually just tried your suggestion, but it only partially helps, unfortunately.

I just tried instrumenting the VCP_Ctrl() function, and upon connecting the USB cable to a Windows PC, the sequence of commands received is:

GET_LINE_CODING - SET_CONTROL_LINE_STATE - SET_LINE_CODING - GET_LINE_CODING

Upon connecting PuTTY, I get

4x GET_LINE_CODING - SET_LINE_CODING - GET_LINE_CODING - SET_CONTROL_LINE_STATE - SET_LINE_CODING - GET_LINE_CODING

I guess I could build a state machine that sets a flag based on that sequence, but I fear it would be pretty specific to a version of PuTTY, and might not work for other terminal apps. The fact that Windows sends the same commands upon USB connection makes it a bit unreliable

On the other hand, I found a way to achieve what I wanted: a way to printf() via the USB that works even if the USB is not connected to a terminal application. I was using this version of the VCP/USB library http://vedder.se/2012/07/usb-serial-on-stm32f4/ because the newest ST version doesn't work for me. It turns out that along the way, ST managed to solve the blocking issue, by masking the FIFOempty interrupt flag in the FIFO writing function. Here's the relevant portion, from the usb_dcd_int.c file:

static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum)
{
  USB_OTG_DTXFSTSn_TypeDef  txstatus;
  USB_OTG_EP *ep;
  uint32_t len = 0;
  uint32_t len32b;
  txstatus.d32 = 0;
  uint32_t fifoemptymsk;  // added to unblock
  
  ep = &pdev->dev.in_ep[epnum];    
  
  len = ep->xfer_len - ep->xfer_count;
  
  if (len > ep->maxpacket)
  {
    len = ep->maxpacket;
  }
  
  len32b = (len + 3) / 4;
  txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS);
  
  
  
  while  (txstatus.b.txfspcavail > len32b &&
          ep->xfer_count < ep->xfer_len &&
            ep->xfer_len != 0)
  {
    /* Write the FIFO */
    len = ep->xfer_len - ep->xfer_count;
    
    if (len > ep->maxpacket)
    {
      len = ep->maxpacket;
    }
    len32b = (len + 3) / 4;
    
    USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len);
    
    ep->xfer_buff  += len;
    ep->xfer_count += len;
    
    txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS);
 
 
    /* Mask the TxFIFOEmpty interrupt  */ //added to unblock
        if (ep->xfer_len == ep->xfer_count)
        {
          fifoemptymsk = 0x1 << ep->num;
          USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK,
                               fifoemptymsk, 0);
        }	// added  to unblock
  }
  
  return 1;
}

this way I can just printf() and if the terminal is connected, it prints, if not, just discards the buffer and keeps running

I need to understand why the new USB library doesn't work for me, but right now I'm unblocked even using the older version