AnsweredAssumed Answered

STM32_USBD_OTG VCP example explanation

Question asked by bauer.jack.001 on Mar 17, 2013
Latest reply on Mar 21, 2013 by xu.jie.001

Hi all,

I am a beginner to USB and after some days of reading USB OTG library and RM0033
in the scope of getting started with USB. I'll to try to explain the virual com
port example in my own words and fore w/o garantee.
The examples is the same for STM32F4xx and STM32F105/107 devices.
Thanks to post your corrections/comments and suggestios by replying to this post.
I will not cover the initialization and enumeration phases as it seems to be little
bit complicated (for a beginner) than communication phase.
The examples configures other than (EP0) the endpoints as following:
 - EP1: bulk IN / bulk OUT
 - EP2: Control IN

When sending data from terminal like application (from your host (PC)), the RXFLVL
flag (of GINTSTS register) is set and DCD_HandleRxStatusQueueLevel_ISR() is executed
within USBD_OTG_ISR_Handler()
In DCD_HandleRxStatusQueueLevel_ISR():
   - Read OTG_HS_GRXSTSP register
   - check the packet status filed
   - if packet status is data update (PKTSTS = 0010: OUT data packet received)
     (defined as STS_DATA_UPDT in USB lib)
     * read data from FIFO USB_OTG_ReadPacket(pdev,ep->xfer_buff, status.b.bcnt);
When reading data from FIFO is completed, the RXFLVL flag is set again and
DCD_HandleRxStatusQueueLevel_ISR() is executed within USBD_OTG_ISR_Handler()
In DCD_HandleRxStatusQueueLevel_ISR():
   - Read OTG_HS_GRXSTSP register
   - check the packet status filed
   - if packet status is transfer complete (PKTSTS = 0011: OUT transfer completed (triggers an interrupt))
     (defined as STS_XFER_COMP in USB lib)
     no special processing in this case !

The trasnfert complete triggers the EP1 OUT Endpoint hendler and USBD_OTG_EP1OUT_ISR_Handler()
is executed. Whithin USBD_OTG_EP1OUT_ISR_Handler():
   - Read DOEPINT register
   - Check that xfercompl flag is set set (XFRC bit in OTG_HS_DOEPINTx register)
   - If so inform upper layer that data are ready and call USBD_DataOutStage()
     which calls pdev->dev.class_cb->DataOut(pdev, epnum) ==> usbd_cdc_DataOut()
     ==> VCP_DataRx() ==> USART_SendData()
     (==> means function call)

When receiving data from external device to STM32 through USART_RX pin, the
EVAL_COM_IRQHandler() is executed which calls VCP_DataTx() which stores the received
data APP_Rx_Buffer[] buffer.
In usbd_cdc_SOF() which is called every SOF (125 µs in HS), check if FrameCounter
is equal to CDC_IN_FRAME_INTERVAL if so call Handle_USBAsynchXfer() and this stage
USB core will be aware that there are data to send over USB.
In Handle_USBAsynchXfer():
  - Set global variable USB_Tx_State
  - Configure EP1 (APP_Rx_Buffer, datalength)
  - Enable Tx FIFO empty interrupt source on EP1

In next call of USBD_OTG_ISR_Handler(), read GINTSTS register and inepint flag
is set and DCD_HandleInEP_ISR() is executed  and as EP1 has a dedicated IRQ handler
the interrupt was already masked to allow the execution on OTG_HS_EP1_IN_IRQHandler()

In OTG_HS_EP1_IN_IRQHandler()
  - read DIEPINT register and check if Tx empty flag is set (TXFE in DIEPINT in
    RM0033 and emptyintr in USB lib) if so call
    DCD_WriteEmptyTxFifo() ==> USB_OTG_WritePacket
OTG_HS_EP1_IN_IRQHandler() is triggered again with transfert complete flag set
this calls USBD_DCD_INT_fops->DataInStage(pdev , 1) ==> USBD_DataInStage()
==> usbd_cdc_DataIn() which resets USB_Tx_State = 0
 
Thanks & Regards,

Jack Bauer 

Outcomes