cancel
Showing results for 
Search instead for 
Did you mean: 

Flooded ''empty FIFO'' interrupts still make USB devices crawl

tsuneo
Senior
Posted on May 02, 2013 at 21:47

ST libraries in problem: STM32_USB-Host-Device_Lib_V2.1.0

Fixed usb_dcd_int.c is attached to this post. On this post, bil.til had pointed out on the problem of flooded ''empty FIFO'' interrupts on STM32_USB-FS-Device_Lib_V3.3.0 https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex%5fmx%5fstm32%2fYet%20another%20STM32F1057%20USB%20OTG%20driver%20issue%20%28VCP%20device%29 This problem was carried over to the USB device implementation of STM32_USB-Host-Device_Lib. On recent libraries, ST have tried to fix this problem, but they didn't follow bil.til's solution. bil.til suggests that the ''empty FIFO'' interrupt should be masked in DCD_WriteEmptyTxFifo(), which is called by ''empty FIFO'' interrupt. But ST masks ''empty FIFO'' interrupt at the transfer completion interrupt, as follows.

STM32_USB-Host-Device_Lib_V2.1.0\Libraries\STM32_USB_OTG_Driver\src\usb_dcd_int.c
static uint32_t DCD_HandleInEP_ISR(USB_OTG_CORE_HANDLE *pdev)
{
... 
while ( ep_intr )
{
if (ep_intr&0x1) /* In ITR */
{
diepint.d32 = DCD_ReadDevInEP(pdev , epnum); /* Get In ITR status */
if ( diepint.b.xfercompl ) // <--- transfer completion interrupt
{
fifoemptymsk = 0x1 << 
epnum
; // <--- ST's bad solution
USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0); // <---

As the result, flooded ''empty FIFO'' interrupts still make the firmware crawl until host would initiate IN transactions. As you know, host doesn't always put IN transactions immediately after the firmware calls DCD_EP_Tx(). Here is the REAL fix, followed to bil.til solution.

STM32_USB-Host-Device_Lib_V2.1.0\Libraries\STM32_USB_OTG_Driver\src\usb_dcd_int.c
static uint32_t DCD_WriteEmptyTxFifo(USB_OTG_CORE_HANDLE *pdev, uint32_t epnum)
{
...
while (txstatus.b.txfspcavail > len32b &&
ep->xfer_count < 
ep-
>xfer_len &&
ep->xfer_len != 0)
{
/* Write the FIFO */
len = ep->xfer_len - ep->xfer_count;
if (len > ep->maxpacket)
{
len = ep->maxpacket;
}
len32b = (len + 3) / 4;
USB_OTG_WritePacket (pdev , ep->xfer_buff, epnum, len);
ep->xfer_buff += len;
ep->xfer_count += len;
// <--------- fix: from here
if( ep->xfer_count >= ep->xfer_len){
uint32_t fifoemptymsk = 1 << 
epnum
;
USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0);
break;
}
// <--------- fix: to here
txstatus.d32 = USB_OTG_READ_REG32(&pdev->regs.INEP_REGS[epnum]->DTXFSTS);
}
return 1;
}

Tsuneo
2 REPLIES 2
ivous2
Associate
Posted on January 21, 2014 at 13:29

Hello Tsuneo,

Thanks for reporting this problem. Your solution is not complete. There is one more occurrence of 

CLEAR_IN_EP_INTR(1, emptyintr);

It is in the same file and you have to replace this macro with :

fifoemptymsk = 0x1 << 1;

USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0)

Regards,

Ivo
yingf
Associate
Posted on June 25, 2014 at 03:49

Hello,

Lvo

Thanks for your great sharing which helped me solve the most problems. Unfortunately, I encounted one more problem with the function DCD_WriteEmptyTxFifo(), specifically with the code line

txstatus.d32 = USB_OTG_READ_REG32( &pdev->regs.INEP_REGS[epnum]->DTXFSTS);

the problem is the value of txstatus.d32 is never updated with DTXFSTS. therefore the while condition txstatus.b.txfspcavail > len32b can not be satisfied.

I want to ask you guys whether or not you met the same problem with EP2 other than EP0? how did you fix this problem?

Really appreciated your great help! Best regards! --Ying