mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-10-30 22:01:02 +00:00
Merge upstream
This commit is contained in:
commit
b0e26440ee
@ -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
1
ci.sh
@ -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
|
||||
|
||||
|
||||
|
@ -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};
|
||||
#[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) {
|
||||
#[derive(Clone, Copy)]
|
||||
struct N(u16);
|
||||
unsafe impl cortex_m::interrupt::InterruptNumber for N {
|
||||
fn number(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
||||
unsafe fn steal() -> Self {
|
||||
Self(())
|
||||
}
|
||||
unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::Handler {
|
||||
unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler {
|
||||
#[export_name = #name_handler]
|
||||
static HANDLER: ::embassy_cortex_m::interrupt::Handler = ::embassy_cortex_m::interrupt::Handler::new();
|
||||
static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new();
|
||||
&HANDLER
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
||||
pub unsafe extern "C" fn trampoline() {
|
||||
extern "C" {
|
||||
#[link_name = #name_handler]
|
||||
static HANDLER: interrupt::Handler;
|
||||
static HANDLER: interrupt::DynHandler;
|
||||
}
|
||||
|
||||
let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
|
||||
|
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -140,6 +140,10 @@ impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -148,6 +148,12 @@ impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
|
||||
|
||||
impl_pwm!(PWM0, PWM0, PWM0);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -150,6 +150,12 @@ impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
|
||||
|
||||
impl_pwm!(PWM0, PWM0, PWM0);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -153,6 +153,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
impl_timer!(TIMER3, TIMER3, TIMER3, extended);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -146,6 +146,9 @@ embassy_hal_common::peripherals! {
|
||||
|
||||
// I2S
|
||||
I2S,
|
||||
|
||||
// PDM
|
||||
PDM,
|
||||
}
|
||||
|
||||
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
||||
@ -168,6 +171,12 @@ impl_pwm!(PWM0, PWM0, PWM0);
|
||||
impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -197,6 +197,12 @@ impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
impl_pwm!(PWM3, PWM3, PWM3);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -208,6 +208,12 @@ impl_timer!(TIMER4, TIMER4, TIMER4, extended);
|
||||
|
||||
impl_qspi!(QSPI, QSPI, QSPI);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_qdec!(QDEC, QDEC, QDEC);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -34,10 +34,10 @@ pub mod pac {
|
||||
nvmc_ns as nvmc,
|
||||
oscillators_ns as oscillators,
|
||||
p0_ns as p0,
|
||||
pdm0_ns as pdm0,
|
||||
pdm0_ns as pdm,
|
||||
power_ns as power,
|
||||
pwm0_ns as pwm0,
|
||||
qdec0_ns as qdec0,
|
||||
qdec0_ns as qdec,
|
||||
qspi_ns as qspi,
|
||||
regulators_ns as regulators,
|
||||
reset_ns as reset,
|
||||
@ -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")]
|
||||
|
@ -127,6 +127,9 @@ embassy_hal_common::peripherals! {
|
||||
// SAADC
|
||||
SAADC,
|
||||
|
||||
// RNG
|
||||
RNG,
|
||||
|
||||
// PWM
|
||||
PWM0,
|
||||
PWM1,
|
||||
@ -252,6 +255,8 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
|
@ -301,6 +301,8 @@ impl_pwm!(PWM1, PWM1, PWM1);
|
||||
impl_pwm!(PWM2, PWM2, PWM2);
|
||||
impl_pwm!(PWM3, PWM3, PWM3);
|
||||
|
||||
impl_pdm!(PDM, PDM, PDM);
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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() }
|
||||
}
|
||||
|
||||
|
@ -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(®s().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(®s().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)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ impl Event {
|
||||
}
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
unsafe { &*pac::PPI::ptr() }
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,22 @@
|
||||
//! Quadrature decoder (QDEC) driver.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::QDEC;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
/// Quadrature decoder driver.
|
||||
pub struct Qdec<'d> {
|
||||
_p: PeripheralRef<'d, QDEC>,
|
||||
pub struct Qdec<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// QDEC config
|
||||
@ -44,44 +46,52 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'d> Qdec<'d> {
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
T::regs().intenclr.write(|w| w.reportrdy().clear());
|
||||
T::state().waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Qdec<'d, T> {
|
||||
/// Create a new QDEC.
|
||||
pub fn new(
|
||||
qdec: impl Peripheral<P = QDEC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
||||
qdec: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(a, b);
|
||||
Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config)
|
||||
into_ref!(qdec, a, b);
|
||||
Self::new_inner(qdec, a.map_into(), b.map_into(), None, config)
|
||||
}
|
||||
|
||||
/// Create a new QDEC, with a pin for LED output.
|
||||
pub fn new_with_led(
|
||||
qdec: impl Peripheral<P = QDEC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
||||
qdec: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
led: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(a, b, led);
|
||||
Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config)
|
||||
into_ref!(qdec, a, b, led);
|
||||
Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
p: impl Peripheral<P = QDEC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
||||
p: PeripheralRef<'d, T>,
|
||||
a: PeripheralRef<'d, AnyPin>,
|
||||
b: PeripheralRef<'d, AnyPin>,
|
||||
led: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(p, irq);
|
||||
let r = Self::regs();
|
||||
let r = T::regs();
|
||||
|
||||
// Select pins.
|
||||
a.conf().write(|w| w.input().connect().pull().pullup());
|
||||
@ -124,20 +134,15 @@ impl<'d> Qdec<'d> {
|
||||
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
||||
});
|
||||
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
// Enable peripheral
|
||||
r.enable.write(|w| w.enable().set_bit());
|
||||
|
||||
// Start sampling
|
||||
unsafe { r.tasks_start.write(|w| w.bits(1)) };
|
||||
|
||||
irq.disable();
|
||||
irq.set_handler(|_| {
|
||||
let r = Self::regs();
|
||||
r.intenclr.write(|w| w.reportrdy().clear());
|
||||
WAKER.wake();
|
||||
});
|
||||
irq.enable();
|
||||
|
||||
Self { _p: p }
|
||||
}
|
||||
|
||||
@ -155,12 +160,12 @@ impl<'d> Qdec<'d> {
|
||||
/// let delta = q.read().await;
|
||||
/// ```
|
||||
pub async fn read(&mut self) -> i16 {
|
||||
let t = Self::regs();
|
||||
let t = T::regs();
|
||||
t.intenset.write(|w| w.reportrdy().set());
|
||||
unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
|
||||
|
||||
let value = poll_fn(|cx| {
|
||||
WAKER.register(cx.waker());
|
||||
T::state().waker.register(cx.waker());
|
||||
if t.events_reportrdy.read().bits() == 0 {
|
||||
return Poll::Pending;
|
||||
} else {
|
||||
@ -172,10 +177,6 @@ impl<'d> Qdec<'d> {
|
||||
.await;
|
||||
value
|
||||
}
|
||||
|
||||
fn regs() -> &'static pac::qdec::RegisterBlock {
|
||||
unsafe { &*pac::QDEC::ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample period
|
||||
@ -236,3 +237,48 @@ pub enum LedPolarity {
|
||||
/// Active low (a low output turns on the LED).
|
||||
ActiveLow,
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static crate::pac::qdec::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// qdec peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
macro_rules! impl_qdec {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::qdec::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::qdec::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::qdec::sealed::State {
|
||||
static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new();
|
||||
&STATE
|
||||
}
|
||||
}
|
||||
impl crate::qdec::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -3,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")]
|
||||
{
|
||||
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
|
||||
#[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> {
|
||||
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
|
||||
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
|
||||
use super::*;
|
||||
|
||||
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(offset as usize, data).await
|
||||
}
|
||||
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 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) {
|
||||
self.erase(address).await?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(offset, data).await
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
||||
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
|
||||
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||
for address in (from..to).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
|
||||
self.erase(address).await?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn capacity(&self) -> usize {
|
||||
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, data).await
|
||||
}
|
||||
|
||||
fn capacity(&self) -> usize {
|
||||
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 {
|
||||
|
@ -1,83 +1,48 @@
|
||||
//! Random Number Generator (RNG) driver.
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::RNG;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
impl RNG {
|
||||
fn regs() -> &'static pac::rng::RegisterBlock {
|
||||
unsafe { &*pac::RNG::ptr() }
|
||||
}
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
static STATE: State = State {
|
||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
||||
end: AtomicPtr::new(ptr::null_mut()),
|
||||
waker: AtomicWaker::new(),
|
||||
};
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let s = T::state();
|
||||
let r = T::regs();
|
||||
|
||||
struct State {
|
||||
ptr: AtomicPtr<u8>,
|
||||
end: AtomicPtr<u8>,
|
||||
waker: AtomicWaker,
|
||||
}
|
||||
|
||||
/// A wrapper around an nRF RNG peripheral.
|
||||
///
|
||||
/// It has a non-blocking API, and a blocking api through `rand`.
|
||||
pub struct Rng<'d> {
|
||||
irq: PeripheralRef<'d, interrupt::RNG>,
|
||||
}
|
||||
|
||||
impl<'d> Rng<'d> {
|
||||
/// Creates a new RNG driver from the `RNG` peripheral and interrupt.
|
||||
///
|
||||
/// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
|
||||
/// e.g. using `mem::forget`.
|
||||
///
|
||||
/// The synchronous API is safe.
|
||||
pub fn new(_rng: impl Peripheral<P = RNG> + 'd, irq: impl Peripheral<P = interrupt::RNG> + 'd) -> Self {
|
||||
into_ref!(irq);
|
||||
|
||||
let this = Self { irq };
|
||||
|
||||
this.stop();
|
||||
this.disable_irq();
|
||||
|
||||
this.irq.set_handler(Self::on_interrupt);
|
||||
this.irq.unpend();
|
||||
this.irq.enable();
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
// Clear the event.
|
||||
RNG::regs().events_valrdy.reset();
|
||||
r.events_valrdy.reset();
|
||||
|
||||
// Mutate the slice within a critical section,
|
||||
// so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
|
||||
let (ptr, end) = critical_section::with(|_| {
|
||||
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
||||
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||
// We need to make sure we haven't already filled the whole slice,
|
||||
// in case the interrupt fired again before the executor got back to the future.
|
||||
let end = STATE.end.load(Ordering::Relaxed);
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
if !ptr.is_null() && ptr != end {
|
||||
// If the future was dropped, the pointer would have been set to null,
|
||||
// so we're still good to mutate the slice.
|
||||
// The safety contract of `Rng::new` means that the future can't have been dropped
|
||||
// without calling its destructor.
|
||||
unsafe {
|
||||
*ptr = RNG::regs().value.read().value().bits();
|
||||
*ptr = r.value.read().value().bits();
|
||||
}
|
||||
}
|
||||
(ptr, end)
|
||||
@ -90,15 +55,15 @@ impl<'d> Rng<'d> {
|
||||
}
|
||||
|
||||
let new_ptr = unsafe { ptr.add(1) };
|
||||
match STATE
|
||||
match s
|
||||
.ptr
|
||||
.compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
|
||||
{
|
||||
Ok(_) => {
|
||||
let end = STATE.end.load(Ordering::Relaxed);
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
// It doesn't matter if `end` was changed under our feet, because then this will just be false.
|
||||
if new_ptr == end {
|
||||
STATE.waker.wake();
|
||||
s.waker.wake();
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
@ -107,21 +72,53 @@ impl<'d> Rng<'d> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around an nRF RNG peripheral.
|
||||
///
|
||||
/// It has a non-blocking API, and a blocking api through `rand`.
|
||||
pub struct Rng<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Rng<'d, T> {
|
||||
/// Creates a new RNG driver from the `RNG` peripheral and interrupt.
|
||||
///
|
||||
/// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
|
||||
/// e.g. using `mem::forget`.
|
||||
///
|
||||
/// The synchronous API is safe.
|
||||
pub fn new(
|
||||
rng: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(rng);
|
||||
|
||||
let this = Self { _peri: rng };
|
||||
|
||||
this.stop();
|
||||
this.disable_irq();
|
||||
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
RNG::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_stop.write(|w| unsafe { w.bits(1) })
|
||||
}
|
||||
|
||||
fn start(&self) {
|
||||
RNG::regs().tasks_start.write(|w| unsafe { w.bits(1) })
|
||||
T::regs().tasks_start.write(|w| unsafe { w.bits(1) })
|
||||
}
|
||||
|
||||
fn enable_irq(&self) {
|
||||
RNG::regs().intenset.write(|w| w.valrdy().set());
|
||||
T::regs().intenset.write(|w| w.valrdy().set());
|
||||
}
|
||||
|
||||
fn disable_irq(&self) {
|
||||
RNG::regs().intenclr.write(|w| w.valrdy().clear());
|
||||
T::regs().intenclr.write(|w| w.valrdy().clear());
|
||||
}
|
||||
|
||||
/// Enable or disable the RNG's bias correction.
|
||||
@ -131,7 +128,7 @@ impl<'d> Rng<'d> {
|
||||
///
|
||||
/// Defaults to disabled.
|
||||
pub fn set_bias_correction(&self, enable: bool) {
|
||||
RNG::regs().config.write(|w| w.dercen().bit(enable))
|
||||
T::regs().config.write(|w| w.dercen().bit(enable))
|
||||
}
|
||||
|
||||
/// Fill the buffer with random bytes.
|
||||
@ -140,11 +137,13 @@ impl<'d> Rng<'d> {
|
||||
return; // Nothing to fill
|
||||
}
|
||||
|
||||
let s = T::state();
|
||||
|
||||
let range = dest.as_mut_ptr_range();
|
||||
// Even if we've preempted the interrupt, it can't preempt us again,
|
||||
// so we don't need to worry about the order we write these in.
|
||||
STATE.ptr.store(range.start, Ordering::Relaxed);
|
||||
STATE.end.store(range.end, Ordering::Relaxed);
|
||||
s.ptr.store(range.start, Ordering::Relaxed);
|
||||
s.end.store(range.end, Ordering::Relaxed);
|
||||
|
||||
self.enable_irq();
|
||||
self.start();
|
||||
@ -154,16 +153,16 @@ impl<'d> Rng<'d> {
|
||||
self.disable_irq();
|
||||
|
||||
// The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
|
||||
STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
STATE.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
STATE.waker.register(cx.waker());
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
// The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
|
||||
let end = STATE.end.load(Ordering::Relaxed);
|
||||
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||
|
||||
if ptr == end {
|
||||
// We're done.
|
||||
@ -183,7 +182,7 @@ impl<'d> Rng<'d> {
|
||||
self.start();
|
||||
|
||||
for byte in dest.iter_mut() {
|
||||
let regs = RNG::regs();
|
||||
let regs = T::regs();
|
||||
while regs.events_valrdy.read().bits() == 0 {}
|
||||
regs.events_valrdy.reset();
|
||||
*byte = regs.value.read().value().bits();
|
||||
@ -193,13 +192,16 @@ impl<'d> Rng<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for Rng<'d> {
|
||||
impl<'d, T: Instance> Drop for Rng<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
self.irq.disable()
|
||||
self.stop();
|
||||
let s = T::state();
|
||||
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> rand_core::RngCore for Rng<'d> {
|
||||
impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
self.blocking_fill_bytes(dest);
|
||||
}
|
||||
@ -223,4 +225,53 @@ impl<'d> rand_core::RngCore for Rng<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> rand_core::CryptoRng for Rng<'d> {}
|
||||
impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub ptr: AtomicPtr<u8>,
|
||||
pub end: AtomicPtr<u8>,
|
||||
pub waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
||||
end: AtomicPtr::new(ptr::null_mut()),
|
||||
waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
fn regs() -> &'static crate::pac::rng::RegisterBlock;
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
}
|
||||
|
||||
/// RNG peripheral instance.
|
||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||
/// Interrupt for this peripheral.
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
macro_rules! impl_rng {
|
||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||
impl crate::rng::sealed::Instance for peripherals::$type {
|
||||
fn regs() -> &'static crate::pac::rng::RegisterBlock {
|
||||
unsafe { &*pac::$pac_type::ptr() }
|
||||
}
|
||||
fn state() -> &'static crate::rng::sealed::State {
|
||||
static STATE: crate::rng::sealed::State = crate::rng::sealed::State::new();
|
||||
&STATE
|
||||
}
|
||||
}
|
||||
impl crate::rng::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use core::future::poll_fn;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
@ -17,7 +18,6 @@ use saadc::oversample::OVERSAMPLE_A;
|
||||
use saadc::resolution::VAL_A;
|
||||
|
||||
use self::sealed::Input as _;
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
@ -28,9 +28,30 @@ use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
#[non_exhaustive]
|
||||
pub enum Error {}
|
||||
|
||||
/// One-shot and continuous SAADC.
|
||||
pub struct Saadc<'d, const N: usize> {
|
||||
_p: PeripheralRef<'d, peripherals::SAADC>,
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl interrupt::Handler<interrupt::SAADC> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = unsafe { &*SAADC::ptr() };
|
||||
|
||||
if r.events_calibratedone.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.calibratedone().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
@ -114,15 +135,20 @@ pub enum CallbackResult {
|
||||
Stop,
|
||||
}
|
||||
|
||||
/// One-shot and continuous SAADC.
|
||||
pub struct Saadc<'d, const N: usize> {
|
||||
_p: PeripheralRef<'d, peripherals::SAADC>,
|
||||
}
|
||||
|
||||
impl<'d, const N: usize> Saadc<'d, N> {
|
||||
/// Create a new SAADC driver.
|
||||
pub fn new(
|
||||
saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
|
||||
irq: impl Peripheral<P = interrupt::SAADC> + 'd,
|
||||
_irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd,
|
||||
config: Config,
|
||||
channel_configs: [ChannelConfig; N],
|
||||
) -> Self {
|
||||
into_ref!(saadc, irq);
|
||||
into_ref!(saadc);
|
||||
|
||||
let r = unsafe { &*SAADC::ptr() };
|
||||
|
||||
@ -163,32 +189,12 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { interrupt::SAADC::steal() }.unpend();
|
||||
unsafe { interrupt::SAADC::steal() }.enable();
|
||||
|
||||
Self { _p: saadc }
|
||||
}
|
||||
|
||||
fn on_interrupt(_ctx: *mut ()) {
|
||||
let r = Self::regs();
|
||||
|
||||
if r.events_calibratedone.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.calibratedone().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
|
||||
if r.events_started.read().bits() != 0 {
|
||||
r.intenclr.write(|w| w.started().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
|
||||
fn regs() -> &'static saadc::RegisterBlock {
|
||||
unsafe { &*SAADC::ptr() }
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -14,7 +15,7 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
||||
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -31,11 +32,6 @@ pub enum Error {
|
||||
BufferNotInRAM,
|
||||
}
|
||||
|
||||
/// SPIM driver.
|
||||
pub struct Spim<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// SPIM configuration.
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
@ -62,11 +58,33 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SPIM driver.
|
||||
pub struct Spim<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Spim<'d, T> {
|
||||
/// Create a new SPIM driver.
|
||||
pub fn new(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -75,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
into_ref!(sck, miso, mosi);
|
||||
Self::new_inner(
|
||||
spim,
|
||||
irq,
|
||||
sck.map_into(),
|
||||
Some(miso.map_into()),
|
||||
Some(mosi.map_into()),
|
||||
@ -86,36 +103,35 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
/// Create a new SPIM driver, capable of TX only (MOSI only).
|
||||
pub fn new_txonly(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, mosi);
|
||||
Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config)
|
||||
Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config)
|
||||
}
|
||||
|
||||
/// Create a new SPIM driver, capable of RX only (MISO only).
|
||||
pub fn new_rxonly(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sck, miso);
|
||||
Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config)
|
||||
Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
spim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
sck: PeripheralRef<'d, AnyPin>,
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(spim, irq);
|
||||
into_ref!(spim);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: spim }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#![macro_use]
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -12,7 +13,7 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
|
||||
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -29,11 +30,6 @@ pub enum Error {
|
||||
BufferNotInRAM,
|
||||
}
|
||||
|
||||
/// SPIS driver.
|
||||
pub struct Spis<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
/// SPIS configuration.
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
@ -67,11 +63,38 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
|
||||
if r.events_acquired.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.acquired().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SPIS driver.
|
||||
pub struct Spis<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Spis<'d, T> {
|
||||
/// Create a new SPIS driver.
|
||||
pub fn new(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -81,7 +104,6 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
into_ref!(cs, sck, miso, mosi);
|
||||
Self::new_inner(
|
||||
spis,
|
||||
irq,
|
||||
cs.map_into(),
|
||||
sck.map_into(),
|
||||
Some(miso.map_into()),
|
||||
@ -93,48 +115,31 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
/// Create a new SPIS driver, capable of TX only (MISO only).
|
||||
pub fn new_txonly(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(cs, sck, miso);
|
||||
Self::new_inner(
|
||||
spis,
|
||||
irq,
|
||||
cs.map_into(),
|
||||
sck.map_into(),
|
||||
Some(miso.map_into()),
|
||||
None,
|
||||
config,
|
||||
)
|
||||
Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config)
|
||||
}
|
||||
|
||||
/// Create a new SPIS driver, capable of RX only (MOSI only).
|
||||
pub fn new_rxonly(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(cs, sck, mosi);
|
||||
Self::new_inner(
|
||||
spis,
|
||||
irq,
|
||||
cs.map_into(),
|
||||
sck.map_into(),
|
||||
None,
|
||||
Some(mosi.map_into()),
|
||||
config,
|
||||
)
|
||||
Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
spis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
cs: PeripheralRef<'d, AnyPin>,
|
||||
sck: PeripheralRef<'d, AnyPin>,
|
||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||
@ -143,7 +148,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
) -> Self {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
into_ref!(spis, irq, cs, sck);
|
||||
into_ref!(spis, cs, sck);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -209,28 +214,12 @@ impl<'d, T: Instance> Spis<'d, T> {
|
||||
// Disable all events interrupts.
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: spis }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_end.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
|
||||
if r.events_acquired.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.acquired().clear());
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||
|
@ -3,6 +3,7 @@
|
||||
use core::future::poll_fn;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::Interrupt;
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
@ -12,27 +13,39 @@ use crate::interrupt::InterruptExt;
|
||||
use crate::peripherals::TEMP;
|
||||
use crate::{interrupt, pac, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl interrupt::Handler<interrupt::TEMP> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = unsafe { &*pac::TEMP::PTR };
|
||||
r.intenclr.write(|w| w.datardy().clear());
|
||||
WAKER.wake();
|
||||
}
|
||||
}
|
||||
|
||||
/// Builtin temperature sensor driver.
|
||||
pub struct Temp<'d> {
|
||||
_irq: PeripheralRef<'d, interrupt::TEMP>,
|
||||
_peri: PeripheralRef<'d, TEMP>,
|
||||
}
|
||||
|
||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
impl<'d> Temp<'d> {
|
||||
/// Create a new temperature sensor driver.
|
||||
pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self {
|
||||
into_ref!(_t, irq);
|
||||
pub fn new(
|
||||
_peri: impl Peripheral<P = TEMP> + 'd,
|
||||
_irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(_peri);
|
||||
|
||||
// Enable interrupt that signals temperature values
|
||||
irq.disable();
|
||||
irq.set_handler(|_| {
|
||||
let t = Self::regs();
|
||||
t.intenclr.write(|w| w.datardy().clear());
|
||||
WAKER.wake();
|
||||
});
|
||||
irq.enable();
|
||||
Self { _irq: irq }
|
||||
unsafe { interrupt::TEMP::steal() }.unpend();
|
||||
unsafe { interrupt::TEMP::steal() }.enable();
|
||||
|
||||
Self { _peri }
|
||||
}
|
||||
|
||||
/// Perform an asynchronous temperature measurement. The returned future
|
||||
|
@ -6,15 +6,9 @@
|
||||
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::Interrupt;
|
||||
use crate::ppi::{Event, Task};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -26,8 +20,6 @@ pub(crate) mod sealed {
|
||||
/// The number of CC registers this instance has.
|
||||
const CCS: usize;
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock;
|
||||
/// Storage for the waker for CC register `n`.
|
||||
fn waker(n: usize) -> &'static AtomicWaker;
|
||||
}
|
||||
pub trait ExtendedInstance {}
|
||||
|
||||
@ -50,12 +42,6 @@ macro_rules! impl_timer {
|
||||
fn regs() -> &'static pac::timer0::RegisterBlock {
|
||||
unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
|
||||
}
|
||||
fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker {
|
||||
use ::embassy_sync::waitqueue::AtomicWaker;
|
||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||
static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs];
|
||||
&WAKERS[n]
|
||||
}
|
||||
}
|
||||
impl crate::timer::Instance for peripherals::$type {
|
||||
type Interrupt = crate::interrupt::$irq;
|
||||
@ -99,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.
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
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()
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
use core::sync::atomic::Ordering::SeqCst;
|
||||
use core::task::Poll;
|
||||
@ -15,7 +16,7 @@ use embassy_time::{Duration, Instant};
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::{slice_in_ram, slice_in_ram_or};
|
||||
use crate::{gpio, pac, Peripheral};
|
||||
|
||||
@ -92,6 +93,27 @@ pub enum Error {
|
||||
Timeout,
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.error().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TWI driver.
|
||||
pub struct Twim<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
@ -101,12 +123,12 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
/// Create a new TWI driver.
|
||||
pub fn new(
|
||||
twim: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(twim, irq, sda, scl);
|
||||
into_ref!(twim, sda, scl);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -152,27 +174,12 @@ impl<'d, T: Instance> Twim<'d, T> {
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: twim }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.end_waker.wake();
|
||||
r.intenclr.write(|w| w.error().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::compiler_fence;
|
||||
use core::sync::atomic::Ordering::SeqCst;
|
||||
use core::task::Poll;
|
||||
@ -14,7 +15,7 @@ use embassy_time::{Duration, Instant};
|
||||
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::Pin as GpioPin;
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::slice_in_ram_or;
|
||||
use crate::{gpio, pac, Peripheral};
|
||||
|
||||
@ -108,6 +109,31 @@ pub enum Command {
|
||||
Write(usize),
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.read().clear().write().clear());
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.error().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TWIS driver.
|
||||
pub struct Twis<'d, T: Instance> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
@ -117,12 +143,12 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
/// Create a new TWIS driver.
|
||||
pub fn new(
|
||||
twis: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(twis, irq, sda, scl);
|
||||
into_ref!(twis, sda, scl);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -178,31 +204,12 @@ impl<'d, T: Instance> Twis<'d, T> {
|
||||
// Generate suspend on read event
|
||||
r.shorts.write(|w| w.read_suspend().enabled());
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self { _p: twis }
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.read().clear().write().clear());
|
||||
}
|
||||
if r.events_stopped.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.stopped().clear());
|
||||
}
|
||||
if r.events_error.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
r.intenclr.modify(|_r, w| w.error().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
@ -26,7 +27,7 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
|
||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||
use crate::gpio::sealed::Pin as _;
|
||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||
use crate::util::slice_in_ram_or;
|
||||
@ -62,6 +63,27 @@ pub enum Error {
|
||||
BufferNotInRAM,
|
||||
}
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
s.endrx_waker.wake();
|
||||
r.intenclr.write(|w| w.endrx().clear());
|
||||
}
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
s.endtx_waker.wake();
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// UARTE driver.
|
||||
pub struct Uarte<'d, T: Instance> {
|
||||
tx: UarteTx<'d, T>,
|
||||
@ -86,19 +108,19 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
/// Create a new UARTE without hardware flow control
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rxd, txd);
|
||||
Self::new_inner(uarte, irq, rxd.map_into(), txd.map_into(), None, None, config)
|
||||
Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config)
|
||||
}
|
||||
|
||||
/// Create a new UARTE with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
@ -108,7 +130,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
into_ref!(rxd, txd, cts, rts);
|
||||
Self::new_inner(
|
||||
uarte,
|
||||
irq,
|
||||
rxd.map_into(),
|
||||
txd.map_into(),
|
||||
Some(cts.map_into()),
|
||||
@ -119,14 +140,13 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
|
||||
fn new_inner(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rxd: PeripheralRef<'d, AnyPin>,
|
||||
txd: PeripheralRef<'d, AnyPin>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(uarte, irq);
|
||||
into_ref!(uarte);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -148,9 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
}
|
||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
|
||||
(false, false) => false,
|
||||
@ -238,20 +257,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
||||
Event::from_reg(&r.events_endtx)
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
if r.events_endrx.read().bits() != 0 {
|
||||
s.endrx_waker.wake();
|
||||
r.intenclr.write(|w| w.endrx().clear());
|
||||
}
|
||||
if r.events_endtx.read().bits() != 0 {
|
||||
s.endtx_waker.wake();
|
||||
r.intenclr.write(|w| w.endtx().clear());
|
||||
}
|
||||
}
|
||||
|
||||
/// Read bytes until the buffer is filled.
|
||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
self.rx.read(buffer).await
|
||||
@ -308,34 +313,33 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
/// Create a new tx-only UARTE without hardware flow control
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(txd);
|
||||
Self::new_inner(uarte, irq, txd.map_into(), None, config)
|
||||
Self::new_inner(uarte, txd.map_into(), None, config)
|
||||
}
|
||||
|
||||
/// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(txd, cts);
|
||||
Self::new_inner(uarte, irq, txd.map_into(), Some(cts.map_into()), config)
|
||||
Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
txd: PeripheralRef<'d, AnyPin>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(uarte, irq);
|
||||
into_ref!(uarte);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -354,9 +358,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
||||
let hardware_flow_control = cts.is_some();
|
||||
configure(r, config, hardware_flow_control);
|
||||
|
||||
irq.set_handler(Uarte::<T>::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let s = T::state();
|
||||
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
@ -506,34 +509,33 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
/// Create a new rx-only UARTE without hardware flow control
|
||||
pub fn new(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rxd);
|
||||
Self::new_inner(uarte, irq, rxd.map_into(), None, config)
|
||||
Self::new_inner(uarte, rxd.map_into(), None, config)
|
||||
}
|
||||
|
||||
/// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
|
||||
pub fn new_with_rtscts(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(rxd, rts);
|
||||
Self::new_inner(uarte, irq, rxd.map_into(), Some(rts.map_into()), config)
|
||||
Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
uarte: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rxd: PeripheralRef<'d, AnyPin>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(uarte, irq);
|
||||
into_ref!(uarte);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@ -549,9 +551,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
||||
r.psel.txd.write(|w| w.connect().disconnected());
|
||||
r.psel.cts.write(|w| w.connect().disconnected());
|
||||
|
||||
irq.set_handler(Uarte::<T>::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
let hardware_flow_control = rts.is_some();
|
||||
configure(r, config, hardware_flow_control);
|
||||
@ -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;
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
#![macro_use]
|
||||
|
||||
pub mod vbus_detect;
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
|
||||
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use cortex_m::peripheral::NVIC;
|
||||
@ -15,7 +17,8 @@ use embassy_usb_driver as driver;
|
||||
use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
|
||||
use pac::usbd::RegisterBlock;
|
||||
|
||||
use crate::interrupt::{Interrupt, InterruptExt};
|
||||
use self::vbus_detect::VbusDetect;
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::util::slice_in_ram;
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
||||
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
||||
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
/// Trait for detecting USB VBUS power.
|
||||
///
|
||||
/// There are multiple ways to detect USB power. The behavior
|
||||
/// here provides a hook into determining whether it is.
|
||||
pub trait VbusDetect {
|
||||
/// Report whether power is detected.
|
||||
///
|
||||
/// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
|
||||
/// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||
fn is_usb_detected(&self) -> bool;
|
||||
|
||||
/// Wait until USB power is ready.
|
||||
///
|
||||
/// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
|
||||
/// `USBPWRRDY` event from the `POWER` peripheral.
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()>;
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
|
||||
///
|
||||
/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
|
||||
/// to POWER. In that case, use [`VbusDetectSignal`].
|
||||
#[cfg(not(feature = "_nrf5340-app"))]
|
||||
pub struct HardwareVbusDetect {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
static POWER_WAKER: AtomicWaker = NEW_AW;
|
||||
|
||||
#[cfg(not(feature = "_nrf5340-app"))]
|
||||
impl HardwareVbusDetect {
|
||||
/// Create a new `VbusDetectNative`.
|
||||
pub fn new(power_irq: impl Interrupt) -> Self {
|
||||
let regs = unsafe { &*pac::POWER::ptr() };
|
||||
|
||||
power_irq.set_handler(Self::on_interrupt);
|
||||
power_irq.unpend();
|
||||
power_irq.enable();
|
||||
|
||||
regs.intenset
|
||||
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
||||
|
||||
Self { _private: () }
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "_nrf5340-app"))]
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let regs = unsafe { &*pac::POWER::ptr() };
|
||||
|
||||
if regs.events_usbdetected.read().bits() != 0 {
|
||||
regs.events_usbdetected.reset();
|
||||
BUS_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_usbremoved.read().bits() != 0 {
|
||||
regs.events_usbremoved.reset();
|
||||
BUS_WAKER.wake();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_usbpwrrdy.read().bits() != 0 {
|
||||
regs.events_usbpwrrdy.reset();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "_nrf5340-app"))]
|
||||
impl VbusDetect for HardwareVbusDetect {
|
||||
fn is_usb_detected(&self) -> bool {
|
||||
let regs = unsafe { &*pac::POWER::ptr() };
|
||||
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
||||
}
|
||||
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||
poll_fn(move |cx| {
|
||||
POWER_WAKER.register(cx.waker());
|
||||
let regs = unsafe { &*pac::POWER::ptr() };
|
||||
|
||||
if regs.usbregstatus.read().outputrdy().is_ready() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if !self.is_usb_detected() {
|
||||
Poll::Ready(Err(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// Software-backed [`VbusDetect`] implementation.
|
||||
///
|
||||
/// This implementation does not interact with the hardware, it allows user code
|
||||
/// to notify the power events by calling functions instead.
|
||||
///
|
||||
/// This is suitable for use with the nRF softdevice, by calling the functions
|
||||
/// when the softdevice reports power-related events.
|
||||
pub struct SoftwareVbusDetect {
|
||||
usb_detected: AtomicBool,
|
||||
power_ready: AtomicBool,
|
||||
}
|
||||
|
||||
impl SoftwareVbusDetect {
|
||||
/// Create a new `SoftwareVbusDetect`.
|
||||
pub fn new(usb_detected: bool, power_ready: bool) -> Self {
|
||||
BUS_WAKER.wake();
|
||||
|
||||
Self {
|
||||
usb_detected: AtomicBool::new(usb_detected),
|
||||
power_ready: AtomicBool::new(power_ready),
|
||||
}
|
||||
}
|
||||
|
||||
/// Report whether power was detected.
|
||||
///
|
||||
/// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||
pub fn detected(&self, detected: bool) {
|
||||
self.usb_detected.store(detected, Ordering::Relaxed);
|
||||
self.power_ready.store(false, Ordering::Relaxed);
|
||||
BUS_WAKER.wake();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
|
||||
/// Report when USB power is ready.
|
||||
///
|
||||
/// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
|
||||
pub fn ready(&self) {
|
||||
self.power_ready.store(true, Ordering::Relaxed);
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
}
|
||||
|
||||
impl VbusDetect for &SoftwareVbusDetect {
|
||||
fn is_usb_detected(&self) -> bool {
|
||||
self.usb_detected.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||
poll_fn(move |cx| {
|
||||
POWER_WAKER.register(cx.waker());
|
||||
|
||||
if self.power_ready.load(Ordering::Relaxed) {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if !self.usb_detected.load(Ordering::Relaxed) {
|
||||
Poll::Ready(Err(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// USB driver.
|
||||
pub struct Driver<'d, T: Instance, P: VbusDetect> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
alloc_in: Allocator,
|
||||
alloc_out: Allocator,
|
||||
usb_supply: P,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
|
||||
/// Create a new USB driver.
|
||||
pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self {
|
||||
into_ref!(usb, irq);
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
|
||||
Self {
|
||||
_p: usb,
|
||||
alloc_in: Allocator::new(),
|
||||
alloc_out: Allocator::new(),
|
||||
usb_supply,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = T::regs();
|
||||
|
||||
if regs.events_usbreset.read().bits() != 0 {
|
||||
@ -255,11 +86,40 @@ impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> {
|
||||
/// USB driver.
|
||||
pub struct Driver<'d, T: Instance, V: VbusDetect> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
alloc_in: Allocator,
|
||||
alloc_out: Allocator,
|
||||
vbus_detect: V,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
|
||||
/// Create a new USB driver.
|
||||
pub fn new(
|
||||
usb: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
vbus_detect: V,
|
||||
) -> Self {
|
||||
into_ref!(usb);
|
||||
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self {
|
||||
_p: usb,
|
||||
alloc_in: Allocator::new(),
|
||||
alloc_out: Allocator::new(),
|
||||
vbus_detect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> {
|
||||
type EndpointOut = Endpoint<'d, T, Out>;
|
||||
type EndpointIn = Endpoint<'d, T, In>;
|
||||
type ControlPipe = ControlPipe<'d, T>;
|
||||
type Bus = Bus<'d, T, P>;
|
||||
type Bus = Bus<'d, T, V>;
|
||||
|
||||
fn alloc_endpoint_in(
|
||||
&mut self,
|
||||
@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
||||
Bus {
|
||||
_p: unsafe { self._p.clone_unchecked() },
|
||||
power_available: false,
|
||||
usb_supply: self.usb_supply,
|
||||
vbus_detect: self.vbus_detect,
|
||||
},
|
||||
ControlPipe {
|
||||
_p: self._p,
|
||||
@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
||||
}
|
||||
|
||||
/// USB bus.
|
||||
pub struct Bus<'d, T: Instance, P: VbusDetect> {
|
||||
pub struct Bus<'d, T: Instance, V: VbusDetect> {
|
||||
_p: PeripheralRef<'d, T>,
|
||||
power_available: bool,
|
||||
usb_supply: P,
|
||||
vbus_detect: V,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
||||
impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||
async fn enable(&mut self) {
|
||||
let regs = T::regs();
|
||||
|
||||
@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
||||
w
|
||||
});
|
||||
|
||||
if self.usb_supply.wait_power_ready().await.is_ok() {
|
||||
if self.vbus_detect.wait_power_ready().await.is_ok() {
|
||||
// Enable the USB pullup, allowing enumeration.
|
||||
regs.usbpullup.write(|w| w.connect().enabled());
|
||||
trace!("enabled");
|
||||
@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
||||
trace!("USB event: ready");
|
||||
}
|
||||
|
||||
if self.usb_supply.is_usb_detected() != self.power_available {
|
||||
if self.vbus_detect.is_usb_detected() != self.power_available {
|
||||
self.power_available = !self.power_available;
|
||||
if self.power_available {
|
||||
trace!("Power event: available");
|
177
embassy-nrf/src/usb/vbus_detect.rs
Normal file
177
embassy-nrf/src/usb/vbus_detect.rs
Normal file
@ -0,0 +1,177 @@
|
||||
//! Trait and implementations for performing VBUS detection.
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::BUS_WAKER;
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::pac;
|
||||
|
||||
/// Trait for detecting USB VBUS power.
|
||||
///
|
||||
/// There are multiple ways to detect USB power. The behavior
|
||||
/// here provides a hook into determining whether it is.
|
||||
pub trait VbusDetect {
|
||||
/// Report whether power is detected.
|
||||
///
|
||||
/// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
|
||||
/// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||
fn is_usb_detected(&self) -> bool;
|
||||
|
||||
/// Wait until USB power is ready.
|
||||
///
|
||||
/// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
|
||||
/// `USBPWRRDY` event from the `POWER` peripheral.
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "_nrf5340"))]
|
||||
type UsbRegIrq = interrupt::POWER_CLOCK;
|
||||
#[cfg(feature = "_nrf5340")]
|
||||
type UsbRegIrq = interrupt::USBREGULATOR;
|
||||
|
||||
#[cfg(not(feature = "_nrf5340"))]
|
||||
type UsbRegPeri = pac::POWER;
|
||||
#[cfg(feature = "_nrf5340")]
|
||||
type UsbRegPeri = pac::USBREGULATOR;
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl interrupt::Handler<UsbRegIrq> for InterruptHandler {
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
|
||||
if regs.events_usbdetected.read().bits() != 0 {
|
||||
regs.events_usbdetected.reset();
|
||||
BUS_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_usbremoved.read().bits() != 0 {
|
||||
regs.events_usbremoved.reset();
|
||||
BUS_WAKER.wake();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
|
||||
if regs.events_usbpwrrdy.read().bits() != 0 {
|
||||
regs.events_usbpwrrdy.reset();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
|
||||
///
|
||||
/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
|
||||
/// to POWER. In that case, use [`VbusDetectSignal`].
|
||||
pub struct HardwareVbusDetect {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
static POWER_WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
impl HardwareVbusDetect {
|
||||
/// Create a new `VbusDetectNative`.
|
||||
pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
|
||||
unsafe { UsbRegIrq::steal() }.unpend();
|
||||
unsafe { UsbRegIrq::steal() }.enable();
|
||||
|
||||
regs.intenset
|
||||
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
||||
|
||||
Self { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl VbusDetect for HardwareVbusDetect {
|
||||
fn is_usb_detected(&self) -> bool {
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
||||
}
|
||||
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||
poll_fn(move |cx| {
|
||||
POWER_WAKER.register(cx.waker());
|
||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||
|
||||
if regs.usbregstatus.read().outputrdy().is_ready() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if !self.is_usb_detected() {
|
||||
Poll::Ready(Err(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// Software-backed [`VbusDetect`] implementation.
|
||||
///
|
||||
/// This implementation does not interact with the hardware, it allows user code
|
||||
/// to notify the power events by calling functions instead.
|
||||
///
|
||||
/// This is suitable for use with the nRF softdevice, by calling the functions
|
||||
/// when the softdevice reports power-related events.
|
||||
pub struct SoftwareVbusDetect {
|
||||
usb_detected: AtomicBool,
|
||||
power_ready: AtomicBool,
|
||||
}
|
||||
|
||||
impl SoftwareVbusDetect {
|
||||
/// Create a new `SoftwareVbusDetect`.
|
||||
pub fn new(usb_detected: bool, power_ready: bool) -> Self {
|
||||
BUS_WAKER.wake();
|
||||
|
||||
Self {
|
||||
usb_detected: AtomicBool::new(usb_detected),
|
||||
power_ready: AtomicBool::new(power_ready),
|
||||
}
|
||||
}
|
||||
|
||||
/// Report whether power was detected.
|
||||
///
|
||||
/// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||
pub fn detected(&self, detected: bool) {
|
||||
self.usb_detected.store(detected, Ordering::Relaxed);
|
||||
self.power_ready.store(false, Ordering::Relaxed);
|
||||
BUS_WAKER.wake();
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
|
||||
/// Report when USB power is ready.
|
||||
///
|
||||
/// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
|
||||
pub fn ready(&self) {
|
||||
self.power_ready.store(true, Ordering::Relaxed);
|
||||
POWER_WAKER.wake();
|
||||
}
|
||||
}
|
||||
|
||||
impl VbusDetect for &SoftwareVbusDetect {
|
||||
fn is_usb_detected(&self) -> bool {
|
||||
self.usb_detected.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||
poll_fn(move |cx| {
|
||||
POWER_WAKER.register(cx.waker());
|
||||
|
||||
if self.power_ready.load(Ordering::Relaxed) {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if !self.usb_detected.load(Ordering::Relaxed) {
|
||||
Poll::Ready(Err(()))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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>,
|
||||
|
@ -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()) };
|
||||
|
@ -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>,
|
||||
|
@ -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,
|
||||
|
@ -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 {}
|
||||
|
@ -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
|
||||
|
@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0"
|
||||
|
||||
[features]
|
||||
default = ["nightly"]
|
||||
msos-descriptor = ["embassy-usb/msos-descriptor"]
|
||||
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
|
||||
"embassy-lora", "lorawan-device", "lorawan"]
|
||||
|
||||
@ -17,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
|
||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
|
||||
embedded-io = "0.4.0"
|
||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
||||
|
||||
@ -36,7 +35,3 @@ rand = { version = "0.8.4", default-features = false }
|
||||
embedded-storage = "0.3.0"
|
||||
usbd-hid = "0.6.0"
|
||||
serde = { version = "1.0.136", default-features = false }
|
||||
|
||||
[[bin]]
|
||||
name = "usb_serial_winusb"
|
||||
required-features = ["msos-descriptor"]
|
||||
|
@ -1,26 +0,0 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::timer::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
|
||||
// default frequency is 1MHz, so this triggers every second
|
||||
t.cc(0).write(1_000_000);
|
||||
// clear the timer value on cc[0] compare match
|
||||
t.cc(0).short_compare_clear();
|
||||
t.start();
|
||||
|
||||
loop {
|
||||
// wait for compare match
|
||||
t.cc(0).wait().await;
|
||||
info!("hardware timer tick");
|
||||
}
|
||||
}
|
@ -4,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!");
|
||||
|
||||
|
@ -7,7 +7,7 @@ use core::f32::consts::PI;
|
||||
use defmt::{error, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type Sample = i16;
|
||||
@ -15,6 +15,10 @@ type Sample = i16;
|
||||
const NUM_BUFFERS: usize = 2;
|
||||
const NUM_SAMPLES: usize = 4;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) {
|
||||
config.sample_width = SampleWidth::_16bit;
|
||||
config.channels = Channels::MonoLeft;
|
||||
|
||||
let irq = interrupt::take!(I2S);
|
||||
let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
|
||||
let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
|
||||
let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex(
|
||||
p.P0_29,
|
||||
p.P0_28,
|
||||
buffers_out,
|
||||
buffers_in,
|
||||
);
|
||||
let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
|
||||
.full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
|
||||
|
||||
let mut modulator = SineOsc::new();
|
||||
modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
|
||||
|
@ -5,14 +5,18 @@
|
||||
use defmt::{debug, error, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::pwm::{Prescaler, SimplePwm};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type Sample = i16;
|
||||
|
||||
const NUM_SAMPLES: usize = 500;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) {
|
||||
config.sample_width = SampleWidth::_16bit;
|
||||
config.channels = Channels::MonoLeft;
|
||||
|
||||
let irq = interrupt::take!(I2S);
|
||||
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
||||
let mut input_stream =
|
||||
I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
|
||||
I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
|
||||
|
||||
// Configure the PWM to use the pins corresponding to the RGB leds
|
||||
let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
|
||||
|
@ -7,13 +7,17 @@ use core::f32::consts::PI;
|
||||
use defmt::{error, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
type Sample = i16;
|
||||
|
||||
const NUM_SAMPLES: usize = 50;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) {
|
||||
config.sample_width = SampleWidth::_16bit;
|
||||
config.channels = Channels::MonoLeft;
|
||||
|
||||
let irq = interrupt::take!(I2S);
|
||||
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
||||
let mut output_stream =
|
||||
I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
|
||||
I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
|
||||
|
||||
let mut waveform = Waveform::new(1.0 / sample_rate as f32);
|
||||
|
||||
|
@ -11,11 +11,15 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_lora::sx126x::*;
|
||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
||||
use embassy_nrf::{interrupt, spim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spim};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) {
|
||||
spi_config.frequency = spim::Frequency::M16;
|
||||
|
||||
let mut radio = {
|
||||
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
||||
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
|
||||
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
||||
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
||||
|
@ -12,13 +12,17 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_lora::sx126x::*;
|
||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
||||
use embassy_nrf::{interrupt, spim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spim};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::pubsub::{PubSubChannel, Publisher};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
|
||||
use {defmt_rtt as _, panic_probe as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
|
||||
});
|
||||
|
||||
// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
|
||||
static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
|
||||
|
||||
@ -58,8 +62,7 @@ async fn main(spawner: Spawner) {
|
||||
spi_config.frequency = spim::Frequency::M16;
|
||||
|
||||
let mut radio = {
|
||||
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
||||
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||
|
||||
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
||||
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
||||
|
@ -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
|
||||
|
@ -4,16 +4,20 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::pdm::{Config, Pdm};
|
||||
use embassy_nrf::pdm::{self, Config, Pdm};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PDM => pdm::InterruptHandler<peripherals::PDM>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let config = Config::default();
|
||||
let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), p.P0_01, p.P0_00, config);
|
||||
let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
|
||||
|
||||
loop {
|
||||
pdm.start().await;
|
||||
|
@ -4,16 +4,19 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::qdec::{self, Qdec};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
QDEC => qdec::InterruptHandler<peripherals::QDEC>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let irq = interrupt::take!(QDEC);
|
||||
let config = qdec::Config::default();
|
||||
let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config);
|
||||
let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config);
|
||||
|
||||
info!("Turn rotary encoder!");
|
||||
let mut value = 0;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -3,15 +3,19 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::rng::Rng;
|
||||
use embassy_nrf::{bind_interrupts, peripherals, rng};
|
||||
use rand::Rng as _;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
|
||||
let mut rng = Rng::new(p.RNG, Irqs);
|
||||
|
||||
// Async API
|
||||
let mut bytes = [0; 4];
|
||||
|
@ -4,17 +4,21 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
|
||||
use embassy_nrf::{bind_interrupts, saadc};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SAADC => saadc::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
let config = Config::default();
|
||||
let channel_config = ChannelConfig::single_ended(&mut p.P0_02);
|
||||
let mut saadc = Saadc::new(p.SAADC, interrupt::take!(SAADC), config, [channel_config]);
|
||||
let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]);
|
||||
|
||||
loop {
|
||||
let mut buf = [0; 1];
|
||||
|
@ -4,14 +4,18 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
|
||||
use embassy_nrf::timer::Frequency;
|
||||
use embassy_nrf::{bind_interrupts, saadc};
|
||||
use embassy_time::Duration;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SAADC => saadc::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
@ -21,7 +25,7 @@ async fn main(_p: Spawner) {
|
||||
let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
|
||||
let mut saadc = Saadc::new(
|
||||
p.SAADC,
|
||||
interrupt::take!(SAADC),
|
||||
Irqs,
|
||||
config,
|
||||
[channel_1_config, channel_2_config, channel_3_config],
|
||||
);
|
||||
|
@ -5,9 +5,13 @@
|
||||
use defmt::{info, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_nrf::{interrupt, spim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spim};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut config = spim::Config::default();
|
||||
config.frequency = spim::Frequency::M16;
|
||||
|
||||
let irq = interrupt::take!(SPIM3);
|
||||
let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
|
||||
let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config);
|
||||
|
||||
let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
|
||||
|
||||
|
@ -4,17 +4,20 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::spis::{Config, Spis};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, spis};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
info!("Running!");
|
||||
|
||||
let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
|
||||
let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
|
||||
let mut spis = Spis::new(p.SPI2, Irqs, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
|
||||
|
||||
loop {
|
||||
let mut rx_buf = [0_u8; 64];
|
||||
|
@ -4,16 +4,19 @@
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::temp::Temp;
|
||||
use embassy_nrf::{bind_interrupts, temp};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
TEMP => temp::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let irq = interrupt::take!(TEMP);
|
||||
let mut temp = Temp::new(p.TEMP, irq);
|
||||
let mut temp = Temp::new(p.TEMP, Irqs);
|
||||
|
||||
loop {
|
||||
let value = temp.read().await;
|
||||
|
@ -8,19 +8,22 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::twim::{self, Twim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x50;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
info!("Initializing TWI...");
|
||||
let config = twim::Config::default();
|
||||
let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
||||
let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
|
||||
|
||||
info!("Reading...");
|
||||
|
||||
|
@ -12,25 +12,28 @@ use core::mem;
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::twim::{self, Twim};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
const ADDRESS: u8 = 0x50;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_p: Spawner) {
|
||||
let mut p = embassy_nrf::init(Default::default());
|
||||
info!("Started!");
|
||||
let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
|
||||
loop {
|
||||
info!("Initializing TWI...");
|
||||
let config = twim::Config::default();
|
||||
|
||||
// Create the TWIM instance with borrowed singletons, so they're not consumed.
|
||||
let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
|
||||
let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config);
|
||||
|
||||
info!("Reading...");
|
||||
|
||||
|
@ -6,19 +6,21 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::interrupt;
|
||||
use embassy_nrf::twis::{self, Command, Twis};
|
||||
use embassy_nrf::{bind_interrupts, peripherals};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
|
||||
let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
||||
let mut config = twis::Config::default();
|
||||
// Set i2c address
|
||||
config.address0 = 0x55;
|
||||
let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
||||
config.address0 = 0x55; // Set i2c address
|
||||
let mut i2c = Twis::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
|
||||
|
||||
info!("Listening...");
|
||||
loop {
|
||||
|
@ -4,9 +4,13 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -14,8 +18,7 @@ async fn main(_spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
||||
let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
||||
|
@ -4,9 +4,14 @@
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::peripherals::UARTE0;
|
||||
use embassy_nrf::{bind_interrupts, uarte};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||
let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
@ -6,13 +6,17 @@ use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::peripherals::UARTE0;
|
||||
use embassy_nrf::uarte::UarteRx;
|
||||
use embassy_nrf::{interrupt, uarte};
|
||||
use embassy_nrf::{bind_interrupts, uarte};
|
||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -20,8 +24,7 @@ async fn main(spawner: Spawner) {
|
||||
config.parity = uarte::Parity::EXCLUDED;
|
||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||
|
||||
let irq = interrupt::take!(UARTE0_UART0);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
||||
let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||
let (mut tx, rx) = uart.split();
|
||||
|
||||
info!("uarte initialized!");
|
||||
|
@ -9,8 +9,9 @@ use embassy_executor::Spawner;
|
||||
use embassy_net::tcp::TcpSocket;
|
||||
use embassy_net::{Stack, StackResources};
|
||||
use embassy_nrf::rng::Rng;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac, peripherals};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb};
|
||||
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
||||
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
||||
use embassy_usb::{Builder, Config, UsbDevice};
|
||||
@ -18,6 +19,12 @@ use embedded_io::asynch::Write;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
||||
|
||||
macro_rules! singleton {
|
||||
@ -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);
|
||||
|
@ -10,8 +10,9 @@ use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_nrf::gpio::{Input, Pin, Pull};
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
||||
@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler};
|
||||
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
});
|
||||
|
||||
static SUSPENDED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[embassy_executor::main]
|
||||
@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut device_descriptor = [0; 256];
|
||||
let mut config_descriptor = [0; 256];
|
||||
let mut bos_descriptor = [0; 256];
|
||||
let mut msos_descriptor = [0; 256];
|
||||
let mut control_buf = [0; 64];
|
||||
let request_handler = MyRequestHandler {};
|
||||
let mut device_handler = MyDeviceHandler::new();
|
||||
@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) {
|
||||
&mut device_descriptor,
|
||||
&mut config_descriptor,
|
||||
&mut bos_descriptor,
|
||||
&mut msos_descriptor,
|
||||
&mut control_buf,
|
||||
);
|
||||
|
||||
|
@ -7,8 +7,9 @@ use core::mem;
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
||||
use embassy_usb::control::OutResponse;
|
||||
@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config};
|
||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut device_descriptor = [0; 256];
|
||||
let mut config_descriptor = [0; 256];
|
||||
let mut bos_descriptor = [0; 256];
|
||||
let mut msos_descriptor = [0; 256];
|
||||
let mut control_buf = [0; 64];
|
||||
let request_handler = MyRequestHandler {};
|
||||
|
||||
@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) {
|
||||
&mut device_descriptor,
|
||||
&mut config_descriptor,
|
||||
&mut bos_descriptor,
|
||||
&mut msos_descriptor,
|
||||
&mut control_buf,
|
||||
);
|
||||
|
||||
|
@ -7,13 +7,19 @@ use core::mem;
|
||||
use defmt::{info, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||
use embassy_nrf::usb::{Driver, Instance};
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||
use embassy_usb::driver::EndpointError;
|
||||
use embassy_usb::{Builder, Config};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) {
|
||||
let mut device_descriptor = [0; 256];
|
||||
let mut config_descriptor = [0; 256];
|
||||
let mut bos_descriptor = [0; 256];
|
||||
let mut msos_descriptor = [0; 256];
|
||||
let mut control_buf = [0; 64];
|
||||
|
||||
let mut state = State::new();
|
||||
@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) {
|
||||
&mut device_descriptor,
|
||||
&mut config_descriptor,
|
||||
&mut bos_descriptor,
|
||||
&mut msos_descriptor,
|
||||
&mut control_buf,
|
||||
);
|
||||
|
||||
|
@ -6,14 +6,29 @@ use core::mem;
|
||||
|
||||
use defmt::{info, panic, unwrap};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
||||
use embassy_nrf::{interrupt, pac, peripherals};
|
||||
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||
use embassy_nrf::usb::Driver;
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||
use embassy_usb::driver::EndpointError;
|
||||
use embassy_usb::{Builder, Config, UsbDevice};
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
});
|
||||
|
||||
macro_rules! singleton {
|
||||
($val:expr) => {{
|
||||
type T = impl Sized;
|
||||
static STATIC_CELL: StaticCell<T> = StaticCell::new();
|
||||
let (x,) = STATIC_CELL.init(($val,));
|
||||
x
|
||||
}};
|
||||
}
|
||||
|
||||
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
||||
|
||||
#[embassy_executor::task]
|
||||
@ -39,10 +54,9 @@ async fn main(spawner: Spawner) {
|
||||
info!("Enabling ext hfosc...");
|
||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
@ -59,34 +73,21 @@ async fn main(spawner: Spawner) {
|
||||
config.device_protocol = 0x01;
|
||||
config.composite_with_iads = true;
|
||||
|
||||
struct Resources {
|
||||
device_descriptor: [u8; 256],
|
||||
config_descriptor: [u8; 256],
|
||||
bos_descriptor: [u8; 256],
|
||||
control_buf: [u8; 64],
|
||||
serial_state: State<'static>,
|
||||
}
|
||||
static RESOURCES: StaticCell<Resources> = StaticCell::new();
|
||||
let res = RESOURCES.init(Resources {
|
||||
device_descriptor: [0; 256],
|
||||
config_descriptor: [0; 256],
|
||||
bos_descriptor: [0; 256],
|
||||
control_buf: [0; 64],
|
||||
serial_state: State::new(),
|
||||
});
|
||||
let state = singleton!(State::new());
|
||||
|
||||
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||
let mut builder = Builder::new(
|
||||
driver,
|
||||
config,
|
||||
&mut res.device_descriptor,
|
||||
&mut res.config_descriptor,
|
||||
&mut res.bos_descriptor,
|
||||
&mut res.control_buf,
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 256])[..],
|
||||
&mut singleton!([0; 128])[..],
|
||||
&mut singleton!([0; 128])[..],
|
||||
);
|
||||
|
||||
// Create classes on the builder.
|
||||
let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64);
|
||||
let class = CdcAcmClass::new(&mut builder, state, 64);
|
||||
|
||||
// Build the builder.
|
||||
let usb = builder.build();
|
||||
|
@ -7,8 +7,9 @@ use core::mem;
|
||||
use defmt::{info, panic};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
||||
use embassy_nrf::{interrupt, pac};
|
||||
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||
use embassy_nrf::usb::{Driver, Instance};
|
||||
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||
use embassy_usb::driver::EndpointError;
|
||||
use embassy_usb::msos::{self, windows_version};
|
||||
@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber;
|
||||
use embassy_usb::{Builder, Config};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||
});
|
||||
|
||||
// This is a randomly generated GUID to allow clients on Windows to find our device
|
||||
const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
|
||||
|
||||
@ -29,9 +35,7 @@ async fn main(_spawner: Spawner) {
|
||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||
|
||||
// Create the driver, from the HAL.
|
||||
let irq = interrupt::take!(USBD);
|
||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
||||
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||
|
||||
// Create embassy-usb Config
|
||||
let mut config = Config::new(0xc0de, 0xcafe);
|
||||
|
@ -4,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"
|
||||
|
@ -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!");
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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"] }
|
||||
|
@ -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"] }
|
||||
|
9
tests/nrf/.cargo/config.toml
Normal file
9
tests/nrf/.cargo/config.toml
Normal 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
20
tests/nrf/Cargo.toml
Normal 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
16
tests/nrf/build.rs
Normal 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
Loading…
Reference in New Issue
Block a user