USBD endpoint transfer completion event.

In my NRF52840 based device using NRF5 SDK 17.1.0, I notice that sometimes this loop in the nrfx usbd driver code of the SDK doesn't finish:

[modules/nrfx/drivers/src/nrfx_usbd.c: 1444]

/* There is a lot of USBD registers that cannot be accessed during EasyDMA transfer.
 * This is quick fix to maintain stability of the stack.
 * It cost some performance but makes stack stable. */
while (!nrf_usbd_event_check(nrfx_usbd_ep_to_endevent(ep)) &&
       !nrf_usbd_event_check(NRF_USBD_EVENT_USBRESET))
{
    /* Empty */
}

It seems the transfer-end EasyDMA hardware-event isn't generated reliably in all situations. This happens mostly with small transfers on interrupt-in-endpoints and only with some usb hosts (notably raspberry pi). This is a big problem, because this function is called from interrupt context (and therefore should actually not do such busy waiting).

Is this a known issue and is there a workaround? I tried to enter the loop conditionally only when transfer size is bigger than 4 or 8 bytes, which seems to fix this, but that causes other problems.  I tried to pad the 2-byte transfer to 8 bytes, but that doesn't change anything. I think it could work to skip the loop for interrupt endpoints, but this routine handles interrupt and bulk endpoints the same; there is no USBD register that keeps track of bulk vs. interrupt endpoints.

I know that NRF5 sdk is out of support, but my project was built with it and it isn't easy to move to NRF-Connect SDK.

  • Hi Ronald, 
    I'm really sorry for the late response. It's my mistake that the feedback from our R&D engineer didn't get back here. Here is his thought: 

    STARTED event is completely independent from host issuing the IN token. The host may not issue IN token at all, and yet the STARTED event will be generated.

    The customer seems to be chasing something, but the conclusion that this in any way allows to determine whether IN token is sent by host is wrong. It does not, never did and never will. Can he observe the issue with Zephyr or NCS?

    By the way, the Zephyr usbd driver no longer does busy loop waiting in the interrupt context. If the customer can reproduce it with Zephyr or NCS, I would be very interesting in investigating this. Otherwise, I just assume there's some bug somewhere in the NRF5 SDK or the customer application and not in the silicon.

    Without a reproducer (full software package both on nRF52840 and host) I cannot check what's going on.

     

    In the ticket customer was asking "What could be the reason why a DMA action isn't captured? Could it be because a previous DMA isn't finished yet?" - there can only be one DMA transfer (between main system memory and USBD endpoint buffer) active at a time. If the previous one hasn't finished before new one is started then for sure things won't work. But considering that nrfx does busy loop until the transfer ends, I don't think it is possible to trigger next DMA before previous one finished with nrfx.

     

    A long shot at tackling this problem could be to try to remove the *((volatile uint32_t *)0x40027C1C) = 0x00000000; from usbd_dma_pending_clear() completely. This would result in increased current consumption, but could provide some insight whether or not the issue is related to errata 199 or not.

     

Related