Merge upstream

This commit is contained in:
Mehmet Ali Anil 2023-03-07 10:46:59 +01:00
commit b0e26440ee
104 changed files with 3042 additions and 1560 deletions

View File

@ -14,6 +14,10 @@ Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows
- **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
- <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families.
- <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
- <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 microcontroller.
- <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips.
- Embassy HAL support for Espressif chips is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
- Async WiFi, Bluetooth and ESP-NOW is being developed in the [esp-rs/esp-wifi](https://github.com/esp-rs/esp-wifi) repository.
- **Time that Just Works** -
No more messing with hardware timers. <a href="https://docs.embassy.dev/embassy-time">embassy_time</a> provides Instant, Duration and Timer types that are globally available and never overflow.

1
ci.sh
View File

@ -133,6 +133,7 @@ cargo batch \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/nucleo-stm32wb55rg \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/iot-stm32u585ai \
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
$BUILD_EXTRA

View File

@ -1,18 +1,22 @@
//! Executor specific to cortex-m devices.
use core::marker::PhantomData;
use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use atomic_polyfill::{AtomicBool, Ordering};
use cortex_m::interrupt::InterruptNumber;
use cortex_m::peripheral::NVIC;
pub use embassy_executor::*;
use crate::interrupt::{Interrupt, InterruptExt};
fn pend_by_number(n: u16) {
#[derive(Clone, Copy)]
struct N(u16);
unsafe impl cortex_m::interrupt::InterruptNumber for N {
#[derive(Clone, Copy)]
struct N(u16);
unsafe impl cortex_m::interrupt::InterruptNumber for N {
fn number(self) -> u16 {
self.0
}
}
}
fn pend_by_number(n: u16) {
cortex_m::peripheral::NVIC::pend(N(n))
}
@ -37,26 +41,37 @@ fn pend_by_number(n: u16) {
///
/// It is somewhat more complex to use, it's recommended to use the thread-mode
/// [`Executor`] instead, if it works for your use case.
pub struct InterruptExecutor<I: Interrupt> {
irq: I,
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
pub struct InterruptExecutor {
started: AtomicBool,
executor: UnsafeCell<MaybeUninit<raw::Executor>>,
}
impl<I: Interrupt> InterruptExecutor<I> {
/// Create a new Executor.
pub fn new(irq: I) -> Self {
let ctx = irq.number() as *mut ();
unsafe impl Send for InterruptExecutor {}
unsafe impl Sync for InterruptExecutor {}
impl InterruptExecutor {
/// Create a new, not started `InterruptExecutor`.
#[inline]
pub const fn new() -> Self {
Self {
irq,
inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx),
not_send: PhantomData,
started: AtomicBool::new(false),
executor: UnsafeCell::new(MaybeUninit::uninit()),
}
}
/// Executor interrupt callback.
///
/// # Safety
///
/// You MUST call this from the interrupt handler, and from nowhere else.
pub unsafe fn on_interrupt(&'static self) {
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
executor.poll();
}
/// Start the executor.
///
/// This initializes the executor, configures and enables the interrupt, and returns.
/// This initializes the executor, enables the interrupt, and returns.
/// The executor keeps running in the background through the interrupt.
///
/// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
@ -67,23 +82,35 @@ impl<I: Interrupt> InterruptExecutor<I> {
/// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from
/// a task running in it.
///
/// This function requires `&'static mut self`. This means you have to store the
/// Executor instance in a place where it'll live forever and grants you mutable
/// access. There's a few ways to do this:
/// # Interrupt requirements
///
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
/// - a `static mut` (unsafe)
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
pub fn start(&'static mut self) -> SendSpawner {
self.irq.disable();
/// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt).
///
/// This method already enables (unmasks) the interrupt, you must NOT do it yourself.
///
/// You must set the interrupt priority before calling this method. You MUST NOT
/// do it after.
///
pub fn start(&'static self, irq: impl InterruptNumber) -> SendSpawner {
if self
.started
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
panic!("InterruptExecutor::start() called multiple times on the same executor.");
}
self.irq.set_handler(|ctx| unsafe {
let executor = &*(ctx as *const raw::Executor);
executor.poll();
});
self.irq.set_handler_context(&self.inner as *const _ as _);
self.irq.enable();
unsafe {
(&mut *self.executor.get()).as_mut_ptr().write(raw::Executor::new(
|ctx| pend_by_number(ctx as u16),
irq.number() as *mut (),
))
}
self.inner.spawner().make_send()
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
unsafe { NVIC::unmask(irq) }
executor.spawner().make_send()
}
}

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

@ -24,6 +24,7 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNowFuture { yielded: false }
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct YieldNowFuture {
yielded: bool,
}

View File

@ -14,10 +14,18 @@ use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
/// One concurrent writer and one concurrent reader are supported, even at
/// different execution priorities (like main and irq).
pub struct RingBuffer {
buf: AtomicPtr<u8>,
len: AtomicUsize,
start: AtomicUsize,
end: AtomicUsize,
pub buf: AtomicPtr<u8>,
pub len: AtomicUsize,
// start and end wrap at len*2, not at len.
// This allows distinguishing "full" and "empty".
// full is when start+len == end (modulo len*2)
// empty is when start == end
//
// This avoids having to consider the ringbuffer "full" at len-1 instead of len.
// The usual solution is adding a "full" flag, but that can't be made atomic
pub start: AtomicUsize,
pub end: AtomicUsize,
}
pub struct Reader<'a>(&'a RingBuffer);
@ -90,7 +98,7 @@ impl RingBuffer {
let start = self.start.load(Ordering::Relaxed);
let end = self.end.load(Ordering::Relaxed);
len == 0 || self.wrap(end + 1) == start
self.wrap(start + len) == end
}
pub fn is_empty(&self) -> bool {
@ -100,15 +108,13 @@ impl RingBuffer {
start == end
}
fn wrap(&self, n: usize) -> usize {
fn wrap(&self, mut n: usize) -> usize {
let len = self.len.load(Ordering::Relaxed);
assert!(n <= len);
if n == len {
0
} else {
n
if n >= len * 2 {
n -= len * 2
}
n
}
}
@ -147,6 +153,14 @@ impl<'a> Writer<'a> {
unsafe { slice::from_raw_parts_mut(data, len) }
}
/// Get up to two buffers where data can be pushed to.
///
/// Equivalent to [`Self::push_bufs`] but returns slices.
pub fn push_slices(&mut self) -> [&mut [u8]; 2] {
let [(d0, l0), (d1, l1)] = self.push_bufs();
unsafe { [slice::from_raw_parts_mut(d0, l0), slice::from_raw_parts_mut(d1, l1)] }
}
/// Get a buffer where data can be pushed to.
///
/// Write data to the start of the buffer, then call `push_done` with
@ -161,21 +175,69 @@ impl<'a> Writer<'a> {
pub fn push_buf(&mut self) -> (*mut u8, usize) {
// Ordering: popping writes `start` last, so we read `start` first.
// Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
let start = self.0.start.load(Ordering::Acquire);
let mut start = self.0.start.load(Ordering::Acquire);
let buf = self.0.buf.load(Ordering::Relaxed);
let len = self.0.len.load(Ordering::Relaxed);
let end = self.0.end.load(Ordering::Relaxed);
let mut end = self.0.end.load(Ordering::Relaxed);
let n = if start <= end {
len - end - (start == 0 && len != 0) as usize
} else {
start - end - 1
};
let empty = start == end;
if start >= len {
start -= len
}
if end >= len {
end -= len
}
if start == end && !empty {
// full
return (buf, 0);
}
let n = if start > end { start - end } else { len - end };
trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n);
(unsafe { buf.add(end) }, n)
}
/// Get up to two buffers where data can be pushed to.
///
/// Write data starting at the beginning of the first buffer, then call
/// `push_done` with however many bytes you've pushed.
///
/// The buffers are suitable to DMA to.
///
/// If the ringbuf is full, both buffers will be zero length.
/// If there is only area available, the second buffer will be zero length.
///
/// The buffer stays valid as long as no other `Writer` method is called
/// and `init`/`deinit` aren't called on the ringbuf.
pub fn push_bufs(&mut self) -> [(*mut u8, usize); 2] {
// Ordering: as per push_buf()
let mut start = self.0.start.load(Ordering::Acquire);
let buf = self.0.buf.load(Ordering::Relaxed);
let len = self.0.len.load(Ordering::Relaxed);
let mut end = self.0.end.load(Ordering::Relaxed);
let empty = start == end;
if start >= len {
start -= len
}
if end >= len {
end -= len
}
if start == end && !empty {
// full
return [(buf, 0), (buf, 0)];
}
let n0 = if start > end { start - end } else { len - end };
let n1 = if start <= end { start } else { 0 };
trace!(" ringbuf: push_bufs [{:?}..{:?}, {:?}..{:?}]", end, end + n0, 0, n1);
[(unsafe { buf.add(end) }, n0), (buf, n1)]
}
pub fn push_done(&mut self, n: usize) {
trace!(" ringbuf: push {:?}", n);
let end = self.0.end.load(Ordering::Relaxed);
@ -239,12 +301,23 @@ impl<'a> Reader<'a> {
// Ordering: pushing writes `end` last, so we read `end` first.
// Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
// This is needed to guarantee we "see" the data written by the writer.
let end = self.0.end.load(Ordering::Acquire);
let mut end = self.0.end.load(Ordering::Acquire);
let buf = self.0.buf.load(Ordering::Relaxed);
let len = self.0.len.load(Ordering::Relaxed);
let start = self.0.start.load(Ordering::Relaxed);
let mut start = self.0.start.load(Ordering::Relaxed);
let n = if end < start { len - start } else { end - start };
if start == end {
return (buf, 0);
}
if start >= len {
start -= len
}
if end >= len {
end -= len
}
let n = if end > start { end - start } else { len - start };
trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n);
(unsafe { buf.add(start) }, n)
@ -280,12 +353,12 @@ mod tests {
assert_eq!(rb.is_full(), false);
rb.writer().push(|buf| {
// If capacity is 4, we can fill it up to 3.
assert_eq!(3, buf.len());
assert_eq!(4, buf.len());
buf[0] = 1;
buf[1] = 2;
buf[2] = 3;
3
buf[3] = 4;
4
});
assert_eq!(rb.is_empty(), false);
@ -301,7 +374,7 @@ mod tests {
assert_eq!(rb.is_full(), true);
rb.reader().pop(|buf| {
assert_eq!(3, buf.len());
assert_eq!(4, buf.len());
assert_eq!(1, buf[0]);
1
});
@ -310,7 +383,7 @@ mod tests {
assert_eq!(rb.is_full(), false);
rb.reader().pop(|buf| {
assert_eq!(2, buf.len());
assert_eq!(3, buf.len());
0
});
@ -318,11 +391,16 @@ mod tests {
assert_eq!(rb.is_full(), false);
rb.reader().pop(|buf| {
assert_eq!(2, buf.len());
assert_eq!(3, buf.len());
assert_eq!(2, buf[0]);
assert_eq!(3, buf[1]);
2
});
rb.reader().pop(|buf| {
assert_eq!(1, buf.len());
assert_eq!(4, buf[0]);
1
});
assert_eq!(rb.is_empty(), true);
assert_eq!(rb.is_full(), false);
@ -333,18 +411,27 @@ mod tests {
});
rb.writer().push(|buf| {
assert_eq!(1, buf.len());
assert_eq!(4, buf.len());
buf[0] = 10;
1
});
rb.writer().push(|buf| {
assert_eq!(2, buf.len());
assert_eq!(3, buf.len());
buf[0] = 11;
buf[1] = 12;
2
});
assert_eq!(rb.is_empty(), false);
assert_eq!(rb.is_full(), false);
rb.writer().push(|buf| {
assert_eq!(1, buf.len());
buf[0] = 13;
1
});
assert_eq!(rb.is_empty(), false);
assert_eq!(rb.is_full(), true);
}
@ -368,4 +455,104 @@ mod tests {
});
}
}
#[test]
fn push_slices() {
init();
let mut b = [0; 4];
let rb = RingBuffer::new();
unsafe {
rb.init(b.as_mut_ptr(), 4);
/* push 3 -> [1 2 3 x] */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(4, ps[0].len());
assert_eq!(0, ps[1].len());
ps[0][0] = 1;
ps[0][1] = 2;
ps[0][2] = 3;
w.push_done(3);
drop(w);
/* pop 2 -> [x x 3 x] */
rb.reader().pop(|buf| {
assert_eq!(3, buf.len());
assert_eq!(1, buf[0]);
assert_eq!(2, buf[1]);
assert_eq!(3, buf[2]);
2
});
/* push 3 -> [5 6 3 4] */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(1, ps[0].len());
assert_eq!(2, ps[1].len());
ps[0][0] = 4;
ps[1][0] = 5;
ps[1][1] = 6;
w.push_done(3);
drop(w);
/* buf is now full */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(0, ps[0].len());
assert_eq!(0, ps[1].len());
/* pop 2 -> [5 6 x x] */
rb.reader().pop(|buf| {
assert_eq!(2, buf.len());
assert_eq!(3, buf[0]);
assert_eq!(4, buf[1]);
2
});
/* should now have one push slice again */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(2, ps[0].len());
assert_eq!(0, ps[1].len());
drop(w);
/* pop 2 -> [x x x x] */
rb.reader().pop(|buf| {
assert_eq!(2, buf.len());
assert_eq!(5, buf[0]);
assert_eq!(6, buf[1]);
2
});
/* should now have two push slices */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(2, ps[0].len());
assert_eq!(2, ps[1].len());
drop(w);
/* make sure we exercise all wrap around cases properly */
for _ in 0..10 {
/* should be empty, push 1 */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(4, ps[0].len() + ps[1].len());
w.push_done(1);
drop(w);
/* should have 1 element */
let mut w = rb.writer();
let ps = w.push_slices();
assert_eq!(3, ps[0].len() + ps[1].len());
drop(w);
/* pop 1 */
rb.reader().pop(|buf| {
assert_eq!(1, buf.len());
1
});
}
}
}
}

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

@ -236,6 +236,22 @@ impl<D: Driver + 'static> Stack<D> {
/// Make a query for a given name and return the corresponding IP addresses.
#[cfg(feature = "dns")]
pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
// For A and AAAA queries we try detect whether `name` is just an IP address
match qtype {
dns::DnsQueryType::A => {
if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
return Ok([ip].into_iter().collect());
}
}
#[cfg(feature = "proto-ipv6")]
dns::DnsQueryType::Aaaa => {
if let Ok(ip) = name.parse().map(IpAddress::Ipv6) {
return Ok([ip].into_iter().collect());
}
}
_ => {}
}
let query = poll_fn(|cx| {
self.with_mut(|s, i| {
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);

View File

@ -1,10 +1,5 @@
//! Async buffered UART driver.
//!
//! WARNING!!! The functionality provided here is intended to be used only
//! in situations where hardware flow control are available i.e. CTS and RTS.
//! This is a problem that should be addressed at a later stage and can be
//! fully explained at <https://github.com/embassy-rs/embassy/issues/536>.
//!
//! Note that discarding a future from a read or write operation may lead to losing
//! data. For example, when using `futures_util::future::select` and completion occurs
//! on the "other" future, you should capture the incomplete future and continue to use
@ -13,83 +8,236 @@
//!
//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used.
use core::cell::RefCell;
use core::cmp::min;
use core::future::poll_fn;
use core::sync::atomic::{compiler_fence, Ordering};
use core::marker::PhantomData;
use core::slice;
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
use core::task::Poll;
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
use embassy_hal_common::ring_buffer::RingBuffer;
use embassy_cortex_m::interrupt::Interrupt;
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
use embassy_hal_common::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::WakerRegistration;
use embassy_sync::waitqueue::AtomicWaker;
// Re-export SVD variants to allow user to directly set values
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
use crate::gpio::{self, Pin as GpioPin};
use crate::interrupt::InterruptExt;
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
use crate::gpio::sealed::Pin;
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
use crate::interrupt::{self, InterruptExt};
use crate::ppi::{
self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
};
use crate::timer::{Instance as TimerInstance, Timer};
use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
use crate::{pac, Peripheral};
#[derive(Copy, Clone, Debug, PartialEq)]
enum RxState {
Idle,
Receiving,
}
mod sealed {
use super::*;
#[derive(Copy, Clone, Debug, PartialEq)]
enum TxState {
Idle,
Transmitting(usize),
}
pub struct State {
pub tx_waker: AtomicWaker,
pub tx_buf: RingBuffer,
pub tx_count: AtomicUsize,
/// A type for storing the state of the UARTE peripheral that can be stored in a static.
pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>);
impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> {
/// Create an instance for storing UARTE peripheral state.
pub fn new() -> Self {
Self(StateStorage::new())
pub rx_waker: AtomicWaker,
pub rx_buf: RingBuffer,
pub rx_bufs: AtomicU8,
pub rx_ppi_ch: AtomicU8,
}
}
struct StateInner<'d, U: UarteInstance, T: TimerInstance> {
_peri: PeripheralRef<'d, U>,
timer: Timer<'d, T>,
_ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>,
_ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>,
/// UART error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
// No errors for now
}
rx: RingBuffer<'d>,
rx_state: RxState,
rx_waker: WakerRegistration,
pub(crate) use sealed::State;
tx: RingBuffer<'d>,
tx_state: TxState,
tx_waker: WakerRegistration,
impl State {
pub(crate) const fn new() -> Self {
Self {
tx_waker: AtomicWaker::new(),
tx_buf: RingBuffer::new(),
tx_count: AtomicUsize::new(0),
rx_waker: AtomicWaker::new(),
rx_buf: RingBuffer::new(),
rx_bufs: AtomicU8::new(0),
rx_ppi_ch: AtomicU8::new(0),
}
}
}
/// Interrupt handler.
pub struct InterruptHandler<U: UarteInstance> {
_phantom: PhantomData<U>,
}
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();
let buf_len = s.rx_buf.len();
let half_len = buf_len / 2;
let mut tx = unsafe { s.tx_buf.reader() };
let mut rx = unsafe { s.rx_buf.writer() };
if r.events_error.read().bits() != 0 {
r.events_error.reset();
let errs = r.errorsrc.read();
r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) });
if errs.overrun().bit() {
panic!("BufferedUarte overrun");
}
}
// Received some bytes, wake task.
if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 {
r.intenclr.write(|w| w.rxdrdy().clear());
r.events_rxdrdy.reset();
s.rx_waker.wake();
}
// If not RXing, start.
if s.rx_bufs.load(Ordering::Relaxed) == 0 {
let (ptr, len) = rx.push_buf();
if len >= half_len {
//trace!(" irq_rx: starting {:?}", half_len);
s.rx_bufs.store(1, Ordering::Relaxed);
// Set up the DMA read
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
// Start UARTE Receive transaction
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
rx.push_done(half_len);
r.intenset.write(|w| w.rxstarted().set());
}
}
if r.events_rxstarted.read().bits() != 0 {
//trace!(" irq_rx: rxstarted");
let (ptr, len) = rx.push_buf();
if len >= half_len {
//trace!(" irq_rx: starting second {:?}", half_len);
// Set up the DMA read
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
rx.push_done(half_len);
r.events_rxstarted.reset();
} else {
//trace!(" irq_rx: rxstarted no buf");
r.intenclr.write(|w| w.rxstarted().clear());
}
}
// =============================
// TX end
if r.events_endtx.read().bits() != 0 {
r.events_endtx.reset();
let n = s.tx_count.load(Ordering::Relaxed);
//trace!(" irq_tx: endtx {:?}", n);
tx.pop_done(n);
s.tx_waker.wake();
s.tx_count.store(0, Ordering::Relaxed);
}
// If not TXing, start.
if s.tx_count.load(Ordering::Relaxed) == 0 {
let (ptr, len) = tx.pop_buf();
if len != 0 {
//trace!(" irq_tx: starting {:?}", len);
s.tx_count.store(len, Ordering::Relaxed);
// Set up the DMA write
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
// Start UARTE Transmit transaction
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
}
}
//trace!("irq: end");
}
}
/// Buffered UARTE driver.
pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
inner: RefCell<PeripheralMutex<'d, StateInner<'d, U, T>>>,
_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 instance of a BufferedUarte.
/// Create a new BufferedUarte without hardware flow control.
///
/// See the [module documentation](crate::buffered_uarte) for more details about the intended use.
/// # Panics
///
/// The BufferedUarte uses the provided state to store the buffers and peripheral state. The timer and ppi channels are used to 'emulate' idle line detection so that read operations
/// can return early if there is no data to receive.
/// Panics if `rx_buffer.len()` is odd.
pub fn new(
state: &'d mut State<'d, U, T>,
peri: impl Peripheral<P = U> + 'd,
uarte: impl Peripheral<P = U> + 'd,
timer: impl Peripheral<P = T> + 'd,
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
irq: impl Peripheral<P = U::Interrupt> + '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,
@ -98,12 +246,43 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
rx_buffer: &'d mut [u8],
tx_buffer: &'d mut [u8],
) -> Self {
into_ref!(peri, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts);
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();
let mut timer = Timer::new(timer);
rxd.conf().write(|w| w.input().connect().drive().h0h1());
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
@ -111,92 +290,98 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
txd.conf().write(|w| w.dir().output().drive().h0h1());
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
cts.conf().write(|w| w.input().connect().drive().h0h1());
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()) });
rts.set_high();
rts.conf().write(|w| w.dir().output().drive().h0h1());
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()) });
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
r.config.write(|w| w.parity().variant(config.parity));
// 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(true);
w.hwfc().bit(false);
w.parity().variant(config.parity);
w
});
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
// Enable interrupts
r.intenset.write(|w| w.endrx().set().endtx().set());
// clear errors
let errors = r.errorsrc.read().bits();
r.errorsrc.write(|w| unsafe { w.bits(errors) });
// Disable the irq, let the Registration enable it when everything is set up.
irq.disable();
irq.pend();
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());
// BAUDRATE register values are `baudrate * 2^32 / 16000000`
// source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
//
// We want to stop RX if line is idle for 2 bytes worth of time
// That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
// This gives us the amount of 16M ticks for 20 bits.
let timeout = 0x8000_0000 / (config.baudrate as u32 / 40);
// 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();
timer.set_frequency(Frequency::F16MHz);
timer.cc(0).write(timeout);
timer.cc(0).short_compare_clear();
timer.cc(0).short_compare_stop();
let mut ppi_ch1 = Ppi::new_one_to_two(
ppi_ch1.map_into(),
Event::from_reg(&r.events_rxdrdy),
timer.task_clear(),
timer.task_start(),
);
let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count());
ppi_ch1.enable();
let mut ppi_ch2 = Ppi::new_one_to_one(
ppi_ch2.map_into(),
timer.cc(0).event_compare(),
Task::from_reg(&r.tasks_stoprx),
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.enable();
ppi_ch2.disable();
ppi_group.add_channel(&ppi_ch2);
unsafe { U::Interrupt::steal() }.pend();
unsafe { U::Interrupt::steal() }.enable();
Self {
inner: RefCell::new(PeripheralMutex::new(irq, &mut state.0, move || StateInner {
_peri: peri,
timer,
_ppi_ch1: ppi_ch1,
_ppi_ch2: ppi_ch2,
rx: RingBuffer::new(rx_buffer),
rx_state: RxState::Idle,
rx_waker: WakerRegistration::new(),
tx: RingBuffer::new(tx_buffer),
tx_state: TxState::Idle,
tx_waker: WakerRegistration::new(),
})),
_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) {
self.inner.borrow_mut().with(|state| {
let r = U::regs();
let timeout = 0x8000_0000 / (baudrate as u32 / 40);
state.timer.cc(0).write(timeout);
state.timer.clear();
r.baudrate.write(|w| w.baudrate().variant(baudrate));
});
}
/// Split the UART in reader and writer parts.
@ -206,120 +391,142 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
(BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self })
}
async fn inner_read<'a>(&'a self, buf: &'a mut [u8]) -> Result<usize, core::convert::Infallible> {
async fn inner_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
let data = self.inner_fill_buf().await?;
let n = data.len().min(buf.len());
buf[..n].copy_from_slice(&data[..n]);
self.inner_consume(n);
Ok(n)
}
async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> {
poll_fn(move |cx| {
let mut do_pend = false;
let mut inner = self.inner.borrow_mut();
let res = inner.with(|state| {
compiler_fence(Ordering::SeqCst);
trace!("poll_read");
//trace!("poll_write: {:?}", buf.len());
let s = U::buffered_state();
let mut tx = unsafe { s.tx_buf.writer() };
// We have data ready in buffer? Return it.
let data = state.rx.pop_buf();
if !data.is_empty() {
trace!(" got {:?} {:?}", data.as_ptr() as u32, data.len());
let len = data.len().min(buf.len());
buf[..len].copy_from_slice(&data[..len]);
state.rx.pop(len);
do_pend = true;
return Poll::Ready(Ok(len));
}
trace!(" empty");
state.rx_waker.register(cx.waker());
Poll::Pending
});
if do_pend {
inner.pend();
}
res
})
.await
}
async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, core::convert::Infallible> {
poll_fn(move |cx| {
let mut inner = self.inner.borrow_mut();
let res = inner.with(|state| {
trace!("poll_write: {:?}", buf.len());
let tx_buf = state.tx.push_buf();
let tx_buf = tx.push_slice();
if tx_buf.is_empty() {
trace!("poll_write: pending");
state.tx_waker.register(cx.waker());
//trace!("poll_write: pending");
s.tx_waker.register(cx.waker());
return Poll::Pending;
}
let n = min(tx_buf.len(), buf.len());
tx_buf[..n].copy_from_slice(&buf[..n]);
state.tx.push(n);
tx.push_done(n);
trace!("poll_write: queued {:?}", n);
//trace!("poll_write: queued {:?}", n);
compiler_fence(Ordering::SeqCst);
Self::pend_irq();
Poll::Ready(Ok(n))
});
inner.pend();
res
})
.await
}
async fn inner_flush<'a>(&'a self) -> Result<(), core::convert::Infallible> {
async fn inner_flush<'a>(&'a self) -> Result<(), Error> {
poll_fn(move |cx| {
self.inner.borrow_mut().with(|state| {
trace!("poll_flush");
if !state.tx.is_empty() {
trace!("poll_flush: pending");
state.tx_waker.register(cx.waker());
//trace!("poll_flush");
let s = U::buffered_state();
if !s.tx_buf.is_empty() {
//trace!("poll_flush: pending");
s.tx_waker.register(cx.waker());
return Poll::Pending;
}
Poll::Ready(Ok(()))
})
})
.await
}
async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], core::convert::Infallible> {
async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> {
poll_fn(move |cx| {
self.inner.borrow_mut().with(|state| {
compiler_fence(Ordering::SeqCst);
trace!("fill_buf");
//trace!("poll_read");
// We have data ready in buffer? Return it.
let buf = state.rx.pop_buf();
if !buf.is_empty() {
trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len());
let buf: &[u8] = buf;
// Safety: buffer lives as long as uart
let buf: &[u8] = unsafe { core::mem::transmute(buf) };
return Poll::Ready(Ok(buf));
let r = U::regs();
let s = U::buffered_state();
// Read the RXDRDY counter.
T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) });
let mut end = T::regs().cc[0].read().bits() as usize;
//trace!(" rxdrdy count = {:?}", end);
// We've set a compare channel that resets the counter to 0 when it reaches `len*2`.
// However, it's unclear if that's instant, or there's a small window where you can
// still read `len()*2`.
// This could happen if in one clock cycle the counter is updated, and in the next the
// clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER
// is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one
// clock cycle of the PCLK16M." :shrug:
// So, we wrap the counter ourselves, just in case.
if end > s.rx_buf.len() * 2 {
end = 0
}
trace!(" empty");
state.rx_waker.register(cx.waker());
Poll::<Result<&[u8], core::convert::Infallible>>::Pending
})
// This logic mirrors `atomic_ring_buffer::Reader::pop_buf()`
let mut start = s.rx_buf.start.load(Ordering::Relaxed);
let len = s.rx_buf.len();
if start == end {
//trace!(" empty");
s.rx_waker.register(cx.waker());
r.intenset.write(|w| w.rxdrdy().set_bit());
return Poll::Pending;
}
if start >= len {
start -= len
}
if end >= len {
end -= len
}
let n = if end > start { end - start } else { len - start };
assert!(n != 0);
//trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n);
let buf = s.rx_buf.buf.load(Ordering::Relaxed);
Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) }))
})
.await
}
fn inner_consume(&self, amt: usize) {
let mut inner = self.inner.borrow_mut();
let signal = inner.with(|state| {
let full = state.rx.is_full();
state.rx.pop(amt);
full
});
if signal {
inner.pend();
if amt == 0 {
return;
}
let s = U::buffered_state();
let mut rx = unsafe { s.rx_buf.reader() };
rx.pop_done(amt);
U::regs().intenset.write(|w| w.rxstarted().set());
}
/// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
self.inner_read(buf).await
}
/// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
self.inner_fill_buf().await
}
/// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
pub fn consume(&mut self, amt: usize) {
self.inner_consume(amt)
}
/// Write a buffer into this writer, returning how many bytes were written.
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
self.inner_write(buf).await
}
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
pub async fn flush(&mut self) -> Result<(), Error> {
self.inner_flush().await
}
}
@ -328,36 +535,75 @@ pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> {
inner: &'u BufferedUarte<'d, U, T>,
}
impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> {
/// Write a buffer into this writer, returning how many bytes were written.
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
self.inner.inner_write(buf).await
}
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
pub async fn flush(&mut self) -> Result<(), Error> {
self.inner.inner_flush().await
}
}
/// Writer part of the buffered UARTE driver.
pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> {
inner: &'u BufferedUarte<'d, U, T>,
}
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> {
type Error = core::convert::Infallible;
impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> {
/// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
self.inner.inner_read(buf).await
}
/// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
self.inner.inner_fill_buf().await
}
/// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
pub fn consume(&mut self, amt: usize) {
self.inner.inner_consume(amt)
}
}
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> {
type Error = core::convert::Infallible;
}
#[cfg(feature = "nightly")]
mod _embedded_io {
use super::*;
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> {
type Error = core::convert::Infallible;
}
impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
match *self {}
}
}
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> {
type Error = Error;
}
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> {
type Error = Error;
}
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> {
type Error = Error;
}
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.inner_read(buf).await
}
}
}
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> {
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.inner.inner_read(buf).await
}
}
}
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> {
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> {
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
self.inner_fill_buf().await
}
@ -365,9 +611,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for Bu
fn consume(&mut self, amt: usize) {
self.inner_consume(amt)
}
}
}
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> {
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> {
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
self.inner.inner_fill_buf().await
}
@ -375,9 +621,9 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRea
fn consume(&mut self, amt: usize) {
self.inner.inner_consume(amt)
}
}
}
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> {
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.inner_write(buf).await
}
@ -385,9 +631,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for Buff
async fn flush(&mut self) -> Result<(), Self::Error> {
self.inner_flush().await
}
}
}
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> {
impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.inner.inner_write(buf).await
}
@ -395,9 +641,10 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write
async fn flush(&mut self) -> Result<(), Self::Error> {
self.inner.inner_flush().await
}
}
}
impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> {
fn drop(&mut self) {
let r = U::regs();
@ -418,108 +665,11 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
gpio::deconfigure_pin(r.psel.txd.read().bits());
gpio::deconfigure_pin(r.psel.rts.read().bits());
gpio::deconfigure_pin(r.psel.cts.read().bits());
}
}
impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, U, T> {
type Interrupt = U::Interrupt;
fn on_interrupt(&mut self) {
trace!("irq: start");
let r = U::regs();
loop {
match self.rx_state {
RxState::Idle => {
trace!(" irq_rx: in state idle");
let buf = self.rx.push_buf();
if !buf.is_empty() {
trace!(" irq_rx: starting {:?}", buf.len());
self.rx_state = RxState::Receiving;
// Set up the DMA read
r.rxd.ptr.write(|w|
// The PTR field is a full 32 bits wide and accepts the full range
// of values.
unsafe { w.ptr().bits(buf.as_ptr() as u32) });
r.rxd.maxcnt.write(|w|
// We're giving it the length of the buffer, so no danger of
// accessing invalid memory. We have verified that the length of the
// buffer fits in an `u8`, so the cast to `u8` is also fine.
//
// The MAXCNT field is at least 8 bits wide and accepts the full
// range of values.
unsafe { w.maxcnt().bits(buf.len() as _) });
trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len());
// Start UARTE Receive transaction
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
}
break;
}
RxState::Receiving => {
trace!(" irq_rx: in state receiving");
if r.events_endrx.read().bits() != 0 {
self.timer.stop();
let n: usize = r.rxd.amount.read().amount().bits() as usize;
trace!(" irq_rx: endrx {:?}", n);
self.rx.push(n);
r.events_endrx.reset();
self.rx_waker.wake();
self.rx_state = RxState::Idle;
} else {
break;
}
}
}
}
loop {
match self.tx_state {
TxState::Idle => {
trace!(" irq_tx: in state Idle");
let buf = self.tx.pop_buf();
if !buf.is_empty() {
trace!(" irq_tx: starting {:?}", buf.len());
self.tx_state = TxState::Transmitting(buf.len());
// Set up the DMA write
r.txd.ptr.write(|w|
// The PTR field is a full 32 bits wide and accepts the full range
// of values.
unsafe { w.ptr().bits(buf.as_ptr() as u32) });
r.txd.maxcnt.write(|w|
// We're giving it the length of the buffer, so no danger of
// accessing invalid memory. We have verified that the length of the
// buffer fits in an `u8`, so the cast to `u8` is also fine.
//
// The MAXCNT field is 8 bits wide and accepts the full range of
// values.
unsafe { w.maxcnt().bits(buf.len() as _) });
// Start UARTE Transmit transaction
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
}
break;
}
TxState::Transmitting(n) => {
trace!(" irq_tx: in state Transmitting");
if r.events_endtx.read().bits() != 0 {
r.events_endtx.reset();
trace!(" irq_tx: endtx {:?}", n);
self.tx.pop(n);
self.tx_waker.wake();
self.tx_state = TxState::Idle;
} else {
break;
}
}
}
}
trace!("irq: end");
let s = U::buffered_state();
unsafe {
s.rx_buf.deinit();
s.tx_buf.deinit();
}
}
}

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,
@ -250,6 +250,16 @@ embassy_hal_common::peripherals! {
TIMER1,
TIMER2,
// QSPI
QSPI,
// PDM
PDM0,
// QDEC
QDEC0,
QDEC1,
// GPIOTE
GPIOTE_CH0,
GPIOTE_CH1,
@ -393,6 +403,13 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
impl_timer!(TIMER1, TIMER1, TIMER1);
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

@ -315,6 +315,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
// =======================
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct PortInputFuture<'a> {
pin: PeripheralRef<'a, AnyPin>,
}

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

@ -37,7 +37,6 @@ pub(crate) mod util;
#[cfg(feature = "_time-driver")]
mod time_driver;
#[cfg(feature = "nightly")]
pub mod buffered_uarte;
pub mod gpio;
#[cfg(feature = "gpiote")]
@ -48,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(feature = "nrf52840")]
#[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;
@ -96,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
@ -112,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

@ -6,7 +6,7 @@ use crate::{pac, Peripheral};
const DPPI_ENABLE_BIT: u32 = 0x8000_0000;
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
fn regs() -> &'static pac::dppic::RegisterBlock {
pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock {
unsafe { &*pac::DPPIC::ptr() }
}

View File

@ -17,16 +17,16 @@
use core::ptr::NonNull;
use embassy_hal_common::{impl_peripheral, PeripheralRef};
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
use crate::{peripherals, Peripheral};
#[cfg(feature = "_dppi")]
mod dppi;
#[cfg(feature = "_ppi")]
mod ppi;
#[cfg_attr(feature = "_dppi", path = "dppi.rs")]
#[cfg_attr(feature = "_ppi", path = "ppi.rs")]
mod _version;
pub(crate) use _version::*;
/// An instance of the Programmable peripheral interconnect on nRF devices.
/// PPI channel driver.
pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
ch: PeripheralRef<'d, C>,
#[cfg(feature = "_dppi")]
@ -35,6 +35,88 @@ pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize
tasks: [Task; TASK_COUNT],
}
/// PPI channel group driver.
pub struct PpiGroup<'d, G: Group> {
g: PeripheralRef<'d, G>,
}
impl<'d, G: Group> PpiGroup<'d, G> {
/// Create a new PPI group driver.
///
/// The group is initialized as containing no channels.
pub fn new(g: impl Peripheral<P = G> + 'd) -> Self {
into_ref!(g);
let r = regs();
let n = g.number();
r.chg[n].write(|w| unsafe { w.bits(0) });
Self { g }
}
/// Add a PPI channel to this group.
///
/// If the channel is already in the group, this is a no-op.
pub fn add_channel<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>(
&mut self,
ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>,
) {
let r = regs();
let ng = self.g.number();
let nc = ch.ch.number();
r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) });
}
/// Remove a PPI channel from this group.
///
/// If the channel is already not in the group, this is a no-op.
pub fn remove_channel<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>(
&mut self,
ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>,
) {
let r = regs();
let ng = self.g.number();
let nc = ch.ch.number();
r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) });
}
/// Enable all the channels in this group.
pub fn enable_all(&mut self) {
let n = self.g.number();
regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) });
}
/// Disable all the channels in this group.
pub fn disable_all(&mut self) {
let n = self.g.number();
regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) });
}
/// Get a reference to the "enable all" task.
///
/// When triggered, it will enable all the channels in this group.
pub fn task_enable_all(&self) -> Task {
let n = self.g.number();
Task::from_reg(&regs().tasks_chg[n].en)
}
/// Get a reference to the "disable all" task.
///
/// When triggered, it will disable all the channels in this group.
pub fn task_disable_all(&self) -> Task {
let n = self.g.number();
Task::from_reg(&regs().tasks_chg[n].dis)
}
}
impl<'d, G: Group> Drop for PpiGroup<'d, G> {
fn drop(&mut self) {
let r = regs();
let n = self.g.number();
r.chg[n].write(|w| unsafe { w.bits(0) });
}
}
#[cfg(feature = "_dppi")]
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
@ -112,7 +194,7 @@ pub(crate) mod sealed {
}
/// Interface for PPI channels.
pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized {
pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized + 'static {
/// Returns the number of the channel
fn number(&self) -> usize;
}
@ -130,7 +212,7 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
}
/// Interface for a group of PPI channels.
pub trait Group: sealed::Group + Sized {
pub trait Group: sealed::Group + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static {
/// Returns the number of the group.
fn number(&self) -> usize;
/// Convert into a type erased group.
@ -248,6 +330,12 @@ macro_rules! impl_group {
$number
}
}
impl From<peripherals::$type> for crate::ppi::AnyGroup {
fn from(val: peripherals::$type) -> Self {
crate::ppi::Group::degrade(val)
}
}
};
}

View File

@ -14,7 +14,7 @@ impl Event {
}
}
fn regs() -> &'static pac::ppi::RegisterBlock {
pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
unsafe { &*pac::PPI::ptr() }
}

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,19 +3,21 @@
#![macro_use]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::ptr;
use core::task::Poll;
use embassy_hal_common::drop::OnDrop;
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 {
@ -82,6 +84,8 @@ pub struct Config {
pub spi_mode: SpiMode,
/// Addressing mode (24-bit or 32-bit)
pub address_mode: AddressMode,
/// Flash memory capacity in bytes. This is the value reported by the `embedded-storage` traits.
pub capacity: u32,
}
impl Default for Config {
@ -96,6 +100,7 @@ impl Default for Config {
sck_delay: 80,
spi_mode: SpiMode::MODE0,
address_mode: AddressMode::_24BIT,
capacity: 0,
}
}
}
@ -110,17 +115,35 @@ pub enum Error {
// TODO add "not in data memory" error and check for it
}
/// QSPI flash driver.
pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
irq: PeripheralRef<'d, T::Interrupt>,
dpm_enabled: bool,
/// Interrupt handler.
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
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> {
_peri: PeripheralRef<'d, T>,
dpm_enabled: bool,
capacity: u32,
}
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,
@ -128,30 +151,31 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
io2: impl Peripheral<P = impl GpioPin> + 'd,
io3: impl Peripheral<P = impl GpioPin> + 'd,
config: Config,
) -> Qspi<'d, T, FLASH_SIZE> {
into_ref!(irq, sck, csn, io0, io1, io2, io3);
) -> Self {
into_ref!(qspi, sck, csn, io0, io1, io2, io3);
let r = T::regs();
sck.set_high();
csn.set_high();
io0.set_high();
io1.set_high();
io2.set_high();
io3.set_high();
sck.conf().write(|w| w.dir().output().drive().h0h1());
csn.conf().write(|w| w.dir().output().drive().h0h1());
io0.conf().write(|w| w.dir().output().drive().h0h1());
io1.conf().write(|w| w.dir().output().drive().h0h1());
io2.conf().write(|w| w.dir().output().drive().h0h1());
io3.conf().write(|w| w.dir().output().drive().h0h1());
macro_rules! config_pin {
($pin:ident) => {
$pin.set_high();
$pin.conf().write(|w| {
w.dir().output();
w.drive().h0h1();
#[cfg(feature = "_nrf5340-s")]
w.mcusel().peripheral();
w
});
r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) });
};
}
r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) });
r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) });
r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) });
r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) });
r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) });
config_pin!(sck);
config_pin!(csn);
config_pin!(io0);
config_pin!(io1);
config_pin!(io2);
config_pin!(io3);
r.ifconfig0.write(|w| {
w.addrmode().variant(config.address_mode);
@ -183,16 +207,16 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
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,
};
r.events_ready.reset();
@ -205,16 +229,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
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);
@ -303,7 +317,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
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(());
}
@ -321,17 +335,15 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
}
}
fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
// TODO: Return these as errors instead.
assert_eq!(data.as_ptr() as u32 % 4, 0);
assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0);
if address > FLASH_SIZE {
return Err(Error::OutOfBounds);
}
assert_eq!(address % 4, 0);
let r = T::regs();
r.read.src.write(|w| unsafe { w.src().bits(address as u32) });
r.read.src.write(|w| unsafe { w.src().bits(address) });
r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) });
r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
@ -342,18 +354,15 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
Ok(())
}
fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
// TODO: Return these as errors instead.
assert_eq!(data.as_ptr() as u32 % 4, 0);
assert_eq!(data.len() as u32 % 4, 0);
assert_eq!(address as u32 % 4, 0);
if address > FLASH_SIZE {
return Err(Error::OutOfBounds);
}
assert_eq!(address % 4, 0);
let r = T::regs();
r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
r.write.dst.write(|w| unsafe { w.dst().bits(address as u32) });
r.write.dst.write(|w| unsafe { w.dst().bits(address) });
r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
r.events_ready.reset();
@ -363,14 +372,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
Ok(())
}
fn start_erase(&mut self, address: usize) -> Result<(), Error> {
assert_eq!(address as u32 % 4096, 0);
if address > FLASH_SIZE {
return Err(Error::OutOfBounds);
}
fn start_erase(&mut self, address: u32) -> Result<(), Error> {
// TODO: Return these as errors instead.
assert_eq!(address % 4096, 0);
let r = T::regs();
r.erase.ptr.write(|w| unsafe { w.ptr().bits(address as u32) });
r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) });
r.erase.len.write(|w| w.len()._4kb());
r.events_ready.reset();
@ -380,8 +387,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
Ok(())
}
/// Read data from the flash memory.
pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
/// Raw QSPI read.
///
/// The difference with `read` is that this does not do bounds checks
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
let ondrop = OnDrop::new(Self::blocking_wait_ready);
self.start_read(address, data)?;
@ -392,8 +403,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
Ok(())
}
/// Write data to the flash memory.
pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
/// Raw QSPI write.
///
/// The difference with `write` is that this does not do bounds checks
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
let ondrop = OnDrop::new(Self::blocking_wait_ready);
self.start_write(address, data)?;
@ -404,8 +419,46 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
Ok(())
}
/// Raw QSPI read, blocking version.
///
/// The difference with `blocking_read` is that this does not do bounds checks
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
self.start_read(address, data)?;
Self::blocking_wait_ready();
Ok(())
}
/// Raw QSPI write, blocking version.
///
/// The difference with `blocking_write` is that this does not do bounds checks
/// against the flash capacity. It is intended for use when QSPI is used as
/// a raw bus, not with flash memory.
pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
self.start_write(address, data)?;
Self::blocking_wait_ready();
Ok(())
}
/// Read data from the flash memory.
pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
self.bounds_check(address, data.len())?;
self.read_raw(address, data).await
}
/// Write data to the flash memory.
pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
self.bounds_check(address, data.len())?;
self.write_raw(address, data).await
}
/// Erase a sector on the flash memory.
pub async fn erase(&mut self, address: usize) -> Result<(), Error> {
pub async fn erase(&mut self, address: u32) -> Result<(), Error> {
if address >= self.capacity {
return Err(Error::OutOfBounds);
}
let ondrop = OnDrop::new(Self::blocking_wait_ready);
self.start_erase(address)?;
@ -417,28 +470,39 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
}
/// Read data from the flash memory, blocking version.
pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
self.start_read(address, data)?;
Self::blocking_wait_ready();
Ok(())
pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
self.bounds_check(address, data.len())?;
self.blocking_read_raw(address, data)
}
/// Write data to the flash memory, blocking version.
pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
self.start_write(address, data)?;
Self::blocking_wait_ready();
Ok(())
pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
self.bounds_check(address, data.len())?;
self.blocking_write_raw(address, data)
}
/// Erase a sector on the flash memory, blocking version.
pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> {
pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> {
if address >= self.capacity {
return Err(Error::OutOfBounds);
}
self.start_erase(address)?;
Self::blocking_wait_ready();
Ok(())
}
fn bounds_check(&self, address: u32, len: usize) -> Result<(), Error> {
let len_u32: u32 = len.try_into().map_err(|_| Error::OutOfBounds)?;
let end_address = address.checked_add(len_u32).ok_or(Error::OutOfBounds)?;
if end_address > self.capacity {
return Err(Error::OutOfBounds);
}
Ok(())
}
}
impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> {
impl<'d, T: Instance> Drop for Qspi<'d, T> {
fn drop(&mut self) {
let r = T::regs();
@ -468,8 +532,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE>
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.
@ -483,9 +545,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE>
}
}
use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> {
impl<'d, T: Instance> ErrorType for Qspi<'d, T> {
type Error = Error;
}
@ -495,66 +555,66 @@ impl NorFlashError for Error {
}
}
impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> {
const READ_SIZE: usize = 4;
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(offset as usize, bytes)?;
self.blocking_read(offset, bytes)?;
Ok(())
}
fn capacity(&self) -> usize {
FLASH_SIZE
self.capacity as usize
}
}
impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> {
impl<'d, T: Instance> NorFlash for Qspi<'d, T> {
const WRITE_SIZE: usize = 4;
const ERASE_SIZE: usize = 4096;
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
for address in (from as usize..to as usize).step_by(<Self as NorFlash>::ERASE_SIZE) {
for address in (from..to).step_by(<Self as NorFlash>::ERASE_SIZE) {
self.blocking_erase(address)?;
}
Ok(())
}
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(offset as usize, bytes)?;
self.blocking_write(offset, bytes)?;
Ok(())
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "nightly")]
{
#[cfg(feature = "nightly")]
mod _eh1 {
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> {
use super::*;
impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> {
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
self.write(offset as usize, data).await
self.write(offset, data).await
}
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
for address in (from..to).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
self.erase(address).await?
}
Ok(())
}
}
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> {
const READ_SIZE: usize = 4;
async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
self.read(address as usize, data).await
self.read(address, data).await
}
fn capacity(&self) -> usize {
FLASH_SIZE
}
self.capacity as usize
}
}
}
@ -562,27 +622,27 @@ cfg_if::cfg_if! {
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;
}
@ -590,7 +650,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,73 +85,49 @@ 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)
}
}
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.
pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self {
Self::new_inner(timer)
Self::new_inner(timer, false)
}
}
impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
/// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
/// Create a new `Timer` driver in counter mode.
///
/// This is used by the public constructors.
fn new_inner(timer: impl Peripheral<P = T> + 'd) -> Self {
/// 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)
}
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.
this.stop();
// Set the instance to timer mode.
if is_counter {
regs.mode.write(|w| w.mode().counter());
} else {
regs.mode.write(|w| w.mode().timer());
}
// Make the counter's max value as high as possible.
// TODO: is there a reason someone would want to set this lower?
@ -225,6 +187,14 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
Task::from_reg(&T::regs().tasks_clear)
}
/// Returns the COUNT task, for use with PPI.
///
/// When triggered, this task increments the timer's counter by 1.
/// Only works in counter mode.
pub fn task_count(&self) -> Task {
Task::from_reg(&T::regs().tasks_count)
}
/// Change the timer's frequency.
///
/// This will stop the timer if it isn't already stopped,
@ -239,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,
}
}
}
@ -275,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);
@ -883,6 +884,7 @@ pub(crate) mod sealed {
pub trait Instance {
fn regs() -> &'static pac::uarte0::RegisterBlock;
fn state() -> &'static State;
fn buffered_state() -> &'static crate::buffered_uarte::State;
}
}
@ -902,6 +904,10 @@ macro_rules! impl_uarte {
static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new();
&STATE
}
fn buffered_state() -> &'static crate::buffered_uarte::State {
static STATE: crate::buffered_uarte::State = crate::buffered_uarte::State::new();
&STATE
}
}
impl crate::uarte::Instance for peripherals::$type {
type Interrupt = crate::interrupt::$irq;

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

@ -7,6 +7,7 @@ use embassy_hal_common::into_ref;
use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal_02::adc::{Channel, OneShot};
use crate::gpio::Pin;
use crate::interrupt::{self, InterruptExt};
use crate::peripherals::ADC;
use crate::{pac, peripherals, Peripheral};
@ -90,9 +91,17 @@ impl<'d> Adc<'d> {
}
}
pub async fn read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
let r = Self::regs();
unsafe {
// disable pull-down and pull-up resistors
// pull-down resistors are enabled by default
pin.pad_ctrl().modify(|w| {
w.set_ie(true);
let (pu, pd) = (false, false);
w.set_pue(pu);
w.set_pde(pd);
});
r.cs().modify(|w| {
w.set_ainsel(PIN::channel());
w.set_start_once(true)

View File

@ -151,6 +151,7 @@ fn copy_inner<'a, C: Channel>(
Transfer::new(ch)
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Transfer<'a, C: Channel> {
channel: PeripheralRef<'a, C>,
}

View File

@ -174,7 +174,7 @@ unsafe fn IO_IRQ_BANK0() {
w.set_edge_low(pin_group, false);
}
InterruptTrigger::LevelHigh => {
debug!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin);
trace!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin);
w.set_level_high(pin_group, false);
}
InterruptTrigger::LevelLow => {
@ -193,6 +193,7 @@ unsafe fn IO_IRQ_BANK0() {
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct InputFuture<'a, T: Pin> {
pin: PeripheralRef<'a, T>,
level: InterruptTrigger,
@ -213,7 +214,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
critical_section::with(|_| {
pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
InterruptTrigger::LevelHigh => {
debug!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
w.set_level_high(pin_group, true);
}
InterruptTrigger::LevelLow => {
@ -260,45 +261,45 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
// the pin and if it has been disabled that means it was done by the
// interrupt service routine, so we then know that the event/trigger
// happened and Poll::Ready will be returned.
debug!("{:?} for pin {}", self.level, self.pin.pin());
trace!("{:?} for pin {}", self.level, self.pin.pin());
match self.level {
InterruptTrigger::AnyEdge => {
if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
#[rustfmt::skip]
debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::LevelHigh => {
if !inte.level_high(pin_group) {
#[rustfmt::skip]
debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::LevelLow => {
if !inte.level_low(pin_group) {
#[rustfmt::skip]
debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::EdgeHigh => {
if !inte.edge_high(pin_group) {
#[rustfmt::skip]
debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::EdgeLow => {
if !inte.edge_low(pin_group) {
#[rustfmt::skip]
debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
}
debug!("InputFuture::poll return Poll::Pending");
trace!("InputFuture::poll return Poll::Pending");
Poll::Pending
}
}

View File

@ -120,6 +120,7 @@ unsafe fn PIO1_IRQ_0() {
}
/// Future that waits for TX-FIFO to become writable
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> {
sm: &'a mut SM,
pio: PhantomData<PIO>,
@ -182,6 +183,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'
}
/// Future that waits for RX-FIFO to become readable
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> {
sm: &'a mut SM,
pio: PhantomData<PIO>,
@ -241,6 +243,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
}
/// Future that waits for IRQ
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct IrqFuture<PIO: PioInstance> {
pio: PhantomData<PIO>,
irq_no: u8,

View File

@ -299,7 +299,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
}
}
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
fn new_inner(
_uart: impl Peripheral<P = T> + 'd,
mut tx: PeripheralRef<'d, AnyPin>,
@ -350,23 +350,7 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
pin.pad_ctrl().write(|w| w.set_ie(true));
}
let clk_base = crate::clocks::clk_peri_freq();
let baud_rate_div = (8 * clk_base) / config.baudrate;
let mut baud_ibrd = baud_rate_div >> 7;
let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
if baud_ibrd == 0 {
baud_ibrd = 1;
baud_fbrd = 0;
} else if baud_ibrd >= 65535 {
baud_ibrd = 65535;
baud_fbrd = 0;
}
// Load PL011's baud divisor registers
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
Self::set_baudrate_inner(config.baudrate);
let (pen, eps) = match config.parity {
Parity::ParityNone => (false, false),
@ -400,6 +384,35 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
});
}
}
/// sets baudrate on runtime
pub fn set_baudrate(&mut self, baudrate: u32) {
Self::set_baudrate_inner(baudrate);
}
fn set_baudrate_inner(baudrate: u32) {
let r = T::regs();
let clk_base = crate::clocks::clk_peri_freq();
let baud_rate_div = (8 * clk_base) / baudrate;
let mut baud_ibrd = baud_rate_div >> 7;
let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
if baud_ibrd == 0 {
baud_ibrd = 1;
baud_fbrd = 0;
} else if baud_ibrd >= 65535 {
baud_ibrd = 65535;
baud_fbrd = 0;
}
unsafe {
// Load PL011's baud divisor registers
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
}
}
}
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {

View File

@ -273,6 +273,7 @@ mod transfers {
Transfer::new(channel)
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct Transfer<'a, C: Channel> {
channel: PeripheralRef<'a, C>,
}

View File

@ -5,6 +5,7 @@
mod _version;
pub mod generic_smi;
use core::mem::MaybeUninit;
use core::task::Context;
use embassy_net_driver::{Capabilities, LinkState};
@ -39,6 +40,13 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX],
}
}
// Allow to initialize a Self without requiring it to go on the stack
pub fn init(this: &mut MaybeUninit<Self>) {
unsafe {
this.as_mut_ptr().write_bytes(0u8, 1);
}
}
}
static WAKER: AtomicWaker = AtomicWaker::new();

View File

@ -198,6 +198,7 @@ mod eha {
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct ExtiInputFuture<'a> {
pin: u8,
phantom: PhantomData<&'a mut AnyPin>,

View File

@ -456,13 +456,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
set_rxdmaen(T::REGS, true);
}
// SPIv3 clears rxfifo on SPE=0
#[cfg(not(any(spi_v3, spi_v4)))]
flush_rx_fifo(T::REGS);
set_rxdmaen(T::REGS, true);
let clock_byte_count = data.len();
let rx_request = self.rxdma.request();
@ -510,13 +511,14 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
T::REGS.cr1().modify(|w| {
w.set_spe(false);
});
set_rxdmaen(T::REGS, true);
}
// SPIv3 clears rxfifo on SPE=0
#[cfg(not(any(spi_v3, spi_v4)))]
flush_rx_fifo(T::REGS);
set_rxdmaen(T::REGS, true);
let rx_request = self.rxdma.request();
let rx_src = T::REGS.rx_ptr();
unsafe { self.rxdma.start_read(rx_request, rx_src, read, Default::default()) };

View File

@ -181,6 +181,7 @@ where
}
/// Future returned by [`Channel::recv`] and [`Receiver::recv`].
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct RecvFuture<'ch, M, T, const N: usize>
where
M: RawMutex,
@ -203,6 +204,7 @@ where
}
/// Future returned by [`DynamicReceiver::recv`].
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct DynamicRecvFuture<'ch, T> {
channel: &'ch dyn DynamicChannel<T>,
}
@ -219,6 +221,7 @@ impl<'ch, T> Future for DynamicRecvFuture<'ch, T> {
}
/// Future returned by [`Channel::send`] and [`Sender::send`].
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct SendFuture<'ch, M, T, const N: usize>
where
M: RawMutex,
@ -250,6 +253,7 @@ where
impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {}
/// Future returned by [`DynamicSender::send`].
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct DynamicSendFuture<'ch, T> {
channel: &'ch dyn DynamicChannel<T>,
message: Option<T>,

View File

@ -48,6 +48,7 @@ where
}
/// Future returned by [`Pipe::write`] and [`Writer::write`].
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct WriteFuture<'p, M, const N: usize>
where
M: RawMutex,
@ -110,6 +111,7 @@ where
}
/// Future returned by [`Pipe::read`] and [`Reader::read`].
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct ReadFuture<'p, M, const N: usize>
where
M: RawMutex,

View File

@ -1,4 +1,4 @@
use core::future::Future;
use core::future::{poll_fn, Future};
use core::pin::Pin;
use core::task::{Context, Poll, Waker};
@ -26,6 +26,7 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out
}
/// A future that completes at a specified [Instant](struct.Instant.html).
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Timer {
expires_at: Instant,
yielded_once: bool,
@ -131,6 +132,20 @@ impl Ticker {
let expires_at = Instant::now() + duration;
Self { expires_at, duration }
}
/// Waits for the next tick
pub fn next(&mut self) -> impl Future<Output = ()> + '_ {
poll_fn(|cx| {
if self.expires_at <= Instant::now() {
let dur = self.duration;
self.expires_at += dur;
Poll::Ready(())
} else {
schedule_wake(self.expires_at, cx.waker());
Poll::Pending
}
})
}
}
impl Unpin for Ticker {}

View File

@ -276,6 +276,106 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
pub async fn wait_connection(&mut self) {
self.read_ep.wait_enabled().await
}
/// Split the class into a sender and receiver.
///
/// This allows concurrently sending and receiving packets from separate tasks.
pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) {
(
Sender {
write_ep: self.write_ep,
control: self.control,
},
Receiver {
read_ep: self.read_ep,
control: self.control,
},
)
}
}
/// CDC ACM class packet sender.
///
/// You can obtain a `Sender` with [`CdcAcmClass::split`]
pub struct Sender<'d, D: Driver<'d>> {
write_ep: D::EndpointIn,
control: &'d ControlShared,
}
impl<'d, D: Driver<'d>> Sender<'d, D> {
/// Gets the maximum packet size in bytes.
pub fn max_packet_size(&self) -> u16 {
// The size is the same for both endpoints.
self.write_ep.info().max_packet_size
}
/// Gets the current line coding. The line coding contains information that's mainly relevant
/// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding {
self.control.line_coding.lock(|x| x.get())
}
/// Gets the DTR (data terminal ready) state
pub fn dtr(&self) -> bool {
self.control.dtr.load(Ordering::Relaxed)
}
/// Gets the RTS (request to send) state
pub fn rts(&self) -> bool {
self.control.rts.load(Ordering::Relaxed)
}
/// Writes a single packet into the IN endpoint.
pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> {
self.write_ep.write(data).await
}
/// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) {
self.write_ep.wait_enabled().await
}
}
/// CDC ACM class packet receiver.
///
/// You can obtain a `Receiver` with [`CdcAcmClass::split`]
pub struct Receiver<'d, D: Driver<'d>> {
read_ep: D::EndpointOut,
control: &'d ControlShared,
}
impl<'d, D: Driver<'d>> Receiver<'d, D> {
/// Gets the maximum packet size in bytes.
pub fn max_packet_size(&self) -> u16 {
// The size is the same for both endpoints.
self.read_ep.info().max_packet_size
}
/// Gets the current line coding. The line coding contains information that's mainly relevant
/// for USB to UART serial port emulators, and can be ignored if not relevant.
pub fn line_coding(&self) -> LineCoding {
self.control.line_coding.lock(|x| x.get())
}
/// Gets the DTR (data terminal ready) state
pub fn dtr(&self) -> bool {
self.control.dtr.load(Ordering::Relaxed)
}
/// Gets the RTS (request to send) state
pub fn rts(&self) -> bool {
self.control.rts.load(Ordering::Relaxed)
}
/// Reads a single packet from the OUT endpoint.
pub async fn read_packet(&mut self, data: &mut [u8]) -> Result<usize, EndpointError> {
self.read_ep.read(data).await
}
/// Waits for the USB host to enable this interface
pub async fn wait_connection(&mut self) {
self.read_ep.wait_enabled().await
}
}
/// Number of stop bits for LineCoding

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,12 +4,15 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_nrf::buffered_uarte::{BufferedUarte, State};
use embassy_nrf::{interrupt, uarte};
use embedded_io::asynch::{BufRead, Write};
use futures::pin_mut;
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());
@ -20,25 +23,19 @@ 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 state = State::new();
// Please note - important to have hardware flow control (https://github.com/embassy-rs/embassy/issues/536)
let u = BufferedUarte::new(
&mut state,
let mut u = BufferedUarte::new(
p.UARTE0,
p.TIMER0,
p.PPI_CH0,
p.PPI_CH1,
irq,
p.PPI_GROUP0,
Irqs,
p.P0_08,
p.P0_06,
p.P0_07,
p.P0_05,
config,
&mut rx_buffer,
&mut tx_buffer,
);
pin_mut!(u);
info!("uarte initialized!");

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

@ -57,11 +57,14 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::mem;
use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry;
use defmt::{info, unwrap};
use embassy_nrf::executor::{Executor, InterruptExecutor};
use embassy_nrf::interrupt;
use embassy_nrf::interrupt::InterruptExt;
use embassy_nrf::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
@ -108,28 +111,35 @@ async fn run_low() {
}
}
static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new();
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new();
static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
#[interrupt]
unsafe fn SWI1_EGU1() {
EXECUTOR_HIGH.on_interrupt()
}
#[interrupt]
unsafe fn SWI0_EGU0() {
EXECUTOR_MED.on_interrupt()
}
#[entry]
fn main() -> ! {
info!("Hello World!");
let _p = embassy_nrf::init(Default::default());
let mut nvic: NVIC = unsafe { mem::transmute(()) };
// High-priority executor: SWI1_EGU1, priority level 6
let irq = interrupt::take!(SWI1_EGU1);
irq.set_priority(interrupt::Priority::P6);
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
let spawner = executor.start();
unsafe { nvic.set_priority(Interrupt::SWI1_EGU1, 6 << 5) };
let spawner = EXECUTOR_HIGH.start(Interrupt::SWI1_EGU1);
unwrap!(spawner.spawn(run_high()));
// Medium-priority executor: SWI0_EGU0, priority level 7
let irq = interrupt::take!(SWI0_EGU0);
irq.set_priority(interrupt::Priority::P7);
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
let spawner = executor.start();
unsafe { nvic.set_priority(Interrupt::SWI0_EGU0, 7 << 5) };
let spawner = EXECUTOR_MED.start(Interrupt::SWI0_EGU0);
unwrap!(spawner.spawn(run_med()));
// Low priority executor: runs in thread mode, using WFE/SEV

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

@ -4,7 +4,8 @@
use defmt::{assert_eq, info, unwrap};
use embassy_executor::Spawner;
use embassy_nrf::{interrupt, qspi};
use embassy_nrf::qspi::Frequency;
use embassy_nrf::{bind_interrupts, peripherals, qspi};
use {defmt_rtt as _, panic_probe as _};
const PAGE_SIZE: usize = 4096;
@ -14,18 +15,23 @@ 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());
// Config for the MX25R64 present in the nRF52840 DK
let mut config = qspi::Config::default();
config.capacity = 8 * 1024 * 1024; // 8 MB
config.frequency = Frequency::M32;
config.read_opcode = qspi::ReadOpcode::READ4IO;
config.write_opcode = qspi::WriteOpcode::PP4IO;
config.write_page_size = qspi::WritePageSize::_256BYTES;
let irq = interrupt::take!(QSPI);
let mut q: qspi::Qspi<_, 67108864> = 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,
let mut q = qspi::Qspi::new(
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];
@ -52,23 +58,23 @@ async fn main(_spawner: Spawner) {
for i in 0..8 {
info!("page {:?}: erasing... ", i);
unwrap!(q.erase(i * PAGE_SIZE).await);
unwrap!(q.erase(i * PAGE_SIZE as u32).await);
for j in 0..PAGE_SIZE {
buf.0[j] = pattern((j + i * PAGE_SIZE) as u32);
buf.0[j] = pattern((j as u32 + i * PAGE_SIZE as u32) as u32);
}
info!("programming...");
unwrap!(q.write(i * PAGE_SIZE, &buf.0).await);
unwrap!(q.write(i * PAGE_SIZE as u32, &buf.0).await);
}
for i in 0..8 {
info!("page {:?}: reading... ", i);
unwrap!(q.read(i * PAGE_SIZE, &mut buf.0).await);
unwrap!(q.read(i * PAGE_SIZE as u32, &mut buf.0).await);
info!("verifying...");
for j in 0..PAGE_SIZE {
assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32));
assert_eq!(buf.0[j], pattern((j as u32 + i * PAGE_SIZE as u32) as u32));
}
}

View File

@ -6,7 +6,8 @@ use core::mem;
use defmt::{info, unwrap};
use embassy_executor::Spawner;
use embassy_nrf::{interrupt, qspi};
use embassy_nrf::qspi::Frequency;
use embassy_nrf::{bind_interrupts, peripherals, qspi};
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
@ -15,14 +16,19 @@ 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
let mut config = qspi::Config::default();
config.capacity = 8 * 1024 * 1024; // 8 MB
config.frequency = Frequency::M32;
config.read_opcode = qspi::ReadOpcode::READ4IO;
config.write_opcode = qspi::WriteOpcode::PP4IO;
config.write_page_size = qspi::WritePageSize::_256BYTES;
@ -31,9 +37,9 @@ async fn main(_p: Spawner) {
exit_time: 3, // tRDP = 35uS
});
let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
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 {
@ -46,31 +53,8 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
stack.run().await
}
#[inline(never)]
pub fn test_function() -> (usize, u32, [u32; 2]) {
let mut array = [3; 2];
let mut index = 0;
let mut result = 0;
for x in [1, 2] {
if x == 1 {
array[1] = 99;
} else {
index = if x == 2 { 1 } else { 0 };
// grabs value from array[0], not array[1]
result = array[index];
}
}
(index, result, array)
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
info!("{:?}", test_function());
let p = embassy_nrf::init(Default::default());
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
@ -79,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);
@ -105,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.
@ -131,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,24 +4,13 @@ name = "embassy-nrf5340-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[features]
default = ["nightly"]
nightly = [
"embassy-executor/nightly",
"embassy-nrf/nightly",
"embassy-net/nightly",
"embassy-nrf/unstable-traits",
"embassy-usb",
"embedded-io/async",
"embassy-net",
]
[dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [
"defmt",
] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [
"nightly",
"defmt",
"integrated-timers",
] }
@ -30,6 +19,8 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = [
"defmt-timestamp-uptime",
] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
"nightly",
"unstable-traits",
"defmt",
"nrf5340-app-s",
"time-driver-rtc1",
@ -37,16 +28,16 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
"unstable-pac",
] }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
"nightly",
"defmt",
"tcp",
"dhcpv4",
"medium-ethernet",
], optional = true }
] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
"defmt",
], optional = true }
embedded-io = "0.4.0"
] }
embedded-io = { version = "0.4.0", features = [ "async" ]}
defmt = "0.3"
defmt-rtt = "0.4"

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

@ -65,7 +65,7 @@ async fn main_task(spawner: Spawner) {
let seed = u64::from_le_bytes(seed);
// Init network stack
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed));
// Launch network task
spawner.spawn(net_task(stack)).unwrap();

View File

@ -65,7 +65,7 @@ async fn main_task(spawner: Spawner) {
let seed = u64::from_le_bytes(seed);
// Init network stack
let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed));
// Launch network task
spawner.spawn(net_task(stack)).unwrap();

View File

@ -62,7 +62,7 @@ async fn main_task(spawner: Spawner) {
let seed = u64::from_le_bytes(seed);
// Init network stack
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<3>::new()), seed));
// Launch network task
spawner.spawn(net_task(stack)).unwrap();

View File

@ -15,5 +15,5 @@ panic-probe = "0.3"
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] }
static_cell = "1.0"

View File

@ -57,11 +57,14 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::mem;
use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry;
use defmt::*;
use embassy_stm32::executor::{Executor, InterruptExecutor};
use embassy_stm32::interrupt;
use embassy_stm32::interrupt::InterruptExt;
use embassy_stm32::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
@ -108,27 +111,34 @@ async fn run_low() {
}
}
static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::USART1>> = StaticCell::new();
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::USART2>> = StaticCell::new();
static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
#[interrupt]
unsafe fn USART1() {
EXECUTOR_HIGH.on_interrupt()
}
#[interrupt]
unsafe fn USART2() {
EXECUTOR_MED.on_interrupt()
}
#[entry]
fn main() -> ! {
// Initialize and create handle for devicer peripherals
let _p = embassy_stm32::init(Default::default());
let mut nvic: NVIC = unsafe { mem::transmute(()) };
// High-priority executor: USART1, priority level 6
let irq = interrupt::take!(USART1);
irq.set_priority(interrupt::Priority::P6);
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
let spawner = executor.start();
unsafe { nvic.set_priority(Interrupt::USART1, 6 << 4) };
let spawner = EXECUTOR_HIGH.start(Interrupt::USART1);
unwrap!(spawner.spawn(run_high()));
// Medium-priority executor: USART2, priority level 7
let irq = interrupt::take!(USART2);
irq.set_priority(interrupt::Priority::P7);
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
let spawner = executor.start();
unsafe { nvic.set_priority(Interrupt::USART2, 7 << 4) };
let spawner = EXECUTOR_MED.start(Interrupt::USART2);
unwrap!(spawner.spawn(run_med()));
// Low priority executor: runs in thread mode, using WFE/SEV

View File

@ -57,11 +57,14 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::mem;
use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry;
use defmt::*;
use embassy_stm32::executor::{Executor, InterruptExecutor};
use embassy_stm32::interrupt;
use embassy_stm32::interrupt::InterruptExt;
use embassy_stm32::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
@ -108,28 +111,35 @@ async fn run_low() {
}
}
static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new();
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new();
static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
#[interrupt]
unsafe fn UART4() {
EXECUTOR_HIGH.on_interrupt()
}
#[interrupt]
unsafe fn UART5() {
EXECUTOR_MED.on_interrupt()
}
#[entry]
fn main() -> ! {
info!("Hello World!");
let _p = embassy_stm32::init(Default::default());
let mut nvic: NVIC = unsafe { mem::transmute(()) };
// High-priority executor: SWI1_EGU1, priority level 6
let irq = interrupt::take!(UART4);
irq.set_priority(interrupt::Priority::P6);
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
let spawner = executor.start();
// High-priority executor: UART4, priority level 6
unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) };
let spawner = EXECUTOR_HIGH.start(Interrupt::UART4);
unwrap!(spawner.spawn(run_high()));
// Medium-priority executor: SWI0_EGU0, priority level 7
let irq = interrupt::take!(UART5);
irq.set_priority(interrupt::Priority::P7);
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
let spawner = executor.start();
// Medium-priority executor: UART5, priority level 7
unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) };
let spawner = EXECUTOR_MED.start(Interrupt::UART5);
unwrap!(spawner.spawn(run_med()));
// Low priority executor: runs in thread mode, using WFE/SEV

View File

@ -10,7 +10,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", "unstable-traits", "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"], optional = true }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
defmt = "0.3"
defmt-rtt = "0.4"
@ -27,9 +27,5 @@ embedded-storage = "0.3.0"
micromath = "2.0.0"
static_cell = "1.0"
[[bin]]
name = "usb_ethernet"
required-features = ["embassy-net"]
[profile.release]
debug = 2

View File

@ -57,11 +57,14 @@
#![no_main]
#![feature(type_alias_impl_trait)]
use core::mem;
use cortex_m::peripheral::NVIC;
use cortex_m_rt::entry;
use defmt::*;
use embassy_stm32::executor::{Executor, InterruptExecutor};
use embassy_stm32::interrupt;
use embassy_stm32::interrupt::InterruptExt;
use embassy_stm32::pac::Interrupt;
use embassy_time::{Duration, Instant, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
@ -108,28 +111,35 @@ async fn run_low() {
}
}
static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new();
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new();
static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
#[interrupt]
unsafe fn UART4() {
EXECUTOR_HIGH.on_interrupt()
}
#[interrupt]
unsafe fn UART5() {
EXECUTOR_MED.on_interrupt()
}
#[entry]
fn main() -> ! {
info!("Hello World!");
let _p = embassy_stm32::init(Default::default());
let mut nvic: NVIC = unsafe { mem::transmute(()) };
// High-priority executor: SWI1_EGU1, priority level 6
let irq = interrupt::take!(UART4);
irq.set_priority(interrupt::Priority::P6);
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
let spawner = executor.start();
// High-priority executor: UART4, priority level 6
unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) };
let spawner = EXECUTOR_HIGH.start(Interrupt::UART4);
unwrap!(spawner.spawn(run_high()));
// Medium-priority executor: SWI0_EGU0, priority level 7
let irq = interrupt::take!(UART5);
irq.set_priority(interrupt::Priority::P7);
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
let spawner = executor.start();
// Medium-priority executor: UART5, priority level 7
unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) };
let spawner = EXECUTOR_MED.start(Interrupt::UART5);
unwrap!(spawner.spawn(run_med()));
// Low priority executor: runs in thread mode, using WFE/SEV

View File

@ -100,8 +100,8 @@ async fn main(spawner: Spawner) {
let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
unwrap!(spawner.spawn(usb_ncm_task(runner)));
let config = embassy_net::ConfigStrategy::Dhcp;
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@ -114,12 +114,7 @@ async fn main(spawner: Spawner) {
let seed = u64::from_le_bytes(seed);
// Init network stack
let stack = &*singleton!(Stack::new(
device,
config,
singleton!(StackResources::<1, 2, 8>::new()),
seed
));
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
unwrap!(spawner.spawn(net_task(stack)));

View File

@ -4,8 +4,6 @@ name = "embassy-stm32l4-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[features]
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }

View File

@ -4,8 +4,6 @@ name = "embassy-stm32l5-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[features]
[dependencies]
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }

View File

@ -0,0 +1,9 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
#runner = "teleprobe local run --chip nRF52840_xxAA --elf"
runner = "teleprobe client run --target nrf52840-dk --elf"
[build]
target = "thumbv7em-none-eabi"
[env]
DEFMT_LOG = "trace"

20
tests/nrf/Cargo.toml Normal file
View File

@ -0,0 +1,20 @@
[package]
edition = "2021"
name = "embassy-nrf-examples"
version = "0.1.0"
license = "MIT OR Apache-2.0"
[dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt", "nightly"] }
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "nightly", "integrated-timers"] }
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
embedded-io = { version = "0.4.0", features = ["async"] }
defmt = "0.3"
defmt-rtt = "0.4"
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.0"
panic-probe = { version = "0.3", features = ["print-defmt"] }

16
tests/nrf/build.rs Normal file
View File

@ -0,0 +1,16 @@
use std::error::Error;
use std::path::PathBuf;
use std::{env, fs};
fn main() -> Result<(), Box<dyn Error>> {
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
println!("cargo:rustc-link-search={}", out.display());
println!("cargo:rerun-if-changed=link_ram.x");
println!("cargo:rustc-link-arg-bins=--nmagic");
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
Ok(())
}

Some files were not shown because too many files have changed in this diff Show More