Hi guys,
I am in need of your help, unfortunately STs documentation is lacking some information here.

I am basically trying to implement a USB device (CDC-ACM to be precise) that utilizes suspend/wakeup. I am using the "STM32_USB-Host-Device_Lib_V2.1.0" and looked into the HID example for help. 
Unfortunately there is no example that shows the USB HS with suspend/wakeup using an external ULPI. I am using the SMSC USB3300 ULPI chip with an external 24MHz crystal.

The first thing that baffles me is in dcd_int.c:
Below the function DCD_HandleUSBSuspend_ISR gets called on a suspend interrupt. This interrupt gets called successfully.

  1. uint32_t USBD_OTG_ISR_Handler (USB_OTG_CORE_HANDLE *pdev)
  2. {
  3. ...
  4. if (gintr_status.b.usbsuspend)
  5. {
  6. retval |= DCD_HandleUSBSuspend_ISR(pdev);
  7. }
  8. ....
  9. }

Now, inside this function I see:

  1. if((pdev->cfg.low_power) && (dsts.b.suspsts == ) &&
  2. (pdev->dev.connection_status == ) &&
  3. (prev_status == USB_OTG_CONFIGURED))
  4. {
  5. /* switch-off the clocks */
  6. ....
  7. }

The strange part now is, that I cannot find another reference of dev.connection_status, which gets tested in this if-statement, thus this variable never gets to 1 and I wonder why and what I am missing.
Also prev_status (which gets set by dev.device_status) never equals USB_OTG_CONFIGURED which is defined as 3. It always is equal to 2, which is defined as USB_OTG_ADDRESSED

This lead to the problem that obviously, the ULPI never went into the low power mode. I commented out the two non-reachable if-conditions and now I can see the USB3300 to stop its external 24MHz oscillator. I should note that I commented out the deepsleep part in this function

Now comes the second thing, I can not yet understand. As in the HID example, I activated the EXTI_Line20 and enabled the OTG_HS_WKUP_IRQn in USB_OTG_BSP_Init. Now when I disable my device in the windows device manager, I no longer see the SOF microframes on my oscilloscope. The suspend interrupt gets called and I disable the USB3300 clocks as shown above. 
Unfortunately, the OTG_HS_WKUP_IRQHandler gets called now immediately and with the call to USB_OTG_UngateClock enables the USB3300 clocks again. After some time, the HS core sees the suspend condition on the bus and goes to suspend AGAIN. This keeps repeating on and on.

So I had some long looks into the Ref Man having the tongue at the right angle and read something like:
EXTI line 20 is connected to the USB OTG HS (configured in FS) Wakeup event

So I wondered: since I am using HS usb with external phy and the USB OTH HS core, is this even necessary for waking up? Maybe the strange behaviour is here? 
The sad thing is, that I can't seem to find anything on people trying to use USB suspend with external PHYs.
As far as I understood, the EXTI Line 20 is used to asynchronously detect any changes on the USB lines and feed it into the NVIC, which in turn knows that it has to call the OTG_HS_WKUP_IRQHandler.
Now since I am using the ULPI, I don't think this is valid anymore. However, there seems to be yet another instance of wakeup interrupts buried within the HS core: OTG_HS_GINTSTS contains an interrupt status flag for waking up: WKUINT
And now I am completely confused why there are so many configuraiton possibilites for the wakeup interrupt. 
Again, since the documentation is lacking information on this (or I simply can not find it, though searching for some days now) I can not figure out, how to correctly implement USB HS wake up using the external PHY.

This is why am I am searching for help here in the forum and hope someone can shed some light onto this. I am very much looking forward to any means of helping, thanks!

EDIT at 14:58. Found this in the reference manual of the USB stack:
Even if the #define USB_OTG_HS_LOW_PWR_MGMT_SUPPORT is uncommented, the
USB HID Device enters Low Power mode but cannot wakeup after a new Host
connection.
This behavior is normal since the wakeup signal in the USB OTG HS Core is available
only when the USB OTG HS core is working in Full Speed mode.

What exactly does that mean? Do I have to set the core into FS mode after suspend and then wait for wake up? Or should I use FS mode only?

Hi

Yes, I cannot get it to work either.
Im working on USB CDC/VCP.

"The strange part now is, that I cannot find another reference of dev.connection_status"
Yes, you have to add
#define VBUS_SENSING_ENABLED
to usb_conf.h

to enable the connect/disconnect ISRs which then change the state.

"After some time, the HS core sees the suspend condition on the bus and goes to suspend AGAIN. This keeps repeating on and on."
Yes, I got this as well.

I have put in a request for help with our ST rep

Hi!
I found the problem with dev.connection_status, you are right as in that I had to define
#define VBUS_SENSING_ENABLED
#define USB_OTG_INTERNAL_VBUS_ENABLED

to use with my USB3300 ULPI chip. Now i get the correct connection status in the suspend ISR.

In the meantime I managed to enumerate in Full Speed mode using the ULPI chip and my hope was, that suspend would work better here,
as the USB library manual states. But I was disappointed, because I get the exact same behaviour as before:
As soon as the device notices the suspend, it disables the clocks. But immediately after that, I get the wake interrupt and enter the loop I have described before.

I am somehow glad, that I am not the only one having this exact problem.

I found something else, that is rather curious: Why does "the" USBD_OTG_ISR_Handler contain this

  1. if (gintr_status.b.wkupintr)

Although I could never get the HS core to set the wkupintr bit and execute the OTG_HS_IRQHandler, although the mask bit in GREGS->GINTMSK is set (in USB_OTG_EnableCommonInt)

And why does it even exist, when there is the OTG_HS_WKUP_IRQHandler that is supposed to be used for waking?

I guess I am doing something wrong regarding the wake up handling. Lets see what STM has to say about this.

Bye!

For the sake of completeness, here is the contents of my Wakeup ISR Handler

  1. void OTG_HS_WKUP_IRQHandler(void)
  2. {
  3. if(USB_OTG_dev.cfg.low_power) {
  4. USB_OTG_CORE_HANDLE* pdev = &USB_OTG_dev;
  5. USB_OTG_GINTSTS_TypeDef gintsts;
  6. USB_OTG_DCTL_TypeDef devctl;
  7. USB_OTG_PCGCCTL_TypeDef power;
  8.  
  9. USB_OTG_UngateClock(&USB_OTG_dev);
  10.  
  11. /* Clear the Remote Wake-up Signaling */
  12. devctl.d32 = ;
  13. devctl.b.rmtwkupsig = ;
  14. USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DCTL, devctl.d32, );
  15.  
  16. /* Inform upper layer by the Resume Event */
  17. USBD_DCD_INT_fops->Resume (pdev);
  18.  
  19. /* Clear interrupt */
  20. gintsts.d32 = ;
  21. gintsts.b.wkupintr = ;
  22. USB_OTG_WRITE_REG32 (&pdev->regs.GREGS->GINTSTS, gintsts.d32);
  23.  
  24. uint32_t A = USB_OTG_READ_REG32(&pdev->regs.PCGCCTL);
  25. uint32_t B = USB_OTG_READ_REG32(&pdev->regs.GREGS->GINTSTS);
  26. uint32_t C = USB_OTG_READ_REG32(&pdev->regs.GREGS->GUSBCFG);
  27. }
  28.  
  29. NVIC_ClearPendingIRQ(OTG_HS_IRQn);
  30. EXTI_ClearITPendingBit(EXTI_Line20);
  31. }

To be more precise: If i re-enable my USB device in the device manager again, and the host starts spitting out SOFs again, the STM32 breaks the loop (probably because the suspend function is not called anymore)

Just to let you know, I found something veeeery interesting in the code of the STM32CubeF4 here:
http://www.st.com/web/en/catalog/tools/PF259243#
File:
stm32cubef4.zip\STM32Cube_FW_F4_V1.1.0\Projects\STM324xG_EVAL\Applications\USB_Device\HID_Standalone\Src\usbd_conf.c

  1. void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
  2. {
  3. __IO uint32_t i=;
  4.  
  5. if (hpcd->Instance == USB_OTG_HS)
  6. {
  7. __HAL_USB_HS_EXTI_DISABLE_IT();
  8.  
  9. __HAL_PCD_GATE_PHYCLOCK(hpcd);
  10.  
  11. /*wait tiemout of 6 ULPI PHY clock ~= 18 cpu clocks @168MHz*/
  12. for (i=; i<; i++)
  13. {
  14. __NOP();
  15. }
  16.  
  17. if (__HAL_PCD_IS_PHY_SUSPENDED(hpcd)) /* when set then false resume condition*/
  18. {
  19. __HAL_USB_HS_EXTI_CLEAR_FLAG();
  20. __HAL_USB_HS_EXTI_ENABLE_IT();
  21.  
  22. USBD_LL_Suspend(hpcd->pData);
  23.  
  24. /*Enter in STOP mode */
  25. if (hpcd->Init.low_power_enable)
  26. {
  27. /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register */
  28. SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
  29. }
  30. }
  31. }
  32. else
  33. {
  34.  
  35. __HAL_PCD_GATE_PHYCLOCK(hpcd);
  36. USBD_LL_Suspend(hpcd->pData);
  37.  
  38. /*Enter in STOP mode */
  39. if (hpcd->Init.low_power_enable)
  40. {
  41.  
  42. /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register */
  43. SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
  44. }
  45.  
  46. }
  47.  
  48. }

It looks like there are some specialties regarding HS core and suspending. As far as I can see, the EXTI line for wake up is deactivated while the HS core is put into suspend.

And of course, THIS was the problem. I reverse engineered the code from the zip file and entered it into the usb stack
I quote from usb_dcd_int.c:

  1. static uint32_t DCD_HandleUSBSuspend_ISR(USB_OTG_CORE_HANDLE *pdev)
  2. {
  3. USB_OTG_GINTSTS_TypeDef gintsts;
  4. USB_OTG_PCGCCTL_TypeDef power;
  5. USB_OTG_DSTS_TypeDef dsts;
  6. __IO uint8_t prev_status = ;
  7.  
  8. prev_status = pdev->dev.device_status;
  9. USBD_DCD_INT_fops->Suspend (pdev);
  10.  
  11. dsts.d32 = USB_OTG_READ_REG32(&pdev->regs.DREGS->DSTS);
  12.  
  13. /* Clear interrupt */
  14. gintsts.d32 = ;
  15. gintsts.b.usbsuspend = ;
  16. USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32);
  17.  
  18. if((pdev->cfg.low_power) && (dsts.b.suspsts == ) &&
  19. (pdev->dev.connection_status == ) )//&&
  20. // (prev_status == USB_OTG_CONFIGURED))
  21. {
  22. #ifndef USE_USB_OTG_HS
  23.  
  24. /* switch-off the clocks */
  25. power.d32 = ;
  26. power.b.stoppclk = ;
  27. USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, , power.d32);
  28.  
  29. power.b.gatehclk = ;
  30. USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, , power.d32);
  31. #else
  32. #define USB_HS_EXTI_LINE_WAKEUP ((uint32_t)0x00100000) /*!< External interrupt line 20 Connected to the USB HS EXTI Line */
  33.  
  34. /* Disable EXTI for wakupe */
  35. EXTI->IMR &= ~(USB_HS_EXTI_LINE_WAKEUP);
  36.  
  37. /* Gate PHY clock */
  38. power.d32 = ;
  39. power.b.stoppclk = ;
  40. USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, , power.d32);
  41.  
  42. power.b.gatehclk = ;
  43. USB_OTG_MODIFY_REG32(pdev->regs.PCGCCTL, , power.d32);
  44.  
  45. /* Wait timeout of 6 ULPI PHY clock. found this in STM324 HID eval code */
  46. for (uint32_t i=; i<; i++) {
  47. __NOP();
  48. }
  49.  
  50. power.d32 = USB_OTG_READ_REG32(pdev->regs.PCGCCTL);
  51.  
  52. if (power.b.phy_susp) {
  53. /* Clear flag and enable IT */
  54. EXTI->PR = (USB_HS_EXTI_LINE_WAKEUP);
  55. EXTI->IMR |= (USB_HS_EXTI_LINE_WAKEUP);
  56. }
  57. #endif
  58.  
  59. /* Request to enter Sleep mode after exit from current ISR */
  60. //SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk);
  61. }
  62.  
  63. return ;
  64. }
And everything works as expected. I suspect the culprit to be the missing 6 ULPI clock delays. If you look carefully in the USB3300 datasheet, it says that after disabling the clocks, the ULPI is active for another 5 (or something) clock cycles, before it eventually shuts down and feeds through the USB lines to the ULPI in order for the OTG HS core to monitor them for wake up.

 

STM32F4, USB HS with ULPI and Suspend/Wakeup的更多相关文章

  1. STM32F4 HAL Composite USB Device Example : CDC + MSC

    STM32F4 USB Composite CDC + MSC I'm in the process of building a USB composite CDC + MSC device on t ...

  2. usb驱动开发5之总线设备与接口

    Linux设备模型中的总线落实在USB子系统里就是usb_bus_type,它在usb_init的函数bus_register(&usb_bus_type)里注册.usb_bus_type定义 ...

  3. Qt 获取usb设备信息 hacking

    /************************************************************************** * Qt 获取usb设备信息 hacking * ...

  4. 设备管理 USB ID

    发现个USB ID站点,对于做设备管理识别的小伙伴特别实用 http://www.linux-usb.org/usb.ids 附录: # # List of USB ID's # # Maintain ...

  5. linux usb总线驱动(一)

    目录 linux usb总线驱动框架 USB 介绍 传输类型 控制器接口 2440接口 基本流程 alloc_dev choose_address hub_port_init usb_get_devi ...

  6. DM816X 实现 USB HID Gadget 鼠标键盘功能【转】

    转自:https://my.oschina.net/renyongke/blog/410695 开发环境: 平台: DM8168 内核 :linux 2.6.32 RDK:DVRRDK_04.00.0 ...

  7. Android USB驱动源码分析(-)

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  8. Linux 内核注册一个 USB 驱动

    所有 USB 驱动必须创建的主要结构是 struct usb_driver. 这个结构必须被 USB 驱动填 充并且包含多个函数回调和变量, 来向 USB 核心代码描述 USB 驱动: struct ...

  9. STM32F4xx -- Cortex M4

    STM32F4xx official page: http://www.st.com/internet/mcu/subclass/1521.jspIntroductionFPU - Floating ...

随机推荐

  1. Unable to Distribute in Xcode5?

    Blog Unable to Distribute in Xcode5? I have the  question, if this screenshot is what you getting. ( ...

  2. python中的__getattr__、__getattribute__、__setattr__、__delattr__、__dir__

    __getattr__:     属性查找失败后,解释器会调用 __getattr__ 方法. class TmpTest: def __init__(self): self.tmp = 'tmp12 ...

  3. NOIP2016-D2-T2 蚯蚓(单调队列)

    构建三个单调队列(用STL),分别储存未切的蚯蚓,切后的第一段,切后的第二段,即可简单证明其单调性. 证明:设$q$为单调队列$\because a_1 \geqslant a_2 \geqslant ...

  4. linux下搭建我的世界spongeforge 服务器 (海绵端)

    以下我用的都是1.10.2版本 且以下用的服务器连接管理软件有WinSCP.Xshell 5 首先,去下载一个MC1.10.2的纯净服务端,这个不会很难,百度一下! 比如我下的文件就叫minecraf ...

  5. Maven从私服上下载所需jar包——(十四)

    1.修改settings.xml 将下面代码添加到settings.xml中 <profile> <!--profile的id--> <id>dev</id& ...

  6. 常用Javascript集锦【不定期更新】

    怎样用javascript删除某个HEML标签 document.getElementById(id).parentNode.removeChild(document.getElementById(i ...

  7. java 编译与运行

    javac  编译 .java文件 javac file.java //将file.java 编译为 file.classjavac -d folder file.java //将file.java ...

  8. jq选择子元素

    jq选择子元素 一.获取父级元素 1. parent([expr]): 获取指定元素的所有父级元素 <div id="par_div"><a id="h ...

  9. MVC -18.缓存(2)

    一.MVC缓存简介 缓存是将信息(数据或页面)放在内存中以避免频繁的数据库存储或执行整个页面的生命周期,直到缓存的信息过期或依赖变更才再次从数据库中读取数据或重新执行页面的生命周期.在系统优化过程中, ...

  10. Polly公共处理 -重试(Retry)

    封装处理下Polly重试 private ILogger<PollyHelper> _logger; /// <summary> /// /// </summary> ...