STMicroelectronics/STM32CubeF7

USBD_LL_GetRxDataSize/HAL_PCD_EP_GetRxCount return wrong value

davekeck opened this issue · 2 comments

When both of these conditions are true:

  • A USB OTG HS device has DMA enabled ("Enable internal IP DMA" checkbox in the UI)
  • USBD_LL_PrepareReceive is used to initiate a transfer that's larger than the max packet size

Under these circumstances, when the DataOut USB callback is called as a result of USBD_LL_PrepareReceive, USBD_LL_GetRxDataSize/HAL_PCD_EP_GetRxCount return an incorrect value for the number of bytes received.

The bug appears to be due to these lines in PCD_EP_OutXfrComplete_int:

hpcd->OUT_ep[epnum].xfer_count =
hpcd->OUT_ep[epnum].maxpacket -
(USBx_OUTEP(epnum)->DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ);
hpcd->OUT_ep[epnum].xfer_buff += hpcd->OUT_ep[epnum].maxpacket;

Th above math incorrectly uses the the max packet size (instead of the transfer size), so that when the transfer size is larger than the max packet size, xfer_count is assigned to an incorrect value, which breaks USBD_LL_GetRxDataSize/HAL_PCD_EP_GetRxCount.

This replacement code fixes the issue for me:

const uint32_t xfer_len = hpcd->OUT_ep[epnum].xfer_len;
const uint32_t xfrsiz = (USBx_OUTEP(epnum)->DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ);
if (xfer_len) {
    const uint32_t xfer_count = xfer_len - xfrsiz;
    hpcd->OUT_ep[epnum].xfer_count = xfer_count;
    hpcd->OUT_ep[epnum].xfer_buff += xfer_count;
} else {
    hpcd->OUT_ep[epnum].xfer_count = 0;
}

Hi @davekeck,

Thank you for this clear and concise report and for the fix proposal. It has been forwarded to our development teams. I will get to you as soon as they provide their feedback.

With regards,

ST Internal Reference: 120891