aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-01-05 22:10:52 +0100
committerGitHub <[email protected]>2021-01-05 22:10:52 +0100
commit9bb4c97dc2167331df97288b014085f6c22c23c8 (patch)
tree50fc3f921931a5a5e394d7208eb1c4a9f06cb5ec /embassy-nrf/src
parent607e67f51a33d83c59db5e091348e4bda0b5ddbb (diff)
parent0631623b511d2906993bf2fa3799ea7eec3d7f4a (diff)
Merge pull request #14 from timokroeger/uarte-power-optimization
UARTE power optimization and improvements
Diffstat (limited to 'embassy-nrf/src')
-rw-r--r--embassy-nrf/src/uarte.rs122
-rw-r--r--embassy-nrf/src/util/mod.rs10
2 files changed, 93 insertions, 39 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 8aee11c47..9daed2f4a 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -17,8 +17,8 @@ use crate::hal::gpio::Port as GpioPort;
17use crate::hal::pac; 17use crate::hal::pac;
18use crate::hal::prelude::*; 18use crate::hal::prelude::*;
19use crate::hal::target_constants::EASY_DMA_SIZE; 19use crate::hal::target_constants::EASY_DMA_SIZE;
20use crate::interrupt;
21use crate::interrupt::OwnedInterrupt; 20use crate::interrupt::OwnedInterrupt;
21use crate::{interrupt, util};
22 22
23pub use crate::hal::uarte::Pins; 23pub use crate::hal::uarte::Pins;
24// Re-export SVD variants to allow user to directly set values. 24// Re-export SVD variants to allow user to directly set values.
@@ -131,6 +131,8 @@ where
131 } 131 }
132 132
133 pub fn free(self) -> (T, T::Interrupt, Pins) { 133 pub fn free(self) -> (T, T::Interrupt, Pins) {
134 // Wait for the peripheral to be disabled from the ISR.
135 while self.instance.enable.read().enable().is_enabled() {}
134 (self.instance, self.irq, self.pins) 136 (self.instance, self.irq, self.pins)
135 } 137 }
136 138
@@ -156,6 +158,13 @@ where
156 uarte.events_endtx.reset(); 158 uarte.events_endtx.reset();
157 trace!("endtx"); 159 trace!("endtx");
158 compiler_fence(Ordering::SeqCst); 160 compiler_fence(Ordering::SeqCst);
161
162 if uarte.events_txstarted.read().bits() != 0 {
163 // The ENDTX was signal triggered because DMA has finished.
164 uarte.events_txstarted.reset();
165 try_disable = true;
166 }
167
159 T::state().tx_done.signal(()); 168 T::state().tx_done.signal(());
160 } 169 }
161 170
@@ -170,6 +179,13 @@ where
170 trace!("endrx"); 179 trace!("endrx");
171 let len = uarte.rxd.amount.read().bits(); 180 let len = uarte.rxd.amount.read().bits();
172 compiler_fence(Ordering::SeqCst); 181 compiler_fence(Ordering::SeqCst);
182
183 if uarte.events_rxstarted.read().bits() != 0 {
184 // The ENDRX was signal triggered because DMA buffer is full.
185 uarte.events_rxstarted.reset();
186 try_disable = true;
187 }
188
173 T::state().rx_done.signal(len); 189 T::state().rx_done.signal(len);
174 } 190 }
175 191
@@ -204,7 +220,7 @@ impl<T: Instance> embassy::uart::Uart for Uarte<T> {
204 // `mem::forget()` on a previous future after polling it once. 220 // `mem::forget()` on a previous future after polling it once.
205 assert!(!self.tx_started()); 221 assert!(!self.tx_started());
206 222
207 self.enable(); 223 T::state().tx_done.reset();
208 224
209 SendFuture { 225 SendFuture {
210 uarte: self, 226 uarte: self,
@@ -227,7 +243,7 @@ impl<T: Instance> embassy::uart::Uart for Uarte<T> {
227 // `mem::forget()` on a previous future after polling it once. 243 // `mem::forget()` on a previous future after polling it once.
228 assert!(!self.rx_started()); 244 assert!(!self.rx_started());
229 245
230 self.enable(); 246 T::state().rx_done.reset();
231 247
232 ReceiveFuture { 248 ReceiveFuture {
233 uarte: self, 249 uarte: self,
@@ -241,7 +257,7 @@ pub struct SendFuture<'a, T>
241where 257where
242 T: Instance, 258 T: Instance,
243{ 259{
244 uarte: &'a Uarte<T>, 260 uarte: &'a mut Uarte<T>,
245 buf: &'a [u8], 261 buf: &'a [u8],
246} 262}
247 263
@@ -259,7 +275,9 @@ where
259 .instance 275 .instance
260 .tasks_stoptx 276 .tasks_stoptx
261 .write(|w| unsafe { w.bits(1) }); 277 .write(|w| unsafe { w.bits(1) });
262 T::state().tx_done.blocking_wait(); 278
279 // TX is stopped almost instantly, spinning is fine.
280 while !T::state().tx_done.signaled() {}
263 } 281 }
264 } 282 }
265} 283}
@@ -273,28 +291,34 @@ where
273 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 291 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
274 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; 292 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
275 293
276 if !uarte.tx_started() { 294 if T::state().tx_done.poll_wait(cx).is_pending() {
277 let uarte = &uarte.instance;
278
279 T::state().tx_done.reset();
280
281 let ptr = buf.as_ptr(); 295 let ptr = buf.as_ptr();
282 let len = buf.len(); 296 let len = buf.len();
283 assert!(len <= EASY_DMA_SIZE); 297 assert!(len <= EASY_DMA_SIZE);
284 // TODO: panic if buffer is not in SRAM 298 // TODO: panic if buffer is not in SRAM
285 299
300 uarte.enable();
301
286 compiler_fence(Ordering::SeqCst); 302 compiler_fence(Ordering::SeqCst);
287 uarte.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
288 uarte 303 uarte
304 .instance
305 .txd
306 .ptr
307 .write(|w| unsafe { w.ptr().bits(ptr as u32) });
308 uarte
309 .instance
289 .txd 310 .txd
290 .maxcnt 311 .maxcnt
291 .write(|w| unsafe { w.maxcnt().bits(len as _) }); 312 .write(|w| unsafe { w.maxcnt().bits(len as _) });
292 313
293 trace!("starttx"); 314 trace!("starttx");
294 uarte.tasks_starttx.write(|w| unsafe { w.bits(1) }); 315 uarte.instance.tasks_starttx.write(|w| unsafe { w.bits(1) });
295 } 316 while !uarte.tx_started() {} // Make sure transmission has started
296 317
297 T::state().tx_done.poll_wait(cx).map(|()| Ok(())) 318 Poll::Pending
319 } else {
320 Poll::Ready(Ok(()))
321 }
298 } 322 }
299} 323}
300 324
@@ -303,7 +327,7 @@ pub struct ReceiveFuture<'a, T>
303where 327where
304 T: Instance, 328 T: Instance,
305{ 329{
306 uarte: &'a Uarte<T>, 330 uarte: &'a mut Uarte<T>,
307 buf: &'a mut [u8], 331 buf: &'a mut [u8],
308} 332}
309 333
@@ -313,14 +337,15 @@ where
313{ 337{
314 fn drop(self: &mut Self) { 338 fn drop(self: &mut Self) {
315 if self.uarte.rx_started() { 339 if self.uarte.rx_started() {
316 trace!("stoprx"); 340 trace!("stoprx (drop)");
317 341
318 self.uarte.instance.events_rxstarted.reset(); 342 self.uarte.instance.events_rxstarted.reset();
319 self.uarte 343 self.uarte
320 .instance 344 .instance
321 .tasks_stoprx 345 .tasks_stoprx
322 .write(|w| unsafe { w.bits(1) }); 346 .write(|w| unsafe { w.bits(1) });
323 T::state().rx_done.blocking_wait(); 347
348 util::low_power_wait_until(|| T::state().rx_done.signaled())
324 } 349 }
325 } 350 }
326} 351}
@@ -334,27 +359,35 @@ where
334 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 359 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
335 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() }; 360 let Self { uarte, buf } = unsafe { self.get_unchecked_mut() };
336 361
337 if !uarte.rx_started() { 362 match T::state().rx_done.poll_wait(cx) {
338 let uarte = &uarte.instance; 363 Poll::Pending if !uarte.rx_started() => {
339 364 let ptr = buf.as_ptr();
340 T::state().rx_done.reset(); 365 let len = buf.len();
341 366 assert!(len <= EASY_DMA_SIZE);
342 let ptr = buf.as_ptr(); 367
343 let len = buf.len(); 368 uarte.enable();
344 assert!(len <= EASY_DMA_SIZE); 369
345 370 compiler_fence(Ordering::SeqCst);
346 compiler_fence(Ordering::SeqCst); 371 uarte
347 uarte.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); 372 .instance
348 uarte 373 .rxd
349 .rxd 374 .ptr
350 .maxcnt 375 .write(|w| unsafe { w.ptr().bits(ptr as u32) });
351 .write(|w| unsafe { w.maxcnt().bits(len as _) }); 376 uarte
352 377 .instance
353 trace!("startrx"); 378 .rxd
354 uarte.tasks_startrx.write(|w| unsafe { w.bits(1) }); 379 .maxcnt
380 .write(|w| unsafe { w.maxcnt().bits(len as _) });
381
382 trace!("startrx");
383 uarte.instance.tasks_startrx.write(|w| unsafe { w.bits(1) });
384 while !uarte.rx_started() {} // Make sure reception has started
385
386 Poll::Pending
387 }
388 Poll::Pending => Poll::Pending,
389 Poll::Ready(_) => Poll::Ready(Ok(())),
355 } 390 }
356
357 T::state().rx_done.poll_wait(cx).map(|_| Ok(()))
358 } 391 }
359} 392}
360 393
@@ -365,8 +398,19 @@ where
365{ 398{
366 /// Stops the ongoing reception and returns the number of bytes received. 399 /// Stops the ongoing reception and returns the number of bytes received.
367 pub async fn stop(self) -> usize { 400 pub async fn stop(self) -> usize {
368 drop(self); 401 let len = if self.uarte.rx_started() {
369 let len = T::state().rx_done.wait().await; 402 trace!("stoprx (stop)");
403
404 self.uarte.instance.events_rxstarted.reset();
405 self.uarte
406 .instance
407 .tasks_stoprx
408 .write(|w| unsafe { w.bits(1) });
409 T::state().rx_done.wait().await
410 } else {
411 // Transfer was stopped before it even started. No bytes were sent.
412 0
413 };
370 len as _ 414 len as _
371 } 415 }
372} 416}
diff --git a/embassy-nrf/src/util/mod.rs b/embassy-nrf/src/util/mod.rs
index 2fd5453d3..cf3306545 100644
--- a/embassy-nrf/src/util/mod.rs
+++ b/embassy-nrf/src/util/mod.rs
@@ -1,2 +1,12 @@
1pub mod peripheral; 1pub mod peripheral;
2pub mod ring_buffer; 2pub mod ring_buffer;
3
4/// Low power blocking wait loop using WFE/SEV.
5pub fn low_power_wait_until(mut condition: impl FnMut() -> bool) {
6 while !condition() {
7 // WFE might "eat" an event that would have otherwise woken the executor.
8 cortex_m::asm::wfe();
9 }
10 // Retrigger an event to be transparent to the executor.
11 cortex_m::asm::sev();
12}