cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 & STM32F7 USB Host Core (Interrupt flood)

Tim Michals
Associate II
Posted on May 19, 2017 at 01:02

Issue:

USB Core issing interrupt at a rate of 8.65us causing high CPU loading.

Software/Chip:

Using USB Host/CDC from STM32Cube V1.15 on a STM32F429 board. 

  USB interrupt sources:

- SOF Interrupts (It is not needed for CDC type transfers) turned this interrupt off and still getting high interrupt rate.

   This is configured in

HAL_StatusTypeDef USB_HostInit (USB_OTG_GlobalTypeDef *USBx, USB_OTG_CfgTypeDef cfg)

.....

  /* Enable interrupts matching to the Host mode ONLY */

  USBx->GINTMSK |= (USB_OTG_GINTMSK_PRTIM            | USB_OTG_GINTMSK_HCIM |\

                 

   USB_OTG_GINTMSK_SOFM

|USB_OTG_GINTSTS_DISCINT|\

                    USB_OTG_GINTMSK_PXFRM_IISOOXFRM  | USB_OTG_GINTMSK_WUIM);

 

  return HAL_OK;

}

- NAK interrupts from bulk in endpoint.  The issue is when the OTG USB gets enough NAKs from the bulk endpoint and issues an interrupt at a rate of 8.625us. 

Solutions

?

Is there a work around that does not degrade USB performance?  The STM32FH7 also has has the same code to re-enable the bulk in endpoint. 

static void HCD_HC_IN_IRQHandler   (HCD_HandleTypeDef *hhcd, uint8_t chnum)

  }

  else if ((USBx_HC(chnum)->HCINT) &  USB_OTG_HCINT_NAK)

  {   

    if(hhcd->hc[chnum].ep_type == EP_TYPE_INTR)

    {

      __HAL_HCD_UNMASK_HALT_HC_INT(chnum);  

      USB_HC_Halt(hhcd->Instance, chnum);   

    }

    else if  ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL)||

         (hhcd->hc[chnum].ep_type == EP_TYPE_BULK))

    {

      /* re-activate the channel  */

      tmpreg = USBx_HC(chnum)->HCCHAR;

      tmpreg &= ~USB_OTG_HCCHAR_CHDIS;

      tmpreg |= USB_OTG_HCCHAR_CHENA;

      USBx_HC(chnum)->HCCHAR = tmpreg;

    }

    hhcd->hc[chnum].state = HC_NAK;

    __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK);

  }

}

There are several postings about this issue (The first posting is the best description of the issue)

https://community.st.com/0D50X00009XkYz2SAF

 

https://community.st.com/0D50X00009XkYSSSA3

 

https://community.st.com/0D50X00009Xked0SAB

 

null
37 REPLIES 37

Hello @AEila​ ,

Sorry for this delay.

In fact, this is a limitation in the OTG peripheral and will be fixed to implement the auto channel re-enable when IN-NAK received for next/new STM32 products.

I shared workaround provided for STM32H7 that implements the needed modifications (Unfortunately, not implemented on the STM32CubeF7 and CubeF4 packages and no plan to integrate officialy on HAL and USB Middleware).

1. Updated host lib with fix added during enumeration process, and non-periodic MSC IN bulk and CDC IN Bulk processes

2. Updated HAL

3. MSC applications with changes on usbd_conf.c/h files

User needs to set during init of the host controller the number of NAK’s allowed and the relaxing time in usbh_conf.c file via:

hhcd.Init.NakCount = 3U;

hhcd.Init.NakTimeout = USBH_HS_NAK_TIMEOUT_MS; /* for HS mode */

hhcd.Init.NakTimeout = USBH_FS_NAK_TIMEOUT_MS; /* for FS mode */

adjust the timeout in usbh_conf.h file via:

#define USBH_FS_NAK_TIMEOUT_MS 1000U /* Timeout in micro Second */

#define USBH_HS_NAK_TIMEOUT_MS 125U /* Timeout in micro Second */

Setting Timeout to Zero or NakCount to zero leads to switch to default mode (channel reactivation when NAK Int is received)

Kind Regards,

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
AEila
Associate

Thanks Imen, appreciate your feedback.

I've Cc'ed Guy Livneh, our software manager to follow up as needed.

Regards,

AGoma
Associate

I had this problem and resolve it.

CDC device has BULK endpoint type, but BULK channel planning in last order. After polling BULK endpoint from host and if device endpoint buffer is empty then device send NAK packet. After received packet on host host planning next request, except BULK endpoint we have not any endpoints and host request next packet at once. BULK endpoints are not planning periodic. You should be replace in CDC interface descriptor endpoint type, from bulk to interrupt, and set bInterval 1ms or more.

Also STM host library replace hardcoded EP type config in file "stm32_usb_host_library/class/cdc/src/usbh_cdc.c" by code below:

static USBH_StatusTypeDef USBH_CDC_InterfaceInit(USBH_HandleTypeDef *phost)
{
    USBH_StatusTypeDef status = USBH_FAIL;
    uint8_t interface;
    CDC_HandleTypeDef *CDC_Handle;
 
    interface = USBH_FindInterface(phost,
                                   COMMUNICATION_INTERFACE_CLASS_CODE,
                                   ABSTRACT_CONTROL_MODEL,
                                   COMMON_AT_COMMAND);
 
    if (interface == 0xFFU) /* No Valid Interface */
    {
        USBH_DbgLog ("Cannot Find the interface for Communication Interface Class.", phost->pActiveClass->Name);
    }
    else
    {
        USBH_SelectInterface(phost, interface);
        phost->pActiveClass->pData = &hcdc_instance;
        CDC_Handle = (CDC_HandleTypeDef*)phost->pActiveClass->pData;
 
        /*Collect the notification endpoint address and length*/
        if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U)
        {
            CDC_Handle->CommItf.NotifEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
            CDC_Handle->CommItf.NotifEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
        }
 
        /*Allocate the length for host channel number in*/
        CDC_Handle->CommItf.NotifPipe = USBH_AllocPipe(phost, CDC_Handle->CommItf.NotifEp);
 
        /* Open pipe for Notification endpoint */
        USBH_OpenPipe(phost, CDC_Handle->CommItf.NotifPipe, CDC_Handle->CommItf.NotifEp,
                      phost->device.address, phost->device.speed,
                      phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bmAttributes & 0x3, // this argument had been replaced
                      CDC_Handle->CommItf.NotifEpSize);
 
        USBH_LL_SetToggle(phost, CDC_Handle->CommItf.NotifPipe, 0U);
 
        interface = USBH_FindInterface(phost,
                                       DATA_INTERFACE_CLASS_CODE,
                                       RESERVED,
                                       NO_CLASS_SPECIFIC_PROTOCOL_CODE);
 
        if (interface == 0xFFU) /* No Valid Interface */
        {
            USBH_DbgLog ("Cannot Find the interface for Data Interface Class.", phost->pActiveClass->Name);
        }
        else
        {
            uint8_t ep_out_type = 0;    // this added
            uint8_t ep_in_type = 0;       // -//-
 
            /*Collect the class specific endpoint address and length*/
            if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U)
            {
                CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
                CDC_Handle->DataItf.InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
                ep_in_type = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bmAttributes & 0x3;
            }
            else
            {
                CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
                CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
                ep_out_type = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bmAttributes & 0x3;
            }
 
            if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress & 0x80U)
            {
                CDC_Handle->DataItf.InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
                CDC_Handle->DataItf.InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
                ep_in_type = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bmAttributes & 0x3;
            }
            else
            {
                CDC_Handle->DataItf.OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress;
                CDC_Handle->DataItf.OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize;
                ep_out_type = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bmAttributes & 0x3;
            }
 
            /*Allocate the length for host channel number out*/
            CDC_Handle->DataItf.OutPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.OutEp);
 
            /*Allocate the length for host channel number in*/
            CDC_Handle->DataItf.InPipe = USBH_AllocPipe(phost, CDC_Handle->DataItf.InEp);
 
            /* Open channel for OUT endpoint */
            USBH_OpenPipe(phost, CDC_Handle->DataItf.OutPipe, CDC_Handle->DataItf.OutEp,
                          phost->device.address, phost->device.speed,
                          ep_out_type,           // this argument had been replaced
                          CDC_Handle->DataItf.OutEpSize);
            /* Open channel for IN endpoint */
            USBH_OpenPipe(phost, CDC_Handle->DataItf.InPipe, CDC_Handle->DataItf.InEp,
                          phost->device.address, phost->device.speed,
                          ep_in_type,             // this argument had been replaced
                          CDC_Handle->DataItf.InEpSize);
 
            CDC_Handle->state = CDC_IDLE_STATE;
 
            USBH_LL_SetToggle(phost, CDC_Handle->DataItf.OutPipe, 0U);
            USBH_LL_SetToggle(phost, CDC_Handle->DataItf.InPipe, 0U);
            status = USBH_OK;
        }
    }
    return status;
}

 And in USB device library, where placed your CDC descriptor replace old code by code below, at the bottom:

  /*Endpoint OUT Descriptor*/
  0x07,   /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  CDC_OUT_EP,                        /* bEndpointAddress */
  0x03,                              /* bmAttributes: Interrupt */            
  LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  0x01,                              /* bInterval */
 
  /*Endpoint IN Descriptor*/
  0x07,   /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  CDC_IN_EP,                         /* bEndpointAddress */
  0x03,                              /* bmAttributes: Interrupt */
  LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  0x01                               /* bInterval */

Hello @Imen DAHMEN​ 

I know this is an old discussion. I am currently using a STM32H757 and I am running into the same issue. I got the source from STM Cube package for the H7 family. I see that that the USB Host library was updated April 2019, however, I dont see any notes relating to a fix for this issue. Is there a plan to fix the drivers for the H7 family?

Thanks!

Hello @TMiha​ ,

Happy new year !

This is a limitation in the OTG peripheral and there will be a lot of change in the HAL and Middleware.

We just offered in this discussion a generic and reliable workaround that does not affect performance in different use case, but Unfortunately no plan to integrate officialy on HAL and Middleware.

We apologize for any inconvenience this may cause and thank you for your understanding.

Best Regards,

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

So this means that current STM32 devices with USB OTG peripheral are not suitable for USB Host applications?

The 'generic and reliable' workaround is a little difficult to apply if you're using F4 or F7 parts, or a different version of the HAL. Any advice?

Imen,

Thanks for putting up a fix. I've been porting it to the STM32F745 and I noticed that there was a function missing in the solution you posted.

usbh_pipes.c has the following function:

USBH_StatusTypeDef USBH_ActivatePipe(USBH_HandleTypeDef *phost, uint8_t pipe_num)

{

 USBH_LL_ActivatePipe(phost, pipe_num);

 return USBH_OK;

}

But there doesn't seem to be a USBH_LL_ActivatePipe(...) anywhere.

There's a declaration for USBH_LL_ActivatePipe(phost, pipe_num); in usbh_core.h, but there's no function definition in usbh_core.c or usbh_conf.c. I'm guessing this function is defined in usbh_conf.c but was missed when you posted the fix.

Do you think you could post the definition for the following function?

USBH_StatusTypeDef  USBH_LL_ActivatePipe (USBH_HandleTypeDef *phost,

                      uint8_t);

Thanks in advance!

@DRmotion​  this is defined in the usbd_conf.c

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

I did find the usbh_conf.c in the MSC_Standalone/Src directory. Preliminary testing of the port indicates that everything is working for the STM32F745.

Best

Hello @DRmotion​ 

I am also trying to implement my own port of the fix above onto an STM32F769 and am having some troubles. Do you think you could post your port here?

Thank you in advance