This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Bug in HS USB device driver for STM32F4xxx (Middleware)

There's a nasty bug hidden in USBD_HS_STM32F4xx.c driver code.
It ALWAYS enables on-chip HSUSB PHY even if device is configured to use external PHY,
making PB15 wrongly routed to PHY instead of another configured peripheral (SPI2 MOSI in my case).

Fix is very simple:

static int32_t USBD_DeviceConnect (void) {
  if (!(otg_hs_state & OTG_HS_USBD_DRIVER_POWERED) ) { return ARM_DRIVER_ERROR; }
  if (  otg_hs_state & OTG_HS_USBD_DRIVER_CONNECTED) { return ARM_DRIVER_OK; }

  OTG->DCTL    &= ~OTG_HS_DCTL_SDIS;    // Soft disconnect disabled
#ifndef RTE_USB_OTG_HS_PHY
  OTG->GCCFG   |=  OTG_HS_GCCFG_PWRDWN;
#endif

  otg_hs_state |=  OTG_HS_USBD_DRIVER_CONNECTED;
  return ARM_DRIVER_OK;
}

It caused me a lot of headache, so I would like to share it with anyone that might have the similar
problem.

  • In latest DFP version v2.4.0 for STM32F400 pins are configured in OTG module and in that case if External ULPI phy is used pins for Embedded phy will not be configured for use with USB and should not interact with other peripherals.

    In your case it is also odd if pins are selected in alternate function for SPI it should not have any interaction with USB even if PWRDWN is unnecessarily used.

  • Sorry, but you got it wrong. It is not pin configuration that is wrong.
    I configured pins correctly and it works as supposed as long as USB controller's
    PHY is disabled but as soon as you enable it, it tooks control over PB15 regardless of
    how GPIO pin function is programmed... I can send you sample project for MCBSTM32F400 and you
    can check it for yourself.

  • If GPIO alternate function is not selected to USB, USB phy enable disable shouldn't impact pins,
    anyways it will be corrected in new ST pack.

  • Yes, it should not, but it does... :-)

  • Does

    static int32_t USBD_DeviceConnect (void) {
    
      if ((otg_hs_state & OTG_HS_USBD_DRIVER_POWERED) == 0U) { return ARM_DRIVER_ERROR; }
    
      OTG->DCTL    &= ~OTG_HS_DCTL_SDIS;    // Soft disconnect disabled
    #ifndef MX_USB_OTG_HS_ULPI_D7_Pin
      OTG->GCCFG   |=  OTG_HS_GCCFG_PWRDWN; // Disable power down
    #endif
    
      return ARM_DRIVER_OK;
    }
    

    From the brand new STM32F4 DFP 2.5.0 solve this for you?

    I need to know as we're on the starting line of a new project where this might matter...

  • Tobias, the new Pack 2.5.0 has indeed a fix for that problem (as Milorad describes).

  • Problem still presists in V2.xx drivers. That is, if RTE_Device.h is used for configuration, MX_USB_OTG_HS_ULPI_D7_Pin is not defined at all, so it won't work.
    I suggest following solution:

    static int32_t USBD_DeviceDisconnect (void) {
    
      if (hw_powered == false) { return ARM_DRIVER_ERROR; }
    
      OTG->DCTL  |=  OTG_HS_DCTL_SDIS;      // Soft disconnect enabled
    
    #if !defined(RTE_USB_OTG_HS_ULPI_D7_PIN) && !defined(RTE_USB_OTG_HS_ULPI_D7_PIN)
      OTG->GCCFG &= ~OTG_HS_GCCFG_PWRDWN;   // Enable power down
    #endif
    
      return ARM_DRIVER_OK;
    }
    

  • Talking about latest released STM32F4xx_DFP pack v2.10.0, and assuming Classic Framework is used.

    From expectation of functionality currently driver looks as expected.
    If External ULPI high-speed PHY is selected with RTE_USB_OTG_HS_PHY = 1 in OTG_HS_STM32F4xx.h header file the MX_USB_OTG_HS_ULPI_D7_Pin will get defined, else if On-chip full-speed PHY is selected in RTE_Device.h then MX_USB_OTG_HS_ULPI_D7_Pin will not get defined thus it is used in driver to figure out at compile time if external PHY or on-chip PHY is used.

    So, if MX_USB_OTG_HS_ULPI_D7_Pin is not defined means on-chip PHY is used and code should address that in driver (it looks like it does).

    BTW, in your suggestion you have twice same condition "!defined(RTE_USB_OTG_HS_ULPI_D7_PIN)" && "!defined(RTE_USB_OTG_HS_ULPI_D7_PIN)", probably an overlook. Also, in your suggestion RTE_USB_OTG_HS_ULPI_D7_PIN is always defined as it is done so by RTE_Device.h so your suggestion is same if you would have written

    #if 1
      OTG->GCCFG &= ~OTG_HS_GCCFG_PWRDWN;   // Enable power down
    #endif
    
    

    unless you manually change RTE_USB_OTG_HS_ULPI_D7_PORT_ID to value different than 0, in which case preprocessor would throw an error.

    It might be that there is some problem with functionality that you expect, we can try to clarify that?

    Best regards, Milorad