AnsweredAssumed Answered

Bug in STM32_USB_OTG_Driver causes 100% CPU in fifo empty interrupts

Question asked by osterlund.petter on Nov 22, 2012
Latest reply on Nov 22, 2012 by bulychev.alexand.002
There is a bug in STM32_USB-Host-Device_Lib_V2.1.0 and earler versions.

When sending data on an EP the data is placed in a FIFO. Packets are then accepted by the core and eventually fetched by the usb host. Consider the simpest case where just one packet is to be sent. Then the FIFO will be filled with say 10 bytes and directly accepted by the core. Now the FIFO is empty and an emptyintr is generated. As there is no more data to send nothing more happens except clearing the IRQ. Then the interrupt is asserted again, and again until the PC fetches the data from the EP. Now the transfer comple interrupt triggered, xfercompl. This is handled by the library by disabling fifoemptymsk and notify the user that transfer is completed.

As the packet cannot be scheduled for pickup immediately the processor will be fully occupied with handling fifoempty interrupts during this time which may be bad for the application if it has other stuff to. In particular if the driver is not asking for data this will be a permanent state.

A fix for this can be made in usb_dcd_int.c in two places.

1. First disable fifo interrupt when last byte is put in fifo:
static uint32_t DCD_WriteEmptyTxFifo()
// --- start fix (just before return 1)
  if (len < ep->maxpacket)
    // FIFO empty
    fifoemptymsk = 0x1 << epnum;
    USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0);    
// end of fix
  return 1;
// end of function

2. Remove the lines within the #if 0 block as it is not needed any more.
static uint32_t DCD_HandleInEP_ISR()
      if ( diepint.b.xfercompl )
#if 0 // THIS CODE IS REMOVED, done in DCD_WriteEmptyTxFifo()
        fifoemptymsk = 0x1 << epnum;
        USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, fifoemptymsk, 0);
        CLEAR_IN_EP_INTR(epnum, xfercompl);
        /* TX COMPLETE */
        USBD_DCD_INT_fops->DataInStage(pdev , epnum);

NOTE: The same bug is likely on EP0 as well and needs a similar fix.