aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/Cargo.toml1
-rw-r--r--embassy-nrf/src/lib.rs1
-rw-r--r--embassy-nrf/src/uarte.rs418
-rw-r--r--examples/src/bin/buffered_uart.rs84
-rw-r--r--examples/src/bin/uart.rs121
5 files changed, 576 insertions, 49 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 7fe285c62..eb5370ea7 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -26,6 +26,7 @@ log = { version = "0.4.11", optional = true }
26cortex-m-rt = "0.6.13" 26cortex-m-rt = "0.6.13"
27cortex-m = { version = "0.6.4" } 27cortex-m = { version = "0.6.4" }
28embedded-hal = { version = "0.2.4" } 28embedded-hal = { version = "0.2.4" }
29embedded-dma = { version = "0.1.2" }
29 30
30nrf52810-pac = { version = "0.9.0", optional = true } 31nrf52810-pac = { version = "0.9.0", optional = true }
31nrf52811-pac = { version = "0.9.1", optional = true } 32nrf52811-pac = { version = "0.9.1", optional = true }
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 0ca328138..e97002a20 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -57,5 +57,6 @@ pub mod interrupt;
57#[cfg(feature = "52840")] 57#[cfg(feature = "52840")]
58pub mod qspi; 58pub mod qspi;
59pub mod rtc; 59pub mod rtc;
60pub mod uarte;
60 61
61pub use cortex_m_rt::interrupt; 62pub use cortex_m_rt::interrupt;
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
new file mode 100644
index 000000000..f0337be8b
--- /dev/null
+++ b/embassy-nrf/src/uarte.rs
@@ -0,0 +1,418 @@
1//! Async low power UARTE.
2//!
3//! The peripheral is automatically enabled and disabled as required to save power.
4//! Lowest power consumption can only be guaranteed if the send receive futures
5//! are dropped correctly (e.g. not using `mem::forget()`).
6
7use core::future::Future;
8use core::ops::Deref;
9use core::sync::atomic::{compiler_fence, Ordering};
10use core::task::{Context, Poll};
11
12use embassy::util::Signal;
13use embedded_dma::{ReadBuffer, WriteBuffer};
14
15use crate::fmt::{assert, *};
16#[cfg(any(feature = "52833", feature = "52840"))]
17use crate::hal::gpio::Port as GpioPort;
18use crate::hal::pac;
19use crate::hal::prelude::*;
20use crate::hal::target_constants::EASY_DMA_SIZE;
21use crate::interrupt;
22use crate::interrupt::OwnedInterrupt;
23
24pub use crate::hal::uarte::Pins;
25// Re-export SVD variants to allow user to directly set values.
26pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
27
28/// Interface to the UARTE peripheral
29pub struct Uarte<T>
30where
31 T: Instance,
32{
33 instance: T,
34 irq: T::Interrupt,
35 pins: Pins,
36}
37
38pub struct State {
39 tx_done: Signal<()>,
40 rx_done: Signal<u32>,
41}
42
43// TODO: Remove when https://github.com/nrf-rs/nrf-hal/pull/276 has landed
44#[cfg(any(feature = "52833", feature = "52840"))]
45fn port_bit(port: GpioPort) -> bool {
46 match port {
47 GpioPort::Port0 => false,
48 GpioPort::Port1 => true,
49 }
50}
51
52impl<T> Uarte<T>
53where
54 T: Instance,
55{
56 /// Creates the interface to a UARTE instance.
57 /// Sets the baud rate, parity and assigns the pins to the UARTE peripheral.
58 ///
59 /// # Unsafe
60 ///
61 /// The returned API is safe unless you use `mem::forget` (or similar safe mechanisms)
62 /// on stack allocated buffers which which have been passed to [`send()`](Uarte::send)
63 /// or [`receive`](Uarte::receive).
64 #[allow(unused_unsafe)]
65 pub unsafe fn new(
66 uarte: T,
67 irq: T::Interrupt,
68 mut pins: Pins,
69 parity: Parity,
70 baudrate: Baudrate,
71 ) -> Self {
72 assert!(uarte.enable.read().enable().is_disabled());
73
74 uarte.psel.rxd.write(|w| {
75 let w = unsafe { w.pin().bits(pins.rxd.pin()) };
76 #[cfg(any(feature = "52833", feature = "52840"))]
77 let w = w.port().bit(port_bit(pins.rxd.port()));
78 w.connect().connected()
79 });
80
81 pins.txd.set_high().unwrap();
82 uarte.psel.txd.write(|w| {
83 let w = unsafe { w.pin().bits(pins.txd.pin()) };
84 #[cfg(any(feature = "52833", feature = "52840"))]
85 let w = w.port().bit(port_bit(pins.txd.port()));
86 w.connect().connected()
87 });
88
89 // Optional pins
90 uarte.psel.cts.write(|w| {
91 if let Some(ref pin) = pins.cts {
92 let w = unsafe { w.pin().bits(pin.pin()) };
93 #[cfg(any(feature = "52833", feature = "52840"))]
94 let w = w.port().bit(port_bit(pin.port()));
95 w.connect().connected()
96 } else {
97 w.connect().disconnected()
98 }
99 });
100
101 uarte.psel.rts.write(|w| {
102 if let Some(ref pin) = pins.rts {
103 let w = unsafe { w.pin().bits(pin.pin()) };
104 #[cfg(any(feature = "52833", feature = "52840"))]
105 let w = w.port().bit(port_bit(pin.port()));
106 w.connect().connected()
107 } else {
108 w.connect().disconnected()
109 }
110 });
111
112 uarte.baudrate.write(|w| w.baudrate().variant(baudrate));
113 uarte.config.write(|w| w.parity().variant(parity));
114
115 // Enable interrupts
116 uarte.events_endtx.reset();
117 uarte.events_endrx.reset();
118 uarte
119 .intenset
120 .write(|w| w.endtx().set().txstopped().set().endrx().set().rxto().set());
121
122 // Register ISR
123 irq.set_handler(Self::on_irq);
124 irq.unpend();
125 irq.enable();
126
127 Uarte {
128 instance: uarte,
129 irq,
130 pins,
131 }
132 }
133
134 pub fn free(self) -> (T, T::Interrupt, Pins) {
135 (self.instance, self.irq, self.pins)
136 }
137
138 fn enable(&mut self) {
139 trace!("enable");
140 self.instance.enable.write(|w| w.enable().enabled());
141 }
142
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 {
165 self.instance.events_txstarted.read().bits() != 0
166 }
167
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 {
195 self.instance.events_rxstarted.read().bits() != 0
196 }
197
198 unsafe fn on_irq() {
199 let uarte = &*pac::UARTE0::ptr();
200
201 let mut try_disable = false;
202
203 if uarte.events_endtx.read().bits() != 0 {
204 uarte.events_endtx.reset();
205 trace!("endtx");
206 compiler_fence(Ordering::SeqCst);
207 T::state().tx_done.signal(());
208 }
209
210 if uarte.events_txstopped.read().bits() != 0 {
211 uarte.events_txstopped.reset();
212 trace!("txstopped");
213 try_disable = true;
214 }
215
216 if uarte.events_endrx.read().bits() != 0 {
217 uarte.events_endrx.reset();
218 trace!("endrx");
219 let len = uarte.rxd.amount.read().bits();
220 compiler_fence(Ordering::SeqCst);
221 T::state().rx_done.signal(len);
222 }
223
224 if uarte.events_rxto.read().bits() != 0 {
225 uarte.events_rxto.reset();
226 trace!("rxto");
227 try_disable = true;
228 }
229
230 // Disable the peripheral if not active.
231 if try_disable
232 && uarte.events_txstarted.read().bits() == 0
233 && uarte.events_rxstarted.read().bits() == 0
234 {
235 trace!("disable");
236 uarte.enable.write(|w| w.enable().disabled());
237 }
238 }
239}
240
241/// Future for the [`Uarte::send()`] method.
242pub struct SendFuture<'a, T, B>
243where
244 T: Instance,
245{
246 uarte: &'a Uarte<T>,
247 buf: B,
248}
249
250impl<'a, T, B> Drop for SendFuture<'a, T, B>
251where
252 T: Instance,
253{
254 fn drop(self: &mut Self) {
255 if self.uarte.tx_started() {
256 trace!("stoptx");
257
258 // Stop the transmitter to minimize the current consumption.
259 self.uarte.instance.events_txstarted.reset();
260 self.uarte
261 .instance
262 .tasks_stoptx
263 .write(|w| unsafe { w.bits(1) });
264 T::state().tx_done.blocking_wait();
265 }
266 }
267}
268
269impl<'a, T, B> Future for SendFuture<'a, T, B>
270where
271 T: Instance,
272 B: ReadBuffer<Word = u8>,
273{
274 type Output = ();
275
276 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
277 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
278
279 if !uarte.tx_started() {
280 let uarte = &uarte.instance;
281
282 T::state().tx_done.reset();
283
284 let (ptr, len) = unsafe { buf.read_buffer() };
285 assert!(len <= EASY_DMA_SIZE);
286 // TODO: panic if buffer is not in SRAM
287
288 compiler_fence(Ordering::SeqCst);
289 uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
290 uarte
291 .txd
292 .maxcnt
293 .write(|w| unsafe { w.maxcnt().bits(len as _) });
294
295 trace!("starttx");
296 uarte.tasks_starttx.write(|w| unsafe { w.bits(1) });
297 }
298
299 T::state().tx_done.poll_wait(cx)
300 }
301}
302
303/// Future for the [`Uarte::receive()`] method.
304pub struct ReceiveFuture<'a, T, B>
305where
306 T: Instance,
307{
308 uarte: &'a Uarte<T>,
309 buf: Option<B>,
310}
311
312impl<'a, T, B> Drop for ReceiveFuture<'a, T, B>
313where
314 T: Instance,
315{
316 fn drop(self: &mut Self) {
317 if self.uarte.rx_started() {
318 trace!("stoprx");
319
320 self.uarte.instance.events_rxstarted.reset();
321 self.uarte
322 .instance
323 .tasks_stoprx
324 .write(|w| unsafe { w.bits(1) });
325 T::state().rx_done.blocking_wait();
326 }
327 }
328}
329
330impl<'a, T, B> Future for ReceiveFuture<'a, T, B>
331where
332 T: Instance,
333 B: WriteBuffer<Word = u8>,
334{
335 type Output = B;
336
337 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B> {
338 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
339
340 if !uarte.rx_started() {
341 let uarte = &uarte.instance;
342
343 T::state().rx_done.reset();
344
345 let (ptr, len) = unsafe { buf.as_mut().unwrap().write_buffer() };
346 assert!(len <= EASY_DMA_SIZE);
347
348 compiler_fence(Ordering::SeqCst);
349 uarte.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
350 uarte
351 .rxd
352 .maxcnt
353 .write(|w| unsafe { w.maxcnt().bits(len as _) });
354
355 trace!("startrx");
356 uarte.tasks_startrx.write(|w| unsafe { w.bits(1) });
357 }
358
359 T::state()
360 .rx_done
361 .poll_wait(cx)
362 .map(|_| buf.take().unwrap())
363 }
364}
365
366/// Future for the [`receive()`] method.
367impl<'a, T, B> ReceiveFuture<'a, T, B>
368where
369 T: Instance,
370{
371 /// Stops the ongoing reception and returns the number of bytes received.
372 pub async fn stop(mut self) -> (B, usize) {
373 let buf = self.buf.take().unwrap();
374 drop(self);
375 let len = T::state().rx_done.wait().await;
376 (buf, len as _)
377 }
378}
379
380mod private {
381 pub trait Sealed {}
382}
383
384pub trait Instance: Deref<Target = pac::uarte0::RegisterBlock> + Sized + private::Sealed {
385 type Interrupt: OwnedInterrupt;
386
387 #[doc(hidden)]
388 fn state() -> &'static State;
389}
390
391static UARTE0_STATE: State = State {
392 tx_done: Signal::new(),
393 rx_done: Signal::new(),
394};
395impl private::Sealed for pac::UARTE0 {}
396impl Instance for pac::UARTE0 {
397 type Interrupt = interrupt::UARTE0_UART0Interrupt;
398
399 fn state() -> &'static State {
400 &UARTE0_STATE
401 }
402}
403
404#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
405static UARTE1_STATE: State = State {
406 tx_done: Signal::new(),
407 rx_done: Signal::new(),
408};
409#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
410impl private::Sealed for pac::UARTE1 {}
411#[cfg(any(feature = "52833", feature = "52840", feature = "9160"))]
412impl Instance for pac::UARTE1 {
413 type Interrupt = interrupt::UARTE1Interrupt;
414
415 fn state() -> &'static State {
416 &UARTE1_STATE
417 }
418}
diff --git a/examples/src/bin/buffered_uart.rs b/examples/src/bin/buffered_uart.rs
new file mode 100644
index 000000000..6e15fbcfa
--- /dev/null
+++ b/examples/src/bin/buffered_uart.rs
@@ -0,0 +1,84 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use example_common::*;
8
9use cortex_m_rt::entry;
10use defmt::panic;
11use futures::pin_mut;
12use nrf52840_hal::gpio;
13
14use embassy::executor::{task, Executor};
15use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt};
16use embassy::util::Forever;
17use embassy_nrf::buffered_uarte;
18use embassy_nrf::interrupt;
19
20#[task]
21async fn run() {
22 let p = unwrap!(embassy_nrf::pac::Peripherals::take());
23
24 let port0 = gpio::p0::Parts::new(p.P0);
25
26 let pins = buffered_uarte::Pins {
27 rxd: port0.p0_08.into_floating_input().degrade(),
28 txd: port0
29 .p0_06
30 .into_push_pull_output(gpio::Level::Low)
31 .degrade(),
32 cts: None,
33 rts: None,
34 };
35
36 let irq = interrupt::take!(UARTE0_UART0);
37 let u = buffered_uarte::BufferedUarte::new(
38 p.UARTE0,
39 irq,
40 pins,
41 buffered_uarte::Parity::EXCLUDED,
42 buffered_uarte::Baudrate::BAUD115200,
43 );
44 pin_mut!(u);
45
46 info!("uarte initialized!");
47
48 unwrap!(u.write_all(b"Hello!\r\n").await);
49 info!("wrote hello in uart!");
50
51 // Simple demo, reading 8-char chunks and echoing them back reversed.
52 loop {
53 info!("reading...");
54 let mut buf = [0u8; 8];
55 unwrap!(u.read_exact(&mut buf).await);
56 info!("read done, got {:[u8]}", buf);
57
58 // Reverse buf
59 for i in 0..4 {
60 let tmp = buf[i];
61 buf[i] = buf[7 - i];
62 buf[7 - i] = tmp;
63 }
64
65 info!("writing...");
66 unwrap!(u.write_all(&buf).await);
67 info!("write done");
68 }
69}
70
71static EXECUTOR: Forever<Executor> = Forever::new();
72
73#[entry]
74fn main() -> ! {
75 info!("Hello World!");
76
77 let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev));
78 unwrap!(executor.spawn(run()));
79
80 loop {
81 executor.run();
82 cortex_m::asm::wfe();
83 }
84}
diff --git a/examples/src/bin/uart.rs b/examples/src/bin/uart.rs
index 6e15fbcfa..107936686 100644
--- a/examples/src/bin/uart.rs
+++ b/examples/src/bin/uart.rs
@@ -8,74 +8,97 @@ 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;
13
14use embassy::executor::{task, Executor}; 11use embassy::executor::{task, Executor};
15use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; 12use embassy::time::{Duration, Timer};
16use embassy::util::Forever; 13use embassy::util::Forever;
17use embassy_nrf::buffered_uarte; 14use embassy_nrf::{interrupt, pac, rtc, uarte};
18use embassy_nrf::interrupt; 15use futures::future::{select, Either};
16use nrf52840_hal::clocks;
17use nrf52840_hal::gpio;
19 18
20#[task] 19#[task]
21async fn run() { 20async fn run(mut uart: uarte::Uarte<pac::UARTE0>) {
22 let p = unwrap!(embassy_nrf::pac::Peripherals::take());
23
24 let port0 = gpio::p0::Parts::new(p.P0);
25
26 let pins = buffered_uarte::Pins {
27 rxd: port0.p0_08.into_floating_input().degrade(),
28 txd: port0
29 .p0_06
30 .into_push_pull_output(gpio::Level::Low)
31 .degrade(),
32 cts: None,
33 rts: None,
34 };
35
36 let irq = interrupt::take!(UARTE0_UART0);
37 let u = buffered_uarte::BufferedUarte::new(
38 p.UARTE0,
39 irq,
40 pins,
41 buffered_uarte::Parity::EXCLUDED,
42 buffered_uarte::Baudrate::BAUD115200,
43 );
44 pin_mut!(u);
45
46 info!("uarte initialized!"); 21 info!("uarte initialized!");
47 22
48 unwrap!(u.write_all(b"Hello!\r\n").await); 23 // Message must be in SRAM
24 let mut buf = [0; 8];
25 buf.copy_from_slice(b"Hello!\r\n");
26
27 uart.send(&buf).await;
49 info!("wrote hello in uart!"); 28 info!("wrote hello in uart!");
50 29
51 // Simple demo, reading 8-char chunks and echoing them back reversed. 30 info!("reading...");
52 loop { 31 loop {
53 info!("reading..."); 32 let received = match select(
54 let mut buf = [0u8; 8]; 33 uart.receive(&mut buf),
55 unwrap!(u.read_exact(&mut buf).await); 34 Timer::after(Duration::from_millis(10)),
56 info!("read done, got {:[u8]}", buf); 35 )
57 36 .await
58 // Reverse buf 37 {
59 for i in 0..4 { 38 Either::Left((buf, _)) => buf,
60 let tmp = buf[i]; 39 Either::Right((_, read)) => {
61 buf[i] = buf[7 - i]; 40 let (buf, n) = read.stop().await;
62 buf[7 - i] = tmp; 41 &buf[..n]
42 }
43 };
44
45 if received.len() > 0 {
46 info!("read done, got {:[u8]}", received);
47
48 // Echo back received data
49 uart.send(received).await;
63 } 50 }
64
65 info!("writing...");
66 unwrap!(u.write_all(&buf).await);
67 info!("write done");
68 } 51 }
69} 52}
70 53
54static RTC: Forever<rtc::RTC<pac::RTC1>> = Forever::new();
55static ALARM: Forever<rtc::Alarm<pac::RTC1>> = Forever::new();
71static EXECUTOR: Forever<Executor> = Forever::new(); 56static EXECUTOR: Forever<Executor> = Forever::new();
72 57
73#[entry] 58#[entry]
74fn main() -> ! { 59fn main() -> ! {
75 info!("Hello World!"); 60 info!("Hello World!");
76 61
77 let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); 62 let p = unwrap!(embassy_nrf::pac::Peripherals::take());
78 unwrap!(executor.spawn(run())); 63
64 clocks::Clocks::new(p.CLOCK)
65 .enable_ext_hfosc()
66 .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass)
67 .start_lfclk();
68
69 let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
70 rtc.start();
71
72 unsafe { embassy::time::set_clock(rtc) };
73
74 let alarm = ALARM.put(rtc.alarm0());
75 let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev));
76
77 // Init UART
78 let port0 = gpio::p0::Parts::new(p.P0);
79
80 let pins = uarte::Pins {
81 rxd: port0.p0_08.into_floating_input().degrade(),
82 txd: port0
83 .p0_06
84 .into_push_pull_output(gpio::Level::Low)
85 .degrade(),
86 cts: None,
87 rts: None,
88 };
89
90 // NOTE(unsafe): Safe becasue we do not use `mem::forget` anywhere.
91 let uart = unsafe {
92 uarte::Uarte::new(
93 p.UARTE0,
94 interrupt::take!(UARTE0_UART0),
95 pins,
96 uarte::Parity::EXCLUDED,
97 uarte::Baudrate::BAUD115200,
98 )
99 };
100
101 unwrap!(executor.spawn(run(uart)));
79 102
80 loop { 103 loop {
81 executor.run(); 104 executor.run();