-
Notifications
You must be signed in to change notification settings - Fork 1.3k
NRF: USB Disconnect / Reconnect / Enumeration fails during sleep #2855
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
Comments
I believe at least part of the problem is due to the fact that there doesn't seem to be anything listening to the diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c
index 539a9cf90..24a0c4bdd 100644
--- a/ports/nrf/supervisor/port.c
+++ b/ports/nrf/supervisor/port.c
@@ -67,6 +67,10 @@ static void power_warning_handler(void) {
const nrfx_rtc_t rtc_instance = NRFX_RTC_INSTANCE(2);
+#if NRF_POWER_HAS_USBREG
+extern void tusb_hal_nrf_power_event(uint32_t event);
+#endif
+
const nrfx_rtc_config_t rtc_config = {
.prescaler = RTC_FREQ_TO_PRESCALER(0x8000),
.reliable = 0,
@@ -115,6 +119,12 @@ safe_mode_t port_init(void) {
nrfx_power_pof_init(&power_failure_config);
nrfx_power_pof_enable(&power_failure_config);
+ #if NRF_POWER_HAS_USBREG
+ const nrfx_power_usbevt_config_t usbevt_config = { .handler = ((nrfx_power_usb_event_handler_t) tusb_hal_nrf_power_event) };
+ nrfx_power_usbevt_init(&usbevt_config);
+ nrfx_power_usbevt_enable();
+ #endif
+
nrf_peripherals_enable_cache();
// Configure millisecond timer initialization. That at least gets it part of the way there. However, it still appears as though the device isn't responding to USB properly. In particular, while the config descriptor and initial string descriptor get transferred, the device doesn't appear to be acknowledging them. |
@hathach Does tinyusb use interrupts for these USB events? Sleep will wake and call |
TinyUSB requires application to call The power IRQHandler is used and shared with SoftDevice therefore it cannot be actively handled when SD is enabled. The above modification by @xobs is part of the initial |
I thought it was odd that it seemed to somewhat work even without that patch. The strange part is I can see the events fire, and I see the |
My guess is that there is an interrupt we need to enable so that it wakes up from WFI. Did you confirm that it works when the actual WFI call is commented out? This looks very similar to the SAMD21 issue where a SETUP packet interrupt is piggybacking on a OUT interrupt. It still failed when WFI was commented out because it was a timing issue.
Definitely not. It's only really useful when on battery. When on USB you have an external power supply. |
It does work if the WFI call is commented out. Let me look through the USB interrupts and see what's going on. |
@hathach You're right, I didn't see that the event was already being hooked. So the patch I made probably doesn't seem necessary. However, it does appear as though the OUT data isn't getting ACKed for whatever reason. And it's always the same descriptor. At least it's consistent. The contents of the
And after plugging back in, while the host is waiting for the device to ACK the 5th SETUP packet:
|
When I connect it when it's in this state, this is the output I receive:
I have placed multiple "\n" entries where the host is waiting for the device to ACK an IN packet. Note that this board is being debugged by bit-banging SWD on a raspberry pi, so I needed to hack in rtt support. I think this is accurate, though. Also, my USB Beagle is in need of a new inductor. It is incredibly flaky right now, making it hard to get reliable measurements, particularly when it involves a lot of unplugging and plugging in. |
In looking at https://github.com/hathach/tinyusb/blob/master/src/portable/nordic/nrf5x/dcd_nrf5x.c#L292-L297 it almost seems as though this isn't actually firing. One thing I can see is that the
|
The issue is that interrupts were still enabled while calling This PR adds a patch to disable interrupts (and run background tasks with interrupts disabled to ensure buffers are drained) on the nrf platform: #2868 I suspect other platforms will have similar subtle issues. |
Looks like it's not possible to run @hathach do you have any suggestions for how we could do this? |
I've applied this patch to my local copy of tinyusb, which causes it to poll the interrupt handler if interrupts are disabled. This seems to prevent the deadlock: diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 12435ea2..acc1af58 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -101,7 +101,11 @@ static void edpt_dma_start(volatile uint32_t* reg_startep)
else
{
// Otherwise simply block wait
- while ( _dcd.dma_running ) { }
+ while ( _dcd.dma_running ) {
+ // Manually poll the handler if interrupts are disabled
+ if (!__get_PRIMASK())
+ dcd_int_handler(0);
+ }
}
} |
I submitted a PR for this here: hathach/tinyusb#396 I've also found additional places where |
Also, run background tasks with interrupts disabled. This ensures that any buffers are drained, and if an interrupt arrives after buffers are drained but before the WFI is executed then the WFI instruction will return immediately. This fixes adafruit#2855 on NRF. Signed-off-by: Sean Cross <[email protected]>
Is the cause for this a race between the last background task run and the wfi call? WFI should work fine with interrupts enabled but for TinyUSB that means work may have been queued but not done. |
WFI does work fine if interrupts are enabled, but without disabling interrupts you can never be sure that there isn't pending data before issuing sleep_until_time:
; ... do some prep involving the RTC
bl usb_background
wfi
usb_background:
; ... service USB buffers
bx lr Even though The solution is to disable interrupts, flush buffers, and issue |
Also, run background tasks with interrupts disabled. This ensures that any buffers are drained, and if an interrupt arrives after buffers are drained but before the WFI is executed then the WFI instruction will return immediately. This fixes adafruit#2855 on NRF. Signed-off-by: Sean Cross <[email protected]>
Also, run background tasks with interrupts disabled. This ensures that any buffers are drained, and if an interrupt arrives after buffers are drained but before the WFI is executed then the WFI instruction will return immediately. This fixes adafruit#2855 on NRF. Signed-off-by: Sean Cross <[email protected]>
With the most recent patches, issuing
time.sleep(x)
issues awfi
instruction. This aggressively puts the CPU to sleep. However, this appears to cause USB to no longer enumerate. While this is not an issue with a device that's powered off of USB, if a device has its own battery, then this will prevent the device from enumerating during sleep.Steps to reproduce
The following
code.py
should trigger this bug:The text was updated successfully, but these errors were encountered: