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!
STM32F401 USB maximum transfer size limitation
- 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
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
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
- 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
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
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
Re: STM32F401 USB maximum transfer size limitation
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.
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.
Re: STM32F401 USB maximum transfer size limitation
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.
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.
- 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
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
Giovanni
Re: STM32F401 USB maximum transfer size limitation
Where do I find that assertion?
It is not in the function that I call for receiving on an OUT endpoint:
nor is it in the OTG lld function that the above calls:
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;
}
- 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
Hi,
RAM is allocated when the EPs are created, look at function otg_ram_alloc() and the 2 places where it is called.
Giovanni
RAM is allocated when the EPs are created, look at function otg_ram_alloc() and the 2 places where it is called.
Giovanni
Re: STM32F401 USB maximum transfer size limitation
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.
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.
Who is online
Users browsing this forum: No registered users and 10 guests