aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-12-16 07:44:40 +0000
committerGitHub <[email protected]>2021-12-16 07:44:40 +0000
commit5df16c6793a3730535ac91af8133ff744d76fad5 (patch)
treeefe5218718aa6115d472aa00b8611c8bb5510078
parentd5a3064c2c20b4a9515e5322bb9a74724ebcf7c9 (diff)
parent0642eec01e23d9037e21186cfb0c169e56f9a161 (diff)
Merge #544
544: Introduces split on the nRF Uarte r=Dirbaio a=huntc A new `split` method is introduced such that the Uarte tx and rx can be used from separate tasks. An MPSC is used in an example to illustrate how data may be passed between these tasks. The approach taken within the `Uarte` struct is to split into tx and rx fields on calling `Uarte::new`. These fields are returned given a call to `Uarte::split`, but otherwise, if that call isn't made, then the API remains as it was before. Here's a snippet from a new example introduced: ```rust #[embassy::main] async fn main(spawner: Spawner, p: Peripherals) { // ... let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config); let (mut tx, rx) = uart.split(); // ... // Spawn a task responsible purely for reading unwrap!(spawner.spawn(reader(rx, s))); // ... // Continue reading in this main task and write // back out the buffer we receive from the read // task. loop { if let Some(buf) = r.recv().await { info!("writing..."); unwrap!(tx.write(&buf).await); } } } #[embassy::task] async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) { let mut buf = [0; 8]; loop { info!("reading..."); unwrap!(rx.read(&mut buf).await); unwrap!(s.send(buf).await); } } ``` Co-authored-by: huntc <[email protected]>
-rw-r--r--embassy-nrf/src/uarte.rs215
-rw-r--r--examples/nrf/src/bin/uart_split.rs68
2 files changed, 220 insertions, 63 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index ff781cabd..17417c0e2 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -54,6 +54,20 @@ impl Default for Config {
54/// Interface to the UARTE peripheral 54/// Interface to the UARTE peripheral
55pub struct Uarte<'d, T: Instance> { 55pub struct Uarte<'d, T: Instance> {
56 phantom: PhantomData<&'d mut T>, 56 phantom: PhantomData<&'d mut T>,
57 tx: UarteTx<'d, T>,
58 rx: UarteRx<'d, T>,
59}
60
61/// Transmitter interface to the UARTE peripheral obtained
62/// via [Uarte]::split.
63pub struct UarteTx<'d, T: Instance> {
64 phantom: PhantomData<&'d mut T>,
65}
66
67/// Receiver interface to the UARTE peripheral obtained
68/// via [Uarte]::split.
69pub struct UarteRx<'d, T: Instance> {
70 phantom: PhantomData<&'d mut T>,
57} 71}
58 72
59impl<'d, T: Instance> Uarte<'d, T> { 73impl<'d, T: Instance> Uarte<'d, T> {
@@ -119,11 +133,24 @@ impl<'d, T: Instance> Uarte<'d, T> {
119 apply_workaround_for_enable_anomaly(&r); 133 apply_workaround_for_enable_anomaly(&r);
120 r.enable.write(|w| w.enable().enabled()); 134 r.enable.write(|w| w.enable().enabled());
121 135
136 let s = T::state();
137
138 s.tx_rx_refcount.store(2, Ordering::Relaxed);
139
122 Self { 140 Self {
123 phantom: PhantomData, 141 phantom: PhantomData,
142 tx: UarteTx::new(),
143 rx: UarteRx::new(),
124 } 144 }
125 } 145 }
126 146
147 /// Split the Uarte into a transmitter and receiver, which is
148 /// particuarly useful when having two tasks correlating to
149 /// transmitting and receiving.
150 pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) {
151 (self.tx, self.rx)
152 }
153
127 fn on_interrupt(_: *mut ()) { 154 fn on_interrupt(_: *mut ()) {
128 let r = T::regs(); 155 let r = T::regs();
129 let s = T::state(); 156 let s = T::state();
@@ -139,72 +166,72 @@ impl<'d, T: Instance> Uarte<'d, T> {
139 } 166 }
140} 167}
141 168
142impl<'a, T: Instance> Drop for Uarte<'a, T> { 169impl<'d, T: Instance> Read for Uarte<'d, T> {
143 fn drop(&mut self) { 170 #[rustfmt::skip]
144 info!("uarte drop"); 171 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a;
145
146 let r = T::regs();
147
148 let did_stoprx = r.events_rxstarted.read().bits() != 0;
149 let did_stoptx = r.events_txstarted.read().bits() != 0;
150 info!("did_stoprx {} did_stoptx {}", did_stoprx, did_stoptx);
151 172
152 // Wait for rxto or txstopped, if needed. 173 fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
153 while (did_stoprx && r.events_rxto.read().bits() == 0) 174 self.rx.read(rx_buffer)
154 || (did_stoptx && r.events_txstopped.read().bits() == 0) 175 }
155 {} 176}
156 177
157 // Finally we can disable! 178impl<'d, T: Instance> Write for Uarte<'d, T> {
158 r.enable.write(|w| w.enable().disabled()); 179 #[rustfmt::skip]
180 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a;
159 181
160 gpio::deconfigure_pin(r.psel.rxd.read().bits()); 182 fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
161 gpio::deconfigure_pin(r.psel.txd.read().bits()); 183 self.tx.write(tx_buffer)
162 gpio::deconfigure_pin(r.psel.rts.read().bits()); 184 }
163 gpio::deconfigure_pin(r.psel.cts.read().bits()); 185}
164 186
165 info!("uarte drop: done"); 187impl<'d, T: Instance> UarteTx<'d, T> {
188 pub fn new() -> Self {
189 Self {
190 phantom: PhantomData,
191 }
166 } 192 }
167} 193}
168 194
169impl<'d, T: Instance> Read for Uarte<'d, T> { 195impl<'d, T: Instance> Write for UarteTx<'d, T> {
170 #[rustfmt::skip] 196 #[rustfmt::skip]
171 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; 197 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a;
172 198
173 fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { 199 fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> {
174 async move { 200 async move {
175 let ptr = rx_buffer.as_ptr(); 201 let ptr = tx_buffer.as_ptr();
176 let len = rx_buffer.len(); 202 let len = tx_buffer.len();
177 assert!(len <= EASY_DMA_SIZE); 203 assert!(len <= EASY_DMA_SIZE);
204 // TODO: panic if buffer is not in SRAM
178 205
179 let r = T::regs(); 206 let r = T::regs();
180 let s = T::state(); 207 let s = T::state();
181 208
182 let drop = OnDrop::new(move || { 209 let drop = OnDrop::new(move || {
183 info!("read drop: stopping"); 210 info!("write drop: stopping");
184
185 r.intenclr.write(|w| w.endrx().clear());
186 r.events_rxto.reset();
187 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
188 211
189 while r.events_endrx.read().bits() == 0 {} 212 r.intenclr.write(|w| w.endtx().clear());
213 r.events_txstopped.reset();
214 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
190 215
191 info!("read drop: stopped"); 216 // TX is stopped almost instantly, spinning is fine.
217 while r.events_endtx.read().bits() == 0 {}
218 info!("write drop: stopped");
192 }); 219 });
193 220
194 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 221 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
195 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 222 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
196 223
197 r.events_endrx.reset(); 224 r.events_endtx.reset();
198 r.intenset.write(|w| w.endrx().set()); 225 r.intenset.write(|w| w.endtx().set());
199 226
200 compiler_fence(Ordering::SeqCst); 227 compiler_fence(Ordering::SeqCst);
201 228
202 trace!("startrx"); 229 trace!("starttx");
203 r.tasks_startrx.write(|w| unsafe { w.bits(1) }); 230 r.tasks_starttx.write(|w| unsafe { w.bits(1) });
204 231
205 poll_fn(|cx| { 232 poll_fn(|cx| {
206 s.endrx_waker.register(cx.waker()); 233 s.endtx_waker.register(cx.waker());
207 if r.events_endrx.read().bits() != 0 { 234 if r.events_endtx.read().bits() != 0 {
208 return Poll::Ready(()); 235 return Poll::Ready(());
209 } 236 }
210 Poll::Pending 237 Poll::Pending
@@ -212,7 +239,7 @@ impl<'d, T: Instance> Read for Uarte<'d, T> {
212 .await; 239 .await;
213 240
214 compiler_fence(Ordering::SeqCst); 241 compiler_fence(Ordering::SeqCst);
215 r.events_rxstarted.reset(); 242 r.events_txstarted.reset();
216 drop.defuse(); 243 drop.defuse();
217 244
218 Ok(()) 245 Ok(())
@@ -220,46 +247,71 @@ impl<'d, T: Instance> Read for Uarte<'d, T> {
220 } 247 }
221} 248}
222 249
223impl<'d, T: Instance> Write for Uarte<'d, T> { 250impl<'a, T: Instance> Drop for UarteTx<'a, T> {
251 fn drop(&mut self) {
252 info!("uarte tx drop");
253
254 let r = T::regs();
255
256 let did_stoptx = r.events_txstarted.read().bits() != 0;
257 info!("did_stoptx {}", did_stoptx);
258
259 // Wait for txstopped, if needed.
260 while did_stoptx && r.events_txstopped.read().bits() == 0 {}
261
262 let s = T::state();
263
264 drop_tx_rx(&r, &s);
265 }
266}
267
268impl<'d, T: Instance> UarteRx<'d, T> {
269 pub fn new() -> Self {
270 Self {
271 phantom: PhantomData,
272 }
273 }
274}
275
276impl<'d, T: Instance> Read for UarteRx<'d, T> {
224 #[rustfmt::skip] 277 #[rustfmt::skip]
225 type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a; 278 type ReadFuture<'a> where Self: 'a = impl Future<Output = Result<(), TraitError>> + 'a;
226 279
227 fn write<'a>(&'a mut self, tx_buffer: &'a [u8]) -> Self::WriteFuture<'a> { 280 fn read<'a>(&'a mut self, rx_buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
228 async move { 281 async move {
229 let ptr = tx_buffer.as_ptr(); 282 let ptr = rx_buffer.as_ptr();
230 let len = tx_buffer.len(); 283 let len = rx_buffer.len();
231 assert!(len <= EASY_DMA_SIZE); 284 assert!(len <= EASY_DMA_SIZE);
232 // TODO: panic if buffer is not in SRAM
233 285
234 let r = T::regs(); 286 let r = T::regs();
235 let s = T::state(); 287 let s = T::state();
236 288
237 let drop = OnDrop::new(move || { 289 let drop = OnDrop::new(move || {
238 info!("write drop: stopping"); 290 info!("read drop: stopping");
239 291
240 r.intenclr.write(|w| w.endtx().clear()); 292 r.intenclr.write(|w| w.endrx().clear());
241 r.events_txstopped.reset(); 293 r.events_rxto.reset();
242 r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); 294 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
243 295
244 // TX is stopped almost instantly, spinning is fine. 296 while r.events_endrx.read().bits() == 0 {}
245 while r.events_endtx.read().bits() == 0 {} 297
246 info!("write drop: stopped"); 298 info!("read drop: stopped");
247 }); 299 });
248 300
249 r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 301 r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
250 r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); 302 r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) });
251 303
252 r.events_endtx.reset(); 304 r.events_endrx.reset();
253 r.intenset.write(|w| w.endtx().set()); 305 r.intenset.write(|w| w.endrx().set());
254 306
255 compiler_fence(Ordering::SeqCst); 307 compiler_fence(Ordering::SeqCst);
256 308
257 trace!("starttx"); 309 trace!("startrx");
258 r.tasks_starttx.write(|w| unsafe { w.bits(1) }); 310 r.tasks_startrx.write(|w| unsafe { w.bits(1) });
259 311
260 poll_fn(|cx| { 312 poll_fn(|cx| {
261 s.endtx_waker.register(cx.waker()); 313 s.endrx_waker.register(cx.waker());
262 if r.events_endtx.read().bits() != 0 { 314 if r.events_endrx.read().bits() != 0 {
263 return Poll::Ready(()); 315 return Poll::Ready(());
264 } 316 }
265 Poll::Pending 317 Poll::Pending
@@ -267,7 +319,7 @@ impl<'d, T: Instance> Write for Uarte<'d, T> {
267 .await; 319 .await;
268 320
269 compiler_fence(Ordering::SeqCst); 321 compiler_fence(Ordering::SeqCst);
270 r.events_txstarted.reset(); 322 r.events_rxstarted.reset();
271 drop.defuse(); 323 drop.defuse();
272 324
273 Ok(()) 325 Ok(())
@@ -275,6 +327,24 @@ impl<'d, T: Instance> Write for Uarte<'d, T> {
275 } 327 }
276} 328}
277 329
330impl<'a, T: Instance> Drop for UarteRx<'a, T> {
331 fn drop(&mut self) {
332 info!("uarte rx drop");
333
334 let r = T::regs();
335
336 let did_stoprx = r.events_rxstarted.read().bits() != 0;
337 info!("did_stoprx {}", did_stoprx);
338
339 // Wait for rxto, if needed.
340 while did_stoprx && r.events_rxto.read().bits() == 0 {}
341
342 let s = T::state();
343
344 drop_tx_rx(&r, &s);
345 }
346}
347
278#[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] 348#[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))]
279pub(in crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { 349pub(in crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) {
280 // Do nothing 350 // Do nothing
@@ -328,6 +398,21 @@ pub(in crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::Reg
328 } 398 }
329} 399}
330 400
401pub(in crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) {
402 if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 {
403 // Finally we can disable, and we do so for the peripheral
404 // i.e. not just rx concerns.
405 r.enable.write(|w| w.enable().disabled());
406
407 gpio::deconfigure_pin(r.psel.rxd.read().bits());
408 gpio::deconfigure_pin(r.psel.txd.read().bits());
409 gpio::deconfigure_pin(r.psel.rts.read().bits());
410 gpio::deconfigure_pin(r.psel.cts.read().bits());
411
412 info!("uarte tx and rx drop: done");
413 }
414}
415
331/// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, 416/// Interface to an UARTE peripheral that uses an additional timer and two PPI channels,
332/// allowing it to implement the ReadUntilIdle trait. 417/// allowing it to implement the ReadUntilIdle trait.
333pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { 418pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> {
@@ -487,6 +572,8 @@ impl<'d, U: Instance, T: TimerInstance> Write for UarteWithIdle<'d, U, T> {
487} 572}
488 573
489pub(crate) mod sealed { 574pub(crate) mod sealed {
575 use core::sync::atomic::AtomicU8;
576
490 use embassy::waitqueue::AtomicWaker; 577 use embassy::waitqueue::AtomicWaker;
491 578
492 use super::*; 579 use super::*;
@@ -494,12 +581,14 @@ pub(crate) mod sealed {
494 pub struct State { 581 pub struct State {
495 pub endrx_waker: AtomicWaker, 582 pub endrx_waker: AtomicWaker,
496 pub endtx_waker: AtomicWaker, 583 pub endtx_waker: AtomicWaker,
584 pub tx_rx_refcount: AtomicU8,
497 } 585 }
498 impl State { 586 impl State {
499 pub const fn new() -> Self { 587 pub const fn new() -> Self {
500 Self { 588 Self {
501 endrx_waker: AtomicWaker::new(), 589 endrx_waker: AtomicWaker::new(),
502 endtx_waker: AtomicWaker::new(), 590 endtx_waker: AtomicWaker::new(),
591 tx_rx_refcount: AtomicU8::new(0),
503 } 592 }
504 } 593 }
505 } 594 }
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf/src/bin/uart_split.rs
new file mode 100644
index 000000000..4b5dbb21f
--- /dev/null
+++ b/examples/nrf/src/bin/uart_split.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use embassy::blocking_mutex::kind::Noop;
8use embassy::channel::mpsc::{self, Channel, Sender};
9use embassy::util::Forever;
10use embassy_nrf::peripherals::UARTE0;
11use embassy_nrf::uarte::UarteRx;
12use example_common::*;
13
14use embassy::executor::Spawner;
15use embassy::traits::uart::{Read, Write};
16use embassy_nrf::gpio::NoPin;
17use embassy_nrf::{interrupt, uarte, Peripherals};
18
19static CHANNEL: Forever<Channel<Noop, [u8; 8], 1>> = Forever::new();
20
21#[embassy::main]
22async fn main(spawner: Spawner, p: Peripherals) {
23 let mut config = uarte::Config::default();
24 config.parity = uarte::Parity::EXCLUDED;
25 config.baudrate = uarte::Baudrate::BAUD115200;
26
27 let irq = interrupt::take!(UARTE0_UART0);
28 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config);
29 let (mut tx, rx) = uart.split();
30
31 let c = CHANNEL.put(Channel::new());
32 let (s, mut r) = mpsc::split(c);
33
34 info!("uarte initialized!");
35
36 // Spawn a task responsible purely for reading
37
38 unwrap!(spawner.spawn(reader(rx, s)));
39
40 // Message must be in SRAM
41 {
42 let mut buf = [0; 23];
43 buf.copy_from_slice(b"Type 8 chars to echo!\r\n");
44
45 unwrap!(tx.write(&buf).await);
46 info!("wrote hello in uart!");
47 }
48
49 // Continue reading in this main task and write
50 // back out the buffer we receive from the read
51 // task.
52 loop {
53 if let Some(buf) = r.recv().await {
54 info!("writing...");
55 unwrap!(tx.write(&buf).await);
56 }
57 }
58}
59
60#[embassy::task]
61async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) {
62 let mut buf = [0; 8];
63 loop {
64 info!("reading...");
65 unwrap!(rx.read(&mut buf).await);
66 unwrap!(s.send(buf).await);
67 }
68}