nrf/usb: switch to new interrupt binding, fix vbus detect on nrf53.
This commit is contained in:
parent
5913553cb1
commit
5249996d28
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
|
pub mod vbus_detect;
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
@ -15,7 +17,8 @@ use embassy_usb_driver as driver;
|
|||||||
use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
|
use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
|
||||||
use pac::usbd::RegisterBlock;
|
use pac::usbd::RegisterBlock;
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use self::vbus_detect::VbusDetect;
|
||||||
|
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||||
use crate::util::slice_in_ram;
|
use crate::util::slice_in_ram;
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
|||||||
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
||||||
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
/// Trait for detecting USB VBUS power.
|
/// Interrupt handler.
|
||||||
///
|
pub struct InterruptHandler<T: Instance> {
|
||||||
/// There are multiple ways to detect USB power. The behavior
|
_phantom: PhantomData<T>,
|
||||||
/// here provides a hook into determining whether it is.
|
|
||||||
pub trait VbusDetect {
|
|
||||||
/// Report whether power is detected.
|
|
||||||
///
|
|
||||||
/// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
|
|
||||||
/// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
|
||||||
fn is_usb_detected(&self) -> bool;
|
|
||||||
|
|
||||||
/// Wait until USB power is ready.
|
|
||||||
///
|
|
||||||
/// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
|
|
||||||
/// `USBPWRRDY` event from the `POWER` peripheral.
|
|
||||||
async fn wait_power_ready(&mut self) -> Result<(), ()>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
///
|
unsafe fn on_interrupt() {
|
||||||
/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
|
|
||||||
/// to POWER. In that case, use [`VbusDetectSignal`].
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
pub struct HardwareVbusDetect {
|
|
||||||
_private: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
static POWER_WAKER: AtomicWaker = NEW_AW;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
impl HardwareVbusDetect {
|
|
||||||
/// Create a new `VbusDetectNative`.
|
|
||||||
pub fn new(power_irq: impl Interrupt) -> Self {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
power_irq.set_handler(Self::on_interrupt);
|
|
||||||
power_irq.unpend();
|
|
||||||
power_irq.enable();
|
|
||||||
|
|
||||||
regs.intenset
|
|
||||||
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
|
||||||
|
|
||||||
Self { _private: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
fn on_interrupt(_: *mut ()) {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
if regs.events_usbdetected.read().bits() != 0 {
|
|
||||||
regs.events_usbdetected.reset();
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
if regs.events_usbremoved.read().bits() != 0 {
|
|
||||||
regs.events_usbremoved.reset();
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
if regs.events_usbpwrrdy.read().bits() != 0 {
|
|
||||||
regs.events_usbpwrrdy.reset();
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
impl VbusDetect for HardwareVbusDetect {
|
|
||||||
fn is_usb_detected(&self) -> bool {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
POWER_WAKER.register(cx.waker());
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
if regs.usbregstatus.read().outputrdy().is_ready() {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
} else if !self.is_usb_detected() {
|
|
||||||
Poll::Ready(Err(()))
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Software-backed [`VbusDetect`] implementation.
|
|
||||||
///
|
|
||||||
/// This implementation does not interact with the hardware, it allows user code
|
|
||||||
/// to notify the power events by calling functions instead.
|
|
||||||
///
|
|
||||||
/// This is suitable for use with the nRF softdevice, by calling the functions
|
|
||||||
/// when the softdevice reports power-related events.
|
|
||||||
pub struct SoftwareVbusDetect {
|
|
||||||
usb_detected: AtomicBool,
|
|
||||||
power_ready: AtomicBool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SoftwareVbusDetect {
|
|
||||||
/// Create a new `SoftwareVbusDetect`.
|
|
||||||
pub fn new(usb_detected: bool, power_ready: bool) -> Self {
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
usb_detected: AtomicBool::new(usb_detected),
|
|
||||||
power_ready: AtomicBool::new(power_ready),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report whether power was detected.
|
|
||||||
///
|
|
||||||
/// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
|
||||||
pub fn detected(&self, detected: bool) {
|
|
||||||
self.usb_detected.store(detected, Ordering::Relaxed);
|
|
||||||
self.power_ready.store(false, Ordering::Relaxed);
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report when USB power is ready.
|
|
||||||
///
|
|
||||||
/// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
|
|
||||||
pub fn ready(&self) {
|
|
||||||
self.power_ready.store(true, Ordering::Relaxed);
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VbusDetect for &SoftwareVbusDetect {
|
|
||||||
fn is_usb_detected(&self) -> bool {
|
|
||||||
self.usb_detected.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
POWER_WAKER.register(cx.waker());
|
|
||||||
|
|
||||||
if self.power_ready.load(Ordering::Relaxed) {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
} else if !self.usb_detected.load(Ordering::Relaxed) {
|
|
||||||
Poll::Ready(Err(()))
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// USB driver.
|
|
||||||
pub struct Driver<'d, T: Instance, P: VbusDetect> {
|
|
||||||
_p: PeripheralRef<'d, T>,
|
|
||||||
alloc_in: Allocator,
|
|
||||||
alloc_out: Allocator,
|
|
||||||
usb_supply: P,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
|
|
||||||
/// Create a new USB driver.
|
|
||||||
pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self {
|
|
||||||
into_ref!(usb, irq);
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
|
||||||
irq.unpend();
|
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
_p: usb,
|
|
||||||
alloc_in: Allocator::new(),
|
|
||||||
alloc_out: Allocator::new(),
|
|
||||||
usb_supply,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_interrupt(_: *mut ()) {
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
if regs.events_usbreset.read().bits() != 0 {
|
if regs.events_usbreset.read().bits() != 0 {
|
||||||
@ -255,11 +86,40 @@ impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> {
|
/// USB driver.
|
||||||
|
pub struct Driver<'d, T: Instance, V: VbusDetect> {
|
||||||
|
_p: PeripheralRef<'d, T>,
|
||||||
|
alloc_in: Allocator,
|
||||||
|
alloc_out: Allocator,
|
||||||
|
vbus_detect: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
|
||||||
|
/// Create a new USB driver.
|
||||||
|
pub fn new(
|
||||||
|
usb: impl Peripheral<P = T> + 'd,
|
||||||
|
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
vbus_detect: V,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(usb);
|
||||||
|
|
||||||
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
_p: usb,
|
||||||
|
alloc_in: Allocator::new(),
|
||||||
|
alloc_out: Allocator::new(),
|
||||||
|
vbus_detect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> {
|
||||||
type EndpointOut = Endpoint<'d, T, Out>;
|
type EndpointOut = Endpoint<'d, T, Out>;
|
||||||
type EndpointIn = Endpoint<'d, T, In>;
|
type EndpointIn = Endpoint<'d, T, In>;
|
||||||
type ControlPipe = ControlPipe<'d, T>;
|
type ControlPipe = ControlPipe<'d, T>;
|
||||||
type Bus = Bus<'d, T, P>;
|
type Bus = Bus<'d, T, V>;
|
||||||
|
|
||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
|||||||
Bus {
|
Bus {
|
||||||
_p: unsafe { self._p.clone_unchecked() },
|
_p: unsafe { self._p.clone_unchecked() },
|
||||||
power_available: false,
|
power_available: false,
|
||||||
usb_supply: self.usb_supply,
|
vbus_detect: self.vbus_detect,
|
||||||
},
|
},
|
||||||
ControlPipe {
|
ControlPipe {
|
||||||
_p: self._p,
|
_p: self._p,
|
||||||
@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// USB bus.
|
/// USB bus.
|
||||||
pub struct Bus<'d, T: Instance, P: VbusDetect> {
|
pub struct Bus<'d, T: Instance, V: VbusDetect> {
|
||||||
_p: PeripheralRef<'d, T>,
|
_p: PeripheralRef<'d, T>,
|
||||||
power_available: bool,
|
power_available: bool,
|
||||||
usb_supply: P,
|
vbus_detect: V,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||||
async fn enable(&mut self) {
|
async fn enable(&mut self) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
|||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.usb_supply.wait_power_ready().await.is_ok() {
|
if self.vbus_detect.wait_power_ready().await.is_ok() {
|
||||||
// Enable the USB pullup, allowing enumeration.
|
// Enable the USB pullup, allowing enumeration.
|
||||||
regs.usbpullup.write(|w| w.connect().enabled());
|
regs.usbpullup.write(|w| w.connect().enabled());
|
||||||
trace!("enabled");
|
trace!("enabled");
|
||||||
@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
|||||||
trace!("USB event: ready");
|
trace!("USB event: ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.usb_supply.is_usb_detected() != self.power_available {
|
if self.vbus_detect.is_usb_detected() != self.power_available {
|
||||||
self.power_available = !self.power_available;
|
self.power_available = !self.power_available;
|
||||||
if self.power_available {
|
if self.power_available {
|
||||||
trace!("Power event: available");
|
trace!("Power event: available");
|
177
embassy-nrf/src/usb/vbus_detect.rs
Normal file
177
embassy-nrf/src/usb/vbus_detect.rs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
//! Trait and implementations for performing VBUS detection.
|
||||||
|
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use super::BUS_WAKER;
|
||||||
|
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||||
|
use crate::pac;
|
||||||
|
|
||||||
|
/// Trait for detecting USB VBUS power.
|
||||||
|
///
|
||||||
|
/// There are multiple ways to detect USB power. The behavior
|
||||||
|
/// here provides a hook into determining whether it is.
|
||||||
|
pub trait VbusDetect {
|
||||||
|
/// Report whether power is detected.
|
||||||
|
///
|
||||||
|
/// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
|
||||||
|
/// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||||
|
fn is_usb_detected(&self) -> bool;
|
||||||
|
|
||||||
|
/// Wait until USB power is ready.
|
||||||
|
///
|
||||||
|
/// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
|
||||||
|
/// `USBPWRRDY` event from the `POWER` peripheral.
|
||||||
|
async fn wait_power_ready(&mut self) -> Result<(), ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "_nrf5340"))]
|
||||||
|
type UsbRegIrq = interrupt::POWER_CLOCK;
|
||||||
|
#[cfg(feature = "_nrf5340")]
|
||||||
|
type UsbRegIrq = interrupt::USBREGULATOR;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "_nrf5340"))]
|
||||||
|
type UsbRegPeri = pac::POWER;
|
||||||
|
#[cfg(feature = "_nrf5340")]
|
||||||
|
type UsbRegPeri = pac::USBREGULATOR;
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl interrupt::Handler<UsbRegIrq> for InterruptHandler {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
|
if regs.events_usbdetected.read().bits() != 0 {
|
||||||
|
regs.events_usbdetected.reset();
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
if regs.events_usbremoved.read().bits() != 0 {
|
||||||
|
regs.events_usbremoved.reset();
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
if regs.events_usbpwrrdy.read().bits() != 0 {
|
||||||
|
regs.events_usbpwrrdy.reset();
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
|
||||||
|
///
|
||||||
|
/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
|
||||||
|
/// to POWER. In that case, use [`VbusDetectSignal`].
|
||||||
|
pub struct HardwareVbusDetect {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
static POWER_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
|
impl HardwareVbusDetect {
|
||||||
|
/// Create a new `VbusDetectNative`.
|
||||||
|
pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
|
unsafe { UsbRegIrq::steal() }.unpend();
|
||||||
|
unsafe { UsbRegIrq::steal() }.enable();
|
||||||
|
|
||||||
|
regs.intenset
|
||||||
|
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
||||||
|
|
||||||
|
Self { _private: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VbusDetect for HardwareVbusDetect {
|
||||||
|
fn is_usb_detected(&self) -> bool {
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
POWER_WAKER.register(cx.waker());
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
|
if regs.usbregstatus.read().outputrdy().is_ready() {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else if !self.is_usb_detected() {
|
||||||
|
Poll::Ready(Err(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Software-backed [`VbusDetect`] implementation.
|
||||||
|
///
|
||||||
|
/// This implementation does not interact with the hardware, it allows user code
|
||||||
|
/// to notify the power events by calling functions instead.
|
||||||
|
///
|
||||||
|
/// This is suitable for use with the nRF softdevice, by calling the functions
|
||||||
|
/// when the softdevice reports power-related events.
|
||||||
|
pub struct SoftwareVbusDetect {
|
||||||
|
usb_detected: AtomicBool,
|
||||||
|
power_ready: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoftwareVbusDetect {
|
||||||
|
/// Create a new `SoftwareVbusDetect`.
|
||||||
|
pub fn new(usb_detected: bool, power_ready: bool) -> Self {
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
usb_detected: AtomicBool::new(usb_detected),
|
||||||
|
power_ready: AtomicBool::new(power_ready),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report whether power was detected.
|
||||||
|
///
|
||||||
|
/// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||||
|
pub fn detected(&self, detected: bool) {
|
||||||
|
self.usb_detected.store(detected, Ordering::Relaxed);
|
||||||
|
self.power_ready.store(false, Ordering::Relaxed);
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report when USB power is ready.
|
||||||
|
///
|
||||||
|
/// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
|
||||||
|
pub fn ready(&self) {
|
||||||
|
self.power_ready.store(true, Ordering::Relaxed);
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VbusDetect for &SoftwareVbusDetect {
|
||||||
|
fn is_usb_detected(&self) -> bool {
|
||||||
|
self.usb_detected.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
POWER_WAKER.register(cx.waker());
|
||||||
|
|
||||||
|
if self.power_ready.load(Ordering::Relaxed) {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else if !self.usb_detected.load(Ordering::Relaxed) {
|
||||||
|
Poll::Ready(Err(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["nightly"]
|
default = ["nightly"]
|
||||||
msos-descriptor = ["embassy-usb/msos-descriptor"]
|
|
||||||
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
|
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
|
||||||
"embassy-lora", "lorawan-device", "lorawan"]
|
"embassy-lora", "lorawan-device", "lorawan"]
|
||||||
|
|
||||||
@ -17,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
|||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
|
||||||
embedded-io = "0.4.0"
|
embedded-io = "0.4.0"
|
||||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
||||||
|
|
||||||
@ -36,7 +35,3 @@ rand = { version = "0.8.4", default-features = false }
|
|||||||
embedded-storage = "0.3.0"
|
embedded-storage = "0.3.0"
|
||||||
usbd-hid = "0.6.0"
|
usbd-hid = "0.6.0"
|
||||||
serde = { version = "1.0.136", default-features = false }
|
serde = { version = "1.0.136", default-features = false }
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "usb_serial_winusb"
|
|
||||||
required-features = ["msos-descriptor"]
|
|
||||||
|
@ -9,8 +9,9 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{Stack, StackResources};
|
use embassy_net::{Stack, StackResources};
|
||||||
use embassy_nrf::rng::Rng;
|
use embassy_nrf::rng::Rng;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{bind_interrupts, interrupt, pac, peripherals, rng};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb};
|
||||||
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
||||||
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
@ -19,6 +20,8 @@ use static_cell::StaticCell;
|
|||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,9 +63,7 @@ async fn main(spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -86,6 +87,7 @@ async fn main(spawner: Spawner) {
|
|||||||
&mut singleton!([0; 256])[..],
|
&mut singleton!([0; 256])[..],
|
||||||
&mut singleton!([0; 256])[..],
|
&mut singleton!([0; 256])[..],
|
||||||
&mut singleton!([0; 128])[..],
|
&mut singleton!([0; 128])[..],
|
||||||
|
&mut singleton!([0; 128])[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Our MAC addr.
|
// Our MAC addr.
|
||||||
|
@ -10,8 +10,9 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use embassy_nrf::gpio::{Input, Pin, Pull};
|
use embassy_nrf::gpio::{Input, Pin, Pull};
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::signal::Signal;
|
use embassy_sync::signal::Signal;
|
||||||
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
||||||
@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler};
|
|||||||
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
static SUSPENDED: AtomicBool = AtomicBool::new(false);
|
static SUSPENDED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut device_descriptor = [0; 256];
|
let mut device_descriptor = [0; 256];
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
let request_handler = MyRequestHandler {};
|
let request_handler = MyRequestHandler {};
|
||||||
let mut device_handler = MyDeviceHandler::new();
|
let mut device_handler = MyDeviceHandler::new();
|
||||||
@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut device_descriptor,
|
&mut device_descriptor,
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
|
&mut msos_descriptor,
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -7,8 +7,9 @@ use core::mem;
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
||||||
use embassy_usb::control::OutResponse;
|
use embassy_usb::control::OutResponse;
|
||||||
@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config};
|
|||||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut device_descriptor = [0; 256];
|
let mut device_descriptor = [0; 256];
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
let request_handler = MyRequestHandler {};
|
let request_handler = MyRequestHandler {};
|
||||||
|
|
||||||
@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut device_descriptor,
|
&mut device_descriptor,
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
|
&mut msos_descriptor,
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -7,13 +7,19 @@ use core::mem;
|
|||||||
use defmt::{info, panic};
|
use defmt::{info, panic};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::{Driver, Instance};
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut device_descriptor = [0; 256];
|
let mut device_descriptor = [0; 256];
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut device_descriptor,
|
&mut device_descriptor,
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
|
&mut msos_descriptor,
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -6,14 +6,29 @@ use core::mem;
|
|||||||
|
|
||||||
use defmt::{info, panic, unwrap};
|
use defmt::{info, panic, unwrap};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac, peripherals};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
macro_rules! singleton {
|
||||||
|
($val:expr) => {{
|
||||||
|
type T = impl Sized;
|
||||||
|
static STATIC_CELL: StaticCell<T> = StaticCell::new();
|
||||||
|
let (x,) = STATIC_CELL.init(($val,));
|
||||||
|
x
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
@ -39,10 +54,9 @@ async fn main(spawner: Spawner) {
|
|||||||
info!("Enabling ext hfosc...");
|
info!("Enabling ext hfosc...");
|
||||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -59,34 +73,21 @@ async fn main(spawner: Spawner) {
|
|||||||
config.device_protocol = 0x01;
|
config.device_protocol = 0x01;
|
||||||
config.composite_with_iads = true;
|
config.composite_with_iads = true;
|
||||||
|
|
||||||
struct Resources {
|
let state = singleton!(State::new());
|
||||||
device_descriptor: [u8; 256],
|
|
||||||
config_descriptor: [u8; 256],
|
|
||||||
bos_descriptor: [u8; 256],
|
|
||||||
control_buf: [u8; 64],
|
|
||||||
serial_state: State<'static>,
|
|
||||||
}
|
|
||||||
static RESOURCES: StaticCell<Resources> = StaticCell::new();
|
|
||||||
let res = RESOURCES.init(Resources {
|
|
||||||
device_descriptor: [0; 256],
|
|
||||||
config_descriptor: [0; 256],
|
|
||||||
bos_descriptor: [0; 256],
|
|
||||||
control_buf: [0; 64],
|
|
||||||
serial_state: State::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create embassy-usb DeviceBuilder using the driver and config.
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
driver,
|
driver,
|
||||||
config,
|
config,
|
||||||
&mut res.device_descriptor,
|
&mut singleton!([0; 256])[..],
|
||||||
&mut res.config_descriptor,
|
&mut singleton!([0; 256])[..],
|
||||||
&mut res.bos_descriptor,
|
&mut singleton!([0; 256])[..],
|
||||||
&mut res.control_buf,
|
&mut singleton!([0; 128])[..],
|
||||||
|
&mut singleton!([0; 128])[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create classes on the builder.
|
// Create classes on the builder.
|
||||||
let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64);
|
let class = CdcAcmClass::new(&mut builder, state, 64);
|
||||||
|
|
||||||
// Build the builder.
|
// Build the builder.
|
||||||
let usb = builder.build();
|
let usb = builder.build();
|
||||||
|
@ -7,8 +7,9 @@ use core::mem;
|
|||||||
use defmt::{info, panic};
|
use defmt::{info, panic};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::{Driver, Instance};
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::msos::{self, windows_version};
|
use embassy_usb::msos::{self, windows_version};
|
||||||
@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber;
|
|||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
// This is a randomly generated GUID to allow clients on Windows to find our device
|
// This is a randomly generated GUID to allow clients on Windows to find our device
|
||||||
const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
|
const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
|
||||||
|
|
||||||
@ -29,9 +35,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
|
Loading…
Reference in New Issue
Block a user