diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-03-05 22:36:53 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-03-06 00:17:51 +0100 |
| commit | 5249996d282e1ae08cea1593193e2fe6ca20880a (patch) | |
| tree | 752b37a914066ceb602fbb821e56cfcda2d9912e | |
| parent | 5913553cb1e95431665d3370dce8154a6869e434 (diff) | |
nrf/usb: switch to new interrupt binding, fix vbus detect on nrf53.
| -rw-r--r-- | embassy-nrf/src/usb/mod.rs (renamed from embassy-nrf/src/usb.rs) | 234 | ||||
| -rw-r--r-- | embassy-nrf/src/usb/vbus_detect.rs | 177 | ||||
| -rw-r--r-- | examples/nrf52840/Cargo.toml | 7 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_ethernet.rs | 12 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_hid_keyboard.rs | 16 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_hid_mouse.rs | 16 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_serial.rs | 16 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_serial_multitask.rs | 51 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/usb_serial_winusb.rs | 14 |
9 files changed, 300 insertions, 243 deletions
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb/mod.rs index cd142f00f..56de511df 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb/mod.rs | |||
| @@ -2,10 +2,12 @@ | |||
| 2 | 2 | ||
| 3 | #![macro_use] | 3 | #![macro_use] |
| 4 | 4 | ||
| 5 | pub mod vbus_detect; | ||
| 6 | |||
| 5 | use core::future::poll_fn; | 7 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 8 | use core::marker::PhantomData; |
| 7 | use core::mem::MaybeUninit; | 9 | use core::mem::MaybeUninit; |
| 8 | use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | 10 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; |
| 9 | use core::task::Poll; | 11 | use core::task::Poll; |
| 10 | 12 | ||
| 11 | use cortex_m::peripheral::NVIC; | 13 | use cortex_m::peripheral::NVIC; |
| @@ -15,7 +17,8 @@ use embassy_usb_driver as driver; | |||
| 15 | use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; | 17 | use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; |
| 16 | use pac::usbd::RegisterBlock; | 18 | use pac::usbd::RegisterBlock; |
| 17 | 19 | ||
| 18 | use crate::interrupt::{Interrupt, InterruptExt}; | 20 | use self::vbus_detect::VbusDetect; |
| 21 | use crate::interrupt::{self, Interrupt, InterruptExt}; | ||
| 19 | use crate::util::slice_in_ram; | 22 | use crate::util::slice_in_ram; |
| 20 | use crate::{pac, Peripheral}; | 23 | use crate::{pac, Peripheral}; |
| 21 | 24 | ||
| @@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | |||
| 26 | static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | 29 | static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; |
| 27 | static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); | 30 | static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); |
| 28 | 31 | ||
| 29 | /// Trait for detecting USB VBUS power. | 32 | /// Interrupt handler. |
| 30 | /// | 33 | pub struct InterruptHandler<T: Instance> { |
| 31 | /// There are multiple ways to detect USB power. The behavior | 34 | _phantom: PhantomData<T>, |
| 32 | /// here provides a hook into determining whether it is. | ||
| 33 | pub trait VbusDetect { | ||
| 34 | /// Report whether power is detected. | ||
| 35 | /// | ||
| 36 | /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the | ||
| 37 | /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||
| 38 | fn is_usb_detected(&self) -> bool; | ||
| 39 | |||
| 40 | /// Wait until USB power is ready. | ||
| 41 | /// | ||
| 42 | /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the | ||
| 43 | /// `USBPWRRDY` event from the `POWER` peripheral. | ||
| 44 | async fn wait_power_ready(&mut self) -> Result<(), ()>; | ||
| 45 | } | ||
| 46 | |||
| 47 | /// [`VbusDetect`] implementation using the native hardware POWER peripheral. | ||
| 48 | /// | ||
| 49 | /// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces | ||
| 50 | /// to POWER. In that case, use [`VbusDetectSignal`]. | ||
| 51 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 52 | pub struct HardwareVbusDetect { | ||
| 53 | _private: (), | ||
| 54 | } | ||
| 55 | |||
| 56 | static POWER_WAKER: AtomicWaker = NEW_AW; | ||
| 57 | |||
| 58 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 59 | impl HardwareVbusDetect { | ||
| 60 | /// Create a new `VbusDetectNative`. | ||
| 61 | pub fn new(power_irq: impl Interrupt) -> Self { | ||
| 62 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 63 | |||
| 64 | power_irq.set_handler(Self::on_interrupt); | ||
| 65 | power_irq.unpend(); | ||
| 66 | power_irq.enable(); | ||
| 67 | |||
| 68 | regs.intenset | ||
| 69 | .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||
| 70 | |||
| 71 | Self { _private: () } | ||
| 72 | } | ||
| 73 | |||
| 74 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 75 | fn on_interrupt(_: *mut ()) { | ||
| 76 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 77 | |||
| 78 | if regs.events_usbdetected.read().bits() != 0 { | ||
| 79 | regs.events_usbdetected.reset(); | ||
| 80 | BUS_WAKER.wake(); | ||
| 81 | } | ||
| 82 | |||
| 83 | if regs.events_usbremoved.read().bits() != 0 { | ||
| 84 | regs.events_usbremoved.reset(); | ||
| 85 | BUS_WAKER.wake(); | ||
| 86 | POWER_WAKER.wake(); | ||
| 87 | } | ||
| 88 | |||
| 89 | if regs.events_usbpwrrdy.read().bits() != 0 { | ||
| 90 | regs.events_usbpwrrdy.reset(); | ||
| 91 | POWER_WAKER.wake(); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 97 | impl VbusDetect for HardwareVbusDetect { | ||
| 98 | fn is_usb_detected(&self) -> bool { | ||
| 99 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 100 | regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||
| 101 | } | ||
| 102 | |||
| 103 | async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||
| 104 | poll_fn(move |cx| { | ||
| 105 | POWER_WAKER.register(cx.waker()); | ||
| 106 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 107 | |||
| 108 | if regs.usbregstatus.read().outputrdy().is_ready() { | ||
| 109 | Poll::Ready(Ok(())) | ||
| 110 | } else if !self.is_usb_detected() { | ||
| 111 | Poll::Ready(Err(())) | ||
| 112 | } else { | ||
| 113 | Poll::Pending | ||
| 114 | } | ||
| 115 | }) | ||
| 116 | .await | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Software-backed [`VbusDetect`] implementation. | ||
| 121 | /// | ||
| 122 | /// This implementation does not interact with the hardware, it allows user code | ||
| 123 | /// to notify the power events by calling functions instead. | ||
| 124 | /// | ||
| 125 | /// This is suitable for use with the nRF softdevice, by calling the functions | ||
| 126 | /// when the softdevice reports power-related events. | ||
| 127 | pub struct SoftwareVbusDetect { | ||
| 128 | usb_detected: AtomicBool, | ||
| 129 | power_ready: AtomicBool, | ||
| 130 | } | ||
| 131 | |||
| 132 | impl SoftwareVbusDetect { | ||
| 133 | /// Create a new `SoftwareVbusDetect`. | ||
| 134 | pub fn new(usb_detected: bool, power_ready: bool) -> Self { | ||
| 135 | BUS_WAKER.wake(); | ||
| 136 | |||
| 137 | Self { | ||
| 138 | usb_detected: AtomicBool::new(usb_detected), | ||
| 139 | power_ready: AtomicBool::new(power_ready), | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | /// Report whether power was detected. | ||
| 144 | /// | ||
| 145 | /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||
| 146 | pub fn detected(&self, detected: bool) { | ||
| 147 | self.usb_detected.store(detected, Ordering::Relaxed); | ||
| 148 | self.power_ready.store(false, Ordering::Relaxed); | ||
| 149 | BUS_WAKER.wake(); | ||
| 150 | POWER_WAKER.wake(); | ||
| 151 | } | ||
| 152 | |||
| 153 | /// Report when USB power is ready. | ||
| 154 | /// | ||
| 155 | /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral. | ||
| 156 | pub fn ready(&self) { | ||
| 157 | self.power_ready.store(true, Ordering::Relaxed); | ||
| 158 | POWER_WAKER.wake(); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | impl VbusDetect for &SoftwareVbusDetect { | ||
| 163 | fn is_usb_detected(&self) -> bool { | ||
| 164 | self.usb_detected.load(Ordering::Relaxed) | ||
| 165 | } | ||
| 166 | |||
| 167 | async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||
| 168 | poll_fn(move |cx| { | ||
| 169 | POWER_WAKER.register(cx.waker()); | ||
| 170 | |||
| 171 | if self.power_ready.load(Ordering::Relaxed) { | ||
| 172 | Poll::Ready(Ok(())) | ||
| 173 | } else if !self.usb_detected.load(Ordering::Relaxed) { | ||
| 174 | Poll::Ready(Err(())) | ||
| 175 | } else { | ||
| 176 | Poll::Pending | ||
| 177 | } | ||
| 178 | }) | ||
| 179 | .await | ||
| 180 | } | ||
| 181 | } | 35 | } |
| 182 | 36 | ||
| 183 | /// USB driver. | 37 | impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> { |
| 184 | pub struct Driver<'d, T: Instance, P: VbusDetect> { | 38 | unsafe fn on_interrupt() { |
| 185 | _p: PeripheralRef<'d, T>, | ||
| 186 | alloc_in: Allocator, | ||
| 187 | alloc_out: Allocator, | ||
| 188 | usb_supply: P, | ||
| 189 | } | ||
| 190 | |||
| 191 | impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> { | ||
| 192 | /// Create a new USB driver. | ||
| 193 | pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self { | ||
| 194 | into_ref!(usb, irq); | ||
| 195 | irq.set_handler(Self::on_interrupt); | ||
| 196 | irq.unpend(); | ||
| 197 | irq.enable(); | ||
| 198 | |||
| 199 | Self { | ||
| 200 | _p: usb, | ||
| 201 | alloc_in: Allocator::new(), | ||
| 202 | alloc_out: Allocator::new(), | ||
| 203 | usb_supply, | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | fn on_interrupt(_: *mut ()) { | ||
| 208 | let regs = T::regs(); | 39 | let regs = T::regs(); |
| 209 | 40 | ||
| 210 | if regs.events_usbreset.read().bits() != 0 { | 41 | if regs.events_usbreset.read().bits() != 0 { |
| @@ -255,11 +86,40 @@ impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> { | |||
| 255 | } | 86 | } |
| 256 | } | 87 | } |
| 257 | 88 | ||
| 258 | impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> { | 89 | /// USB driver. |
| 90 | pub struct Driver<'d, T: Instance, V: VbusDetect> { | ||
| 91 | _p: PeripheralRef<'d, T>, | ||
| 92 | alloc_in: Allocator, | ||
| 93 | alloc_out: Allocator, | ||
| 94 | vbus_detect: V, | ||
| 95 | } | ||
| 96 | |||
| 97 | impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { | ||
| 98 | /// Create a new USB driver. | ||
| 99 | pub fn new( | ||
| 100 | usb: impl Peripheral<P = T> + 'd, | ||
| 101 | _irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 102 | vbus_detect: V, | ||
| 103 | ) -> Self { | ||
| 104 | into_ref!(usb); | ||
| 105 | |||
| 106 | unsafe { T::Interrupt::steal() }.unpend(); | ||
| 107 | unsafe { T::Interrupt::steal() }.enable(); | ||
| 108 | |||
| 109 | Self { | ||
| 110 | _p: usb, | ||
| 111 | alloc_in: Allocator::new(), | ||
| 112 | alloc_out: Allocator::new(), | ||
| 113 | vbus_detect, | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> { | ||
| 259 | type EndpointOut = Endpoint<'d, T, Out>; | 119 | type EndpointOut = Endpoint<'d, T, Out>; |
| 260 | type EndpointIn = Endpoint<'d, T, In>; | 120 | type EndpointIn = Endpoint<'d, T, In>; |
| 261 | type ControlPipe = ControlPipe<'d, T>; | 121 | type ControlPipe = ControlPipe<'d, T>; |
| 262 | type Bus = Bus<'d, T, P>; | 122 | type Bus = Bus<'d, T, V>; |
| 263 | 123 | ||
| 264 | fn alloc_endpoint_in( | 124 | fn alloc_endpoint_in( |
| 265 | &mut self, | 125 | &mut self, |
| @@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P | |||
| 298 | Bus { | 158 | Bus { |
| 299 | _p: unsafe { self._p.clone_unchecked() }, | 159 | _p: unsafe { self._p.clone_unchecked() }, |
| 300 | power_available: false, | 160 | power_available: false, |
| 301 | usb_supply: self.usb_supply, | 161 | vbus_detect: self.vbus_detect, |
| 302 | }, | 162 | }, |
| 303 | ControlPipe { | 163 | ControlPipe { |
| 304 | _p: self._p, | 164 | _p: self._p, |
| @@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P | |||
| 309 | } | 169 | } |
| 310 | 170 | ||
| 311 | /// USB bus. | 171 | /// USB bus. |
| 312 | pub struct Bus<'d, T: Instance, P: VbusDetect> { | 172 | pub struct Bus<'d, T: Instance, V: VbusDetect> { |
| 313 | _p: PeripheralRef<'d, T>, | 173 | _p: PeripheralRef<'d, T>, |
| 314 | power_available: bool, | 174 | power_available: bool, |
| 315 | usb_supply: P, | 175 | vbus_detect: V, |
| 316 | } | 176 | } |
| 317 | 177 | ||
| 318 | impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | 178 | impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { |
| 319 | async fn enable(&mut self) { | 179 | async fn enable(&mut self) { |
| 320 | let regs = T::regs(); | 180 | let regs = T::regs(); |
| 321 | 181 | ||
| @@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | |||
| 347 | w | 207 | w |
| 348 | }); | 208 | }); |
| 349 | 209 | ||
| 350 | if self.usb_supply.wait_power_ready().await.is_ok() { | 210 | if self.vbus_detect.wait_power_ready().await.is_ok() { |
| 351 | // Enable the USB pullup, allowing enumeration. | 211 | // Enable the USB pullup, allowing enumeration. |
| 352 | regs.usbpullup.write(|w| w.connect().enabled()); | 212 | regs.usbpullup.write(|w| w.connect().enabled()); |
| 353 | trace!("enabled"); | 213 | trace!("enabled"); |
| @@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> { | |||
| 406 | trace!("USB event: ready"); | 266 | trace!("USB event: ready"); |
| 407 | } | 267 | } |
| 408 | 268 | ||
| 409 | if self.usb_supply.is_usb_detected() != self.power_available { | 269 | if self.vbus_detect.is_usb_detected() != self.power_available { |
| 410 | self.power_available = !self.power_available; | 270 | self.power_available = !self.power_available; |
| 411 | if self.power_available { | 271 | if self.power_available { |
| 412 | trace!("Power event: available"); | 272 | trace!("Power event: available"); |
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs new file mode 100644 index 000000000..cecd4c595 --- /dev/null +++ b/embassy-nrf/src/usb/vbus_detect.rs | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | //! Trait and implementations for performing VBUS detection. | ||
| 2 | |||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | |||
| 9 | use super::BUS_WAKER; | ||
| 10 | use crate::interrupt::{self, Interrupt, InterruptExt}; | ||
| 11 | use crate::pac; | ||
| 12 | |||
| 13 | /// Trait for detecting USB VBUS power. | ||
| 14 | /// | ||
| 15 | /// There are multiple ways to detect USB power. The behavior | ||
| 16 | /// here provides a hook into determining whether it is. | ||
| 17 | pub trait VbusDetect { | ||
| 18 | /// Report whether power is detected. | ||
| 19 | /// | ||
| 20 | /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the | ||
| 21 | /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||
| 22 | fn is_usb_detected(&self) -> bool; | ||
| 23 | |||
| 24 | /// Wait until USB power is ready. | ||
| 25 | /// | ||
| 26 | /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the | ||
| 27 | /// `USBPWRRDY` event from the `POWER` peripheral. | ||
| 28 | async fn wait_power_ready(&mut self) -> Result<(), ()>; | ||
| 29 | } | ||
| 30 | |||
| 31 | #[cfg(not(feature = "_nrf5340"))] | ||
| 32 | type UsbRegIrq = interrupt::POWER_CLOCK; | ||
| 33 | #[cfg(feature = "_nrf5340")] | ||
| 34 | type UsbRegIrq = interrupt::USBREGULATOR; | ||
| 35 | |||
| 36 | #[cfg(not(feature = "_nrf5340"))] | ||
| 37 | type UsbRegPeri = pac::POWER; | ||
| 38 | #[cfg(feature = "_nrf5340")] | ||
| 39 | type UsbRegPeri = pac::USBREGULATOR; | ||
| 40 | |||
| 41 | /// Interrupt handler. | ||
| 42 | pub struct InterruptHandler { | ||
| 43 | _private: (), | ||
| 44 | } | ||
| 45 | |||
| 46 | impl interrupt::Handler<UsbRegIrq> for InterruptHandler { | ||
| 47 | unsafe fn on_interrupt() { | ||
| 48 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 49 | |||
| 50 | if regs.events_usbdetected.read().bits() != 0 { | ||
| 51 | regs.events_usbdetected.reset(); | ||
| 52 | BUS_WAKER.wake(); | ||
| 53 | } | ||
| 54 | |||
| 55 | if regs.events_usbremoved.read().bits() != 0 { | ||
| 56 | regs.events_usbremoved.reset(); | ||
| 57 | BUS_WAKER.wake(); | ||
| 58 | POWER_WAKER.wake(); | ||
| 59 | } | ||
| 60 | |||
| 61 | if regs.events_usbpwrrdy.read().bits() != 0 { | ||
| 62 | regs.events_usbpwrrdy.reset(); | ||
| 63 | POWER_WAKER.wake(); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// [`VbusDetect`] implementation using the native hardware POWER peripheral. | ||
| 69 | /// | ||
| 70 | /// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces | ||
| 71 | /// to POWER. In that case, use [`VbusDetectSignal`]. | ||
| 72 | pub struct HardwareVbusDetect { | ||
| 73 | _private: (), | ||
| 74 | } | ||
| 75 | |||
| 76 | static POWER_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 77 | |||
| 78 | impl HardwareVbusDetect { | ||
| 79 | /// Create a new `VbusDetectNative`. | ||
| 80 | pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { | ||
| 81 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 82 | |||
| 83 | unsafe { UsbRegIrq::steal() }.unpend(); | ||
| 84 | unsafe { UsbRegIrq::steal() }.enable(); | ||
| 85 | |||
| 86 | regs.intenset | ||
| 87 | .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||
| 88 | |||
| 89 | Self { _private: () } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | impl VbusDetect for HardwareVbusDetect { | ||
| 94 | fn is_usb_detected(&self) -> bool { | ||
| 95 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 96 | regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||
| 97 | } | ||
| 98 | |||
| 99 | async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||
| 100 | poll_fn(move |cx| { | ||
| 101 | POWER_WAKER.register(cx.waker()); | ||
| 102 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 103 | |||
| 104 | if regs.usbregstatus.read().outputrdy().is_ready() { | ||
| 105 | Poll::Ready(Ok(())) | ||
| 106 | } else if !self.is_usb_detected() { | ||
| 107 | Poll::Ready(Err(())) | ||
| 108 | } else { | ||
| 109 | Poll::Pending | ||
| 110 | } | ||
| 111 | }) | ||
| 112 | .await | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Software-backed [`VbusDetect`] implementation. | ||
| 117 | /// | ||
| 118 | /// This implementation does not interact with the hardware, it allows user code | ||
| 119 | /// to notify the power events by calling functions instead. | ||
| 120 | /// | ||
| 121 | /// This is suitable for use with the nRF softdevice, by calling the functions | ||
| 122 | /// when the softdevice reports power-related events. | ||
| 123 | pub struct SoftwareVbusDetect { | ||
| 124 | usb_detected: AtomicBool, | ||
| 125 | power_ready: AtomicBool, | ||
| 126 | } | ||
| 127 | |||
| 128 | impl SoftwareVbusDetect { | ||
| 129 | /// Create a new `SoftwareVbusDetect`. | ||
| 130 | pub fn new(usb_detected: bool, power_ready: bool) -> Self { | ||
| 131 | BUS_WAKER.wake(); | ||
| 132 | |||
| 133 | Self { | ||
| 134 | usb_detected: AtomicBool::new(usb_detected), | ||
| 135 | power_ready: AtomicBool::new(power_ready), | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Report whether power was detected. | ||
| 140 | /// | ||
| 141 | /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||
| 142 | pub fn detected(&self, detected: bool) { | ||
| 143 | self.usb_detected.store(detected, Ordering::Relaxed); | ||
| 144 | self.power_ready.store(false, Ordering::Relaxed); | ||
| 145 | BUS_WAKER.wake(); | ||
| 146 | POWER_WAKER.wake(); | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Report when USB power is ready. | ||
| 150 | /// | ||
| 151 | /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral. | ||
| 152 | pub fn ready(&self) { | ||
| 153 | self.power_ready.store(true, Ordering::Relaxed); | ||
| 154 | POWER_WAKER.wake(); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | impl VbusDetect for &SoftwareVbusDetect { | ||
| 159 | fn is_usb_detected(&self) -> bool { | ||
| 160 | self.usb_detected.load(Ordering::Relaxed) | ||
| 161 | } | ||
| 162 | |||
| 163 | async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||
| 164 | poll_fn(move |cx| { | ||
| 165 | POWER_WAKER.register(cx.waker()); | ||
| 166 | |||
| 167 | if self.power_ready.load(Ordering::Relaxed) { | ||
| 168 | Poll::Ready(Ok(())) | ||
| 169 | } else if !self.usb_detected.load(Ordering::Relaxed) { | ||
| 170 | Poll::Ready(Err(())) | ||
| 171 | } else { | ||
| 172 | Poll::Pending | ||
| 173 | } | ||
| 174 | }) | ||
| 175 | .await | ||
| 176 | } | ||
| 177 | } | ||
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index cfdda076e..cc88d92c7 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml | |||
| @@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0" | |||
| 6 | 6 | ||
| 7 | [features] | 7 | [features] |
| 8 | default = ["nightly"] | 8 | default = ["nightly"] |
| 9 | msos-descriptor = ["embassy-usb/msos-descriptor"] | ||
| 10 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net", | 9 | nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net", |
| 11 | "embassy-lora", "lorawan-device", "lorawan"] | 10 | "embassy-lora", "lorawan-device", "lorawan"] |
| 12 | 11 | ||
| @@ -17,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature | |||
| 17 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 16 | embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 18 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 17 | embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 19 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } | 18 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } |
| 20 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } | 19 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } |
| 21 | embedded-io = "0.4.0" | 20 | embedded-io = "0.4.0" |
| 22 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } | 21 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true } |
| 23 | 22 | ||
| @@ -36,7 +35,3 @@ rand = { version = "0.8.4", default-features = false } | |||
| 36 | embedded-storage = "0.3.0" | 35 | embedded-storage = "0.3.0" |
| 37 | usbd-hid = "0.6.0" | 36 | usbd-hid = "0.6.0" |
| 38 | serde = { version = "1.0.136", default-features = false } | 37 | serde = { version = "1.0.136", default-features = false } |
| 39 | |||
| 40 | [[bin]] | ||
| 41 | name = "usb_serial_winusb" | ||
| 42 | required-features = ["msos-descriptor"] | ||
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 083a1cbb0..b8a72313a 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs | |||
| @@ -9,8 +9,9 @@ use embassy_executor::Spawner; | |||
| 9 | use embassy_net::tcp::TcpSocket; | 9 | use embassy_net::tcp::TcpSocket; |
| 10 | use embassy_net::{Stack, StackResources}; | 10 | use embassy_net::{Stack, StackResources}; |
| 11 | use embassy_nrf::rng::Rng; | 11 | use embassy_nrf::rng::Rng; |
| 12 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 12 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 13 | use embassy_nrf::{bind_interrupts, interrupt, pac, peripherals, rng}; | 13 | use embassy_nrf::usb::Driver; |
| 14 | use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; | ||
| 14 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 15 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| 15 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 16 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| 16 | use embassy_usb::{Builder, Config, UsbDevice}; | 17 | use embassy_usb::{Builder, Config, UsbDevice}; |
| @@ -19,6 +20,8 @@ use static_cell::StaticCell; | |||
| 19 | use {defmt_rtt as _, panic_probe as _}; | 20 | use {defmt_rtt as _, panic_probe as _}; |
| 20 | 21 | ||
| 21 | bind_interrupts!(struct Irqs { | 22 | bind_interrupts!(struct Irqs { |
| 23 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 24 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 22 | RNG => rng::InterruptHandler<peripherals::RNG>; | 25 | RNG => rng::InterruptHandler<peripherals::RNG>; |
| 23 | }); | 26 | }); |
| 24 | 27 | ||
| @@ -60,9 +63,7 @@ async fn main(spawner: Spawner) { | |||
| 60 | while clock.events_hfclkstarted.read().bits() != 1 {} | 63 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 61 | 64 | ||
| 62 | // Create the driver, from the HAL. | 65 | // Create the driver, from the HAL. |
| 63 | let irq = interrupt::take!(USBD); | 66 | let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); |
| 64 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 65 | let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||
| 66 | 67 | ||
| 67 | // Create embassy-usb Config | 68 | // Create embassy-usb Config |
| 68 | let mut config = Config::new(0xc0de, 0xcafe); | 69 | let mut config = Config::new(0xc0de, 0xcafe); |
| @@ -86,6 +87,7 @@ async fn main(spawner: Spawner) { | |||
| 86 | &mut singleton!([0; 256])[..], | 87 | &mut singleton!([0; 256])[..], |
| 87 | &mut singleton!([0; 256])[..], | 88 | &mut singleton!([0; 256])[..], |
| 88 | &mut singleton!([0; 128])[..], | 89 | &mut singleton!([0; 128])[..], |
| 90 | &mut singleton!([0; 128])[..], | ||
| 89 | ); | 91 | ); |
| 90 | 92 | ||
| 91 | // Our MAC addr. | 93 | // Our MAC addr. |
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 3d8a114cd..7ccd2946a 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs | |||
| @@ -10,8 +10,9 @@ use embassy_executor::Spawner; | |||
| 10 | use embassy_futures::join::join; | 10 | use embassy_futures::join::join; |
| 11 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 12 | use embassy_nrf::gpio::{Input, Pin, Pull}; |
| 13 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 13 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 14 | use embassy_nrf::{interrupt, pac}; | 14 | use embassy_nrf::usb::Driver; |
| 15 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 16 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 16 | use embassy_sync::signal::Signal; | 17 | use embassy_sync::signal::Signal; |
| 17 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 18 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; |
| @@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler}; | |||
| 20 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 21 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| 21 | use {defmt_rtt as _, panic_probe as _}; | 22 | use {defmt_rtt as _, panic_probe as _}; |
| 22 | 23 | ||
| 24 | bind_interrupts!(struct Irqs { | ||
| 25 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 26 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 27 | }); | ||
| 28 | |||
| 23 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | 29 | static SUSPENDED: AtomicBool = AtomicBool::new(false); |
| 24 | 30 | ||
| 25 | #[embassy_executor::main] | 31 | #[embassy_executor::main] |
| @@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) { | |||
| 32 | while clock.events_hfclkstarted.read().bits() != 1 {} | 38 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 33 | 39 | ||
| 34 | // Create the driver, from the HAL. | 40 | // Create the driver, from the HAL. |
| 35 | let irq = interrupt::take!(USBD); | 41 | let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); |
| 36 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 37 | let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||
| 38 | 42 | ||
| 39 | // Create embassy-usb Config | 43 | // Create embassy-usb Config |
| 40 | let mut config = Config::new(0xc0de, 0xcafe); | 44 | let mut config = Config::new(0xc0de, 0xcafe); |
| @@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) { | |||
| 50 | let mut device_descriptor = [0; 256]; | 54 | let mut device_descriptor = [0; 256]; |
| 51 | let mut config_descriptor = [0; 256]; | 55 | let mut config_descriptor = [0; 256]; |
| 52 | let mut bos_descriptor = [0; 256]; | 56 | let mut bos_descriptor = [0; 256]; |
| 57 | let mut msos_descriptor = [0; 256]; | ||
| 53 | let mut control_buf = [0; 64]; | 58 | let mut control_buf = [0; 64]; |
| 54 | let request_handler = MyRequestHandler {}; | 59 | let request_handler = MyRequestHandler {}; |
| 55 | let mut device_handler = MyDeviceHandler::new(); | 60 | let mut device_handler = MyDeviceHandler::new(); |
| @@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) { | |||
| 62 | &mut device_descriptor, | 67 | &mut device_descriptor, |
| 63 | &mut config_descriptor, | 68 | &mut config_descriptor, |
| 64 | &mut bos_descriptor, | 69 | &mut bos_descriptor, |
| 70 | &mut msos_descriptor, | ||
| 65 | &mut control_buf, | 71 | &mut control_buf, |
| 66 | ); | 72 | ); |
| 67 | 73 | ||
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index d7c9d55b7..edf634a5e 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs | |||
| @@ -7,8 +7,9 @@ use core::mem; | |||
| 7 | use defmt::*; | 7 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 10 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::usb::Driver; |
| 12 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 12 | use embassy_time::{Duration, Timer}; | 13 | use embassy_time::{Duration, Timer}; |
| 13 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 14 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; |
| 14 | use embassy_usb::control::OutResponse; | 15 | use embassy_usb::control::OutResponse; |
| @@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config}; | |||
| 16 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 17 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 19 | ||
| 20 | bind_interrupts!(struct Irqs { | ||
| 21 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 22 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 23 | }); | ||
| 24 | |||
| 19 | #[embassy_executor::main] | 25 | #[embassy_executor::main] |
| 20 | async fn main(_spawner: Spawner) { | 26 | async fn main(_spawner: Spawner) { |
| 21 | let p = embassy_nrf::init(Default::default()); | 27 | let p = embassy_nrf::init(Default::default()); |
| @@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) { | |||
| 26 | while clock.events_hfclkstarted.read().bits() != 1 {} | 32 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 27 | 33 | ||
| 28 | // Create the driver, from the HAL. | 34 | // Create the driver, from the HAL. |
| 29 | let irq = interrupt::take!(USBD); | 35 | let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); |
| 30 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 31 | let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||
| 32 | 36 | ||
| 33 | // Create embassy-usb Config | 37 | // Create embassy-usb Config |
| 34 | let mut config = Config::new(0xc0de, 0xcafe); | 38 | let mut config = Config::new(0xc0de, 0xcafe); |
| @@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) { | |||
| 43 | let mut device_descriptor = [0; 256]; | 47 | let mut device_descriptor = [0; 256]; |
| 44 | let mut config_descriptor = [0; 256]; | 48 | let mut config_descriptor = [0; 256]; |
| 45 | let mut bos_descriptor = [0; 256]; | 49 | let mut bos_descriptor = [0; 256]; |
| 50 | let mut msos_descriptor = [0; 256]; | ||
| 46 | let mut control_buf = [0; 64]; | 51 | let mut control_buf = [0; 64]; |
| 47 | let request_handler = MyRequestHandler {}; | 52 | let request_handler = MyRequestHandler {}; |
| 48 | 53 | ||
| @@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) { | |||
| 54 | &mut device_descriptor, | 59 | &mut device_descriptor, |
| 55 | &mut config_descriptor, | 60 | &mut config_descriptor, |
| 56 | &mut bos_descriptor, | 61 | &mut bos_descriptor, |
| 62 | &mut msos_descriptor, | ||
| 57 | &mut control_buf, | 63 | &mut control_buf, |
| 58 | ); | 64 | ); |
| 59 | 65 | ||
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index 102d7ea60..9727a4f57 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs | |||
| @@ -7,13 +7,19 @@ use core::mem; | |||
| 7 | use defmt::{info, panic}; | 7 | use defmt::{info, panic}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; | 10 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::usb::{Driver, Instance}; |
| 12 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::{Builder, Config}; | 15 | use embassy_usb::{Builder, Config}; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 20 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 21 | }); | ||
| 22 | |||
| 17 | #[embassy_executor::main] | 23 | #[embassy_executor::main] |
| 18 | async fn main(_spawner: Spawner) { | 24 | async fn main(_spawner: Spawner) { |
| 19 | let p = embassy_nrf::init(Default::default()); | 25 | let p = embassy_nrf::init(Default::default()); |
| @@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) { | |||
| 24 | while clock.events_hfclkstarted.read().bits() != 1 {} | 30 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 25 | 31 | ||
| 26 | // Create the driver, from the HAL. | 32 | // Create the driver, from the HAL. |
| 27 | let irq = interrupt::take!(USBD); | 33 | let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); |
| 28 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 29 | let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||
| 30 | 34 | ||
| 31 | // Create embassy-usb Config | 35 | // Create embassy-usb Config |
| 32 | let mut config = Config::new(0xc0de, 0xcafe); | 36 | let mut config = Config::new(0xc0de, 0xcafe); |
| @@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) { | |||
| 48 | let mut device_descriptor = [0; 256]; | 52 | let mut device_descriptor = [0; 256]; |
| 49 | let mut config_descriptor = [0; 256]; | 53 | let mut config_descriptor = [0; 256]; |
| 50 | let mut bos_descriptor = [0; 256]; | 54 | let mut bos_descriptor = [0; 256]; |
| 55 | let mut msos_descriptor = [0; 256]; | ||
| 51 | let mut control_buf = [0; 64]; | 56 | let mut control_buf = [0; 64]; |
| 52 | 57 | ||
| 53 | let mut state = State::new(); | 58 | let mut state = State::new(); |
| @@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) { | |||
| 58 | &mut device_descriptor, | 63 | &mut device_descriptor, |
| 59 | &mut config_descriptor, | 64 | &mut config_descriptor, |
| 60 | &mut bos_descriptor, | 65 | &mut bos_descriptor, |
| 66 | &mut msos_descriptor, | ||
| 61 | &mut control_buf, | 67 | &mut control_buf, |
| 62 | ); | 68 | ); |
| 63 | 69 | ||
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 558d4ba60..6da2c2a2f 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs | |||
| @@ -6,14 +6,29 @@ use core::mem; | |||
| 6 | 6 | ||
| 7 | use defmt::{info, panic, unwrap}; | 7 | use defmt::{info, panic, unwrap}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::usb::{Driver, HardwareVbusDetect}; | 9 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; |
| 10 | use embassy_nrf::{interrupt, pac, peripherals}; | 10 | use embassy_nrf::usb::Driver; |
| 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 12 | use embassy_usb::driver::EndpointError; | 13 | use embassy_usb::driver::EndpointError; |
| 13 | use embassy_usb::{Builder, Config, UsbDevice}; | 14 | use embassy_usb::{Builder, Config, UsbDevice}; |
| 14 | use static_cell::StaticCell; | 15 | use static_cell::StaticCell; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {defmt_rtt as _, panic_probe as _}; |
| 16 | 17 | ||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 20 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 21 | }); | ||
| 22 | |||
| 23 | macro_rules! singleton { | ||
| 24 | ($val:expr) => {{ | ||
| 25 | type T = impl Sized; | ||
| 26 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | ||
| 27 | let (x,) = STATIC_CELL.init(($val,)); | ||
| 28 | x | ||
| 29 | }}; | ||
| 30 | } | ||
| 31 | |||
| 17 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 32 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; |
| 18 | 33 | ||
| 19 | #[embassy_executor::task] | 34 | #[embassy_executor::task] |
| @@ -39,10 +54,9 @@ async fn main(spawner: Spawner) { | |||
| 39 | info!("Enabling ext hfosc..."); | 54 | info!("Enabling ext hfosc..."); |
| 40 | clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); | 55 | clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); |
| 41 | while clock.events_hfclkstarted.read().bits() != 1 {} | 56 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 57 | |||
| 42 | // Create the driver, from the HAL. | 58 | // Create the driver, from the HAL. |
| 43 | let irq = interrupt::take!(USBD); | 59 | let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); |
| 44 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 45 | let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||
| 46 | 60 | ||
| 47 | // Create embassy-usb Config | 61 | // Create embassy-usb Config |
| 48 | let mut config = Config::new(0xc0de, 0xcafe); | 62 | let mut config = Config::new(0xc0de, 0xcafe); |
| @@ -59,34 +73,21 @@ async fn main(spawner: Spawner) { | |||
| 59 | config.device_protocol = 0x01; | 73 | config.device_protocol = 0x01; |
| 60 | config.composite_with_iads = true; | 74 | config.composite_with_iads = true; |
| 61 | 75 | ||
| 62 | struct Resources { | 76 | let state = singleton!(State::new()); |
| 63 | device_descriptor: [u8; 256], | ||
| 64 | config_descriptor: [u8; 256], | ||
| 65 | bos_descriptor: [u8; 256], | ||
| 66 | control_buf: [u8; 64], | ||
| 67 | serial_state: State<'static>, | ||
| 68 | } | ||
| 69 | static RESOURCES: StaticCell<Resources> = StaticCell::new(); | ||
| 70 | let res = RESOURCES.init(Resources { | ||
| 71 | device_descriptor: [0; 256], | ||
| 72 | config_descriptor: [0; 256], | ||
| 73 | bos_descriptor: [0; 256], | ||
| 74 | control_buf: [0; 64], | ||
| 75 | serial_state: State::new(), | ||
| 76 | }); | ||
| 77 | 77 | ||
| 78 | // Create embassy-usb DeviceBuilder using the driver and config. | 78 | // Create embassy-usb DeviceBuilder using the driver and config. |
| 79 | let mut builder = Builder::new( | 79 | let mut builder = Builder::new( |
| 80 | driver, | 80 | driver, |
| 81 | config, | 81 | config, |
| 82 | &mut res.device_descriptor, | 82 | &mut singleton!([0; 256])[..], |
| 83 | &mut res.config_descriptor, | 83 | &mut singleton!([0; 256])[..], |
| 84 | &mut res.bos_descriptor, | 84 | &mut singleton!([0; 256])[..], |
| 85 | &mut res.control_buf, | 85 | &mut singleton!([0; 128])[..], |
| 86 | &mut singleton!([0; 128])[..], | ||
| 86 | ); | 87 | ); |
| 87 | 88 | ||
| 88 | // Create classes on the builder. | 89 | // Create classes on the builder. |
| 89 | let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); | 90 | let class = CdcAcmClass::new(&mut builder, state, 64); |
| 90 | 91 | ||
| 91 | // Build the builder. | 92 | // Build the builder. |
| 92 | let usb = builder.build(); | 93 | let usb = builder.build(); |
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 6561fc3b4..6e4f71a48 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs | |||
| @@ -7,8 +7,9 @@ use core::mem; | |||
| 7 | use defmt::{info, panic}; | 7 | use defmt::{info, panic}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 9 | use embassy_futures::join::join; |
| 10 | use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect}; | 10 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; |
| 11 | use embassy_nrf::{interrupt, pac}; | 11 | use embassy_nrf::usb::{Driver, Instance}; |
| 12 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | ||
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 13 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 14 | use embassy_usb::driver::EndpointError; |
| 14 | use embassy_usb::msos::{self, windows_version}; | 15 | use embassy_usb::msos::{self, windows_version}; |
| @@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber; | |||
| 16 | use embassy_usb::{Builder, Config}; | 17 | use embassy_usb::{Builder, Config}; |
| 17 | use {defmt_rtt as _, panic_probe as _}; | 18 | use {defmt_rtt as _, panic_probe as _}; |
| 18 | 19 | ||
| 20 | bind_interrupts!(struct Irqs { | ||
| 21 | USBD => usb::InterruptHandler<peripherals::USBD>; | ||
| 22 | POWER_CLOCK => usb::vbus_detect::InterruptHandler; | ||
| 23 | }); | ||
| 24 | |||
| 19 | // This is a randomly generated GUID to allow clients on Windows to find our device | 25 | // This is a randomly generated GUID to allow clients on Windows to find our device |
| 20 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; | 26 | const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; |
| 21 | 27 | ||
| @@ -29,9 +35,7 @@ async fn main(_spawner: Spawner) { | |||
| 29 | while clock.events_hfclkstarted.read().bits() != 1 {} | 35 | while clock.events_hfclkstarted.read().bits() != 1 {} |
| 30 | 36 | ||
| 31 | // Create the driver, from the HAL. | 37 | // Create the driver, from the HAL. |
| 32 | let irq = interrupt::take!(USBD); | 38 | let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); |
| 33 | let power_irq = interrupt::take!(POWER_CLOCK); | ||
| 34 | let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq)); | ||
| 35 | 39 | ||
| 36 | // Create embassy-usb Config | 40 | // Create embassy-usb Config |
| 37 | let mut config = Config::new(0xc0de, 0xcafe); | 41 | let mut config = Config::new(0xc0de, 0xcafe); |
