aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2021-01-04 12:50:22 -0600
committerGitHub <[email protected]>2021-01-04 12:50:22 -0600
commitbe541b94aaac92049a9283a44e715322a7653fcf (patch)
treebac05880888720cb10ef92a5e27c66483a918034
parent9bf09488f10b65401ec4c830c5b974c19508624f (diff)
parent39ca8b8dedb3db14f9770f09814ccf92481b6136 (diff)
Merge branch 'master' into stm32f4
-rw-r--r--Cargo.toml5
-rw-r--r--README.md16
-rw-r--r--embassy-macros/src/lib.rs11
-rw-r--r--embassy-nrf-examples/.cargo/config (renamed from examples/.cargo/config)6
-rw-r--r--embassy-nrf-examples/Cargo.toml (renamed from examples/Cargo.toml)2
-rw-r--r--embassy-nrf-examples/build.rs (renamed from examples/build.rs)0
-rw-r--r--embassy-nrf-examples/memory.x (renamed from examples/memory.x)0
-rw-r--r--embassy-nrf-examples/src/bin/buffered_uart.rs (renamed from examples/src/bin/buffered_uart.rs)11
-rw-r--r--embassy-nrf-examples/src/bin/executor_fairness_test.rs (renamed from examples/src/bin/executor_fairness_test.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/gpiote.rs (renamed from examples/src/bin/gpiote.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/gpiote_port.rs (renamed from examples/src/bin/gpiote_port.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/multiprio.rs (renamed from examples/src/bin/multiprio.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/qspi.rs (renamed from examples/src/bin/qspi.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/rtc_async.rs (renamed from examples/src/bin/rtc_async.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/rtc_raw.rs (renamed from examples/src/bin/rtc_raw.rs)0
-rw-r--r--embassy-nrf-examples/src/bin/uart.rs (renamed from examples/src/bin/uart.rs)37
-rw-r--r--embassy-nrf-examples/src/example_common.rs (renamed from examples/src/example_common.rs)0
-rw-r--r--embassy-nrf/src/buffered_uarte.rs326
-rw-r--r--embassy-nrf/src/lib.rs1
-rw-r--r--embassy-nrf/src/uarte.rs144
-rw-r--r--embassy-nrf/src/util/mod.rs2
-rw-r--r--embassy-nrf/src/util/peripheral.rs107
-rw-r--r--embassy-nrf/src/util/ring_buffer.rs80
-rw-r--r--embassy/src/lib.rs2
-rw-r--r--embassy/src/uart.rs15
-rw-r--r--embassy/src/util/mod.rs4
-rw-r--r--embassy/src/util/waker.rs38
-rw-r--r--embassy/src/util/waker_store.rs23
-rwxr-xr-xtest-build.sh6
29 files changed, 474 insertions, 362 deletions
diff --git a/Cargo.toml b/Cargo.toml
index be98b26f6..843c5f6c3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,8 +5,9 @@ members = [
5 "embassy-nrf", 5 "embassy-nrf",
6 "embassy-stm32f4", 6 "embassy-stm32f4",
7 "embassy-macros", 7 "embassy-macros",
8 "examples", 8 "embassy-nrf-examples",
9 "examples-stm32f4", 9 "embassy-stm32f4-examples",
10 "embassy-macros",
10] 11]
11 12
12exclude = [ 13exclude = [
diff --git a/README.md b/README.md
index 6f7470cf5..0f1cb1be5 100644
--- a/README.md
+++ b/README.md
@@ -11,15 +11,17 @@ Embassy is a project to make async/await a first-class option for embedded devel
11- `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`. 11- `embassy::time`: `Clock` and `Alarm` traits. Std-like `Duration` and `Instant`.
12- More traits for SPI, I2C, UART async HAL coming soon. 12- More traits for SPI, I2C, UART async HAL coming soon.
13 13
14## Executor with timers 14## Executor
15 15
16The `embassy::executor` module provides an async/await executor based on [static-executor](https://github.com/Dirbaio/static-executor). 16The `embassy::executor` module provides an async/await executor designed for embedded usage.
17 17
18- No `alloc`, no heap needed. Task futures are statically allocated. 18- No `alloc`, no heap needed. Task futures are statically allocated.
19- Integrated timer queue allows simple sleeping: `Timer::after(Duration::from_ticks(64000)).await;`. 19- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
20- 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. 20- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
21- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
22- Efficient polling: a wake will only poll the woken task, not all of them.
23- 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.
21- Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. 24- Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
22- Compatible with RTIC (example coming soon).
23 25
24## Utils 26## Utils
25 27
@@ -54,9 +56,7 @@ cargo run --bin rtc_async
54 56
55## Minimum supported Rust version (MSRV) 57## Minimum supported Rust version (MSRV)
56 58
57`rustc 1.48.0-nightly (1fd5b9d51 2020-09-20)` 59Only recent nighly supported. Nightly is required for:
58
59Any recent nightly should work. Nightly is required for:
60 60
61- `generic_associated_types`: for trait funcs returning futures. 61- `generic_associated_types`: for trait funcs returning futures.
62- `type_alias_impl_trait`: for trait funcs returning futures implemented with `async{}` blocks, and for `static-executor`. 62- `type_alias_impl_trait`: for trait funcs returning futures implemented with `async{}` blocks, and for `static-executor`.
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index c2e2d9e27..c46f114a0 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -55,9 +55,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
55 55
56 let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> = 56 let mut arg_names: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]> =
57 syn::punctuated::Punctuated::new(); 57 syn::punctuated::Punctuated::new();
58 let args = &task_fn.sig.inputs; 58 let mut args = task_fn.sig.inputs.clone();
59 59
60 for arg in args.iter() { 60 for arg in args.iter_mut() {
61 match arg { 61 match arg {
62 syn::FnArg::Receiver(_) => { 62 syn::FnArg::Receiver(_) => {
63 arg.span() 63 arg.span()
@@ -66,8 +66,11 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
66 .emit(); 66 .emit();
67 fail = true; 67 fail = true;
68 } 68 }
69 syn::FnArg::Typed(t) => match t.pat.as_ref() { 69 syn::FnArg::Typed(t) => match t.pat.as_mut() {
70 syn::Pat::Ident(i) => arg_names.push(i.ident.clone()), 70 syn::Pat::Ident(i) => {
71 arg_names.push(i.ident.clone());
72 i.mutability = None;
73 }
71 _ => { 74 _ => {
72 arg.span() 75 arg.span()
73 .unwrap() 76 .unwrap()
diff --git a/examples/.cargo/config b/embassy-nrf-examples/.cargo/config
index 3f319ae55..591288879 100644
--- a/examples/.cargo/config
+++ b/embassy-nrf-examples/.cargo/config
@@ -20,8 +20,4 @@ rustflags = [
20] 20]
21 21
22[build] 22[build]
23# Pick ONE of these compilation targets 23target = "thumbv7em-none-eabi"
24# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
25# target = "thumbv7m-none-eabi" # Cortex-M3
26# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
27target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
diff --git a/examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml
index c845c1bfb..0c812db1d 100644
--- a/examples/Cargo.toml
+++ b/embassy-nrf-examples/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"] 2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018" 3edition = "2018"
4name = "embassy-examples" 4name = "embassy-nrf-examples"
5version = "0.1.0" 5version = "0.1.0"
6 6
7[features] 7[features]
diff --git a/examples/build.rs b/embassy-nrf-examples/build.rs
index d534cc3df..d534cc3df 100644
--- a/examples/build.rs
+++ b/embassy-nrf-examples/build.rs
diff --git a/examples/memory.x b/embassy-nrf-examples/memory.x
index 9b04edec0..9b04edec0 100644
--- a/examples/memory.x
+++ b/embassy-nrf-examples/memory.x
diff --git a/examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs
index 6e15fbcfa..68a76f71e 100644
--- a/examples/src/bin/buffered_uart.rs
+++ b/embassy-nrf-examples/src/bin/buffered_uart.rs
@@ -8,15 +8,17 @@ use example_common::*;
8 8
9use cortex_m_rt::entry; 9use cortex_m_rt::entry;
10use defmt::panic; 10use defmt::panic;
11use futures::pin_mut;
12use nrf52840_hal::gpio; 11use nrf52840_hal::gpio;
13 12
14use embassy::executor::{task, Executor}; 13use embassy::executor::{task, Executor};
15use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; 14use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
16use embassy::util::Forever; 15use embassy::util::Forever;
17use embassy_nrf::buffered_uarte; 16use embassy_nrf::buffered_uarte;
18use embassy_nrf::interrupt; 17use embassy_nrf::interrupt;
19 18
19static mut TX_BUFFER: [u8; 4096] = [0; 4096];
20static mut RX_BUFFER: [u8; 4096] = [0; 4096];
21
20#[task] 22#[task]
21async fn run() { 23async fn run() {
22 let p = unwrap!(embassy_nrf::pac::Peripherals::take()); 24 let p = unwrap!(embassy_nrf::pac::Peripherals::take());
@@ -34,14 +36,15 @@ async fn run() {
34 }; 36 };
35 37
36 let irq = interrupt::take!(UARTE0_UART0); 38 let irq = interrupt::take!(UARTE0_UART0);
37 let u = buffered_uarte::BufferedUarte::new( 39 let mut u = buffered_uarte::BufferedUarte::new(
38 p.UARTE0, 40 p.UARTE0,
39 irq, 41 irq,
42 unsafe { &mut RX_BUFFER },
43 unsafe { &mut TX_BUFFER },
40 pins, 44 pins,
41 buffered_uarte::Parity::EXCLUDED, 45 buffered_uarte::Parity::EXCLUDED,
42 buffered_uarte::Baudrate::BAUD115200, 46 buffered_uarte::Baudrate::BAUD115200,
43 ); 47 );
44 pin_mut!(u);
45 48
46 info!("uarte initialized!"); 49 info!("uarte initialized!");
47 50
diff --git a/examples/src/bin/executor_fairness_test.rs b/embassy-nrf-examples/src/bin/executor_fairness_test.rs
index 9b2c1bd26..9b2c1bd26 100644
--- a/examples/src/bin/executor_fairness_test.rs
+++ b/embassy-nrf-examples/src/bin/executor_fairness_test.rs
diff --git a/examples/src/bin/gpiote.rs b/embassy-nrf-examples/src/bin/gpiote.rs
index afa1b85d5..afa1b85d5 100644
--- a/examples/src/bin/gpiote.rs
+++ b/embassy-nrf-examples/src/bin/gpiote.rs
diff --git a/examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs
index f5aa81322..f5aa81322 100644
--- a/examples/src/bin/gpiote_port.rs
+++ b/embassy-nrf-examples/src/bin/gpiote_port.rs
diff --git a/examples/src/bin/multiprio.rs b/embassy-nrf-examples/src/bin/multiprio.rs
index c821e3dba..c821e3dba 100644
--- a/examples/src/bin/multiprio.rs
+++ b/embassy-nrf-examples/src/bin/multiprio.rs
diff --git a/examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs
index a7d47f79c..a7d47f79c 100644
--- a/examples/src/bin/qspi.rs
+++ b/embassy-nrf-examples/src/bin/qspi.rs
diff --git a/examples/src/bin/rtc_async.rs b/embassy-nrf-examples/src/bin/rtc_async.rs
index dcdeb7049..dcdeb7049 100644
--- a/examples/src/bin/rtc_async.rs
+++ b/embassy-nrf-examples/src/bin/rtc_async.rs
diff --git a/examples/src/bin/rtc_raw.rs b/embassy-nrf-examples/src/bin/rtc_raw.rs
index 438585460..438585460 100644
--- a/examples/src/bin/rtc_raw.rs
+++ b/embassy-nrf-examples/src/bin/rtc_raw.rs
diff --git a/examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs
index 107936686..cb38e8fcb 100644
--- a/examples/src/bin/uart.rs
+++ b/embassy-nrf-examples/src/bin/uart.rs
@@ -10,6 +10,7 @@ use cortex_m_rt::entry;
10use defmt::panic; 10use defmt::panic;
11use embassy::executor::{task, Executor}; 11use embassy::executor::{task, Executor};
12use embassy::time::{Duration, Timer}; 12use embassy::time::{Duration, Timer};
13use embassy::uart::Uart;
13use embassy::util::Forever; 14use embassy::util::Forever;
14use embassy_nrf::{interrupt, pac, rtc, uarte}; 15use embassy_nrf::{interrupt, pac, rtc, uarte};
15use futures::future::{select, Either}; 16use futures::future::{select, Either};
@@ -24,29 +25,37 @@ async fn run(mut uart: uarte::Uarte<pac::UARTE0>) {
24 let mut buf = [0; 8]; 25 let mut buf = [0; 8];
25 buf.copy_from_slice(b"Hello!\r\n"); 26 buf.copy_from_slice(b"Hello!\r\n");
26 27
27 uart.send(&buf).await; 28 unwrap!(uart.send(&buf).await);
28 info!("wrote hello in uart!"); 29 info!("wrote hello in uart!");
29 30
30 info!("reading...");
31 loop { 31 loop {
32 let received = match select( 32 let buf_len = buf.len();
33 uart.receive(&mut buf), 33 info!("reading...");
34 Timer::after(Duration::from_millis(10)), 34
35 ) 35 // `receive()` doesn't return until the buffer has been completely filled with
36 .await 36 // incoming data, which in this case is 8 bytes.
37 { 37 //
38 Either::Left((buf, _)) => buf, 38 // This example shows how to use `select` to run an uart receive concurrently with a
39 Either::Right((_, read)) => { 39 // 1 second timer, effectively adding a timeout to the receive operation.
40 let (buf, n) = read.stop().await; 40 let recv_fut = uart.receive(&mut buf);
41 &buf[..n] 41 let timer_fut = Timer::after(Duration::from_millis(1000));
42 } 42 let received_len = match select(recv_fut, timer_fut).await {
43 // recv_fut completed first, so we've received `buf_len` bytes.
44 Either::Left(_) => buf_len,
45 // timer_fut completed first. `select` gives us back the future that didn't complete, which
46 // is `recv_fut` in this case, so we can do further stuff with it.
47 //
48 // The recv_fut would stop the uart read automatically when dropped. However, we want to know how
49 // many bytes have been received, so we have to "gracefully stop" it with `.stop()`.
50 Either::Right((_, recv_fut)) => recv_fut.stop().await,
43 }; 51 };
52 let received = &mut buf[..received_len];
44 53
45 if received.len() > 0 { 54 if received.len() > 0 {
46 info!("read done, got {:[u8]}", received); 55 info!("read done, got {:[u8]}", received);
47 56
48 // Echo back received data 57 // Echo back received data
49 uart.send(received).await; 58 unwrap!(uart.send(received).await);
50 } 59 }
51 } 60 }
52} 61}
diff --git a/examples/src/example_common.rs b/embassy-nrf-examples/src/example_common.rs
index 60bb02082..60bb02082 100644
--- a/examples/src/example_common.rs
+++ b/embassy-nrf-examples/src/example_common.rs
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index db6a83fb4..c67b6f166 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -4,114 +4,29 @@
4//! 4//!
5//! - nrf52832: Section 35 5//! - nrf52832: Section 35
6//! - nrf52840: Section 6.34 6//! - nrf52840: Section 6.34
7use core::cell::UnsafeCell;
8use core::cmp::min; 7use core::cmp::min;
9use core::marker::PhantomPinned; 8use core::marker::PhantomData;
9use core::mem;
10use core::ops::Deref; 10use core::ops::Deref;
11use core::pin::Pin; 11use core::pin::Pin;
12use core::ptr;
13use core::sync::atomic::{compiler_fence, Ordering}; 12use core::sync::atomic::{compiler_fence, Ordering};
14use core::task::{Context, Poll}; 13use core::task::{Context, Poll};
15 14use embassy::io::{AsyncBufRead, AsyncWrite, Result};
15use embassy::util::WakerRegistration;
16use embedded_hal::digital::v2::OutputPin; 16use embedded_hal::digital::v2::OutputPin;
17 17
18use crate::hal::gpio::{Floating, Input, Output, Pin as GpioPin, Port as GpioPort, PushPull}; 18use crate::fmt::{panic, todo, *};
19use crate::interrupt; 19use crate::hal::gpio::Port as GpioPort;
20use crate::interrupt::{CriticalSection, OwnedInterrupt}; 20use crate::interrupt::{self, OwnedInterrupt};
21#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] 21use crate::pac;
22use crate::pac::UARTE1; 22use crate::pac::uarte0;
23use crate::pac::{uarte0, UARTE0}; 23use crate::util::peripheral;
24use crate::util::ring_buffer::RingBuffer;
24 25
25// Re-export SVD variants to allow user to directly set values 26// Re-export SVD variants to allow user to directly set values
27pub use crate::hal::uarte::Pins;
26pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 28pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
27 29
28use embassy::io::{AsyncBufRead, AsyncWrite, Result};
29use embassy::util::WakerStore;
30
31use crate::fmt::{assert, panic, todo, *};
32
33//use crate::trace;
34
35const RINGBUF_SIZE: usize = 512;
36struct RingBuf {
37 buf: [u8; RINGBUF_SIZE],
38 start: usize,
39 end: usize,
40 empty: bool,
41}
42
43impl RingBuf {
44 fn new() -> Self {
45 RingBuf {
46 buf: [0; RINGBUF_SIZE],
47 start: 0,
48 end: 0,
49 empty: true,
50 }
51 }
52
53 fn push_buf(&mut self) -> &mut [u8] {
54 if self.start == self.end && !self.empty {
55 trace!(" ringbuf: push_buf empty");
56 return &mut self.buf[..0];
57 }
58
59 let n = if self.start <= self.end {
60 RINGBUF_SIZE - self.end
61 } else {
62 self.start - self.end
63 };
64
65 trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
66 &mut self.buf[self.end..self.end + n]
67 }
68
69 fn push(&mut self, n: usize) {
70 trace!(" ringbuf: push {:?}", n);
71 if n == 0 {
72 return;
73 }
74
75 self.end = Self::wrap(self.end + n);
76 self.empty = false;
77 }
78
79 fn pop_buf(&mut self) -> &mut [u8] {
80 if self.empty {
81 trace!(" ringbuf: pop_buf empty");
82 return &mut self.buf[..0];
83 }
84
85 let n = if self.end <= self.start {
86 RINGBUF_SIZE - self.start
87 } else {
88 self.end - self.start
89 };
90
91 trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
92 &mut self.buf[self.start..self.start + n]
93 }
94
95 fn pop(&mut self, n: usize) {
96 trace!(" ringbuf: pop {:?}", n);
97 if n == 0 {
98 return;
99 }
100
101 self.start = Self::wrap(self.start + n);
102 self.empty = self.start == self.end;
103 }
104
105 fn wrap(n: usize) -> usize {
106 assert!(n <= RINGBUF_SIZE);
107 if n == RINGBUF_SIZE {
108 0
109 } else {
110 n
111 }
112 }
113}
114
115#[derive(Copy, Clone, Debug, PartialEq)] 30#[derive(Copy, Clone, Debug, PartialEq)]
116enum RxState { 31enum RxState {
117 Idle, 32 Idle,
@@ -133,28 +48,12 @@ enum TxState {
133/// are disabled before using `Uarte`. See product specification: 48/// are disabled before using `Uarte`. See product specification:
134/// - nrf52832: Section 15.2 49/// - nrf52832: Section 15.2
135/// - nrf52840: Section 6.1.2 50/// - nrf52840: Section 6.1.2
136pub struct BufferedUarte<T: Instance> { 51pub struct BufferedUarte<'a, T: Instance> {
137 started: bool, 52 reg: peripheral::Registration<State<'a, T>>,
138 state: UnsafeCell<UarteState<T>>, 53 wtf: PhantomData<&'a ()>,
139} 54}
140 55
141// public because it needs to be used in Instance::{get_state, set_state}, but 56impl<'a, T: Instance> Unpin for BufferedUarte<'a, T> {}
142// should not be used outside the module
143#[doc(hidden)]
144pub struct UarteState<T: Instance> {
145 inner: T,
146 irq: T::Interrupt,
147
148 rx: RingBuf,
149 rx_state: RxState,
150 rx_waker: WakerStore,
151
152 tx: RingBuf,
153 tx_state: TxState,
154 tx_waker: WakerStore,
155
156 _pin: PhantomPinned,
157}
158 57
159#[cfg(any(feature = "52833", feature = "52840"))] 58#[cfg(any(feature = "52833", feature = "52840"))]
160fn port_bit(port: GpioPort) -> bool { 59fn port_bit(port: GpioPort) -> bool {
@@ -164,10 +63,12 @@ fn port_bit(port: GpioPort) -> bool {
164 } 63 }
165} 64}
166 65
167impl<T: Instance> BufferedUarte<T> { 66impl<'a, T: Instance> BufferedUarte<'a, T> {
168 pub fn new( 67 pub fn new(
169 uarte: T, 68 uarte: T,
170 irq: T::Interrupt, 69 irq: T::Interrupt,
70 rx_buffer: &'a mut [u8],
71 tx_buffer: &'a mut [u8],
171 mut pins: Pins, 72 mut pins: Pins,
172 parity: Parity, 73 parity: Parity,
173 baudrate: Baudrate, 74 baudrate: Baudrate,
@@ -225,87 +126,79 @@ impl<T: Instance> BufferedUarte<T> {
225 // Configure frequency 126 // Configure frequency
226 uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); 127 uarte.baudrate.write(|w| w.baudrate().variant(baudrate));
227 128
129 irq.pend();
130
228 BufferedUarte { 131 BufferedUarte {
229 started: false, 132 reg: peripheral::Registration::new(
230 state: UnsafeCell::new(UarteState {
231 inner: uarte,
232 irq, 133 irq,
233 134 State {
234 rx: RingBuf::new(), 135 inner: uarte,
235 rx_state: RxState::Idle, 136
236 rx_waker: WakerStore::new(), 137 rx: RingBuffer::new(rx_buffer),
237 138 rx_state: RxState::Idle,
238 tx: RingBuf::new(), 139 rx_waker: WakerRegistration::new(),
239 tx_state: TxState::Idle, 140
240 tx_waker: WakerStore::new(), 141 tx: RingBuffer::new(tx_buffer),
241 142 tx_state: TxState::Idle,
242 _pin: PhantomPinned, 143 tx_waker: WakerRegistration::new(),
243 }), 144 },
145 ),
146 wtf: PhantomData,
244 } 147 }
245 } 148 }
246
247 fn with_state<'a, R>(
248 self: Pin<&'a mut Self>,
249 f: impl FnOnce(Pin<&'a mut UarteState<T>>) -> R,
250 ) -> R {
251 let Self { state, started } = unsafe { self.get_unchecked_mut() };
252
253 interrupt::free(|cs| {
254 let ptr = state.get();
255
256 if !*started {
257 T::set_state(cs, ptr);
258
259 *started = true;
260
261 // safety: safe because critical section ensures only one *mut UartState
262 // exists at the same time.
263 unsafe { Pin::new_unchecked(&mut *ptr) }.start();
264 }
265
266 // safety: safe because critical section ensures only one *mut UartState
267 // exists at the same time.
268 f(unsafe { Pin::new_unchecked(&mut *ptr) })
269 })
270 }
271} 149}
272 150
273impl<T: Instance> Drop for BufferedUarte<T> { 151impl<'a, T: Instance> Drop for BufferedUarte<'a, T> {
274 fn drop(&mut self) { 152 fn drop(&mut self) {
275 // stop DMA before dropping, because DMA is using the buffer in `self`. 153 // stop DMA before dropping, because DMA is using the buffer in `self`.
276 todo!() 154 todo!()
277 } 155 }
278} 156}
279 157
280impl<T: Instance> AsyncBufRead for BufferedUarte<T> { 158impl<'a, T: Instance> AsyncBufRead for BufferedUarte<'a, T> {
281 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { 159 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
282 self.with_state(|s| s.poll_fill_buf(cx)) 160 let this = unsafe { self.get_unchecked_mut() };
161 this.reg.with(|state, _| {
162 let z: Poll<Result<&[u8]>> = state.poll_fill_buf(cx);
163 let z: Poll<Result<&[u8]>> = unsafe { mem::transmute(z) };
164 z
165 })
283 } 166 }
284 167
285 fn consume(self: Pin<&mut Self>, amt: usize) { 168 fn consume(self: Pin<&mut Self>, amt: usize) {
286 self.with_state(|s| s.consume(amt)) 169 let this = unsafe { self.get_unchecked_mut() };
170 this.reg.with(|state, irq| state.consume(irq, amt))
287 } 171 }
288} 172}
289 173
290impl<T: Instance> AsyncWrite for BufferedUarte<T> { 174impl<'a, T: Instance> AsyncWrite for BufferedUarte<'a, T> {
291 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { 175 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
292 self.with_state(|s| s.poll_write(cx, buf)) 176 let this = unsafe { self.get_unchecked_mut() };
177 this.reg.with(|state, irq| state.poll_write(irq, cx, buf))
293 } 178 }
294} 179}
295 180
296impl<T: Instance> UarteState<T> { 181// ====================================
297 pub fn start(self: Pin<&mut Self>) { 182// ====================================
298 self.irq.set_handler(|| unsafe { 183// ====================================
299 interrupt::free(|cs| T::get_state(cs).as_mut().unwrap().on_interrupt());
300 });
301 184
302 self.irq.pend(); 185// public because it needs to be used in Instance trait, but
303 self.irq.enable(); 186// should not be used outside the module
304 } 187#[doc(hidden)]
188pub struct State<'a, T: Instance> {
189 inner: T,
305 190
306 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { 191 rx: RingBuffer<'a>,
307 let this = unsafe { self.get_unchecked_mut() }; 192 rx_state: RxState,
193 rx_waker: WakerRegistration,
194
195 tx: RingBuffer<'a>,
196 tx_state: TxState,
197 tx_waker: WakerRegistration,
198}
308 199
200impl<'a, T: Instance> State<'a, T> {
201 fn poll_fill_buf(&mut self, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
309 // Conservative compiler fence to prevent optimizations that do not 202 // Conservative compiler fence to prevent optimizations that do not
310 // take in to account actions by DMA. The fence has been placed here, 203 // take in to account actions by DMA. The fence has been placed here,
311 // before any DMA action has started 204 // before any DMA action has started
@@ -313,7 +206,7 @@ impl<T: Instance> UarteState<T> {
313 trace!("poll_read"); 206 trace!("poll_read");
314 207
315 // We have data ready in buffer? Return it. 208 // We have data ready in buffer? Return it.
316 let buf = this.rx.pop_buf(); 209 let buf = self.rx.pop_buf();
317 if buf.len() != 0 { 210 if buf.len() != 0 {
318 trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); 211 trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len());
319 return Poll::Ready(Ok(buf)); 212 return Poll::Ready(Ok(buf));
@@ -321,38 +214,40 @@ impl<T: Instance> UarteState<T> {
321 214
322 trace!(" empty"); 215 trace!(" empty");
323 216
324 if this.rx_state == RxState::ReceivingReady { 217 if self.rx_state == RxState::ReceivingReady {
325 trace!(" stopping"); 218 trace!(" stopping");
326 this.rx_state = RxState::Stopping; 219 self.rx_state = RxState::Stopping;
327 this.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); 220 self.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) });
328 } 221 }
329 222
330 this.rx_waker.store(cx.waker()); 223 self.rx_waker.register(cx.waker());
331 Poll::Pending 224 Poll::Pending
332 } 225 }
333 226
334 fn consume(self: Pin<&mut Self>, amt: usize) { 227 fn consume(&mut self, irq: &mut T::Interrupt, amt: usize) {
335 let this = unsafe { self.get_unchecked_mut() };
336 trace!("consume {:?}", amt); 228 trace!("consume {:?}", amt);
337 this.rx.pop(amt); 229 self.rx.pop(amt);
338 this.irq.pend(); 230 irq.pend();
339 } 231 }
340 232
341 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { 233 fn poll_write(
342 let this = unsafe { self.get_unchecked_mut() }; 234 &mut self,
343 235 irq: &mut T::Interrupt,
236 cx: &mut Context<'_>,
237 buf: &[u8],
238 ) -> Poll<Result<usize>> {
344 trace!("poll_write: {:?}", buf.len()); 239 trace!("poll_write: {:?}", buf.len());
345 240
346 let tx_buf = this.tx.push_buf(); 241 let tx_buf = self.tx.push_buf();
347 if tx_buf.len() == 0 { 242 if tx_buf.len() == 0 {
348 trace!("poll_write: pending"); 243 trace!("poll_write: pending");
349 this.tx_waker.store(cx.waker()); 244 self.tx_waker.register(cx.waker());
350 return Poll::Pending; 245 return Poll::Pending;
351 } 246 }
352 247
353 let n = min(tx_buf.len(), buf.len()); 248 let n = min(tx_buf.len(), buf.len());
354 tx_buf[..n].copy_from_slice(&buf[..n]); 249 tx_buf[..n].copy_from_slice(&buf[..n]);
355 this.tx.push(n); 250 self.tx.push(n);
356 251
357 trace!("poll_write: queued {:?}", n); 252 trace!("poll_write: queued {:?}", n);
358 253
@@ -361,10 +256,17 @@ impl<T: Instance> UarteState<T> {
361 // before any DMA action has started 256 // before any DMA action has started
362 compiler_fence(Ordering::SeqCst); 257 compiler_fence(Ordering::SeqCst);
363 258
364 this.irq.pend(); 259 irq.pend();
365 260
366 Poll::Ready(Ok(n)) 261 Poll::Ready(Ok(n))
367 } 262 }
263}
264
265impl<'a, T: Instance> peripheral::State for State<'a, T> {
266 type Interrupt = T::Interrupt;
267 fn store<'b>() -> &'b peripheral::Store<Self> {
268 unsafe { mem::transmute(T::storage()) }
269 }
368 270
369 fn on_interrupt(&mut self) { 271 fn on_interrupt(&mut self) {
370 trace!("irq: start"); 272 trace!("irq: start");
@@ -504,13 +406,6 @@ impl<T: Instance> UarteState<T> {
504 } 406 }
505} 407}
506 408
507pub struct Pins {
508 pub rxd: GpioPin<Input<Floating>>,
509 pub txd: GpioPin<Output<PushPull>>,
510 pub cts: Option<GpioPin<Input<Floating>>>,
511 pub rts: Option<GpioPin<Output<PushPull>>>,
512}
513
514mod private { 409mod private {
515 pub trait Sealed {} 410 pub trait Sealed {}
516 411
@@ -519,39 +414,28 @@ mod private {
519 impl Sealed for crate::pac::UARTE1 {} 414 impl Sealed for crate::pac::UARTE1 {}
520} 415}
521 416
522pub trait Instance: Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed { 417pub trait Instance:
418 Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed + 'static
419{
523 type Interrupt: OwnedInterrupt; 420 type Interrupt: OwnedInterrupt;
524 421 fn storage() -> &'static peripheral::Store<State<'static, Self>>;
525 #[doc(hidden)]
526 fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self>;
527
528 #[doc(hidden)]
529 fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>);
530} 422}
531 423
532static mut UARTE0_STATE: *mut UarteState<UARTE0> = ptr::null_mut(); 424impl Instance for pac::UARTE0 {
533#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
534static mut UARTE1_STATE: *mut UarteState<UARTE1> = ptr::null_mut();
535
536impl Instance for UARTE0 {
537 type Interrupt = interrupt::UARTE0_UART0Interrupt; 425 type Interrupt = interrupt::UARTE0_UART0Interrupt;
538 426 fn storage() -> &'static peripheral::Store<State<'static, Self>> {
539 fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> { 427 static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE0>> =
540 unsafe { UARTE0_STATE } // Safe because of CriticalSection 428 peripheral::Store::uninit();
541 } 429 &STORAGE
542 fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) {
543 unsafe { UARTE0_STATE = state } // Safe because of CriticalSection
544 } 430 }
545} 431}
546 432
547#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] 433#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
548impl Instance for UARTE1 { 434impl Instance for pac::UARTE1 {
549 type Interrupt = interrupt::UARTE1Interrupt; 435 type Interrupt = interrupt::UARTE1Interrupt;
550 436 fn storage() -> &'static peripheral::Store<State<'static, Self>> {
551 fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> { 437 static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE1>> =
552 unsafe { UARTE1_STATE } // Safe because of CriticalSection 438 peripheral::Store::uninit();
553 } 439 &STORAGE
554 fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) {
555 unsafe { UARTE1_STATE = state } // Safe because of CriticalSection
556 } 440 }
557} 441}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index e97002a20..ac2371766 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -50,6 +50,7 @@ pub use nrf52840_hal as hal;
50 50
51// This mod MUST go first, so that the others see its macros. 51// This mod MUST go first, so that the others see its macros.
52pub(crate) mod fmt; 52pub(crate) mod fmt;
53pub(crate) mod util;
53 54
54pub mod buffered_uarte; 55pub mod buffered_uarte;
55pub mod gpiote; 56pub mod gpiote;
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index f0337be8b..648298b84 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -10,7 +10,6 @@ use core::sync::atomic::{compiler_fence, Ordering};
10use core::task::{Context, Poll}; 10use core::task::{Context, Poll};
11 11
12use embassy::util::Signal; 12use embassy::util::Signal;
13use embedded_dma::{ReadBuffer, WriteBuffer};
14 13
15use crate::fmt::{assert, *}; 14use crate::fmt::{assert, *};
16#[cfg(any(feature = "52833", feature = "52840"))] 15#[cfg(any(feature = "52833", feature = "52840"))]
@@ -140,57 +139,10 @@ where
140 self.instance.enable.write(|w| w.enable().enabled()); 139 self.instance.enable.write(|w| w.enable().enabled());
141 } 140 }
142 141
143 /// Sends serial data.
144 ///
145 /// `tx_buffer` is marked as static as per `embedded-dma` requirements.
146 /// It it safe to use a buffer with a non static lifetime if memory is not
147 /// reused until the future has finished.
148 pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> SendFuture<'a, T, B>
149 where
150 B: ReadBuffer<Word = u8>,
151 {
152 // Panic if TX is running which can happen if the user has called
153 // `mem::forget()` on a previous future after polling it once.
154 assert!(!self.tx_started());
155
156 self.enable();
157
158 SendFuture {
159 uarte: self,
160 buf: tx_buffer,
161 }
162 }
163
164 fn tx_started(&self) -> bool { 142 fn tx_started(&self) -> bool {
165 self.instance.events_txstarted.read().bits() != 0 143 self.instance.events_txstarted.read().bits() != 0
166 } 144 }
167 145
168 /// Receives serial data.
169 ///
170 /// The future is pending until the buffer is completely filled.
171 /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
172 /// unfinished transfers after a timeout to prevent lockup when no more data
173 /// is incoming.
174 ///
175 /// `rx_buffer` is marked as static as per `embedded-dma` requirements.
176 /// It it safe to use a buffer with a non static lifetime if memory is not
177 /// reused until the future has finished.
178 pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> ReceiveFuture<'a, T, B>
179 where
180 B: WriteBuffer<Word = u8>,
181 {
182 // Panic if RX is running which can happen if the user has called
183 // `mem::forget()` on a previous future after polling it once.
184 assert!(!self.rx_started());
185
186 self.enable();
187
188 ReceiveFuture {
189 uarte: self,
190 buf: Some(rx_buffer),
191 }
192 }
193
194 fn rx_started(&self) -> bool { 146 fn rx_started(&self) -> bool {
195 self.instance.events_rxstarted.read().bits() != 0 147 self.instance.events_rxstarted.read().bits() != 0
196 } 148 }
@@ -238,16 +190,62 @@ where
238 } 190 }
239} 191}
240 192
193impl<T: Instance> embassy::uart::Uart for Uarte<T> {
194 type ReceiveFuture<'a> = ReceiveFuture<'a, T>;
195 type SendFuture<'a> = SendFuture<'a, T>;
196
197 /// Sends serial data.
198 ///
199 /// `tx_buffer` is marked as static as per `embedded-dma` requirements.
200 /// It it safe to use a buffer with a non static lifetime if memory is not
201 /// reused until the future has finished.
202 fn send<'a>(&'a mut self, tx_buffer: &'a [u8]) -> SendFuture<'a, T> {
203 // Panic if TX is running which can happen if the user has called
204 // `mem::forget()` on a previous future after polling it once.
205 assert!(!self.tx_started());
206
207 self.enable();
208
209 SendFuture {
210 uarte: self,
211 buf: tx_buffer,
212 }
213 }
214
215 /// Receives serial data.
216 ///
217 /// The future is pending until the buffer is completely filled.
218 /// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
219 /// unfinished transfers after a timeout to prevent lockup when no more data
220 /// is incoming.
221 ///
222 /// `rx_buffer` is marked as static as per `embedded-dma` requirements.
223 /// It it safe to use a buffer with a non static lifetime if memory is not
224 /// reused until the future has finished.
225 fn receive<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> ReceiveFuture<'a, T> {
226 // Panic if RX is running which can happen if the user has called
227 // `mem::forget()` on a previous future after polling it once.
228 assert!(!self.rx_started());
229
230 self.enable();
231
232 ReceiveFuture {
233 uarte: self,
234 buf: rx_buffer,
235 }
236 }
237}
238
241/// Future for the [`Uarte::send()`] method. 239/// Future for the [`Uarte::send()`] method.
242pub struct SendFuture<'a, T, B> 240pub struct SendFuture<'a, T>
243where 241where
244 T: Instance, 242 T: Instance,
245{ 243{
246 uarte: &'a Uarte<T>, 244 uarte: &'a Uarte<T>,
247 buf: B, 245 buf: &'a [u8],
248} 246}
249 247
250impl<'a, T, B> Drop for SendFuture<'a, T, B> 248impl<'a, T> Drop for SendFuture<'a, T>
251where 249where
252 T: Instance, 250 T: Instance,
253{ 251{
@@ -266,14 +264,13 @@ where
266 } 264 }
267} 265}
268 266
269impl<'a, T, B> Future for SendFuture<'a, T, B> 267impl<'a, T> Future for SendFuture<'a, T>
270where 268where
271 T: Instance, 269 T: Instance,
272 B: ReadBuffer<Word = u8>,
273{ 270{
274 type Output = (); 271 type Output = Result<(), embassy::uart::Error>;
275 272
276 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { 273 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
277 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; 274 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
278 275
279 if !uarte.tx_started() { 276 if !uarte.tx_started() {
@@ -281,7 +278,8 @@ where
281 278
282 T::state().tx_done.reset(); 279 T::state().tx_done.reset();
283 280
284 let (ptr, len) = unsafe { buf.read_buffer() }; 281 let ptr = buf.as_ptr();
282 let len = buf.len();
285 assert!(len <= EASY_DMA_SIZE); 283 assert!(len <= EASY_DMA_SIZE);
286 // TODO: panic if buffer is not in SRAM 284 // TODO: panic if buffer is not in SRAM
287 285
@@ -296,20 +294,20 @@ where
296 uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); 294 uarte.tasks_starttx.write(|w| unsafe { w.bits(1) });
297 } 295 }
298 296
299 T::state().tx_done.poll_wait(cx) 297 T::state().tx_done.poll_wait(cx).map(|()| Ok(()))
300 } 298 }
301} 299}
302 300
303/// Future for the [`Uarte::receive()`] method. 301/// Future for the [`Uarte::receive()`] method.
304pub struct ReceiveFuture<'a, T, B> 302pub struct ReceiveFuture<'a, T>
305where 303where
306 T: Instance, 304 T: Instance,
307{ 305{
308 uarte: &'a Uarte<T>, 306 uarte: &'a Uarte<T>,
309 buf: Option<B>, 307 buf: &'a mut [u8],
310} 308}
311 309
312impl<'a, T, B> Drop for ReceiveFuture<'a, T, B> 310impl<'a, T> Drop for ReceiveFuture<'a, T>
313where 311where
314 T: Instance, 312 T: Instance,
315{ 313{
@@ -327,14 +325,13 @@ where
327 } 325 }
328} 326}
329 327
330impl<'a, T, B> Future for ReceiveFuture<'a, T, B> 328impl<'a, T> Future for ReceiveFuture<'a, T>
331where 329where
332 T: Instance, 330 T: Instance,
333 B: WriteBuffer<Word = u8>,
334{ 331{
335 type Output = B; 332 type Output = Result<(), embassy::uart::Error>;
336 333
337 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B> { 334 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
338 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; 335 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
339 336
340 if !uarte.rx_started() { 337 if !uarte.rx_started() {
@@ -342,7 +339,8 @@ where
342 339
343 T::state().rx_done.reset(); 340 T::state().rx_done.reset();
344 341
345 let (ptr, len) = unsafe { buf.as_mut().unwrap().write_buffer() }; 342 let ptr = buf.as_ptr();
343 let len = buf.len();
346 assert!(len <= EASY_DMA_SIZE); 344 assert!(len <= EASY_DMA_SIZE);
347 345
348 compiler_fence(Ordering::SeqCst); 346 compiler_fence(Ordering::SeqCst);
@@ -356,24 +354,20 @@ where
356 uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); 354 uarte.tasks_startrx.write(|w| unsafe { w.bits(1) });
357 } 355 }
358 356
359 T::state() 357 T::state().rx_done.poll_wait(cx).map(|_| Ok(()))
360 .rx_done
361 .poll_wait(cx)
362 .map(|_| buf.take().unwrap())
363 } 358 }
364} 359}
365 360
366/// Future for the [`receive()`] method. 361/// Future for the [`receive()`] method.
367impl<'a, T, B> ReceiveFuture<'a, T, B> 362impl<'a, T> ReceiveFuture<'a, T>
368where 363where
369 T: Instance, 364 T: Instance,
370{ 365{
371 /// Stops the ongoing reception and returns the number of bytes received. 366 /// Stops the ongoing reception and returns the number of bytes received.
372 pub async fn stop(mut self) -> (B, usize) { 367 pub async fn stop(self) -> usize {
373 let buf = self.buf.take().unwrap();
374 drop(self); 368 drop(self);
375 let len = T::state().rx_done.wait().await; 369 let len = T::state().rx_done.wait().await;
376 (buf, len as _) 370 len as _
377 } 371 }
378} 372}
379 373
@@ -381,7 +375,9 @@ mod private {
381 pub trait Sealed {} 375 pub trait Sealed {}
382} 376}
383 377
384pub trait Instance: Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed { 378pub trait Instance:
379 Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed + 'static
380{
385 type Interrupt: OwnedInterrupt; 381 type Interrupt: OwnedInterrupt;
386 382
387 #[doc(hidden)] 383 #[doc(hidden)]
diff --git a/embassy-nrf/src/util/mod.rs b/embassy-nrf/src/util/mod.rs
new file mode 100644
index 000000000..2fd5453d3
--- /dev/null
+++ b/embassy-nrf/src/util/mod.rs
@@ -0,0 +1,2 @@
1pub mod peripheral;
2pub mod ring_buffer;
diff --git a/embassy-nrf/src/util/peripheral.rs b/embassy-nrf/src/util/peripheral.rs
new file mode 100644
index 000000000..85de3419e
--- /dev/null
+++ b/embassy-nrf/src/util/peripheral.rs
@@ -0,0 +1,107 @@
1use core::mem;
2use core::mem::MaybeUninit;
3use core::ptr;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::{cell::UnsafeCell, marker::PhantomData};
6
7use crate::interrupt::OwnedInterrupt;
8
9pub struct Store<T>(MaybeUninit<UnsafeCell<T>>);
10impl<T> Store<T> {
11 pub const fn uninit() -> Self {
12 Self(MaybeUninit::uninit())
13 }
14
15 unsafe fn as_mut_ptr(&self) -> *mut T {
16 (*self.0.as_ptr()).get()
17 }
18
19 unsafe fn as_mut(&self) -> &mut T {
20 &mut *self.as_mut_ptr()
21 }
22
23 unsafe fn write(&self, val: T) {
24 ptr::write(self.as_mut_ptr(), val)
25 }
26
27 unsafe fn drop_in_place(&self) {
28 ptr::drop_in_place(self.as_mut_ptr())
29 }
30
31 unsafe fn read(&self) -> T {
32 ptr::read(self.as_mut_ptr())
33 }
34}
35unsafe impl<T> Send for Store<T> {}
36unsafe impl<T> Sync for Store<T> {}
37
38pub trait State: Sized {
39 type Interrupt: OwnedInterrupt;
40 fn on_interrupt(&mut self);
41 #[doc(hidden)]
42 fn store<'a>() -> &'a Store<Self>;
43}
44
45pub struct Registration<P: State> {
46 irq: P::Interrupt,
47 not_send: PhantomData<*mut P>,
48}
49
50impl<P: State> Registration<P> {
51 pub fn new(irq: P::Interrupt, state: P) -> Self {
52 // safety:
53 // - No other PeripheralRegistration can already exist because we have the owned interrupt
54 // - therefore, storage is uninitialized
55 // - therefore it's safe to overwrite it without dropping the previous contents
56 unsafe { P::store().write(state) }
57
58 irq.set_handler(|| {
59 // safety:
60 // - If a PeripheralRegistration instance exists, P::storage() is initialized.
61 // - It's OK to get a &mut to it since the irq is disabled.
62 unsafe { P::store().as_mut() }.on_interrupt();
63 });
64
65 compiler_fence(Ordering::SeqCst);
66 irq.enable();
67
68 Self {
69 irq,
70 not_send: PhantomData,
71 }
72 }
73
74 pub fn with<R>(&mut self, f: impl FnOnce(&mut P, &mut P::Interrupt) -> R) -> R {
75 self.irq.disable();
76 compiler_fence(Ordering::SeqCst);
77
78 // safety:
79 // - If a PeripheralRegistration instance exists, P::storage() is initialized.
80 // - It's OK to get a &mut to it since the irq is disabled.
81 let r = f(unsafe { P::store().as_mut() }, &mut self.irq);
82
83 compiler_fence(Ordering::SeqCst);
84 self.irq.enable();
85
86 r
87 }
88
89 pub fn free(self) -> (P::Interrupt, P) {
90 let irq = unsafe { ptr::read(&self.irq) };
91 irq.disable();
92 irq.set_handler(|| ());
93 mem::forget(self);
94 let storage = P::store();
95 (irq, unsafe { storage.read() })
96 }
97}
98
99impl<P: State> Drop for Registration<P> {
100 fn drop(&mut self) {
101 self.irq.disable();
102 self.irq.set_handler(|| ());
103
104 let storage = P::store();
105 unsafe { storage.drop_in_place() };
106 }
107}
diff --git a/embassy-nrf/src/util/ring_buffer.rs b/embassy-nrf/src/util/ring_buffer.rs
new file mode 100644
index 000000000..f395785a5
--- /dev/null
+++ b/embassy-nrf/src/util/ring_buffer.rs
@@ -0,0 +1,80 @@
1use crate::fmt::{assert, panic, todo, *};
2
3pub struct RingBuffer<'a> {
4 buf: &'a mut [u8],
5 start: usize,
6 end: usize,
7 empty: bool,
8}
9
10impl<'a> RingBuffer<'a> {
11 pub fn new(buf: &'a mut [u8]) -> Self {
12 Self {
13 buf,
14 start: 0,
15 end: 0,
16 empty: true,
17 }
18 }
19
20 pub fn push_buf(&mut self) -> &mut [u8] {
21 if self.start == self.end && !self.empty {
22 trace!(" ringbuf: push_buf empty");
23 return &mut self.buf[..0];
24 }
25
26 let n = if self.start <= self.end {
27 self.buf.len() - self.end
28 } else {
29 self.start - self.end
30 };
31
32 trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
33 &mut self.buf[self.end..self.end + n]
34 }
35
36 pub fn push(&mut self, n: usize) {
37 trace!(" ringbuf: push {:?}", n);
38 if n == 0 {
39 return;
40 }
41
42 self.end = self.wrap(self.end + n);
43 self.empty = false;
44 }
45
46 pub fn pop_buf(&mut self) -> &mut [u8] {
47 if self.empty {
48 trace!(" ringbuf: pop_buf empty");
49 return &mut self.buf[..0];
50 }
51
52 let n = if self.end <= self.start {
53 self.buf.len() - self.start
54 } else {
55 self.end - self.start
56 };
57
58 trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
59 &mut self.buf[self.start..self.start + n]
60 }
61
62 pub fn pop(&mut self, n: usize) {
63 trace!(" ringbuf: pop {:?}", n);
64 if n == 0 {
65 return;
66 }
67
68 self.start = self.wrap(self.start + n);
69 self.empty = self.start == self.end;
70 }
71
72 fn wrap(&self, n: usize) -> usize {
73 assert!(n <= self.buf.len());
74 if n == self.buf.len() {
75 0
76 } else {
77 n
78 }
79 }
80}
diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs
index bc06ebd13..02d72a84f 100644
--- a/embassy/src/lib.rs
+++ b/embassy/src/lib.rs
@@ -1,5 +1,4 @@
1#![cfg_attr(not(feature = "std"), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![feature(slice_fill)]
3#![feature(generic_associated_types)] 2#![feature(generic_associated_types)]
4#![feature(const_fn)] 3#![feature(const_fn)]
5#![feature(const_fn_fn_ptr_basics)] 4#![feature(const_fn_fn_ptr_basics)]
@@ -13,4 +12,5 @@ pub mod interrupt;
13pub mod io; 12pub mod io;
14pub mod rand; 13pub mod rand;
15pub mod time; 14pub mod time;
15pub mod uart;
16pub mod util; 16pub mod util;
diff --git a/embassy/src/uart.rs b/embassy/src/uart.rs
new file mode 100644
index 000000000..b40b9e9bd
--- /dev/null
+++ b/embassy/src/uart.rs
@@ -0,0 +1,15 @@
1use core::future::Future;
2
3#[derive(Copy, Clone, Debug, Eq, PartialEq)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5#[non_exhaustive]
6pub enum Error {
7 Other,
8}
9
10pub trait Uart {
11 type ReceiveFuture<'a>: Future<Output = Result<(), Error>>;
12 type SendFuture<'a>: Future<Output = Result<(), Error>>;
13 fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a>;
14 fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a>;
15}
diff --git a/embassy/src/util/mod.rs b/embassy/src/util/mod.rs
index 94745b834..5694d6bfb 100644
--- a/embassy/src/util/mod.rs
+++ b/embassy/src/util/mod.rs
@@ -2,10 +2,10 @@ mod drop_bomb;
2mod forever; 2mod forever;
3mod portal; 3mod portal;
4mod signal; 4mod signal;
5mod waker_store; 5mod waker;
6 6
7pub use drop_bomb::*; 7pub use drop_bomb::*;
8pub use forever::*; 8pub use forever::*;
9pub use portal::*; 9pub use portal::*;
10pub use signal::*; 10pub use signal::*;
11pub use waker_store::*; 11pub use waker::*;
diff --git a/embassy/src/util/waker.rs b/embassy/src/util/waker.rs
new file mode 100644
index 000000000..9735438b5
--- /dev/null
+++ b/embassy/src/util/waker.rs
@@ -0,0 +1,38 @@
1use core::task::Context;
2use core::task::Waker;
3
4/// Utility struct to register and wake a waker.
5#[derive(Debug)]
6pub struct WakerRegistration {
7 waker: Option<Waker>,
8}
9
10impl WakerRegistration {
11 pub const fn new() -> Self {
12 Self { waker: None }
13 }
14
15 /// Register a waker. Overwrites the previous waker, if any.
16 pub fn register(&mut self, w: &Waker) {
17 match self.waker {
18 // Optimization: If both the old and new Wakers wake the same task, we can simply
19 // keep the old waker, skipping the clone. (In most executor implementations,
20 // cloning a waker is somewhat expensive, comparable to cloning an Arc).
21 Some(ref w2) if (w2.will_wake(w)) => {}
22 // In all other cases
23 // - we have no waker registered
24 // - we have a waker registered but it's for a different task.
25 // then clone the new waker and store it
26 _ => self.waker = Some(w.clone()),
27 }
28 }
29
30 /// Wake the registered waker, if any.
31 pub fn wake(&mut self) {
32 self.waker.take().map(|w| w.wake());
33 }
34
35 pub fn context(&self) -> Option<Context<'_>> {
36 self.waker.as_ref().map(|w| Context::from_waker(w))
37 }
38} \ No newline at end of file
diff --git a/embassy/src/util/waker_store.rs b/embassy/src/util/waker_store.rs
deleted file mode 100644
index 0b2f09f4b..000000000
--- a/embassy/src/util/waker_store.rs
+++ /dev/null
@@ -1,23 +0,0 @@
1use core::task::Waker;
2
3pub struct WakerStore {
4 waker: Option<Waker>,
5}
6
7impl WakerStore {
8 pub const fn new() -> Self {
9 Self { waker: None }
10 }
11
12 pub fn store(&mut self, w: &Waker) {
13 match self.waker {
14 Some(ref w2) if (w2.will_wake(w)) => {}
15 Some(_) => panic!("Waker overflow"),
16 None => self.waker = Some(w.clone()),
17 }
18 }
19
20 pub fn wake(&mut self) {
21 self.waker.take().map(|w| w.wake());
22 }
23}
diff --git a/test-build.sh b/test-build.sh
index 52bf7bb7b..f67cc5b2b 100755
--- a/test-build.sh
+++ b/test-build.sh
@@ -2,9 +2,6 @@
2 2
3set -euxo pipefail 3set -euxo pipefail
4 4
5# examples
6(cd examples; cargo build --target thumbv7em-none-eabi --bins)
7
8# embassy std 5# embassy std
9(cd embassy; cargo build --features log,std) 6(cd embassy; cargo build --features log,std)
10 7
@@ -14,6 +11,9 @@ set -euxo pipefail
14(cd embassy; cargo build --target thumbv7em-none-eabi --features defmt) 11(cd embassy; cargo build --target thumbv7em-none-eabi --features defmt)
15 12
16# embassy-nrf 13# embassy-nrf
14
15(cd embassy-nrf-examples; cargo build --target thumbv7em-none-eabi --bins)
16
17(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810) 17(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810)
18#(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet 18#(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet
19(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832) 19(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832)