Skip to main content
Explorer II
September 6, 2024
Solved

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

  • September 6, 2024
  • 3 replies
  • 2244 views

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 ); 
 }
}
    This topic has been closed for replies.
    Best answer by Pavel A.

    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?)

     

    3 replies

    Pavel A.Answer
    Super User
    September 7, 2024

    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?)

     

    c_birdAuthor
    Explorer II
    September 9, 2024

    thank you!

    Super User
    September 9, 2024

    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

    c_birdAuthor
    Explorer II
    September 11, 2024

    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.

    Super User
    September 11, 2024

    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

    Super User
    September 11, 2024

    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