aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}