AnsweredAssumed Answered

How determine when USB TX is complete from device to host

Question asked by hornang on Nov 4, 2014
Latest reply on Jun 5, 2015 by hornang
- STM32CubeF4 V1.3.0
- STM32_USB_Device_Library from STM32CubeF4 V1.3.0
- VCP_V1.3.1_Setup.exe (ST's host side USB CDC driver for Windows 7)
- STM32F4Discovery (STM32F407)
- FreeRTOS 8.1.2

I'm using the CDC class driver bundled with the USB device library.

My goal is to stream binary data from USB device to host through USB CDC. The streaming works fine, but problem arises when there is no client application connected to the virtual COM port when data is beeing transmitted from the USB device.

See USBD_CDC_TransmitPacket function from usbd_cdc.c below. It has been modified according to Point no. 22 at this page: http://visualgdb.com/tutorials/arm/stm32/usb/ .

uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
{     
  USBD_CDC_HandleTypeDef   *hcdc = pdev->pClassData;
   
  if(pdev->pClassData != NULL)
  {
    if(hcdc->TxState == 0)
    {
 
      /* Tx Transfer in progress */
      hcdc->TxState = 1;
       
      /* Transmit next packet */
      USBD_LL_Transmit(pdev,
                       CDC_IN_EP,
                       hcdc->TxBuffer,
                       hcdc->TxLength);
      return USBD_OK;
    }
    else
    {
      return USBD_BUSY;
    }
  }
  else
  {
    return USBD_FAIL;
  }
}

As you can see this function just returns "busy" if the previous transfer is in progress. This happens if nobody is listening on the PC side. This is probably correct and kind of an improvement to a regular COM port without flow control.

What I want is to block (for some time) until I can transmit my next packet. This is possible by polling on TxState flag, not very elegant but it works.

This is the code that resets the TxFlag:

static uint8_t  USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
{
  USBD_CDC_HandleTypeDef   *hcdc = pdev->pClassData;
   
  if(pdev->pClassData != NULL)
  {
     
    hcdc->TxState = 0;
 
    return USBD_OK;
  }
  else
  {
    return USBD_FAIL;
  }
}

Two questions:

1. What does USBD_CDC_DataIn really mean? Is this the callback for when a (bulk) transfer has succesfully been transmitted to the host PC?
2. Is there a way to implement blocking version of a "USB transmit"-function? I'm using FreeRTOS which indeed have mutexes, but I'm unsure where I should lock and unlock.
3. Before calling USBD_CDC_TransmitPacket one have to call USBD_CDC_SetTxBuffer. Can this ruin the ongoing transfer? There is not TxState check in this function.

Outcomes