4
\$\begingroup\$

I have a battery-powered device using an STM32F107. The device works and I am currently working on minimizing its power consumption.

One of the bigger current draws is the USB subsystem itself, using about 8mA when idle. The USB is only used for configuration purposes; it is almost always unnecessary to have it enabled.

I am using ST's USB Library v2.1.0. It communicates as a CDC class Virtual COM Port ("VCP"). I'm using the embedded Full Speed PHY.

Upon power-up I want the USB to initialize and be active for, say, 30 seconds. After this, assuming there is no connection to a host, I want to simply shut down the USB functionality. As if I had never enabled it in the first place.

I don't see anything exposed in the API which would make this possible. There are a few noteworthy functions but they don't seem to be what I need:

  • from the API template: usbDeInit()

    This is intended for custom user code. However, it is called by the device driver function usbd_cdc_DeInit(), which is never actually called, as far as I can see.

  • in the cdc_core library: usbd_cdc_DeInit()

    This is the file that never is called in the driver source. It closes the endpoints, then calls the (previously mentioned) usbDeInit() function. It seems promising; however, it is declared as static in the driver source. I'm hesitant to change the driver library code directly as this will get overwritten when updating ST's driver in the future.

  • from the device_core library: USBD_DeInit()

    This is called by the driver in a few places, but is empty. That is, the function contains no code at all. Again, I'd rather not change ST's driver source.

My initialization routing looks like this:

// Configure USB Clock Source
RCC_OTGFSCLKConfig(RCC_OTGFSCLKSource_PLLVCO_Div3);

// Enable USB Clock
RCC_AHBPeriphClockCmd(USB_AHB_CLK, ENABLE);

// Initialize USB
USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_CDC_cb, &USR_cb);

Of course, if I simply disable the USB clock source then the microcontroller hangs.

I've made sure that the USB_OTG_FS_LOW_PWR_MGMT_SUPPORT switch is enabled in the usb_conf.h file, but the current draw remains. I'm assuming it doesn't go into suspend mode (which, as Ali Chen says, would be the proper solution).

  1. Anybody know how to achieve what I'm looking for?
  2. Is there anything special I need to do at the Host side to tell the device to suspend?
\$\endgroup\$
  • \$\begingroup\$ Why you don't want to use SUSPEND function? There should be a standard power management API. Every USB these days is designed from power management perspective, first thing. The suspend function is exactly the function you need, it should stop PHY clock and controller clock properly. \$\endgroup\$ – Ale..chenski Jan 20 '17 at 2:14
  • 1
    \$\begingroup\$ STM32 peripherals typically have a power management bit, and a clock enable bit. Deactivate any software components that would complain, de-assert these enables per the programmer's manual or whatever HAL you are using, and if you can disable the presence detect/speed pullup. Chitchat with the host about what you plan to do is fairly optional... you could just appear to be unplugged. Of course you could also only ever start up the USB block if you see Vbus. \$\endgroup\$ – Chris Stratton Jan 20 '17 at 2:58
  • \$\begingroup\$ Thanks, @ChrisStratton, I like the "check for Vbus" idea. \$\endgroup\$ – bitsmack Jan 23 '17 at 21:39
4
\$\begingroup\$

Disabling functional blocks as USB in a modern SoC is not something that is advised to be done on register level by user. The USB IP block contains several sub-blocks and interfaces between them: access fabric, core controller, FIFOs/SIPOs, PHY. All interfaces usually work with some handshake protocols that usually require some presence of clocks on both sides of the interface, so arbitrary mocking with clock control registers might result in deadlocks. Therefore it is strongly advised to use pre-designed functions (as SUSPEND) from software IP to manage USB block. The documentation says, in part:

The OTG_HS interface has the following features: ... - Powersaving features such as system clock stop during USB suspend, switching off of the digital core internal clock domains, PHY and DFIFO power management ...

and

Device suspend When the device detects a suspend condition on the USB, the library stops all the operations and puts the system to suspend state (if low power mode is enabled by in the usb_conf.h file).

Therefore, to accomplish the power savings task, I would strongly advise to use already developed functions from STM USB library.

ADDITION: The STM package seems to have a limitation that the suspend or disconnect modes cannot be forced by user firmware. Here is an idea: After the device function is finished, switch the OTG controller into HOST MODE. But then don't proceed with initialization of the HOST function, or shut the HOST function down. It might result in fully disabled USB block.

\$\endgroup\$
  • \$\begingroup\$ Thanks, and I agree with you. I don't see anywhere in the API to force suspend mode; it seems to be driven by the host. I've enabled the USB_OTG_FS_LOW_PWR_MGMT_SUPPORT switch in the usb_conf.h file, but the current draw still exists. Should the user be able to force Suspend mode? \$\endgroup\$ – bitsmack Jan 20 '17 at 19:03
  • \$\begingroup\$ You are right, the normal suspend function should occur automatically in 3ms after the upstream link drops USB activity (flow of SOFs). However, there should be forced disconnect function on device side. I am not a software guy, I just want to warn you about general complexities of clock and power gating in the USB IP block. \$\endgroup\$ – Ale..chenski Jan 20 '17 at 19:14
  • \$\begingroup\$ Yep, I also don't see the "force disconnect" function in the package. Too bad. Usually the forced disconnect function is used when a developer needs to switch roles of the device, say from debug mode to normal mode, or after loading/updating device's firmware, with change in VID/PID. Then you need to create this function, which will be challenging, since fine details of register interfaces are usually protected and secured by manufacturer. \$\endgroup\$ – Ale..chenski Jan 20 '17 at 19:32
  • \$\begingroup\$ Some designs implement "force disconnect" with analog switches that open the data lines outside the chip. \$\endgroup\$ – Ronan Paixão Jan 22 '17 at 16:55
1
\$\begingroup\$

You probably need to disable everything in inverse order. Try:

USBD_DeInit();
RCC_AHBPeriphClockCmd(USB_AHB_CLK, ENABLE);

Or maybe the inverse.

\$\endgroup\$
  • \$\begingroup\$ The API for STM32 do contain special functions to put the USB controller and PHY in SUSPEND. This is precisely the function that "disables everything" in correct order, without "or" or "maybe". Hacking this functionality at register level is highly unwise. \$\endgroup\$ – Ale..chenski Jan 20 '17 at 18:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.