aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-07-11 00:01:41 +0000
committerGitHub <[email protected]>2022-07-11 00:01:41 +0000
commit9753f767946d79c5987c166e513150aca98ec042 (patch)
treecafaeeaa7714fff7271818b3eea976f71f382739
parent163cf1f335ed11011a68c2a90c447ece121fc22f (diff)
parent8785fbc6f1a1227115d3ffa6a6c19035bed6ef8c (diff)
Merge #810
810: Takes care of power for nRF USB devices r=Dirbaio a=huntc Modifies the usb-serial example to illustrate how to setup USB for situations where the USB power can be detected and removed. Gaps: ~~* No support for the nrf-softdevices as yet, although this should be possible via another constructor.~~ * No support for the nrf5340, although this should be possible via USBREG. The change is tested and appears to work. Some notes: * There's an existing field named self_powered as a UsbDevice field. It doesn't ever appear to get set. I'm wondering if this field is intended to signal that a device has the nRF VBUS power situation or not. I'm not presently using it. * The new PowerDetected event is generated on the bus initially in situations where just new is used i.e. without power management, including on STM. We can therefore rely on this event always being generated. Old description: ~~EnabledUsbDevice is a wrapper around the `UsbDevice` where its enablement is also subject to external events, such as `POWER` events for nRF. It is introduced generically to support other platforms should they also require external signaling for enablement.~~ Co-authored-by: huntc <[email protected]>
-rw-r--r--embassy-nrf/src/usb.rs183
-rw-r--r--embassy-stm32/src/usb/usb.rs83
-rw-r--r--embassy-usb/src/driver.rs6
-rw-r--r--embassy-usb/src/lib.rs38
-rw-r--r--examples/nrf/src/bin/usb_ethernet.rs12
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs71
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs10
-rw-r--r--examples/nrf/src/bin/usb_serial.rs14
-rw-r--r--examples/nrf/src/bin/usb_serial_multitask.rs13
9 files changed, 273 insertions, 157 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 6c872581d..9b6e6e83d 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -2,7 +2,7 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::mem::MaybeUninit; 4use core::mem::MaybeUninit;
5use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 5use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
6use core::task::Poll; 6use core::task::Poll;
7 7
8use cortex_m::peripheral::NVIC; 8use cortex_m::peripheral::NVIC;
@@ -26,14 +26,149 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
26static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; 26static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); 27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
28 28
29pub struct Driver<'d, T: Instance> { 29/// There are multiple ways to detect USB power. The behavior
30/// here provides a hook into determining whether it is.
31pub trait UsbSupply {
32 fn is_usb_detected(&self) -> bool;
33
34 type UsbPowerReadyFuture<'a>: Future<Output = Result<(), ()>> + 'a
35 where
36 Self: 'a;
37 fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_>;
38}
39
40pub struct Driver<'d, T: Instance, P: UsbSupply> {
30 phantom: PhantomData<&'d mut T>, 41 phantom: PhantomData<&'d mut T>,
31 alloc_in: Allocator, 42 alloc_in: Allocator,
32 alloc_out: Allocator, 43 alloc_out: Allocator,
44 usb_supply: P,
33} 45}
34 46
35impl<'d, T: Instance> Driver<'d, T> { 47/// Uses the POWER peripheral to detect when power is available
36 pub fn new(_usb: impl Unborrow<Target = T> + 'd, irq: impl Unborrow<Target = T::Interrupt> + 'd) -> Self { 48/// for USB. Unsuitable for usage with the nRF softdevice.
49#[cfg(not(feature = "_nrf5340-app"))]
50pub struct PowerUsb {}
51
52/// Can be used to signal that power is available. Particularly suited for
53/// use with the nRF softdevice.
54pub struct SignalledSupply {
55 usb_detected: AtomicBool,
56 power_ready: AtomicBool,
57}
58
59static POWER_WAKER: AtomicWaker = NEW_AW;
60
61#[cfg(not(feature = "_nrf5340-app"))]
62impl PowerUsb {
63 pub fn new(power_irq: impl Interrupt) -> Self {
64 let regs = unsafe { &*pac::POWER::ptr() };
65
66 power_irq.set_handler(Self::on_interrupt);
67 power_irq.unpend();
68 power_irq.enable();
69
70 regs.intenset
71 .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
72
73 Self {}
74 }
75
76 #[cfg(not(feature = "_nrf5340-app"))]
77 fn on_interrupt(_: *mut ()) {
78 let regs = unsafe { &*pac::POWER::ptr() };
79
80 if regs.events_usbdetected.read().bits() != 0 {
81 regs.events_usbdetected.reset();
82 BUS_WAKER.wake();
83 }
84
85 if regs.events_usbremoved.read().bits() != 0 {
86 regs.events_usbremoved.reset();
87 BUS_WAKER.wake();
88 POWER_WAKER.wake();
89 }
90
91 if regs.events_usbpwrrdy.read().bits() != 0 {
92 regs.events_usbpwrrdy.reset();
93 POWER_WAKER.wake();
94 }
95 }
96}
97
98#[cfg(not(feature = "_nrf5340-app"))]
99impl UsbSupply for PowerUsb {
100 fn is_usb_detected(&self) -> bool {
101 let regs = unsafe { &*pac::POWER::ptr() };
102 regs.usbregstatus.read().vbusdetect().is_vbus_present()
103 }
104
105 type UsbPowerReadyFuture<'a> = impl Future<Output = Result<(), ()>> + 'a where Self: 'a;
106 fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_> {
107 poll_fn(move |cx| {
108 POWER_WAKER.register(cx.waker());
109 let regs = unsafe { &*pac::POWER::ptr() };
110
111 if regs.usbregstatus.read().outputrdy().is_ready() {
112 Poll::Ready(Ok(()))
113 } else if !self.is_usb_detected() {
114 Poll::Ready(Err(()))
115 } else {
116 Poll::Pending
117 }
118 })
119 }
120}
121
122impl SignalledSupply {
123 pub fn new(usb_detected: bool, power_ready: bool) -> Self {
124 BUS_WAKER.wake();
125
126 Self {
127 usb_detected: AtomicBool::new(usb_detected),
128 power_ready: AtomicBool::new(power_ready),
129 }
130 }
131
132 pub fn detected(&self, detected: bool) {
133 self.usb_detected.store(detected, Ordering::Relaxed);
134 self.power_ready.store(false, Ordering::Relaxed);
135 BUS_WAKER.wake();
136 POWER_WAKER.wake();
137 }
138
139 pub fn ready(&self) {
140 self.power_ready.store(true, Ordering::Relaxed);
141 POWER_WAKER.wake();
142 }
143}
144
145impl UsbSupply for SignalledSupply {
146 fn is_usb_detected(&self) -> bool {
147 self.usb_detected.load(Ordering::Relaxed)
148 }
149
150 type UsbPowerReadyFuture<'a> = impl Future<Output = Result<(), ()>> + 'a where Self: 'a;
151 fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_> {
152 poll_fn(move |cx| {
153 POWER_WAKER.register(cx.waker());
154
155 if self.power_ready.load(Ordering::Relaxed) {
156 Poll::Ready(Ok(()))
157 } else if !self.usb_detected.load(Ordering::Relaxed) {
158 Poll::Ready(Err(()))
159 } else {
160 Poll::Pending
161 }
162 })
163 }
164}
165
166impl<'d, T: Instance, P: UsbSupply> Driver<'d, T, P> {
167 pub fn new(
168 _usb: impl Unborrow<Target = T> + 'd,
169 irq: impl Unborrow<Target = T::Interrupt> + 'd,
170 usb_supply: P,
171 ) -> Self {
37 unborrow!(irq); 172 unborrow!(irq);
38 irq.set_handler(Self::on_interrupt); 173 irq.set_handler(Self::on_interrupt);
39 irq.unpend(); 174 irq.unpend();
@@ -43,6 +178,7 @@ impl<'d, T: Instance> Driver<'d, T> {
43 phantom: PhantomData, 178 phantom: PhantomData,
44 alloc_in: Allocator::new(), 179 alloc_in: Allocator::new(),
45 alloc_out: Allocator::new(), 180 alloc_out: Allocator::new(),
181 usb_supply,
46 } 182 }
47 } 183 }
48 184
@@ -76,7 +212,6 @@ impl<'d, T: Instance> Driver<'d, T> {
76 // doesn't cause an infinite irq loop. 212 // doesn't cause an infinite irq loop.
77 if regs.events_usbevent.read().bits() != 0 { 213 if regs.events_usbevent.read().bits() != 0 {
78 regs.events_usbevent.reset(); 214 regs.events_usbevent.reset();
79 //regs.intenclr.write(|w| w.usbevent().clear());
80 BUS_WAKER.wake(); 215 BUS_WAKER.wake();
81 } 216 }
82 217
@@ -98,11 +233,11 @@ impl<'d, T: Instance> Driver<'d, T> {
98 } 233 }
99} 234}
100 235
101impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { 236impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> {
102 type EndpointOut = Endpoint<'d, T, Out>; 237 type EndpointOut = Endpoint<'d, T, Out>;
103 type EndpointIn = Endpoint<'d, T, In>; 238 type EndpointIn = Endpoint<'d, T, In>;
104 type ControlPipe = ControlPipe<'d, T>; 239 type ControlPipe = ControlPipe<'d, T>;
105 type Bus = Bus<'d, T>; 240 type Bus = Bus<'d, T, P>;
106 241
107 fn alloc_endpoint_in( 242 fn alloc_endpoint_in(
108 &mut self, 243 &mut self,
@@ -138,7 +273,11 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
138 273
139 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 274 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
140 ( 275 (
141 Bus { phantom: PhantomData }, 276 Bus {
277 phantom: PhantomData,
278 power_available: false,
279 usb_supply: self.usb_supply,
280 },
142 ControlPipe { 281 ControlPipe {
143 _phantom: PhantomData, 282 _phantom: PhantomData,
144 max_packet_size: control_max_packet_size, 283 max_packet_size: control_max_packet_size,
@@ -147,11 +286,13 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
147 } 286 }
148} 287}
149 288
150pub struct Bus<'d, T: Instance> { 289pub struct Bus<'d, T: Instance, P: UsbSupply> {
151 phantom: PhantomData<&'d mut T>, 290 phantom: PhantomData<&'d mut T>,
291 power_available: bool,
292 usb_supply: P,
152} 293}
153 294
154impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 295impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
155 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 296 type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
156 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; 297 type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
157 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; 298 type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a;
@@ -188,9 +329,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
188 w.epdata().set_bit(); 329 w.epdata().set_bit();
189 w 330 w
190 }); 331 });
191 // Enable the USB pullup, allowing enumeration. 332
192 regs.usbpullup.write(|w| w.connect().enabled()); 333 if self.usb_supply.wait_power_ready().await.is_ok() {
193 trace!("enabled"); 334 // Enable the USB pullup, allowing enumeration.
335 regs.usbpullup.write(|w| w.connect().enabled());
336 trace!("enabled");
337 } else {
338 trace!("usb power not ready due to usb removal");
339 }
194 } 340 }
195 } 341 }
196 342
@@ -246,6 +392,17 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
246 trace!("USB event: ready"); 392 trace!("USB event: ready");
247 } 393 }
248 394
395 if self.usb_supply.is_usb_detected() != self.power_available {
396 self.power_available = !self.power_available;
397 if self.power_available {
398 trace!("Power event: available");
399 return Poll::Ready(Event::PowerDetected);
400 } else {
401 trace!("Power event: removed");
402 return Poll::Ready(Event::PowerRemoved);
403 }
404 }
405
249 Poll::Pending 406 Poll::Pending
250 }) 407 })
251 } 408 }
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index cadbb423c..4633ff00c 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -161,6 +161,9 @@ impl<'d, T: Instance> Driver<'d, T> {
161 dm.set_as_af(dm.af_num(), AFType::OutputPushPull); 161 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
162 } 162 }
163 163
164 // Initialize the bus so that it signals that power is available
165 BUS_WAKER.wake();
166
164 Self { 167 Self {
165 phantom: PhantomData, 168 phantom: PhantomData,
166 alloc: [EndpointData { 169 alloc: [EndpointData {
@@ -406,6 +409,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
406 Bus { 409 Bus {
407 phantom: PhantomData, 410 phantom: PhantomData,
408 ep_types, 411 ep_types,
412 inited: false,
409 }, 413 },
410 ControlPipe { 414 ControlPipe {
411 _phantom: PhantomData, 415 _phantom: PhantomData,
@@ -420,6 +424,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
420pub struct Bus<'d, T: Instance> { 424pub struct Bus<'d, T: Instance> {
421 phantom: PhantomData<&'d mut T>, 425 phantom: PhantomData<&'d mut T>,
422 ep_types: [EpType; EP_COUNT - 1], 426 ep_types: [EpType; EP_COUNT - 1],
427 inited: bool,
423} 428}
424 429
425impl<'d, T: Instance> driver::Bus for Bus<'d, T> { 430impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
@@ -428,53 +433,59 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
428 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { 433 fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> {
429 poll_fn(move |cx| unsafe { 434 poll_fn(move |cx| unsafe {
430 BUS_WAKER.register(cx.waker()); 435 BUS_WAKER.register(cx.waker());
431 let regs = T::regs();
432 436
433 let flags = IRQ_FLAGS.load(Ordering::Acquire); 437 if self.inited {
438 let regs = T::regs();
434 439
435 if flags & IRQ_FLAG_RESUME != 0 { 440 let flags = IRQ_FLAGS.load(Ordering::Acquire);
436 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
437 return Poll::Ready(Event::Resume);
438 }
439 441
440 if flags & IRQ_FLAG_RESET != 0 { 442 if flags & IRQ_FLAG_RESUME != 0 {
441 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel); 443 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
444 return Poll::Ready(Event::Resume);
445 }
442 446
443 trace!("RESET REGS WRITINGINGING"); 447 if flags & IRQ_FLAG_RESET != 0 {
444 regs.daddr().write(|w| { 448 IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel);
445 w.set_ef(true);
446 w.set_add(0);
447 });
448 449
449 regs.epr(0).write(|w| { 450 trace!("RESET REGS WRITINGINGING");
450 w.set_ep_type(EpType::CONTROL); 451 regs.daddr().write(|w| {
451 w.set_stat_rx(Stat::NAK); 452 w.set_ef(true);
452 w.set_stat_tx(Stat::NAK); 453 w.set_add(0);
453 }); 454 });
454 455
455 for i in 1..EP_COUNT { 456 regs.epr(0).write(|w| {
456 regs.epr(i).write(|w| { 457 w.set_ep_type(EpType::CONTROL);
457 w.set_ea(i as _); 458 w.set_stat_rx(Stat::NAK);
458 w.set_ep_type(self.ep_types[i - 1]); 459 w.set_stat_tx(Stat::NAK);
459 }) 460 });
460 } 461
462 for i in 1..EP_COUNT {
463 regs.epr(i).write(|w| {
464 w.set_ea(i as _);
465 w.set_ep_type(self.ep_types[i - 1]);
466 })
467 }
461 468
462 for w in &EP_IN_WAKERS { 469 for w in &EP_IN_WAKERS {
463 w.wake() 470 w.wake()
464 } 471 }
465 for w in &EP_OUT_WAKERS { 472 for w in &EP_OUT_WAKERS {
466 w.wake() 473 w.wake()
474 }
475
476 return Poll::Ready(Event::Reset);
467 } 477 }
468 478
469 return Poll::Ready(Event::Reset); 479 if flags & IRQ_FLAG_SUSPEND != 0 {
470 } 480 IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel);
481 return Poll::Ready(Event::Suspend);
482 }
471 483
472 if flags & IRQ_FLAG_SUSPEND != 0 { 484 Poll::Pending
473 IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel); 485 } else {
474 return Poll::Ready(Event::Suspend); 486 self.inited = true;
487 return Poll::Ready(Event::PowerDetected);
475 } 488 }
476
477 Poll::Pending
478 }) 489 })
479 } 490 }
480 491
diff --git a/embassy-usb/src/driver.rs b/embassy-usb/src/driver.rs
index bfe44d627..2a84ff9e7 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb/src/driver.rs
@@ -202,6 +202,12 @@ pub enum Event {
202 /// A USB resume request has been detected after being suspended or, in the case of self-powered 202 /// A USB resume request has been detected after being suspended or, in the case of self-powered
203 /// devices, the device has been connected to the USB bus. 203 /// devices, the device has been connected to the USB bus.
204 Resume, 204 Resume,
205
206 /// The USB power has been detected.
207 PowerDetected,
208
209 /// The USB power has been removed. Not supported by all devices.
210 PowerRemoved,
205} 211}
206 212
207#[derive(Copy, Clone, Eq, PartialEq, Debug)] 213#[derive(Copy, Clone, Eq, PartialEq, Debug)]
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index f2577d4fc..82ff4e32f 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -30,6 +30,9 @@ use crate::driver::ControlPipe;
30#[derive(PartialEq, Eq, Copy, Clone, Debug)] 30#[derive(PartialEq, Eq, Copy, Clone, Debug)]
31#[cfg_attr(feature = "defmt", derive(defmt::Format))] 31#[cfg_attr(feature = "defmt", derive(defmt::Format))]
32pub enum UsbDeviceState { 32pub enum UsbDeviceState {
33 /// The USB device has no power.
34 Unpowered,
35
33 /// The USB device is disabled. 36 /// The USB device is disabled.
34 Disabled, 37 Disabled,
35 38
@@ -154,7 +157,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
154 config_descriptor, 157 config_descriptor,
155 bos_descriptor, 158 bos_descriptor,
156 159
157 device_state: UsbDeviceState::Disabled, 160 device_state: UsbDeviceState::Unpowered,
158 suspended: false, 161 suspended: false,
159 remote_wakeup_enabled: false, 162 remote_wakeup_enabled: false,
160 self_powered: false, 163 self_powered: false,
@@ -185,20 +188,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
185 /// before calling any other `UsbDevice` methods to fully reset the 188 /// before calling any other `UsbDevice` methods to fully reset the
186 /// peripheral. 189 /// peripheral.
187 pub async fn run_until_suspend(&mut self) -> () { 190 pub async fn run_until_suspend(&mut self) -> () {
188 if self.inner.device_state == UsbDeviceState::Disabled {
189 self.inner.bus.enable().await;
190 self.inner.device_state = UsbDeviceState::Default;
191
192 if let Some(h) = &self.inner.handler {
193 h.enabled(true);
194 }
195 }
196
197 while !self.inner.suspended { 191 while !self.inner.suspended {
198 let control_fut = self.control.setup(); 192 let control_fut = self.control.setup();
199 let bus_fut = self.inner.bus.poll(); 193 let bus_fut = self.inner.bus.poll();
200 match select(bus_fut, control_fut).await { 194 match select(bus_fut, control_fut).await {
201 Either::First(evt) => self.inner.handle_bus_event(evt), 195 Either::First(evt) => self.inner.handle_bus_event(evt).await,
202 Either::Second(req) => self.handle_control(req).await, 196 Either::Second(req) => self.handle_control(req).await,
203 } 197 }
204 } 198 }
@@ -224,7 +218,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
224 pub async fn wait_resume(&mut self) { 218 pub async fn wait_resume(&mut self) {
225 while self.inner.suspended { 219 while self.inner.suspended {
226 let evt = self.inner.bus.poll().await; 220 let evt = self.inner.bus.poll().await;
227 self.inner.handle_bus_event(evt); 221 self.inner.handle_bus_event(evt).await;
228 } 222 }
229 } 223 }
230 224
@@ -341,7 +335,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
341} 335}
342 336
343impl<'d, D: Driver<'d>> Inner<'d, D> { 337impl<'d, D: Driver<'d>> Inner<'d, D> {
344 fn handle_bus_event(&mut self, evt: Event) { 338 async fn handle_bus_event(&mut self, evt: Event) {
345 match evt { 339 match evt {
346 Event::Reset => { 340 Event::Reset => {
347 trace!("usb: reset"); 341 trace!("usb: reset");
@@ -376,6 +370,24 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
376 h.suspended(true); 370 h.suspended(true);
377 } 371 }
378 } 372 }
373 Event::PowerDetected => {
374 trace!("usb: power detected");
375 self.bus.enable().await;
376 self.device_state = UsbDeviceState::Default;
377
378 if let Some(h) = &self.handler {
379 h.enabled(true);
380 }
381 }
382 Event::PowerRemoved => {
383 trace!("usb: power removed");
384 self.bus.disable().await;
385 self.device_state = UsbDeviceState::Unpowered;
386
387 if let Some(h) = &self.handler {
388 h.enabled(false);
389 }
390 }
379 } 391 }
380 } 392 }
381 393
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index a20321fe8..e57cdaf63 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -15,14 +15,14 @@ use embassy::util::Forever;
15use embassy_net::tcp::TcpSocket; 15use embassy_net::tcp::TcpSocket;
16use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; 16use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
17use embassy_nrf::rng::Rng; 17use embassy_nrf::rng::Rng;
18use embassy_nrf::usb::Driver; 18use embassy_nrf::usb::{Driver, PowerUsb};
19use embassy_nrf::{interrupt, pac, peripherals, Peripherals}; 19use embassy_nrf::{interrupt, pac, peripherals, Peripherals};
20use embassy_usb::{Builder, Config, UsbDevice}; 20use embassy_usb::{Builder, Config, UsbDevice};
21use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State}; 21use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
22use embedded_io::asynch::{Read, Write}; 22use embedded_io::asynch::{Read, Write};
23use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
24 24
25type MyDriver = Driver<'static, peripherals::USBD>; 25type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
26 26
27macro_rules! forever { 27macro_rules! forever {
28 ($val:expr) => {{ 28 ($val:expr) => {{
@@ -84,19 +84,15 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
84#[embassy::main] 84#[embassy::main]
85async fn main(spawner: Spawner, p: Peripherals) { 85async fn main(spawner: Spawner, p: Peripherals) {
86 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 86 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
87 let power: pac::POWER = unsafe { mem::transmute(()) };
88 87
89 info!("Enabling ext hfosc..."); 88 info!("Enabling ext hfosc...");
90 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 89 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
91 while clock.events_hfclkstarted.read().bits() != 1 {} 90 while clock.events_hfclkstarted.read().bits() != 1 {}
92 91
93 info!("Waiting for vbus...");
94 while !power.usbregstatus.read().vbusdetect().is_vbus_present() {}
95 info!("vbus OK");
96
97 // Create the driver, from the HAL. 92 // Create the driver, from the HAL.
98 let irq = interrupt::take!(USBD); 93 let irq = interrupt::take!(USBD);
99 let driver = Driver::new(p.USBD, irq); 94 let power_irq = interrupt::take!(POWER_CLOCK);
95 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
100 96
101 // Create embassy-usb Config 97 // Create embassy-usb Config
102 let mut config = Config::new(0xc0de, 0xcafe); 98 let mut config = Config::new(0xc0de, 0xcafe);
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 97ec861d8..539ae6f16 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -10,10 +10,9 @@ use defmt::*;
10use embassy::channel::signal::Signal; 10use embassy::channel::signal::Signal;
11use embassy::executor::Spawner; 11use embassy::executor::Spawner;
12use embassy::time::Duration; 12use embassy::time::Duration;
13use embassy::util::{select, select3, Either, Either3}; 13use embassy::util::{select, Either};
14use embassy_nrf::gpio::{Input, Pin, Pull}; 14use embassy_nrf::gpio::{Input, Pin, Pull};
15use embassy_nrf::interrupt::InterruptExt; 15use embassy_nrf::usb::{Driver, PowerUsb};
16use embassy_nrf::usb::Driver;
17use embassy_nrf::{interrupt, pac, Peripherals}; 16use embassy_nrf::{interrupt, pac, Peripherals};
18use embassy_usb::control::OutResponse; 17use embassy_usb::control::OutResponse;
19use embassy_usb::{Builder, Config, DeviceStateHandler}; 18use embassy_usb::{Builder, Config, DeviceStateHandler};
@@ -22,29 +21,11 @@ use futures::future::join;
22use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 21use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
23use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
24 23
25static ENABLE_USB: Signal<bool> = Signal::new();
26static SUSPENDED: AtomicBool = AtomicBool::new(false); 24static SUSPENDED: AtomicBool = AtomicBool::new(false);
27 25
28fn on_power_interrupt(_: *mut ()) {
29 let regs = unsafe { &*pac::POWER::ptr() };
30
31 if regs.events_usbdetected.read().bits() != 0 {
32 regs.events_usbdetected.reset();
33 info!("Vbus detected, enabling USB...");
34 ENABLE_USB.signal(true);
35 }
36
37 if regs.events_usbremoved.read().bits() != 0 {
38 regs.events_usbremoved.reset();
39 info!("Vbus removed, disabling USB...");
40 ENABLE_USB.signal(false);
41 }
42}
43
44#[embassy::main] 26#[embassy::main]
45async fn main(_spawner: Spawner, p: Peripherals) { 27async fn main(_spawner: Spawner, p: Peripherals) {
46 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 28 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
47 let power: pac::POWER = unsafe { mem::transmute(()) };
48 29
49 info!("Enabling ext hfosc..."); 30 info!("Enabling ext hfosc...");
50 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 31 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
@@ -52,7 +33,8 @@ async fn main(_spawner: Spawner, p: Peripherals) {
52 33
53 // Create the driver, from the HAL. 34 // Create the driver, from the HAL.
54 let irq = interrupt::take!(USBD); 35 let irq = interrupt::take!(USBD);
55 let driver = Driver::new(p.USBD, irq); 36 let power_irq = interrupt::take!(POWER_CLOCK);
37 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
56 38
57 // Create embassy-usb Config 39 // Create embassy-usb Config
58 let mut config = Config::new(0xc0de, 0xcafe); 40 let mut config = Config::new(0xc0de, 0xcafe);
@@ -100,31 +82,11 @@ async fn main(_spawner: Spawner, p: Peripherals) {
100 82
101 // Run the USB device. 83 // Run the USB device.
102 let usb_fut = async { 84 let usb_fut = async {
103 enable_command().await;
104 loop { 85 loop {
105 match select(usb.run_until_suspend(), ENABLE_USB.wait()).await { 86 usb.run_until_suspend().await;
106 Either::First(_) => {} 87 match select(usb.wait_resume(), remote_wakeup.wait()).await {
107 Either::Second(enable) => { 88 Either::First(_) => (),
108 if enable { 89 Either::Second(_) => unwrap!(usb.remote_wakeup().await),
109 warn!("Enable when already enabled!");
110 } else {
111 usb.disable().await;
112 enable_command().await;
113 }
114 }
115 }
116
117 match select3(usb.wait_resume(), ENABLE_USB.wait(), remote_wakeup.wait()).await {
118 Either3::First(_) => (),
119 Either3::Second(enable) => {
120 if enable {
121 warn!("Enable when already enabled!");
122 } else {
123 usb.disable().await;
124 enable_command().await;
125 }
126 }
127 Either3::Third(_) => unwrap!(usb.remote_wakeup().await),
128 } 90 }
129 } 91 }
130 }; 92 };
@@ -174,28 +136,11 @@ async fn main(_spawner: Spawner, p: Peripherals) {
174 reader.run(false, &request_handler).await; 136 reader.run(false, &request_handler).await;
175 }; 137 };
176 138
177 let power_irq = interrupt::take!(POWER_CLOCK);
178 power_irq.set_handler(on_power_interrupt);
179 power_irq.unpend();
180 power_irq.enable();
181
182 power.intenset.write(|w| w.usbdetected().set().usbremoved().set());
183
184 // Run everything concurrently. 139 // Run everything concurrently.
185 // If we had made everything `'static` above instead, we could do this using separate tasks instead. 140 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
186 join(usb_fut, join(in_fut, out_fut)).await; 141 join(usb_fut, join(in_fut, out_fut)).await;
187} 142}
188 143
189async fn enable_command() {
190 loop {
191 if ENABLE_USB.wait().await {
192 break;
193 } else {
194 warn!("Received disable signal when already disabled!");
195 }
196 }
197}
198
199struct MyRequestHandler {} 144struct MyRequestHandler {}
200 145
201impl RequestHandler for MyRequestHandler { 146impl RequestHandler for MyRequestHandler {
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index 9c44e5cc8..516e7ea95 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -8,7 +8,7 @@ use core::mem;
8use defmt::*; 8use defmt::*;
9use embassy::executor::Spawner; 9use embassy::executor::Spawner;
10use embassy::time::{Duration, Timer}; 10use embassy::time::{Duration, Timer};
11use embassy_nrf::usb::Driver; 11use embassy_nrf::usb::{Driver, PowerUsb};
12use embassy_nrf::{interrupt, pac, Peripherals}; 12use embassy_nrf::{interrupt, pac, Peripherals};
13use embassy_usb::control::OutResponse; 13use embassy_usb::control::OutResponse;
14use embassy_usb::{Builder, Config}; 14use embassy_usb::{Builder, Config};
@@ -20,19 +20,15 @@ use {defmt_rtt as _, panic_probe as _};
20#[embassy::main] 20#[embassy::main]
21async fn main(_spawner: Spawner, p: Peripherals) { 21async fn main(_spawner: Spawner, p: Peripherals) {
22 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 22 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
23 let power: pac::POWER = unsafe { mem::transmute(()) };
24 23
25 info!("Enabling ext hfosc..."); 24 info!("Enabling ext hfosc...");
26 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 25 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
27 while clock.events_hfclkstarted.read().bits() != 1 {} 26 while clock.events_hfclkstarted.read().bits() != 1 {}
28 27
29 info!("Waiting for vbus...");
30 while !power.usbregstatus.read().vbusdetect().is_vbus_present() {}
31 info!("vbus OK");
32
33 // Create the driver, from the HAL. 28 // Create the driver, from the HAL.
34 let irq = interrupt::take!(USBD); 29 let irq = interrupt::take!(USBD);
35 let driver = Driver::new(p.USBD, irq); 30 let power_irq = interrupt::take!(POWER_CLOCK);
31 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
36 32
37 // Create embassy-usb Config 33 // Create embassy-usb Config
38 let mut config = Config::new(0xc0de, 0xcafe); 34 let mut config = Config::new(0xc0de, 0xcafe);
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index f108db46d..d2200dc5d 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -7,7 +7,7 @@ use core::mem;
7 7
8use defmt::{info, panic}; 8use defmt::{info, panic};
9use embassy::executor::Spawner; 9use embassy::executor::Spawner;
10use embassy_nrf::usb::{Driver, Instance}; 10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply};
11use embassy_nrf::{interrupt, pac, Peripherals}; 11use embassy_nrf::{interrupt, pac, Peripherals};
12use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config}; 13use embassy_usb::{Builder, Config};
@@ -18,19 +18,15 @@ use {defmt_rtt as _, panic_probe as _};
18#[embassy::main] 18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) { 19async fn main(_spawner: Spawner, p: Peripherals) {
20 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 20 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
21 let power: pac::POWER = unsafe { mem::transmute(()) };
22 21
23 info!("Enabling ext hfosc..."); 22 info!("Enabling ext hfosc...");
24 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 23 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
25 while clock.events_hfclkstarted.read().bits() != 1 {} 24 while clock.events_hfclkstarted.read().bits() != 1 {}
26 25
27 info!("Waiting for vbus...");
28 while !power.usbregstatus.read().vbusdetect().is_vbus_present() {}
29 info!("vbus OK");
30
31 // Create the driver, from the HAL. 26 // Create the driver, from the HAL.
32 let irq = interrupt::take!(USBD); 27 let irq = interrupt::take!(USBD);
33 let driver = Driver::new(p.USBD, irq); 28 let power_irq = interrupt::take!(POWER_CLOCK);
29 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
34 30
35 // Create embassy-usb Config 31 // Create embassy-usb Config
36 let mut config = Config::new(0xc0de, 0xcafe); 32 let mut config = Config::new(0xc0de, 0xcafe);
@@ -101,7 +97,9 @@ impl From<EndpointError> for Disconnected {
101 } 97 }
102} 98}
103 99
104async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { 100async fn echo<'d, T: Instance + 'd, P: UsbSupply + 'd>(
101 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
102) -> Result<(), Disconnected> {
105 let mut buf = [0; 64]; 103 let mut buf = [0; 64];
106 loop { 104 loop {
107 let n = class.read_packet(&mut buf).await?; 105 let n = class.read_packet(&mut buf).await?;
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index dc503e67c..3806da5a0 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -8,14 +8,14 @@ use core::mem;
8use defmt::{info, panic, unwrap}; 8use defmt::{info, panic, unwrap};
9use embassy::executor::Spawner; 9use embassy::executor::Spawner;
10use embassy::util::Forever; 10use embassy::util::Forever;
11use embassy_nrf::usb::Driver; 11use embassy_nrf::usb::{Driver, PowerUsb};
12use embassy_nrf::{interrupt, pac, peripherals, Peripherals}; 12use embassy_nrf::{interrupt, pac, peripherals, Peripherals};
13use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
14use embassy_usb::{Builder, Config, UsbDevice}; 14use embassy_usb::{Builder, Config, UsbDevice};
15use embassy_usb_serial::{CdcAcmClass, State}; 15use embassy_usb_serial::{CdcAcmClass, State};
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18type MyDriver = Driver<'static, peripherals::USBD>; 18type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
19 19
20#[embassy::task] 20#[embassy::task]
21async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { 21async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
@@ -35,19 +35,14 @@ async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) {
35#[embassy::main] 35#[embassy::main]
36async fn main(spawner: Spawner, p: Peripherals) { 36async fn main(spawner: Spawner, p: Peripherals) {
37 let clock: pac::CLOCK = unsafe { mem::transmute(()) }; 37 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
38 let power: pac::POWER = unsafe { mem::transmute(()) };
39 38
40 info!("Enabling ext hfosc..."); 39 info!("Enabling ext hfosc...");
41 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 40 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
42 while clock.events_hfclkstarted.read().bits() != 1 {} 41 while clock.events_hfclkstarted.read().bits() != 1 {}
43
44 info!("Waiting for vbus...");
45 while !power.usbregstatus.read().vbusdetect().is_vbus_present() {}
46 info!("vbus OK");
47
48 // Create the driver, from the HAL. 42 // Create the driver, from the HAL.
49 let irq = interrupt::take!(USBD); 43 let irq = interrupt::take!(USBD);
50 let driver = Driver::new(p.USBD, irq); 44 let power_irq = interrupt::take!(POWER_CLOCK);
45 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
51 46
52 // Create embassy-usb Config 47 // Create embassy-usb Config
53 let mut config = Config::new(0xc0de, 0xcafe); 48 let mut config = Config::new(0xc0de, 0xcafe);