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.

Parents
  • I dove a bit deeper in the situation and it seems the notification ep transfer isn't started at all (or at least it doesn't arrive at the host side) and therefore the end event doesn't occur either. The driver code just calls 2 inline functions (nrf_usbd_ep_easydma_set and usbd_dma_start) and assumes the transfer is started without checking if it really did.

    According to the nRF52840_PS_v1.8.pdf, there should be a 'STARTED' event when the PTR and MAXCOUNT have been 'captured'. Only when they have, it makes sense to wait for the ENDEPIN event to ensure the buffer is 'free' again (although I disagree that this should be done in the interrupt routine, alas).

    What could be the reason why a DMA action isn't captured? Could it be because a previous DMA isn't finished yet?

Reply
  • I dove a bit deeper in the situation and it seems the notification ep transfer isn't started at all (or at least it doesn't arrive at the host side) and therefore the end event doesn't occur either. The driver code just calls 2 inline functions (nrf_usbd_ep_easydma_set and usbd_dma_start) and assumes the transfer is started without checking if it really did.

    According to the nRF52840_PS_v1.8.pdf, there should be a 'STARTED' event when the PTR and MAXCOUNT have been 'captured'. Only when they have, it makes sense to wait for the ENDEPIN event to ensure the buffer is 'free' again (although I disagree that this should be done in the interrupt routine, alas).

    What could be the reason why a DMA action isn't captured? Could it be because a previous DMA isn't finished yet?

Children
No Data
Related