STM32F401 USB maximum transfer size limitation

Report here problems in any of ChibiOS components. This forum is NOT for support.
elagil
Posts: 92
Joined: Tue Sep 19, 2017 7:38 am
Has thanked: 8 times
Been thanked: 7 times

STM32F401 USB maximum transfer size limitation

Postby elagil » Sun Apr 16, 2023 9:45 pm

Hello,

I have a strange problem that I don't understand with USB data reception on an STM32F401 in device mode.

I have a USB audio application running (UAC 1), where I have an OUT endpoint for audio streaming (isochronous). Alongside it, there is a feedback IN endpoint (max. transfer size 4 bytes).

Playing around with the maximum transfer size of the OUT endpoint (endpoint config field "out_maxsize"), and attempting reception of that maximum possible transfer size, I have a problem at certain size settings.

When the maximum transfer size is chosen above 436 bytes, usbGetReceiveTransactionSizeX (called in the OUT callback) always returns zero. If I set it to 436 and below, it reports the correct packet size. The host always sends packets of 288 bytes size (checked in Wireshark).

How can that be explained? I was expecting that I can get close to the 1280 bytes of transaction size that is available in the FIFO buffer.

Thanks in advance!

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: STM32F401 USB maximum transfer size limitation

Postby Giovanni » Mon Apr 17, 2023 6:33 am

Hi,

RAM is allocated in the OTG memory, are assertions enabled? it is possible you are getting an overflow error while initializing the endpoint, without assertions you cannot see it.

Giovanni

elagil
Posts: 92
Joined: Tue Sep 19, 2017 7:38 am
Has thanked: 8 times
Been thanked: 7 times

Re: STM32F401 USB maximum transfer size limitation

Postby elagil » Mon Apr 17, 2023 5:15 pm

Yes, assertions are already enabled via CH_DBG_ENABLE_ASSERTS, but they don't fire.

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: STM32F401 USB maximum transfer size limitation

Postby Giovanni » Mon Apr 17, 2023 6:03 pm

The transaction size is increased each time a packet arrives on the endpoint, having it at zero means that the OTG is no more getting packets for some reason.

Not sure what could cause this.

Try to change the FIFO size of the other endpoint and see if the threshold stays at 436 or if it changes too.

Giovanni

elagil
Posts: 92
Joined: Tue Sep 19, 2017 7:38 am
Has thanked: 8 times
Been thanked: 7 times

Re: STM32F401 USB maximum transfer size limitation

Postby elagil » Mon Apr 17, 2023 9:09 pm

Actually, I made another discovery.

When I waste some time in the receive callback (just copy some values around, for example), then I begin to get zero packets, even at maximum packet size below of 436!

So maybe it is a problem with processing time that is spent somewhere. Is that a possibility?

Edit: to be investigated, this is probably a different issue altogether.
Last edited by elagil on Mon Apr 17, 2023 10:16 pm, edited 1 time in total.

elagil
Posts: 92
Joined: Tue Sep 19, 2017 7:38 am
Has thanked: 8 times
Been thanked: 7 times

Re: STM32F401 USB maximum transfer size limitation

Postby elagil » Mon Apr 17, 2023 10:15 pm

Ok, I tried to increase STM32_USB_OTG1_RX_FIFO_SIZE to 1024 (from the default 512).
Now, the maximum setting I can use is 948 bytes - which is exactly 512 bytes higher than before.

So, the issue is definitely the RX FIFO running out. I wonder how this could be made obvious by means of some error code.

Probably, most of the rest of the FIFO is used for the control endpoint (looks like 64 bytes), leaving 12 bytes that I don't know where they are used up.

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: STM32F401 USB maximum transfer size limitation

Postby Giovanni » Tue Apr 18, 2023 7:30 am

There is an assertion on memory allocation error but for some reason it is not triggered in your case, perhaps the check is wrong.

Giovanni

elagil
Posts: 92
Joined: Tue Sep 19, 2017 7:38 am
Has thanked: 8 times
Been thanked: 7 times

Re: STM32F401 USB maximum transfer size limitation

Postby elagil » Tue Apr 18, 2023 5:16 pm

Where do I find that assertion?

It is not in the function that I call for receiving on an OUT endpoint:

Code: Select all

void usbStartReceiveI(USBDriver *usbp, usbep_t ep,
                      uint8_t *buf, size_t n) {
  USBOutEndpointState *osp;

  osalDbgCheckClassI();
  osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS));
  osalDbgAssert(!usbGetReceiveStatusI(usbp, ep), "already receiving");

  /* Marking the endpoint as active.*/
  usbp->receiving |= (uint16_t)((unsigned)1U << (unsigned)ep);

  /* Setting up the transfer.*/
  /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/
  osp = usbp->epc[ep]->out_state;
  /*lint -restore*/
  osp->rxbuf  = buf;
  osp->rxsize = n;
  osp->rxcnt  = 0;
#if USB_USE_WAIT == TRUE
  osp->thread = NULL;
#endif

  /* Starting transfer.*/
  usb_lld_start_out(usbp, ep);
}


nor is it in the OTG lld function that the above calls:

Code: Select all

void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
  uint32_t pcnt, rxsize;
  USBOutEndpointState *osp = usbp->epc[ep]->out_state;

  /* Transfer initialization.*/
  osp->totsize = osp->rxsize;
  if ((ep == 0) && (osp->rxsize > EP0_MAX_OUTSIZE))
      osp->rxsize = EP0_MAX_OUTSIZE;

  /* Transaction size is rounded to a multiple of packet size because the
     following requirement in the RM:
     "For OUT transfers, the transfer size field in the endpoint's transfer
     size register must be a multiple of the maximum packet size of the
     endpoint, adjusted to the Word boundary".*/
  pcnt   = (osp->rxsize + usbp->epc[ep]->out_maxsize - 1U) /
           usbp->epc[ep]->out_maxsize;
  rxsize = (pcnt * usbp->epc[ep]->out_maxsize + 3U) & 0xFFFFFFFCU;

  /* Setting up transaction parameters in DOEPTSIZ.*/
  usbp->otg->oe[ep].DOEPTSIZ = DOEPTSIZ_STUPCNT(3) | DOEPTSIZ_PKTCNT(pcnt) |
                               DOEPTSIZ_XFRSIZ(rxsize);

  /* Special case of isochronous endpoint.*/
  if ((usbp->epc[ep]->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_ISOC) {
    /* Odd/even bit toggling for isochronous endpoint.*/
    if (usbp->otg->DSTS & DSTS_FNSOF_ODD)
      usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SEVNFRM;
    else
      usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_SODDFRM;
  }

  /* Starting operation.*/
  usbp->otg->oe[ep].DOEPCTL |= DOEPCTL_EPENA | DOEPCTL_CNAK;
}

User avatar
Giovanni
Site Admin
Posts: 14458
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1076 times
Been thanked: 922 times
Contact:

Re: STM32F401 USB maximum transfer size limitation

Postby Giovanni » Tue Apr 18, 2023 5:31 pm

Hi,

RAM is allocated when the EPs are created, look at function otg_ram_alloc() and the 2 places where it is called.

Giovanni

elagil
Posts: 92
Joined: Tue Sep 19, 2017 7:38 am
Has thanked: 8 times
Been thanked: 7 times

Re: STM32F401 USB maximum transfer size limitation

Postby elagil » Tue Apr 18, 2023 6:43 pm

I think I see the problem.

On initializing an endpoint, only the allocation of memory for the TX FIFO is checked (hal_usb_lld.c:1023, marked with >>> below).
For the RX FIFO that check does not exist. OTG_FS_GRXFSIZ is just set to the specified size of the RX FIFO, but there is no checking.

If you like, I can work on a patch.

Code: Select all


  /* OUT endpoint activation or deactivation.*/
  otgp->oe[ep].DOEPTSIZ = 0;
  if (usbp->epc[ep]->out_state != NULL) {
    otgp->oe[ep].DOEPCTL = ctl | DOEPCTL_MPSIZ(usbp->epc[ep]->out_maxsize);
    otgp->DAINTMSK |= DAINTMSK_OEPM(ep);
  }
  else {
    otgp->oe[ep].DOEPCTL &= ~DOEPCTL_USBAEP;
    otgp->DAINTMSK &= ~DAINTMSK_OEPM(ep);
  }

  /* IN endpoint activation or deactivation.*/
  otgp->ie[ep].DIEPTSIZ = 0;
  if (usbp->epc[ep]->in_state != NULL) {
    /* FIFO allocation for the IN endpoint.*/
    fsize = usbp->epc[ep]->in_maxsize / 4;
    if (usbp->epc[ep]->in_multiplier > 1)
      fsize *= usbp->epc[ep]->in_multiplier;
    otgp->DIEPTXF[ep - 1] = DIEPTXF_INEPTXFD(fsize) |
>>>                         DIEPTXF_INEPTXSA(otg_ram_alloc(usbp, fsize));
    otg_txfifo_flush(usbp, ep);

    otgp->ie[ep].DIEPCTL = ctl |
                           DIEPCTL_TXFNUM(ep) |
                           DIEPCTL_MPSIZ(usbp->epc[ep]->in_maxsize);
    otgp->DAINTMSK |= DAINTMSK_IEPM(ep);
  }
Last edited by elagil on Tue Apr 18, 2023 7:49 pm, edited 2 times in total.


Return to “Bug Reports”

Who is online

Users browsing this forum: No registered users and 10 guests