Merge pull request #1224 from embassy-rs/interrupt-binding
nrf: new interrupt binding traits/macro
This commit is contained in:
commit
18fe398673
@ -13,14 +13,44 @@ pub mod _export {
|
||||
pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare};
|
||||
}
|
||||
|
||||
/// Interrupt handler trait.
|
||||
///
|
||||
/// Drivers that need to handle interrupts implement this trait.
|
||||
/// The user must ensure `on_interrupt()` is called every time the interrupt fires.
|
||||
/// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
|
||||
pub trait Handler<I: Interrupt> {
|
||||
/// Interrupt handler function.
|
||||
///
|
||||
/// Must be called every time the `I` interrupt fires, synchronously from
|
||||
/// the interrupt handler context.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function must ONLY be called from the interrupt handler for `I`.
|
||||
unsafe fn on_interrupt();
|
||||
}
|
||||
|
||||
/// Compile-time assertion that an interrupt has been bound to a handler.
|
||||
///
|
||||
/// For the vast majority of cases, you should use the `bind_interrupts!`
|
||||
/// macro instead of writing `unsafe impl`s of this trait.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
|
||||
/// to be called every time the `I` interrupt fires.
|
||||
///
|
||||
/// This allows drivers to check bindings at compile-time.
|
||||
pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
|
||||
|
||||
/// Implementation detail, do not use outside embassy crates.
|
||||
#[doc(hidden)]
|
||||
pub struct Handler {
|
||||
pub struct DynHandler {
|
||||
pub func: AtomicPtr<()>,
|
||||
pub ctx: AtomicPtr<()>,
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
impl DynHandler {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
func: AtomicPtr::new(ptr::null_mut()),
|
||||
@ -51,7 +81,7 @@ pub unsafe trait Interrupt: Peripheral<P = Self> {
|
||||
|
||||
/// Implementation detail, do not use outside embassy crates.
|
||||
#[doc(hidden)]
|
||||
unsafe fn __handler(&self) -> &'static Handler;
|
||||
unsafe fn __handler(&self) -> &'static DynHandler;
|
||||
}
|
||||
|
||||
/// Represents additional behavior for all interrupts.
|
||||
|
@ -21,9 +21,9 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
||||
unsafe fn steal() -> Self {
|
||||
Self(())
|
||||
}
|
||||
unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::Handler {
|
||||
unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler {
|
||||
#[export_name = #name_handler]
|
||||
static HANDLER: ::embassy_cortex_m::interrupt::Handler = ::embassy_cortex_m::interrupt::Handler::new();
|
||||
static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new();
|
||||
&HANDLER
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
||||
pub unsafe extern "C" fn trampoline() {
|
||||
extern "C" {
|
||||
#[link_name = #name_handler]
|
||||
static HANDLER: interrupt::Handler;
|
||||
static HANDLER: interrupt::DynHandler;
|
||||
}
|
||||
|
||||
let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use core::cmp::min;
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::slice;
|
||||
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
|
||||
use core::task::Poll;
|
||||
@ -23,7 +24,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
|
||||
|
||||
use crate::gpio::sealed::Pin;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::interrupt::{self, InterruptExt};
|
||||
use crate::ppi::{
|
||||
self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
|
||||
};
|
||||
@ -71,211 +72,13 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
/// Buffered UARTE driver.
|
||||
pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
|
||||
_peri: PeripheralRef<'d, U>,
|
||||
timer: Timer<'d, T>,
|
||||
_ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
|
||||
_ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
|
||||
_ppi_group: PpiGroup<'d, AnyGroup>,
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<U: UarteInstance> {
|
||||
_phantom: PhantomData<U>,
|
||||
}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
/// Create a new BufferedUarte without hardware flow control.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `rx_buffer.len()` is odd.
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = U> + 'd,
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||
irq: impl Peripheral<P = U::Interrupt> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
rx_buffer: &'d mut [u8],
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> Self {
|
||||
into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group);
|
||||
Self::new_inner(
|
||||
uarte,
|
||||
timer,
|
||||
ppi_ch1.map_into(),
|
||||
ppi_ch2.map_into(),
|
||||
ppi_group.map_into(),
|
||||
irq,
|
||||
rxd.map_into(),
|
||||
txd.map_into(),
|
||||
None,
|
||||
None,
|
||||
config,
|
||||
rx_buffer,
|
||||
tx_buffer,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new BufferedUarte with hardware flow control (RTS/CTS)
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `rx_buffer.len()` is odd.
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = U> + 'd,
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||
irq: impl Peripheral<P = U::Interrupt> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
rx_buffer: &'d mut [u8],
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> Self {
|
||||
into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group);
|
||||
Self::new_inner(
|
||||
uarte,
|
||||
timer,
|
||||
ppi_ch1.map_into(),
|
||||
ppi_ch2.map_into(),
|
||||
ppi_group.map_into(),
|
||||
irq,
|
||||
rxd.map_into(),
|
||||
txd.map_into(),
|
||||
Some(cts.map_into()),
|
||||
Some(rts.map_into()),
|
||||
config,
|
||||
rx_buffer,
|
||||
tx_buffer,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = U> + 'd,
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
|
||||
ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
|
||||
ppi_group: PeripheralRef<'d, AnyGroup>,
|
||||
irq: impl Peripheral<P = U::Interrupt> + 'd,
|
||||
rxd: PeripheralRef<'d, AnyPin>,
|
||||
txd: PeripheralRef<'d, AnyPin>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
rx_buffer: &'d mut [u8],
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> Self {
|
||||
into_ref!(peri, timer, irq);
|
||||
|
||||
assert!(rx_buffer.len() % 2 == 0);
|
||||
|
||||
let r = U::regs();
|
||||
|
||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||
|
||||
txd.set_high();
|
||||
txd.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
}
|
||||
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &rts {
|
||||
pin.set_high();
|
||||
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
|
||||
// Initialize state
|
||||
let s = U::buffered_state();
|
||||
s.tx_count.store(0, Ordering::Relaxed);
|
||||
s.rx_bufs.store(0, Ordering::Relaxed);
|
||||
let len = tx_buffer.len();
|
||||
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
let len = rx_buffer.len();
|
||||
unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||
|
||||
// Configure
|
||||
r.config.write(|w| {
|
||||
w.hwfc().bit(false);
|
||||
w.parity().variant(config.parity);
|
||||
w
|
||||
});
|
||||
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
|
||||
|
||||
// clear errors
|
||||
let errors = r.errorsrc.read().bits();
|
||||
r.errorsrc.write(|w| unsafe { w.bits(errors) });
|
||||
|
||||
r.events_rxstarted.reset();
|
||||
r.events_txstarted.reset();
|
||||
r.events_error.reset();
|
||||
r.events_endrx.reset();
|
||||
r.events_endtx.reset();
|
||||
|
||||
// Enable interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(!0) });
|
||||
r.intenset.write(|w| {
|
||||
w.endtx().set();
|
||||
w.rxstarted().set();
|
||||
w.error().set();
|
||||
w
|
||||
});
|
||||
|
||||
// Enable UARTE instance
|
||||
apply_workaround_for_enable_anomaly(&r);
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
|
||||
// Configure byte counter.
|
||||
let mut timer = Timer::new_counter(timer);
|
||||
timer.cc(1).write(rx_buffer.len() as u32 * 2);
|
||||
timer.cc(1).short_compare_clear();
|
||||
timer.clear();
|
||||
timer.start();
|
||||
|
||||
let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count());
|
||||
ppi_ch1.enable();
|
||||
|
||||
s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed);
|
||||
let mut ppi_group = PpiGroup::new(ppi_group);
|
||||
let mut ppi_ch2 = Ppi::new_one_to_two(
|
||||
ppi_ch2,
|
||||
Event::from_reg(&r.events_endrx),
|
||||
Task::from_reg(&r.tasks_startrx),
|
||||
ppi_group.task_disable_all(),
|
||||
);
|
||||
ppi_ch2.disable();
|
||||
ppi_group.add_channel(&ppi_ch2);
|
||||
|
||||
irq.disable();
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.pend();
|
||||
irq.enable();
|
||||
|
||||
Self {
|
||||
_peri: peri,
|
||||
timer,
|
||||
_ppi_ch1: ppi_ch1,
|
||||
_ppi_ch2: ppi_ch2,
|
||||
_ppi_group: ppi_group,
|
||||
}
|
||||
}
|
||||
|
||||
fn pend_irq() {
|
||||
unsafe { <U::Interrupt as Interrupt>::steal() }.pend()
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> {
|
||||
unsafe fn on_interrupt() {
|
||||
//trace!("irq: start");
|
||||
let r = U::regs();
|
||||
let s = U::buffered_state();
|
||||
@ -374,6 +177,206 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
|
||||
//trace!("irq: end");
|
||||
}
|
||||
}
|
||||
|
||||
/// Buffered UARTE driver.
|
||||
pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
|
||||
_peri: PeripheralRef<'d, U>,
|
||||
timer: Timer<'d, T>,
|
||||
_ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
|
||||
_ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
|
||||
_ppi_group: PpiGroup<'d, AnyGroup>,
|
||||
}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
|
||||
|
||||
impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||
/// Create a new BufferedUarte without hardware flow control.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `rx_buffer.len()` is odd.
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = U> + 'd,
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||
_irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
rx_buffer: &'d mut [u8],
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> Self {
|
||||
into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group);
|
||||
Self::new_inner(
|
||||
uarte,
|
||||
timer,
|
||||
ppi_ch1.map_into(),
|
||||
ppi_ch2.map_into(),
|
||||
ppi_group.map_into(),
|
||||
rxd.map_into(),
|
||||
txd.map_into(),
|
||||
None,
|
||||
None,
|
||||
config,
|
||||
rx_buffer,
|
||||
tx_buffer,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new BufferedUarte with hardware flow control (RTS/CTS)
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `rx_buffer.len()` is odd.
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = U> + 'd,
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||
_irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
rx_buffer: &'d mut [u8],
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> Self {
|
||||
into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group);
|
||||
Self::new_inner(
|
||||
uarte,
|
||||
timer,
|
||||
ppi_ch1.map_into(),
|
||||
ppi_ch2.map_into(),
|
||||
ppi_group.map_into(),
|
||||
rxd.map_into(),
|
||||
txd.map_into(),
|
||||
Some(cts.map_into()),
|
||||
Some(rts.map_into()),
|
||||
config,
|
||||
rx_buffer,
|
||||
tx_buffer,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = U> + 'd,
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
|
||||
ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
|
||||
ppi_group: PeripheralRef<'d, AnyGroup>,
|
||||
rxd: PeripheralRef<'d, AnyPin>,
|
||||
txd: PeripheralRef<'d, AnyPin>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
rx_buffer: &'d mut [u8],
|
||||
tx_buffer: &'d mut [u8],
|
||||
) -> Self {
|
||||
into_ref!(peri, timer);
|
||||
|
||||
assert!(rx_buffer.len() % 2 == 0);
|
||||
|
||||
let r = U::regs();
|
||||
|
||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||
|
||||
txd.set_high();
|
||||
txd.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &cts {
|
||||
pin.conf().write(|w| w.input().connect().drive().h0h1());
|
||||
}
|
||||
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
||||
|
||||
if let Some(pin) = &rts {
|
||||
pin.set_high();
|
||||
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
|
||||
// Initialize state
|
||||
let s = U::buffered_state();
|
||||
s.tx_count.store(0, Ordering::Relaxed);
|
||||
s.rx_bufs.store(0, Ordering::Relaxed);
|
||||
let len = tx_buffer.len();
|
||||
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
let len = rx_buffer.len();
|
||||
unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||
|
||||
// Configure
|
||||
r.config.write(|w| {
|
||||
w.hwfc().bit(false);
|
||||
w.parity().variant(config.parity);
|
||||
w
|
||||
});
|
||||
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
|
||||
|
||||
// clear errors
|
||||
let errors = r.errorsrc.read().bits();
|
||||
r.errorsrc.write(|w| unsafe { w.bits(errors) });
|
||||
|
||||
r.events_rxstarted.reset();
|
||||
r.events_txstarted.reset();
|
||||
r.events_error.reset();
|
||||
r.events_endrx.reset();
|
||||
r.events_endtx.reset();
|
||||
|
||||
// Enable interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(!0) });
|
||||
r.intenset.write(|w| {
|
||||
w.endtx().set();
|
||||
w.rxstarted().set();
|
||||
w.error().set();
|
||||
w
|
||||
});
|
||||
|
||||
// Enable UARTE instance
|
||||
apply_workaround_for_enable_anomaly(&r);
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
|
||||
// Configure byte counter.
|
||||
let mut timer = Timer::new_counter(timer);
|
||||
timer.cc(1).write(rx_buffer.len() as u32 * 2);
|
||||
timer.cc(1).short_compare_clear();
|
||||
timer.clear();
|
||||
timer.start();
|
||||
|
||||
let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count());
|
||||
ppi_ch1.enable();
|
||||
|
||||
s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed);
|
||||
let mut ppi_group = PpiGroup::new(ppi_group);
|
||||
let mut ppi_ch2 = Ppi::new_one_to_two(
|
||||
ppi_ch2,
|
||||
Event::from_reg(&r.events_endrx),
|
||||
Task::from_reg(&r.tasks_startrx),
|
||||
ppi_group.task_disable_all(),
|
||||
);
|
||||
ppi_ch2.disable();
|
||||
ppi_group.add_channel(&ppi_ch2);
|
||||
|
||||
unsafe { U::Interrupt::steal() }.pend();
|
||||
unsafe { U::Interrupt::steal() }.enable();
|
||||
|
||||
Self {
|
||||
_peri: peri,
|
||||
timer,
|
||||
_ppi_ch1: ppi_ch1,
|
||||
_ppi_ch2: ppi_ch2,
|
||||
_ppi_group: ppi_group,
|
||||
}
|
||||
}
|
||||
|
||||
fn pend_irq() {
|
||||
unsafe { <U::Interrupt as Interrupt>::steal() }.pend()
|
||||
}
|
||||
|
||||
/// Adjust the baud rate to the provided value.
|
||||
pub fn set_baudrate(&mut self, baudrate: Baudrate) {
|
||||
|
@ -140,6 +140,10 @@ impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -148,6 +148,12 @@ impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_pwm!(PWM0, PWM0, PWM0);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -150,6 +150,12 @@ impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
|
||||
|
||||
impl_pwm!(PWM0, PWM0, PWM0);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -153,6 +153,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
impl_timer!(TIMER3, TIMER3, TIMER3, extended);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -146,6 +146,9 @@ embassy_hal_common::peripherals! {
|
||||
|
||||
// I2S
|
||||
I2S,
|
||||
|
||||
// PDM
|
||||
PDM,
|
||||
}
|
||||
|
||||
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
||||
@ -168,6 +171,12 @@ impl_pwm!(PWM0, PWM0, PWM0);
|
||||
impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -197,6 +197,12 @@ impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
impl_pwm!(PWM3, PWM3, PWM3);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -208,6 +208,12 @@ impl_timer!(TIMER4, TIMER4, TIMER4, extended);
|
||||
|
||||
impl_qspi!(QSPI, QSPI, QSPI);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -34,10 +34,10 @@ pub mod pac {
|
||||
nvmc_ns as nvmc,
|
||||
oscillators_ns as oscillators,
|
||||
p0_ns as p0,
|
||||
pdm0_ns as pdm0,
|
||||
pdm0_ns as pdm,
|
||||
power_ns as power,
|
||||
pwm0_ns as pwm0,
|
||||
qdec0_ns as qdec0,
|
||||
qdec0_ns as qdec,
|
||||
qspi_ns as qspi,
|
||||
regulators_ns as regulators,
|
||||
reset_ns as reset,
|
||||
@ -253,6 +253,13 @@ embassy_hal_common::peripherals! {
|
||||
// QSPI
|
||||
QSPI,
|
||||
|
||||
// PDM
|
||||
PDM0,
|
||||
|
||||
// QDEC
|
||||
QDEC0,
|
||||
QDEC1,
|
||||
|
||||
// GPIOTE
|
||||
GPIOTE_CH0,
|
||||
GPIOTE_CH1,
|
||||
@ -398,6 +405,11 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_qspi!(QSPI, QSPI, QSPI);
|
||||
|
||||
impl_pdm!(PDM0, PDM0, PDM0);
|
||||
|
||||
impl_qdec!(QDEC0, QDEC0, QDEC0);
|
||||
impl_qdec!(QDEC1, QDEC1, QDEC1);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
#[cfg(feature = "nfc-pins-as-gpio")]
|
||||
|
@ -127,6 +127,9 @@ embassy_hal_common::peripherals! {
|
||||
// SAADC
|
||||
SAADC,
|
||||
|
||||
// RNG
|
||||
RNG,
|
||||
|
||||
// PWM
|
||||
PWM0,
|
||||
PWM1,
|
||||
@ -252,6 +255,8 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -301,6 +301,8 @@ impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
impl_pwm!(PWM3, PWM3, PWM3);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -14,7 +14,7 @@ use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::Interrupt;
|
||||
use crate::interrupt::{self, Interrupt};
|
||||
use crate::pac::i2s::RegisterBlock;
|
||||
use crate::util::{slice_in_ram_or, slice_ptr_parts};
|
||||
use crate::{Peripheral, EASY_DMA_SIZE};
|
||||
@ -363,10 +363,39 @@ impl From<Channels> for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let device = Device::<T>::new();
|
||||
let s = T::state();
|
||||
|
||||
if device.is_tx_ptr_updated() {
|
||||
trace!("TX INT");
|
||||
s.tx_waker.wake();
|
||||
device.disable_tx_ptr_interrupt();
|
||||
}
|
||||
|
||||
if device.is_rx_ptr_updated() {
|
||||
trace!("RX INT");
|
||||
s.rx_waker.wake();
|
||||
device.disable_rx_ptr_interrupt();
|
||||
}
|
||||
|
||||
if device.is_stopped() {
|
||||
trace!("STOPPED INT");
|
||||
s.stop_waker.wake();
|
||||
device.disable_stopped_interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// I2S driver.
|
||||
pub struct I2S<'d, T: Instance> {
|
||||
i2s: PeripheralRef<'d, T>,
|
||||
irq: PeripheralRef<'d, T::Interrupt>,
|
||||
mck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
sck: PeripheralRef<'d, AnyPin>,
|
||||
lrck: PeripheralRef<'d, AnyPin>,
|
||||
@ -378,19 +407,18 @@ pub struct I2S<'d, T: Instance> {
|
||||
|
||||
impl<'d, T: Instance> I2S<'d, T> {
|
||||
/// Create a new I2S in master mode
|
||||
pub fn master(
|
||||
pub fn new_master(
|
||||
i2s: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
mck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
master_clock: MasterClock,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(i2s, irq, mck, sck, lrck);
|
||||
into_ref!(i2s, mck, sck, lrck);
|
||||
Self {
|
||||
i2s,
|
||||
irq,
|
||||
mck: Some(mck.map_into()),
|
||||
sck: sck.map_into(),
|
||||
lrck: lrck.map_into(),
|
||||
@ -402,17 +430,16 @@ impl<'d, T: Instance> I2S<'d, T> {
|
||||
}
|
||||
|
||||
/// Create a new I2S in slave mode
|
||||
pub fn slave(
|
||||
pub fn new_slave(
|
||||
i2s: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(i2s, irq, sck, lrck);
|
||||
into_ref!(i2s, sck, lrck);
|
||||
Self {
|
||||
i2s,
|
||||
irq,
|
||||
mck: None,
|
||||
sck: sck.map_into(),
|
||||
lrck: lrck.map_into(),
|
||||
@ -537,9 +564,8 @@ impl<'d, T: Instance> I2S<'d, T> {
|
||||
}
|
||||
|
||||
fn setup_interrupt(&self) {
|
||||
self.irq.set_handler(Self::on_interrupt);
|
||||
self.irq.unpend();
|
||||
self.irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let device = Device::<T>::new();
|
||||
device.disable_tx_ptr_interrupt();
|
||||
@ -555,29 +581,6 @@ impl<'d, T: Instance> I2S<'d, T> {
|
||||
device.enable_stopped_interrupt();
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let device = Device::<T>::new();
|
||||
let s = T::state();
|
||||
|
||||
if device.is_tx_ptr_updated() {
|
||||
trace!("TX INT");
|
||||
s.tx_waker.wake();
|
||||
device.disable_tx_ptr_interrupt();
|
||||
}
|
||||
|
||||
if device.is_rx_ptr_updated() {
|
||||
trace!("RX INT");
|
||||
s.rx_waker.wake();
|
||||
device.disable_rx_ptr_interrupt();
|
||||
}
|
||||
|
||||
if device.is_stopped() {
|
||||
trace!("STOPPED INT");
|
||||
s.stop_waker.wake();
|
||||
device.disable_stopped_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
async fn stop() {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
@ -1168,7 +1171,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
/// I2S peripehral instance.
|
||||
/// I2S peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
|
@ -47,19 +47,21 @@ pub mod nvmc;
|
||||
#[cfg(any(
|
||||
feature = "nrf52810",
|
||||
feature = "nrf52811",
|
||||
feature = "nrf52832",
|
||||
feature = "nrf52833",
|
||||
feature = "nrf52840",
|
||||
feature = "_nrf5340-app",
|
||||
feature = "_nrf9160"
|
||||
))]
|
||||
pub mod pdm;
|
||||
pub mod ppi;
|
||||
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod pwm;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
|
||||
pub mod qdec;
|
||||
#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
|
||||
pub mod qspi;
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
|
||||
pub mod rng;
|
||||
#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod saadc;
|
||||
@ -95,14 +97,39 @@ pub mod wdt;
|
||||
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
||||
mod chip;
|
||||
|
||||
pub use chip::EASY_DMA_SIZE;
|
||||
|
||||
pub mod interrupt {
|
||||
//! nRF interrupts for cortex-m devices.
|
||||
//! Interrupt definitions and macros to bind them.
|
||||
pub use cortex_m::interrupt::{CriticalSection, Mutex};
|
||||
pub use embassy_cortex_m::interrupt::*;
|
||||
pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
|
||||
|
||||
pub use crate::chip::irqs::*;
|
||||
|
||||
/// Macro to bind interrupts to handlers.
|
||||
///
|
||||
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
||||
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
||||
/// prove at compile-time that the right interrupts have been bound.
|
||||
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
|
||||
#[macro_export]
|
||||
macro_rules! bind_interrupts {
|
||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||
$vis struct $name;
|
||||
|
||||
$(
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn $irq() {
|
||||
$(
|
||||
<$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
|
||||
)*
|
||||
)*
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Reexports
|
||||
@ -111,7 +138,7 @@ pub mod interrupt {
|
||||
pub use chip::pac;
|
||||
#[cfg(not(feature = "unstable-pac"))]
|
||||
pub(crate) use chip::pac;
|
||||
pub use chip::{peripherals, Peripherals};
|
||||
pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
|
||||
pub use embassy_cortex_m::executor;
|
||||
pub use embassy_cortex_m::interrupt::_export::interrupt;
|
||||
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||
|
@ -1,25 +1,37 @@
|
||||
//! Pulse Density Modulation (PDM) mirophone driver.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures::future::poll_fn;
|
||||
|
||||
use crate::chip::EASY_DMA_SIZE;
|
||||
use crate::gpio::sealed::Pin;
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::{self, InterruptExt};
|
||||
use crate::peripherals::PDM;
|
||||
use crate::{pac, Peripheral};
|
||||
use crate::Peripheral;
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
T::regs().intenclr.write(|w| w.end().clear());
|
||||
T::state().waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
/// PDM microphone interface
|
||||
pub struct Pdm<'d> {
|
||||
irq: PeripheralRef<'d, interrupt::PDM>,
|
||||
phantom: PhantomData<&'d PDM>,
|
||||
pub struct Pdm<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// PDM error.
|
||||
@ -35,32 +47,30 @@ pub enum Error {
|
||||
NotRunning,
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
static DUMMY_BUFFER: [i16; 1] = [0; 1];
|
||||
|
||||
impl<'d> Pdm<'d> {
|
||||
impl<'d, T: Instance> Pdm<'d, T> {
|
||||
/// Create PDM driver
|
||||
pub fn new(
|
||||
pdm: impl Peripheral<P = PDM> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::PDM> + 'd,
|
||||
pdm: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
clk: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
din: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(clk, din);
|
||||
Self::new_inner(pdm, irq, clk.map_into(), din.map_into(), config)
|
||||
into_ref!(pdm, clk, din);
|
||||
Self::new_inner(pdm, clk.map_into(), din.map_into(), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
_pdm: impl Peripheral<P = PDM> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::PDM> + 'd,
|
||||
pdm: PeripheralRef<'d, T>,
|
||||
clk: PeripheralRef<'d, AnyPin>,
|
||||
din: PeripheralRef<'d, AnyPin>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(irq);
|
||||
into_ref!(pdm);
|
||||
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
// setup gpio pins
|
||||
din.conf().write(|w| w.input().set_bit());
|
||||
@ -84,26 +94,18 @@ impl<'d> Pdm<'d> {
|
||||
r.gainr.write(|w| w.gainr().default_gain());
|
||||
|
||||
// IRQ
|
||||
irq.disable();
|
||||
irq.set_handler(|_| {
|
||||
let r = Self::regs();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
WAKER.wake();
|
||||
});
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
r.enable.write(|w| w.enable().set_bit());
|
||||
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
irq,
|
||||
}
|
||||
Self { _peri: pdm }
|
||||
}
|
||||
|
||||
/// Start sampling microphon data into a dummy buffer
|
||||
/// Usefull to start the microphon and keep it active between recording samples
|
||||
pub async fn start(&mut self) {
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
// start dummy sampling because microphon needs some setup time
|
||||
r.sample
|
||||
@ -113,13 +115,13 @@ impl<'d> Pdm<'d> {
|
||||
.maxcnt
|
||||
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
|
||||
|
||||
r.tasks_start.write(|w| w.tasks_start().set_bit());
|
||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
/// Stop sampling microphon data inta a dummy buffer
|
||||
pub async fn stop(&mut self) {
|
||||
let r = Self::regs();
|
||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
||||
let r = T::regs();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
r.events_started.reset();
|
||||
}
|
||||
|
||||
@ -132,9 +134,9 @@ impl<'d> Pdm<'d> {
|
||||
return Err(Error::BufferTooLong);
|
||||
}
|
||||
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
if r.events_started.read().events_started().bit_is_clear() {
|
||||
if r.events_started.read().bits() == 0 {
|
||||
return Err(Error::NotRunning);
|
||||
}
|
||||
|
||||
@ -179,7 +181,7 @@ impl<'d> Pdm<'d> {
|
||||
}
|
||||
|
||||
async fn wait_for_sample() {
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
r.events_end.reset();
|
||||
r.intenset.write(|w| w.end().set());
|
||||
@ -187,8 +189,8 @@ impl<'d> Pdm<'d> {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
poll_fn(|cx| {
|
||||
WAKER.register(cx.waker());
|
||||
if r.events_end.read().events_end().bit_is_set() {
|
||||
T::state().waker.register(cx.waker());
|
||||
if r.events_end.read().bits() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Pending
|
||||
@ -197,10 +199,6 @@ impl<'d> Pdm<'d> {
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::pdm::RegisterBlock {
|
||||
unsafe { &*pac::PDM::ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
/// PDM microphone driver Config
|
||||
@ -238,13 +236,11 @@ pub enum Edge {
|
||||
LeftFalling,
|
||||
}
|
||||
|
||||
impl<'d> Drop for Pdm<'d> {
|
||||
impl<'d, T: Instance> Drop for Pdm<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
||||
|
||||
self.irq.disable();
|
||||
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
|
||||
@ -252,3 +248,48 @@ impl<'d> Drop for Pdm<'d> {
|
||||
r.psel.clk.reset();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static crate::pac::pdm::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// PDM peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
macro_rules! impl_pdm {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::pdm::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::pdm::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::pdm::sealed::State {
|
||||
static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new();
|
||||
&STATE
|
||||
}
|
||||
}
|
||||
impl crate::pdm::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,20 +1,22 @@
|
||||
//! Quadrature decoder (QDEC) driver.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::QDEC;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
/// Quadrature decoder driver.
|
||||
pub struct Qdec<'d> {
|
||||
_p: PeripheralRef<'d, QDEC>,
|
||||
pub struct Qdec<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// QDEC config
|
||||
@ -44,44 +46,52 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'d> Qdec<'d> {
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
T::regs().intenclr.write(|w| w.reportrdy().clear());
|
||||
T::state().waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Qdec<'d, T> {
|
||||
/// Create a new QDEC.
|
||||
pub fn new(
|
||||
qdec: impl Peripheral<P = QDEC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
||||
qdec: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(a, b);
|
||||
Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config)
|
||||
into_ref!(qdec, a, b);
|
||||
Self::new_inner(qdec, a.map_into(), b.map_into(), None, config)
|
||||
}
|
||||
|
||||
/// Create a new QDEC, with a pin for LED output.
|
||||
pub fn new_with_led(
|
||||
qdec: impl Peripheral<P = QDEC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
||||
qdec: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
led: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(a, b, led);
|
||||
Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config)
|
||||
into_ref!(qdec, a, b, led);
|
||||
Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
p: impl Peripheral<P = QDEC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
||||
p: PeripheralRef<'d, T>,
|
||||
a: PeripheralRef<'d, AnyPin>,
|
||||
b: PeripheralRef<'d, AnyPin>,
|
||||
led: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(p, irq);
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
// Select pins.
|
||||
a.conf().write(|w| w.input().connect().pull().pullup());
|
||||
@ -124,20 +134,15 @@ impl<'d> Qdec<'d> {
|
||||
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
||||
});
|
||||
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
// Enable peripheral
|
||||
r.enable.write(|w| w.enable().set_bit());
|
||||
|
||||
// Start sampling
|
||||
unsafe { r.tasks_start.write(|w| w.bits(1)) };
|
||||
|
||||
irq.disable();
|
||||
irq.set_handler(|_| {
|
||||
let r = Self::regs();
|
||||
r.intenclr.write(|w| w.reportrdy().clear());
|
||||
WAKER.wake();
|
||||
});
|
||||
irq.enable();
|
||||
|
||||
Self { _p: p }
|
||||
}
|
||||
|
||||
@ -155,12 +160,12 @@ impl<'d> Qdec<'d> {
|
||||
/// let delta = q.read().await;
|
||||
/// ```
|
||||
pub async fn read(&mut self) -> i16 {
|
||||
let t = Self::regs();
|
||||
let t = T::regs();
|
||||
t.intenset.write(|w| w.reportrdy().set());
|
||||
unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
|
||||
|
||||
let value = poll_fn(|cx| {
|
||||
WAKER.register(cx.waker());
|
||||
T::state().waker.register(cx.waker());
|
||||
if t.events_reportrdy.read().bits() == 0 {
|
||||
return Poll::Pending;
|
||||
} else {
|
||||
@ -172,10 +177,6 @@ impl<'d> Qdec<'d> {
|
||||
.await;
|
||||
value
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::qdec::RegisterBlock {
|
||||
unsafe { &*pac::QDEC::ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample period
|
||||
@ -236,3 +237,48 @@ pub enum LedPolarity {
|
||||
/// Active low (a low output turns on the LED).
|
||||
ActiveLow,
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static crate::pac::qdec::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// qdec peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
macro_rules! impl_qdec {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::qdec::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::qdec::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::qdec::sealed::State {
|
||||
static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new();
|
||||
&STATE
|
||||
}
|
||||
}
|
||||
impl crate::qdec::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::task::Poll;
|
||||
|
||||
@ -11,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
|
||||
|
||||
use crate::gpio::{self, Pin as GpioPin};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
pub use crate::pac::qspi::ifconfig0::{
|
||||
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
||||
};
|
||||
pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
|
||||
use crate::{pac, Peripheral};
|
||||
use crate::Peripheral;
|
||||
|
||||
/// Deep power-down config.
|
||||
pub struct DeepPowerDownConfig {
|
||||
@ -114,9 +115,26 @@ pub enum Error {
|
||||
// TODO add "not in data memory" error and check for it
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.ready().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// QSPI flash driver.
|
||||
pub struct Qspi<'d, T: Instance> {
|
||||
irq: PeripheralRef<'d, T::Interrupt>,
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
dpm_enabled: bool,
|
||||
capacity: u32,
|
||||
}
|
||||
@ -124,8 +142,8 @@ pub struct Qspi<'d, T: Instance> {
|
||||
impl<'d, T: Instance> Qspi<'d, T> {
|
||||
/// Create a new QSPI driver.
|
||||
pub fn new(
|
||||
_qspi: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
qspi: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
csn: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
io0: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -134,7 +152,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
io3: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(irq, sck, csn, io0, io1, io2, io3);
|
||||
into_ref!(qspi, sck, csn, io0, io1, io2, io3);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -189,16 +207,15 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
w
|
||||
});
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
// Enable it
|
||||
r.enable.write(|w| w.enable().enabled());
|
||||
|
||||
let res = Self {
|
||||
_peri: qspi,
|
||||
dpm_enabled: config.deep_power_down.is_some(),
|
||||
irq,
|
||||
capacity: config.capacity,
|
||||
};
|
||||
|
||||
@ -212,16 +229,6 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
res
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
s.ready_waker.wake();
|
||||
r.intenclr.write(|w| w.ready().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Do a custom QSPI instruction.
|
||||
pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
|
||||
let ondrop = OnDrop::new(Self::blocking_wait_ready);
|
||||
@ -310,7 +317,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
poll_fn(move |cx| {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
s.ready_waker.register(cx.waker());
|
||||
s.waker.register(cx.waker());
|
||||
if r.events_ready.read().bits() != 0 {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
@ -525,8 +532,6 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
|
||||
|
||||
r.enable.write(|w| w.enable().disabled());
|
||||
|
||||
self.irq.disable();
|
||||
|
||||
// Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
|
||||
// leaving it floating, the flash chip might read it as zero which would cause it to
|
||||
// spuriously exit DPM.
|
||||
@ -624,27 +629,27 @@ mod _eh1 {
|
||||
pub(crate) mod sealed {
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub ready_waker: AtomicWaker,
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ready_waker: AtomicWaker::new(),
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static pac::qspi::RegisterBlock;
|
||||
fn regs() -> &'static crate::pac::qspi::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// QSPI peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
@ -652,7 +657,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||
macro_rules! impl_qspi {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::qspi::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static pac::qspi::RegisterBlock {
|
||||
fn regs() -> &'static crate::pac::qspi::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::qspi::sealed::State {
|
||||
|
@ -1,83 +1,48 @@
|
||||
//! Random Number Generator (RNG) driver.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::RNG;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
impl RNG {
|
||||
fn regs() -> &'static pac::rng::RegisterBlock {
|
||||
unsafe { &*pac::RNG::ptr() }
|
||||
}
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
static STATE: State = State {
|
||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
||||
end: AtomicPtr::new(ptr::null_mut()),
|
||||
waker: AtomicWaker::new(),
|
||||
};
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let s = T::state();
|
||||
let r = T::regs();
|
||||
|
||||
struct State {
|
||||
ptr: AtomicPtr<u8>,
|
||||
end: AtomicPtr<u8>,
|
||||
waker: AtomicWaker,
|
||||
}
|
||||
|
||||
/// A wrapper around an nRF RNG peripheral.
|
||||
///
|
||||
/// It has a non-blocking API, and a blocking api through `rand`.
|
||||
pub struct Rng<'d> {
|
||||
irq: PeripheralRef<'d, interrupt::RNG>,
|
||||
}
|
||||
|
||||
impl<'d> Rng<'d> {
|
||||
/// Creates a new RNG driver from the `RNG` peripheral and interrupt.
|
||||
///
|
||||
/// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
|
||||
/// e.g. using `mem::forget`.
|
||||
///
|
||||
/// The synchronous API is safe.
|
||||
pub fn new(_rng: impl Peripheral<P = RNG> + 'd, irq: impl Peripheral<P = interrupt::RNG> + 'd) -> Self {
|
||||
into_ref!(irq);
|
||||
|
||||
let this = Self { irq };
|
||||
|
||||
this.stop();
|
||||
this.disable_irq();
|
||||
|
||||
this.irq.set_handler(Self::on_interrupt);
|
||||
this.irq.unpend();
|
||||
this.irq.enable();
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
// Clear the event.
|
||||
RNG::regs().events_valrdy.reset();
|
||||
r.events_valrdy.reset();
|
||||
|
||||
// Mutate the slice within a critical section,
|
||||
// so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
|
||||
let (ptr, end) = critical_section::with(|_| {
|
||||
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
||||
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||
// We need to make sure we haven't already filled the whole slice,
|
||||
// in case the interrupt fired again before the executor got back to the future.
|
||||
let end = STATE.end.load(Ordering::Relaxed);
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
if !ptr.is_null() && ptr != end {
|
||||
// If the future was dropped, the pointer would have been set to null,
|
||||
// so we're still good to mutate the slice.
|
||||
// The safety contract of `Rng::new` means that the future can't have been dropped
|
||||
// without calling its destructor.
|
||||
unsafe {
|
||||
*ptr = RNG::regs().value.read().value().bits();
|
||||
*ptr = r.value.read().value().bits();
|
||||
}
|
||||
}
|
||||
(ptr, end)
|
||||
@ -90,15 +55,15 @@ impl<'d> Rng<'d> {
|
||||
}
|
||||
|
||||
let new_ptr = unsafe { ptr.add(1) };
|
||||
match STATE
|
||||
match s
|
||||
.ptr
|
||||
.compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
|
||||
{
|
||||
Ok(_) => {
|
||||
let end = STATE.end.load(Ordering::Relaxed);
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
// It doesn't matter if `end` was changed under our feet, because then this will just be false.
|
||||
if new_ptr == end {
|
||||
STATE.waker.wake();
|
||||
s.waker.wake();
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
@ -107,21 +72,53 @@ impl<'d> Rng<'d> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around an nRF RNG peripheral.
|
||||
///
|
||||
/// It has a non-blocking API, and a blocking api through `rand`.
|
||||
pub struct Rng<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Rng<'d, T> {
|
||||
/// Creates a new RNG driver from the `RNG` peripheral and interrupt.
|
||||
///
|
||||
/// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
|
||||
/// e.g. using `mem::forget`.
|
||||
///
|
||||
/// The synchronous API is safe.
|
||||
pub fn new(
|
||||
rng: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(rng);
|
||||
|
||||
let this = Self { _peri: rng };
|
||||
|
||||
this.stop();
|
||||
this.disable_irq();
|
||||
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
RNG::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
|
||||
}
|
||||
|
||||
fn start(&self) {
|
||||
RNG::regs().tasks_start.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
|
||||
}
|
||||
|
||||
fn enable_irq(&self) {
|
||||
RNG::regs().intenset.write(|w| w.valrdy().set());
|
||||
T::regs().intenset.write(|w| w.valrdy().set());
|
||||
}
|
||||
|
||||
fn disable_irq(&self) {
|
||||
RNG::regs().intenclr.write(|w| w.valrdy().clear());
|
||||
T::regs().intenclr.write(|w| w.valrdy().clear());
|
||||
}
|
||||
|
||||
/// Enable or disable the RNG's bias correction.
|
||||
@ -131,7 +128,7 @@ impl<'d> Rng<'d> {
|
||||
///
|
||||
/// Defaults to disabled.
|
||||
pub fn set_bias_correction(&self, enable: bool) {
|
||||
RNG::regs().config.write(|w| w.dercen().bit(enable))
|
||||
T::regs().config.write(|w| w.dercen().bit(enable))
|
||||
}
|
||||
|
||||
/// Fill the buffer with random bytes.
|
||||
@ -140,11 +137,13 @@ impl<'d> Rng<'d> {
|
||||
return; // Nothing to fill
|
||||
}
|
||||
|
||||
let s = T::state();
|
||||
|
||||
let range = dest.as_mut_ptr_range();
|
||||
// Even if we've preempted the interrupt, it can't preempt us again,
|
||||
// so we don't need to worry about the order we write these in.
|
||||
STATE.ptr.store(range.start, Ordering::Relaxed);
|
||||
STATE.end.store(range.end, Ordering::Relaxed);
|
||||
s.ptr.store(range.start, Ordering::Relaxed);
|
||||
s.end.store(range.end, Ordering::Relaxed);
|
||||
|
||||
self.enable_irq();
|
||||
self.start();
|
||||
@ -154,16 +153,16 @@ impl<'d> Rng<'d> {
|
||||
self.disable_irq();
|
||||
|
||||
// The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
|
||||
STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
STATE.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
STATE.waker.register(cx.waker());
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
// The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
|
||||
let end = STATE.end.load(Ordering::Relaxed);
|
||||
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||
|
||||
if ptr == end {
|
||||
// We're done.
|
||||
@ -183,7 +182,7 @@ impl<'d> Rng<'d> {
|
||||
self.start();
|
||||
|
||||
for byte in dest.iter_mut() {
|
||||
let regs = RNG::regs();
|
||||
let regs = T::regs();
|
||||
while regs.events_valrdy.read().bits() == 0 {}
|
||||
regs.events_valrdy.reset();
|
||||
*byte = regs.value.read().value().bits();
|
||||
@ -193,13 +192,16 @@ impl<'d> Rng<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for Rng<'d> {
|
||||
impl<'d, T: Instance> Drop for Rng<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
self.irq.disable()
|
||||
self.stop();
|
||||
let s = T::state();
|
||||
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> rand_core::RngCore for Rng<'d> {
|
||||
impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
self.blocking_fill_bytes(dest);
|
||||
}
|
||||
@ -223,4 +225,53 @@ impl<'d> rand_core::RngCore for Rng<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> rand_core::CryptoRng for Rng<'d> {}
|
||||
impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub ptr: AtomicPtr<u8>,
|
||||
pub end: AtomicPtr<u8>,
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
||||
end: AtomicPtr::new(ptr::null_mut()),
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static crate::pac::rng::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// RNG peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
macro_rules! impl_rng {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::rng::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::rng::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::rng::sealed::State {
|
||||
static STATE: crate::rng::sealed::State = crate::rng::sealed::State::new();
|
||||
&STATE
|
||||
}
|
||||
}
|
||||
impl crate::rng::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use core::future::poll_fn;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
@ -17,7 +18,6 @@ use saadc::oversample::OVERSAMPLE_A;
|
||||
use saadc::resolution::VAL_A;
|
||||
|
||||
use self::sealed::Input as _;
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
@ -28,9 +28,30 @@ use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
#[non_exhaustive]
|
||||
pub enum Error {}
|
||||
|
||||
/// One-shot and continuous SAADC.
|
||||
pub struct Saadc<'d, const N: usize> {
|
||||
_p: PeripheralRef<'d, peripherals::SAADC>,
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl interrupt::Handler<interrupt::SAADC> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = unsafe { &*SAADC::ptr() };
|
||||
|
||||
if r.events_calibratedone.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.calibratedone().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
@ -114,15 +135,20 @@ pub enum CallbackResult {
|
||||
Stop,
|
||||
}
|
||||
|
||||
/// One-shot and continuous SAADC.
|
||||
pub struct Saadc<'d, const N: usize> {
|
||||
_p: PeripheralRef<'d, peripherals::SAADC>,
|
||||
}
|
||||
|
||||
impl<'d, const N: usize> Saadc<'d, N> {
|
||||
/// Create a new SAADC driver.
|
||||
pub fn new(
|
||||
saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::SAADC> + 'd,
|
||||
_irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd,
|
||||
config: Config,
|
||||
channel_configs: [ChannelConfig; N],
|
||||
) -> Self {
|
||||
into_ref!(saadc, irq);
|
||||
into_ref!(saadc);
|
||||
|
||||
let r = unsafe { &*SAADC::ptr() };
|
||||
|
||||
@ -163,32 +189,12 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { interrupt::SAADC::steal() }.unpend();
|
||||
unsafe { interrupt::SAADC::steal() }.enable();
|
||||
|
||||
Self { _p: saadc }
|
||||
}
|
||||
|
||||
fn on_interrupt(_ctx: *mut ()) {
|
||||
let r = Self::regs();
|
||||
|
||||
if r.events_calibratedone.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.calibratedone().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
|
||||
fn regs() -> &'static saadc::RegisterBlock {
|
||||
unsafe { &*SAADC::ptr() }
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
||||
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -31,11 +32,6 @@ pub enum Error {
|
||||
BufferNotInRAM,
|
||||
}
|
||||
|
||||
/// SPIM driver.
|
||||
pub struct Spim<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// SPIM configuration.
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
@ -62,11 +58,33 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SPIM driver.
|
||||
pub struct Spim<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Spim<'d, T> {
|
||||
/// Create a new SPIM driver.
|
||||
pub fn new(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -75,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
into_ref!(sck, miso, mosi);
|
||||
Self::new_inner(
|
||||
spim,
|
||||
irq,
|
||||
sck.map_into(),
|
||||
Some(miso.map_into()),
|
||||
Some(mosi.map_into()),
|
||||
@ -86,36 +103,35 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
/// Create a new SPIM driver, capable of TX only (MOSI only).
|
||||
pub fn new_txonly(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, mosi);
|
||||
Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config)
|
||||
Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config)
|
||||
}
|
||||
|
||||
/// Create a new SPIM driver, capable of RX only (MISO only).
|
||||
pub fn new_rxonly(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, miso);
|
||||
Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config)
|
||||
Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
sck: PeripheralRef<'d, AnyPin>,
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(spim, irq);
|
||||
into_ref!(spim);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: spim }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#![macro_use]
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -12,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
|
||||
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -29,11 +30,6 @@ pub enum Error {
|
||||
BufferNotInRAM,
|
||||
}
|
||||
|
||||
/// SPIS driver.
|
||||
pub struct Spis<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// SPIS configuration.
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
@ -67,11 +63,38 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
|
||||
if r.events_acquired.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.acquired().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SPIS driver.
|
||||
pub struct Spis<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Spis<'d, T> {
|
||||
/// Create a new SPIS driver.
|
||||
pub fn new(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -81,7 +104,6 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
into_ref!(cs, sck, miso, mosi);
|
||||
Self::new_inner(
|
||||
spis,
|
||||
irq,
|
||||
cs.map_into(),
|
||||
sck.map_into(),
|
||||
Some(miso.map_into()),
|
||||
@ -93,48 +115,31 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
/// Create a new SPIS driver, capable of TX only (MISO only).
|
||||
pub fn new_txonly(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(cs, sck, miso);
|
||||
Self::new_inner(
|
||||
spis,
|
||||
irq,
|
||||
cs.map_into(),
|
||||
sck.map_into(),
|
||||
Some(miso.map_into()),
|
||||
None,
|
||||
config,
|
||||
)
|
||||
Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config)
|
||||
}
|
||||
|
||||
/// Create a new SPIS driver, capable of RX only (MOSI only).
|
||||
pub fn new_rxonly(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(cs, sck, mosi);
|
||||
Self::new_inner(
|
||||
spis,
|
||||
irq,
|
||||
cs.map_into(),
|
||||
sck.map_into(),
|
||||
None,
|
||||
Some(mosi.map_into()),
|
||||
config,
|
||||
)
|
||||
Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
cs: PeripheralRef<'d, AnyPin>,
|
||||
sck: PeripheralRef<'d, AnyPin>,
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
@ -143,7 +148,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
) -> Self {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
into_ref!(spis, irq, cs, sck);
|
||||
into_ref!(spis, cs, sck);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -209,28 +214,12 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
// Disable all events interrupts.
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: spis }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
|
||||
if r.events_acquired.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.acquired().clear());
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||
|
@ -3,6 +3,7 @@
|
||||
use core::future::poll_fn;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
@ -12,27 +13,39 @@ use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::TEMP;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl interrupt::Handler<interrupt::TEMP> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = unsafe { &*pac::TEMP::PTR };
|
||||
r.intenclr.write(|w| w.datardy().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
|
||||
/// Builtin temperature sensor driver.
|
||||
pub struct Temp<'d> {
|
||||
_irq: PeripheralRef<'d, interrupt::TEMP>,
|
||||
_peri: PeripheralRef<'d, TEMP>,
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
impl<'d> Temp<'d> {
|
||||
/// Create a new temperature sensor driver.
|
||||
pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self {
|
||||
into_ref!(_t, irq);
|
||||
pub fn new(
|
||||
_peri: impl Peripheral<P = TEMP> + 'd,
|
||||
_irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(_peri);
|
||||
|
||||
// Enable interrupt that signals temperature values
|
||||
irq.disable();
|
||||
irq.set_handler(|_| {
|
||||
let t = Self::regs();
|
||||
t.intenclr.write(|w| w.datardy().clear());
|
||||
WAKER.wake();
|
||||
});
|
||||
irq.enable();
|
||||
Self { _irq: irq }
|
||||
unsafe { interrupt::TEMP::steal() }.unpend();
|
||||
unsafe { interrupt::TEMP::steal() }.enable();
|
||||
|
||||
Self { _peri }
|
||||
}
|
||||
|
||||
/// Perform an asynchronous temperature measurement. The returned future
|
||||
|
@ -6,15 +6,9 @@
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::Interrupt;
|
||||
use crate::ppi::{Event, Task};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -26,8 +20,6 @@ pub(crate) mod sealed {
|
||||
/// The number of CC registers this instance has.
|
||||
const CCS: usize;
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock;
|
||||
/// Storage for the waker for CC register `n`.
|
||||
fn waker(n: usize) -> &'static AtomicWaker;
|
||||
}
|
||||
pub trait ExtendedInstance {}
|
||||
|
||||
@ -50,12 +42,6 @@ macro_rules! impl_timer {
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock {
|
||||
unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
|
||||
}
|
||||
fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker {
|
||||
use ::embassy_sync::waitqueue::AtomicWaker;
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs];
|
||||
&WAKERS[n]
|
||||
}
|
||||
}
|
||||
impl crate::timer::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
@ -99,59 +85,18 @@ pub enum Frequency {
|
||||
/// nRF Timer driver.
|
||||
///
|
||||
/// The timer has an internal counter, which is incremented for every tick of the timer.
|
||||
/// The counter is 32-bit, so it wraps back to 0 at 4294967296.
|
||||
/// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32.
|
||||
///
|
||||
/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
|
||||
/// or trigger an event when the counter reaches a certain value.
|
||||
|
||||
pub trait TimerType: sealed::TimerType {}
|
||||
|
||||
/// Marker type indicating the timer driver can await expiration (it owns the timer interrupt).
|
||||
pub enum Awaitable {}
|
||||
|
||||
/// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt).
|
||||
pub enum NotAwaitable {}
|
||||
|
||||
impl sealed::TimerType for Awaitable {}
|
||||
impl sealed::TimerType for NotAwaitable {}
|
||||
impl TimerType for Awaitable {}
|
||||
impl TimerType for NotAwaitable {}
|
||||
|
||||
/// Timer driver.
|
||||
pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> {
|
||||
pub struct Timer<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
_i: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Timer<'d, T, Awaitable> {
|
||||
/// Create a new async-capable timer driver.
|
||||
pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self {
|
||||
into_ref!(irq);
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
|
||||
Self::new_inner(timer, false)
|
||||
}
|
||||
|
||||
/// Create a new async-capable timer driver in counter mode.
|
||||
pub fn new_awaitable_counter(
|
||||
timer: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(irq);
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
|
||||
Self::new_inner(timer, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Timer<'d, T, NotAwaitable> {
|
||||
/// Create a `Timer` driver without an interrupt, meaning `Cc::wait` won't work.
|
||||
impl<'d, T: Instance> Timer<'d, T> {
|
||||
/// Create a new `Timer` driver.
|
||||
///
|
||||
/// This can be useful for triggering tasks via PPI
|
||||
/// `Uarte` uses this internally.
|
||||
@ -159,28 +104,20 @@ impl<'d, T: Instance> Timer<'d, T, NotAwaitable> {
|
||||
Self::new_inner(timer, false)
|
||||
}
|
||||
|
||||
/// Create a `Timer` driver in counter mode without an interrupt, meaning `Cc::wait` won't work.
|
||||
/// Create a new `Timer` driver in counter mode.
|
||||
///
|
||||
/// This can be useful for triggering tasks via PPI
|
||||
/// `Uarte` uses this internally.
|
||||
pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self {
|
||||
Self::new_inner(timer, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
|
||||
/// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
|
||||
///
|
||||
/// This is used by the public constructors.
|
||||
fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self {
|
||||
into_ref!(timer);
|
||||
|
||||
let regs = T::regs();
|
||||
|
||||
let mut this = Self {
|
||||
_p: timer,
|
||||
_i: PhantomData,
|
||||
};
|
||||
let mut this = Self { _p: timer };
|
||||
|
||||
// Stop the timer before doing anything else,
|
||||
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
|
||||
@ -272,31 +209,17 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
|
||||
.write(|w| unsafe { w.prescaler().bits(frequency as u8) })
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let regs = T::regs();
|
||||
for n in 0..T::CCS {
|
||||
if regs.events_compare[n].read().bits() != 0 {
|
||||
// Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits.
|
||||
// We can't clear the event, because it's used to poll whether the future is done or still pending.
|
||||
regs.intenclr
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) });
|
||||
T::waker(n).wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this timer's `n`th CC register.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
|
||||
pub fn cc(&mut self, n: usize) -> Cc<T, I> {
|
||||
pub fn cc(&mut self, n: usize) -> Cc<T> {
|
||||
if n >= T::CCS {
|
||||
panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS);
|
||||
}
|
||||
Cc {
|
||||
n,
|
||||
_p: self._p.reborrow(),
|
||||
_i: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -308,49 +231,12 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
|
||||
///
|
||||
/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
|
||||
/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
|
||||
pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> {
|
||||
pub struct Cc<'d, T: Instance> {
|
||||
n: usize,
|
||||
_p: PeripheralRef<'d, T>,
|
||||
_i: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Cc<'d, T, Awaitable> {
|
||||
/// Wait until the timer's counter reaches the value stored in this register.
|
||||
///
|
||||
/// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
|
||||
pub async fn wait(&mut self) {
|
||||
let regs = T::regs();
|
||||
|
||||
// Enable the interrupt for this CC's COMPARE event.
|
||||
regs.intenset
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
|
||||
|
||||
// Disable the interrupt if the future is dropped.
|
||||
let on_drop = OnDrop::new(|| {
|
||||
regs.intenclr
|
||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
T::waker(self.n).register(cx.waker());
|
||||
|
||||
if regs.events_compare[self.n].read().bits() != 0 {
|
||||
// Reset the register for next time
|
||||
regs.events_compare[self.n].reset();
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
// The interrupt was already disabled in the interrupt handler, so there's no need to disable it again.
|
||||
on_drop.defuse();
|
||||
}
|
||||
}
|
||||
impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {}
|
||||
|
||||
impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> {
|
||||
impl<'d, T: Instance> Cc<'d, T> {
|
||||
/// Get the current value stored in the register.
|
||||
pub fn read(&self) -> u32 {
|
||||
T::regs().cc[self.n].read().cc().bits()
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
use core::sync::atomic::Ordering::SeqCst;
|
||||
use core::task::Poll;
|
||||
@ -15,7 +16,7 @@ use embassy_time::{Duration, Instant};
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::{slice_in_ram, slice_in_ram_or};
|
||||
use crate::{gpio, pac, Peripheral};
|
||||
|
||||
@ -92,6 +93,27 @@ pub enum Error {
|
||||
Timeout,
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.error().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TWI driver.
|
||||
pub struct Twim<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
@ -101,12 +123,12 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// Create a new TWI driver.
|
||||
pub fn new(
|
||||
twim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(twim, irq, sda, scl);
|
||||
into_ref!(twim, sda, scl);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -152,27 +174,12 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: twim }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.error().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
use core::sync::atomic::Ordering::SeqCst;
|
||||
use core::task::Poll;
|
||||
@ -14,7 +15,7 @@ use embassy_time::{Duration, Instant};
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{gpio, pac, Peripheral};
|
||||
|
||||
@ -108,6 +109,31 @@ pub enum Command {
|
||||
Write(usize),
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.read().clear().write().clear());
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.error().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TWIS driver.
|
||||
pub struct Twis<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
@ -117,12 +143,12 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
/// Create a new TWIS driver.
|
||||
pub fn new(
|
||||
twis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(twis, irq, sda, scl);
|
||||
into_ref!(twis, sda, scl);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -178,31 +204,12 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
// Generate suspend on read event
|
||||
r.shorts.write(|w| w.read_suspend().enabled());
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: twis }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.read().clear().write().clear());
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.error().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -26,7 +27,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||
use crate::util::slice_in_ram_or;
|
||||
@ -62,6 +63,27 @@ pub enum Error {
|
||||
BufferNotInRAM,
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
s.endrx_waker.wake();
|
||||
r.intenclr.write(|w| w.endrx().clear());
|
||||
}
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
s.endtx_waker.wake();
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// UARTE driver.
|
||||
pub struct Uarte<'d, T: Instance> {
|
||||
tx: UarteTx<'d, T>,
|
||||
@ -86,19 +108,19 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
/// Create a new UARTE without hardware flow control
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rxd, txd);
|
||||
Self::new_inner(uarte, irq, rxd.map_into(), txd.map_into(), None, None, config)
|
||||
Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config)
|
||||
}
|
||||
|
||||
/// Create a new UARTE with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -108,7 +130,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
into_ref!(rxd, txd, cts, rts);
|
||||
Self::new_inner(
|
||||
uarte,
|
||||
irq,
|
||||
rxd.map_into(),
|
||||
txd.map_into(),
|
||||
Some(cts.map_into()),
|
||||
@ -119,14 +140,13 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
|
||||
fn new_inner(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rxd: PeripheralRef<'d, AnyPin>,
|
||||
txd: PeripheralRef<'d, AnyPin>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(uarte, irq);
|
||||
into_ref!(uarte);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -148,9 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
|
||||
(false, false) => false,
|
||||
@ -238,20 +257,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
Event::from_reg(&r.events_endtx)
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
s.endrx_waker.wake();
|
||||
r.intenclr.write(|w| w.endrx().clear());
|
||||
}
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
s.endtx_waker.wake();
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Read bytes until the buffer is filled.
|
||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.rx.read(buffer).await
|
||||
@ -308,34 +313,33 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
/// Create a new tx-only UARTE without hardware flow control
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(txd);
|
||||
Self::new_inner(uarte, irq, txd.map_into(), None, config)
|
||||
Self::new_inner(uarte, txd.map_into(), None, config)
|
||||
}
|
||||
|
||||
/// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(txd, cts);
|
||||
Self::new_inner(uarte, irq, txd.map_into(), Some(cts.map_into()), config)
|
||||
Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
txd: PeripheralRef<'d, AnyPin>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(uarte, irq);
|
||||
into_ref!(uarte);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -354,9 +358,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
let hardware_flow_control = cts.is_some();
|
||||
configure(r, config, hardware_flow_control);
|
||||
|
||||
irq.set_handler(Uarte::<T>::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let s = T::state();
|
||||
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
@ -506,34 +509,33 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
/// Create a new rx-only UARTE without hardware flow control
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rxd);
|
||||
Self::new_inner(uarte, irq, rxd.map_into(), None, config)
|
||||
Self::new_inner(uarte, rxd.map_into(), None, config)
|
||||
}
|
||||
|
||||
/// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rxd, rts);
|
||||
Self::new_inner(uarte, irq, rxd.map_into(), Some(rts.map_into()), config)
|
||||
Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rxd: PeripheralRef<'d, AnyPin>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(uarte, irq);
|
||||
into_ref!(uarte);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -549,9 +551,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
r.psel.txd.write(|w| w.connect().disconnected());
|
||||
r.psel.cts.write(|w| w.connect().disconnected());
|
||||
|
||||
irq.set_handler(Uarte::<T>::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let hardware_flow_control = rts.is_some();
|
||||
configure(r, config, hardware_flow_control);
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
#![macro_use]
|
||||
|
||||
pub mod vbus_detect;
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
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 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 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::{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 READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
/// 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<(), ()>;
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// [`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`].
|
||||
#[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 ()) {
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = T::regs();
|
||||
|
||||
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 EndpointIn = Endpoint<'d, T, In>;
|
||||
type ControlPipe = ControlPipe<'d, T>;
|
||||
type Bus = Bus<'d, T, P>;
|
||||
type Bus = Bus<'d, T, V>;
|
||||
|
||||
fn alloc_endpoint_in(
|
||||
&mut self,
|
||||
@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
||||
Bus {
|
||||
_p: unsafe { self._p.clone_unchecked() },
|
||||
power_available: false,
|
||||
usb_supply: self.usb_supply,
|
||||
vbus_detect: self.vbus_detect,
|
||||
},
|
||||
ControlPipe {
|
||||
_p: self._p,
|
||||
@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
||||
}
|
||||
|
||||
/// USB bus.
|
||||
pub struct Bus<'d, T: Instance, P: VbusDetect> {
|
||||
pub struct Bus<'d, T: Instance, V: VbusDetect> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
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) {
|
||||
let regs = T::regs();
|
||||
|
||||
@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
||||
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.
|
||||
regs.usbpullup.write(|w| w.connect().enabled());
|
||||
trace!("enabled");
|
||||
@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
||||
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;
|
||||
if self.power_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]
|
||||
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",
|
||||
"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-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-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"
|
||||
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"
|
||||
usbd-hid = "0.6.0"
|
||||
serde = { version = "1.0.136", default-features = false }
|
||||
|
||||
[[bin]]
|
||||
name = "usb_serial_winusb"
|
||||
required-features = ["msos-descriptor"]
|
||||
|
@ -1,26 +0,0 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::timer::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
|
||||
// default frequency is 1MHz, so this triggers every second
|
||||
t.cc(0).write(1_000_000);
|
||||
// clear the timer value on cc[0] compare match
|
||||
t.cc(0).short_compare_clear();
|
||||
t.start();
|
||||
|
||||
loop {
|
||||
// wait for compare match
|
||||
t.cc(0).wait().await;
|
||||
info!("hardware timer tick");
|
||||
}
|
||||
}
|
@ -4,11 +4,15 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::buffered_uarte::BufferedUarte;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::buffered_uarte::{self, BufferedUarte};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||
use embedded_io::asynch::Write;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -19,14 +23,13 @@ async fn main(_spawner: Spawner) {
|
||||
let mut tx_buffer = [0u8; 4096];
|
||||
let mut rx_buffer = [0u8; 4096];
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let mut u = BufferedUarte::new(
|
||||
p.UARTE0,
|
||||
p.TIMER0,
|
||||
p.PPI_CH0,
|
||||
p.PPI_CH1,
|
||||
p.PPI_GROUP0,
|
||||
irq,
|
||||
Irqs,
|
||||
p.P0_08,
|
||||
p.P0_06,
|
||||
config,
|
||||
|
@ -7,7 +7,7 @@ use core::f32::consts::PI;
|
||||
use defmt::{error, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type Sample = i16;
|
||||
@ -15,6 +15,10 @@ type Sample = i16;
|
||||
const NUM_BUFFERS: usize = 2;
|
||||
const NUM_SAMPLES: usize = 4;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) {
|
||||
config.sample_width = SampleWidth::_16bit;
|
||||
config.channels = Channels::MonoLeft;
|
||||
|
||||
let irq = interrupt::take!(I2S);
|
||||
let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
|
||||
let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
|
||||
let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex(
|
||||
p.P0_29,
|
||||
p.P0_28,
|
||||
buffers_out,
|
||||
buffers_in,
|
||||
);
|
||||
let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
|
||||
.full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
|
||||
|
||||
let mut modulator = SineOsc::new();
|
||||
modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
|
||||
|
@ -5,14 +5,18 @@
|
||||
use defmt::{debug, error, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::pwm::{Prescaler, SimplePwm};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type Sample = i16;
|
||||
|
||||
const NUM_SAMPLES: usize = 500;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) {
|
||||
config.sample_width = SampleWidth::_16bit;
|
||||
config.channels = Channels::MonoLeft;
|
||||
|
||||
let irq = interrupt::take!(I2S);
|
||||
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
||||
let mut input_stream =
|
||||
I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
|
||||
I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
|
||||
|
||||
// Configure the PWM to use the pins corresponding to the RGB leds
|
||||
let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
|
||||
|
@ -7,13 +7,17 @@ use core::f32::consts::PI;
|
||||
use defmt::{error, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type Sample = i16;
|
||||
|
||||
const NUM_SAMPLES: usize = 50;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) {
|
||||
config.sample_width = SampleWidth::_16bit;
|
||||
config.channels = Channels::MonoLeft;
|
||||
|
||||
let irq = interrupt::take!(I2S);
|
||||
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
||||
let mut output_stream =
|
||||
I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
|
||||
I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
|
||||
|
||||
let mut waveform = Waveform::new(1.0 / sample_rate as f32);
|
||||
|
||||
|
@ -11,11 +11,15 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_lora::sx126x::*;
|
||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
||||
use embassy_nrf::{interrupt, spim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spim};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) {
|
||||
spi_config.frequency = spim::Frequency::M16;
|
||||
|
||||
let mut radio = {
|
||||
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
||||
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
|
||||
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
||||
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
||||
|
@ -12,13 +12,17 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_lora::sx126x::*;
|
||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
||||
use embassy_nrf::{interrupt, spim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spim};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::pubsub::{PubSubChannel, Publisher};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
|
||||
use {defmt_rtt as _, panic_probe as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
|
||||
});
|
||||
|
||||
// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
|
||||
static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
|
||||
|
||||
@ -58,8 +62,7 @@ async fn main(spawner: Spawner) {
|
||||
spi_config.frequency = spim::Frequency::M16;
|
||||
|
||||
let mut radio = {
|
||||
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
||||
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
|
||||
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
||||
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
||||
|
@ -4,16 +4,20 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::pdm::{Config, Pdm};
|
||||
use embassy_nrf::pdm::{self, Config, Pdm};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PDM => pdm::InterruptHandler<peripherals::PDM>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let config = Config::default();
|
||||
let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), p.P0_01, p.P0_00, config);
|
||||
let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
|
||||
|
||||
loop {
|
||||
pdm.start().await;
|
||||
|
@ -4,16 +4,19 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::qdec::{self, Qdec};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
QDEC => qdec::InterruptHandler<peripherals::QDEC>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let irq = interrupt::take!(QDEC);
|
||||
let config = qdec::Config::default();
|
||||
let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config);
|
||||
let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config);
|
||||
|
||||
info!("Turn rotary encoder!");
|
||||
let mut value = 0;
|
||||
|
@ -5,7 +5,7 @@
|
||||
use defmt::{assert_eq, info, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::qspi::Frequency;
|
||||
use embassy_nrf::{interrupt, qspi};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, qspi};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const PAGE_SIZE: usize = 4096;
|
||||
@ -15,6 +15,10 @@ const PAGE_SIZE: usize = 4096;
|
||||
#[repr(C, align(4))]
|
||||
struct AlignedBuf([u8; 4096]);
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -26,9 +30,8 @@ async fn main(_spawner: Spawner) {
|
||||
config.write_opcode = qspi::WriteOpcode::PP4IO;
|
||||
config.write_page_size = qspi::WritePageSize::_256BYTES;
|
||||
|
||||
let irq = interrupt::take!(QSPI);
|
||||
let mut q = qspi::Qspi::new(
|
||||
p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
|
||||
p.QSPI, Irqs, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
|
||||
);
|
||||
|
||||
let mut id = [1; 3];
|
||||
|
@ -7,7 +7,7 @@ use core::mem;
|
||||
use defmt::{info, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::qspi::Frequency;
|
||||
use embassy_nrf::{interrupt, qspi};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, qspi};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
@ -16,10 +16,13 @@ use {defmt_rtt as _, panic_probe as _};
|
||||
#[repr(C, align(4))]
|
||||
struct AlignedBuf([u8; 64]);
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
let mut irq = interrupt::take!(QSPI);
|
||||
|
||||
loop {
|
||||
// Config for the MX25R64 present in the nRF52840 DK
|
||||
@ -36,7 +39,7 @@ async fn main(_p: Spawner) {
|
||||
|
||||
let mut q = qspi::Qspi::new(
|
||||
&mut p.QSPI,
|
||||
&mut irq,
|
||||
Irqs,
|
||||
&mut p.P0_19,
|
||||
&mut p.P0_17,
|
||||
&mut p.P0_20,
|
||||
|
@ -3,15 +3,19 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::rng::Rng;
|
||||
use embassy_nrf::{bind_interrupts, peripherals, rng};
|
||||
use rand::Rng as _;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
|
||||
let mut rng = Rng::new(p.RNG, Irqs);
|
||||
|
||||
// Async API
|
||||
let mut bytes = [0; 4];
|
||||
|
@ -4,17 +4,21 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
|
||||
use embassy_nrf::{bind_interrupts, saadc};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SAADC => saadc::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
let config = Config::default();
|
||||
let channel_config = ChannelConfig::single_ended(&mut p.P0_02);
|
||||
let mut saadc = Saadc::new(p.SAADC, interrupt::take!(SAADC), config, [channel_config]);
|
||||
let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]);
|
||||
|
||||
loop {
|
||||
let mut buf = [0; 1];
|
||||
|
@ -4,14 +4,18 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
|
||||
use embassy_nrf::timer::Frequency;
|
||||
use embassy_nrf::{bind_interrupts, saadc};
|
||||
use embassy_time::Duration;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SAADC => saadc::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
@ -21,7 +25,7 @@ async fn main(_p: Spawner) {
|
||||
let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
|
||||
let mut saadc = Saadc::new(
|
||||
p.SAADC,
|
||||
interrupt::take!(SAADC),
|
||||
Irqs,
|
||||
config,
|
||||
[channel_1_config, channel_2_config, channel_3_config],
|
||||
);
|
||||
|
@ -5,9 +5,13 @@
|
||||
use defmt::{info, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_nrf::{interrupt, spim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spim};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut config = spim::Config::default();
|
||||
config.frequency = spim::Frequency::M16;
|
||||
|
||||
let irq = interrupt::take!(SPIM3);
|
||||
let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
|
||||
let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config);
|
||||
|
||||
let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
|
||||
|
||||
|
@ -4,17 +4,20 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::spis::{Config, Spis};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spis};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
info!("Running!");
|
||||
|
||||
let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
|
||||
let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
|
||||
let mut spis = Spis::new(p.SPI2, Irqs, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
|
||||
|
||||
loop {
|
||||
let mut rx_buf = [0_u8; 64];
|
||||
|
@ -4,16 +4,19 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::temp::Temp;
|
||||
use embassy_nrf::{bind_interrupts, temp};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
TEMP => temp::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let irq = interrupt::take!(TEMP);
|
||||
let mut temp = Temp::new(p.TEMP, irq);
|
||||
let mut temp = Temp::new(p.TEMP, Irqs);
|
||||
|
||||
loop {
|
||||
let value = temp.read().await;
|
||||
|
@ -8,19 +8,22 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::twim::{self, Twim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x50;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
info!("Initializing TWI...");
|
||||
let config = twim::Config::default();
|
||||
let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
||||
let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
|
||||
|
||||
info!("Reading...");
|
||||
|
||||
|
@ -12,25 +12,28 @@ use core::mem;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::twim::{self, Twim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x50;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
info!("Started!");
|
||||
let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
|
||||
loop {
|
||||
info!("Initializing TWI...");
|
||||
let config = twim::Config::default();
|
||||
|
||||
// Create the TWIM instance with borrowed singletons, so they're not consumed.
|
||||
let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
|
||||
let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config);
|
||||
|
||||
info!("Reading...");
|
||||
|
||||
|
@ -6,19 +6,21 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::twis::{self, Command, Twis};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
|
||||
let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
let mut config = twis::Config::default();
|
||||
// Set i2c address
|
||||
config.address0 = 0x55;
|
||||
let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
||||
config.address0 = 0x55; // Set i2c address
|
||||
let mut i2c = Twis::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
|
||||
|
||||
info!("Listening...");
|
||||
loop {
|
||||
|
@ -4,9 +4,13 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -14,8 +18,7 @@ async fn main(_spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
||||
let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
||||
|
@ -4,9 +4,14 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::peripherals::UARTE0;
|
||||
use embassy_nrf::{bind_interrupts, uarte};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||
let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
@ -6,13 +6,17 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::peripherals::UARTE0;
|
||||
use embassy_nrf::uarte::UarteRx;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::{bind_interrupts, uarte};
|
||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -20,8 +24,7 @@ async fn main(spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||
let (mut tx, rx) = uart.split();
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
@ -9,8 +9,9 @@ use embassy_executor::Spawner;
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
use embassy_net::{Stack, StackResources};
|
||||
use embassy_nrf::rng::Rng;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac, peripherals};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
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::{CdcNcmClass, State};
|
||||
use embassy_usb::{Builder, Config, UsbDevice};
|
||||
@ -18,6 +19,12 @@ use embedded_io::asynch::Write;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
||||
|
||||
macro_rules! singleton {
|
||||
@ -56,9 +63,7 @@ async fn main(spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -82,6 +87,7 @@ async fn main(spawner: Spawner) {
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 128])[..],
|
||||
&mut singleton!([0; 128])[..],
|
||||
);
|
||||
|
||||
// Our MAC addr.
|
||||
@ -108,7 +114,7 @@ async fn main(spawner: Spawner) {
|
||||
//});
|
||||
|
||||
// Generate random seed
|
||||
let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
|
||||
let mut rng = Rng::new(p.RNG, Irqs);
|
||||
let mut seed = [0; 8];
|
||||
rng.blocking_fill_bytes(&mut seed);
|
||||
let seed = u64::from_le_bytes(seed);
|
||||
|
@ -10,8 +10,9 @@ use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_nrf::gpio::{Input, Pin, Pull};
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::signal::Signal;
|
||||
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 {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);
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut device_descriptor = [0; 256];
|
||||
let mut config_descriptor = [0; 256];
|
||||
let mut bos_descriptor = [0; 256];
|
||||
let mut msos_descriptor = [0; 256];
|
||||
let mut control_buf = [0; 64];
|
||||
let request_handler = MyRequestHandler {};
|
||||
let mut device_handler = MyDeviceHandler::new();
|
||||
@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) {
|
||||
&mut device_descriptor,
|
||||
&mut config_descriptor,
|
||||
&mut bos_descriptor,
|
||||
&mut msos_descriptor,
|
||||
&mut control_buf,
|
||||
);
|
||||
|
||||
|
@ -7,8 +7,9 @@ use core::mem;
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
||||
use embassy_usb::control::OutResponse;
|
||||
@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config};
|
||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||
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]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut device_descriptor = [0; 256];
|
||||
let mut config_descriptor = [0; 256];
|
||||
let mut bos_descriptor = [0; 256];
|
||||
let mut msos_descriptor = [0; 256];
|
||||
let mut control_buf = [0; 64];
|
||||
let request_handler = MyRequestHandler {};
|
||||
|
||||
@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) {
|
||||
&mut device_descriptor,
|
||||
&mut config_descriptor,
|
||||
&mut bos_descriptor,
|
||||
&mut msos_descriptor,
|
||||
&mut control_buf,
|
||||
);
|
||||
|
||||
|
@ -7,13 +7,19 @@ use core::mem;
|
||||
use defmt::{info, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||
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::driver::EndpointError;
|
||||
use embassy_usb::{Builder, Config};
|
||||
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]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut device_descriptor = [0; 256];
|
||||
let mut config_descriptor = [0; 256];
|
||||
let mut bos_descriptor = [0; 256];
|
||||
let mut msos_descriptor = [0; 256];
|
||||
let mut control_buf = [0; 64];
|
||||
|
||||
let mut state = State::new();
|
||||
@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) {
|
||||
&mut device_descriptor,
|
||||
&mut config_descriptor,
|
||||
&mut bos_descriptor,
|
||||
&mut msos_descriptor,
|
||||
&mut control_buf,
|
||||
);
|
||||
|
||||
|
@ -6,14 +6,29 @@ use core::mem;
|
||||
|
||||
use defmt::{info, panic, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac, peripherals};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||
use embassy_usb::driver::EndpointError;
|
||||
use embassy_usb::{Builder, Config, UsbDevice};
|
||||
use static_cell::StaticCell;
|
||||
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>;
|
||||
|
||||
#[embassy_executor::task]
|
||||
@ -39,10 +54,9 @@ async fn main(spawner: Spawner) {
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -59,34 +73,21 @@ async fn main(spawner: Spawner) {
|
||||
config.device_protocol = 0x01;
|
||||
config.composite_with_iads = true;
|
||||
|
||||
struct Resources {
|
||||
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(),
|
||||
});
|
||||
let state = singleton!(State::new());
|
||||
|
||||
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||
let mut builder = Builder::new(
|
||||
driver,
|
||||
config,
|
||||
&mut res.device_descriptor,
|
||||
&mut res.config_descriptor,
|
||||
&mut res.bos_descriptor,
|
||||
&mut res.control_buf,
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 128])[..],
|
||||
&mut singleton!([0; 128])[..],
|
||||
);
|
||||
|
||||
// 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.
|
||||
let usb = builder.build();
|
||||
|
@ -7,8 +7,9 @@ use core::mem;
|
||||
use defmt::{info, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||
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::driver::EndpointError;
|
||||
use embassy_usb::msos::{self, windows_version};
|
||||
@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber;
|
||||
use embassy_usb::{Builder, Config};
|
||||
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
|
||||
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 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
|
@ -4,9 +4,14 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::peripherals::SERIAL0;
|
||||
use embassy_nrf::{bind_interrupts, uarte};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SERIAL0 => uarte::InterruptHandler<SERIAL0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(SERIAL0);
|
||||
let mut uart = uarte::Uarte::new(p.SERIAL0, irq, p.P1_00, p.P1_01, config);
|
||||
let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config);
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
||||
|
@ -5,10 +5,14 @@
|
||||
use defmt::{assert_eq, *};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::buffered_uarte::BufferedUarte;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::buffered_uarte::{self, BufferedUarte};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -25,7 +29,7 @@ async fn main(_spawner: Spawner) {
|
||||
p.PPI_CH0,
|
||||
p.PPI_CH1,
|
||||
p.PPI_GROUP0,
|
||||
interrupt::take!(UARTE0_UART0),
|
||||
Irqs,
|
||||
p.P1_03,
|
||||
p.P1_02,
|
||||
config.clone(),
|
||||
|
@ -7,14 +7,19 @@ use core::ptr::NonNull;
|
||||
|
||||
use defmt::{assert_eq, *};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::buffered_uarte::BufferedUarte;
|
||||
use embassy_nrf::buffered_uarte::{self, BufferedUarte};
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_nrf::ppi::{Event, Ppi, Task};
|
||||
use embassy_nrf::uarte::Uarte;
|
||||
use embassy_nrf::{interrupt, pac, uarte};
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, uarte};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
|
||||
UARTE1 => uarte::InterruptHandler<peripherals::UARTE1>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
@ -33,7 +38,7 @@ async fn main(_spawner: Spawner) {
|
||||
p.PPI_CH0,
|
||||
p.PPI_CH1,
|
||||
p.PPI_GROUP0,
|
||||
interrupt::take!(UARTE0_UART0),
|
||||
Irqs,
|
||||
p.P1_03,
|
||||
p.P1_04,
|
||||
config.clone(),
|
||||
@ -49,7 +54,7 @@ async fn main(_spawner: Spawner) {
|
||||
// Tx spam in a loop.
|
||||
const NSPAM: usize = 17;
|
||||
static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let _spam = Uarte::new(p.UARTE1, interrupt::take!(UARTE1), p.P1_01, p.P1_02, config.clone());
|
||||
let _spam = Uarte::new(p.UARTE1, Irqs, p.P1_01, p.P1_02, config.clone());
|
||||
let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) };
|
||||
let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) };
|
||||
let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) };
|
||||
|
Loading…
x
Reference in New Issue
Block a user