aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias <[email protected]>2022-08-26 09:05:12 +0200
committerMathias <[email protected]>2022-09-09 10:48:30 +0200
commit9611e7c9f2609271af2ead7e91e6ee918d3dadd3 (patch)
tree571498da96f19ec68c7814e7b5acc9d1f2f97e7c
parent573c433f64a049d4e0d501df1194c3228aae0863 (diff)
Add BufferedUart implementation, and feature-guard time-driver initialization, to free up TIMER peripheral if not used with embassy executor
-rw-r--r--embassy-rp/Cargo.toml45
-rw-r--r--embassy-rp/src/lib.rs2
-rw-r--r--embassy-rp/src/uart/buffered.rs286
-rw-r--r--embassy-rp/src/uart/mod.rs (renamed from embassy-rp/src/uart.rs)84
4 files changed, 401 insertions, 16 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index ccb2f6525..92780ee39 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -7,9 +7,7 @@ edition = "2021"
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/" 7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/" 8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/"
9features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] 9features = ["nightly", "defmt", "unstable-pac", "unstable-traits"]
10flavors = [ 10flavors = [{ name = "rp2040", target = "thumbv6m-none-eabi" }]
11 { name = "rp2040", target = "thumbv6m-none-eabi" },
12]
13 11
14[features] 12[features]
15defmt = ["dep:defmt", "embassy-usb?/defmt"] 13defmt = ["dep:defmt", "embassy-usb?/defmt"]
@@ -20,8 +18,16 @@ defmt = ["dep:defmt", "embassy-usb?/defmt"]
20# There are no plans to make this stable. 18# There are no plans to make this stable.
21unstable-pac = [] 19unstable-pac = []
22 20
21time-driver = []
22
23# Enable nightly-only features 23# Enable nightly-only features
24nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"] 24nightly = [
25 "embassy-executor/nightly",
26 "embedded-hal-1",
27 "embedded-hal-async",
28 "embassy-embedded-hal/nightly",
29 "dep:embassy-usb",
30]
25 31
26# Implement embedded-hal 1.0 alpha traits. 32# Implement embedded-hal 1.0 alpha traits.
27# Implement embedded-hal-async traits if `nightly` is set as well. 33# Implement embedded-hal-async traits if `nightly` is set as well.
@@ -30,11 +36,15 @@ unstable-traits = ["embedded-hal-1"]
30[dependencies] 36[dependencies]
31embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 37embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
32embassy-executor = { version = "0.1.0", path = "../embassy-executor" } 38embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
33embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 39embassy-time = { version = "0.1.0", path = "../embassy-time", features = [
34embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} 40 "tick-hz-1_000_000",
35embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 41] }
36embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 42embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = [
37embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } 43 "prio-bits-2",
44] }
45embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
46embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
47embassy-usb = { version = "0.1.0", path = "../embassy-usb", optional = true }
38atomic-polyfill = "1.0.1" 48atomic-polyfill = "1.0.1"
39defmt = { version = "0.3", optional = true } 49defmt = { version = "0.3", optional = true }
40log = { version = "0.4.14", optional = true } 50log = { version = "0.4.14", optional = true }
@@ -43,11 +53,18 @@ cfg-if = "1.0.0"
43cortex-m-rt = ">=0.6.15,<0.8" 53cortex-m-rt = ">=0.6.15,<0.8"
44cortex-m = "0.7.6" 54cortex-m = "0.7.6"
45critical-section = "1.1" 55critical-section = "1.1"
46futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 56futures = { version = "0.3.17", default-features = false, features = [
57 "async-await",
58] }
59embedded-io = { version = "0.3.0", features = ["async"], optional = true }
47 60
48rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } 61rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev = "017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = [
62 "rt",
63] }
49#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } 64#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
50 65
51embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 66embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
52embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} 67 "unproven",
53embedded-hal-async = { version = "0.1.0-alpha.1", optional = true} 68] }
69embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true }
70embedded-hal-async = { version = "0.1.0-alpha.1", optional = true }
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index aebbbf567..8dcefece2 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -8,6 +8,7 @@ pub mod dma;
8pub mod gpio; 8pub mod gpio;
9pub mod interrupt; 9pub mod interrupt;
10pub mod spi; 10pub mod spi;
11#[cfg(feature = "time-driver")]
11pub mod timer; 12pub mod timer;
12pub mod uart; 13pub mod uart;
13#[cfg(feature = "nightly")] 14#[cfg(feature = "nightly")]
@@ -108,6 +109,7 @@ pub fn init(_config: config::Config) -> Peripherals {
108 109
109 unsafe { 110 unsafe {
110 clocks::init(); 111 clocks::init();
112 #[cfg(feature = "time-driver")]
111 timer::init(); 113 timer::init();
112 dma::init(); 114 dma::init();
113 } 115 }
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
new file mode 100644
index 000000000..c31af8018
--- /dev/null
+++ b/embassy-rp/src/uart/buffered.rs
@@ -0,0 +1,286 @@
1use core::future::Future;
2use core::task::Poll;
3
4use atomic_polyfill::{compiler_fence, Ordering};
5use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
6use embassy_hal_common::ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::WakerRegistration;
8use futures::future::poll_fn;
9
10use super::*;
11
12pub struct State<'d, T: Instance>(StateStorage<StateInner<'d, T>>);
13impl<'d, T: Instance> State<'d, T> {
14 pub fn new() -> Self {
15 Self(StateStorage::new())
16 }
17}
18
19struct StateInner<'d, T: Instance> {
20 phantom: PhantomData<&'d mut T>,
21
22 rx_waker: WakerRegistration,
23 rx: RingBuffer<'d>,
24
25 tx_waker: WakerRegistration,
26 tx: RingBuffer<'d>,
27}
28
29unsafe impl<'d, T: Instance> Send for StateInner<'d, T> {}
30unsafe impl<'d, T: Instance> Sync for StateInner<'d, T> {}
31
32pub struct BufferedUart<'d, T: Instance> {
33 inner: PeripheralMutex<'d, StateInner<'d, T>>,
34}
35
36impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {}
37
38impl<'d, T: Instance> BufferedUart<'d, T> {
39 pub fn new<M: Mode>(
40 state: &'d mut State<'d, T>,
41 _uart: Uart<'d, T, M>,
42 irq: impl Peripheral<P = T::Interrupt> + 'd,
43 tx_buffer: &'d mut [u8],
44 rx_buffer: &'d mut [u8],
45 ) -> BufferedUart<'d, T> {
46 into_ref!(irq);
47
48 let r = T::regs();
49 unsafe {
50 r.uartimsc().modify(|w| {
51 // TODO: Should and more or fewer interrupts be enabled?
52 w.set_rxim(true);
53 w.set_rtim(true);
54 });
55 }
56
57 Self {
58 inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner {
59 phantom: PhantomData,
60 tx: RingBuffer::new(tx_buffer),
61 tx_waker: WakerRegistration::new(),
62
63 rx: RingBuffer::new(rx_buffer),
64 rx_waker: WakerRegistration::new(),
65 }),
66 }
67 }
68}
69
70impl<'d, T: Instance> StateInner<'d, T>
71where
72 Self: 'd,
73{
74 fn on_rx(&mut self) {
75 let r = T::regs();
76 unsafe {
77 let ris = r.uartris().read();
78 // Clear interrupt flags
79 r.uarticr().write(|w| {
80 w.set_rxic(true);
81 w.set_rtic(true);
82 });
83
84 if ris.rxris() {
85 if ris.peris() {
86 warn!("Parity error");
87 }
88 if ris.feris() {
89 warn!("Framing error");
90 }
91 if ris.beris() {
92 warn!("Break error");
93 }
94 if ris.oeris() {
95 warn!("Overrun error");
96 }
97
98 let buf = self.rx.push_buf();
99 if !buf.is_empty() {
100 buf[0] = r.uartdr().read().data();
101 self.rx.push(1);
102 } else {
103 warn!("RX buffer full, discard received byte");
104 }
105
106 if self.rx.is_full() {
107 self.rx_waker.wake();
108 }
109 }
110
111 if ris.rtris() {
112 self.rx_waker.wake();
113 };
114 }
115 }
116
117 fn on_tx(&mut self) {
118 let r = T::regs();
119 unsafe {
120 let ris = r.uartris().read();
121 // Clear interrupt flags
122 r.uarticr().write(|w| {
123 w.set_rtic(true);
124 });
125
126 if ris.txris() {
127 let buf = self.tx.pop_buf();
128 if !buf.is_empty() {
129 r.uartimsc().modify(|w| {
130 w.set_txim(true);
131 });
132 r.uartdr().write(|w| w.set_data(buf[0].into()));
133 self.tx.pop(1);
134 self.tx_waker.wake();
135 } else {
136 // Disable interrupt until we have something to transmit again
137 r.uartimsc().modify(|w| {
138 w.set_txim(false);
139 });
140 }
141 }
142 }
143 }
144}
145
146impl<'d, T: Instance> PeripheralState for StateInner<'d, T>
147where
148 Self: 'd,
149{
150 type Interrupt = T::Interrupt;
151 fn on_interrupt(&mut self) {
152 self.on_rx();
153 self.on_tx();
154 }
155}
156
157impl embedded_io::Error for Error {
158 fn kind(&self) -> embedded_io::ErrorKind {
159 embedded_io::ErrorKind::Other
160 }
161}
162
163impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> {
164 type Error = Error;
165}
166
167impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> {
168 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
169 where
170 Self: 'a;
171
172 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
173 poll_fn(move |cx| {
174 let mut do_pend = false;
175 let res = self.inner.with(|state| {
176 compiler_fence(Ordering::SeqCst);
177
178 // We have data ready in buffer? Return it.
179 let data = state.rx.pop_buf();
180 if !data.is_empty() {
181 let len = data.len().min(buf.len());
182 buf[..len].copy_from_slice(&data[..len]);
183
184 if state.rx.is_full() {
185 do_pend = true;
186 }
187 state.rx.pop(len);
188
189 return Poll::Ready(Ok(len));
190 }
191
192 state.rx_waker.register(cx.waker());
193 Poll::Pending
194 });
195
196 if do_pend {
197 self.inner.pend();
198 }
199
200 res
201 })
202 }
203}
204
205impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
206 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
207 where
208 Self: 'a;
209
210 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
211 poll_fn(move |cx| {
212 self.inner.with(|state| {
213 compiler_fence(Ordering::SeqCst);
214
215 // We have data ready in buffer? Return it.
216 let buf = state.rx.pop_buf();
217 if !buf.is_empty() {
218 let buf: &[u8] = buf;
219 // Safety: buffer lives as long as uart
220 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
221 return Poll::Ready(Ok(buf));
222 }
223
224 state.rx_waker.register(cx.waker());
225 Poll::<Result<&[u8], Self::Error>>::Pending
226 })
227 })
228 }
229
230 fn consume(&mut self, amt: usize) {
231 let signal = self.inner.with(|state| {
232 let full = state.rx.is_full();
233 state.rx.pop(amt);
234 full
235 });
236 if signal {
237 self.inner.pend();
238 }
239 }
240}
241
242impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
243 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
244 where
245 Self: 'a;
246
247 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
248 poll_fn(move |cx| {
249 let (poll, empty) = self.inner.with(|state| {
250 let empty = state.tx.is_empty();
251 let tx_buf = state.tx.push_buf();
252 if tx_buf.is_empty() {
253 state.tx_waker.register(cx.waker());
254 return (Poll::Pending, empty);
255 }
256
257 let n = core::cmp::min(tx_buf.len(), buf.len());
258 tx_buf[..n].copy_from_slice(&buf[..n]);
259 state.tx.push(n);
260
261 (Poll::Ready(Ok(n)), empty)
262 });
263 if empty {
264 self.inner.pend();
265 }
266 poll
267 })
268 }
269
270 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
271 where
272 Self: 'a;
273
274 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
275 poll_fn(move |cx| {
276 self.inner.with(|state| {
277 if !state.tx.is_empty() {
278 state.tx_waker.register(cx.waker());
279 return Poll::Pending;
280 }
281
282 Poll::Ready(Ok(()))
283 })
284 })
285 }
286}
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs
index 987b716b4..3b71d87be 100644
--- a/embassy-rp/src/uart.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -475,6 +475,76 @@ mod eh1 {
475 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { 475 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> {
476 type Error = Error; 476 type Error = Error;
477 } 477 }
478
479 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> {
480 fn read(&mut self) -> nb::Result<u8, Self::Error> {
481 let r = T::regs();
482 unsafe {
483 let dr = r.uartdr().read();
484
485 if dr.oe() {
486 Err(nb::Error::Other(Error::Overrun))
487 } else if dr.be() {
488 Err(nb::Error::Other(Error::Break))
489 } else if dr.pe() {
490 Err(nb::Error::Other(Error::Parity))
491 } else if dr.fe() {
492 Err(nb::Error::Other(Error::Framing))
493 } else if dr.fe() {
494 Ok(dr.data())
495 } else {
496 Err(nb::Error::WouldBlock)
497 }
498 }
499 }
500 }
501
502 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> {
503 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
504 self.blocking_write(buffer)
505 }
506
507 fn flush(&mut self) -> Result<(), Self::Error> {
508 self.blocking_flush()
509 }
510 }
511
512 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> {
513 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
514 self.blocking_write(&[char]).map_err(nb::Error::Other)
515 }
516
517 fn flush(&mut self) -> nb::Result<(), Self::Error> {
518 self.blocking_flush().map_err(nb::Error::Other)
519 }
520 }
521
522 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> {
523 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
524 embedded_hal_02::serial::Read::read(&mut self.rx)
525 }
526 }
527
528 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> {
529 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
530 self.blocking_write(buffer)
531 }
532
533 fn flush(&mut self) -> Result<(), Self::Error> {
534 self.blocking_flush()
535 }
536 }
537
538 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> {
539 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
540 self.blocking_write(&[char]).map_err(nb::Error::Other)
541 }
542
543 fn flush(&mut self) -> nb::Result<(), Self::Error> {
544 self.blocking_flush().map_err(nb::Error::Other)
545 }
546 }
547
478} 548}
479 549
480#[cfg(all( 550#[cfg(all(
@@ -532,6 +602,12 @@ mod eha {
532 } 602 }
533} 603}
534 604
605#[cfg(feature = "nightly")]
606mod buffered;
607#[cfg(feature = "nightly")]
608pub use buffered::*;
609
610
535mod sealed { 611mod sealed {
536 use super::*; 612 use super::*;
537 613
@@ -541,6 +617,8 @@ mod sealed {
541 const TX_DREQ: u8; 617 const TX_DREQ: u8;
542 const RX_DREQ: u8; 618 const RX_DREQ: u8;
543 619
620 type Interrupt: crate::interrupt::Interrupt;
621
544 fn regs() -> pac::uart::Uart; 622 fn regs() -> pac::uart::Uart;
545 } 623 }
546 pub trait TxPin<T: Instance> {} 624 pub trait TxPin<T: Instance> {}
@@ -571,6 +649,8 @@ macro_rules! impl_instance {
571 impl sealed::Instance for peripherals::$inst { 649 impl sealed::Instance for peripherals::$inst {
572 const TX_DREQ: u8 = $tx_dreq; 650 const TX_DREQ: u8 = $tx_dreq;
573 const RX_DREQ: u8 = $rx_dreq; 651 const RX_DREQ: u8 = $rx_dreq;
652
653 type Interrupt = crate::interrupt::$irq;
574 654
575 fn regs() -> pac::uart::Uart { 655 fn regs() -> pac::uart::Uart {
576 pac::$inst 656 pac::$inst
@@ -580,8 +660,8 @@ macro_rules! impl_instance {
580 }; 660 };
581} 661}
582 662
583impl_instance!(UART0, UART0, 20, 21); 663impl_instance!(UART0, UART0_IRQ, 20, 21);
584impl_instance!(UART1, UART1, 22, 23); 664impl_instance!(UART1, UART1_IRQ, 22, 23);
585 665
586pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} 666pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
587pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} 667pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}