Merge branch 'master' into stm32f4
This commit is contained in:
commit
be541b94aa
@ -5,8 +5,9 @@ members = [
|
|||||||
"embassy-nrf",
|
"embassy-nrf",
|
||||||
"embassy-stm32f4",
|
"embassy-stm32f4",
|
||||||
"embassy-macros",
|
"embassy-macros",
|
||||||
"examples",
|
"embassy-nrf-examples",
|
||||||
"examples-stm32f4",
|
"embassy-stm32f4-examples",
|
||||||
|
"embassy-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = [
|
exclude = [
|
||||||
|
16
README.md
16
README.md
@ -11,15 +11,17 @@ Embassy is a project to make async/await a first-class option for embedded devel
|
|||||||
- `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`.
|
- `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`.
|
||||||
- More traits for SPI, I2C, UART async HAL coming soon.
|
- More traits for SPI, I2C, UART async HAL coming soon.
|
||||||
|
|
||||||
## Executor with timers
|
## Executor
|
||||||
|
|
||||||
The `embassy::executor` module provides an async/await executor based on [static-executor](https://github.com/Dirbaio/static-executor).
|
The `embassy::executor` module provides an async/await executor designed for embedded usage.
|
||||||
|
|
||||||
- No `alloc`, no heap needed. Task futures are statically allocated.
|
- No `alloc`, no heap needed. Task futures are statically allocated.
|
||||||
- Integrated timer queue allows simple sleeping: `Timer::after(Duration::from_ticks(64000)).await;`.
|
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||||
- Suitable for low-power operation. Using interrupts or `WFE/SEV` ensures the CPU sleeps when there's no work to do. No busy-loop polling.
|
- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
||||||
|
- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
||||||
|
- Efficient polling: a wake will only poll the woken task, not all of them.
|
||||||
|
- Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
||||||
- Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
|
- Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
|
||||||
- Compatible with RTIC (example coming soon).
|
|
||||||
|
|
||||||
## Utils
|
## Utils
|
||||||
|
|
||||||
@ -54,9 +56,7 @@ cargo run --bin rtc_async
|
|||||||
|
|
||||||
## Minimum supported Rust version (MSRV)
|
## Minimum supported Rust version (MSRV)
|
||||||
|
|
||||||
`rustc 1.48.0-nightly (1fd5b9d51 2020-09-20)`
|
Only recent nighly supported. Nightly is required for:
|
||||||
|
|
||||||
Any recent nightly should work. Nightly is required for:
|
|
||||||
|
|
||||||
- `generic_associated_types`: for trait funcs returning futures.
|
- `generic_associated_types`: for trait funcs returning futures.
|
||||||
- `type_alias_impl_trait`: for trait funcs returning futures implemented with `async{}` blocks, and for `static-executor`.
|
- `type_alias_impl_trait`: for trait funcs returning futures implemented with `async{}` blocks, and for `static-executor`.
|
||||||
|
@ -55,9 +55,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
|
let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
|
||||||
syn::punctuated::Punctuated::new();
|
syn::punctuated::Punctuated::new();
|
||||||
let args = &task_fn.sig.inputs;
|
let mut args = task_fn.sig.inputs.clone();
|
||||||
|
|
||||||
for arg in args.iter() {
|
for arg in args.iter_mut() {
|
||||||
match arg {
|
match arg {
|
||||||
syn::FnArg::Receiver(_) => {
|
syn::FnArg::Receiver(_) => {
|
||||||
arg.span()
|
arg.span()
|
||||||
@ -66,8 +66,11 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
.emit();
|
.emit();
|
||||||
fail = true;
|
fail = true;
|
||||||
}
|
}
|
||||||
syn::FnArg::Typed(t) => match t.pat.as_ref() {
|
syn::FnArg::Typed(t) => match t.pat.as_mut() {
|
||||||
syn::Pat::Ident(i) => arg_names.push(i.ident.clone()),
|
syn::Pat::Ident(i) => {
|
||||||
|
arg_names.push(i.ident.clone());
|
||||||
|
i.mutability = None;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
arg.span()
|
arg.span()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -20,8 +20,4 @@ rustflags = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
# Pick ONE of these compilation targets
|
target = "thumbv7em-none-eabi"
|
||||||
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
|
||||||
# target = "thumbv7m-none-eabi" # Cortex-M3
|
|
||||||
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
|
||||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
|
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "embassy-examples"
|
name = "embassy-nrf-examples"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
@ -8,15 +8,17 @@ use example_common::*;
|
|||||||
|
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use defmt::panic;
|
use defmt::panic;
|
||||||
use futures::pin_mut;
|
|
||||||
use nrf52840_hal::gpio;
|
use nrf52840_hal::gpio;
|
||||||
|
|
||||||
use embassy::executor::{task, Executor};
|
use embassy::executor::{task, Executor};
|
||||||
use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt};
|
use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
|
||||||
use embassy::util::Forever;
|
use embassy::util::Forever;
|
||||||
use embassy_nrf::buffered_uarte;
|
use embassy_nrf::buffered_uarte;
|
||||||
use embassy_nrf::interrupt;
|
use embassy_nrf::interrupt;
|
||||||
|
|
||||||
|
static mut TX_BUFFER: [u8; 4096] = [0; 4096];
|
||||||
|
static mut RX_BUFFER: [u8; 4096] = [0; 4096];
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
async fn run() {
|
async fn run() {
|
||||||
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||||
@ -34,14 +36,15 @@ async fn run() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let irq = interrupt::take!(UARTE0_UART0);
|
let irq = interrupt::take!(UARTE0_UART0);
|
||||||
let u = buffered_uarte::BufferedUarte::new(
|
let mut u = buffered_uarte::BufferedUarte::new(
|
||||||
p.UARTE0,
|
p.UARTE0,
|
||||||
irq,
|
irq,
|
||||||
|
unsafe { &mut RX_BUFFER },
|
||||||
|
unsafe { &mut TX_BUFFER },
|
||||||
pins,
|
pins,
|
||||||
buffered_uarte::Parity::EXCLUDED,
|
buffered_uarte::Parity::EXCLUDED,
|
||||||
buffered_uarte::Baudrate::BAUD115200,
|
buffered_uarte::Baudrate::BAUD115200,
|
||||||
);
|
);
|
||||||
pin_mut!(u);
|
|
||||||
|
|
||||||
info!("uarte initialized!");
|
info!("uarte initialized!");
|
||||||
|
|
@ -10,6 +10,7 @@ use cortex_m_rt::entry;
|
|||||||
use defmt::panic;
|
use defmt::panic;
|
||||||
use embassy::executor::{task, Executor};
|
use embassy::executor::{task, Executor};
|
||||||
use embassy::time::{Duration, Timer};
|
use embassy::time::{Duration, Timer};
|
||||||
|
use embassy::uart::Uart;
|
||||||
use embassy::util::Forever;
|
use embassy::util::Forever;
|
||||||
use embassy_nrf::{interrupt, pac, rtc, uarte};
|
use embassy_nrf::{interrupt, pac, rtc, uarte};
|
||||||
use futures::future::{select, Either};
|
use futures::future::{select, Either};
|
||||||
@ -24,29 +25,37 @@ async fn run(mut uart: uarte::Uarte<pac::UARTE0>) {
|
|||||||
let mut buf = [0; 8];
|
let mut buf = [0; 8];
|
||||||
buf.copy_from_slice(b"Hello!\r\n");
|
buf.copy_from_slice(b"Hello!\r\n");
|
||||||
|
|
||||||
uart.send(&buf).await;
|
unwrap!(uart.send(&buf).await);
|
||||||
info!("wrote hello in uart!");
|
info!("wrote hello in uart!");
|
||||||
|
|
||||||
info!("reading...");
|
|
||||||
loop {
|
loop {
|
||||||
let received = match select(
|
let buf_len = buf.len();
|
||||||
uart.receive(&mut buf),
|
info!("reading...");
|
||||||
Timer::after(Duration::from_millis(10)),
|
|
||||||
)
|
// `receive()` doesn't return until the buffer has been completely filled with
|
||||||
.await
|
// incoming data, which in this case is 8 bytes.
|
||||||
{
|
//
|
||||||
Either::Left((buf, _)) => buf,
|
// This example shows how to use `select` to run an uart receive concurrently with a
|
||||||
Either::Right((_, read)) => {
|
// 1 second timer, effectively adding a timeout to the receive operation.
|
||||||
let (buf, n) = read.stop().await;
|
let recv_fut = uart.receive(&mut buf);
|
||||||
&buf[..n]
|
let timer_fut = Timer::after(Duration::from_millis(1000));
|
||||||
}
|
let received_len = match select(recv_fut, timer_fut).await {
|
||||||
|
// recv_fut completed first, so we've received `buf_len` bytes.
|
||||||
|
Either::Left(_) => buf_len,
|
||||||
|
// timer_fut completed first. `select` gives us back the future that didn't complete, which
|
||||||
|
// is `recv_fut` in this case, so we can do further stuff with it.
|
||||||
|
//
|
||||||
|
// The recv_fut would stop the uart read automatically when dropped. However, we want to know how
|
||||||
|
// many bytes have been received, so we have to "gracefully stop" it with `.stop()`.
|
||||||
|
Either::Right((_, recv_fut)) => recv_fut.stop().await,
|
||||||
};
|
};
|
||||||
|
let received = &mut buf[..received_len];
|
||||||
|
|
||||||
if received.len() > 0 {
|
if received.len() > 0 {
|
||||||
info!("read done, got {:[u8]}", received);
|
info!("read done, got {:[u8]}", received);
|
||||||
|
|
||||||
// Echo back received data
|
// Echo back received data
|
||||||
uart.send(received).await;
|
unwrap!(uart.send(received).await);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,114 +4,29 @@
|
|||||||
//!
|
//!
|
||||||
//! - nrf52832: Section 35
|
//! - nrf52832: Section 35
|
||||||
//! - nrf52840: Section 6.34
|
//! - nrf52840: Section 6.34
|
||||||
use core::cell::UnsafeCell;
|
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
use core::marker::PhantomPinned;
|
use core::marker::PhantomData;
|
||||||
|
use core::mem;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use core::ptr;
|
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
use embassy::io::{AsyncBufRead, AsyncWrite, Result};
|
||||||
|
use embassy::util::WakerRegistration;
|
||||||
use embedded_hal::digital::v2::OutputPin;
|
use embedded_hal::digital::v2::OutputPin;
|
||||||
|
|
||||||
use crate::hal::gpio::{Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull};
|
use crate::fmt::{panic, todo, *};
|
||||||
use crate::interrupt;
|
use crate::hal::gpio::Port as GpioPort;
|
||||||
use crate::interrupt::{CriticalSection, OwnedInterrupt};
|
use crate::interrupt::{self, OwnedInterrupt};
|
||||||
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
|
use crate::pac;
|
||||||
use crate::pac::UARTE1;
|
use crate::pac::uarte0;
|
||||||
use crate::pac::{uarte0, UARTE0};
|
use crate::util::peripheral;
|
||||||
|
use crate::util::ring_buffer::RingBuffer;
|
||||||
|
|
||||||
// Re-export SVD variants to allow user to directly set values
|
// Re-export SVD variants to allow user to directly set values
|
||||||
|
pub use crate::hal::uarte::Pins;
|
||||||
pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||||
|
|
||||||
use embassy::io::{AsyncBufRead, AsyncWrite, Result};
|
|
||||||
use embassy::util::WakerStore;
|
|
||||||
|
|
||||||
use crate::fmt::{assert, panic, todo, *};
|
|
||||||
|
|
||||||
//use crate::trace;
|
|
||||||
|
|
||||||
const RINGBUF_SIZE: usize = 512;
|
|
||||||
struct RingBuf {
|
|
||||||
buf: [u8; RINGBUF_SIZE],
|
|
||||||
start: usize,
|
|
||||||
end: usize,
|
|
||||||
empty: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RingBuf {
|
|
||||||
fn new() -> Self {
|
|
||||||
RingBuf {
|
|
||||||
buf: [0; RINGBUF_SIZE],
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
empty: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_buf(&mut self) -> &mut [u8] {
|
|
||||||
if self.start == self.end && !self.empty {
|
|
||||||
trace!(" ringbuf: push_buf empty");
|
|
||||||
return &mut self.buf[..0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = if self.start <= self.end {
|
|
||||||
RINGBUF_SIZE - self.end
|
|
||||||
} else {
|
|
||||||
self.start - self.end
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
|
|
||||||
&mut self.buf[self.end..self.end + n]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push(&mut self, n: usize) {
|
|
||||||
trace!(" ringbuf: push {:?}", n);
|
|
||||||
if n == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.end = Self::wrap(self.end + n);
|
|
||||||
self.empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_buf(&mut self) -> &mut [u8] {
|
|
||||||
if self.empty {
|
|
||||||
trace!(" ringbuf: pop_buf empty");
|
|
||||||
return &mut self.buf[..0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = if self.end <= self.start {
|
|
||||||
RINGBUF_SIZE - self.start
|
|
||||||
} else {
|
|
||||||
self.end - self.start
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
|
|
||||||
&mut self.buf[self.start..self.start + n]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop(&mut self, n: usize) {
|
|
||||||
trace!(" ringbuf: pop {:?}", n);
|
|
||||||
if n == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.start = Self::wrap(self.start + n);
|
|
||||||
self.empty = self.start == self.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrap(n: usize) -> usize {
|
|
||||||
assert!(n <= RINGBUF_SIZE);
|
|
||||||
if n == RINGBUF_SIZE {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
enum RxState {
|
enum RxState {
|
||||||
Idle,
|
Idle,
|
||||||
@ -133,28 +48,12 @@ enum TxState {
|
|||||||
/// are disabled before using `Uarte`. See product specification:
|
/// are disabled before using `Uarte`. See product specification:
|
||||||
/// - nrf52832: Section 15.2
|
/// - nrf52832: Section 15.2
|
||||||
/// - nrf52840: Section 6.1.2
|
/// - nrf52840: Section 6.1.2
|
||||||
pub struct BufferedUarte<T: Instance> {
|
pub struct BufferedUarte<'a, T: Instance> {
|
||||||
started: bool,
|
reg: peripheral::Registration<State<'a, T>>,
|
||||||
state: UnsafeCell<UarteState<T>>,
|
wtf: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// public because it needs to be used in Instance::{get_state, set_state}, but
|
impl<'a, T: Instance> Unpin for BufferedUarte<'a, T> {}
|
||||||
// should not be used outside the module
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct UarteState<T: Instance> {
|
|
||||||
inner: T,
|
|
||||||
irq: T::Interrupt,
|
|
||||||
|
|
||||||
rx: RingBuf,
|
|
||||||
rx_state: RxState,
|
|
||||||
rx_waker: WakerStore,
|
|
||||||
|
|
||||||
tx: RingBuf,
|
|
||||||
tx_state: TxState,
|
|
||||||
tx_waker: WakerStore,
|
|
||||||
|
|
||||||
_pin: PhantomPinned,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
fn port_bit(port: GpioPort) -> bool {
|
fn port_bit(port: GpioPort) -> bool {
|
||||||
@ -164,10 +63,12 @@ fn port_bit(port: GpioPort) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> BufferedUarte<T> {
|
impl<'a, T: Instance> BufferedUarte<'a, T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: T,
|
uarte: T,
|
||||||
irq: T::Interrupt,
|
irq: T::Interrupt,
|
||||||
|
rx_buffer: &'a mut [u8],
|
||||||
|
tx_buffer: &'a mut [u8],
|
||||||
mut pins: Pins,
|
mut pins: Pins,
|
||||||
parity: Parity,
|
parity: Parity,
|
||||||
baudrate: Baudrate,
|
baudrate: Baudrate,
|
||||||
@ -225,87 +126,79 @@ impl<T: Instance> BufferedUarte<T> {
|
|||||||
// Configure frequency
|
// Configure frequency
|
||||||
uarte.baudrate.write(|w| w.baudrate().variant(baudrate));
|
uarte.baudrate.write(|w| w.baudrate().variant(baudrate));
|
||||||
|
|
||||||
|
irq.pend();
|
||||||
|
|
||||||
BufferedUarte {
|
BufferedUarte {
|
||||||
started: false,
|
reg: peripheral::Registration::new(
|
||||||
state: UnsafeCell::new(UarteState {
|
|
||||||
inner: uarte,
|
|
||||||
irq,
|
irq,
|
||||||
|
State {
|
||||||
|
inner: uarte,
|
||||||
|
|
||||||
rx: RingBuf::new(),
|
rx: RingBuffer::new(rx_buffer),
|
||||||
rx_state: RxState::Idle,
|
rx_state: RxState::Idle,
|
||||||
rx_waker: WakerStore::new(),
|
rx_waker: WakerRegistration::new(),
|
||||||
|
|
||||||
tx: RingBuf::new(),
|
tx: RingBuffer::new(tx_buffer),
|
||||||
tx_state: TxState::Idle,
|
tx_state: TxState::Idle,
|
||||||
tx_waker: WakerStore::new(),
|
tx_waker: WakerRegistration::new(),
|
||||||
|
},
|
||||||
_pin: PhantomPinned,
|
),
|
||||||
}),
|
wtf: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_state<'a, R>(
|
|
||||||
self: Pin<&'a mut Self>,
|
|
||||||
f: impl FnOnce(Pin<&'a mut UarteState<T>>) -> R,
|
|
||||||
) -> R {
|
|
||||||
let Self { state, started } = unsafe { self.get_unchecked_mut() };
|
|
||||||
|
|
||||||
interrupt::free(|cs| {
|
|
||||||
let ptr = state.get();
|
|
||||||
|
|
||||||
if !*started {
|
|
||||||
T::set_state(cs, ptr);
|
|
||||||
|
|
||||||
*started = true;
|
|
||||||
|
|
||||||
// safety: safe because critical section ensures only one *mut UartState
|
|
||||||
// exists at the same time.
|
|
||||||
unsafe { Pin::new_unchecked(&mut *ptr) }.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// safety: safe because critical section ensures only one *mut UartState
|
|
||||||
// exists at the same time.
|
|
||||||
f(unsafe { Pin::new_unchecked(&mut *ptr) })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> Drop for BufferedUarte<T> {
|
impl<'a, T: Instance> Drop for BufferedUarte<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// stop DMA before dropping, because DMA is using the buffer in `self`.
|
// stop DMA before dropping, because DMA is using the buffer in `self`.
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> AsyncBufRead for BufferedUarte<T> {
|
impl<'a, T: Instance> AsyncBufRead for BufferedUarte<'a, T> {
|
||||||
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
|
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
|
||||||
self.with_state(|s| s.poll_fill_buf(cx))
|
let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
this.reg.with(|state, _| {
|
||||||
|
let z: Poll<Result<&[u8]>> = state.poll_fill_buf(cx);
|
||||||
|
let z: Poll<Result<&[u8]>> = unsafe { mem::transmute(z) };
|
||||||
|
z
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(self: Pin<&mut Self>, amt: usize) {
|
fn consume(self: Pin<&mut Self>, amt: usize) {
|
||||||
self.with_state(|s| s.consume(amt))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Instance> AsyncWrite for BufferedUarte<T> {
|
|
||||||
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
|
|
||||||
self.with_state(|s| s.poll_write(cx, buf))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Instance> UarteState<T> {
|
|
||||||
pub fn start(self: Pin<&mut Self>) {
|
|
||||||
self.irq.set_handler(|| unsafe {
|
|
||||||
interrupt::free(|cs| T::get_state(cs).as_mut().unwrap().on_interrupt());
|
|
||||||
});
|
|
||||||
|
|
||||||
self.irq.pend();
|
|
||||||
self.irq.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
|
|
||||||
let this = unsafe { self.get_unchecked_mut() };
|
let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
this.reg.with(|state, irq| state.consume(irq, amt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Instance> AsyncWrite for BufferedUarte<'a, T> {
|
||||||
|
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
|
||||||
|
let this = unsafe { self.get_unchecked_mut() };
|
||||||
|
this.reg.with(|state, irq| state.poll_write(irq, cx, buf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================================
|
||||||
|
// ====================================
|
||||||
|
// ====================================
|
||||||
|
|
||||||
|
// public because it needs to be used in Instance trait, but
|
||||||
|
// should not be used outside the module
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct State<'a, T: Instance> {
|
||||||
|
inner: T,
|
||||||
|
|
||||||
|
rx: RingBuffer<'a>,
|
||||||
|
rx_state: RxState,
|
||||||
|
rx_waker: WakerRegistration,
|
||||||
|
|
||||||
|
tx: RingBuffer<'a>,
|
||||||
|
tx_state: TxState,
|
||||||
|
tx_waker: WakerRegistration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Instance> State<'a, T> {
|
||||||
|
fn poll_fill_buf(&mut self, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
|
||||||
// Conservative compiler fence to prevent optimizations that do not
|
// Conservative compiler fence to prevent optimizations that do not
|
||||||
// take in to account actions by DMA. The fence has been placed here,
|
// take in to account actions by DMA. The fence has been placed here,
|
||||||
// before any DMA action has started
|
// before any DMA action has started
|
||||||
@ -313,7 +206,7 @@ impl<T: Instance> UarteState<T> {
|
|||||||
trace!("poll_read");
|
trace!("poll_read");
|
||||||
|
|
||||||
// We have data ready in buffer? Return it.
|
// We have data ready in buffer? Return it.
|
||||||
let buf = this.rx.pop_buf();
|
let buf = self.rx.pop_buf();
|
||||||
if buf.len() != 0 {
|
if buf.len() != 0 {
|
||||||
trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len());
|
trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len());
|
||||||
return Poll::Ready(Ok(buf));
|
return Poll::Ready(Ok(buf));
|
||||||
@ -321,38 +214,40 @@ impl<T: Instance> UarteState<T> {
|
|||||||
|
|
||||||
trace!(" empty");
|
trace!(" empty");
|
||||||
|
|
||||||
if this.rx_state == RxState::ReceivingReady {
|
if self.rx_state == RxState::ReceivingReady {
|
||||||
trace!(" stopping");
|
trace!(" stopping");
|
||||||
this.rx_state = RxState::Stopping;
|
self.rx_state = RxState::Stopping;
|
||||||
this.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
self.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rx_waker.store(cx.waker());
|
self.rx_waker.register(cx.waker());
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(self: Pin<&mut Self>, amt: usize) {
|
fn consume(&mut self, irq: &mut T::Interrupt, amt: usize) {
|
||||||
let this = unsafe { self.get_unchecked_mut() };
|
|
||||||
trace!("consume {:?}", amt);
|
trace!("consume {:?}", amt);
|
||||||
this.rx.pop(amt);
|
self.rx.pop(amt);
|
||||||
this.irq.pend();
|
irq.pend();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
|
fn poll_write(
|
||||||
let this = unsafe { self.get_unchecked_mut() };
|
&mut self,
|
||||||
|
irq: &mut T::Interrupt,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Poll<Result<usize>> {
|
||||||
trace!("poll_write: {:?}", buf.len());
|
trace!("poll_write: {:?}", buf.len());
|
||||||
|
|
||||||
let tx_buf = this.tx.push_buf();
|
let tx_buf = self.tx.push_buf();
|
||||||
if tx_buf.len() == 0 {
|
if tx_buf.len() == 0 {
|
||||||
trace!("poll_write: pending");
|
trace!("poll_write: pending");
|
||||||
this.tx_waker.store(cx.waker());
|
self.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]);
|
||||||
this.tx.push(n);
|
self.tx.push(n);
|
||||||
|
|
||||||
trace!("poll_write: queued {:?}", n);
|
trace!("poll_write: queued {:?}", n);
|
||||||
|
|
||||||
@ -361,10 +256,17 @@ impl<T: Instance> UarteState<T> {
|
|||||||
// before any DMA action has started
|
// before any DMA action has started
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
this.irq.pend();
|
irq.pend();
|
||||||
|
|
||||||
Poll::Ready(Ok(n))
|
Poll::Ready(Ok(n))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Instance> peripheral::State for State<'a, T> {
|
||||||
|
type Interrupt = T::Interrupt;
|
||||||
|
fn store<'b>() -> &'b peripheral::Store<Self> {
|
||||||
|
unsafe { mem::transmute(T::storage()) }
|
||||||
|
}
|
||||||
|
|
||||||
fn on_interrupt(&mut self) {
|
fn on_interrupt(&mut self) {
|
||||||
trace!("irq: start");
|
trace!("irq: start");
|
||||||
@ -504,13 +406,6 @@ impl<T: Instance> UarteState<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pins {
|
|
||||||
pub rxd: GpioPin<Input<Floating>>,
|
|
||||||
pub txd: GpioPin<Output<PushPull>>,
|
|
||||||
pub cts: Option<GpioPin<Input<Floating>>>,
|
|
||||||
pub rts: Option<GpioPin<Output<PushPull>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
mod private {
|
mod private {
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
|
|
||||||
@ -519,39 +414,28 @@ mod private {
|
|||||||
impl Sealed for crate::pac::UARTE1 {}
|
impl Sealed for crate::pac::UARTE1 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed {
|
pub trait Instance:
|
||||||
|
Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed + 'static
|
||||||
|
{
|
||||||
type Interrupt: OwnedInterrupt;
|
type Interrupt: OwnedInterrupt;
|
||||||
|
fn storage() -> &'static peripheral::Store<State<'static, Self>>;
|
||||||
#[doc(hidden)]
|
|
||||||
fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self>;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut UARTE0_STATE: *mut UarteState<UARTE0> = ptr::null_mut();
|
impl Instance for pac::UARTE0 {
|
||||||
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
|
|
||||||
static mut UARTE1_STATE: *mut UarteState<UARTE1> = ptr::null_mut();
|
|
||||||
|
|
||||||
impl Instance for UARTE0 {
|
|
||||||
type Interrupt = interrupt::UARTE0_UART0Interrupt;
|
type Interrupt = interrupt::UARTE0_UART0Interrupt;
|
||||||
|
fn storage() -> &'static peripheral::Store<State<'static, Self>> {
|
||||||
fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> {
|
static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE0>> =
|
||||||
unsafe { UARTE0_STATE } // Safe because of CriticalSection
|
peripheral::Store::uninit();
|
||||||
}
|
&STORAGE
|
||||||
fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) {
|
|
||||||
unsafe { UARTE0_STATE = state } // Safe because of CriticalSection
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
|
#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
|
||||||
impl Instance for UARTE1 {
|
impl Instance for pac::UARTE1 {
|
||||||
type Interrupt = interrupt::UARTE1Interrupt;
|
type Interrupt = interrupt::UARTE1Interrupt;
|
||||||
|
fn storage() -> &'static peripheral::Store<State<'static, Self>> {
|
||||||
fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> {
|
static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE1>> =
|
||||||
unsafe { UARTE1_STATE } // Safe because of CriticalSection
|
peripheral::Store::uninit();
|
||||||
}
|
&STORAGE
|
||||||
fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) {
|
|
||||||
unsafe { UARTE1_STATE = state } // Safe because of CriticalSection
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ pub use nrf52840_hal as hal;
|
|||||||
|
|
||||||
// This mod MUST go first, so that the others see its macros.
|
// This mod MUST go first, so that the others see its macros.
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
pub(crate) mod util;
|
||||||
|
|
||||||
pub mod buffered_uarte;
|
pub mod buffered_uarte;
|
||||||
pub mod gpiote;
|
pub mod gpiote;
|
||||||
|
@ -10,7 +10,6 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
|||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use embassy::util::Signal;
|
use embassy::util::Signal;
|
||||||
use embedded_dma::{ReadBuffer, WriteBuffer};
|
|
||||||
|
|
||||||
use crate::fmt::{assert, *};
|
use crate::fmt::{assert, *};
|
||||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||||
@ -140,57 +139,10 @@ where
|
|||||||
self.instance.enable.write(|w| w.enable().enabled());
|
self.instance.enable.write(|w| w.enable().enabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends serial data.
|
|
||||||
///
|
|
||||||
/// `tx_buffer` is marked as static as per `embedded-dma` requirements.
|
|
||||||
/// It it safe to use a buffer with a non static lifetime if memory is not
|
|
||||||
/// reused until the future has finished.
|
|
||||||
pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> SendFuture<'a, T, B>
|
|
||||||
where
|
|
||||||
B: ReadBuffer<Word = u8>,
|
|
||||||
{
|
|
||||||
// Panic if TX is running which can happen if the user has called
|
|
||||||
// `mem::forget()` on a previous future after polling it once.
|
|
||||||
assert!(!self.tx_started());
|
|
||||||
|
|
||||||
self.enable();
|
|
||||||
|
|
||||||
SendFuture {
|
|
||||||
uarte: self,
|
|
||||||
buf: tx_buffer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tx_started(&self) -> bool {
|
fn tx_started(&self) -> bool {
|
||||||
self.instance.events_txstarted.read().bits() != 0
|
self.instance.events_txstarted.read().bits() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives serial data.
|
|
||||||
///
|
|
||||||
/// The future is pending until the buffer is completely filled.
|
|
||||||
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
|
|
||||||
/// unfinished transfers after a timeout to prevent lockup when no more data
|
|
||||||
/// is incoming.
|
|
||||||
///
|
|
||||||
/// `rx_buffer` is marked as static as per `embedded-dma` requirements.
|
|
||||||
/// It it safe to use a buffer with a non static lifetime if memory is not
|
|
||||||
/// reused until the future has finished.
|
|
||||||
pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> ReceiveFuture<'a, T, B>
|
|
||||||
where
|
|
||||||
B: WriteBuffer<Word = u8>,
|
|
||||||
{
|
|
||||||
// Panic if RX is running which can happen if the user has called
|
|
||||||
// `mem::forget()` on a previous future after polling it once.
|
|
||||||
assert!(!self.rx_started());
|
|
||||||
|
|
||||||
self.enable();
|
|
||||||
|
|
||||||
ReceiveFuture {
|
|
||||||
uarte: self,
|
|
||||||
buf: Some(rx_buffer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rx_started(&self) -> bool {
|
fn rx_started(&self) -> bool {
|
||||||
self.instance.events_rxstarted.read().bits() != 0
|
self.instance.events_rxstarted.read().bits() != 0
|
||||||
}
|
}
|
||||||
@ -238,16 +190,62 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> embassy::uart::Uart for Uarte<T> {
|
||||||
|
type ReceiveFuture<'a> = ReceiveFuture<'a, T>;
|
||||||
|
type SendFuture<'a> = SendFuture<'a, T>;
|
||||||
|
|
||||||
|
/// Sends serial data.
|
||||||
|
///
|
||||||
|
/// `tx_buffer` is marked as static as per `embedded-dma` requirements.
|
||||||
|
/// It it safe to use a buffer with a non static lifetime if memory is not
|
||||||
|
/// reused until the future has finished.
|
||||||
|
fn send<'a>(&'a mut self, tx_buffer: &'a [u8]) -> SendFuture<'a, T> {
|
||||||
|
// Panic if TX is running which can happen if the user has called
|
||||||
|
// `mem::forget()` on a previous future after polling it once.
|
||||||
|
assert!(!self.tx_started());
|
||||||
|
|
||||||
|
self.enable();
|
||||||
|
|
||||||
|
SendFuture {
|
||||||
|
uarte: self,
|
||||||
|
buf: tx_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Receives serial data.
|
||||||
|
///
|
||||||
|
/// The future is pending until the buffer is completely filled.
|
||||||
|
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
|
||||||
|
/// unfinished transfers after a timeout to prevent lockup when no more data
|
||||||
|
/// is incoming.
|
||||||
|
///
|
||||||
|
/// `rx_buffer` is marked as static as per `embedded-dma` requirements.
|
||||||
|
/// It it safe to use a buffer with a non static lifetime if memory is not
|
||||||
|
/// reused until the future has finished.
|
||||||
|
fn receive<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> ReceiveFuture<'a, T> {
|
||||||
|
// Panic if RX is running which can happen if the user has called
|
||||||
|
// `mem::forget()` on a previous future after polling it once.
|
||||||
|
assert!(!self.rx_started());
|
||||||
|
|
||||||
|
self.enable();
|
||||||
|
|
||||||
|
ReceiveFuture {
|
||||||
|
uarte: self,
|
||||||
|
buf: rx_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Future for the [`Uarte::send()`] method.
|
/// Future for the [`Uarte::send()`] method.
|
||||||
pub struct SendFuture<'a, T, B>
|
pub struct SendFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
uarte: &'a Uarte<T>,
|
uarte: &'a Uarte<T>,
|
||||||
buf: B,
|
buf: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, B> Drop for SendFuture<'a, T, B>
|
impl<'a, T> Drop for SendFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -266,14 +264,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, B> Future for SendFuture<'a, T, B>
|
impl<'a, T> Future for SendFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
B: ReadBuffer<Word = u8>,
|
|
||||||
{
|
{
|
||||||
type Output = ();
|
type Output = Result<(), embassy::uart::Error>;
|
||||||
|
|
||||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
|
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
|
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
|
||||||
|
|
||||||
if !uarte.tx_started() {
|
if !uarte.tx_started() {
|
||||||
@ -281,7 +278,8 @@ where
|
|||||||
|
|
||||||
T::state().tx_done.reset();
|
T::state().tx_done.reset();
|
||||||
|
|
||||||
let (ptr, len) = unsafe { buf.read_buffer() };
|
let ptr = buf.as_ptr();
|
||||||
|
let len = buf.len();
|
||||||
assert!(len <= EASY_DMA_SIZE);
|
assert!(len <= EASY_DMA_SIZE);
|
||||||
// TODO: panic if buffer is not in SRAM
|
// TODO: panic if buffer is not in SRAM
|
||||||
|
|
||||||
@ -296,20 +294,20 @@ where
|
|||||||
uarte.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
uarte.tasks_starttx.write(|w| unsafe { w.bits(1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
T::state().tx_done.poll_wait(cx)
|
T::state().tx_done.poll_wait(cx).map(|()| Ok(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future for the [`Uarte::receive()`] method.
|
/// Future for the [`Uarte::receive()`] method.
|
||||||
pub struct ReceiveFuture<'a, T, B>
|
pub struct ReceiveFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
uarte: &'a Uarte<T>,
|
uarte: &'a Uarte<T>,
|
||||||
buf: Option<B>,
|
buf: &'a mut [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, B> Drop for ReceiveFuture<'a, T, B>
|
impl<'a, T> Drop for ReceiveFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -327,14 +325,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, B> Future for ReceiveFuture<'a, T, B>
|
impl<'a, T> Future for ReceiveFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
B: WriteBuffer<Word = u8>,
|
|
||||||
{
|
{
|
||||||
type Output = B;
|
type Output = Result<(), embassy::uart::Error>;
|
||||||
|
|
||||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B> {
|
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
|
let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
|
||||||
|
|
||||||
if !uarte.rx_started() {
|
if !uarte.rx_started() {
|
||||||
@ -342,7 +339,8 @@ where
|
|||||||
|
|
||||||
T::state().rx_done.reset();
|
T::state().rx_done.reset();
|
||||||
|
|
||||||
let (ptr, len) = unsafe { buf.as_mut().unwrap().write_buffer() };
|
let ptr = buf.as_ptr();
|
||||||
|
let len = buf.len();
|
||||||
assert!(len <= EASY_DMA_SIZE);
|
assert!(len <= EASY_DMA_SIZE);
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
@ -356,24 +354,20 @@ where
|
|||||||
uarte.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
uarte.tasks_startrx.write(|w| unsafe { w.bits(1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
T::state()
|
T::state().rx_done.poll_wait(cx).map(|_| Ok(()))
|
||||||
.rx_done
|
|
||||||
.poll_wait(cx)
|
|
||||||
.map(|_| buf.take().unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future for the [`receive()`] method.
|
/// Future for the [`receive()`] method.
|
||||||
impl<'a, T, B> ReceiveFuture<'a, T, B>
|
impl<'a, T> ReceiveFuture<'a, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
/// Stops the ongoing reception and returns the number of bytes received.
|
/// Stops the ongoing reception and returns the number of bytes received.
|
||||||
pub async fn stop(mut self) -> (B, usize) {
|
pub async fn stop(self) -> usize {
|
||||||
let buf = self.buf.take().unwrap();
|
|
||||||
drop(self);
|
drop(self);
|
||||||
let len = T::state().rx_done.wait().await;
|
let len = T::state().rx_done.wait().await;
|
||||||
(buf, len as _)
|
len as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +375,9 @@ mod private {
|
|||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed {
|
pub trait Instance:
|
||||||
|
Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed + 'static
|
||||||
|
{
|
||||||
type Interrupt: OwnedInterrupt;
|
type Interrupt: OwnedInterrupt;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
2
embassy-nrf/src/util/mod.rs
Normal file
2
embassy-nrf/src/util/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod peripheral;
|
||||||
|
pub mod ring_buffer;
|
107
embassy-nrf/src/util/peripheral.rs
Normal file
107
embassy-nrf/src/util/peripheral.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
use core::mem;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use core::ptr;
|
||||||
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
use core::{cell::UnsafeCell, marker::PhantomData};
|
||||||
|
|
||||||
|
use crate::interrupt::OwnedInterrupt;
|
||||||
|
|
||||||
|
pub struct Store<T>(MaybeUninit<UnsafeCell<T>>);
|
||||||
|
impl<T> Store<T> {
|
||||||
|
pub const fn uninit() -> Self {
|
||||||
|
Self(MaybeUninit::uninit())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn as_mut_ptr(&self) -> *mut T {
|
||||||
|
(*self.0.as_ptr()).get()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn as_mut(&self) -> &mut T {
|
||||||
|
&mut *self.as_mut_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write(&self, val: T) {
|
||||||
|
ptr::write(self.as_mut_ptr(), val)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn drop_in_place(&self) {
|
||||||
|
ptr::drop_in_place(self.as_mut_ptr())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn read(&self) -> T {
|
||||||
|
ptr::read(self.as_mut_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl<T> Send for Store<T> {}
|
||||||
|
unsafe impl<T> Sync for Store<T> {}
|
||||||
|
|
||||||
|
pub trait State: Sized {
|
||||||
|
type Interrupt: OwnedInterrupt;
|
||||||
|
fn on_interrupt(&mut self);
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn store<'a>() -> &'a Store<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Registration<P: State> {
|
||||||
|
irq: P::Interrupt,
|
||||||
|
not_send: PhantomData<*mut P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: State> Registration<P> {
|
||||||
|
pub fn new(irq: P::Interrupt, state: P) -> Self {
|
||||||
|
// safety:
|
||||||
|
// - No other PeripheralRegistration can already exist because we have the owned interrupt
|
||||||
|
// - therefore, storage is uninitialized
|
||||||
|
// - therefore it's safe to overwrite it without dropping the previous contents
|
||||||
|
unsafe { P::store().write(state) }
|
||||||
|
|
||||||
|
irq.set_handler(|| {
|
||||||
|
// safety:
|
||||||
|
// - If a PeripheralRegistration instance exists, P::storage() is initialized.
|
||||||
|
// - It's OK to get a &mut to it since the irq is disabled.
|
||||||
|
unsafe { P::store().as_mut() }.on_interrupt();
|
||||||
|
});
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
irq.enable();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
irq,
|
||||||
|
not_send: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with<R>(&mut self, f: impl FnOnce(&mut P, &mut P::Interrupt) -> R) -> R {
|
||||||
|
self.irq.disable();
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
// safety:
|
||||||
|
// - If a PeripheralRegistration instance exists, P::storage() is initialized.
|
||||||
|
// - It's OK to get a &mut to it since the irq is disabled.
|
||||||
|
let r = f(unsafe { P::store().as_mut() }, &mut self.irq);
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
self.irq.enable();
|
||||||
|
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free(self) -> (P::Interrupt, P) {
|
||||||
|
let irq = unsafe { ptr::read(&self.irq) };
|
||||||
|
irq.disable();
|
||||||
|
irq.set_handler(|| ());
|
||||||
|
mem::forget(self);
|
||||||
|
let storage = P::store();
|
||||||
|
(irq, unsafe { storage.read() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: State> Drop for Registration<P> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.irq.disable();
|
||||||
|
self.irq.set_handler(|| ());
|
||||||
|
|
||||||
|
let storage = P::store();
|
||||||
|
unsafe { storage.drop_in_place() };
|
||||||
|
}
|
||||||
|
}
|
80
embassy-nrf/src/util/ring_buffer.rs
Normal file
80
embassy-nrf/src/util/ring_buffer.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use crate::fmt::{assert, panic, todo, *};
|
||||||
|
|
||||||
|
pub struct RingBuffer<'a> {
|
||||||
|
buf: &'a mut [u8],
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
empty: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RingBuffer<'a> {
|
||||||
|
pub fn new(buf: &'a mut [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
buf,
|
||||||
|
start: 0,
|
||||||
|
end: 0,
|
||||||
|
empty: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_buf(&mut self) -> &mut [u8] {
|
||||||
|
if self.start == self.end && !self.empty {
|
||||||
|
trace!(" ringbuf: push_buf empty");
|
||||||
|
return &mut self.buf[..0];
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = if self.start <= self.end {
|
||||||
|
self.buf.len() - self.end
|
||||||
|
} else {
|
||||||
|
self.start - self.end
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
|
||||||
|
&mut self.buf[self.end..self.end + n]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, n: usize) {
|
||||||
|
trace!(" ringbuf: push {:?}", n);
|
||||||
|
if n == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.end = self.wrap(self.end + n);
|
||||||
|
self.empty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_buf(&mut self) -> &mut [u8] {
|
||||||
|
if self.empty {
|
||||||
|
trace!(" ringbuf: pop_buf empty");
|
||||||
|
return &mut self.buf[..0];
|
||||||
|
}
|
||||||
|
|
||||||
|
let n = if self.end <= self.start {
|
||||||
|
self.buf.len() - self.start
|
||||||
|
} else {
|
||||||
|
self.end - self.start
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
|
||||||
|
&mut self.buf[self.start..self.start + n]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self, n: usize) {
|
||||||
|
trace!(" ringbuf: pop {:?}", n);
|
||||||
|
if n == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.start = self.wrap(self.start + n);
|
||||||
|
self.empty = self.start == self.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrap(&self, n: usize) -> usize {
|
||||||
|
assert!(n <= self.buf.len());
|
||||||
|
if n == self.buf.len() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![feature(slice_fill)]
|
|
||||||
#![feature(generic_associated_types)]
|
#![feature(generic_associated_types)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(const_fn_fn_ptr_basics)]
|
#![feature(const_fn_fn_ptr_basics)]
|
||||||
@ -13,4 +12,5 @@ pub mod interrupt;
|
|||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod rand;
|
pub mod rand;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
pub mod uart;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
15
embassy/src/uart.rs
Normal file
15
embassy/src/uart.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use core::future::Future;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Error {
|
||||||
|
Other,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Uart {
|
||||||
|
type ReceiveFuture<'a>: Future<Output = Result<(), Error>>;
|
||||||
|
type SendFuture<'a>: Future<Output = Result<(), Error>>;
|
||||||
|
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>;
|
||||||
|
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
|
||||||
|
}
|
@ -2,10 +2,10 @@ mod drop_bomb;
|
|||||||
mod forever;
|
mod forever;
|
||||||
mod portal;
|
mod portal;
|
||||||
mod signal;
|
mod signal;
|
||||||
mod waker_store;
|
mod waker;
|
||||||
|
|
||||||
pub use drop_bomb::*;
|
pub use drop_bomb::*;
|
||||||
pub use forever::*;
|
pub use forever::*;
|
||||||
pub use portal::*;
|
pub use portal::*;
|
||||||
pub use signal::*;
|
pub use signal::*;
|
||||||
pub use waker_store::*;
|
pub use waker::*;
|
||||||
|
38
embassy/src/util/waker.rs
Normal file
38
embassy/src/util/waker.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use core::task::Context;
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
|
/// Utility struct to register and wake a waker.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WakerRegistration {
|
||||||
|
waker: Option<Waker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WakerRegistration {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { waker: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker. Overwrites the previous waker, if any.
|
||||||
|
pub fn register(&mut self, w: &Waker) {
|
||||||
|
match self.waker {
|
||||||
|
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
||||||
|
// keep the old waker, skipping the clone. (In most executor implementations,
|
||||||
|
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
||||||
|
Some(ref w2) if (w2.will_wake(w)) => {}
|
||||||
|
// In all other cases
|
||||||
|
// - we have no waker registered
|
||||||
|
// - we have a waker registered but it's for a different task.
|
||||||
|
// then clone the new waker and store it
|
||||||
|
_ => self.waker = Some(w.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the registered waker, if any.
|
||||||
|
pub fn wake(&mut self) {
|
||||||
|
self.waker.take().map(|w| w.wake());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn context(&self) -> Option<Context<'_>> {
|
||||||
|
self.waker.as_ref().map(|w| Context::from_waker(w))
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
use core::task::Waker;
|
|
||||||
|
|
||||||
pub struct WakerStore {
|
|
||||||
waker: Option<Waker>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WakerStore {
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self { waker: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store(&mut self, w: &Waker) {
|
|
||||||
match self.waker {
|
|
||||||
Some(ref w2) if (w2.will_wake(w)) => {}
|
|
||||||
Some(_) => panic!("Waker overflow"),
|
|
||||||
None => self.waker = Some(w.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wake(&mut self) {
|
|
||||||
self.waker.take().map(|w| w.wake());
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
|
|
||||||
# examples
|
|
||||||
(cd examples; cargo build --target thumbv7em-none-eabi --bins)
|
|
||||||
|
|
||||||
# embassy std
|
# embassy std
|
||||||
(cd embassy; cargo build --features log,std)
|
(cd embassy; cargo build --features log,std)
|
||||||
|
|
||||||
@ -14,6 +11,9 @@ set -euxo pipefail
|
|||||||
(cd embassy; cargo build --target thumbv7em-none-eabi --features defmt)
|
(cd embassy; cargo build --target thumbv7em-none-eabi --features defmt)
|
||||||
|
|
||||||
# embassy-nrf
|
# embassy-nrf
|
||||||
|
|
||||||
|
(cd embassy-nrf-examples; cargo build --target thumbv7em-none-eabi --bins)
|
||||||
|
|
||||||
(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810)
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810)
|
||||||
#(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet
|
#(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet
|
||||||
(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832)
|
(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832)
|
||||||
|
Loading…
Reference in New Issue
Block a user