-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix usb sleep for NRF #2868
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
Fix usb sleep for NRF #2868
Conversation
Note that this patch doesn't actually work, because you cannot run
|
This patchset requires hathach/tinyusb#396 There may be other areas where |
Update: With this patchset, usage is down to 10 uA when running on battery. It quickly and reliably wakes from sleep, and it appears to be capable of logging to internal flash. |
Why do you think this improves power usage so dramatically? Were we never actually sleeping? |
That was poor wording on my part. Without these patches, I couldn't reliably test, since whenever it went on battery it would effectively crash. With this patchset in place, I was able to concentrate on other parts of the chip in order to bring current consumption down there. The most recent victory was setting the Without this patchset, it would grind to a halt prematurely, causing the host to reset it (if connected via USB), or delaying flash writes until the system awoke from sleep. |
kk, awesome! I'm excited to see the subsequent PRs. Are you blocked on TinyUSB changes now? |
This does depend on the tinyusb patch, because My concern is that other background tasks require interrupts to be enabled, and I am unable to exercise those. However, I do think that others will begin to report issues with missed events with the lower power WFI patch, and some approach like this will be required to fix them. So it's probably better to figure out what crashes and fix it. |
I'm assuming we'll have bugs to track down with the lower_power merge. So, merging this is fine once TinyUSB has the needed update. We can test the other background stuff in the beta releases. |
ports/nrf/supervisor/port.c
Outdated
// available, even though the actual handler won't fire until | ||
// we re-enable interrupts. | ||
common_hal_mcu_disable_interrupts(); | ||
RUN_BACKGROUND_TASKS; // Drain any buffers remaining |
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.
background task are run in the caller mp_hal_delay_ms()
, we don't have to run it here, other platforms don't seem to run this before WFI() as well. I am not so sure though, will do more testing.
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.
Correct, but you must run background tests after you disable interrupts, to ensure that e.g. the USB queues are empty.
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, I know that intention of yours, I am thinking a way to make tinyusb maybe cooperate better with wfi() 🤔 🤔
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.
@tannewt @xobs we shouldn't run background task with interrupt disabled. This particular issue is mentioned by TockOS team (note 3) a few months ago hathach/tinyusb#279 . but I overlooked it. The better implementation should be an function to check if there is anything to run with the event queue of tud_task(), if yes, don't enter WFI(), re-enable interrupt, and loop over again.
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.
There are two approaches that we can take, and I think @tannewt should decide which approach they think is best:
- Allow background tasks to be run with interrupts disabled. This is the approach that's started by this patch, but there may be many other minefields in other code that requires interrupts to be enabled in order to function properly
- Add a new
SHOULD_RUN_BACKGROUND_TASKS
macro that polls each subsystem, similar to howRUN_BACKGROUND_TASKS
runs each subsystem. ThisSHOULD_RUN_BACKGROUND_TASKS
will include a call totud_task_is_queue_empty()
, among other calls.
Am I correct in stating you're advocating for approach 2? This patch takes approach 1, because I thought it would be easier to implement and require less code overall. Also because tud_task_is_queue_empty()
didn't exist. Approach 2 does benefit from potentially allowing non-critical-section-safe code from going into the RUN_BACKGROUND_TASKS
macro, which seems cleaner.
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 you are spot-on and I am adding the usb event queue count API() just now. Your PR has already implemented 99% of the work. We only need to change the run background
to if still has more background then skip
before executing wfi().
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.
PR for tinyusb hathach/tinyusb#414 is on the way.
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.
How often do you encounter the deadblock, I switch to your PR branch to try reproducing it. I know it is totally possible, but it is bit hard to encounter. I may just simulate it with other modified example, the goal is to check the corresponding registers to find a simpler alternative fix to hathach/tinyusb#396 than invoking the dcd_int_handler() if possible. |
I encountered it maybe 20% of the time. The problem always seemed to occur on the last packet as part of an MSC SCSI transaction (the same packet that causes adafruit/Adafruit_nRF52_Bootloader#120 interestingly enough) that gets stuck in the queue between calling |
Thanks for the reply, I hardly got into it, I guess it depends on the host OS as well since it is racing. I will try to simulate it then with my simple example, it shouldn't be much different. I may need your help to test with it again if you have some time :). |
Sure. I still need to rework my USB Beagle -- an inductor has decided it doesn't like its house on the PCB, and has started trying to separate from the PCB -- but I can test it. This seems like a discussion for hathach/tinyusb#396 though. For this issue, I'm confused about what @tannewt means -- with the |
This update gives us access to a function we can run with interrupts disabled to determine if the queue is empty. Signed-off-by: Sean Cross <[email protected]>
Allow for passing `-DCFG_TUSB_DEBUG=1` or `-DCFG_TUSB_DEBUG=2` on the command line to enable debugging tinyusb within circuitpython. Signed-off-by: Sean Cross <[email protected]>
In order to ensure we don't have any outstanding requests, disable interrupts prior to issuing `WFI`. As part of this process, check to see if there are any pending USB requests, and only execute the `WFI` if there is no pending data. This fixes micropython#2855 on NRF. Signed-off-by: Sean Cross <[email protected]>
ARM recommends issuing a DSB instruction propr to issuing WFI, as it is required on many parts suchas Cortex-M7. This is effectively a no-op on the Cortex-M4 used in most NRF parts, however it ensures that we won't be surprised when new parts come out. See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html for more information. Signed-off-by: Sean Cross <[email protected]>
If interrupts are disabled, then calling sd_* functions will hardfault. Instead, assume that it's safe to write if interrupts are disabled. Signed-off-by: Sean Cross <[email protected]>
I've updated the PR to use Note that it keeps the bulk of the previous patches, because it uses |
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.
This PR address all issues around entering low power mode with WFI as implemented by other platforms (freeRTOS tickless, zephyrs cpu idle). Should be ready to merge, great work @xobs
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.
This fixes connecting and disconnecting USB while executing
time.sleep()
on NRF. This issue may be present on other ports, so similar fixes should be implemented on other platforms as well.