AnsweredAssumed Answered

Flooded "empty FIFO" interrupts still make USB devices crawl

Question asked by Chinzei.Tsuneo on May 2, 2013
Latest reply on Jun 25, 2014 by jia.ying
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

Attachments

Outcomes