Merge pull request #1224 from embassy-rs/interrupt-binding

nrf: new interrupt binding traits/macro
This commit is contained in:
Dario Nieuwenhuis 2023-03-06 00:41:47 +01:00 committed by GitHub
commit 18fe398673
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 1404 additions and 1110 deletions

View File

@ -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.

View File

@ -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
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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")]

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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};

View File

@ -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;
}
};
}

View File

@ -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;
}
};
}

View File

@ -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 {

View File

@ -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;
}
};
}

View File

@ -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() }
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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)?;

View File

@ -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)?;

View File

@ -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);

View File

@ -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");

View 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
}
}

View File

@ -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"]

View File

@ -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");
}
}

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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,

View File

@ -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];

View File

@ -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];

View File

@ -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],
);

View File

@ -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);

View File

@ -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];

View File

@ -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;

View File

@ -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...");

View File

@ -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...");

View File

@ -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 {

View File

@ -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!");

View File

@ -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!");

View File

@ -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!");

View File

@ -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);

View File

@ -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,
);

View File

@ -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,
);

View File

@ -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,
);

View File

@ -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();

View File

@ -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);

View File

@ -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!");

View File

@ -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(),

View File

@ -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 _)) };