cancel
Showing results for 
Search instead for 
Did you mean: 

How to confirm that the USB data has been successfully sent?

c_bird
Associate II

I saw the following function in the USB library.

uint32_t USB_OTG_GetEPStatus(USB_OTG_CORE_HANDLE *pdev ,USB_OTG_EP *ep)

{

         ··········

        if (depctl.b.stall == 1)
        {
             Status = USB_OTG_EP_TX_STALL;
        }
        else if (depctl.b.naksts == 1)
       {
            Status = USB_OTG_EP_TX_NAK;
       }
       else
      {
            Status = USB_OTG_EP_TX_VALID;
       }

        ····················

       return Status;

}

I am using the function USB_OTG_EPStartXfer(pdev, ep); to send data."I then found that the PC could not recognize this USB identifier. Through DEBUG debugging, I discovered that when the USB is first connected, `USB_OTG_GetEPStatus(pdev, ep)` returns `USB_OTG_EP_TX_NAK`, which causes the recognition to fail. Therefore, this method is not very effective. Are there any other ways to detect whether the USB data has been sent successfully or whether the USB port is currently idle and ready to send data?"

if(USB_OTG_GetEPStatus(pdev,ep) == USB_OTG_EP_TX_VALID))  //sending is valid
{
   if ( ep->num == 0 )
   {
      USB_OTG_EP0StartXfer(pdev , ep);
   }
   else
  {
      USB_OTG_EPStartXfer(pdev, ep ); 
  }
}
1 ACCEPTED SOLUTION

Accepted Solutions
Pavel A.
Evangelist III

any other ways to detect whether the USB data has been sent successfully

Use USB bus analyzer

or whether the USB port is currently idle and ready to send data

Read the EP status register, in overall context of the USB device state (is it in reset? some stage of enumeration?)

 

View solution in original post

7 REPLIES 7
Pavel A.
Evangelist III

any other ways to detect whether the USB data has been sent successfully

Use USB bus analyzer

or whether the USB port is currently idle and ready to send data

Read the EP status register, in overall context of the USB device state (is it in reset? some stage of enumeration?)

 

thank you!

What is this, SPL? Are you aware of the fact that SPL is deprecated for some 10 years now?

USB_OTG_GetEPStatus() reads DIEPCTLx and USB_OTG_EP_TX_NAK means, that DIEPCTLx.NAKSTS = 1, which effectively tells the Host (PC) that "there are no more data available in this In endpoint" (USB is a polled bus, i.e. the Device in reality does not transmit data through In endpoints, but the Host repeatedly tries to read out data from that endpoint) and probably gets set by the hardware when all data from given endpoint have been read out by the Host (there's also a second possibility, namely that Device can decide to set for whatever reason NAK for given endpoint by writing DIEPCTLx.SNAK=1, but such usage is rare and I don't think the STM32 USB libraries do that ever).

So, at the end of the day, yes, USB_OTG_EP_TX_NAK is a good indicator that data from given endpoint have been "sent" (i.e. Host has read them).

> when the USB is first connected, `USB_OTG_GetEPStatus(pdev, ep)` returns `USB_OTG_EP_TX_NAK`, which causes the recognition to fail.

Reading DIEPCTLx should not cause anything to fail. I don't know what do you mean by "recognition" in this case, but the reason for failure is probably something else.

JW

Thank you very much for your help. I would like to ask if there is specific documentation to support the statement "that DIEPCTLx.NAKSTS = 1, which effectively tells the Host (PC) that 'there are no more data available in this In endpoint' (USB is a polled bus, i.e., the Device in reality does not transmit data through In endpoints, but the Host repeatedly tries to read out data from that endpoint)."

The recognition failure I mentioned refers to the PC being unable to recognize the VCP virtual COM port identifier because I read the state of DIEPCTLx.NAKSTS before sending. This led to such a result because when USB is first connected to the device, there is a chance that DIEPCTLx.NAKSTS equals 1. However, after the device successfully handshakes with the host, DIEPCTLx.NAKSTS is always 0.

Which STM32?

> PC being unable to recognize the VCP virtual COM port identifier 

Are you talking about failed enumeration? What are the symptoms exactly? 

> because I read the state of DIEPCTLx.NAKSTS

Why do you do that? Which register exactly, for which endpoint? How do you do that, in code or using debugger? If in code, show that code; if in debugger, try not using it.

JW

>Which STM32?

YES

>Why do you do that?

Because I need to check if the data in the current USB port has been completely transmitted to prevent it from being overwritten

> Which register exactly, for which endpoint?

It is the DIEPCTLx register, and the port is EP1.

>How do you do that, in code or using debugger?

In code,the code is as follows,i used this function to send my data. After I added this if condition, the PC could not recognize the VCP, which caused the connection with the host computer to fail. However, after I added a delay and then enabled this if condition, I was able to communicate normally with the host computer.

/**
* @brief  Transmit data over USB
* @PAram pdev: device instance
* @PAram ep_addr: endpoint address
* @PAram pbuf: pointer to Tx buffer
* @PAram buf_len: data length
* @retval : status
*/
uint32_t  DCD_EP_Tx ( USB_OTG_CORE_HANDLE *pdev,
                     uint8_t   ep_addr,
                     uint8_t   *pbuf,
                     uint32_t   buf_len)
{
  USB_OTG_EP *ep;
  
  ep = &pdev->dev.in_ep[ep_addr & 0x7F];
  
  /* Setup and start the Transfer */
  ep->is_in = 1;                       
  ep->num = ep_addr & 0x7F;         
  ep->xfer_buff = pbuf;
  ep->dma_addr = (uint32_t)pbuf;  
  ep->xfer_count = 0;               
  ep->xfer_len  = buf_len;           

  if(USB_OTG_GetEPStatus(pdev,ep) == USB_OTG_EP_TX_VALID))  //Check if the transmission is valid
	{

		if ( ep->num == 0 )
		{
			USB_OTG_EP0StartXfer(pdev , ep);
		}
		else
		{
			USB_OTG_EPStartXfer(pdev, ep );   //Non-zero control port
		}
	}

			
  return 0;
}

 

I meant, which STM32 model are you using. There are differences in the OTG USB implementations in individual STM32, so the exact behaviour may change from model to model.

The OTG Device implementation in SPL you appear to be using is interrupt-based - in particular, when a transfer is finished, the XFRC interrupt is handled in DCD_HandleInEP_ISR() and that calls the DCD layer's DataInStage() callback which by default is USBD_DataInStage(); that in turn for non-0 endpoint calls the class's DataIn() which for CDC by default is usbd_cdc_DataIn(), and that, for finished transfers, sets USB_Tx_State = USB_CDC_IDLE; . That is used in Handle_USBAsynchXfer() to start transferring more data, based on data present in the APP_Rx_Buffer[] circular buffer and its head pointer APP_Rx_ptr_in. Note, that this all happens in interrupt context (so beware of atomicity). See usbd_cdc_vcp.c:VCP_DataTx() in the VCP example in the library for example usage of this mechanism.

The OTG machine is relatively complex and fragile, and you are not supposed to mix interrupt-based and polled approaches. The DIEPCTLx.NAKSTS may or may not get set and cleared by hardware due to various events, e.g. endpoint may get automatically disabled at the end of transfer and that may or may not clear NAKSTS. The description of the exact behaviour of the individual flags is sketchy and it's best to follow the steps in Operational model subchapter of the OTG chapter in RM (however messy they are), and/or either the SPL or Cube implementations.

JW