cancel
Showing results for 
Search instead for 
Did you mean: 

How to reduce power consumption while connected via CDC USB

antfarmer
Associate III

I'm developing a board with an STM32L452 and would like to find out if I can improve power consumption while it remains connected via USB (as a device). I've tried putting the device to sleep using the following code:

 

while (1) {
	// ... do stuff
	HAL_SuspendTick();
	HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
	HAL_ResumeTick();
}

 

My configuration for USB is CDC and has SOF, Low power, and Link power management enabled. I've tried changing these settings, but none of these seem to make a difference.

 

The issue is the USB IRQ keeps the device from staying in sleep mode, so there's very little difference in power usage overall. I would like to keep the USB connection, otherwise the host pc software would have to poll and try reconnecting constantly. I know the host can tell the device to suspend, but is there a way the USB device can tell the host to pause and continue if either the host or device have something to communicate? Sort of like SDMMC can do with clock power saving mode.

1 ACCEPTED SOLUTION

Accepted Solutions
antfarmer
Associate III

Looks like there's no way to really improve the power usage beyond this point while connected to usb. Reading more from this presentation, it appears that the SOF packet is not handled in the peripheral, but rather the stm32 interrupt. So this will prevent the cpu from staying in sleep. It would have been nice if these could be handled in the peripheral and allow the cpu to sleep until there is an rx/tx event like usart. Anyway, thanks for the advice on this.

View solution in original post

10 REPLIES 10

What's it drawing now and what's the goal?

What's happening in "do stuff"?

WFI should allow for relatively low consumption between interrupts, especially if the "do stuff" can be limited and gated by knowing if you "need to do stuff" or what stuff specifically has to get done in this sleep cycle vs the interrupt source that woke it.

Most of the USB Library is likely premised on the PC powering the system, maybe look to see if their are commercial libraries with different priorities or expectations? 

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

Right now it's about 7.8mA which is pretty much what the power calculator says for the run state. I'd like to get closer to the sleep state calculation, roughly 2.1mA. This runs on its own supply with battery, so that would be a big improvement.

The main loop is fairly quiet, only running the ADC every 5 seconds or so. I know the USB is creating the issue as I've added a line in the USB PCD IRQ to increment some leds and it flashes like crazy the whole time. Adding the same code to all the other IRQ handlers just increments the led's every 5 seconds as expected. I'll have to look to see other libraries, but I'm not even sure if that's even possible within the USB communication framework.

Not sure, but look to see if the cause of the IRQ can be determined, or if it's due to constant querying or keep-alive from the host side, or that the source isn't cleared.

Probably using USBSER.SYS, so shot-gunned that, 32ms period? (31.25 Hz)

https://community.arm.com/support-forums/f/keil-forum/32273/usbser-sys-quirks-explained

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Piranha
Chief II

Taking both of these suggestions I found the cause of the extra wake cycles. I created a 10s timer which prints the total number of microseconds taken by each interrupt and how much was in sleep. Also, I realized I was measuring the current for the entire board, the current just for the MCU section is a little over 6mA. Anyway, here are the timings:

----CPU Times (us)---- 6mA @ MCU w/ SOF int
sleep: 9,976,854
main: 16,096
dma1: 10
usb: 28,008

 

So then I dug into the USB PCD logic and put counters in the IRQ handler there to see how many calls were occurring:

----USB IRQs----
usbEndPoint: 43
...
usbSOF: 9999
usbESOF: 0

 

So this matches the 1ms SOF signal. I'm surprised this in there since I don't use it for anything. I decided to disable the interrupt to see what would happen. Everything still works which is good, but it only showed a 100uA savings, if that. Here are the new numbers:

----CPU Times (us)---- 5.9mA @ MCU w/o SOF int
sleep: 9,994,562
main: 5,422
dma1: 12
usb: 292

----USB IRQs----
usbEndPoint: 43
...
usbSOF: 0
usbESOF: 0

 

So while the disabling the SOF interrupt improves the cpu sleep time and current draw, it's not that much really. I had to modify the stm32l4xx_ll_usb.c file so I'm not to excited about having to replace that each time any ioc configuration changes. In my reading, I think what would really improve the power usage is to put the link in L1 state available under LPM. Apparently the host is supposed to manage that, but I'm not sure how to issue such low-level commands from the dumb terminal emulator I'm using on Linux, or any software I'm aware of for that matter. Anyone is aware of how to issue these commands from the host or the device?

antfarmer
Associate III

Looks like there's no way to really improve the power usage beyond this point while connected to usb. Reading more from this presentation, it appears that the SOF packet is not handled in the peripheral, but rather the stm32 interrupt. So this will prevent the cpu from staying in sleep. It would have been nice if these could be handled in the peripheral and allow the cpu to sleep until there is an rx/tx event like usart. Anyway, thanks for the advice on this.

Pavel A.
Evangelist III

Answer of Artificial Intelligence...

---- [quote

"According to the USB 2.1 specification, a USB device can request the host to enter suspend mode by sending a Remote Wakeup signal. This signal is a single-ended zero (SE0) state on the upstream facing port for at least 2.5 microseconds and less than 15 milliseconds. The device must be in the Enabled state and have the Remote Wakeup feature enabled by the host before sending this signal. The host will acknowledge the signal by suspending the bus within 10 milliseconds [1]

However, not all hosts support the Remote Wakeup feature, and some devices may not be able to generate the SE0 state. In that case, the device cannot initiate the suspend mode, and it depends on the host to suspend the bus after detecting no bus traffic for 3 milliseconds.

 

[1] USB 2.1 Specification, Section 7.1.7.6 
--- quote]
 

Thanks for your post. I'm not sure what is meant by "request the host to enter suspend mode". In the other direction, host to device, this wording describes the mechanism which tells the device that the host is going to suspend mode and reduce power consumption and therefore the device should as well since no communication would be possible anyway. I don't have the USB spec, is there any clarification on what suspend means, i.e. is it suspending the devices, the entire bus, or just the traffic to the particular usb device? What I need is to leave both host and device in active state and simply stop traffic between the two until either side has something to communicate.

This is interesting, but I could not see from the STM32L4 reference documentation or HAL libraries, any way to tell the host to suspend and put the usb peripheral on the mcu into low power mode at the same time. Have you any experience reducing power while keeping the port open?

Pavel A.
Evangelist III

In the other direction, host to device, this wording describes the mechanism which tells the device that the host is going to suspend mode

Not exactly. The original "selective suspend" is initiated by host, it allows the host to tell the device to go to low-power mode, with option to request attention ("remote wakeup"). The host itself does not have to sleep, it does what it wants to. 

 I don't have the USB spec, is there any clarification

Yes, it is in the USB spec))  The AI is to your service as well.

What I need is to leave both host and device in active state and simply stop traffic between the two until either side has something to communicate.

This is easy with a custom host driver. The device just can tell the driver via private protocol to do something for it, like put it in selective suspend mode. But with generic drivers, such as Windows in-box drivers, vendor-independent standard mechanism is needed. This is what you've asked about, correct?