-
Notifications
You must be signed in to change notification settings - Fork 3k
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
USBDevice: add documentation on USB suspend/resume to enter deep sleep #11635
USBDevice: add documentation on USB suspend/resume to enter deep sleep #11635
Conversation
@hugueskamba, thank you for your changes. |
bf2be08
to
1e1b67d
Compare
drivers/source/usb/USBDevice.cpp
Outdated
core_util_critical_section_enter(); | ||
if (_phy_enabled != enabled) { | ||
if (enabled) { | ||
USBDevice::connect(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it seems that deinit
calls disconnect
and connect
calls init
so we should be good there. But i'm not 100% sure it will restore the state. Is calling disconnect
and phy->deinit
legal in every state? Basically if I call enable_phy(false)
, go to sleep, wake up, call enable_phy(true)
and try to continue using USB will it work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I programmed a K64F with a firmware that allowed me to call enable_phy()
by pressing a button to enable/disable USB phy.
After enable_phy(false)
, nothing can be received on the USB interface and the device goes to deep sleep. After enable_phy(true)
, bytes can once again be received on the USB interface.
Is that what you were not sure about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the test you performed is a good one, but I'm not sure it's definitive for all implementation based on the specification. Could you check that it's actually mandated by the spec? Russ would be able to help I'm sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @c1728p9 ,
Could you please comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike some of the other peripherals, the USB code to disable deep sleep is target specific and in a subclass of USBPhy. There is no code common to all targets which locks deep sleep. Depending on implementation, targets could unlock deep sleep on a call to disconnect(), or even do it automatically when USB power is lost. Currently all the implementation I'm aware of only unlock deep sleep in deinit() though.
Is calling disconnect and phy->deinit legal in every state?
Yes, this is equivalent to the user unplugging the device. This may have negative side effects though, such as corrupting a mass storage drive if disconnecting in the middle of a write.
But i'm not 100% sure it will restore the state.
The call to enable_phy(true) can make the device re-enumerate, but can't directly restore the state. The USB host controls the enumeration process so it chooses when and how the device will be restored. Even if the device state is returned to what it was before the disconnect, the host PC software may not be where it left off - for example a serial port may need to be re-opended by the user.
The safest thing to do would be only deinit() when USB power is lost and init() and connect() when it is detected. That way there isn't any state to restore.
Finally, one thing to note is that suspend/resume is already terminology used by the USB standard. It referrs to a USB host initiated low power mode. This may add some confusion to users. I'm not sure of a good way to avoid this though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's also not guaranteed to be clean operation in terms of state being preserved I would say suspend and resume doesn't necessarily work. Is directly calling init/deinit or connect/disconnect a viable solution? Documentation can be clear that it's up to the user to make sure all the transfers have concluded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@hugueskamba Could you please update your description to give some context and put it in the right place? Thanks |
1e1b67d
to
0ee70e1
Compare
@bulislaw |
0ee70e1
to
8d29adf
Compare
This force-push removes the |
8d29adf
to
52e6e30
Compare
This force-push removes the remnants of the removed |
It is possible to temporarily suspend USB and safely preserve its configuration. This is needed to allow a device to enter deep sleep as a USBDevice instance prevents deep sleep. USB operation can be suspended with `deinit` and restored with `connect`.
52e6e30
to
a3f20f8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with this PR which adds documentation on how to achieve power saving.
On a side note, I find confusing the fact that connect() calls init() (although the init() documentation says that "This function must be called before calling any other functions of this class" and deinit() calls disconnect(). It would have been a cleaner API if each function only did one thing (at the expense of the users doing the right thing). But this is not someting I would like to change now.
CI started |
Test run: SUCCESSSummary: 11 of 11 test jobs passed |
Description
It is now possible to temporarily suspend a USB Component and safely preserve its state. This functionality is needed to allow a device to enter deep sleep as a USBDevice instance prevents deep sleep.
Pull request type
Reviewers
@bulislaw @c1728p9 @evedon
Release Notes