Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork8.2k
rp2: Selectively leave the USB clocks enabled in light sleep.#15111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
rp2: Selectively leave the USB clocks enabled in light sleep.#15111
Uh oh!
There was an error while loading.Please reload this page.
Conversation
github-actionsbot commentedMay 24, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Code size report:
|
Without this change going to lightsleep stops the USB peripheral clock, andcan lead to either the device going into a weird state or the host decidingto issue a bus reset.This change only keeps the USB peripheral clocks enabled if the USB deviceis currently active and a host has configured the device. This means theUSB device continues to respond to host transfers and (presumably) willeven complete pending endpoint transfers. All other requests are NAKedwhile still asleep, but the interaction with the host seems to resumecorrectly on wakeOtherwise, if USB is not active or configured by a host, USB clocks aredisabled, the same as before.With the change, one can issue a `machine.lightsleep(...)` with USB CDCconnected and the USB CDC remains connected during the sleep and resumeswhen the lightsleep finishes.Tested on a RPi Pico, the power consumption is:- During normal idle at the REPL, about 15.3mA.- During lightsleep, prior to this change, about 1.35mA.- During lightsleep, with this change and USB CDC connected, about 3.7mA.If power consumption should be as low as possible when USB is connected,one can use `machine.USBDevice` to disable the USB before enteringlightsleep.As discussed athttps://github.com/orgs/micropython/discussions/14401This work was funded through GitHub Sponsors.Signed-off-by: Angus Gratton <angus@redyak.com.au>
d6986d6
toa84c7a0
CompareThis is a really great enhancement (and very simple)! It's not very user friendly that USB resumes in a broken state after lightsleep finishes. Tested it and it works very well. But I think you're current measurements are a factor of 10 too high. Idle REPL consumption is about 15mA, lightsleep is about 1.35mA without this PR, and about 3.67mA with this PR. IMO that's totally acceptable, a few extra mA to keep the USB alive. If users really need to get lower power consumption with USB connected they can use |
a84c7a0
intomicropython:masterUh oh!
There was an error while loading.Please reload this page.
projectgus commentedJun 3, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Oh you're right, that does sound more reasonable! Thanks. EDIT: Yes I quickly checked and I definitely read off the value wrong. |
@projectgus How would you feel if I replaced the 'disable_usb' parameter, and included checking 'sleep_en[]' for the appropriate bits - thus keeping USB clock running. |
@mungewell Thanks for the heads-up. I will aim to get back to you on your PR soon. |
Can someone please explain what command I can use to turn of the USB. I have enabled (and connected to) the UART REPL, the USB is still showing connected when I |
Uh oh!
There was an error while loading.Please reload this page.
Without this change going to lightsleep stops the USB peripheral clock, and can lead to either the device going into a weird state or the host deciding to issue a bus reset.
This change only keeps the USB peripheral clocks enabled if the USB device is currently active and a host has configured the device. Otherwise USB clocks are disabled same as before.
Increases power consumption in light sleep (measured at the USB port for a PICO board as 1.2-1.3mA without this change, and 3.4-3.5mA with this change). I think can argue that if you have a working active USB host connection, an extra 2mA is unlikely to be significant.
(EDIT: Above measurement was originally off by a factor of 10, corrected in comments.)
As discussed athttps://github.com/orgs/micropython/discussions/14401
Tested with
mpremote run
mpremote a1 exec "import machine; machine.lightsleep(5000)"
(plus some longer and shorter delays, up to 30 seconds).Details
Logic analyser shows that without this change the USB Host continues sending SoF and other requests to the sleeping device, and it doesn't respond so every transfer is an error. On my system, the host seems to keep trying indefinitely. After waking, TinyUSB ends up in a bad state and doesn't set up any new transfers itself (i.e. the USB-CDC doesn't send any data to the host.) If using a REPL, pressing a key to send some data from the host to the device is enough to make it come back from this weird state and it seems to resume normal operations.
Behaviour seems to vary between host controllers - the discussion includes anexample of the host deciding the device is no longer responding and resetting it. I wasn't able to reproduce this here, can only guess it depends on the host controller (and/or maybe the hub controller, especially for superspeed hubs.)
With this change applied, the USB device continues to respond to host transfers and (presumably) will even complete pending endpoint transfers. All other requests are NAKed while still asleep, but the interaction with the host seems to resume correctly on wake.
Alternatives
One alternative approach would be to disconnect the USB device pins when going into lightsleep. This would cause the host to definitely see the device as disconnected, rather than ending up in the current weird in-between states. Also no increase in power usage. If we do the planned work to support transparent USB serial disconnect/reconnect in mpremote then it will probably be possible for mpremote to cleanly recover the connection on wake, also.
I also did some experiments with getting TinyUSB and the host to recover from the weird in-between state, without the host needing to initiate an OUT transfer. This obviously doesn't help for hosts which trigger a full bus reset, but might help for some hosts. I had a little unreliable success with this, but it seems flaky.
This work was funded through GitHub sponsors.