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.
|
- **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-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-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** -
|
- **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.
|
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 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/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/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
|
$BUILD_EXTRA
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
//! Executor specific to cortex-m devices.
|
//! 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::*;
|
pub use embassy_executor::*;
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
|
||||||
|
|
||||||
fn pend_by_number(n: u16) {
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct N(u16);
|
struct N(u16);
|
||||||
unsafe impl cortex_m::interrupt::InterruptNumber for N {
|
unsafe impl cortex_m::interrupt::InterruptNumber for N {
|
||||||
@ -13,6 +15,8 @@ fn pend_by_number(n: u16) {
|
|||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pend_by_number(n: u16) {
|
||||||
cortex_m::peripheral::NVIC::pend(N(n))
|
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
|
/// It is somewhat more complex to use, it's recommended to use the thread-mode
|
||||||
/// [`Executor`] instead, if it works for your use case.
|
/// [`Executor`] instead, if it works for your use case.
|
||||||
pub struct InterruptExecutor<I: Interrupt> {
|
pub struct InterruptExecutor {
|
||||||
irq: I,
|
started: AtomicBool,
|
||||||
inner: raw::Executor,
|
executor: UnsafeCell<MaybeUninit<raw::Executor>>,
|
||||||
not_send: PhantomData<*mut ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interrupt> InterruptExecutor<I> {
|
unsafe impl Send for InterruptExecutor {}
|
||||||
/// Create a new Executor.
|
unsafe impl Sync for InterruptExecutor {}
|
||||||
pub fn new(irq: I) -> Self {
|
|
||||||
let ctx = irq.number() as *mut ();
|
impl InterruptExecutor {
|
||||||
|
/// Create a new, not started `InterruptExecutor`.
|
||||||
|
#[inline]
|
||||||
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
irq,
|
started: AtomicBool::new(false),
|
||||||
inner: raw::Executor::new(|ctx| pend_by_number(ctx as u16), ctx),
|
executor: UnsafeCell::new(MaybeUninit::uninit()),
|
||||||
not_send: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// 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.
|
/// The executor keeps running in the background through the interrupt.
|
||||||
///
|
///
|
||||||
/// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`]
|
/// 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
|
/// 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.
|
/// a task running in it.
|
||||||
///
|
///
|
||||||
/// This function requires `&'static mut self`. This means you have to store the
|
/// # Interrupt requirements
|
||||||
/// Executor instance in a place where it'll live forever and grants you mutable
|
|
||||||
/// access. There's a few ways to do this:
|
|
||||||
///
|
///
|
||||||
/// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe)
|
/// You must write the interrupt handler yourself, and make it call [`on_interrupt()`](Self::on_interrupt).
|
||||||
/// - a `static mut` (unsafe)
|
///
|
||||||
/// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
|
/// This method already enables (unmasks) the interrupt, you must NOT do it yourself.
|
||||||
pub fn start(&'static mut self) -> SendSpawner {
|
///
|
||||||
self.irq.disable();
|
/// 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 {
|
unsafe {
|
||||||
let executor = &*(ctx as *const raw::Executor);
|
(&mut *self.executor.get()).as_mut_ptr().write(raw::Executor::new(
|
||||||
executor.poll();
|
|ctx| pend_by_number(ctx as u16),
|
||||||
});
|
irq.number() as *mut (),
|
||||||
self.irq.set_handler_context(&self.inner as *const _ as _);
|
))
|
||||||
self.irq.enable();
|
}
|
||||||
|
|
||||||
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};
|
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.
|
/// Implementation detail, do not use outside embassy crates.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct Handler {
|
pub struct DynHandler {
|
||||||
pub func: AtomicPtr<()>,
|
pub func: AtomicPtr<()>,
|
||||||
pub ctx: AtomicPtr<()>,
|
pub ctx: AtomicPtr<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handler {
|
impl DynHandler {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
func: AtomicPtr::new(ptr::null_mut()),
|
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.
|
/// Implementation detail, do not use outside embassy crates.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
unsafe fn __handler(&self) -> &'static Handler;
|
unsafe fn __handler(&self) -> &'static DynHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents additional behavior for all interrupts.
|
/// Represents additional behavior for all interrupts.
|
||||||
|
@ -24,6 +24,7 @@ pub fn yield_now() -> impl Future<Output = ()> {
|
|||||||
YieldNowFuture { yielded: false }
|
YieldNowFuture { yielded: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
struct YieldNowFuture {
|
struct YieldNowFuture {
|
||||||
yielded: bool,
|
yielded: bool,
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,18 @@ use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
|||||||
/// One concurrent writer and one concurrent reader are supported, even at
|
/// One concurrent writer and one concurrent reader are supported, even at
|
||||||
/// different execution priorities (like main and irq).
|
/// different execution priorities (like main and irq).
|
||||||
pub struct RingBuffer {
|
pub struct RingBuffer {
|
||||||
buf: AtomicPtr<u8>,
|
pub buf: AtomicPtr<u8>,
|
||||||
len: AtomicUsize,
|
pub len: AtomicUsize,
|
||||||
start: AtomicUsize,
|
|
||||||
end: 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);
|
pub struct Reader<'a>(&'a RingBuffer);
|
||||||
@ -90,7 +98,7 @@ impl RingBuffer {
|
|||||||
let start = self.start.load(Ordering::Relaxed);
|
let start = self.start.load(Ordering::Relaxed);
|
||||||
let end = self.end.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 {
|
pub fn is_empty(&self) -> bool {
|
||||||
@ -100,15 +108,13 @@ impl RingBuffer {
|
|||||||
start == end
|
start == end
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap(&self, n: usize) -> usize {
|
fn wrap(&self, mut n: usize) -> usize {
|
||||||
let len = self.len.load(Ordering::Relaxed);
|
let len = self.len.load(Ordering::Relaxed);
|
||||||
|
|
||||||
assert!(n <= len);
|
if n >= len * 2 {
|
||||||
if n == len {
|
n -= len * 2
|
||||||
0
|
|
||||||
} else {
|
|
||||||
n
|
|
||||||
}
|
}
|
||||||
|
n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +153,14 @@ impl<'a> Writer<'a> {
|
|||||||
unsafe { slice::from_raw_parts_mut(data, len) }
|
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.
|
/// Get a buffer where data can be pushed to.
|
||||||
///
|
///
|
||||||
/// Write data to the start of the buffer, then call `push_done` with
|
/// 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) {
|
pub fn push_buf(&mut self) -> (*mut u8, usize) {
|
||||||
// Ordering: popping writes `start` last, so we read `start` first.
|
// 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.
|
// 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 buf = self.0.buf.load(Ordering::Relaxed);
|
||||||
let len = self.0.len.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 {
|
let empty = start == end;
|
||||||
len - end - (start == 0 && len != 0) as usize
|
|
||||||
} else {
|
if start >= len {
|
||||||
start - end - 1
|
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);
|
trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n);
|
||||||
(unsafe { buf.add(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) {
|
pub fn push_done(&mut self, n: usize) {
|
||||||
trace!(" ringbuf: push {:?}", n);
|
trace!(" ringbuf: push {:?}", n);
|
||||||
let end = self.0.end.load(Ordering::Relaxed);
|
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.
|
// 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.
|
// 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.
|
// 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 buf = self.0.buf.load(Ordering::Relaxed);
|
||||||
let len = self.0.len.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);
|
trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n);
|
||||||
(unsafe { buf.add(start) }, n)
|
(unsafe { buf.add(start) }, n)
|
||||||
@ -280,12 +353,12 @@ mod tests {
|
|||||||
assert_eq!(rb.is_full(), false);
|
assert_eq!(rb.is_full(), false);
|
||||||
|
|
||||||
rb.writer().push(|buf| {
|
rb.writer().push(|buf| {
|
||||||
// If capacity is 4, we can fill it up to 3.
|
assert_eq!(4, buf.len());
|
||||||
assert_eq!(3, buf.len());
|
|
||||||
buf[0] = 1;
|
buf[0] = 1;
|
||||||
buf[1] = 2;
|
buf[1] = 2;
|
||||||
buf[2] = 3;
|
buf[2] = 3;
|
||||||
3
|
buf[3] = 4;
|
||||||
|
4
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(rb.is_empty(), false);
|
assert_eq!(rb.is_empty(), false);
|
||||||
@ -301,7 +374,7 @@ mod tests {
|
|||||||
assert_eq!(rb.is_full(), true);
|
assert_eq!(rb.is_full(), true);
|
||||||
|
|
||||||
rb.reader().pop(|buf| {
|
rb.reader().pop(|buf| {
|
||||||
assert_eq!(3, buf.len());
|
assert_eq!(4, buf.len());
|
||||||
assert_eq!(1, buf[0]);
|
assert_eq!(1, buf[0]);
|
||||||
1
|
1
|
||||||
});
|
});
|
||||||
@ -310,7 +383,7 @@ mod tests {
|
|||||||
assert_eq!(rb.is_full(), false);
|
assert_eq!(rb.is_full(), false);
|
||||||
|
|
||||||
rb.reader().pop(|buf| {
|
rb.reader().pop(|buf| {
|
||||||
assert_eq!(2, buf.len());
|
assert_eq!(3, buf.len());
|
||||||
0
|
0
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -318,11 +391,16 @@ mod tests {
|
|||||||
assert_eq!(rb.is_full(), false);
|
assert_eq!(rb.is_full(), false);
|
||||||
|
|
||||||
rb.reader().pop(|buf| {
|
rb.reader().pop(|buf| {
|
||||||
assert_eq!(2, buf.len());
|
assert_eq!(3, buf.len());
|
||||||
assert_eq!(2, buf[0]);
|
assert_eq!(2, buf[0]);
|
||||||
assert_eq!(3, buf[1]);
|
assert_eq!(3, buf[1]);
|
||||||
2
|
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_empty(), true);
|
||||||
assert_eq!(rb.is_full(), false);
|
assert_eq!(rb.is_full(), false);
|
||||||
@ -333,18 +411,27 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rb.writer().push(|buf| {
|
rb.writer().push(|buf| {
|
||||||
assert_eq!(1, buf.len());
|
assert_eq!(4, buf.len());
|
||||||
buf[0] = 10;
|
buf[0] = 10;
|
||||||
1
|
1
|
||||||
});
|
});
|
||||||
|
|
||||||
rb.writer().push(|buf| {
|
rb.writer().push(|buf| {
|
||||||
assert_eq!(2, buf.len());
|
assert_eq!(3, buf.len());
|
||||||
buf[0] = 11;
|
buf[0] = 11;
|
||||||
buf[1] = 12;
|
buf[1] = 12;
|
||||||
2
|
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_empty(), false);
|
||||||
assert_eq!(rb.is_full(), true);
|
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 {
|
unsafe fn steal() -> Self {
|
||||||
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]
|
#[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
|
&HANDLER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
|||||||
pub unsafe extern "C" fn trampoline() {
|
pub unsafe extern "C" fn trampoline() {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[link_name = #name_handler]
|
#[link_name = #name_handler]
|
||||||
static HANDLER: interrupt::Handler;
|
static HANDLER: interrupt::DynHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
|
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.
|
/// Make a query for a given name and return the corresponding IP addresses.
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
|
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| {
|
let query = poll_fn(|cx| {
|
||||||
self.with_mut(|s, i| {
|
self.with_mut(|s, i| {
|
||||||
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
|
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
//! Async buffered UART driver.
|
//! Async buffered UART driver.
|
||||||
//!
|
//!
|
||||||
//! WARNING!!! The functionality provided here is intended to be used only
|
|
||||||
//! in situations where hardware flow control are available i.e. CTS and RTS.
|
|
||||||
//! This is a problem that should be addressed at a later stage and can be
|
|
||||||
//! fully explained at <https://github.com/embassy-rs/embassy/issues/536>.
|
|
||||||
//!
|
|
||||||
//! Note that discarding a future from a read or write operation may lead to losing
|
//! Note that discarding a future from a read or write operation may lead to losing
|
||||||
//! data. For example, when using `futures_util::future::select` and completion occurs
|
//! data. For example, when using `futures_util::future::select` and completion occurs
|
||||||
//! on the "other" future, you should capture the incomplete future and continue to use
|
//! on the "other" future, you should capture the incomplete future and continue to use
|
||||||
@ -13,83 +8,236 @@
|
|||||||
//!
|
//!
|
||||||
//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used.
|
//! Please also see [crate::uarte] to understand when [BufferedUarte] should be used.
|
||||||
|
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::marker::PhantomData;
|
||||||
|
use core::slice;
|
||||||
|
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
|
use embassy_cortex_m::interrupt::Interrupt;
|
||||||
use embassy_hal_common::ring_buffer::RingBuffer;
|
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
// Re-export SVD variants to allow user to directly set values
|
// Re-export SVD variants to allow user to directly set values
|
||||||
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||||
|
|
||||||
use crate::gpio::{self, Pin as GpioPin};
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
use crate::interrupt::{self, InterruptExt};
|
||||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
use crate::ppi::{
|
||||||
|
self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
|
||||||
|
};
|
||||||
|
use crate::timer::{Instance as TimerInstance, Timer};
|
||||||
use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
|
use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
mod sealed {
|
||||||
enum RxState {
|
use super::*;
|
||||||
Idle,
|
|
||||||
Receiving,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
pub struct State {
|
||||||
enum TxState {
|
pub tx_waker: AtomicWaker,
|
||||||
Idle,
|
pub tx_buf: RingBuffer,
|
||||||
Transmitting(usize),
|
pub tx_count: AtomicUsize,
|
||||||
}
|
|
||||||
|
|
||||||
/// A type for storing the state of the UARTE peripheral that can be stored in a static.
|
pub rx_waker: AtomicWaker,
|
||||||
pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>);
|
pub rx_buf: RingBuffer,
|
||||||
impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> {
|
pub rx_bufs: AtomicU8,
|
||||||
/// Create an instance for storing UARTE peripheral state.
|
pub rx_ppi_ch: AtomicU8,
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(StateStorage::new())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StateInner<'d, U: UarteInstance, T: TimerInstance> {
|
/// UART error.
|
||||||
_peri: PeripheralRef<'d, U>,
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
timer: Timer<'d, T>,
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
_ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>,
|
#[non_exhaustive]
|
||||||
_ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>,
|
pub enum Error {
|
||||||
|
// No errors for now
|
||||||
|
}
|
||||||
|
|
||||||
rx: RingBuffer<'d>,
|
pub(crate) use sealed::State;
|
||||||
rx_state: RxState,
|
|
||||||
rx_waker: WakerRegistration,
|
|
||||||
|
|
||||||
tx: RingBuffer<'d>,
|
impl State {
|
||||||
tx_state: TxState,
|
pub(crate) const fn new() -> Self {
|
||||||
tx_waker: WakerRegistration,
|
Self {
|
||||||
|
tx_waker: AtomicWaker::new(),
|
||||||
|
tx_buf: RingBuffer::new(),
|
||||||
|
tx_count: AtomicUsize::new(0),
|
||||||
|
|
||||||
|
rx_waker: AtomicWaker::new(),
|
||||||
|
rx_buf: RingBuffer::new(),
|
||||||
|
rx_bufs: AtomicU8::new(0),
|
||||||
|
rx_ppi_ch: AtomicU8::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler<U: UarteInstance> {
|
||||||
|
_phantom: PhantomData<U>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
//trace!("irq: start");
|
||||||
|
let r = U::regs();
|
||||||
|
let s = U::buffered_state();
|
||||||
|
|
||||||
|
let buf_len = s.rx_buf.len();
|
||||||
|
let half_len = buf_len / 2;
|
||||||
|
let mut tx = unsafe { s.tx_buf.reader() };
|
||||||
|
let mut rx = unsafe { s.rx_buf.writer() };
|
||||||
|
|
||||||
|
if r.events_error.read().bits() != 0 {
|
||||||
|
r.events_error.reset();
|
||||||
|
let errs = r.errorsrc.read();
|
||||||
|
r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) });
|
||||||
|
|
||||||
|
if errs.overrun().bit() {
|
||||||
|
panic!("BufferedUarte overrun");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Received some bytes, wake task.
|
||||||
|
if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 {
|
||||||
|
r.intenclr.write(|w| w.rxdrdy().clear());
|
||||||
|
r.events_rxdrdy.reset();
|
||||||
|
s.rx_waker.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not RXing, start.
|
||||||
|
if s.rx_bufs.load(Ordering::Relaxed) == 0 {
|
||||||
|
let (ptr, len) = rx.push_buf();
|
||||||
|
if len >= half_len {
|
||||||
|
//trace!(" irq_rx: starting {:?}", half_len);
|
||||||
|
s.rx_bufs.store(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Set up the DMA read
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
|
||||||
|
|
||||||
|
// Start UARTE Receive transaction
|
||||||
|
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
|
rx.push_done(half_len);
|
||||||
|
r.intenset.write(|w| w.rxstarted().set());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.events_rxstarted.read().bits() != 0 {
|
||||||
|
//trace!(" irq_rx: rxstarted");
|
||||||
|
let (ptr, len) = rx.push_buf();
|
||||||
|
if len >= half_len {
|
||||||
|
//trace!(" irq_rx: starting second {:?}", half_len);
|
||||||
|
|
||||||
|
// Set up the DMA read
|
||||||
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) });
|
||||||
|
|
||||||
|
let chn = s.rx_ppi_ch.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) });
|
||||||
|
|
||||||
|
rx.push_done(half_len);
|
||||||
|
|
||||||
|
r.events_rxstarted.reset();
|
||||||
|
} else {
|
||||||
|
//trace!(" irq_rx: rxstarted no buf");
|
||||||
|
r.intenclr.write(|w| w.rxstarted().clear());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================
|
||||||
|
|
||||||
|
// TX end
|
||||||
|
if r.events_endtx.read().bits() != 0 {
|
||||||
|
r.events_endtx.reset();
|
||||||
|
|
||||||
|
let n = s.tx_count.load(Ordering::Relaxed);
|
||||||
|
//trace!(" irq_tx: endtx {:?}", n);
|
||||||
|
tx.pop_done(n);
|
||||||
|
s.tx_waker.wake();
|
||||||
|
s.tx_count.store(0, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not TXing, start.
|
||||||
|
if s.tx_count.load(Ordering::Relaxed) == 0 {
|
||||||
|
let (ptr, len) = tx.pop_buf();
|
||||||
|
if len != 0 {
|
||||||
|
//trace!(" irq_tx: starting {:?}", len);
|
||||||
|
s.tx_count.store(len, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Set up the DMA write
|
||||||
|
r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
|
||||||
|
r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
|
||||||
|
|
||||||
|
// Start UARTE Transmit transaction
|
||||||
|
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//trace!("irq: end");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Buffered UARTE driver.
|
/// Buffered UARTE driver.
|
||||||
pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
|
pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
|
||||||
inner: RefCell<PeripheralMutex<'d, StateInner<'d, U, T>>>,
|
_peri: PeripheralRef<'d, U>,
|
||||||
|
timer: Timer<'d, T>,
|
||||||
|
_ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
|
||||||
|
_ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
|
||||||
|
_ppi_group: PpiGroup<'d, AnyGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
|
impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
|
||||||
|
|
||||||
impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
||||||
/// Create a new instance of a BufferedUarte.
|
/// Create a new BufferedUarte without hardware flow control.
|
||||||
///
|
///
|
||||||
/// See the [module documentation](crate::buffered_uarte) for more details about the intended use.
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// The BufferedUarte uses the provided state to store the buffers and peripheral state. The timer and ppi channels are used to 'emulate' idle line detection so that read operations
|
/// Panics if `rx_buffer.len()` is odd.
|
||||||
/// can return early if there is no data to receive.
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
state: &'d mut State<'d, U, T>,
|
uarte: impl Peripheral<P = U> + 'd,
|
||||||
peri: impl Peripheral<P = U> + 'd,
|
|
||||||
timer: impl Peripheral<P = T> + 'd,
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
irq: impl Peripheral<P = U::Interrupt> + 'd,
|
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||||
|
_irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
||||||
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
|
config: Config,
|
||||||
|
rx_buffer: &'d mut [u8],
|
||||||
|
tx_buffer: &'d mut [u8],
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group);
|
||||||
|
Self::new_inner(
|
||||||
|
uarte,
|
||||||
|
timer,
|
||||||
|
ppi_ch1.map_into(),
|
||||||
|
ppi_ch2.map_into(),
|
||||||
|
ppi_group.map_into(),
|
||||||
|
rxd.map_into(),
|
||||||
|
txd.map_into(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
config,
|
||||||
|
rx_buffer,
|
||||||
|
tx_buffer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new BufferedUarte with hardware flow control (RTS/CTS)
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if `rx_buffer.len()` is odd.
|
||||||
|
pub fn new_with_rtscts(
|
||||||
|
uarte: impl Peripheral<P = U> + 'd,
|
||||||
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
|
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
|
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
|
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||||
|
_irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -98,12 +246,43 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
tx_buffer: &'d mut [u8],
|
tx_buffer: &'d mut [u8],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts);
|
into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group);
|
||||||
|
Self::new_inner(
|
||||||
|
uarte,
|
||||||
|
timer,
|
||||||
|
ppi_ch1.map_into(),
|
||||||
|
ppi_ch2.map_into(),
|
||||||
|
ppi_group.map_into(),
|
||||||
|
rxd.map_into(),
|
||||||
|
txd.map_into(),
|
||||||
|
Some(cts.map_into()),
|
||||||
|
Some(rts.map_into()),
|
||||||
|
config,
|
||||||
|
rx_buffer,
|
||||||
|
tx_buffer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_inner(
|
||||||
|
peri: impl Peripheral<P = U> + 'd,
|
||||||
|
timer: impl Peripheral<P = T> + 'd,
|
||||||
|
ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>,
|
||||||
|
ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>,
|
||||||
|
ppi_group: PeripheralRef<'d, AnyGroup>,
|
||||||
|
rxd: PeripheralRef<'d, AnyPin>,
|
||||||
|
txd: PeripheralRef<'d, AnyPin>,
|
||||||
|
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
|
config: Config,
|
||||||
|
rx_buffer: &'d mut [u8],
|
||||||
|
tx_buffer: &'d mut [u8],
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(peri, timer);
|
||||||
|
|
||||||
|
assert!(rx_buffer.len() % 2 == 0);
|
||||||
|
|
||||||
let r = U::regs();
|
let r = U::regs();
|
||||||
|
|
||||||
let mut timer = Timer::new(timer);
|
|
||||||
|
|
||||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||||
|
|
||||||
@ -111,92 +290,98 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
txd.conf().write(|w| w.dir().output().drive().h0h1());
|
txd.conf().write(|w| w.dir().output().drive().h0h1());
|
||||||
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) });
|
||||||
|
|
||||||
cts.conf().write(|w| w.input().connect().drive().h0h1());
|
if let Some(pin) = &cts {
|
||||||
|
pin.conf().write(|w| w.input().connect().drive().h0h1());
|
||||||
|
}
|
||||||
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) });
|
||||||
|
|
||||||
rts.set_high();
|
if let Some(pin) = &rts {
|
||||||
rts.conf().write(|w| w.dir().output().drive().h0h1());
|
pin.set_high();
|
||||||
|
pin.conf().write(|w| w.dir().output().drive().h0h1());
|
||||||
|
}
|
||||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||||
|
|
||||||
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
|
// Initialize state
|
||||||
r.config.write(|w| w.parity().variant(config.parity));
|
let s = U::buffered_state();
|
||||||
|
s.tx_count.store(0, Ordering::Relaxed);
|
||||||
|
s.rx_bufs.store(0, Ordering::Relaxed);
|
||||||
|
let len = tx_buffer.len();
|
||||||
|
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||||
|
let len = rx_buffer.len();
|
||||||
|
unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||||
|
|
||||||
// Configure
|
// Configure
|
||||||
r.config.write(|w| {
|
r.config.write(|w| {
|
||||||
w.hwfc().bit(true);
|
w.hwfc().bit(false);
|
||||||
w.parity().variant(config.parity);
|
w.parity().variant(config.parity);
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
|
r.baudrate.write(|w| w.baudrate().variant(config.baudrate));
|
||||||
|
|
||||||
// Enable interrupts
|
// clear errors
|
||||||
r.intenset.write(|w| w.endrx().set().endtx().set());
|
let errors = r.errorsrc.read().bits();
|
||||||
|
r.errorsrc.write(|w| unsafe { w.bits(errors) });
|
||||||
|
|
||||||
// Disable the irq, let the Registration enable it when everything is set up.
|
r.events_rxstarted.reset();
|
||||||
irq.disable();
|
r.events_txstarted.reset();
|
||||||
irq.pend();
|
r.events_error.reset();
|
||||||
|
r.events_endrx.reset();
|
||||||
|
r.events_endtx.reset();
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
r.intenclr.write(|w| unsafe { w.bits(!0) });
|
||||||
|
r.intenset.write(|w| {
|
||||||
|
w.endtx().set();
|
||||||
|
w.rxstarted().set();
|
||||||
|
w.error().set();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
|
||||||
// Enable UARTE instance
|
// Enable UARTE instance
|
||||||
apply_workaround_for_enable_anomaly(&r);
|
apply_workaround_for_enable_anomaly(&r);
|
||||||
r.enable.write(|w| w.enable().enabled());
|
r.enable.write(|w| w.enable().enabled());
|
||||||
|
|
||||||
// BAUDRATE register values are `baudrate * 2^32 / 16000000`
|
// Configure byte counter.
|
||||||
// source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
|
let mut timer = Timer::new_counter(timer);
|
||||||
//
|
timer.cc(1).write(rx_buffer.len() as u32 * 2);
|
||||||
// We want to stop RX if line is idle for 2 bytes worth of time
|
timer.cc(1).short_compare_clear();
|
||||||
// That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
|
timer.clear();
|
||||||
// This gives us the amount of 16M ticks for 20 bits.
|
timer.start();
|
||||||
let timeout = 0x8000_0000 / (config.baudrate as u32 / 40);
|
|
||||||
|
|
||||||
timer.set_frequency(Frequency::F16MHz);
|
let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count());
|
||||||
timer.cc(0).write(timeout);
|
|
||||||
timer.cc(0).short_compare_clear();
|
|
||||||
timer.cc(0).short_compare_stop();
|
|
||||||
|
|
||||||
let mut ppi_ch1 = Ppi::new_one_to_two(
|
|
||||||
ppi_ch1.map_into(),
|
|
||||||
Event::from_reg(&r.events_rxdrdy),
|
|
||||||
timer.task_clear(),
|
|
||||||
timer.task_start(),
|
|
||||||
);
|
|
||||||
ppi_ch1.enable();
|
ppi_ch1.enable();
|
||||||
|
|
||||||
let mut ppi_ch2 = Ppi::new_one_to_one(
|
s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed);
|
||||||
ppi_ch2.map_into(),
|
let mut ppi_group = PpiGroup::new(ppi_group);
|
||||||
timer.cc(0).event_compare(),
|
let mut ppi_ch2 = Ppi::new_one_to_two(
|
||||||
Task::from_reg(&r.tasks_stoprx),
|
ppi_ch2,
|
||||||
|
Event::from_reg(&r.events_endrx),
|
||||||
|
Task::from_reg(&r.tasks_startrx),
|
||||||
|
ppi_group.task_disable_all(),
|
||||||
);
|
);
|
||||||
ppi_ch2.enable();
|
ppi_ch2.disable();
|
||||||
|
ppi_group.add_channel(&ppi_ch2);
|
||||||
|
|
||||||
|
unsafe { U::Interrupt::steal() }.pend();
|
||||||
|
unsafe { U::Interrupt::steal() }.enable();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
inner: RefCell::new(PeripheralMutex::new(irq, &mut state.0, move || StateInner {
|
|
||||||
_peri: peri,
|
_peri: peri,
|
||||||
timer,
|
timer,
|
||||||
_ppi_ch1: ppi_ch1,
|
_ppi_ch1: ppi_ch1,
|
||||||
_ppi_ch2: ppi_ch2,
|
_ppi_ch2: ppi_ch2,
|
||||||
|
_ppi_group: ppi_group,
|
||||||
rx: RingBuffer::new(rx_buffer),
|
|
||||||
rx_state: RxState::Idle,
|
|
||||||
rx_waker: WakerRegistration::new(),
|
|
||||||
|
|
||||||
tx: RingBuffer::new(tx_buffer),
|
|
||||||
tx_state: TxState::Idle,
|
|
||||||
tx_waker: WakerRegistration::new(),
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pend_irq() {
|
||||||
|
unsafe { <U::Interrupt as Interrupt>::steal() }.pend()
|
||||||
|
}
|
||||||
|
|
||||||
/// Adjust the baud rate to the provided value.
|
/// Adjust the baud rate to the provided value.
|
||||||
pub fn set_baudrate(&mut self, baudrate: Baudrate) {
|
pub fn set_baudrate(&mut self, baudrate: Baudrate) {
|
||||||
self.inner.borrow_mut().with(|state| {
|
|
||||||
let r = U::regs();
|
let r = U::regs();
|
||||||
|
|
||||||
let timeout = 0x8000_0000 / (baudrate as u32 / 40);
|
|
||||||
state.timer.cc(0).write(timeout);
|
|
||||||
state.timer.clear();
|
|
||||||
|
|
||||||
r.baudrate.write(|w| w.baudrate().variant(baudrate));
|
r.baudrate.write(|w| w.baudrate().variant(baudrate));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split the UART in reader and writer parts.
|
/// Split the UART in reader and writer parts.
|
||||||
@ -206,120 +391,142 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
(BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self })
|
(BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self })
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inner_read<'a>(&'a self, buf: &'a mut [u8]) -> Result<usize, core::convert::Infallible> {
|
async fn inner_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
let data = self.inner_fill_buf().await?;
|
||||||
|
let n = data.len().min(buf.len());
|
||||||
|
buf[..n].copy_from_slice(&data[..n]);
|
||||||
|
self.inner_consume(n);
|
||||||
|
Ok(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let mut do_pend = false;
|
//trace!("poll_write: {:?}", buf.len());
|
||||||
let mut inner = self.inner.borrow_mut();
|
let s = U::buffered_state();
|
||||||
let res = inner.with(|state| {
|
let mut tx = unsafe { s.tx_buf.writer() };
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
trace!("poll_read");
|
|
||||||
|
|
||||||
// We have data ready in buffer? Return it.
|
let tx_buf = tx.push_slice();
|
||||||
let data = state.rx.pop_buf();
|
|
||||||
if !data.is_empty() {
|
|
||||||
trace!(" got {:?} {:?}", data.as_ptr() as u32, data.len());
|
|
||||||
let len = data.len().min(buf.len());
|
|
||||||
buf[..len].copy_from_slice(&data[..len]);
|
|
||||||
state.rx.pop(len);
|
|
||||||
do_pend = true;
|
|
||||||
return Poll::Ready(Ok(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!(" empty");
|
|
||||||
state.rx_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
});
|
|
||||||
if do_pend {
|
|
||||||
inner.pend();
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, core::convert::Infallible> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
let mut inner = self.inner.borrow_mut();
|
|
||||||
let res = inner.with(|state| {
|
|
||||||
trace!("poll_write: {:?}", buf.len());
|
|
||||||
|
|
||||||
let tx_buf = state.tx.push_buf();
|
|
||||||
if tx_buf.is_empty() {
|
if tx_buf.is_empty() {
|
||||||
trace!("poll_write: pending");
|
//trace!("poll_write: pending");
|
||||||
state.tx_waker.register(cx.waker());
|
s.tx_waker.register(cx.waker());
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
let n = min(tx_buf.len(), buf.len());
|
let n = min(tx_buf.len(), buf.len());
|
||||||
tx_buf[..n].copy_from_slice(&buf[..n]);
|
tx_buf[..n].copy_from_slice(&buf[..n]);
|
||||||
state.tx.push(n);
|
tx.push_done(n);
|
||||||
|
|
||||||
trace!("poll_write: queued {:?}", n);
|
//trace!("poll_write: queued {:?}", n);
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
Self::pend_irq();
|
||||||
|
|
||||||
Poll::Ready(Ok(n))
|
Poll::Ready(Ok(n))
|
||||||
});
|
|
||||||
|
|
||||||
inner.pend();
|
|
||||||
|
|
||||||
res
|
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inner_flush<'a>(&'a self) -> Result<(), core::convert::Infallible> {
|
async fn inner_flush<'a>(&'a self) -> Result<(), Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
self.inner.borrow_mut().with(|state| {
|
//trace!("poll_flush");
|
||||||
trace!("poll_flush");
|
let s = U::buffered_state();
|
||||||
|
if !s.tx_buf.is_empty() {
|
||||||
if !state.tx.is_empty() {
|
//trace!("poll_flush: pending");
|
||||||
trace!("poll_flush: pending");
|
s.tx_waker.register(cx.waker());
|
||||||
state.tx_waker.register(cx.waker());
|
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll::Ready(Ok(()))
|
Poll::Ready(Ok(()))
|
||||||
})
|
})
|
||||||
})
|
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], core::convert::Infallible> {
|
async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
self.inner.borrow_mut().with(|state| {
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
trace!("fill_buf");
|
//trace!("poll_read");
|
||||||
|
|
||||||
// We have data ready in buffer? Return it.
|
let r = U::regs();
|
||||||
let buf = state.rx.pop_buf();
|
let s = U::buffered_state();
|
||||||
if !buf.is_empty() {
|
|
||||||
trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len());
|
// Read the RXDRDY counter.
|
||||||
let buf: &[u8] = buf;
|
T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) });
|
||||||
// Safety: buffer lives as long as uart
|
let mut end = T::regs().cc[0].read().bits() as usize;
|
||||||
let buf: &[u8] = unsafe { core::mem::transmute(buf) };
|
//trace!(" rxdrdy count = {:?}", end);
|
||||||
return Poll::Ready(Ok(buf));
|
|
||||||
|
// We've set a compare channel that resets the counter to 0 when it reaches `len*2`.
|
||||||
|
// However, it's unclear if that's instant, or there's a small window where you can
|
||||||
|
// still read `len()*2`.
|
||||||
|
// This could happen if in one clock cycle the counter is updated, and in the next the
|
||||||
|
// clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER
|
||||||
|
// is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one
|
||||||
|
// clock cycle of the PCLK16M." :shrug:
|
||||||
|
// So, we wrap the counter ourselves, just in case.
|
||||||
|
if end > s.rx_buf.len() * 2 {
|
||||||
|
end = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(" empty");
|
// This logic mirrors `atomic_ring_buffer::Reader::pop_buf()`
|
||||||
state.rx_waker.register(cx.waker());
|
let mut start = s.rx_buf.start.load(Ordering::Relaxed);
|
||||||
Poll::<Result<&[u8], core::convert::Infallible>>::Pending
|
let len = s.rx_buf.len();
|
||||||
})
|
if start == end {
|
||||||
|
//trace!(" empty");
|
||||||
|
s.rx_waker.register(cx.waker());
|
||||||
|
r.intenset.write(|w| w.rxdrdy().set_bit());
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
if start >= len {
|
||||||
|
start -= len
|
||||||
|
}
|
||||||
|
if end >= len {
|
||||||
|
end -= len
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = if end > start { end - start } else { len - start };
|
||||||
|
assert!(n != 0);
|
||||||
|
//trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n);
|
||||||
|
|
||||||
|
let buf = s.rx_buf.buf.load(Ordering::Relaxed);
|
||||||
|
Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) }))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_consume(&self, amt: usize) {
|
fn inner_consume(&self, amt: usize) {
|
||||||
let mut inner = self.inner.borrow_mut();
|
if amt == 0 {
|
||||||
let signal = inner.with(|state| {
|
return;
|
||||||
let full = state.rx.is_full();
|
|
||||||
state.rx.pop(amt);
|
|
||||||
full
|
|
||||||
});
|
|
||||||
if signal {
|
|
||||||
inner.pend();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let s = U::buffered_state();
|
||||||
|
let mut rx = unsafe { s.rx_buf.reader() };
|
||||||
|
rx.pop_done(amt);
|
||||||
|
U::regs().intenset.write(|w| w.rxstarted().set());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
|
||||||
|
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
self.inner_read(buf).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
|
||||||
|
pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
|
||||||
|
self.inner_fill_buf().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
|
||||||
|
pub fn consume(&mut self, amt: usize) {
|
||||||
|
self.inner_consume(amt)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a buffer into this writer, returning how many bytes were written.
|
||||||
|
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
|
self.inner_write(buf).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
||||||
|
pub async fn flush(&mut self) -> Result<(), Error> {
|
||||||
|
self.inner_flush().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,21 +535,60 @@ pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> {
|
|||||||
inner: &'u BufferedUarte<'d, U, T>,
|
inner: &'u BufferedUarte<'d, U, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> {
|
||||||
|
/// Write a buffer into this writer, returning how many bytes were written.
|
||||||
|
pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
|
self.inner.inner_write(buf).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
||||||
|
pub async fn flush(&mut self) -> Result<(), Error> {
|
||||||
|
self.inner.inner_flush().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Writer part of the buffered UARTE driver.
|
/// Writer part of the buffered UARTE driver.
|
||||||
pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> {
|
pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> {
|
||||||
inner: &'u BufferedUarte<'d, U, T>,
|
inner: &'u BufferedUarte<'d, U, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> {
|
||||||
|
/// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
|
||||||
|
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
self.inner.inner_read(buf).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
|
||||||
|
pub async fn fill_buf(&mut self) -> Result<&[u8], Error> {
|
||||||
|
self.inner.inner_fill_buf().await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
|
||||||
|
pub fn consume(&mut self, amt: usize) {
|
||||||
|
self.inner.inner_consume(amt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "nightly")]
|
||||||
|
mod _embedded_io {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl embedded_io::Error for Error {
|
||||||
|
fn kind(&self) -> embedded_io::ErrorKind {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> {
|
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> {
|
||||||
type Error = core::convert::Infallible;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> {
|
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> {
|
||||||
type Error = core::convert::Infallible;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> {
|
impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> {
|
||||||
type Error = core::convert::Infallible;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
|
impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> {
|
||||||
@ -396,8 +642,9 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write
|
|||||||
self.inner.inner_flush().await
|
self.inner.inner_flush().await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
|
impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let r = U::regs();
|
let r = U::regs();
|
||||||
|
|
||||||
@ -418,108 +665,11 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
|
|||||||
gpio::deconfigure_pin(r.psel.txd.read().bits());
|
gpio::deconfigure_pin(r.psel.txd.read().bits());
|
||||||
gpio::deconfigure_pin(r.psel.rts.read().bits());
|
gpio::deconfigure_pin(r.psel.rts.read().bits());
|
||||||
gpio::deconfigure_pin(r.psel.cts.read().bits());
|
gpio::deconfigure_pin(r.psel.cts.read().bits());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, U, T> {
|
let s = U::buffered_state();
|
||||||
type Interrupt = U::Interrupt;
|
unsafe {
|
||||||
fn on_interrupt(&mut self) {
|
s.rx_buf.deinit();
|
||||||
trace!("irq: start");
|
s.tx_buf.deinit();
|
||||||
let r = U::regs();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match self.rx_state {
|
|
||||||
RxState::Idle => {
|
|
||||||
trace!(" irq_rx: in state idle");
|
|
||||||
|
|
||||||
let buf = self.rx.push_buf();
|
|
||||||
if !buf.is_empty() {
|
|
||||||
trace!(" irq_rx: starting {:?}", buf.len());
|
|
||||||
self.rx_state = RxState::Receiving;
|
|
||||||
|
|
||||||
// Set up the DMA read
|
|
||||||
r.rxd.ptr.write(|w|
|
|
||||||
// The PTR field is a full 32 bits wide and accepts the full range
|
|
||||||
// of values.
|
|
||||||
unsafe { w.ptr().bits(buf.as_ptr() as u32) });
|
|
||||||
r.rxd.maxcnt.write(|w|
|
|
||||||
// We're giving it the length of the buffer, so no danger of
|
|
||||||
// accessing invalid memory. We have verified that the length of the
|
|
||||||
// buffer fits in an `u8`, so the cast to `u8` is also fine.
|
|
||||||
//
|
|
||||||
// The MAXCNT field is at least 8 bits wide and accepts the full
|
|
||||||
// range of values.
|
|
||||||
unsafe { w.maxcnt().bits(buf.len() as _) });
|
|
||||||
trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len());
|
|
||||||
|
|
||||||
// Start UARTE Receive transaction
|
|
||||||
r.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
RxState::Receiving => {
|
|
||||||
trace!(" irq_rx: in state receiving");
|
|
||||||
if r.events_endrx.read().bits() != 0 {
|
|
||||||
self.timer.stop();
|
|
||||||
|
|
||||||
let n: usize = r.rxd.amount.read().amount().bits() as usize;
|
|
||||||
trace!(" irq_rx: endrx {:?}", n);
|
|
||||||
self.rx.push(n);
|
|
||||||
|
|
||||||
r.events_endrx.reset();
|
|
||||||
|
|
||||||
self.rx_waker.wake();
|
|
||||||
self.rx_state = RxState::Idle;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match self.tx_state {
|
|
||||||
TxState::Idle => {
|
|
||||||
trace!(" irq_tx: in state Idle");
|
|
||||||
let buf = self.tx.pop_buf();
|
|
||||||
if !buf.is_empty() {
|
|
||||||
trace!(" irq_tx: starting {:?}", buf.len());
|
|
||||||
self.tx_state = TxState::Transmitting(buf.len());
|
|
||||||
|
|
||||||
// Set up the DMA write
|
|
||||||
r.txd.ptr.write(|w|
|
|
||||||
// The PTR field is a full 32 bits wide and accepts the full range
|
|
||||||
// of values.
|
|
||||||
unsafe { w.ptr().bits(buf.as_ptr() as u32) });
|
|
||||||
r.txd.maxcnt.write(|w|
|
|
||||||
// We're giving it the length of the buffer, so no danger of
|
|
||||||
// accessing invalid memory. We have verified that the length of the
|
|
||||||
// buffer fits in an `u8`, so the cast to `u8` is also fine.
|
|
||||||
//
|
|
||||||
// The MAXCNT field is 8 bits wide and accepts the full range of
|
|
||||||
// values.
|
|
||||||
unsafe { w.maxcnt().bits(buf.len() as _) });
|
|
||||||
|
|
||||||
// Start UARTE Transmit transaction
|
|
||||||
r.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
TxState::Transmitting(n) => {
|
|
||||||
trace!(" irq_tx: in state Transmitting");
|
|
||||||
if r.events_endtx.read().bits() != 0 {
|
|
||||||
r.events_endtx.reset();
|
|
||||||
|
|
||||||
trace!(" irq_tx: endtx {:?}", n);
|
|
||||||
self.tx.pop(n);
|
|
||||||
self.tx_waker.wake();
|
|
||||||
self.tx_state = TxState::Idle;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trace!("irq: end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -140,6 +140,10 @@ impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0);
|
|||||||
|
|
||||||
impl_twis!(TWI0, TWIS0, 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!(TIMER0, TIMER0, TIMER0);
|
||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
|
@ -148,6 +148,12 @@ impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0);
|
|||||||
|
|
||||||
impl_pwm!(PWM0, PWM0, PWM0);
|
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!(TIMER0, TIMER0, TIMER0);
|
||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
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_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!(TIMER0, TIMER0, TIMER0);
|
||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
|
@ -153,6 +153,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1);
|
|||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
impl_timer!(TIMER3, TIMER3, TIMER3, extended);
|
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_00, 0, 0);
|
||||||
impl_pin!(P0_01, 0, 1);
|
impl_pin!(P0_01, 0, 1);
|
||||||
impl_pin!(P0_02, 0, 2);
|
impl_pin!(P0_02, 0, 2);
|
||||||
|
@ -146,6 +146,9 @@ embassy_hal_common::peripherals! {
|
|||||||
|
|
||||||
// I2S
|
// I2S
|
||||||
I2S,
|
I2S,
|
||||||
|
|
||||||
|
// PDM
|
||||||
|
PDM,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
|
||||||
@ -168,6 +171,12 @@ impl_pwm!(PWM0, PWM0, PWM0);
|
|||||||
impl_pwm!(PWM1, PWM1, PWM1);
|
impl_pwm!(PWM1, PWM1, PWM1);
|
||||||
impl_pwm!(PWM2, PWM2, PWM2);
|
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!(TIMER0, TIMER0, TIMER0);
|
||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
|
@ -197,6 +197,12 @@ impl_pwm!(PWM1, PWM1, PWM1);
|
|||||||
impl_pwm!(PWM2, PWM2, PWM2);
|
impl_pwm!(PWM2, PWM2, PWM2);
|
||||||
impl_pwm!(PWM3, PWM3, PWM3);
|
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!(TIMER0, TIMER0, TIMER0);
|
||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
|
@ -208,6 +208,12 @@ impl_timer!(TIMER4, TIMER4, TIMER4, extended);
|
|||||||
|
|
||||||
impl_qspi!(QSPI, QSPI, QSPI);
|
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_00, 0, 0);
|
||||||
impl_pin!(P0_01, 0, 1);
|
impl_pin!(P0_01, 0, 1);
|
||||||
impl_pin!(P0_02, 0, 2);
|
impl_pin!(P0_02, 0, 2);
|
||||||
|
@ -34,10 +34,10 @@ pub mod pac {
|
|||||||
nvmc_ns as nvmc,
|
nvmc_ns as nvmc,
|
||||||
oscillators_ns as oscillators,
|
oscillators_ns as oscillators,
|
||||||
p0_ns as p0,
|
p0_ns as p0,
|
||||||
pdm0_ns as pdm0,
|
pdm0_ns as pdm,
|
||||||
power_ns as power,
|
power_ns as power,
|
||||||
pwm0_ns as pwm0,
|
pwm0_ns as pwm0,
|
||||||
qdec0_ns as qdec0,
|
qdec0_ns as qdec,
|
||||||
qspi_ns as qspi,
|
qspi_ns as qspi,
|
||||||
regulators_ns as regulators,
|
regulators_ns as regulators,
|
||||||
reset_ns as reset,
|
reset_ns as reset,
|
||||||
@ -250,6 +250,16 @@ embassy_hal_common::peripherals! {
|
|||||||
TIMER1,
|
TIMER1,
|
||||||
TIMER2,
|
TIMER2,
|
||||||
|
|
||||||
|
// QSPI
|
||||||
|
QSPI,
|
||||||
|
|
||||||
|
// PDM
|
||||||
|
PDM0,
|
||||||
|
|
||||||
|
// QDEC
|
||||||
|
QDEC0,
|
||||||
|
QDEC1,
|
||||||
|
|
||||||
// GPIOTE
|
// GPIOTE
|
||||||
GPIOTE_CH0,
|
GPIOTE_CH0,
|
||||||
GPIOTE_CH1,
|
GPIOTE_CH1,
|
||||||
@ -393,6 +403,13 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
|||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
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_00, 0, 0);
|
||||||
impl_pin!(P0_01, 0, 1);
|
impl_pin!(P0_01, 0, 1);
|
||||||
#[cfg(feature = "nfc-pins-as-gpio")]
|
#[cfg(feature = "nfc-pins-as-gpio")]
|
||||||
|
@ -127,6 +127,9 @@ embassy_hal_common::peripherals! {
|
|||||||
// SAADC
|
// SAADC
|
||||||
SAADC,
|
SAADC,
|
||||||
|
|
||||||
|
// RNG
|
||||||
|
RNG,
|
||||||
|
|
||||||
// PWM
|
// PWM
|
||||||
PWM0,
|
PWM0,
|
||||||
PWM1,
|
PWM1,
|
||||||
@ -252,6 +255,8 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
|
|||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||||
|
|
||||||
|
impl_rng!(RNG, RNG, RNG);
|
||||||
|
|
||||||
impl_pin!(P0_00, 0, 0);
|
impl_pin!(P0_00, 0, 0);
|
||||||
impl_pin!(P0_01, 0, 1);
|
impl_pin!(P0_01, 0, 1);
|
||||||
impl_pin!(P0_02, 0, 2);
|
impl_pin!(P0_02, 0, 2);
|
||||||
|
@ -301,6 +301,8 @@ impl_pwm!(PWM1, PWM1, PWM1);
|
|||||||
impl_pwm!(PWM2, PWM2, PWM2);
|
impl_pwm!(PWM2, PWM2, PWM2);
|
||||||
impl_pwm!(PWM3, PWM3, PWM3);
|
impl_pwm!(PWM3, PWM3, PWM3);
|
||||||
|
|
||||||
|
impl_pdm!(PDM, PDM, PDM);
|
||||||
|
|
||||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
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> {
|
pub(crate) struct PortInputFuture<'a> {
|
||||||
pin: PeripheralRef<'a, AnyPin>,
|
pin: PeripheralRef<'a, AnyPin>,
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use embassy_hal_common::drop::OnDrop;
|
|||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::Interrupt;
|
use crate::interrupt::{self, Interrupt};
|
||||||
use crate::pac::i2s::RegisterBlock;
|
use crate::pac::i2s::RegisterBlock;
|
||||||
use crate::util::{slice_in_ram_or, slice_ptr_parts};
|
use crate::util::{slice_in_ram_or, slice_ptr_parts};
|
||||||
use crate::{Peripheral, EASY_DMA_SIZE};
|
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.
|
/// I2S driver.
|
||||||
pub struct I2S<'d, T: Instance> {
|
pub struct I2S<'d, T: Instance> {
|
||||||
i2s: PeripheralRef<'d, T>,
|
i2s: PeripheralRef<'d, T>,
|
||||||
irq: PeripheralRef<'d, T::Interrupt>,
|
|
||||||
mck: Option<PeripheralRef<'d, AnyPin>>,
|
mck: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
sck: PeripheralRef<'d, AnyPin>,
|
sck: PeripheralRef<'d, AnyPin>,
|
||||||
lrck: PeripheralRef<'d, AnyPin>,
|
lrck: PeripheralRef<'d, AnyPin>,
|
||||||
@ -378,19 +407,18 @@ pub struct I2S<'d, T: Instance> {
|
|||||||
|
|
||||||
impl<'d, T: Instance> I2S<'d, T> {
|
impl<'d, T: Instance> I2S<'d, T> {
|
||||||
/// Create a new I2S in master mode
|
/// Create a new I2S in master mode
|
||||||
pub fn master(
|
pub fn new_master(
|
||||||
i2s: impl Peripheral<P = T> + 'd,
|
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,
|
mck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
master_clock: MasterClock,
|
master_clock: MasterClock,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(i2s, irq, mck, sck, lrck);
|
into_ref!(i2s, mck, sck, lrck);
|
||||||
Self {
|
Self {
|
||||||
i2s,
|
i2s,
|
||||||
irq,
|
|
||||||
mck: Some(mck.map_into()),
|
mck: Some(mck.map_into()),
|
||||||
sck: sck.map_into(),
|
sck: sck.map_into(),
|
||||||
lrck: lrck.map_into(),
|
lrck: lrck.map_into(),
|
||||||
@ -402,17 +430,16 @@ impl<'d, T: Instance> I2S<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new I2S in slave mode
|
/// Create a new I2S in slave mode
|
||||||
pub fn slave(
|
pub fn new_slave(
|
||||||
i2s: impl Peripheral<P = T> + 'd,
|
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,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(i2s, irq, sck, lrck);
|
into_ref!(i2s, sck, lrck);
|
||||||
Self {
|
Self {
|
||||||
i2s,
|
i2s,
|
||||||
irq,
|
|
||||||
mck: None,
|
mck: None,
|
||||||
sck: sck.map_into(),
|
sck: sck.map_into(),
|
||||||
lrck: lrck.map_into(),
|
lrck: lrck.map_into(),
|
||||||
@ -537,9 +564,8 @@ impl<'d, T: Instance> I2S<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_interrupt(&self) {
|
fn setup_interrupt(&self) {
|
||||||
self.irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
self.irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
self.irq.enable();
|
|
||||||
|
|
||||||
let device = Device::<T>::new();
|
let device = Device::<T>::new();
|
||||||
device.disable_tx_ptr_interrupt();
|
device.disable_tx_ptr_interrupt();
|
||||||
@ -555,29 +581,6 @@ impl<'d, T: Instance> I2S<'d, T> {
|
|||||||
device.enable_stopped_interrupt();
|
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() {
|
async fn stop() {
|
||||||
compiler_fence(Ordering::SeqCst);
|
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 {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: Interrupt;
|
||||||
|
@ -37,7 +37,6 @@ pub(crate) mod util;
|
|||||||
#[cfg(feature = "_time-driver")]
|
#[cfg(feature = "_time-driver")]
|
||||||
mod time_driver;
|
mod time_driver;
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
|
||||||
pub mod buffered_uarte;
|
pub mod buffered_uarte;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
#[cfg(feature = "gpiote")]
|
#[cfg(feature = "gpiote")]
|
||||||
@ -48,19 +47,21 @@ pub mod nvmc;
|
|||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "nrf52810",
|
feature = "nrf52810",
|
||||||
feature = "nrf52811",
|
feature = "nrf52811",
|
||||||
|
feature = "nrf52832",
|
||||||
feature = "nrf52833",
|
feature = "nrf52833",
|
||||||
feature = "nrf52840",
|
feature = "nrf52840",
|
||||||
|
feature = "_nrf5340-app",
|
||||||
feature = "_nrf9160"
|
feature = "_nrf9160"
|
||||||
))]
|
))]
|
||||||
pub mod pdm;
|
pub mod pdm;
|
||||||
pub mod ppi;
|
pub mod ppi;
|
||||||
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
|
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||||
pub mod pwm;
|
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;
|
pub mod qdec;
|
||||||
#[cfg(feature = "nrf52840")]
|
#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
|
||||||
pub mod qspi;
|
pub mod qspi;
|
||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
|
#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||||
pub mod saadc;
|
pub mod saadc;
|
||||||
@ -96,14 +97,39 @@ pub mod wdt;
|
|||||||
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
||||||
mod chip;
|
mod chip;
|
||||||
|
|
||||||
pub use chip::EASY_DMA_SIZE;
|
|
||||||
|
|
||||||
pub mod interrupt {
|
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 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::*;
|
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
|
// Reexports
|
||||||
@ -112,7 +138,7 @@ pub mod interrupt {
|
|||||||
pub use chip::pac;
|
pub use chip::pac;
|
||||||
#[cfg(not(feature = "unstable-pac"))]
|
#[cfg(not(feature = "unstable-pac"))]
|
||||||
pub(crate) use chip::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::executor;
|
||||||
pub use embassy_cortex_m::interrupt::_export::interrupt;
|
pub use embassy_cortex_m::interrupt::_export::interrupt;
|
||||||
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||||
|
@ -1,25 +1,37 @@
|
|||||||
//! Pulse Density Modulation (PDM) mirophone driver.
|
//! Pulse Density Modulation (PDM) mirophone driver.
|
||||||
|
|
||||||
|
#![macro_use]
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_cortex_m::interrupt::Interrupt;
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
|
|
||||||
use crate::chip::EASY_DMA_SIZE;
|
use crate::chip::EASY_DMA_SIZE;
|
||||||
use crate::gpio::sealed::Pin;
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::{self, InterruptExt};
|
use crate::interrupt::{self, InterruptExt};
|
||||||
use crate::peripherals::PDM;
|
use crate::Peripheral;
|
||||||
use crate::{pac, 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
|
/// PDM microphone interface
|
||||||
pub struct Pdm<'d> {
|
pub struct Pdm<'d, T: Instance> {
|
||||||
irq: PeripheralRef<'d, interrupt::PDM>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
phantom: PhantomData<&'d PDM>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PDM error.
|
/// PDM error.
|
||||||
@ -35,32 +47,30 @@ pub enum Error {
|
|||||||
NotRunning,
|
NotRunning,
|
||||||
}
|
}
|
||||||
|
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
|
||||||
static DUMMY_BUFFER: [i16; 1] = [0; 1];
|
static DUMMY_BUFFER: [i16; 1] = [0; 1];
|
||||||
|
|
||||||
impl<'d> Pdm<'d> {
|
impl<'d, T: Instance> Pdm<'d, T> {
|
||||||
/// Create PDM driver
|
/// Create PDM driver
|
||||||
pub fn new(
|
pub fn new(
|
||||||
pdm: impl Peripheral<P = PDM> + 'd,
|
pdm: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = interrupt::PDM> + 'd,
|
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
clk: impl Peripheral<P = impl GpioPin> + 'd,
|
clk: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
din: impl Peripheral<P = impl GpioPin> + 'd,
|
din: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(clk, din);
|
into_ref!(pdm, clk, din);
|
||||||
Self::new_inner(pdm, irq, clk.map_into(), din.map_into(), config)
|
Self::new_inner(pdm, clk.map_into(), din.map_into(), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
_pdm: impl Peripheral<P = PDM> + 'd,
|
pdm: PeripheralRef<'d, T>,
|
||||||
irq: impl Peripheral<P = interrupt::PDM> + 'd,
|
|
||||||
clk: PeripheralRef<'d, AnyPin>,
|
clk: PeripheralRef<'d, AnyPin>,
|
||||||
din: PeripheralRef<'d, AnyPin>,
|
din: PeripheralRef<'d, AnyPin>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(irq);
|
into_ref!(pdm);
|
||||||
|
|
||||||
let r = Self::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
// setup gpio pins
|
// setup gpio pins
|
||||||
din.conf().write(|w| w.input().set_bit());
|
din.conf().write(|w| w.input().set_bit());
|
||||||
@ -84,26 +94,18 @@ impl<'d> Pdm<'d> {
|
|||||||
r.gainr.write(|w| w.gainr().default_gain());
|
r.gainr.write(|w| w.gainr().default_gain());
|
||||||
|
|
||||||
// IRQ
|
// IRQ
|
||||||
irq.disable();
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.set_handler(|_| {
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
let r = Self::regs();
|
|
||||||
r.intenclr.write(|w| w.end().clear());
|
|
||||||
WAKER.wake();
|
|
||||||
});
|
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
r.enable.write(|w| w.enable().set_bit());
|
r.enable.write(|w| w.enable().set_bit());
|
||||||
|
|
||||||
Self {
|
Self { _peri: pdm }
|
||||||
phantom: PhantomData,
|
|
||||||
irq,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start sampling microphon data into a dummy buffer
|
/// Start sampling microphon data into a dummy buffer
|
||||||
/// Usefull to start the microphon and keep it active between recording samples
|
/// Usefull to start the microphon and keep it active between recording samples
|
||||||
pub async fn start(&mut self) {
|
pub async fn start(&mut self) {
|
||||||
let r = Self::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
// start dummy sampling because microphon needs some setup time
|
// start dummy sampling because microphon needs some setup time
|
||||||
r.sample
|
r.sample
|
||||||
@ -113,13 +115,13 @@ impl<'d> Pdm<'d> {
|
|||||||
.maxcnt
|
.maxcnt
|
||||||
.write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) });
|
.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
|
/// Stop sampling microphon data inta a dummy buffer
|
||||||
pub async fn stop(&mut self) {
|
pub async fn stop(&mut self) {
|
||||||
let r = Self::regs();
|
let r = T::regs();
|
||||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||||
r.events_started.reset();
|
r.events_started.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +134,9 @@ impl<'d> Pdm<'d> {
|
|||||||
return Err(Error::BufferTooLong);
|
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);
|
return Err(Error::NotRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +181,7 @@ impl<'d> Pdm<'d> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_sample() {
|
async fn wait_for_sample() {
|
||||||
let r = Self::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
r.events_end.reset();
|
r.events_end.reset();
|
||||||
r.intenset.write(|w| w.end().set());
|
r.intenset.write(|w| w.end().set());
|
||||||
@ -187,8 +189,8 @@ impl<'d> Pdm<'d> {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
WAKER.register(cx.waker());
|
T::state().waker.register(cx.waker());
|
||||||
if r.events_end.read().events_end().bit_is_set() {
|
if r.events_end.read().bits() != 0 {
|
||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -197,10 +199,6 @@ impl<'d> Pdm<'d> {
|
|||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regs() -> &'static pac::pdm::RegisterBlock {
|
|
||||||
unsafe { &*pac::PDM::ptr() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PDM microphone driver Config
|
/// PDM microphone driver Config
|
||||||
@ -238,13 +236,11 @@ pub enum Edge {
|
|||||||
LeftFalling,
|
LeftFalling,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Drop for Pdm<'d> {
|
impl<'d, T: Instance> Drop for Pdm<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let r = Self::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
r.tasks_stop.write(|w| w.tasks_stop().set_bit());
|
r.tasks_stop.write(|w| unsafe { w.bits(1) });
|
||||||
|
|
||||||
self.irq.disable();
|
|
||||||
|
|
||||||
r.enable.write(|w| w.enable().disabled());
|
r.enable.write(|w| w.enable().disabled());
|
||||||
|
|
||||||
@ -252,3 +248,48 @@ impl<'d> Drop for Pdm<'d> {
|
|||||||
r.psel.clk.reset();
|
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_ENABLE_BIT: u32 = 0x8000_0000;
|
||||||
const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF;
|
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() }
|
unsafe { &*pac::DPPIC::ptr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,16 +17,16 @@
|
|||||||
|
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
use embassy_hal_common::{impl_peripheral, PeripheralRef};
|
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::{peripherals, Peripheral};
|
use crate::{peripherals, Peripheral};
|
||||||
|
|
||||||
#[cfg(feature = "_dppi")]
|
#[cfg_attr(feature = "_dppi", path = "dppi.rs")]
|
||||||
mod dppi;
|
#[cfg_attr(feature = "_ppi", path = "ppi.rs")]
|
||||||
#[cfg(feature = "_ppi")]
|
mod _version;
|
||||||
mod ppi;
|
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> {
|
pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> {
|
||||||
ch: PeripheralRef<'d, C>,
|
ch: PeripheralRef<'d, C>,
|
||||||
#[cfg(feature = "_dppi")]
|
#[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],
|
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")]
|
#[cfg(feature = "_dppi")]
|
||||||
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
|
const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>();
|
||||||
|
|
||||||
@ -112,7 +194,7 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Interface for PPI channels.
|
/// 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
|
/// Returns the number of the channel
|
||||||
fn number(&self) -> usize;
|
fn number(&self) -> usize;
|
||||||
}
|
}
|
||||||
@ -130,7 +212,7 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Interface for a group of PPI channels.
|
/// 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.
|
/// Returns the number of the group.
|
||||||
fn number(&self) -> usize;
|
fn number(&self) -> usize;
|
||||||
/// Convert into a type erased group.
|
/// Convert into a type erased group.
|
||||||
@ -248,6 +330,12 @@ macro_rules! impl_group {
|
|||||||
$number
|
$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() }
|
unsafe { &*pac::PPI::ptr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
//! Quadrature decoder (QDEC) driver.
|
//! Quadrature decoder (QDEC) driver.
|
||||||
|
|
||||||
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_cortex_m::interrupt::Interrupt;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
|
||||||
|
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::peripherals::QDEC;
|
use crate::{interrupt, Peripheral};
|
||||||
use crate::{interrupt, pac, Peripheral};
|
|
||||||
|
|
||||||
/// Quadrature decoder driver.
|
/// Quadrature decoder driver.
|
||||||
pub struct Qdec<'d> {
|
pub struct Qdec<'d, T: Instance> {
|
||||||
_p: PeripheralRef<'d, QDEC>,
|
_p: PeripheralRef<'d, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QDEC config
|
/// 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.
|
/// Create a new QDEC.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
qdec: impl Peripheral<P = QDEC> + 'd,
|
qdec: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(a, b);
|
into_ref!(qdec, a, b);
|
||||||
Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config)
|
Self::new_inner(qdec, a.map_into(), b.map_into(), None, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new QDEC, with a pin for LED output.
|
/// Create a new QDEC, with a pin for LED output.
|
||||||
pub fn new_with_led(
|
pub fn new_with_led(
|
||||||
qdec: impl Peripheral<P = QDEC> + 'd,
|
qdec: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
led: impl Peripheral<P = impl GpioPin> + 'd,
|
led: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(a, b, led);
|
into_ref!(qdec, a, b, led);
|
||||||
Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config)
|
Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
p: impl Peripheral<P = QDEC> + 'd,
|
p: PeripheralRef<'d, T>,
|
||||||
irq: impl Peripheral<P = interrupt::QDEC> + 'd,
|
|
||||||
a: PeripheralRef<'d, AnyPin>,
|
a: PeripheralRef<'d, AnyPin>,
|
||||||
b: PeripheralRef<'d, AnyPin>,
|
b: PeripheralRef<'d, AnyPin>,
|
||||||
led: Option<PeripheralRef<'d, AnyPin>>,
|
led: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(p, irq);
|
let r = T::regs();
|
||||||
let r = Self::regs();
|
|
||||||
|
|
||||||
// Select pins.
|
// Select pins.
|
||||||
a.conf().write(|w| w.input().connect().pull().pullup());
|
a.conf().write(|w| w.input().connect().pull().pullup());
|
||||||
@ -124,20 +134,15 @@ impl<'d> Qdec<'d> {
|
|||||||
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
|
|
||||||
// Enable peripheral
|
// Enable peripheral
|
||||||
r.enable.write(|w| w.enable().set_bit());
|
r.enable.write(|w| w.enable().set_bit());
|
||||||
|
|
||||||
// Start sampling
|
// Start sampling
|
||||||
unsafe { r.tasks_start.write(|w| w.bits(1)) };
|
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 }
|
Self { _p: p }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,12 +160,12 @@ impl<'d> Qdec<'d> {
|
|||||||
/// let delta = q.read().await;
|
/// let delta = q.read().await;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn read(&mut self) -> i16 {
|
pub async fn read(&mut self) -> i16 {
|
||||||
let t = Self::regs();
|
let t = T::regs();
|
||||||
t.intenset.write(|w| w.reportrdy().set());
|
t.intenset.write(|w| w.reportrdy().set());
|
||||||
unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
|
unsafe { t.tasks_readclracc.write(|w| w.bits(1)) };
|
||||||
|
|
||||||
let value = poll_fn(|cx| {
|
let value = poll_fn(|cx| {
|
||||||
WAKER.register(cx.waker());
|
T::state().waker.register(cx.waker());
|
||||||
if t.events_reportrdy.read().bits() == 0 {
|
if t.events_reportrdy.read().bits() == 0 {
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
} else {
|
} else {
|
||||||
@ -172,10 +177,6 @@ impl<'d> Qdec<'d> {
|
|||||||
.await;
|
.await;
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn regs() -> &'static pac::qdec::RegisterBlock {
|
|
||||||
unsafe { &*pac::QDEC::ptr() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample period
|
/// Sample period
|
||||||
@ -236,3 +237,48 @@ pub enum LedPolarity {
|
|||||||
/// Active low (a low output turns on the LED).
|
/// Active low (a low output turns on the LED).
|
||||||
ActiveLow,
|
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]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
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::gpio::{self, Pin as GpioPin};
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||||
pub use crate::pac::qspi::ifconfig0::{
|
pub use crate::pac::qspi::ifconfig0::{
|
||||||
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
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;
|
pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
|
||||||
use crate::{pac, Peripheral};
|
use crate::Peripheral;
|
||||||
|
|
||||||
/// Deep power-down config.
|
/// Deep power-down config.
|
||||||
pub struct DeepPowerDownConfig {
|
pub struct DeepPowerDownConfig {
|
||||||
@ -82,6 +84,8 @@ pub struct Config {
|
|||||||
pub spi_mode: SpiMode,
|
pub spi_mode: SpiMode,
|
||||||
/// Addressing mode (24-bit or 32-bit)
|
/// Addressing mode (24-bit or 32-bit)
|
||||||
pub address_mode: AddressMode,
|
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 {
|
impl Default for Config {
|
||||||
@ -96,6 +100,7 @@ impl Default for Config {
|
|||||||
sck_delay: 80,
|
sck_delay: 80,
|
||||||
spi_mode: SpiMode::MODE0,
|
spi_mode: SpiMode::MODE0,
|
||||||
address_mode: AddressMode::_24BIT,
|
address_mode: AddressMode::_24BIT,
|
||||||
|
capacity: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,17 +115,35 @@ pub enum Error {
|
|||||||
// TODO add "not in data memory" error and check for it
|
// TODO add "not in data memory" error and check for it
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QSPI flash driver.
|
/// Interrupt handler.
|
||||||
pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
|
pub struct InterruptHandler<T: Instance> {
|
||||||
irq: PeripheralRef<'d, T::Interrupt>,
|
_phantom: PhantomData<T>,
|
||||||
dpm_enabled: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
/// Create a new QSPI driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_qspi: impl Peripheral<P = T> + 'd,
|
qspi: 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,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
csn: impl Peripheral<P = impl GpioPin> + 'd,
|
csn: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
io0: 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,
|
io2: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
io3: impl Peripheral<P = impl GpioPin> + 'd,
|
io3: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Qspi<'d, T, FLASH_SIZE> {
|
) -> Self {
|
||||||
into_ref!(irq, sck, csn, io0, io1, io2, io3);
|
into_ref!(qspi, sck, csn, io0, io1, io2, io3);
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
sck.set_high();
|
macro_rules! config_pin {
|
||||||
csn.set_high();
|
($pin:ident) => {
|
||||||
io0.set_high();
|
$pin.set_high();
|
||||||
io1.set_high();
|
$pin.conf().write(|w| {
|
||||||
io2.set_high();
|
w.dir().output();
|
||||||
io3.set_high();
|
w.drive().h0h1();
|
||||||
sck.conf().write(|w| w.dir().output().drive().h0h1());
|
#[cfg(feature = "_nrf5340-s")]
|
||||||
csn.conf().write(|w| w.dir().output().drive().h0h1());
|
w.mcusel().peripheral();
|
||||||
io0.conf().write(|w| w.dir().output().drive().h0h1());
|
w
|
||||||
io1.conf().write(|w| w.dir().output().drive().h0h1());
|
});
|
||||||
io2.conf().write(|w| w.dir().output().drive().h0h1());
|
r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) });
|
||||||
io3.conf().write(|w| w.dir().output().drive().h0h1());
|
};
|
||||||
|
}
|
||||||
|
|
||||||
r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) });
|
config_pin!(sck);
|
||||||
r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) });
|
config_pin!(csn);
|
||||||
r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) });
|
config_pin!(io0);
|
||||||
r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) });
|
config_pin!(io1);
|
||||||
r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) });
|
config_pin!(io2);
|
||||||
r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) });
|
config_pin!(io3);
|
||||||
|
|
||||||
r.ifconfig0.write(|w| {
|
r.ifconfig0.write(|w| {
|
||||||
w.addrmode().variant(config.address_mode);
|
w.addrmode().variant(config.address_mode);
|
||||||
@ -183,16 +207,16 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
// Enable it
|
// Enable it
|
||||||
r.enable.write(|w| w.enable().enabled());
|
r.enable.write(|w| w.enable().enabled());
|
||||||
|
|
||||||
let res = Self {
|
let res = Self {
|
||||||
|
_peri: qspi,
|
||||||
dpm_enabled: config.deep_power_down.is_some(),
|
dpm_enabled: config.deep_power_down.is_some(),
|
||||||
irq,
|
capacity: config.capacity,
|
||||||
};
|
};
|
||||||
|
|
||||||
r.events_ready.reset();
|
r.events_ready.reset();
|
||||||
@ -205,16 +229,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|||||||
res
|
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.
|
/// Do a custom QSPI instruction.
|
||||||
pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
|
pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
|
||||||
let ondrop = OnDrop::new(Self::blocking_wait_ready);
|
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| {
|
poll_fn(move |cx| {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
s.ready_waker.register(cx.waker());
|
s.waker.register(cx.waker());
|
||||||
if r.events_ready.read().bits() != 0 {
|
if r.events_ready.read().bits() != 0 {
|
||||||
return Poll::Ready(());
|
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.as_ptr() as u32 % 4, 0);
|
||||||
assert_eq!(data.len() as u32 % 4, 0);
|
assert_eq!(data.len() as u32 % 4, 0);
|
||||||
assert_eq!(address as u32 % 4, 0);
|
assert_eq!(address % 4, 0);
|
||||||
if address > FLASH_SIZE {
|
|
||||||
return Err(Error::OutOfBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = T::regs();
|
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.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) });
|
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(())
|
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.as_ptr() as u32 % 4, 0);
|
||||||
assert_eq!(data.len() as u32 % 4, 0);
|
assert_eq!(data.len() as u32 % 4, 0);
|
||||||
assert_eq!(address as u32 % 4, 0);
|
assert_eq!(address % 4, 0);
|
||||||
|
|
||||||
if address > FLASH_SIZE {
|
|
||||||
return Err(Error::OutOfBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) });
|
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.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) });
|
||||||
|
|
||||||
r.events_ready.reset();
|
r.events_ready.reset();
|
||||||
@ -363,14 +372,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_erase(&mut self, address: usize) -> Result<(), Error> {
|
fn start_erase(&mut self, address: u32) -> Result<(), Error> {
|
||||||
assert_eq!(address as u32 % 4096, 0);
|
// TODO: Return these as errors instead.
|
||||||
if address > FLASH_SIZE {
|
assert_eq!(address % 4096, 0);
|
||||||
return Err(Error::OutOfBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = T::regs();
|
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.erase.len.write(|w| w.len()._4kb());
|
||||||
|
|
||||||
r.events_ready.reset();
|
r.events_ready.reset();
|
||||||
@ -380,8 +387,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read data from the flash memory.
|
/// Raw QSPI read.
|
||||||
pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
|
///
|
||||||
|
/// 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);
|
let ondrop = OnDrop::new(Self::blocking_wait_ready);
|
||||||
|
|
||||||
self.start_read(address, data)?;
|
self.start_read(address, data)?;
|
||||||
@ -392,8 +403,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write data to the flash memory.
|
/// Raw QSPI write.
|
||||||
pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
|
///
|
||||||
|
/// 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);
|
let ondrop = OnDrop::new(Self::blocking_wait_ready);
|
||||||
|
|
||||||
self.start_write(address, data)?;
|
self.start_write(address, data)?;
|
||||||
@ -404,8 +419,46 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
|
|||||||
Ok(())
|
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.
|
/// 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);
|
let ondrop = OnDrop::new(Self::blocking_wait_ready);
|
||||||
|
|
||||||
self.start_erase(address)?;
|
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.
|
/// Read data from the flash memory, blocking version.
|
||||||
pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> {
|
||||||
self.start_read(address, data)?;
|
self.bounds_check(address, data.len())?;
|
||||||
Self::blocking_wait_ready();
|
self.blocking_read_raw(address, data)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write data to the flash memory, blocking version.
|
/// Write data to the flash memory, blocking version.
|
||||||
pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> {
|
||||||
self.start_write(address, data)?;
|
self.bounds_check(address, data.len())?;
|
||||||
Self::blocking_wait_ready();
|
self.blocking_write_raw(address, data)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Erase a sector on the flash memory, blocking version.
|
/// 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.start_erase(address)?;
|
||||||
Self::blocking_wait_ready();
|
Self::blocking_wait_ready();
|
||||||
Ok(())
|
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) {
|
fn drop(&mut self) {
|
||||||
let r = T::regs();
|
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());
|
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,
|
// 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
|
// leaving it floating, the flash chip might read it as zero which would cause it to
|
||||||
// spuriously exit DPM.
|
// 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> ErrorType for Qspi<'d, T> {
|
||||||
|
|
||||||
impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> {
|
|
||||||
type Error = Error;
|
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;
|
const READ_SIZE: usize = 4;
|
||||||
|
|
||||||
fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capacity(&self) -> usize {
|
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 WRITE_SIZE: usize = 4;
|
||||||
const ERASE_SIZE: usize = 4096;
|
const ERASE_SIZE: usize = 4096;
|
||||||
|
|
||||||
fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
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)?;
|
self.blocking_erase(address)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.blocking_write(offset as usize, bytes)?;
|
self.blocking_write(offset, bytes)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
#[cfg(feature = "nightly")]
|
||||||
if #[cfg(feature = "nightly")]
|
mod _eh1 {
|
||||||
{
|
|
||||||
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
|
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
|
||||||
|
|
||||||
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
use super::*;
|
||||||
|
|
||||||
|
impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> {
|
||||||
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
|
const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
|
||||||
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
|
const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
|
||||||
|
|
||||||
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
|
async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.write(offset as usize, data).await
|
self.write(offset, data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
|
||||||
for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
|
for address in (from..to).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) {
|
||||||
self.erase(address).await?
|
self.erase(address).await?
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> {
|
impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> {
|
||||||
const READ_SIZE: usize = 4;
|
const READ_SIZE: usize = 4;
|
||||||
async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
|
async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
self.read(address as usize, data).await
|
self.read(address, data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capacity(&self) -> usize {
|
fn capacity(&self) -> usize {
|
||||||
FLASH_SIZE
|
self.capacity as usize
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,27 +622,27 @@ cfg_if::cfg_if! {
|
|||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use super::*;
|
/// Peripheral static state
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub ready_waker: AtomicWaker,
|
pub waker: AtomicWaker,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ready_waker: AtomicWaker::new(),
|
waker: AtomicWaker::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
fn regs() -> &'static pac::qspi::RegisterBlock;
|
fn regs() -> &'static crate::pac::qspi::RegisterBlock;
|
||||||
fn state() -> &'static State;
|
fn state() -> &'static State;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QSPI peripheral instance.
|
/// 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.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: Interrupt;
|
||||||
}
|
}
|
||||||
@ -590,7 +650,7 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
|||||||
macro_rules! impl_qspi {
|
macro_rules! impl_qspi {
|
||||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||||
impl crate::qspi::sealed::Instance for peripherals::$type {
|
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() }
|
unsafe { &*pac::$pac_type::ptr() }
|
||||||
}
|
}
|
||||||
fn state() -> &'static crate::qspi::sealed::State {
|
fn state() -> &'static crate::qspi::sealed::State {
|
||||||
|
@ -1,83 +1,48 @@
|
|||||||
//! Random Number Generator (RNG) driver.
|
//! Random Number Generator (RNG) driver.
|
||||||
|
|
||||||
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_cortex_m::interrupt::Interrupt;
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::peripherals::RNG;
|
use crate::{interrupt, Peripheral};
|
||||||
use crate::{interrupt, pac, Peripheral};
|
|
||||||
|
|
||||||
impl RNG {
|
/// Interrupt handler.
|
||||||
fn regs() -> &'static pac::rng::RegisterBlock {
|
pub struct InterruptHandler<T: Instance> {
|
||||||
unsafe { &*pac::RNG::ptr() }
|
_phantom: PhantomData<T>,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static STATE: State = State {
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
unsafe fn on_interrupt() {
|
||||||
end: AtomicPtr::new(ptr::null_mut()),
|
let s = T::state();
|
||||||
waker: AtomicWaker::new(),
|
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.
|
// Clear the event.
|
||||||
RNG::regs().events_valrdy.reset();
|
r.events_valrdy.reset();
|
||||||
|
|
||||||
// Mutate the slice within a critical section,
|
// Mutate the slice within a critical section,
|
||||||
// so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
|
// 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, 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,
|
// 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.
|
// 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 !ptr.is_null() && ptr != end {
|
||||||
// If the future was dropped, the pointer would have been set to null,
|
// If the future was dropped, the pointer would have been set to null,
|
||||||
// so we're still good to mutate the slice.
|
// so we're still good to mutate the slice.
|
||||||
// The safety contract of `Rng::new` means that the future can't have been dropped
|
// The safety contract of `Rng::new` means that the future can't have been dropped
|
||||||
// without calling its destructor.
|
// without calling its destructor.
|
||||||
unsafe {
|
unsafe {
|
||||||
*ptr = RNG::regs().value.read().value().bits();
|
*ptr = r.value.read().value().bits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ptr, end)
|
(ptr, end)
|
||||||
@ -90,15 +55,15 @@ impl<'d> Rng<'d> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let new_ptr = unsafe { ptr.add(1) };
|
let new_ptr = unsafe { ptr.add(1) };
|
||||||
match STATE
|
match s
|
||||||
.ptr
|
.ptr
|
||||||
.compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
|
.compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
|
||||||
{
|
{
|
||||||
Ok(_) => {
|
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.
|
// It doesn't matter if `end` was changed under our feet, because then this will just be false.
|
||||||
if new_ptr == end {
|
if new_ptr == end {
|
||||||
STATE.waker.wake();
|
s.waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => {
|
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) {
|
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) {
|
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) {
|
fn enable_irq(&self) {
|
||||||
RNG::regs().intenset.write(|w| w.valrdy().set());
|
T::regs().intenset.write(|w| w.valrdy().set());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_irq(&self) {
|
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.
|
/// Enable or disable the RNG's bias correction.
|
||||||
@ -131,7 +128,7 @@ impl<'d> Rng<'d> {
|
|||||||
///
|
///
|
||||||
/// Defaults to disabled.
|
/// Defaults to disabled.
|
||||||
pub fn set_bias_correction(&self, enable: bool) {
|
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.
|
/// Fill the buffer with random bytes.
|
||||||
@ -140,11 +137,13 @@ impl<'d> Rng<'d> {
|
|||||||
return; // Nothing to fill
|
return; // Nothing to fill
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let s = T::state();
|
||||||
|
|
||||||
let range = dest.as_mut_ptr_range();
|
let range = dest.as_mut_ptr_range();
|
||||||
// Even if we've preempted the interrupt, it can't preempt us again,
|
// 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.
|
// so we don't need to worry about the order we write these in.
|
||||||
STATE.ptr.store(range.start, Ordering::Relaxed);
|
s.ptr.store(range.start, Ordering::Relaxed);
|
||||||
STATE.end.store(range.end, Ordering::Relaxed);
|
s.end.store(range.end, Ordering::Relaxed);
|
||||||
|
|
||||||
self.enable_irq();
|
self.enable_irq();
|
||||||
self.start();
|
self.start();
|
||||||
@ -154,16 +153,16 @@ impl<'d> Rng<'d> {
|
|||||||
self.disable_irq();
|
self.disable_irq();
|
||||||
|
|
||||||
// The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
|
// 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);
|
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||||
STATE.end.store(ptr::null_mut(), Ordering::Relaxed);
|
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||||
});
|
});
|
||||||
|
|
||||||
poll_fn(|cx| {
|
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`.
|
// 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 end = s.end.load(Ordering::Relaxed);
|
||||||
let ptr = STATE.ptr.load(Ordering::Relaxed);
|
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||||
|
|
||||||
if ptr == end {
|
if ptr == end {
|
||||||
// We're done.
|
// We're done.
|
||||||
@ -183,7 +182,7 @@ impl<'d> Rng<'d> {
|
|||||||
self.start();
|
self.start();
|
||||||
|
|
||||||
for byte in dest.iter_mut() {
|
for byte in dest.iter_mut() {
|
||||||
let regs = RNG::regs();
|
let regs = T::regs();
|
||||||
while regs.events_valrdy.read().bits() == 0 {}
|
while regs.events_valrdy.read().bits() == 0 {}
|
||||||
regs.events_valrdy.reset();
|
regs.events_valrdy.reset();
|
||||||
*byte = regs.value.read().value().bits();
|
*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) {
|
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]) {
|
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
self.blocking_fill_bytes(dest);
|
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::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -17,7 +18,6 @@ use saadc::oversample::OVERSAMPLE_A;
|
|||||||
use saadc::resolution::VAL_A;
|
use saadc::resolution::VAL_A;
|
||||||
|
|
||||||
use self::sealed::Input as _;
|
use self::sealed::Input as _;
|
||||||
use crate::interrupt::InterruptExt;
|
|
||||||
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||||
@ -28,9 +28,30 @@ use crate::{interrupt, pac, peripherals, Peripheral};
|
|||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {}
|
pub enum Error {}
|
||||||
|
|
||||||
/// One-shot and continuous SAADC.
|
/// Interrupt handler.
|
||||||
pub struct Saadc<'d, const N: usize> {
|
pub struct InterruptHandler {
|
||||||
_p: PeripheralRef<'d, peripherals::SAADC>,
|
_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();
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
@ -114,15 +135,20 @@ pub enum CallbackResult {
|
|||||||
Stop,
|
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> {
|
impl<'d, const N: usize> Saadc<'d, N> {
|
||||||
/// Create a new SAADC driver.
|
/// Create a new SAADC driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
|
saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
|
||||||
irq: impl Peripheral<P = interrupt::SAADC> + 'd,
|
_irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
channel_configs: [ChannelConfig; N],
|
channel_configs: [ChannelConfig; N],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(saadc, irq);
|
into_ref!(saadc);
|
||||||
|
|
||||||
let r = unsafe { &*SAADC::ptr() };
|
let r = unsafe { &*SAADC::ptr() };
|
||||||
|
|
||||||
@ -163,32 +189,12 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
|||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { interrupt::SAADC::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { interrupt::SAADC::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { _p: saadc }
|
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 {
|
fn regs() -> &'static saadc::RegisterBlock {
|
||||||
unsafe { &*SAADC::ptr() }
|
unsafe { &*SAADC::ptr() }
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
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::chip::FORCE_COPY_BUFFER_SIZE;
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
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::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
@ -31,11 +32,6 @@ pub enum Error {
|
|||||||
BufferNotInRAM,
|
BufferNotInRAM,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SPIM driver.
|
|
||||||
pub struct Spim<'d, T: Instance> {
|
|
||||||
_p: PeripheralRef<'d, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SPIM configuration.
|
/// SPIM configuration.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Config {
|
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> {
|
impl<'d, T: Instance> Spim<'d, T> {
|
||||||
/// Create a new SPIM driver.
|
/// Create a new SPIM driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
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,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
mosi: 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);
|
into_ref!(sck, miso, mosi);
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
spim,
|
spim,
|
||||||
irq,
|
|
||||||
sck.map_into(),
|
sck.map_into(),
|
||||||
Some(miso.map_into()),
|
Some(miso.map_into()),
|
||||||
Some(mosi.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).
|
/// Create a new SPIM driver, capable of TX only (MOSI only).
|
||||||
pub fn new_txonly(
|
pub fn new_txonly(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
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,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(sck, mosi);
|
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).
|
/// Create a new SPIM driver, capable of RX only (MISO only).
|
||||||
pub fn new_rxonly(
|
pub fn new_rxonly(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
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,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(sck, miso);
|
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(
|
fn new_inner(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
spim: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
|
||||||
sck: PeripheralRef<'d, AnyPin>,
|
sck: PeripheralRef<'d, AnyPin>,
|
||||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
mosi: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(spim, irq);
|
into_ref!(spim);
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
@ -191,23 +207,12 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { _p: spim }
|
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> {
|
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
||||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
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::chip::FORCE_COPY_BUFFER_SIZE;
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin};
|
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::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
@ -29,11 +30,6 @@ pub enum Error {
|
|||||||
BufferNotInRAM,
|
BufferNotInRAM,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SPIS driver.
|
|
||||||
pub struct Spis<'d, T: Instance> {
|
|
||||||
_p: PeripheralRef<'d, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SPIS configuration.
|
/// SPIS configuration.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Config {
|
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> {
|
impl<'d, T: Instance> Spis<'d, T> {
|
||||||
/// Create a new SPIS driver.
|
/// Create a new SPIS driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
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,
|
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: 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);
|
into_ref!(cs, sck, miso, mosi);
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
spis,
|
spis,
|
||||||
irq,
|
|
||||||
cs.map_into(),
|
cs.map_into(),
|
||||||
sck.map_into(),
|
sck.map_into(),
|
||||||
Some(miso.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).
|
/// Create a new SPIS driver, capable of TX only (MISO only).
|
||||||
pub fn new_txonly(
|
pub fn new_txonly(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
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,
|
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(cs, sck, miso);
|
into_ref!(cs, sck, miso);
|
||||||
Self::new_inner(
|
Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config)
|
||||||
spis,
|
|
||||||
irq,
|
|
||||||
cs.map_into(),
|
|
||||||
sck.map_into(),
|
|
||||||
Some(miso.map_into()),
|
|
||||||
None,
|
|
||||||
config,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new SPIS driver, capable of RX only (MOSI only).
|
/// Create a new SPIS driver, capable of RX only (MOSI only).
|
||||||
pub fn new_rxonly(
|
pub fn new_rxonly(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
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,
|
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(cs, sck, mosi);
|
into_ref!(cs, sck, mosi);
|
||||||
Self::new_inner(
|
Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config)
|
||||||
spis,
|
|
||||||
irq,
|
|
||||||
cs.map_into(),
|
|
||||||
sck.map_into(),
|
|
||||||
None,
|
|
||||||
Some(mosi.map_into()),
|
|
||||||
config,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
spis: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
|
||||||
cs: PeripheralRef<'d, AnyPin>,
|
cs: PeripheralRef<'d, AnyPin>,
|
||||||
sck: PeripheralRef<'d, AnyPin>,
|
sck: PeripheralRef<'d, AnyPin>,
|
||||||
miso: Option<PeripheralRef<'d, AnyPin>>,
|
miso: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
@ -143,7 +148,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
into_ref!(spis, irq, cs, sck);
|
into_ref!(spis, cs, sck);
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
@ -209,28 +214,12 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
// Disable all events interrupts.
|
// Disable all events interrupts.
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { _p: spis }
|
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> {
|
fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
slice_in_ram_or(tx, Error::BufferNotInRAM)?;
|
||||||
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
// NOTE: RAM slice check for rx is not necessary, as a mutable
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_cortex_m::interrupt::Interrupt;
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -12,27 +13,39 @@ use crate::interrupt::InterruptExt;
|
|||||||
use crate::peripherals::TEMP;
|
use crate::peripherals::TEMP;
|
||||||
use crate::{interrupt, pac, Peripheral};
|
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.
|
/// Builtin temperature sensor driver.
|
||||||
pub struct Temp<'d> {
|
pub struct Temp<'d> {
|
||||||
_irq: PeripheralRef<'d, interrupt::TEMP>,
|
_peri: PeripheralRef<'d, TEMP>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
impl<'d> Temp<'d> {
|
impl<'d> Temp<'d> {
|
||||||
/// Create a new temperature sensor driver.
|
/// Create a new temperature sensor driver.
|
||||||
pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self {
|
pub fn new(
|
||||||
into_ref!(_t, irq);
|
_peri: impl Peripheral<P = TEMP> + 'd,
|
||||||
|
_irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(_peri);
|
||||||
|
|
||||||
// Enable interrupt that signals temperature values
|
// Enable interrupt that signals temperature values
|
||||||
irq.disable();
|
unsafe { interrupt::TEMP::steal() }.unpend();
|
||||||
irq.set_handler(|_| {
|
unsafe { interrupt::TEMP::steal() }.enable();
|
||||||
let t = Self::regs();
|
|
||||||
t.intenclr.write(|w| w.datardy().clear());
|
Self { _peri }
|
||||||
WAKER.wake();
|
|
||||||
});
|
|
||||||
irq.enable();
|
|
||||||
Self { _irq: irq }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform an asynchronous temperature measurement. The returned future
|
/// Perform an asynchronous temperature measurement. The returned future
|
||||||
|
@ -6,15 +6,9 @@
|
|||||||
|
|
||||||
#![macro_use]
|
#![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_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::ppi::{Event, Task};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
@ -26,8 +20,6 @@ pub(crate) mod sealed {
|
|||||||
/// The number of CC registers this instance has.
|
/// The number of CC registers this instance has.
|
||||||
const CCS: usize;
|
const CCS: usize;
|
||||||
fn regs() -> &'static pac::timer0::RegisterBlock;
|
fn regs() -> &'static pac::timer0::RegisterBlock;
|
||||||
/// Storage for the waker for CC register `n`.
|
|
||||||
fn waker(n: usize) -> &'static AtomicWaker;
|
|
||||||
}
|
}
|
||||||
pub trait ExtendedInstance {}
|
pub trait ExtendedInstance {}
|
||||||
|
|
||||||
@ -50,12 +42,6 @@ macro_rules! impl_timer {
|
|||||||
fn regs() -> &'static pac::timer0::RegisterBlock {
|
fn regs() -> &'static pac::timer0::RegisterBlock {
|
||||||
unsafe { &*(pac::$pac_type::ptr() as *const 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 {
|
impl crate::timer::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::$irq;
|
||||||
@ -99,73 +85,49 @@ pub enum Frequency {
|
|||||||
/// nRF Timer driver.
|
/// nRF Timer driver.
|
||||||
///
|
///
|
||||||
/// The timer has an internal counter, which is incremented for every tick of the timer.
|
/// 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
|
/// 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.
|
/// 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.
|
/// Timer driver.
|
||||||
pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> {
|
pub struct Timer<'d, T: Instance> {
|
||||||
_p: PeripheralRef<'d, T>,
|
_p: PeripheralRef<'d, T>,
|
||||||
_i: PhantomData<I>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Timer<'d, T, Awaitable> {
|
impl<'d, T: Instance> Timer<'d, T> {
|
||||||
/// Create a new async-capable timer driver.
|
/// Create a new `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.
|
|
||||||
///
|
///
|
||||||
/// This can be useful for triggering tasks via PPI
|
/// This can be useful for triggering tasks via PPI
|
||||||
/// `Uarte` uses this internally.
|
/// `Uarte` uses this internally.
|
||||||
pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self {
|
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 new `Timer` driver in counter mode.
|
||||||
/// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
|
|
||||||
///
|
///
|
||||||
/// This is used by the public constructors.
|
/// This can be useful for triggering tasks via PPI
|
||||||
fn new_inner(timer: impl Peripheral<P = T> + 'd) -> Self {
|
/// `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);
|
into_ref!(timer);
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
let mut this = Self {
|
let mut this = Self { _p: timer };
|
||||||
_p: timer,
|
|
||||||
_i: PhantomData,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stop the timer before doing anything else,
|
// Stop the timer before doing anything else,
|
||||||
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
|
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
|
||||||
this.stop();
|
this.stop();
|
||||||
|
|
||||||
// Set the instance to timer mode.
|
if is_counter {
|
||||||
|
regs.mode.write(|w| w.mode().counter());
|
||||||
|
} else {
|
||||||
regs.mode.write(|w| w.mode().timer());
|
regs.mode.write(|w| w.mode().timer());
|
||||||
|
}
|
||||||
|
|
||||||
// Make the counter's max value as high as possible.
|
// Make the counter's max value as high as possible.
|
||||||
// TODO: is there a reason someone would want to set this lower?
|
// 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)
|
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.
|
/// Change the timer's frequency.
|
||||||
///
|
///
|
||||||
/// This will stop the timer if it isn't already stopped,
|
/// 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) })
|
.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.
|
/// Returns this timer's `n`th CC register.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
|
/// 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 {
|
if n >= T::CCS {
|
||||||
panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS);
|
panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS);
|
||||||
}
|
}
|
||||||
Cc {
|
Cc {
|
||||||
n,
|
n,
|
||||||
_p: self._p.reborrow(),
|
_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.
|
/// 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
|
/// 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,
|
n: usize,
|
||||||
_p: PeripheralRef<'d, T>,
|
_p: PeripheralRef<'d, T>,
|
||||||
_i: PhantomData<I>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Cc<'d, T, Awaitable> {
|
impl<'d, T: Instance> Cc<'d, T> {
|
||||||
/// 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> {
|
|
||||||
/// Get the current value stored in the register.
|
/// Get the current value stored in the register.
|
||||||
pub fn read(&self) -> u32 {
|
pub fn read(&self) -> u32 {
|
||||||
T::regs().cc[self.n].read().cc().bits()
|
T::regs().cc[self.n].read().cc().bits()
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::{poll_fn, Future};
|
use core::future::{poll_fn, Future};
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::compiler_fence;
|
use core::sync::atomic::compiler_fence;
|
||||||
use core::sync::atomic::Ordering::SeqCst;
|
use core::sync::atomic::Ordering::SeqCst;
|
||||||
use core::task::Poll;
|
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::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::Pin as GpioPin;
|
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::util::{slice_in_ram, slice_in_ram_or};
|
||||||
use crate::{gpio, pac, Peripheral};
|
use crate::{gpio, pac, Peripheral};
|
||||||
|
|
||||||
@ -92,6 +93,27 @@ pub enum Error {
|
|||||||
Timeout,
|
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.
|
/// TWI driver.
|
||||||
pub struct Twim<'d, T: Instance> {
|
pub struct Twim<'d, T: Instance> {
|
||||||
_p: PeripheralRef<'d, T>,
|
_p: PeripheralRef<'d, T>,
|
||||||
@ -101,12 +123,12 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
/// Create a new TWI driver.
|
/// Create a new TWI driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
twim: impl Peripheral<P = T> + 'd,
|
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,
|
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(twim, irq, sda, scl);
|
into_ref!(twim, sda, scl);
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
@ -152,27 +174,12 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { _p: twim }
|
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.
|
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::{poll_fn, Future};
|
use core::future::{poll_fn, Future};
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::compiler_fence;
|
use core::sync::atomic::compiler_fence;
|
||||||
use core::sync::atomic::Ordering::SeqCst;
|
use core::sync::atomic::Ordering::SeqCst;
|
||||||
use core::task::Poll;
|
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::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::Pin as GpioPin;
|
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::util::slice_in_ram_or;
|
||||||
use crate::{gpio, pac, Peripheral};
|
use crate::{gpio, pac, Peripheral};
|
||||||
|
|
||||||
@ -108,6 +109,31 @@ pub enum Command {
|
|||||||
Write(usize),
|
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.
|
/// TWIS driver.
|
||||||
pub struct Twis<'d, T: Instance> {
|
pub struct Twis<'d, T: Instance> {
|
||||||
_p: PeripheralRef<'d, T>,
|
_p: PeripheralRef<'d, T>,
|
||||||
@ -117,12 +143,12 @@ impl<'d, T: Instance> Twis<'d, T> {
|
|||||||
/// Create a new TWIS driver.
|
/// Create a new TWIS driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
twis: impl Peripheral<P = T> + 'd,
|
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,
|
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(twis, irq, sda, scl);
|
into_ref!(twis, sda, scl);
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
@ -178,31 +204,12 @@ impl<'d, T: Instance> Twis<'d, T> {
|
|||||||
// Generate suspend on read event
|
// Generate suspend on read event
|
||||||
r.shorts.write(|w| w.read_suspend().enabled());
|
r.shorts.write(|w| w.read_suspend().enabled());
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { _p: twis }
|
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.
|
/// Set TX buffer, checking that it is in RAM and has suitable length.
|
||||||
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
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::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
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::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||||
use crate::util::slice_in_ram_or;
|
use crate::util::slice_in_ram_or;
|
||||||
@ -62,6 +63,27 @@ pub enum Error {
|
|||||||
BufferNotInRAM,
|
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.
|
/// UARTE driver.
|
||||||
pub struct Uarte<'d, T: Instance> {
|
pub struct Uarte<'d, T: Instance> {
|
||||||
tx: UarteTx<'d, T>,
|
tx: UarteTx<'d, T>,
|
||||||
@ -86,19 +108,19 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
/// Create a new UARTE without hardware flow control
|
/// Create a new UARTE without hardware flow control
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
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,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(rxd, txd);
|
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)
|
/// Create a new UARTE with hardware flow control (RTS/CTS)
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
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,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
cts: 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);
|
into_ref!(rxd, txd, cts, rts);
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
uarte,
|
uarte,
|
||||||
irq,
|
|
||||||
rxd.map_into(),
|
rxd.map_into(),
|
||||||
txd.map_into(),
|
txd.map_into(),
|
||||||
Some(cts.map_into()),
|
Some(cts.map_into()),
|
||||||
@ -119,14 +140,13 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
|
|
||||||
fn new_inner(
|
fn new_inner(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
|
||||||
rxd: PeripheralRef<'d, AnyPin>,
|
rxd: PeripheralRef<'d, AnyPin>,
|
||||||
txd: PeripheralRef<'d, AnyPin>,
|
txd: PeripheralRef<'d, AnyPin>,
|
||||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(uarte, irq);
|
into_ref!(uarte);
|
||||||
|
|
||||||
let r = T::regs();
|
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()) });
|
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||||
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
|
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
|
||||||
(false, false) => false,
|
(false, false) => false,
|
||||||
@ -238,20 +257,6 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
Event::from_reg(&r.events_endtx)
|
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.
|
/// Read bytes until the buffer is filled.
|
||||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
self.rx.read(buffer).await
|
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
|
/// Create a new tx-only UARTE without hardware flow control
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
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,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(txd);
|
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)
|
/// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
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,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(txd, cts);
|
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(
|
fn new_inner(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
|
||||||
txd: PeripheralRef<'d, AnyPin>,
|
txd: PeripheralRef<'d, AnyPin>,
|
||||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(uarte, irq);
|
into_ref!(uarte);
|
||||||
|
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
|
|
||||||
@ -354,9 +358,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
|||||||
let hardware_flow_control = cts.is_some();
|
let hardware_flow_control = cts.is_some();
|
||||||
configure(r, config, hardware_flow_control);
|
configure(r, config, hardware_flow_control);
|
||||||
|
|
||||||
irq.set_handler(Uarte::<T>::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
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
|
/// Create a new rx-only UARTE without hardware flow control
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
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,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(rxd);
|
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)
|
/// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
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,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(rxd, rts);
|
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(
|
fn new_inner(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
|
||||||
rxd: PeripheralRef<'d, AnyPin>,
|
rxd: PeripheralRef<'d, AnyPin>,
|
||||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(uarte, irq);
|
into_ref!(uarte);
|
||||||
|
|
||||||
let r = T::regs();
|
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.txd.write(|w| w.connect().disconnected());
|
||||||
r.psel.cts.write(|w| w.connect().disconnected());
|
r.psel.cts.write(|w| w.connect().disconnected());
|
||||||
|
|
||||||
irq.set_handler(Uarte::<T>::on_interrupt);
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
irq.unpend();
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
let hardware_flow_control = rts.is_some();
|
let hardware_flow_control = rts.is_some();
|
||||||
configure(r, config, hardware_flow_control);
|
configure(r, config, hardware_flow_control);
|
||||||
@ -883,6 +884,7 @@ pub(crate) mod sealed {
|
|||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
fn regs() -> &'static pac::uarte0::RegisterBlock;
|
fn regs() -> &'static pac::uarte0::RegisterBlock;
|
||||||
fn state() -> &'static State;
|
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();
|
static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new();
|
||||||
&STATE
|
&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 {
|
impl crate::uarte::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::$irq;
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
|
pub mod vbus_detect;
|
||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
@ -15,7 +17,8 @@ use embassy_usb_driver as driver;
|
|||||||
use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
|
use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
|
||||||
use pac::usbd::RegisterBlock;
|
use pac::usbd::RegisterBlock;
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use self::vbus_detect::VbusDetect;
|
||||||
|
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||||
use crate::util::slice_in_ram;
|
use crate::util::slice_in_ram;
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
@ -26,185 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
|||||||
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
|
||||||
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
/// Trait for detecting USB VBUS power.
|
/// Interrupt handler.
|
||||||
///
|
pub struct InterruptHandler<T: Instance> {
|
||||||
/// There are multiple ways to detect USB power. The behavior
|
_phantom: PhantomData<T>,
|
||||||
/// here provides a hook into determining whether it is.
|
|
||||||
pub trait VbusDetect {
|
|
||||||
/// Report whether power is detected.
|
|
||||||
///
|
|
||||||
/// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
|
|
||||||
/// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
|
||||||
fn is_usb_detected(&self) -> bool;
|
|
||||||
|
|
||||||
/// Wait until USB power is ready.
|
|
||||||
///
|
|
||||||
/// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
|
|
||||||
/// `USBPWRRDY` event from the `POWER` peripheral.
|
|
||||||
async fn wait_power_ready(&mut self) -> Result<(), ()>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
|
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
///
|
unsafe fn on_interrupt() {
|
||||||
/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
|
|
||||||
/// to POWER. In that case, use [`VbusDetectSignal`].
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
pub struct HardwareVbusDetect {
|
|
||||||
_private: (),
|
|
||||||
}
|
|
||||||
|
|
||||||
static POWER_WAKER: AtomicWaker = NEW_AW;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
impl HardwareVbusDetect {
|
|
||||||
/// Create a new `VbusDetectNative`.
|
|
||||||
pub fn new(power_irq: impl Interrupt) -> Self {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
power_irq.set_handler(Self::on_interrupt);
|
|
||||||
power_irq.unpend();
|
|
||||||
power_irq.enable();
|
|
||||||
|
|
||||||
regs.intenset
|
|
||||||
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
|
||||||
|
|
||||||
Self { _private: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
fn on_interrupt(_: *mut ()) {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
if regs.events_usbdetected.read().bits() != 0 {
|
|
||||||
regs.events_usbdetected.reset();
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
if regs.events_usbremoved.read().bits() != 0 {
|
|
||||||
regs.events_usbremoved.reset();
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
if regs.events_usbpwrrdy.read().bits() != 0 {
|
|
||||||
regs.events_usbpwrrdy.reset();
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340-app"))]
|
|
||||||
impl VbusDetect for HardwareVbusDetect {
|
|
||||||
fn is_usb_detected(&self) -> bool {
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
POWER_WAKER.register(cx.waker());
|
|
||||||
let regs = unsafe { &*pac::POWER::ptr() };
|
|
||||||
|
|
||||||
if regs.usbregstatus.read().outputrdy().is_ready() {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
} else if !self.is_usb_detected() {
|
|
||||||
Poll::Ready(Err(()))
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Software-backed [`VbusDetect`] implementation.
|
|
||||||
///
|
|
||||||
/// This implementation does not interact with the hardware, it allows user code
|
|
||||||
/// to notify the power events by calling functions instead.
|
|
||||||
///
|
|
||||||
/// This is suitable for use with the nRF softdevice, by calling the functions
|
|
||||||
/// when the softdevice reports power-related events.
|
|
||||||
pub struct SoftwareVbusDetect {
|
|
||||||
usb_detected: AtomicBool,
|
|
||||||
power_ready: AtomicBool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SoftwareVbusDetect {
|
|
||||||
/// Create a new `SoftwareVbusDetect`.
|
|
||||||
pub fn new(usb_detected: bool, power_ready: bool) -> Self {
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
usb_detected: AtomicBool::new(usb_detected),
|
|
||||||
power_ready: AtomicBool::new(power_ready),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report whether power was detected.
|
|
||||||
///
|
|
||||||
/// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
|
||||||
pub fn detected(&self, detected: bool) {
|
|
||||||
self.usb_detected.store(detected, Ordering::Relaxed);
|
|
||||||
self.power_ready.store(false, Ordering::Relaxed);
|
|
||||||
BUS_WAKER.wake();
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Report when USB power is ready.
|
|
||||||
///
|
|
||||||
/// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
|
|
||||||
pub fn ready(&self) {
|
|
||||||
self.power_ready.store(true, Ordering::Relaxed);
|
|
||||||
POWER_WAKER.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VbusDetect for &SoftwareVbusDetect {
|
|
||||||
fn is_usb_detected(&self) -> bool {
|
|
||||||
self.usb_detected.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
|
||||||
poll_fn(move |cx| {
|
|
||||||
POWER_WAKER.register(cx.waker());
|
|
||||||
|
|
||||||
if self.power_ready.load(Ordering::Relaxed) {
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
} else if !self.usb_detected.load(Ordering::Relaxed) {
|
|
||||||
Poll::Ready(Err(()))
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// USB driver.
|
|
||||||
pub struct Driver<'d, T: Instance, P: VbusDetect> {
|
|
||||||
_p: PeripheralRef<'d, T>,
|
|
||||||
alloc_in: Allocator,
|
|
||||||
alloc_out: Allocator,
|
|
||||||
usb_supply: P,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
|
|
||||||
/// Create a new USB driver.
|
|
||||||
pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self {
|
|
||||||
into_ref!(usb, irq);
|
|
||||||
irq.set_handler(Self::on_interrupt);
|
|
||||||
irq.unpend();
|
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
_p: usb,
|
|
||||||
alloc_in: Allocator::new(),
|
|
||||||
alloc_out: Allocator::new(),
|
|
||||||
usb_supply,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_interrupt(_: *mut ()) {
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
if regs.events_usbreset.read().bits() != 0 {
|
if regs.events_usbreset.read().bits() != 0 {
|
||||||
@ -255,11 +86,40 @@ impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> {
|
/// USB driver.
|
||||||
|
pub struct Driver<'d, T: Instance, V: VbusDetect> {
|
||||||
|
_p: PeripheralRef<'d, T>,
|
||||||
|
alloc_in: Allocator,
|
||||||
|
alloc_out: Allocator,
|
||||||
|
vbus_detect: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
|
||||||
|
/// Create a new USB driver.
|
||||||
|
pub fn new(
|
||||||
|
usb: impl Peripheral<P = T> + 'd,
|
||||||
|
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
vbus_detect: V,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(usb);
|
||||||
|
|
||||||
|
unsafe { T::Interrupt::steal() }.unpend();
|
||||||
|
unsafe { T::Interrupt::steal() }.enable();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
_p: usb,
|
||||||
|
alloc_in: Allocator::new(),
|
||||||
|
alloc_out: Allocator::new(),
|
||||||
|
vbus_detect,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> {
|
||||||
type EndpointOut = Endpoint<'d, T, Out>;
|
type EndpointOut = Endpoint<'d, T, Out>;
|
||||||
type EndpointIn = Endpoint<'d, T, In>;
|
type EndpointIn = Endpoint<'d, T, In>;
|
||||||
type ControlPipe = ControlPipe<'d, T>;
|
type ControlPipe = ControlPipe<'d, T>;
|
||||||
type Bus = Bus<'d, T, P>;
|
type Bus = Bus<'d, T, V>;
|
||||||
|
|
||||||
fn alloc_endpoint_in(
|
fn alloc_endpoint_in(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -298,7 +158,7 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
|||||||
Bus {
|
Bus {
|
||||||
_p: unsafe { self._p.clone_unchecked() },
|
_p: unsafe { self._p.clone_unchecked() },
|
||||||
power_available: false,
|
power_available: false,
|
||||||
usb_supply: self.usb_supply,
|
vbus_detect: self.vbus_detect,
|
||||||
},
|
},
|
||||||
ControlPipe {
|
ControlPipe {
|
||||||
_p: self._p,
|
_p: self._p,
|
||||||
@ -309,13 +169,13 @@ impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// USB bus.
|
/// USB bus.
|
||||||
pub struct Bus<'d, T: Instance, P: VbusDetect> {
|
pub struct Bus<'d, T: Instance, V: VbusDetect> {
|
||||||
_p: PeripheralRef<'d, T>,
|
_p: PeripheralRef<'d, T>,
|
||||||
power_available: bool,
|
power_available: bool,
|
||||||
usb_supply: P,
|
vbus_detect: V,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
|
||||||
async fn enable(&mut self) {
|
async fn enable(&mut self) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
@ -347,7 +207,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
|||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.usb_supply.wait_power_ready().await.is_ok() {
|
if self.vbus_detect.wait_power_ready().await.is_ok() {
|
||||||
// Enable the USB pullup, allowing enumeration.
|
// Enable the USB pullup, allowing enumeration.
|
||||||
regs.usbpullup.write(|w| w.connect().enabled());
|
regs.usbpullup.write(|w| w.connect().enabled());
|
||||||
trace!("enabled");
|
trace!("enabled");
|
||||||
@ -406,7 +266,7 @@ impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
|
|||||||
trace!("USB event: ready");
|
trace!("USB event: ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.usb_supply.is_usb_detected() != self.power_available {
|
if self.vbus_detect.is_usb_detected() != self.power_available {
|
||||||
self.power_available = !self.power_available;
|
self.power_available = !self.power_available;
|
||||||
if self.power_available {
|
if self.power_available {
|
||||||
trace!("Power event: available");
|
trace!("Power event: available");
|
177
embassy-nrf/src/usb/vbus_detect.rs
Normal file
177
embassy-nrf/src/usb/vbus_detect.rs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
//! Trait and implementations for performing VBUS detection.
|
||||||
|
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use super::BUS_WAKER;
|
||||||
|
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||||
|
use crate::pac;
|
||||||
|
|
||||||
|
/// Trait for detecting USB VBUS power.
|
||||||
|
///
|
||||||
|
/// There are multiple ways to detect USB power. The behavior
|
||||||
|
/// here provides a hook into determining whether it is.
|
||||||
|
pub trait VbusDetect {
|
||||||
|
/// Report whether power is detected.
|
||||||
|
///
|
||||||
|
/// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
|
||||||
|
/// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||||
|
fn is_usb_detected(&self) -> bool;
|
||||||
|
|
||||||
|
/// Wait until USB power is ready.
|
||||||
|
///
|
||||||
|
/// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
|
||||||
|
/// `USBPWRRDY` event from the `POWER` peripheral.
|
||||||
|
async fn wait_power_ready(&mut self) -> Result<(), ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "_nrf5340"))]
|
||||||
|
type UsbRegIrq = interrupt::POWER_CLOCK;
|
||||||
|
#[cfg(feature = "_nrf5340")]
|
||||||
|
type UsbRegIrq = interrupt::USBREGULATOR;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "_nrf5340"))]
|
||||||
|
type UsbRegPeri = pac::POWER;
|
||||||
|
#[cfg(feature = "_nrf5340")]
|
||||||
|
type UsbRegPeri = pac::USBREGULATOR;
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl interrupt::Handler<UsbRegIrq> for InterruptHandler {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
|
if regs.events_usbdetected.read().bits() != 0 {
|
||||||
|
regs.events_usbdetected.reset();
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
if regs.events_usbremoved.read().bits() != 0 {
|
||||||
|
regs.events_usbremoved.reset();
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
if regs.events_usbpwrrdy.read().bits() != 0 {
|
||||||
|
regs.events_usbpwrrdy.reset();
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
|
||||||
|
///
|
||||||
|
/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
|
||||||
|
/// to POWER. In that case, use [`VbusDetectSignal`].
|
||||||
|
pub struct HardwareVbusDetect {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
static POWER_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
|
impl HardwareVbusDetect {
|
||||||
|
/// Create a new `VbusDetectNative`.
|
||||||
|
pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
|
unsafe { UsbRegIrq::steal() }.unpend();
|
||||||
|
unsafe { UsbRegIrq::steal() }.enable();
|
||||||
|
|
||||||
|
regs.intenset
|
||||||
|
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
||||||
|
|
||||||
|
Self { _private: () }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VbusDetect for HardwareVbusDetect {
|
||||||
|
fn is_usb_detected(&self) -> bool {
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
regs.usbregstatus.read().vbusdetect().is_vbus_present()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
POWER_WAKER.register(cx.waker());
|
||||||
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
|
if regs.usbregstatus.read().outputrdy().is_ready() {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else if !self.is_usb_detected() {
|
||||||
|
Poll::Ready(Err(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Software-backed [`VbusDetect`] implementation.
|
||||||
|
///
|
||||||
|
/// This implementation does not interact with the hardware, it allows user code
|
||||||
|
/// to notify the power events by calling functions instead.
|
||||||
|
///
|
||||||
|
/// This is suitable for use with the nRF softdevice, by calling the functions
|
||||||
|
/// when the softdevice reports power-related events.
|
||||||
|
pub struct SoftwareVbusDetect {
|
||||||
|
usb_detected: AtomicBool,
|
||||||
|
power_ready: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoftwareVbusDetect {
|
||||||
|
/// Create a new `SoftwareVbusDetect`.
|
||||||
|
pub fn new(usb_detected: bool, power_ready: bool) -> Self {
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
usb_detected: AtomicBool::new(usb_detected),
|
||||||
|
power_ready: AtomicBool::new(power_ready),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report whether power was detected.
|
||||||
|
///
|
||||||
|
/// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
|
||||||
|
pub fn detected(&self, detected: bool) {
|
||||||
|
self.usb_detected.store(detected, Ordering::Relaxed);
|
||||||
|
self.power_ready.store(false, Ordering::Relaxed);
|
||||||
|
BUS_WAKER.wake();
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report when USB power is ready.
|
||||||
|
///
|
||||||
|
/// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
|
||||||
|
pub fn ready(&self) {
|
||||||
|
self.power_ready.store(true, Ordering::Relaxed);
|
||||||
|
POWER_WAKER.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VbusDetect for &SoftwareVbusDetect {
|
||||||
|
fn is_usb_detected(&self) -> bool {
|
||||||
|
self.usb_detected.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_power_ready(&mut self) -> Result<(), ()> {
|
||||||
|
poll_fn(move |cx| {
|
||||||
|
POWER_WAKER.register(cx.waker());
|
||||||
|
|
||||||
|
if self.power_ready.load(Ordering::Relaxed) {
|
||||||
|
Poll::Ready(Ok(()))
|
||||||
|
} else if !self.usb_detected.load(Ordering::Relaxed) {
|
||||||
|
Poll::Ready(Err(()))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ use embassy_hal_common::into_ref;
|
|||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embedded_hal_02::adc::{Channel, OneShot};
|
use embedded_hal_02::adc::{Channel, OneShot};
|
||||||
|
|
||||||
|
use crate::gpio::Pin;
|
||||||
use crate::interrupt::{self, InterruptExt};
|
use crate::interrupt::{self, InterruptExt};
|
||||||
use crate::peripherals::ADC;
|
use crate::peripherals::ADC;
|
||||||
use crate::{pac, peripherals, Peripheral};
|
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();
|
let r = Self::regs();
|
||||||
unsafe {
|
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| {
|
r.cs().modify(|w| {
|
||||||
w.set_ainsel(PIN::channel());
|
w.set_ainsel(PIN::channel());
|
||||||
w.set_start_once(true)
|
w.set_start_once(true)
|
||||||
|
@ -151,6 +151,7 @@ fn copy_inner<'a, C: Channel>(
|
|||||||
Transfer::new(ch)
|
Transfer::new(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct Transfer<'a, C: Channel> {
|
pub struct Transfer<'a, C: Channel> {
|
||||||
channel: PeripheralRef<'a, C>,
|
channel: PeripheralRef<'a, C>,
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ unsafe fn IO_IRQ_BANK0() {
|
|||||||
w.set_edge_low(pin_group, false);
|
w.set_edge_low(pin_group, false);
|
||||||
}
|
}
|
||||||
InterruptTrigger::LevelHigh => {
|
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);
|
w.set_level_high(pin_group, false);
|
||||||
}
|
}
|
||||||
InterruptTrigger::LevelLow => {
|
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> {
|
struct InputFuture<'a, T: Pin> {
|
||||||
pin: PeripheralRef<'a, T>,
|
pin: PeripheralRef<'a, T>,
|
||||||
level: InterruptTrigger,
|
level: InterruptTrigger,
|
||||||
@ -213,7 +214,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
|||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
|
pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
|
||||||
InterruptTrigger::LevelHigh => {
|
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);
|
w.set_level_high(pin_group, true);
|
||||||
}
|
}
|
||||||
InterruptTrigger::LevelLow => {
|
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
|
// 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
|
// interrupt service routine, so we then know that the event/trigger
|
||||||
// happened and Poll::Ready will be returned.
|
// 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 {
|
match self.level {
|
||||||
InterruptTrigger::AnyEdge => {
|
InterruptTrigger::AnyEdge => {
|
||||||
if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
|
if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
|
||||||
#[rustfmt::skip]
|
#[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(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InterruptTrigger::LevelHigh => {
|
InterruptTrigger::LevelHigh => {
|
||||||
if !inte.level_high(pin_group) {
|
if !inte.level_high(pin_group) {
|
||||||
#[rustfmt::skip]
|
#[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(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InterruptTrigger::LevelLow => {
|
InterruptTrigger::LevelLow => {
|
||||||
if !inte.level_low(pin_group) {
|
if !inte.level_low(pin_group) {
|
||||||
#[rustfmt::skip]
|
#[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(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InterruptTrigger::EdgeHigh => {
|
InterruptTrigger::EdgeHigh => {
|
||||||
if !inte.edge_high(pin_group) {
|
if !inte.edge_high(pin_group) {
|
||||||
#[rustfmt::skip]
|
#[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(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InterruptTrigger::EdgeLow => {
|
InterruptTrigger::EdgeLow => {
|
||||||
if !inte.edge_low(pin_group) {
|
if !inte.edge_low(pin_group) {
|
||||||
#[rustfmt::skip]
|
#[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(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("InputFuture::poll return Poll::Pending");
|
trace!("InputFuture::poll return Poll::Pending");
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,7 @@ unsafe fn PIO1_IRQ_0() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Future that waits for TX-FIFO to become writable
|
/// 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> {
|
pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> {
|
||||||
sm: &'a mut SM,
|
sm: &'a mut SM,
|
||||||
pio: PhantomData<PIO>,
|
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
|
/// 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> {
|
pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> {
|
||||||
sm: &'a mut SM,
|
sm: &'a mut SM,
|
||||||
pio: PhantomData<PIO>,
|
pio: PhantomData<PIO>,
|
||||||
@ -241,6 +243,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Future that waits for IRQ
|
/// Future that waits for IRQ
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct IrqFuture<PIO: PioInstance> {
|
pub struct IrqFuture<PIO: PioInstance> {
|
||||||
pio: PhantomData<PIO>,
|
pio: PhantomData<PIO>,
|
||||||
irq_no: u8,
|
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(
|
fn new_inner(
|
||||||
_uart: impl Peripheral<P = T> + 'd,
|
_uart: impl Peripheral<P = T> + 'd,
|
||||||
mut tx: PeripheralRef<'d, AnyPin>,
|
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));
|
pin.pad_ctrl().write(|w| w.set_ie(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
let clk_base = crate::clocks::clk_peri_freq();
|
Self::set_baudrate_inner(config.baudrate);
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
let (pen, eps) = match config.parity {
|
let (pen, eps) = match config.parity {
|
||||||
Parity::ParityNone => (false, false),
|
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> {
|
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||||
|
@ -273,6 +273,7 @@ mod transfers {
|
|||||||
Transfer::new(channel)
|
Transfer::new(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub(crate) struct Transfer<'a, C: Channel> {
|
pub(crate) struct Transfer<'a, C: Channel> {
|
||||||
channel: PeripheralRef<'a, C>,
|
channel: PeripheralRef<'a, C>,
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
mod _version;
|
mod _version;
|
||||||
pub mod generic_smi;
|
pub mod generic_smi;
|
||||||
|
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
use core::task::Context;
|
use core::task::Context;
|
||||||
|
|
||||||
use embassy_net_driver::{Capabilities, LinkState};
|
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],
|
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();
|
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> {
|
struct ExtiInputFuture<'a> {
|
||||||
pin: u8,
|
pin: u8,
|
||||||
phantom: PhantomData<&'a mut AnyPin>,
|
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| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
set_rxdmaen(T::REGS, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPIv3 clears rxfifo on SPE=0
|
// SPIv3 clears rxfifo on SPE=0
|
||||||
#[cfg(not(any(spi_v3, spi_v4)))]
|
#[cfg(not(any(spi_v3, spi_v4)))]
|
||||||
flush_rx_fifo(T::REGS);
|
flush_rx_fifo(T::REGS);
|
||||||
|
|
||||||
|
set_rxdmaen(T::REGS, true);
|
||||||
|
|
||||||
let clock_byte_count = data.len();
|
let clock_byte_count = data.len();
|
||||||
|
|
||||||
let rx_request = self.rxdma.request();
|
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| {
|
T::REGS.cr1().modify(|w| {
|
||||||
w.set_spe(false);
|
w.set_spe(false);
|
||||||
});
|
});
|
||||||
set_rxdmaen(T::REGS, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPIv3 clears rxfifo on SPE=0
|
// SPIv3 clears rxfifo on SPE=0
|
||||||
#[cfg(not(any(spi_v3, spi_v4)))]
|
#[cfg(not(any(spi_v3, spi_v4)))]
|
||||||
flush_rx_fifo(T::REGS);
|
flush_rx_fifo(T::REGS);
|
||||||
|
|
||||||
|
set_rxdmaen(T::REGS, true);
|
||||||
|
|
||||||
let rx_request = self.rxdma.request();
|
let rx_request = self.rxdma.request();
|
||||||
let rx_src = T::REGS.rx_ptr();
|
let rx_src = T::REGS.rx_ptr();
|
||||||
unsafe { self.rxdma.start_read(rx_request, rx_src, read, Default::default()) };
|
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`].
|
/// 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>
|
pub struct RecvFuture<'ch, M, T, const N: usize>
|
||||||
where
|
where
|
||||||
M: RawMutex,
|
M: RawMutex,
|
||||||
@ -203,6 +204,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Future returned by [`DynamicReceiver::recv`].
|
/// Future returned by [`DynamicReceiver::recv`].
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct DynamicRecvFuture<'ch, T> {
|
pub struct DynamicRecvFuture<'ch, T> {
|
||||||
channel: &'ch dyn DynamicChannel<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`].
|
/// 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>
|
pub struct SendFuture<'ch, M, T, const N: usize>
|
||||||
where
|
where
|
||||||
M: RawMutex,
|
M: RawMutex,
|
||||||
@ -250,6 +253,7 @@ where
|
|||||||
impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {}
|
impl<'ch, M, T, const N: usize> Unpin for SendFuture<'ch, M, T, N> where M: RawMutex {}
|
||||||
|
|
||||||
/// Future returned by [`DynamicSender::send`].
|
/// Future returned by [`DynamicSender::send`].
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub struct DynamicSendFuture<'ch, T> {
|
pub struct DynamicSendFuture<'ch, T> {
|
||||||
channel: &'ch dyn DynamicChannel<T>,
|
channel: &'ch dyn DynamicChannel<T>,
|
||||||
message: Option<T>,
|
message: Option<T>,
|
||||||
|
@ -48,6 +48,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Future returned by [`Pipe::write`] and [`Writer::write`].
|
/// 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>
|
pub struct WriteFuture<'p, M, const N: usize>
|
||||||
where
|
where
|
||||||
M: RawMutex,
|
M: RawMutex,
|
||||||
@ -110,6 +111,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Future returned by [`Pipe::read`] and [`Reader::read`].
|
/// 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>
|
pub struct ReadFuture<'p, M, const N: usize>
|
||||||
where
|
where
|
||||||
M: RawMutex,
|
M: RawMutex,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use core::future::Future;
|
use core::future::{poll_fn, Future};
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use core::task::{Context, Poll, Waker};
|
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).
|
/// 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 {
|
pub struct Timer {
|
||||||
expires_at: Instant,
|
expires_at: Instant,
|
||||||
yielded_once: bool,
|
yielded_once: bool,
|
||||||
@ -131,6 +132,20 @@ impl Ticker {
|
|||||||
let expires_at = Instant::now() + duration;
|
let expires_at = Instant::now() + duration;
|
||||||
Self { expires_at, 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 {}
|
impl Unpin for Ticker {}
|
||||||
|
@ -276,6 +276,106 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
|
|||||||
pub async fn wait_connection(&mut self) {
|
pub async fn wait_connection(&mut self) {
|
||||||
self.read_ep.wait_enabled().await
|
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
|
/// Number of stop bits for LineCoding
|
||||||
|
@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["nightly"]
|
default = ["nightly"]
|
||||||
msos-descriptor = ["embassy-usb/msos-descriptor"]
|
|
||||||
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
|
nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
|
||||||
"embassy-lora", "lorawan-device", "lorawan"]
|
"embassy-lora", "lorawan-device", "lorawan"]
|
||||||
|
|
||||||
@ -17,7 +16,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
|
|||||||
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
|
||||||
embedded-io = "0.4.0"
|
embedded-io = "0.4.0"
|
||||||
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
|
||||||
|
|
||||||
@ -36,7 +35,3 @@ rand = { version = "0.8.4", default-features = false }
|
|||||||
embedded-storage = "0.3.0"
|
embedded-storage = "0.3.0"
|
||||||
usbd-hid = "0.6.0"
|
usbd-hid = "0.6.0"
|
||||||
serde = { version = "1.0.136", default-features = false }
|
serde = { version = "1.0.136", default-features = false }
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "usb_serial_winusb"
|
|
||||||
required-features = ["msos-descriptor"]
|
|
||||||
|
@ -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 defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::buffered_uarte::{BufferedUarte, State};
|
use embassy_nrf::buffered_uarte::{self, BufferedUarte};
|
||||||
use embassy_nrf::{interrupt, uarte};
|
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||||
use embedded_io::asynch::{BufRead, Write};
|
use embedded_io::asynch::Write;
|
||||||
use futures::pin_mut;
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -20,25 +23,19 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut tx_buffer = [0u8; 4096];
|
let mut tx_buffer = [0u8; 4096];
|
||||||
let mut rx_buffer = [0u8; 4096];
|
let mut rx_buffer = [0u8; 4096];
|
||||||
|
|
||||||
let irq = interrupt::take!(UARTE0_UART0);
|
let mut u = BufferedUarte::new(
|
||||||
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,
|
|
||||||
p.UARTE0,
|
p.UARTE0,
|
||||||
p.TIMER0,
|
p.TIMER0,
|
||||||
p.PPI_CH0,
|
p.PPI_CH0,
|
||||||
p.PPI_CH1,
|
p.PPI_CH1,
|
||||||
irq,
|
p.PPI_GROUP0,
|
||||||
|
Irqs,
|
||||||
p.P0_08,
|
p.P0_08,
|
||||||
p.P0_06,
|
p.P0_06,
|
||||||
p.P0_07,
|
|
||||||
p.P0_05,
|
|
||||||
config,
|
config,
|
||||||
&mut rx_buffer,
|
&mut rx_buffer,
|
||||||
&mut tx_buffer,
|
&mut tx_buffer,
|
||||||
);
|
);
|
||||||
pin_mut!(u);
|
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use core::f32::consts::PI;
|
|||||||
use defmt::{error, info};
|
use defmt::{error, info};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
|
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 _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
type Sample = i16;
|
type Sample = i16;
|
||||||
@ -15,6 +15,10 @@ type Sample = i16;
|
|||||||
const NUM_BUFFERS: usize = 2;
|
const NUM_BUFFERS: usize = 2;
|
||||||
const NUM_SAMPLES: usize = 4;
|
const NUM_SAMPLES: usize = 4;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -28,15 +32,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.sample_width = SampleWidth::_16bit;
|
config.sample_width = SampleWidth::_16bit;
|
||||||
config.channels = Channels::MonoLeft;
|
config.channels = Channels::MonoLeft;
|
||||||
|
|
||||||
let irq = interrupt::take!(I2S);
|
|
||||||
let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
|
let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
|
||||||
let buffers_in = 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(
|
let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
|
||||||
p.P0_29,
|
.full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
|
||||||
p.P0_28,
|
|
||||||
buffers_out,
|
|
||||||
buffers_in,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut modulator = SineOsc::new();
|
let mut modulator = SineOsc::new();
|
||||||
modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
|
modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
|
||||||
|
@ -5,14 +5,18 @@
|
|||||||
use defmt::{debug, error, info};
|
use defmt::{debug, error, info};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
|
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::pwm::{Prescaler, SimplePwm};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
type Sample = i16;
|
type Sample = i16;
|
||||||
|
|
||||||
const NUM_SAMPLES: usize = 500;
|
const NUM_SAMPLES: usize = 500;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -26,10 +30,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.sample_width = SampleWidth::_16bit;
|
config.sample_width = SampleWidth::_16bit;
|
||||||
config.channels = Channels::MonoLeft;
|
config.channels = Channels::MonoLeft;
|
||||||
|
|
||||||
let irq = interrupt::take!(I2S);
|
|
||||||
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
||||||
let mut input_stream =
|
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
|
// 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);
|
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 defmt::{error, info};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
|
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 _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
type Sample = i16;
|
type Sample = i16;
|
||||||
|
|
||||||
const NUM_SAMPLES: usize = 50;
|
const NUM_SAMPLES: usize = 50;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
I2S => i2s::InterruptHandler<peripherals::I2S>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -27,10 +31,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.sample_width = SampleWidth::_16bit;
|
config.sample_width = SampleWidth::_16bit;
|
||||||
config.channels = Channels::MonoLeft;
|
config.channels = Channels::MonoLeft;
|
||||||
|
|
||||||
let irq = interrupt::take!(I2S);
|
|
||||||
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
|
||||||
let mut output_stream =
|
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);
|
let mut waveform = Waveform::new(1.0 / sample_rate as f32);
|
||||||
|
|
||||||
|
@ -11,11 +11,15 @@ use defmt::*;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_lora::sx126x::*;
|
use embassy_lora::sx126x::*;
|
||||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
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 embassy_time::{Duration, Timer};
|
||||||
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
|
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -23,8 +27,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
spi_config.frequency = spim::Frequency::M16;
|
spi_config.frequency = spim::Frequency::M16;
|
||||||
|
|
||||||
let mut radio = {
|
let mut radio = {
|
||||||
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||||
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
|
||||||
|
|
||||||
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
||||||
let reset = Output::new(p.P1_06.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_executor::Spawner;
|
||||||
use embassy_lora::sx126x::*;
|
use embassy_lora::sx126x::*;
|
||||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
|
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::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::pubsub::{PubSubChannel, Publisher};
|
use embassy_sync::pubsub::{PubSubChannel, Publisher};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
|
use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
|
||||||
use {defmt_rtt as _, panic_probe as _, panic_probe as _};
|
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)
|
// 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();
|
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;
|
spi_config.frequency = spim::Frequency::M16;
|
||||||
|
|
||||||
let mut radio = {
|
let mut radio = {
|
||||||
let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
||||||
let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
|
|
||||||
|
|
||||||
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
|
||||||
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
|
||||||
|
@ -57,11 +57,14 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use cortex_m::peripheral::NVIC;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::{info, unwrap};
|
use defmt::{info, unwrap};
|
||||||
use embassy_nrf::executor::{Executor, InterruptExecutor};
|
use embassy_nrf::executor::{Executor, InterruptExecutor};
|
||||||
use embassy_nrf::interrupt;
|
use embassy_nrf::interrupt;
|
||||||
use embassy_nrf::interrupt::InterruptExt;
|
use embassy_nrf::pac::Interrupt;
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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_HIGH: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new();
|
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::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]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let _p = embassy_nrf::init(Default::default());
|
let _p = embassy_nrf::init(Default::default());
|
||||||
|
let mut nvic: NVIC = unsafe { mem::transmute(()) };
|
||||||
|
|
||||||
// High-priority executor: SWI1_EGU1, priority level 6
|
// High-priority executor: SWI1_EGU1, priority level 6
|
||||||
let irq = interrupt::take!(SWI1_EGU1);
|
unsafe { nvic.set_priority(Interrupt::SWI1_EGU1, 6 << 5) };
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
let spawner = EXECUTOR_HIGH.start(Interrupt::SWI1_EGU1);
|
||||||
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
|
|
||||||
// Medium-priority executor: SWI0_EGU0, priority level 7
|
// Medium-priority executor: SWI0_EGU0, priority level 7
|
||||||
let irq = interrupt::take!(SWI0_EGU0);
|
unsafe { nvic.set_priority(Interrupt::SWI0_EGU0, 7 << 5) };
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
let spawner = EXECUTOR_MED.start(Interrupt::SWI0_EGU0);
|
||||||
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// Low priority executor: runs in thread mode, using WFE/SEV
|
||||||
|
@ -4,16 +4,20 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
use embassy_nrf::pdm::{self, Config, Pdm};
|
||||||
use embassy_nrf::pdm::{Config, Pdm};
|
use embassy_nrf::{bind_interrupts, peripherals};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
PDM => pdm::InterruptHandler<peripherals::PDM>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_p: Spawner) {
|
async fn main(_p: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
let config = Config::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 {
|
loop {
|
||||||
pdm.start().await;
|
pdm.start().await;
|
||||||
|
@ -4,16 +4,19 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::qdec::{self, Qdec};
|
use embassy_nrf::qdec::{self, Qdec};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
QDEC => qdec::InterruptHandler<peripherals::QDEC>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
let irq = interrupt::take!(QDEC);
|
|
||||||
let config = qdec::Config::default();
|
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!");
|
info!("Turn rotary encoder!");
|
||||||
let mut value = 0;
|
let mut value = 0;
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
use defmt::{assert_eq, info, unwrap};
|
use defmt::{assert_eq, info, unwrap};
|
||||||
use embassy_executor::Spawner;
|
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 _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
const PAGE_SIZE: usize = 4096;
|
const PAGE_SIZE: usize = 4096;
|
||||||
@ -14,18 +15,23 @@ const PAGE_SIZE: usize = 4096;
|
|||||||
#[repr(C, align(4))]
|
#[repr(C, align(4))]
|
||||||
struct AlignedBuf([u8; 4096]);
|
struct AlignedBuf([u8; 4096]);
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
// Config for the MX25R64 present in the nRF52840 DK
|
// Config for the MX25R64 present in the nRF52840 DK
|
||||||
let mut config = qspi::Config::default();
|
let mut config = qspi::Config::default();
|
||||||
|
config.capacity = 8 * 1024 * 1024; // 8 MB
|
||||||
|
config.frequency = Frequency::M32;
|
||||||
config.read_opcode = qspi::ReadOpcode::READ4IO;
|
config.read_opcode = qspi::ReadOpcode::READ4IO;
|
||||||
config.write_opcode = qspi::WriteOpcode::PP4IO;
|
config.write_opcode = qspi::WriteOpcode::PP4IO;
|
||||||
config.write_page_size = qspi::WritePageSize::_256BYTES;
|
config.write_page_size = qspi::WritePageSize::_256BYTES;
|
||||||
|
|
||||||
let irq = interrupt::take!(QSPI);
|
let mut q = qspi::Qspi::new(
|
||||||
let mut q: qspi::Qspi<_, 67108864> = 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,
|
||||||
p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut id = [1; 3];
|
let mut id = [1; 3];
|
||||||
@ -52,23 +58,23 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
info!("page {:?}: erasing... ", i);
|
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 {
|
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...");
|
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 {
|
for i in 0..8 {
|
||||||
info!("page {:?}: reading... ", i);
|
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...");
|
info!("verifying...");
|
||||||
for j in 0..PAGE_SIZE {
|
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 defmt::{info, unwrap};
|
||||||
use embassy_executor::Spawner;
|
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 embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@ -15,14 +16,19 @@ use {defmt_rtt as _, panic_probe as _};
|
|||||||
#[repr(C, align(4))]
|
#[repr(C, align(4))]
|
||||||
struct AlignedBuf([u8; 64]);
|
struct AlignedBuf([u8; 64]);
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
QSPI => qspi::InterruptHandler<peripherals::QSPI>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_p: Spawner) {
|
async fn main(_p: Spawner) {
|
||||||
let mut p = embassy_nrf::init(Default::default());
|
let mut p = embassy_nrf::init(Default::default());
|
||||||
let mut irq = interrupt::take!(QSPI);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Config for the MX25R64 present in the nRF52840 DK
|
// Config for the MX25R64 present in the nRF52840 DK
|
||||||
let mut config = qspi::Config::default();
|
let mut config = qspi::Config::default();
|
||||||
|
config.capacity = 8 * 1024 * 1024; // 8 MB
|
||||||
|
config.frequency = Frequency::M32;
|
||||||
config.read_opcode = qspi::ReadOpcode::READ4IO;
|
config.read_opcode = qspi::ReadOpcode::READ4IO;
|
||||||
config.write_opcode = qspi::WriteOpcode::PP4IO;
|
config.write_opcode = qspi::WriteOpcode::PP4IO;
|
||||||
config.write_page_size = qspi::WritePageSize::_256BYTES;
|
config.write_page_size = qspi::WritePageSize::_256BYTES;
|
||||||
@ -31,9 +37,9 @@ async fn main(_p: Spawner) {
|
|||||||
exit_time: 3, // tRDP = 35uS
|
exit_time: 3, // tRDP = 35uS
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
|
let mut q = qspi::Qspi::new(
|
||||||
&mut p.QSPI,
|
&mut p.QSPI,
|
||||||
&mut irq,
|
Irqs,
|
||||||
&mut p.P0_19,
|
&mut p.P0_19,
|
||||||
&mut p.P0_17,
|
&mut p.P0_17,
|
||||||
&mut p.P0_20,
|
&mut p.P0_20,
|
||||||
|
@ -3,15 +3,19 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::rng::Rng;
|
use embassy_nrf::rng::Rng;
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals, rng};
|
||||||
use rand::Rng as _;
|
use rand::Rng as _;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
|
let mut rng = Rng::new(p.RNG, Irqs);
|
||||||
|
|
||||||
// Async API
|
// Async API
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
|
@ -4,17 +4,21 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
|
use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
|
||||||
|
use embassy_nrf::{bind_interrupts, saadc};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SAADC => saadc::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_p: Spawner) {
|
async fn main(_p: Spawner) {
|
||||||
let mut p = embassy_nrf::init(Default::default());
|
let mut p = embassy_nrf::init(Default::default());
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let channel_config = ChannelConfig::single_ended(&mut p.P0_02);
|
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 {
|
loop {
|
||||||
let mut buf = [0; 1];
|
let mut buf = [0; 1];
|
||||||
|
@ -4,14 +4,18 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
|
use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
|
||||||
use embassy_nrf::timer::Frequency;
|
use embassy_nrf::timer::Frequency;
|
||||||
|
use embassy_nrf::{bind_interrupts, saadc};
|
||||||
use embassy_time::Duration;
|
use embassy_time::Duration;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
|
// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SAADC => saadc::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_p: Spawner) {
|
async fn main(_p: Spawner) {
|
||||||
let mut p = embassy_nrf::init(Default::default());
|
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 channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
|
||||||
let mut saadc = Saadc::new(
|
let mut saadc = Saadc::new(
|
||||||
p.SAADC,
|
p.SAADC,
|
||||||
interrupt::take!(SAADC),
|
Irqs,
|
||||||
config,
|
config,
|
||||||
[channel_1_config, channel_2_config, channel_3_config],
|
[channel_1_config, channel_2_config, channel_3_config],
|
||||||
);
|
);
|
||||||
|
@ -5,9 +5,13 @@
|
|||||||
use defmt::{info, unwrap};
|
use defmt::{info, unwrap};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
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 _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut config = spim::Config::default();
|
let mut config = spim::Config::default();
|
||||||
config.frequency = spim::Frequency::M16;
|
config.frequency = spim::Frequency::M16;
|
||||||
|
|
||||||
let irq = interrupt::take!(SPIM3);
|
let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config);
|
||||||
let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
|
|
||||||
|
|
||||||
let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
|
let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
|
||||||
|
|
||||||
|
@ -4,17 +4,20 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::spis::{Config, Spis};
|
use embassy_nrf::spis::{Config, Spis};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals, spis};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
info!("Running!");
|
info!("Running!");
|
||||||
|
|
||||||
let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
|
let mut spis = Spis::new(p.SPI2, Irqs, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
|
||||||
let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut rx_buf = [0_u8; 64];
|
let mut rx_buf = [0_u8; 64];
|
||||||
|
@ -4,16 +4,19 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::temp::Temp;
|
use embassy_nrf::temp::Temp;
|
||||||
|
use embassy_nrf::{bind_interrupts, temp};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
TEMP => temp::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
let irq = interrupt::take!(TEMP);
|
let mut temp = Temp::new(p.TEMP, Irqs);
|
||||||
let mut temp = Temp::new(p.TEMP, irq);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let value = temp.read().await;
|
let value = temp.read().await;
|
||||||
|
@ -8,19 +8,22 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::twim::{self, Twim};
|
use embassy_nrf::twim::{self, Twim};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
const ADDRESS: u8 = 0x50;
|
const ADDRESS: u8 = 0x50;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
info!("Initializing TWI...");
|
info!("Initializing TWI...");
|
||||||
let config = twim::Config::default();
|
let config = twim::Config::default();
|
||||||
let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
|
||||||
let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
|
||||||
|
|
||||||
info!("Reading...");
|
info!("Reading...");
|
||||||
|
|
||||||
|
@ -12,25 +12,28 @@ use core::mem;
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::twim::{self, Twim};
|
use embassy_nrf::twim::{self, Twim};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
const ADDRESS: u8 = 0x50;
|
const ADDRESS: u8 = 0x50;
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_p: Spawner) {
|
async fn main(_p: Spawner) {
|
||||||
let mut p = embassy_nrf::init(Default::default());
|
let mut p = embassy_nrf::init(Default::default());
|
||||||
info!("Started!");
|
info!("Started!");
|
||||||
let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
info!("Initializing TWI...");
|
info!("Initializing TWI...");
|
||||||
let config = twim::Config::default();
|
let config = twim::Config::default();
|
||||||
|
|
||||||
// Create the TWIM instance with borrowed singletons, so they're not consumed.
|
// 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...");
|
info!("Reading...");
|
||||||
|
|
||||||
|
@ -6,19 +6,21 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::interrupt;
|
|
||||||
use embassy_nrf::twis::{self, Command, Twis};
|
use embassy_nrf::twis::{self, Command, Twis};
|
||||||
|
use embassy_nrf::{bind_interrupts, peripherals};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
|
|
||||||
let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
|
||||||
let mut config = twis::Config::default();
|
let mut config = twis::Config::default();
|
||||||
// Set i2c address
|
config.address0 = 0x55; // Set i2c address
|
||||||
config.address0 = 0x55;
|
let mut i2c = Twis::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
|
||||||
let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
|
|
||||||
|
|
||||||
info!("Listening...");
|
info!("Listening...");
|
||||||
loop {
|
loop {
|
||||||
|
@ -4,9 +4,13 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::{interrupt, uarte};
|
use embassy_nrf::{bind_interrupts, peripherals, uarte};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -14,8 +18,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.parity = uarte::Parity::EXCLUDED;
|
config.parity = uarte::Parity::EXCLUDED;
|
||||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||||
|
|
||||||
let irq = interrupt::take!(UARTE0_UART0);
|
let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||||
let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
|
||||||
|
@ -4,9 +4,14 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
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 _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.parity = uarte::Parity::EXCLUDED;
|
config.parity = uarte::Parity::EXCLUDED;
|
||||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||||
|
|
||||||
let irq = interrupt::take!(UARTE0_UART0);
|
let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||||
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
|
||||||
let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
|
let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
@ -6,13 +6,17 @@ use defmt::*;
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::peripherals::UARTE0;
|
use embassy_nrf::peripherals::UARTE0;
|
||||||
use embassy_nrf::uarte::UarteRx;
|
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::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
use embassy_sync::channel::Channel;
|
use embassy_sync::channel::Channel;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
|
static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -20,8 +24,7 @@ async fn main(spawner: Spawner) {
|
|||||||
config.parity = uarte::Parity::EXCLUDED;
|
config.parity = uarte::Parity::EXCLUDED;
|
||||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||||
|
|
||||||
let irq = interrupt::take!(UARTE0_UART0);
|
let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
|
||||||
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
|
|
||||||
let (mut tx, rx) = uart.split();
|
let (mut tx, rx) = uart.split();
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
@ -9,8 +9,9 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{Stack, StackResources};
|
use embassy_net::{Stack, StackResources};
|
||||||
use embassy_nrf::rng::Rng;
|
use embassy_nrf::rng::Rng;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac, peripherals};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb};
|
||||||
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
|
||||||
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
@ -18,6 +19,12 @@ use embedded_io::asynch::Write;
|
|||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||||
|
});
|
||||||
|
|
||||||
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
||||||
|
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
@ -46,31 +53,8 @@ async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
|
|||||||
stack.run().await
|
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]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) {
|
async fn main(spawner: Spawner) {
|
||||||
info!("{:?}", test_function());
|
|
||||||
|
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
let clock: pac::CLOCK = unsafe { mem::transmute(()) };
|
||||||
|
|
||||||
@ -79,9 +63,7 @@ async fn main(spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -105,6 +87,7 @@ async fn main(spawner: Spawner) {
|
|||||||
&mut singleton!([0; 256])[..],
|
&mut singleton!([0; 256])[..],
|
||||||
&mut singleton!([0; 256])[..],
|
&mut singleton!([0; 256])[..],
|
||||||
&mut singleton!([0; 128])[..],
|
&mut singleton!([0; 128])[..],
|
||||||
|
&mut singleton!([0; 128])[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Our MAC addr.
|
// Our MAC addr.
|
||||||
@ -131,7 +114,7 @@ async fn main(spawner: Spawner) {
|
|||||||
//});
|
//});
|
||||||
|
|
||||||
// Generate random seed
|
// 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];
|
let mut seed = [0; 8];
|
||||||
rng.blocking_fill_bytes(&mut seed);
|
rng.blocking_fill_bytes(&mut seed);
|
||||||
let seed = u64::from_le_bytes(seed);
|
let seed = u64::from_le_bytes(seed);
|
||||||
|
@ -10,8 +10,9 @@ use embassy_executor::Spawner;
|
|||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use embassy_nrf::gpio::{Input, Pin, Pull};
|
use embassy_nrf::gpio::{Input, Pin, Pull};
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
use embassy_sync::signal::Signal;
|
use embassy_sync::signal::Signal;
|
||||||
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
|
||||||
@ -20,6 +21,11 @@ use embassy_usb::{Builder, Config, Handler};
|
|||||||
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
static SUSPENDED: AtomicBool = AtomicBool::new(false);
|
static SUSPENDED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -50,6 +54,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut device_descriptor = [0; 256];
|
let mut device_descriptor = [0; 256];
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
let request_handler = MyRequestHandler {};
|
let request_handler = MyRequestHandler {};
|
||||||
let mut device_handler = MyDeviceHandler::new();
|
let mut device_handler = MyDeviceHandler::new();
|
||||||
@ -62,6 +67,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut device_descriptor,
|
&mut device_descriptor,
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
|
&mut msos_descriptor,
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -7,8 +7,9 @@ use core::mem;
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
|
||||||
use embassy_usb::control::OutResponse;
|
use embassy_usb::control::OutResponse;
|
||||||
@ -16,6 +17,11 @@ use embassy_usb::{Builder, Config};
|
|||||||
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -26,9 +32,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -43,6 +47,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut device_descriptor = [0; 256];
|
let mut device_descriptor = [0; 256];
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
let request_handler = MyRequestHandler {};
|
let request_handler = MyRequestHandler {};
|
||||||
|
|
||||||
@ -54,6 +59,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut device_descriptor,
|
&mut device_descriptor,
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
|
&mut msos_descriptor,
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -7,13 +7,19 @@ use core::mem;
|
|||||||
use defmt::{info, panic};
|
use defmt::{info, panic};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::{Driver, Instance};
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -24,9 +30,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -48,6 +52,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut device_descriptor = [0; 256];
|
let mut device_descriptor = [0; 256];
|
||||||
let mut config_descriptor = [0; 256];
|
let mut config_descriptor = [0; 256];
|
||||||
let mut bos_descriptor = [0; 256];
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut msos_descriptor = [0; 256];
|
||||||
let mut control_buf = [0; 64];
|
let mut control_buf = [0; 64];
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
@ -58,6 +63,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
&mut device_descriptor,
|
&mut device_descriptor,
|
||||||
&mut config_descriptor,
|
&mut config_descriptor,
|
||||||
&mut bos_descriptor,
|
&mut bos_descriptor,
|
||||||
|
&mut msos_descriptor,
|
||||||
&mut control_buf,
|
&mut control_buf,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -6,14 +6,29 @@ use core::mem;
|
|||||||
|
|
||||||
use defmt::{info, panic, unwrap};
|
use defmt::{info, panic, unwrap};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect};
|
use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
|
||||||
use embassy_nrf::{interrupt, pac, peripherals};
|
use embassy_nrf::usb::Driver;
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::{Builder, Config, UsbDevice};
|
use embassy_usb::{Builder, Config, UsbDevice};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
macro_rules! singleton {
|
||||||
|
($val:expr) => {{
|
||||||
|
type T = impl Sized;
|
||||||
|
static STATIC_CELL: StaticCell<T> = StaticCell::new();
|
||||||
|
let (x,) = STATIC_CELL.init(($val,));
|
||||||
|
x
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
@ -39,10 +54,9 @@ async fn main(spawner: Spawner) {
|
|||||||
info!("Enabling ext hfosc...");
|
info!("Enabling ext hfosc...");
|
||||||
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
|
||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
@ -59,34 +73,21 @@ async fn main(spawner: Spawner) {
|
|||||||
config.device_protocol = 0x01;
|
config.device_protocol = 0x01;
|
||||||
config.composite_with_iads = true;
|
config.composite_with_iads = true;
|
||||||
|
|
||||||
struct Resources {
|
let state = singleton!(State::new());
|
||||||
device_descriptor: [u8; 256],
|
|
||||||
config_descriptor: [u8; 256],
|
|
||||||
bos_descriptor: [u8; 256],
|
|
||||||
control_buf: [u8; 64],
|
|
||||||
serial_state: State<'static>,
|
|
||||||
}
|
|
||||||
static RESOURCES: StaticCell<Resources> = StaticCell::new();
|
|
||||||
let res = RESOURCES.init(Resources {
|
|
||||||
device_descriptor: [0; 256],
|
|
||||||
config_descriptor: [0; 256],
|
|
||||||
bos_descriptor: [0; 256],
|
|
||||||
control_buf: [0; 64],
|
|
||||||
serial_state: State::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create embassy-usb DeviceBuilder using the driver and config.
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
driver,
|
driver,
|
||||||
config,
|
config,
|
||||||
&mut res.device_descriptor,
|
&mut singleton!([0; 256])[..],
|
||||||
&mut res.config_descriptor,
|
&mut singleton!([0; 256])[..],
|
||||||
&mut res.bos_descriptor,
|
&mut singleton!([0; 256])[..],
|
||||||
&mut res.control_buf,
|
&mut singleton!([0; 128])[..],
|
||||||
|
&mut singleton!([0; 128])[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create classes on the builder.
|
// Create classes on the builder.
|
||||||
let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64);
|
let class = CdcAcmClass::new(&mut builder, state, 64);
|
||||||
|
|
||||||
// Build the builder.
|
// Build the builder.
|
||||||
let usb = builder.build();
|
let usb = builder.build();
|
||||||
|
@ -7,8 +7,9 @@ use core::mem;
|
|||||||
use defmt::{info, panic};
|
use defmt::{info, panic};
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
|
use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
|
||||||
use embassy_nrf::{interrupt, pac};
|
use embassy_nrf::usb::{Driver, Instance};
|
||||||
|
use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
use embassy_usb::driver::EndpointError;
|
use embassy_usb::driver::EndpointError;
|
||||||
use embassy_usb::msos::{self, windows_version};
|
use embassy_usb::msos::{self, windows_version};
|
||||||
@ -16,6 +17,11 @@ use embassy_usb::types::InterfaceNumber;
|
|||||||
use embassy_usb::{Builder, Config};
|
use embassy_usb::{Builder, Config};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
USBD => usb::InterruptHandler<peripherals::USBD>;
|
||||||
|
POWER_CLOCK => usb::vbus_detect::InterruptHandler;
|
||||||
|
});
|
||||||
|
|
||||||
// This is a randomly generated GUID to allow clients on Windows to find our device
|
// This is a randomly generated GUID to allow clients on Windows to find our device
|
||||||
const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
|
const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
|
||||||
|
|
||||||
@ -29,9 +35,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
while clock.events_hfclkstarted.read().bits() != 1 {}
|
while clock.events_hfclkstarted.read().bits() != 1 {}
|
||||||
|
|
||||||
// Create the driver, from the HAL.
|
// Create the driver, from the HAL.
|
||||||
let irq = interrupt::take!(USBD);
|
let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
|
||||||
let power_irq = interrupt::take!(POWER_CLOCK);
|
|
||||||
let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
|
|
||||||
|
|
||||||
// Create embassy-usb Config
|
// Create embassy-usb Config
|
||||||
let mut config = Config::new(0xc0de, 0xcafe);
|
let mut config = Config::new(0xc0de, 0xcafe);
|
||||||
|
@ -4,24 +4,13 @@ name = "embassy-nrf5340-examples"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "MIT OR Apache-2.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]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
|
||||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [
|
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
] }
|
] }
|
||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [
|
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [
|
||||||
|
"nightly",
|
||||||
"defmt",
|
"defmt",
|
||||||
"integrated-timers",
|
"integrated-timers",
|
||||||
] }
|
] }
|
||||||
@ -30,6 +19,8 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = [
|
|||||||
"defmt-timestamp-uptime",
|
"defmt-timestamp-uptime",
|
||||||
] }
|
] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
|
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
|
||||||
|
"nightly",
|
||||||
|
"unstable-traits",
|
||||||
"defmt",
|
"defmt",
|
||||||
"nrf5340-app-s",
|
"nrf5340-app-s",
|
||||||
"time-driver-rtc1",
|
"time-driver-rtc1",
|
||||||
@ -37,16 +28,16 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
|
|||||||
"unstable-pac",
|
"unstable-pac",
|
||||||
] }
|
] }
|
||||||
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
|
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
|
||||||
|
"nightly",
|
||||||
"defmt",
|
"defmt",
|
||||||
"tcp",
|
"tcp",
|
||||||
"dhcpv4",
|
"dhcpv4",
|
||||||
"medium-ethernet",
|
"medium-ethernet",
|
||||||
], optional = true }
|
] }
|
||||||
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
|
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
|
||||||
"defmt",
|
"defmt",
|
||||||
], optional = true }
|
] }
|
||||||
embedded-io = "0.4.0"
|
embedded-io = { version = "0.4.0", features = [ "async" ]}
|
||||||
|
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
defmt-rtt = "0.4"
|
defmt-rtt = "0.4"
|
||||||
|
@ -4,9 +4,14 @@
|
|||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
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 _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
bind_interrupts!(struct Irqs {
|
||||||
|
SERIAL0 => uarte::InterruptHandler<SERIAL0>;
|
||||||
|
});
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(_spawner: Spawner) {
|
async fn main(_spawner: Spawner) {
|
||||||
let p = embassy_nrf::init(Default::default());
|
let p = embassy_nrf::init(Default::default());
|
||||||
@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
config.parity = uarte::Parity::EXCLUDED;
|
config.parity = uarte::Parity::EXCLUDED;
|
||||||
config.baudrate = uarte::Baudrate::BAUD115200;
|
config.baudrate = uarte::Baudrate::BAUD115200;
|
||||||
|
|
||||||
let irq = interrupt::take!(SERIAL0);
|
let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config);
|
||||||
let mut uart = uarte::Uarte::new(p.SERIAL0, irq, p.P1_00, p.P1_01, config);
|
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ async fn main_task(spawner: Spawner) {
|
|||||||
let seed = u64::from_le_bytes(seed);
|
let seed = u64::from_le_bytes(seed);
|
||||||
|
|
||||||
// Init network stack
|
// 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
|
// Launch network task
|
||||||
spawner.spawn(net_task(stack)).unwrap();
|
spawner.spawn(net_task(stack)).unwrap();
|
||||||
|
@ -65,7 +65,7 @@ async fn main_task(spawner: Spawner) {
|
|||||||
let seed = u64::from_le_bytes(seed);
|
let seed = u64::from_le_bytes(seed);
|
||||||
|
|
||||||
// Init network stack
|
// 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
|
// Launch network task
|
||||||
spawner.spawn(net_task(stack)).unwrap();
|
spawner.spawn(net_task(stack)).unwrap();
|
||||||
|
@ -62,7 +62,7 @@ async fn main_task(spawner: Spawner) {
|
|||||||
let seed = u64::from_le_bytes(seed);
|
let seed = u64::from_le_bytes(seed);
|
||||||
|
|
||||||
// Init network stack
|
// 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
|
// Launch network task
|
||||||
spawner.spawn(net_task(stack)).unwrap();
|
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-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
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-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"
|
static_cell = "1.0"
|
||||||
|
@ -57,11 +57,14 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use cortex_m::peripheral::NVIC;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::executor::{Executor, InterruptExecutor};
|
use embassy_stm32::executor::{Executor, InterruptExecutor};
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::interrupt::InterruptExt;
|
use embassy_stm32::pac::Interrupt;
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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_HIGH: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::USART2>> = StaticCell::new();
|
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::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]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
// Initialize and create handle for devicer peripherals
|
// Initialize and create handle for devicer peripherals
|
||||||
let _p = embassy_stm32::init(Default::default());
|
let _p = embassy_stm32::init(Default::default());
|
||||||
|
let mut nvic: NVIC = unsafe { mem::transmute(()) };
|
||||||
|
|
||||||
// High-priority executor: USART1, priority level 6
|
// High-priority executor: USART1, priority level 6
|
||||||
let irq = interrupt::take!(USART1);
|
unsafe { nvic.set_priority(Interrupt::USART1, 6 << 4) };
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
let spawner = EXECUTOR_HIGH.start(Interrupt::USART1);
|
||||||
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
|
|
||||||
// Medium-priority executor: USART2, priority level 7
|
// Medium-priority executor: USART2, priority level 7
|
||||||
let irq = interrupt::take!(USART2);
|
unsafe { nvic.set_priority(Interrupt::USART2, 7 << 4) };
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
let spawner = EXECUTOR_MED.start(Interrupt::USART2);
|
||||||
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// Low priority executor: runs in thread mode, using WFE/SEV
|
@ -57,11 +57,14 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use cortex_m::peripheral::NVIC;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::executor::{Executor, InterruptExecutor};
|
use embassy_stm32::executor::{Executor, InterruptExecutor};
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::interrupt::InterruptExt;
|
use embassy_stm32::pac::Interrupt;
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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_HIGH: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new();
|
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::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]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let _p = embassy_stm32::init(Default::default());
|
let _p = embassy_stm32::init(Default::default());
|
||||||
|
let mut nvic: NVIC = unsafe { mem::transmute(()) };
|
||||||
|
|
||||||
// High-priority executor: SWI1_EGU1, priority level 6
|
// High-priority executor: UART4, priority level 6
|
||||||
let irq = interrupt::take!(UART4);
|
unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) };
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
let spawner = EXECUTOR_HIGH.start(Interrupt::UART4);
|
||||||
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
|
|
||||||
// Medium-priority executor: SWI0_EGU0, priority level 7
|
// Medium-priority executor: UART5, priority level 7
|
||||||
let irq = interrupt::take!(UART5);
|
unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) };
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
let spawner = EXECUTOR_MED.start(Interrupt::UART5);
|
||||||
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// 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-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-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-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 = "0.3"
|
||||||
defmt-rtt = "0.4"
|
defmt-rtt = "0.4"
|
||||||
@ -27,9 +27,5 @@ embedded-storage = "0.3.0"
|
|||||||
micromath = "2.0.0"
|
micromath = "2.0.0"
|
||||||
static_cell = "1.0"
|
static_cell = "1.0"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "usb_ethernet"
|
|
||||||
required-features = ["embassy-net"]
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = 2
|
debug = 2
|
||||||
|
@ -57,11 +57,14 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
|
|
||||||
|
use cortex_m::peripheral::NVIC;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_stm32::executor::{Executor, InterruptExecutor};
|
use embassy_stm32::executor::{Executor, InterruptExecutor};
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
use embassy_stm32::interrupt::InterruptExt;
|
use embassy_stm32::pac::Interrupt;
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
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_HIGH: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new();
|
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
|
||||||
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::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]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let _p = embassy_stm32::init(Default::default());
|
let _p = embassy_stm32::init(Default::default());
|
||||||
|
let mut nvic: NVIC = unsafe { mem::transmute(()) };
|
||||||
|
|
||||||
// High-priority executor: SWI1_EGU1, priority level 6
|
// High-priority executor: UART4, priority level 6
|
||||||
let irq = interrupt::take!(UART4);
|
unsafe { nvic.set_priority(Interrupt::UART4, 6 << 4) };
|
||||||
irq.set_priority(interrupt::Priority::P6);
|
let spawner = EXECUTOR_HIGH.start(Interrupt::UART4);
|
||||||
let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_high()));
|
unwrap!(spawner.spawn(run_high()));
|
||||||
|
|
||||||
// Medium-priority executor: SWI0_EGU0, priority level 7
|
// Medium-priority executor: UART5, priority level 7
|
||||||
let irq = interrupt::take!(UART5);
|
unsafe { nvic.set_priority(Interrupt::UART5, 7 << 4) };
|
||||||
irq.set_priority(interrupt::Priority::P7);
|
let spawner = EXECUTOR_MED.start(Interrupt::UART5);
|
||||||
let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
|
|
||||||
let spawner = executor.start();
|
|
||||||
unwrap!(spawner.spawn(run_med()));
|
unwrap!(spawner.spawn(run_med()));
|
||||||
|
|
||||||
// Low priority executor: runs in thread mode, using WFE/SEV
|
// 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);
|
let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
|
||||||
unwrap!(spawner.spawn(usb_ncm_task(runner)));
|
unwrap!(spawner.spawn(usb_ncm_task(runner)));
|
||||||
|
|
||||||
let config = embassy_net::ConfigStrategy::Dhcp;
|
let config = embassy_net::Config::Dhcp(Default::default());
|
||||||
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
|
//let config = embassy_net::Config::Static(embassy_net::StaticConfig {
|
||||||
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
|
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
|
||||||
// dns_servers: Vec::new(),
|
// dns_servers: Vec::new(),
|
||||||
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
|
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
|
||||||
@ -114,12 +114,7 @@ async fn main(spawner: Spawner) {
|
|||||||
let seed = u64::from_le_bytes(seed);
|
let seed = u64::from_le_bytes(seed);
|
||||||
|
|
||||||
// Init network stack
|
// Init network stack
|
||||||
let stack = &*singleton!(Stack::new(
|
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
|
||||||
device,
|
|
||||||
config,
|
|
||||||
singleton!(StackResources::<1, 2, 8>::new()),
|
|
||||||
seed
|
|
||||||
));
|
|
||||||
|
|
||||||
unwrap!(spawner.spawn(net_task(stack)));
|
unwrap!(spawner.spawn(net_task(stack)));
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@ name = "embassy-stm32l4-examples"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
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-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
|
||||||
|
@ -4,8 +4,6 @@ name = "embassy-stm32l5-examples"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
|
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-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