aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-02-01 00:48:33 +0100
committerDario Nieuwenhuis <[email protected]>2023-02-01 01:17:41 +0100
commitb5cf332cc076a0de11ce6a0563a2235c9e57eb5c (patch)
treece14e014dfbe8c3764040d7f9f1ffee84ab5747b /embassy-nrf/src
parentca10fe7135d10084e38038f3cd433da39e505bea (diff)
nrf: docs.
Diffstat (limited to 'embassy-nrf/src')
-rw-r--r--embassy-nrf/src/buffered_uarte.rs9
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs1
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs1
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs1
-rw-r--r--embassy-nrf/src/gpio.rs2
-rw-r--r--embassy-nrf/src/gpiote.rs53
-rw-r--r--embassy-nrf/src/i2s.rs109
-rw-r--r--embassy-nrf/src/lib.rs46
-rw-r--r--embassy-nrf/src/nvmc.rs2
-rw-r--r--embassy-nrf/src/pdm.rs14
-rw-r--r--embassy-nrf/src/ppi/dppi.rs3
-rw-r--r--embassy-nrf/src/ppi/mod.rs2
-rw-r--r--embassy-nrf/src/ppi/ppi.rs2
-rw-r--r--embassy-nrf/src/pwm.rs22
-rw-r--r--embassy-nrf/src/qdec.rs37
-rw-r--r--embassy-nrf/src/qspi.rs42
-rw-r--r--embassy-nrf/src/rng.rs6
-rw-r--r--embassy-nrf/src/saadc.rs56
-rw-r--r--embassy-nrf/src/spim.rs33
-rw-r--r--embassy-nrf/src/spis.rs36
-rw-r--r--embassy-nrf/src/temp.rs5
-rw-r--r--embassy-nrf/src/timer.rs36
-rw-r--r--embassy-nrf/src/twim.rs73
-rw-r--r--embassy-nrf/src/twis.rs57
-rw-r--r--embassy-nrf/src/uarte.rs76
-rw-r--r--embassy-nrf/src/usb.rs90
-rw-r--r--embassy-nrf/src/wdt.rs8
27 files changed, 602 insertions, 220 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index ea25236f0..112f084c1 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -1,4 +1,4 @@
1//! Async buffered UART 1//! Async buffered UART driver.
2//! 2//!
3//! WARNING!!! The functionality provided here is intended to be used only 3//! WARNING!!! The functionality provided here is intended to be used only
4//! in situations where hardware flow control are available i.e. CTS and RTS. 4//! in situations where hardware flow control are available i.e. CTS and RTS.
@@ -69,7 +69,7 @@ struct StateInner<'d, U: UarteInstance, T: TimerInstance> {
69 tx_waker: WakerRegistration, 69 tx_waker: WakerRegistration,
70} 70}
71 71
72/// Interface to a UARTE instance 72/// Buffered UARTE driver.
73pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { 73pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
74 inner: RefCell<PeripheralMutex<'d, StateInner<'d, U, T>>>, 74 inner: RefCell<PeripheralMutex<'d, StateInner<'d, U, T>>>,
75} 75}
@@ -199,6 +199,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
199 }); 199 });
200 } 200 }
201 201
202 /// Split the UART in reader and writer parts.
203 ///
204 /// This allows reading and writing concurrently from independent tasks.
202 pub fn split<'u>(&'u mut self) -> (BufferedUarteRx<'u, 'd, U, T>, BufferedUarteTx<'u, 'd, U, T>) { 205 pub fn split<'u>(&'u mut self) -> (BufferedUarteRx<'u, 'd, U, T>, BufferedUarteTx<'u, 'd, U, T>) {
203 (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) 206 (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self })
204 } 207 }
@@ -320,10 +323,12 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
320 } 323 }
321} 324}
322 325
326/// Reader part of the buffered UARTE driver.
323pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> { 327pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> {
324 inner: &'u BufferedUarte<'d, U, T>, 328 inner: &'u BufferedUarte<'d, U, T>,
325} 329}
326 330
331/// Writer part of the buffered UARTE driver.
327pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> { 332pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> {
328 inner: &'u BufferedUarte<'d, U, T>, 333 inner: &'u BufferedUarte<'d, U, T>,
329} 334}
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 4575f09ff..c600fcbf6 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -1,3 +1,4 @@
1/// Peripheral Access Crate
1#[allow(unused_imports)] 2#[allow(unused_imports)]
2#[rustfmt::skip] 3#[rustfmt::skip]
3pub mod pac { 4pub mod pac {
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 54827238a..a46583eca 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -1,3 +1,4 @@
1/// Peripheral Access Crate
1#[allow(unused_imports)] 2#[allow(unused_imports)]
2#[rustfmt::skip] 3#[rustfmt::skip]
3pub mod pac { 4pub mod pac {
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index 472ee6772..e1509ddde 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -1,3 +1,4 @@
1/// Peripheral Access Crate
1#[allow(unused_imports)] 2#[allow(unused_imports)]
2#[rustfmt::skip] 3#[rustfmt::skip]
3pub mod pac { 4pub mod pac {
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index 6ef5033eb..895ab9340 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -1,4 +1,4 @@
1//! General purpose input/output for nRF. 1//! General purpose input/output (GPIO) driver.
2#![macro_use] 2#![macro_use]
3 3
4use core::convert::Infallible; 4use core::convert::Infallible;
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 7467dbc60..e1816eb9b 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -1,3 +1,5 @@
1//! GPIO task/event (GPIOTE) driver.
2
1use core::convert::Infallible; 3use core::convert::Infallible;
2use core::future::{poll_fn, Future}; 4use core::future::{poll_fn, Future};
3use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
@@ -11,29 +13,38 @@ use crate::interrupt::{Interrupt, InterruptExt};
11use crate::ppi::{Event, Task}; 13use crate::ppi::{Event, Task};
12use crate::{interrupt, pac, peripherals}; 14use crate::{interrupt, pac, peripherals};
13 15
14pub const CHANNEL_COUNT: usize = 8; 16/// Amount of GPIOTE channels in the chip.
17const CHANNEL_COUNT: usize = 8;
15 18
16#[cfg(any(feature = "nrf52833", feature = "nrf52840"))] 19#[cfg(any(feature = "nrf52833", feature = "nrf52840"))]
17pub const PIN_COUNT: usize = 48; 20const PIN_COUNT: usize = 48;
18#[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] 21#[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))]
19pub const PIN_COUNT: usize = 32; 22const PIN_COUNT: usize = 32;
20 23
21#[allow(clippy::declare_interior_mutable_const)] 24#[allow(clippy::declare_interior_mutable_const)]
22const NEW_AW: AtomicWaker = AtomicWaker::new(); 25const NEW_AW: AtomicWaker = AtomicWaker::new();
23static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; 26static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT];
24static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT]; 27static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT];
25 28
29/// Polarity for listening to events for GPIOTE input channels.
26pub enum InputChannelPolarity { 30pub enum InputChannelPolarity {
31 /// Don't listen for any pin changes.
27 None, 32 None,
33 /// Listen for high to low changes.
28 HiToLo, 34 HiToLo,
35 /// Listen for low to high changes.
29 LoToHi, 36 LoToHi,
37 /// Listen for any change, either low to high or high to low.
30 Toggle, 38 Toggle,
31} 39}
32 40
33/// Polarity of the `task out` operation. 41/// Polarity of the OUT task operation for GPIOTE output channels.
34pub enum OutputChannelPolarity { 42pub enum OutputChannelPolarity {
43 /// Set the pin high.
35 Set, 44 Set,
45 /// Set the pin low.
36 Clear, 46 Clear,
47 /// Toggle the pin.
37 Toggle, 48 Toggle,
38} 49}
39 50
@@ -162,6 +173,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> {
162} 173}
163 174
164impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { 175impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
176 /// Create a new GPIOTE input channel driver.
165 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { 177 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self {
166 into_ref!(ch); 178 into_ref!(ch);
167 179
@@ -188,6 +200,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> {
188 InputChannel { ch, pin } 200 InputChannel { ch, pin }
189 } 201 }
190 202
203 /// Asynchronously wait for an event in this channel.
191 pub async fn wait(&self) { 204 pub async fn wait(&self) {
192 let g = regs(); 205 let g = regs();
193 let num = self.ch.number(); 206 let num = self.ch.number();
@@ -231,6 +244,7 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> {
231} 244}
232 245
233impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { 246impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
247 /// Create a new GPIOTE output channel driver.
234 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { 248 pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self {
235 into_ref!(ch); 249 into_ref!(ch);
236 let g = regs(); 250 let g = regs();
@@ -258,20 +272,20 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> {
258 OutputChannel { ch, _pin: pin } 272 OutputChannel { ch, _pin: pin }
259 } 273 }
260 274
261 /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). 275 /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle).
262 pub fn out(&self) { 276 pub fn out(&self) {
263 let g = regs(); 277 let g = regs();
264 g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) }); 278 g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) });
265 } 279 }
266 280
267 /// Triggers `task set` (set associated pin high). 281 /// Triggers the SET task (set associated pin high).
268 #[cfg(not(feature = "nrf51"))] 282 #[cfg(not(feature = "nrf51"))]
269 pub fn set(&self) { 283 pub fn set(&self) {
270 let g = regs(); 284 let g = regs();
271 g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) }); 285 g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) });
272 } 286 }
273 287
274 /// Triggers `task clear` (set associated pin low). 288 /// Triggers the CLEAR task (set associated pin low).
275 #[cfg(not(feature = "nrf51"))] 289 #[cfg(not(feature = "nrf51"))]
276 pub fn clear(&self) { 290 pub fn clear(&self) {
277 let g = regs(); 291 let g = regs();
@@ -336,48 +350,58 @@ impl<'a> Future for PortInputFuture<'a> {
336} 350}
337 351
338impl<'d, T: GpioPin> Input<'d, T> { 352impl<'d, T: GpioPin> Input<'d, T> {
353 /// Wait until the pin is high. If it is already high, return immediately.
339 pub async fn wait_for_high(&mut self) { 354 pub async fn wait_for_high(&mut self) {
340 self.pin.wait_for_high().await 355 self.pin.wait_for_high().await
341 } 356 }
342 357
358 /// Wait until the pin is low. If it is already low, return immediately.
343 pub async fn wait_for_low(&mut self) { 359 pub async fn wait_for_low(&mut self) {
344 self.pin.wait_for_low().await 360 self.pin.wait_for_low().await
345 } 361 }
346 362
363 /// Wait for the pin to undergo a transition from low to high.
347 pub async fn wait_for_rising_edge(&mut self) { 364 pub async fn wait_for_rising_edge(&mut self) {
348 self.pin.wait_for_rising_edge().await 365 self.pin.wait_for_rising_edge().await
349 } 366 }
350 367
368 /// Wait for the pin to undergo a transition from high to low.
351 pub async fn wait_for_falling_edge(&mut self) { 369 pub async fn wait_for_falling_edge(&mut self) {
352 self.pin.wait_for_falling_edge().await 370 self.pin.wait_for_falling_edge().await
353 } 371 }
354 372
373 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
355 pub async fn wait_for_any_edge(&mut self) { 374 pub async fn wait_for_any_edge(&mut self) {
356 self.pin.wait_for_any_edge().await 375 self.pin.wait_for_any_edge().await
357 } 376 }
358} 377}
359 378
360impl<'d, T: GpioPin> Flex<'d, T> { 379impl<'d, T: GpioPin> Flex<'d, T> {
380 /// Wait until the pin is high. If it is already high, return immediately.
361 pub async fn wait_for_high(&mut self) { 381 pub async fn wait_for_high(&mut self) {
362 self.pin.conf().modify(|_, w| w.sense().high()); 382 self.pin.conf().modify(|_, w| w.sense().high());
363 PortInputFuture::new(&mut self.pin).await 383 PortInputFuture::new(&mut self.pin).await
364 } 384 }
365 385
386 /// Wait until the pin is low. If it is already low, return immediately.
366 pub async fn wait_for_low(&mut self) { 387 pub async fn wait_for_low(&mut self) {
367 self.pin.conf().modify(|_, w| w.sense().low()); 388 self.pin.conf().modify(|_, w| w.sense().low());
368 PortInputFuture::new(&mut self.pin).await 389 PortInputFuture::new(&mut self.pin).await
369 } 390 }
370 391
392 /// Wait for the pin to undergo a transition from low to high.
371 pub async fn wait_for_rising_edge(&mut self) { 393 pub async fn wait_for_rising_edge(&mut self) {
372 self.wait_for_low().await; 394 self.wait_for_low().await;
373 self.wait_for_high().await; 395 self.wait_for_high().await;
374 } 396 }
375 397
398 /// Wait for the pin to undergo a transition from high to low.
376 pub async fn wait_for_falling_edge(&mut self) { 399 pub async fn wait_for_falling_edge(&mut self) {
377 self.wait_for_high().await; 400 self.wait_for_high().await;
378 self.wait_for_low().await; 401 self.wait_for_low().await;
379 } 402 }
380 403
404 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
381 pub async fn wait_for_any_edge(&mut self) { 405 pub async fn wait_for_any_edge(&mut self) {
382 if self.is_high() { 406 if self.is_high() {
383 self.pin.conf().modify(|_, w| w.sense().low()); 407 self.pin.conf().modify(|_, w| w.sense().low());
@@ -394,8 +418,17 @@ mod sealed {
394 pub trait Channel {} 418 pub trait Channel {}
395} 419}
396 420
421/// GPIOTE channel trait.
422///
423/// Implemented by all GPIOTE channels.
397pub trait Channel: sealed::Channel + Sized { 424pub trait Channel: sealed::Channel + Sized {
425 /// Get the channel number.
398 fn number(&self) -> usize; 426 fn number(&self) -> usize;
427
428 /// Convert this channel to a type-erased `AnyChannel`.
429 ///
430 /// This allows using several channels in situations that might require
431 /// them to be the same type, like putting them in an array.
399 fn degrade(self) -> AnyChannel { 432 fn degrade(self) -> AnyChannel {
400 AnyChannel { 433 AnyChannel {
401 number: self.number() as u8, 434 number: self.number() as u8,
@@ -403,6 +436,12 @@ pub trait Channel: sealed::Channel + Sized {
403 } 436 }
404} 437}
405 438
439/// Type-erased channel.
440///
441/// Obtained by calling `Channel::degrade`.
442///
443/// This allows using several channels in situations that might require
444/// them to be the same type, like putting them in an array.
406pub struct AnyChannel { 445pub struct AnyChannel {
407 number: u8, 446 number: u8,
408} 447}
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index 7e9507751..770df7c89 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1//! Inter-IC Sound (I2S) driver.
2 2
3//! Support for I2S audio 3#![macro_use]
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
@@ -19,16 +19,23 @@ use crate::pac::i2s::RegisterBlock;
19use crate::util::{slice_in_ram_or, slice_ptr_parts}; 19use crate::util::{slice_in_ram_or, slice_ptr_parts};
20use crate::{Peripheral, EASY_DMA_SIZE}; 20use crate::{Peripheral, EASY_DMA_SIZE};
21 21
22/// Type alias for `MultiBuffering` with 2 buffers.
22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; 23pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
23 24
25/// I2S transfer error.
24#[derive(Debug, Clone, Copy, PartialEq, Eq)] 26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))] 27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[non_exhaustive] 28#[non_exhaustive]
27pub enum Error { 29pub enum Error {
30 /// The buffer is too long.
28 BufferTooLong, 31 BufferTooLong,
32 /// The buffer is empty.
29 BufferZeroLength, 33 BufferZeroLength,
30 BufferNotInDataMemory, 34 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
35 BufferNotInRAM,
36 /// The buffer address is not aligned.
31 BufferMisaligned, 37 BufferMisaligned,
38 /// The buffer length is not a multiple of the alignment.
32 BufferLengthMisaligned, 39 BufferLengthMisaligned,
33} 40}
34 41
@@ -36,34 +43,16 @@ pub enum Error {
36#[derive(Clone)] 43#[derive(Clone)]
37#[non_exhaustive] 44#[non_exhaustive]
38pub struct Config { 45pub struct Config {
46 /// Sample width
39 pub sample_width: SampleWidth, 47 pub sample_width: SampleWidth,
48 /// Alignment
40 pub align: Align, 49 pub align: Align,
50 /// Sample format
41 pub format: Format, 51 pub format: Format,
52 /// Channel configuration.
42 pub channels: Channels, 53 pub channels: Channels,
43} 54}
44 55
45impl Config {
46 pub fn sample_width(mut self, sample_width: SampleWidth) -> Self {
47 self.sample_width = sample_width;
48 self
49 }
50
51 pub fn align(mut self, align: Align) -> Self {
52 self.align = align;
53 self
54 }
55
56 pub fn format(mut self, format: Format) -> Self {
57 self.format = format;
58 self
59 }
60
61 pub fn channels(mut self, channels: Channels) -> Self {
62 self.channels = channels;
63 self
64 }
65}
66
67impl Default for Config { 56impl Default for Config {
68 fn default() -> Self { 57 fn default() -> Self {
69 Self { 58 Self {
@@ -75,7 +64,7 @@ impl Default for Config {
75 } 64 }
76} 65}
77 66
78/// I2S Mode 67/// I2S clock configuration.
79#[derive(Debug, Eq, PartialEq, Clone, Copy)] 68#[derive(Debug, Eq, PartialEq, Clone, Copy)]
80pub struct MasterClock { 69pub struct MasterClock {
81 freq: MckFreq, 70 freq: MckFreq,
@@ -83,12 +72,14 @@ pub struct MasterClock {
83} 72}
84 73
85impl MasterClock { 74impl MasterClock {
75 /// Create a new `MasterClock`.
86 pub fn new(freq: MckFreq, ratio: Ratio) -> Self { 76 pub fn new(freq: MckFreq, ratio: Ratio) -> Self {
87 Self { freq, ratio } 77 Self { freq, ratio }
88 } 78 }
89} 79}
90 80
91impl MasterClock { 81impl MasterClock {
82 /// Get the sample rate for this clock configuration.
92 pub fn sample_rate(&self) -> u32 { 83 pub fn sample_rate(&self) -> u32 {
93 self.freq.to_frequency() / self.ratio.to_divisor() 84 self.freq.to_frequency() / self.ratio.to_divisor()
94 } 85 }
@@ -97,18 +88,31 @@ impl MasterClock {
97/// Master clock generator frequency. 88/// Master clock generator frequency.
98#[derive(Debug, Eq, PartialEq, Clone, Copy)] 89#[derive(Debug, Eq, PartialEq, Clone, Copy)]
99pub enum MckFreq { 90pub enum MckFreq {
91 /// 32 Mhz / 8 = 4000.00 kHz
100 _32MDiv8, 92 _32MDiv8,
93 /// 32 Mhz / 10 = 3200.00 kHz
101 _32MDiv10, 94 _32MDiv10,
95 /// 32 Mhz / 11 = 2909.09 kHz
102 _32MDiv11, 96 _32MDiv11,
97 /// 32 Mhz / 15 = 2133.33 kHz
103 _32MDiv15, 98 _32MDiv15,
99 /// 32 Mhz / 16 = 2000.00 kHz
104 _32MDiv16, 100 _32MDiv16,
101 /// 32 Mhz / 21 = 1523.81 kHz
105 _32MDiv21, 102 _32MDiv21,
103 /// 32 Mhz / 23 = 1391.30 kHz
106 _32MDiv23, 104 _32MDiv23,
105 /// 32 Mhz / 30 = 1066.67 kHz
107 _32MDiv30, 106 _32MDiv30,
107 /// 32 Mhz / 31 = 1032.26 kHz
108 _32MDiv31, 108 _32MDiv31,
109 /// 32 Mhz / 32 = 1000.00 kHz
109 _32MDiv32, 110 _32MDiv32,
111 /// 32 Mhz / 42 = 761.90 kHz
110 _32MDiv42, 112 _32MDiv42,
113 /// 32 Mhz / 63 = 507.94 kHz
111 _32MDiv63, 114 _32MDiv63,
115 /// 32 Mhz / 125 = 256.00 kHz
112 _32MDiv125, 116 _32MDiv125,
113} 117}
114 118
@@ -146,14 +150,23 @@ impl From<MckFreq> for usize {
146/// 150///
147#[derive(Debug, Eq, PartialEq, Clone, Copy)] 151#[derive(Debug, Eq, PartialEq, Clone, Copy)]
148pub enum Ratio { 152pub enum Ratio {
153 /// Divide by 32
149 _32x, 154 _32x,
155 /// Divide by 48
150 _48x, 156 _48x,
157 /// Divide by 64
151 _64x, 158 _64x,
159 /// Divide by 96
152 _96x, 160 _96x,
161 /// Divide by 128
153 _128x, 162 _128x,
163 /// Divide by 192
154 _192x, 164 _192x,
165 /// Divide by 256
155 _256x, 166 _256x,
167 /// Divide by 384
156 _384x, 168 _384x,
169 /// Divide by 512
157 _512x, 170 _512x,
158} 171}
159 172
@@ -165,6 +178,7 @@ impl Ratio {
165 usize::from(*self) as u8 178 usize::from(*self) as u8
166 } 179 }
167 180
181 /// Return the divisor for this ratio
168 pub fn to_divisor(&self) -> u32 { 182 pub fn to_divisor(&self) -> u32 {
169 Self::RATIOS[usize::from(*self)] 183 Self::RATIOS[usize::from(*self)]
170 } 184 }
@@ -183,11 +197,17 @@ impl From<Ratio> for usize {
183/// For custom master clock configuration, please refer to [MasterClock]. 197/// For custom master clock configuration, please refer to [MasterClock].
184#[derive(Clone, Copy)] 198#[derive(Clone, Copy)]
185pub enum ApproxSampleRate { 199pub enum ApproxSampleRate {
200 /// 11025 Hz
186 _11025, 201 _11025,
202 /// 16000 Hz
187 _16000, 203 _16000,
204 /// 22050 Hz
188 _22050, 205 _22050,
206 /// 32000 Hz
189 _32000, 207 _32000,
208 /// 44100 Hz
190 _44100, 209 _44100,
210 /// 48000 Hz
191 _48000, 211 _48000,
192} 212}
193 213
@@ -211,6 +231,7 @@ impl From<ApproxSampleRate> for MasterClock {
211} 231}
212 232
213impl ApproxSampleRate { 233impl ApproxSampleRate {
234 /// Get the sample rate as an integer.
214 pub fn sample_rate(&self) -> u32 { 235 pub fn sample_rate(&self) -> u32 {
215 MasterClock::from(*self).sample_rate() 236 MasterClock::from(*self).sample_rate()
216 } 237 }
@@ -223,20 +244,32 @@ impl ApproxSampleRate {
223/// For custom master clock configuration, please refer to [Mode]. 244/// For custom master clock configuration, please refer to [Mode].
224#[derive(Clone, Copy)] 245#[derive(Clone, Copy)]
225pub enum ExactSampleRate { 246pub enum ExactSampleRate {
247 /// 8000 Hz
226 _8000, 248 _8000,
249 /// 10582 Hz
227 _10582, 250 _10582,
251 /// 12500 Hz
228 _12500, 252 _12500,
253 /// 15625 Hz
229 _15625, 254 _15625,
255 /// 15873 Hz
230 _15873, 256 _15873,
257 /// 25000 Hz
231 _25000, 258 _25000,
259 /// 31250 Hz
232 _31250, 260 _31250,
261 /// 50000 Hz
233 _50000, 262 _50000,
263 /// 62500 Hz
234 _62500, 264 _62500,
265 /// 100000 Hz
235 _100000, 266 _100000,
267 /// 125000 Hz
236 _125000, 268 _125000,
237} 269}
238 270
239impl ExactSampleRate { 271impl ExactSampleRate {
272 /// Get the sample rate as an integer.
240 pub fn sample_rate(&self) -> u32 { 273 pub fn sample_rate(&self) -> u32 {
241 MasterClock::from(*self).sample_rate() 274 MasterClock::from(*self).sample_rate()
242 } 275 }
@@ -263,8 +296,11 @@ impl From<ExactSampleRate> for MasterClock {
263/// Sample width. 296/// Sample width.
264#[derive(Debug, Eq, PartialEq, Clone, Copy)] 297#[derive(Debug, Eq, PartialEq, Clone, Copy)]
265pub enum SampleWidth { 298pub enum SampleWidth {
299 /// 8 bit samples.
266 _8bit, 300 _8bit,
301 /// 16 bit samples.
267 _16bit, 302 _16bit,
303 /// 24 bit samples.
268 _24bit, 304 _24bit,
269} 305}
270 306
@@ -277,7 +313,9 @@ impl From<SampleWidth> for u8 {
277/// Channel used for the most significant sample value in a frame. 313/// Channel used for the most significant sample value in a frame.
278#[derive(Debug, Eq, PartialEq, Clone, Copy)] 314#[derive(Debug, Eq, PartialEq, Clone, Copy)]
279pub enum Align { 315pub enum Align {
316 /// Left-align samples.
280 Left, 317 Left,
318 /// Right-align samples.
281 Right, 319 Right,
282} 320}
283 321
@@ -293,7 +331,9 @@ impl From<Align> for bool {
293/// Frame format. 331/// Frame format.
294#[derive(Debug, Eq, PartialEq, Clone, Copy)] 332#[derive(Debug, Eq, PartialEq, Clone, Copy)]
295pub enum Format { 333pub enum Format {
334 /// I2S frame format
296 I2S, 335 I2S,
336 /// Aligned frame format
297 Aligned, 337 Aligned,
298} 338}
299 339
@@ -309,8 +349,11 @@ impl From<Format> for bool {
309/// Channels 349/// Channels
310#[derive(Debug, Eq, PartialEq, Clone, Copy)] 350#[derive(Debug, Eq, PartialEq, Clone, Copy)]
311pub enum Channels { 351pub enum Channels {
352 /// Stereo (2 channels).
312 Stereo, 353 Stereo,
354 /// Mono, left channel only.
313 MonoLeft, 355 MonoLeft,
356 /// Mono, right channel only.
314 MonoRight, 357 MonoRight,
315} 358}
316 359
@@ -320,7 +363,7 @@ impl From<Channels> for u8 {
320 } 363 }
321} 364}
322 365
323/// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload. 366/// I2S driver.
324pub struct I2S<'d, T: Instance> { 367pub struct I2S<'d, T: Instance> {
325 i2s: PeripheralRef<'d, T>, 368 i2s: PeripheralRef<'d, T>,
326 irq: PeripheralRef<'d, T::Interrupt>, 369 irq: PeripheralRef<'d, T::Interrupt>,
@@ -566,7 +609,7 @@ impl<'d, T: Instance> I2S<'d, T> {
566 { 609 {
567 trace!("SEND: {}", buffer_ptr as *const S as u32); 610 trace!("SEND: {}", buffer_ptr as *const S as u32);
568 611
569 slice_in_ram_or(buffer_ptr, Error::BufferNotInDataMemory)?; 612 slice_in_ram_or(buffer_ptr, Error::BufferNotInRAM)?;
570 613
571 compiler_fence(Ordering::SeqCst); 614 compiler_fence(Ordering::SeqCst);
572 615
@@ -1003,7 +1046,10 @@ impl<T: Instance> Device<T> {
1003 1046
1004/// Sample details 1047/// Sample details
1005pub trait Sample: Sized + Copy + Default { 1048pub trait Sample: Sized + Copy + Default {
1049 /// Width of this sample type.
1006 const WIDTH: usize; 1050 const WIDTH: usize;
1051
1052 /// Scale of this sample.
1007 const SCALE: Self; 1053 const SCALE: Self;
1008} 1054}
1009 1055
@@ -1022,12 +1068,13 @@ impl Sample for i32 {
1022 const SCALE: Self = 1 << (Self::WIDTH - 1); 1068 const SCALE: Self = 1 << (Self::WIDTH - 1);
1023} 1069}
1024 1070
1025/// A 4-bytes aligned buffer. 1071/// A 4-bytes aligned buffer. Needed for DMA access.
1026#[derive(Clone, Copy)] 1072#[derive(Clone, Copy)]
1027#[repr(align(4))] 1073#[repr(align(4))]
1028pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]); 1074pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]);
1029 1075
1030impl<T: Sample, const N: usize> AlignedBuffer<T, N> { 1076impl<T: Sample, const N: usize> AlignedBuffer<T, N> {
1077 /// Create a new `AlignedBuffer`.
1031 pub fn new(array: [T; N]) -> Self { 1078 pub fn new(array: [T; N]) -> Self {
1032 Self(array) 1079 Self(array)
1033 } 1080 }
@@ -1052,12 +1099,14 @@ impl<T: Sample, const N: usize> DerefMut for AlignedBuffer<T, N> {
1052 } 1099 }
1053} 1100}
1054 1101
1102/// Set of multiple buffers, for multi-buffering transfers.
1055pub struct MultiBuffering<S: Sample, const NB: usize, const NS: usize> { 1103pub struct MultiBuffering<S: Sample, const NB: usize, const NS: usize> {
1056 buffers: [AlignedBuffer<S, NS>; NB], 1104 buffers: [AlignedBuffer<S, NS>; NB],
1057 index: usize, 1105 index: usize,
1058} 1106}
1059 1107
1060impl<S: Sample, const NB: usize, const NS: usize> MultiBuffering<S, NB, NS> { 1108impl<S: Sample, const NB: usize, const NS: usize> MultiBuffering<S, NB, NS> {
1109 /// Create a new `MultiBuffering`.
1061 pub fn new() -> Self { 1110 pub fn new() -> Self {
1062 assert!(NB > 1); 1111 assert!(NB > 1);
1063 Self { 1112 Self {
@@ -1119,7 +1168,9 @@ pub(crate) mod sealed {
1119 } 1168 }
1120} 1169}
1121 1170
1171/// I2S peripehral instance.
1122pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 1172pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
1173 /// Interrupt for this peripheral.
1123 type Interrupt: Interrupt; 1174 type Interrupt: Interrupt;
1124} 1175}
1125 1176
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 1dd0e7905..20e70a248 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -1,53 +1,11 @@
1//! # Embassy nRF HAL
2//!
3//! HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed.
4//!
5//! The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The HAL implements both blocking and async APIs
6//! for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to
7//! complete operations in low power mod and handling interrupts, so that applications can focus on more important matters.
8//!
9//! ## EasyDMA considerations
10//!
11//! On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
12//! with peripherals. It takes care of sending/receiving data over a variety of bus protocols (TWI/I2C, UART, SPI).
13//! However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust
14//! slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen:
15//!
16//! ```no_run
17//! // As we pass a slice to the function whose contents will not ever change,
18//! // the compiler writes it into the flash and thus the pointer to it will
19//! // reference static memory. Since EasyDMA requires slices to reside in RAM,
20//! // this function call will fail.
21//! let result = spim.write_from_ram(&[1, 2, 3]);
22//! assert_eq!(result, Err(Error::DMABufferNotInDataMemory));
23//!
24//! // The data is still static and located in flash. However, since we are assigning
25//! // it to a variable, the compiler will load it into memory. Passing a reference to the
26//! // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy.
27//! // This function call succeeds.
28//! let data = [1, 2, 3];
29//! let result = spim.write_from_ram(&data);
30//! assert!(result.is_ok());
31//! ```
32//!
33//! Each peripheral struct which uses EasyDMA ([`Spim`](spim::Spim), [`Uarte`](uarte::Uarte), [`Twim`](twim::Twim)) has two variants of their mutating functions:
34//! - Functions with the suffix (e.g. [`write_from_ram`](spim::Spim::write_from_ram), [`transfer_from_ram`](spim::Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM.
35//! - Functions without the suffix (e.g. [`write`](spim::Spim::write), [`transfer`](spim::Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission.
36//!
37//! Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
38//! fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
39//! more inefficient. Be aware that this overhead is not only in terms of instruction count but also in terms of memory usage
40//! as the methods without the suffix will be allocating a statically sized buffer (up to 512 bytes for the nRF52840).
41//!
42//! Note that the methods that read data like [`read`](spim::Spim::read) and [`transfer_in_place`](spim::Spim::transfer_in_place) do not have the corresponding `_from_ram` variants as
43//! mutable slices always reside in RAM.
44
45#![no_std] 1#![no_std]
46#![cfg_attr( 2#![cfg_attr(
47 feature = "nightly", 3 feature = "nightly",
48 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections) 4 feature(type_alias_impl_trait, async_fn_in_trait, impl_trait_projections)
49)] 5)]
50#![cfg_attr(feature = "nightly", allow(incomplete_features))] 6#![cfg_attr(feature = "nightly", allow(incomplete_features))]
7#![doc = include_str!("../README.md")]
8#![warn(missing_docs)]
51 9
52#[cfg(not(any( 10#[cfg(not(any(
53 feature = "nrf51", 11 feature = "nrf51",
diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs
index 405ea3171..c1ffa31aa 100644
--- a/embassy-nrf/src/nvmc.rs
+++ b/embassy-nrf/src/nvmc.rs
@@ -1,4 +1,4 @@
1//! Non-Volatile Memory Controller (NVMC) module. 1//! Non-Volatile Memory Controller (NVMC, AKA internal flash) driver.
2 2
3use core::{ptr, slice}; 3use core::{ptr, slice};
4 4
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index b7c7022cf..54feca4c1 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,4 +1,4 @@
1//! PDM mirophone interface 1//! Pulse Density Modulation (PDM) mirophone driver.
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
@@ -22,12 +22,16 @@ pub struct Pdm<'d> {
22 phantom: PhantomData<&'d PDM>, 22 phantom: PhantomData<&'d PDM>,
23} 23}
24 24
25/// PDM error.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)] 26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))] 27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27#[non_exhaustive] 28#[non_exhaustive]
28pub enum Error { 29pub enum Error {
30 /// Buffer is too long.
29 BufferTooLong, 31 BufferTooLong,
32 /// Buffer is empty
30 BufferZeroLength, 33 BufferZeroLength,
34 /// PDM is not running
31 NotRunning, 35 NotRunning,
32} 36}
33 37
@@ -119,6 +123,7 @@ impl<'d> Pdm<'d> {
119 r.events_started.reset(); 123 r.events_started.reset();
120 } 124 }
121 125
126 /// Sample data into the given buffer.
122 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { 127 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> {
123 if buffer.len() == 0 { 128 if buffer.len() == 0 {
124 return Err(Error::BufferZeroLength); 129 return Err(Error::BufferZeroLength);
@@ -215,14 +220,21 @@ impl Default for Config {
215 } 220 }
216} 221}
217 222
223/// PDM operation mode.
218#[derive(PartialEq)] 224#[derive(PartialEq)]
219pub enum OperationMode { 225pub enum OperationMode {
226 /// Mono (1 channel)
220 Mono, 227 Mono,
228 /// Stereo (2 channels)
221 Stereo, 229 Stereo,
222} 230}
231
232/// PDM edge polarity
223#[derive(PartialEq)] 233#[derive(PartialEq)]
224pub enum Edge { 234pub enum Edge {
235 /// Left edge is rising
225 LeftRising, 236 LeftRising,
237 /// Left edge is falling
226 LeftFalling, 238 LeftFalling,
227} 239}
228 240
diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs
index de856c0ca..0908cd7be 100644
--- a/embassy-nrf/src/ppi/dppi.rs
+++ b/embassy-nrf/src/ppi/dppi.rs
@@ -11,12 +11,14 @@ fn regs() -> &'static pac::dppic::RegisterBlock {
11} 11}
12 12
13impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { 13impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
14 /// Configure PPI channel to trigger `task` on `event`.
14 pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self { 15 pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self {
15 Ppi::new_many_to_many(ch, [event], [task]) 16 Ppi::new_many_to_many(ch, [event], [task])
16 } 17 }
17} 18}
18 19
19impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { 20impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
21 /// Configure PPI channel to trigger both `task1` and `task2` on `event`.
20 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self { 22 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self {
21 Ppi::new_many_to_many(ch, [event], [task1, task2]) 23 Ppi::new_many_to_many(ch, [event], [task1, task2])
22 } 24 }
@@ -25,6 +27,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
25impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usize> 27impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usize>
26 Ppi<'d, C, EVENT_COUNT, TASK_COUNT> 28 Ppi<'d, C, EVENT_COUNT, TASK_COUNT>
27{ 29{
30 /// Configure a DPPI channel to trigger all `tasks` when any of the `events` fires.
28 pub fn new_many_to_many( 31 pub fn new_many_to_many(
29 ch: impl Peripheral<P = C> + 'd, 32 ch: impl Peripheral<P = C> + 'd,
30 events: [Event; EVENT_COUNT], 33 events: [Event; EVENT_COUNT],
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 8f5ed14cd..b76eccf0b 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -1,6 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3//! HAL interface for the PPI and DPPI peripheral. 3//! Programmable Peripheral Interconnect (PPI/DPPI) driver.
4//! 4//!
5//! The (Distributed) Programmable Peripheral Interconnect interface allows for an autonomous interoperability 5//! The (Distributed) Programmable Peripheral Interconnect interface allows for an autonomous interoperability
6//! between peripherals through their events and tasks. There are fixed PPI channels and fully 6//! between peripherals through their events and tasks. There are fixed PPI channels and fully
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index 19abc4e18..a96ab50b7 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -48,7 +48,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> {
48 48
49#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task 49#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
50impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { 50impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> {
51 /// Configure PPI channel to trigger `task1` and `task2` on `event`. 51 /// Configure PPI channel to trigger both `task1` and `task2` on `event`.
52 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self { 52 pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self {
53 into_ref!(ch); 53 into_ref!(ch);
54 54
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 5f750a91e..708f23104 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -1,3 +1,5 @@
1//! Pulse Width Modulation (PWM) driver.
2
1#![macro_use] 3#![macro_use]
2 4
3use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
@@ -32,6 +34,7 @@ pub struct SequencePwm<'d, T: Instance> {
32 ch3: Option<PeripheralRef<'d, AnyPin>>, 34 ch3: Option<PeripheralRef<'d, AnyPin>>,
33} 35}
34 36
37/// PWM error
35#[derive(Debug, Clone, Copy, PartialEq, Eq)] 38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))] 39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37#[non_exhaustive] 40#[non_exhaustive]
@@ -41,7 +44,7 @@ pub enum Error {
41 /// Min Sequence count is 1 44 /// Min Sequence count is 1
42 SequenceTimesAtLeastOne, 45 SequenceTimesAtLeastOne,
43 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 46 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
44 DMABufferNotInDataMemory, 47 BufferNotInRAM,
45} 48}
46 49
47const MAX_SEQUENCE_LEN: usize = 32767; 50const MAX_SEQUENCE_LEN: usize = 32767;
@@ -358,6 +361,7 @@ pub struct Sequence<'s> {
358} 361}
359 362
360impl<'s> Sequence<'s> { 363impl<'s> Sequence<'s> {
364 /// Create a new `Sequence`
361 pub fn new(words: &'s [u16], config: SequenceConfig) -> Self { 365 pub fn new(words: &'s [u16], config: SequenceConfig) -> Self {
362 Self { words, config } 366 Self { words, config }
363 } 367 }
@@ -367,7 +371,7 @@ impl<'s> Sequence<'s> {
367/// Takes at one sequence along with its configuration. 371/// Takes at one sequence along with its configuration.
368#[non_exhaustive] 372#[non_exhaustive]
369pub struct SingleSequencer<'d, 's, T: Instance> { 373pub struct SingleSequencer<'d, 's, T: Instance> {
370 pub sequencer: Sequencer<'d, 's, T>, 374 sequencer: Sequencer<'d, 's, T>,
371} 375}
372 376
373impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> { 377impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> {
@@ -428,8 +432,8 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
428 let sequence0 = &self.sequence0; 432 let sequence0 = &self.sequence0;
429 let alt_sequence = self.sequence1.as_ref().unwrap_or(&self.sequence0); 433 let alt_sequence = self.sequence1.as_ref().unwrap_or(&self.sequence0);
430 434
431 slice_in_ram_or(sequence0.words, Error::DMABufferNotInDataMemory)?; 435 slice_in_ram_or(sequence0.words, Error::BufferNotInRAM)?;
432 slice_in_ram_or(alt_sequence.words, Error::DMABufferNotInDataMemory)?; 436 slice_in_ram_or(alt_sequence.words, Error::BufferNotInRAM)?;
433 437
434 if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN { 438 if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN {
435 return Err(Error::SequenceTooLong); 439 return Err(Error::SequenceTooLong);
@@ -536,13 +540,21 @@ pub enum SequenceMode {
536/// PWM Base clock is system clock (16MHz) divided by prescaler 540/// PWM Base clock is system clock (16MHz) divided by prescaler
537#[derive(Debug, Eq, PartialEq, Clone, Copy)] 541#[derive(Debug, Eq, PartialEq, Clone, Copy)]
538pub enum Prescaler { 542pub enum Prescaler {
543 /// Divide by 1
539 Div1, 544 Div1,
545 /// Divide by 2
540 Div2, 546 Div2,
547 /// Divide by 4
541 Div4, 548 Div4,
549 /// Divide by 8
542 Div8, 550 Div8,
551 /// Divide by 16
543 Div16, 552 Div16,
553 /// Divide by 32
544 Div32, 554 Div32,
555 /// Divide by 64
545 Div64, 556 Div64,
557 /// Divide by 128
546 Div128, 558 Div128,
547} 559}
548 560
@@ -828,7 +840,9 @@ pub(crate) mod sealed {
828 } 840 }
829} 841}
830 842
843/// PWM peripheral instance.
831pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 844pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
845 /// Interrupt for this peripheral.
832 type Interrupt: Interrupt; 846 type Interrupt: Interrupt;
833} 847}
834 848
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 253c85c32..c01babca3 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -1,4 +1,4 @@
1//! Quadrature decoder interface 1//! Quadrature decoder (QDEC) driver.
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::task::Poll; 4use core::task::Poll;
@@ -12,17 +12,23 @@ use crate::interrupt::InterruptExt;
12use crate::peripherals::QDEC; 12use crate::peripherals::QDEC;
13use crate::{interrupt, pac, Peripheral}; 13use crate::{interrupt, pac, Peripheral};
14 14
15/// Quadrature decoder 15/// Quadrature decoder driver.
16pub struct Qdec<'d> { 16pub struct Qdec<'d> {
17 _p: PeripheralRef<'d, QDEC>, 17 _p: PeripheralRef<'d, QDEC>,
18} 18}
19 19
20/// QDEC config
20#[non_exhaustive] 21#[non_exhaustive]
21pub struct Config { 22pub struct Config {
23 /// Number of samples
22 pub num_samples: NumSamples, 24 pub num_samples: NumSamples,
25 /// Sample period
23 pub period: SamplePeriod, 26 pub period: SamplePeriod,
27 /// Set LED output pin polarity
24 pub led_polarity: LedPolarity, 28 pub led_polarity: LedPolarity,
29 /// Enable/disable input debounce filters
25 pub debounce: bool, 30 pub debounce: bool,
31 /// Time period the LED is switched ON prior to sampling (0..511 us).
26 pub led_pre_usecs: u16, 32 pub led_pre_usecs: u16,
27} 33}
28 34
@@ -41,6 +47,7 @@ impl Default for Config {
41static WAKER: AtomicWaker = AtomicWaker::new(); 47static WAKER: AtomicWaker = AtomicWaker::new();
42 48
43impl<'d> Qdec<'d> { 49impl<'d> Qdec<'d> {
50 /// Create a new QDEC.
44 pub fn new( 51 pub fn new(
45 qdec: impl Peripheral<P = QDEC> + 'd, 52 qdec: impl Peripheral<P = QDEC> + 'd,
46 irq: impl Peripheral<P = interrupt::QDEC> + 'd, 53 irq: impl Peripheral<P = interrupt::QDEC> + 'd,
@@ -52,6 +59,7 @@ impl<'d> Qdec<'d> {
52 Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config) 59 Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config)
53 } 60 }
54 61
62 /// Create a new QDEC, with a pin for LED output.
55 pub fn new_with_led( 63 pub fn new_with_led(
56 qdec: impl Peripheral<P = QDEC> + 'd, 64 qdec: impl Peripheral<P = QDEC> + 'd,
57 irq: impl Peripheral<P = interrupt::QDEC> + 'd, 65 irq: impl Peripheral<P = interrupt::QDEC> + 'd,
@@ -170,36 +178,61 @@ impl<'d> Qdec<'d> {
170 } 178 }
171} 179}
172 180
181/// Sample period
173#[derive(Debug, Eq, PartialEq, Clone, Copy)] 182#[derive(Debug, Eq, PartialEq, Clone, Copy)]
174pub enum SamplePeriod { 183pub enum SamplePeriod {
184 /// 128 us
175 _128us, 185 _128us,
186 /// 256 us
176 _256us, 187 _256us,
188 /// 512 us
177 _512us, 189 _512us,
190 /// 1024 us
178 _1024us, 191 _1024us,
192 /// 2048 us
179 _2048us, 193 _2048us,
194 /// 4096 us
180 _4096us, 195 _4096us,
196 /// 8192 us
181 _8192us, 197 _8192us,
198 /// 16384 us
182 _16384us, 199 _16384us,
200 /// 32 ms
183 _32ms, 201 _32ms,
202 /// 65 ms
184 _65ms, 203 _65ms,
204 /// 131 ms
185 _131ms, 205 _131ms,
186} 206}
187 207
208/// Number of samples taken.
188#[derive(Debug, Eq, PartialEq, Clone, Copy)] 209#[derive(Debug, Eq, PartialEq, Clone, Copy)]
189pub enum NumSamples { 210pub enum NumSamples {
211 /// 10 samples
190 _10smpl, 212 _10smpl,
213 /// 40 samples
191 _40smpl, 214 _40smpl,
215 /// 80 samples
192 _80smpl, 216 _80smpl,
217 /// 120 samples
193 _120smpl, 218 _120smpl,
219 /// 160 samples
194 _160smpl, 220 _160smpl,
221 /// 200 samples
195 _200smpl, 222 _200smpl,
223 /// 240 samples
196 _240smpl, 224 _240smpl,
225 /// 280 samples
197 _280smpl, 226 _280smpl,
227 /// 1 sample
198 _1smpl, 228 _1smpl,
199} 229}
200 230
231/// LED polarity
201#[derive(Debug, Eq, PartialEq, Clone, Copy)] 232#[derive(Debug, Eq, PartialEq, Clone, Copy)]
202pub enum LedPolarity { 233pub enum LedPolarity {
234 /// Active high (a high output turns on the LED).
203 ActiveHigh, 235 ActiveHigh,
236 /// Active low (a low output turns on the LED).
204 ActiveLow, 237 ActiveLow,
205} 238}
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index ea0a17031..07a970018 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -1,3 +1,5 @@
1//! Quad Serial Peripheral Interface (QSPI) flash driver.
2
1#![macro_use] 3#![macro_use]
2 4
3use core::future::poll_fn; 5use core::future::poll_fn;
@@ -15,6 +17,7 @@ pub use crate::pac::qspi::ifconfig0::{
15pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; 17pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
16use crate::{pac, Peripheral}; 18use crate::{pac, Peripheral};
17 19
20/// Deep power-down config.
18pub struct DeepPowerDownConfig { 21pub struct DeepPowerDownConfig {
19 /// Time required for entering DPM, in units of 16us 22 /// Time required for entering DPM, in units of 16us
20 pub enter_time: u16, 23 pub enter_time: u16,
@@ -22,37 +25,62 @@ pub struct DeepPowerDownConfig {
22 pub exit_time: u16, 25 pub exit_time: u16,
23} 26}
24 27
28/// QSPI bus frequency.
25pub enum Frequency { 29pub enum Frequency {
30 /// 32 Mhz
26 M32 = 0, 31 M32 = 0,
32 /// 16 Mhz
27 M16 = 1, 33 M16 = 1,
34 /// 10.7 Mhz
28 M10_7 = 2, 35 M10_7 = 2,
36 /// 8 Mhz
29 M8 = 3, 37 M8 = 3,
38 /// 6.4 Mhz
30 M6_4 = 4, 39 M6_4 = 4,
40 /// 5.3 Mhz
31 M5_3 = 5, 41 M5_3 = 5,
42 /// 4.6 Mhz
32 M4_6 = 6, 43 M4_6 = 6,
44 /// 4 Mhz
33 M4 = 7, 45 M4 = 7,
46 /// 3.6 Mhz
34 M3_6 = 8, 47 M3_6 = 8,
48 /// 3.2 Mhz
35 M3_2 = 9, 49 M3_2 = 9,
50 /// 2.9 Mhz
36 M2_9 = 10, 51 M2_9 = 10,
52 /// 2.7 Mhz
37 M2_7 = 11, 53 M2_7 = 11,
54 /// 2.5 Mhz
38 M2_5 = 12, 55 M2_5 = 12,
56 /// 2.3 Mhz
39 M2_3 = 13, 57 M2_3 = 13,
58 /// 2.1 Mhz
40 M2_1 = 14, 59 M2_1 = 14,
60 /// 2 Mhz
41 M2 = 15, 61 M2 = 15,
42} 62}
43 63
64/// QSPI config.
44#[non_exhaustive] 65#[non_exhaustive]
45pub struct Config { 66pub struct Config {
67 /// XIP offset.
46 pub xip_offset: u32, 68 pub xip_offset: u32,
69 /// Opcode used for read operations.
47 pub read_opcode: ReadOpcode, 70 pub read_opcode: ReadOpcode,
71 /// Opcode used for write operations.
48 pub write_opcode: WriteOpcode, 72 pub write_opcode: WriteOpcode,
73 /// Page size for write operations.
49 pub write_page_size: WritePageSize, 74 pub write_page_size: WritePageSize,
75 /// Configuration for deep power down. If None, deep power down is disabled.
50 pub deep_power_down: Option<DeepPowerDownConfig>, 76 pub deep_power_down: Option<DeepPowerDownConfig>,
77 /// QSPI bus frequency.
51 pub frequency: Frequency, 78 pub frequency: Frequency,
52 /// Value is specified in number of 16 MHz periods (62.5 ns) 79 /// Value is specified in number of 16 MHz periods (62.5 ns)
53 pub sck_delay: u8, 80 pub sck_delay: u8,
54 /// Whether data is captured on the clock rising edge and data is output on a falling edge (MODE0) or vice-versa (MODE3) 81 /// Whether data is captured on the clock rising edge and data is output on a falling edge (MODE0) or vice-versa (MODE3)
55 pub spi_mode: SpiMode, 82 pub spi_mode: SpiMode,
83 /// Addressing mode (24-bit or 32-bit)
56 pub address_mode: AddressMode, 84 pub address_mode: AddressMode,
57} 85}
58 86
@@ -72,20 +100,24 @@ impl Default for Config {
72 } 100 }
73} 101}
74 102
103/// Error
75#[derive(Debug, Copy, Clone, Eq, PartialEq)] 104#[derive(Debug, Copy, Clone, Eq, PartialEq)]
76#[cfg_attr(feature = "defmt", derive(defmt::Format))] 105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
77#[non_exhaustive] 106#[non_exhaustive]
78pub enum Error { 107pub enum Error {
108 /// Operation address was out of bounds.
79 OutOfBounds, 109 OutOfBounds,
80 // TODO add "not in data memory" error and check for it 110 // TODO add "not in data memory" error and check for it
81} 111}
82 112
113/// QSPI flash driver.
83pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> { 114pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> {
84 irq: PeripheralRef<'d, T::Interrupt>, 115 irq: PeripheralRef<'d, T::Interrupt>,
85 dpm_enabled: bool, 116 dpm_enabled: bool,
86} 117}
87 118
88impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { 119impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
120 /// Create a new QSPI driver.
89 pub fn new( 121 pub fn new(
90 _qspi: impl Peripheral<P = T> + 'd, 122 _qspi: impl Peripheral<P = T> + 'd,
91 irq: impl Peripheral<P = T::Interrupt> + 'd, 123 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -183,6 +215,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
183 } 215 }
184 } 216 }
185 217
218 /// Do a custom QSPI instruction.
186 pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { 219 pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
187 let bomb = DropBomb::new(); 220 let bomb = DropBomb::new();
188 221
@@ -198,6 +231,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
198 Ok(()) 231 Ok(())
199 } 232 }
200 233
234 /// Do a custom QSPI instruction, blocking version.
201 pub fn blocking_custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { 235 pub fn blocking_custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> {
202 let len = core::cmp::max(req.len(), resp.len()) as u8; 236 let len = core::cmp::max(req.len(), resp.len()) as u8;
203 self.custom_instruction_start(opcode, req, len)?; 237 self.custom_instruction_start(opcode, req, len)?;
@@ -346,6 +380,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
346 Ok(()) 380 Ok(())
347 } 381 }
348 382
383 /// Read data from the flash memory.
349 pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { 384 pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
350 let bomb = DropBomb::new(); 385 let bomb = DropBomb::new();
351 386
@@ -357,6 +392,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
357 Ok(()) 392 Ok(())
358 } 393 }
359 394
395 /// Write data to the flash memory.
360 pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { 396 pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
361 let bomb = DropBomb::new(); 397 let bomb = DropBomb::new();
362 398
@@ -368,6 +404,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
368 Ok(()) 404 Ok(())
369 } 405 }
370 406
407 /// Erase a sector on the flash memory.
371 pub async fn erase(&mut self, address: usize) -> Result<(), Error> { 408 pub async fn erase(&mut self, address: usize) -> Result<(), Error> {
372 let bomb = DropBomb::new(); 409 let bomb = DropBomb::new();
373 410
@@ -379,18 +416,21 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> {
379 Ok(()) 416 Ok(())
380 } 417 }
381 418
419 /// Read data from the flash memory, blocking version.
382 pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { 420 pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> {
383 self.start_read(address, data)?; 421 self.start_read(address, data)?;
384 self.blocking_wait_ready(); 422 self.blocking_wait_ready();
385 Ok(()) 423 Ok(())
386 } 424 }
387 425
426 /// Write data to the flash memory, blocking version.
388 pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { 427 pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> {
389 self.start_write(address, data)?; 428 self.start_write(address, data)?;
390 self.blocking_wait_ready(); 429 self.blocking_wait_ready();
391 Ok(()) 430 Ok(())
392 } 431 }
393 432
433 /// Erase a sector on the flash memory, blocking version.
394 pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> { 434 pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> {
395 self.start_erase(address)?; 435 self.start_erase(address)?;
396 self.blocking_wait_ready(); 436 self.blocking_wait_ready();
@@ -547,7 +587,9 @@ pub(crate) mod sealed {
547 } 587 }
548} 588}
549 589
590/// QSPI peripheral instance.
550pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 591pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
592 /// Interrupt for this peripheral.
551 type Interrupt: Interrupt; 593 type Interrupt: Interrupt;
552} 594}
553 595
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index e0caeaaee..b0b3a8eb8 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -1,3 +1,5 @@
1//! Random Number Generator (RNG) driver.
2
1use core::future::poll_fn; 3use core::future::poll_fn;
2use core::ptr; 4use core::ptr;
3use core::sync::atomic::{AtomicPtr, Ordering}; 5use core::sync::atomic::{AtomicPtr, Ordering};
@@ -128,10 +130,11 @@ impl<'d> Rng<'d> {
128 /// However, this makes the generation of numbers slower. 130 /// However, this makes the generation of numbers slower.
129 /// 131 ///
130 /// Defaults to disabled. 132 /// Defaults to disabled.
131 pub fn bias_correction(&self, enable: bool) { 133 pub fn set_bias_correction(&self, enable: bool) {
132 RNG::regs().config.write(|w| w.dercen().bit(enable)) 134 RNG::regs().config.write(|w| w.dercen().bit(enable))
133 } 135 }
134 136
137 /// Fill the buffer with random bytes.
135 pub async fn fill_bytes(&mut self, dest: &mut [u8]) { 138 pub async fn fill_bytes(&mut self, dest: &mut [u8]) {
136 if dest.len() == 0 { 139 if dest.len() == 0 {
137 return; // Nothing to fill 140 return; // Nothing to fill
@@ -175,6 +178,7 @@ impl<'d> Rng<'d> {
175 drop(on_drop); 178 drop(on_drop);
176 } 179 }
177 180
181 /// Fill the buffer with random bytes, blocking version.
178 pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { 182 pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
179 self.start(); 183 self.start();
180 184
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 4592d4687..2d01a3dda 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -1,3 +1,5 @@
1//! Successive Approximation Analog-to-Digital Converter (SAADC) driver.
2
1#![macro_use] 3#![macro_use]
2 4
3use core::future::poll_fn; 5use core::future::poll_fn;
@@ -20,6 +22,7 @@ use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
20use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 22use crate::timer::{Frequency, Instance as TimerInstance, Timer};
21use crate::{interrupt, pac, peripherals, Peripheral}; 23use crate::{interrupt, pac, peripherals, Peripheral};
22 24
25/// SAADC error
23#[derive(Debug, Clone, Copy, PartialEq, Eq)] 26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))] 27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[non_exhaustive] 28#[non_exhaustive]
@@ -102,17 +105,17 @@ impl<'d> ChannelConfig<'d> {
102 } 105 }
103} 106}
104 107
105/// The state of a continuously running sampler. While it reflects 108/// Value returned by the SAADC callback, deciding what happens next.
106/// the progress of a sampler, it also signals what should be done
107/// next. For example, if the sampler has stopped then the Saadc implementation
108/// can then tear down its infrastructure.
109#[derive(PartialEq)] 109#[derive(PartialEq)]
110pub enum SamplerState { 110pub enum CallbackResult {
111 Sampled, 111 /// The SAADC should keep sampling and calling the callback.
112 Stopped, 112 Continue,
113 /// The SAADC should stop sampling, and return.
114 Stop,
113} 115}
114 116
115impl<'d, const N: usize> Saadc<'d, N> { 117impl<'d, const N: usize> Saadc<'d, N> {
118 /// Create a new SAADC driver.
116 pub fn new( 119 pub fn new(
117 saadc: impl Peripheral<P = peripherals::SAADC> + 'd, 120 saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
118 irq: impl Peripheral<P = interrupt::SAADC> + 'd, 121 irq: impl Peripheral<P = interrupt::SAADC> + 'd,
@@ -285,7 +288,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
285 /// free the buffers from being used by the peripheral. Cancellation will 288 /// free the buffers from being used by the peripheral. Cancellation will
286 /// also cause the sampling to be stopped. 289 /// also cause the sampling to be stopped.
287 290
288 pub async fn run_task_sampler<S, T: TimerInstance, const N0: usize>( 291 pub async fn run_task_sampler<F, T: TimerInstance, const N0: usize>(
289 &mut self, 292 &mut self,
290 timer: &mut T, 293 timer: &mut T,
291 ppi_ch1: &mut impl ConfigurableChannel, 294 ppi_ch1: &mut impl ConfigurableChannel,
@@ -293,9 +296,9 @@ impl<'d, const N: usize> Saadc<'d, N> {
293 frequency: Frequency, 296 frequency: Frequency,
294 sample_counter: u32, 297 sample_counter: u32,
295 bufs: &mut [[[i16; N]; N0]; 2], 298 bufs: &mut [[[i16; N]; N0]; 2],
296 sampler: S, 299 callback: F,
297 ) where 300 ) where
298 S: FnMut(&[[i16; N]]) -> SamplerState, 301 F: FnMut(&[[i16; N]]) -> CallbackResult,
299 { 302 {
300 let r = Self::regs(); 303 let r = Self::regs();
301 304
@@ -321,20 +324,20 @@ impl<'d, const N: usize> Saadc<'d, N> {
321 || { 324 || {
322 sample_ppi.enable(); 325 sample_ppi.enable();
323 }, 326 },
324 sampler, 327 callback,
325 ) 328 )
326 .await; 329 .await;
327 } 330 }
328 331
329 async fn run_sampler<I, S, const N0: usize>( 332 async fn run_sampler<I, F, const N0: usize>(
330 &mut self, 333 &mut self,
331 bufs: &mut [[[i16; N]; N0]; 2], 334 bufs: &mut [[[i16; N]; N0]; 2],
332 sample_rate_divisor: Option<u16>, 335 sample_rate_divisor: Option<u16>,
333 mut init: I, 336 mut init: I,
334 mut sampler: S, 337 mut callback: F,
335 ) where 338 ) where
336 I: FnMut(), 339 I: FnMut(),
337 S: FnMut(&[[i16; N]]) -> SamplerState, 340 F: FnMut(&[[i16; N]]) -> CallbackResult,
338 { 341 {
339 // In case the future is dropped, stop the task and wait for it to end. 342 // In case the future is dropped, stop the task and wait for it to end.
340 let on_drop = OnDrop::new(Self::stop_sampling_immediately); 343 let on_drop = OnDrop::new(Self::stop_sampling_immediately);
@@ -395,12 +398,15 @@ impl<'d, const N: usize> Saadc<'d, N> {
395 r.events_end.reset(); 398 r.events_end.reset();
396 r.intenset.write(|w| w.end().set()); 399 r.intenset.write(|w| w.end().set());
397 400
398 if sampler(&bufs[current_buffer]) == SamplerState::Sampled { 401 match callback(&bufs[current_buffer]) {
399 let next_buffer = 1 - current_buffer; 402 CallbackResult::Continue => {
400 current_buffer = next_buffer; 403 let next_buffer = 1 - current_buffer;
401 } else { 404 current_buffer = next_buffer;
402 return Poll::Ready(()); 405 }
403 }; 406 CallbackResult::Stop => {
407 return Poll::Ready(());
408 }
409 }
404 } 410 }
405 411
406 if r.events_started.read().bits() != 0 { 412 if r.events_started.read().bits() != 0 {
@@ -458,7 +464,7 @@ impl<'d> Saadc<'d, 1> {
458 sample_rate_divisor: u16, 464 sample_rate_divisor: u16,
459 sampler: S, 465 sampler: S,
460 ) where 466 ) where
461 S: FnMut(&[[i16; 1]]) -> SamplerState, 467 S: FnMut(&[[i16; 1]]) -> CallbackResult,
462 { 468 {
463 self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler).await; 469 self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler).await;
464 } 470 }
@@ -658,6 +664,10 @@ pub(crate) mod sealed {
658 664
659/// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal. 665/// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal.
660pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static { 666pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static {
667 /// Convert this SAADC input to a type-erased `AnyInput`.
668 ///
669 /// This allows using several inputs in situations that might require
670 /// them to be the same type, like putting them in an array.
661 fn degrade_saadc(self) -> AnyInput { 671 fn degrade_saadc(self) -> AnyInput {
662 AnyInput { 672 AnyInput {
663 channel: self.channel(), 673 channel: self.channel(),
@@ -665,6 +675,10 @@ pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized +
665 } 675 }
666} 676}
667 677
678/// A type-erased SAADC input.
679///
680/// This allows using several inputs in situations that might require
681/// them to be the same type, like putting them in an array.
668pub struct AnyInput { 682pub struct AnyInput {
669 channel: InputChannel, 683 channel: InputChannel,
670} 684}
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 7bb4e39f7..17e435787 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -1,3 +1,5 @@
1//! Serial Peripheral Instance in master mode (SPIM) driver.
2
1#![macro_use] 3#![macro_use]
2 4
3use core::future::poll_fn; 5use core::future::poll_fn;
@@ -16,27 +18,37 @@ use crate::interrupt::{Interrupt, InterruptExt};
16use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 18use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
17use crate::{pac, Peripheral}; 19use crate::{pac, Peripheral};
18 20
21/// SPIM error
19#[derive(Debug, Clone, Copy, PartialEq, Eq)] 22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))] 23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[non_exhaustive] 24#[non_exhaustive]
22pub enum Error { 25pub enum Error {
26 /// TX buffer was too long.
23 TxBufferTooLong, 27 TxBufferTooLong,
28 /// RX buffer was too long.
24 RxBufferTooLong, 29 RxBufferTooLong,
25 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 30 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
26 DMABufferNotInDataMemory, 31 BufferNotInRAM,
27} 32}
28 33
29/// Interface for the SPIM peripheral using EasyDMA to offload the transmission and reception workload. 34/// SPIM driver.
30///
31/// For more details about EasyDMA, consult the module documentation.
32pub struct Spim<'d, T: Instance> { 35pub struct Spim<'d, T: Instance> {
33 _p: PeripheralRef<'d, T>, 36 _p: PeripheralRef<'d, T>,
34} 37}
35 38
39/// SPIM configuration.
36#[non_exhaustive] 40#[non_exhaustive]
37pub struct Config { 41pub struct Config {
42 /// Frequency
38 pub frequency: Frequency, 43 pub frequency: Frequency,
44
45 /// SPI mode
39 pub mode: Mode, 46 pub mode: Mode,
47
48 /// Overread character.
49 ///
50 /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer,
51 /// this byte will be transmitted in the MOSI line for the left-over bytes.
40 pub orc: u8, 52 pub orc: u8,
41} 53}
42 54
@@ -51,6 +63,7 @@ impl Default for Config {
51} 63}
52 64
53impl<'d, T: Instance> Spim<'d, T> { 65impl<'d, T: Instance> Spim<'d, T> {
66 /// Create a new SPIM driver.
54 pub fn new( 67 pub fn new(
55 spim: impl Peripheral<P = T> + 'd, 68 spim: impl Peripheral<P = T> + 'd,
56 irq: impl Peripheral<P = T::Interrupt> + 'd, 69 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -70,6 +83,7 @@ impl<'d, T: Instance> Spim<'d, T> {
70 ) 83 )
71 } 84 }
72 85
86 /// Create a new SPIM driver, capable of TX only (MOSI only).
73 pub fn new_txonly( 87 pub fn new_txonly(
74 spim: impl Peripheral<P = T> + 'd, 88 spim: impl Peripheral<P = T> + 'd,
75 irq: impl Peripheral<P = T::Interrupt> + 'd, 89 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -81,6 +95,7 @@ impl<'d, T: Instance> Spim<'d, T> {
81 Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config) 95 Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config)
82 } 96 }
83 97
98 /// Create a new SPIM driver, capable of RX only (MISO only).
84 pub fn new_rxonly( 99 pub fn new_rxonly(
85 spim: impl Peripheral<P = T> + 'd, 100 spim: impl Peripheral<P = T> + 'd,
86 irq: impl Peripheral<P = T::Interrupt> + 'd, 101 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -194,7 +209,7 @@ impl<'d, T: Instance> Spim<'d, T> {
194 } 209 }
195 210
196 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 211 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
197 slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; 212 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
198 // NOTE: RAM slice check for rx is not necessary, as a mutable 213 // NOTE: RAM slice check for rx is not necessary, as a mutable
199 // slice can only be built from data located in RAM. 214 // slice can only be built from data located in RAM.
200 215
@@ -236,7 +251,7 @@ impl<'d, T: Instance> Spim<'d, T> {
236 fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { 251 fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
237 match self.blocking_inner_from_ram(rx, tx) { 252 match self.blocking_inner_from_ram(rx, tx) {
238 Ok(_) => Ok(()), 253 Ok(_) => Ok(()),
239 Err(Error::DMABufferNotInDataMemory) => { 254 Err(Error::BufferNotInRAM) => {
240 trace!("Copying SPIM tx buffer into RAM for DMA"); 255 trace!("Copying SPIM tx buffer into RAM for DMA");
241 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 256 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
242 tx_ram_buf.copy_from_slice(tx); 257 tx_ram_buf.copy_from_slice(tx);
@@ -268,7 +283,7 @@ impl<'d, T: Instance> Spim<'d, T> {
268 async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { 283 async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> {
269 match self.async_inner_from_ram(rx, tx).await { 284 match self.async_inner_from_ram(rx, tx).await {
270 Ok(_) => Ok(()), 285 Ok(_) => Ok(()),
271 Err(Error::DMABufferNotInDataMemory) => { 286 Err(Error::BufferNotInRAM) => {
272 trace!("Copying SPIM tx buffer into RAM for DMA"); 287 trace!("Copying SPIM tx buffer into RAM for DMA");
273 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 288 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
274 tx_ram_buf.copy_from_slice(tx); 289 tx_ram_buf.copy_from_slice(tx);
@@ -385,7 +400,9 @@ pub(crate) mod sealed {
385 } 400 }
386} 401}
387 402
403/// SPIM peripheral instance
388pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 404pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
405 /// Interrupt for this peripheral.
389 type Interrupt: Interrupt; 406 type Interrupt: Interrupt;
390} 407}
391 408
@@ -437,7 +454,7 @@ mod eh1 {
437 match *self { 454 match *self {
438 Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, 455 Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
439 Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, 456 Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other,
440 Self::DMABufferNotInDataMemory => embedded_hal_1::spi::ErrorKind::Other, 457 Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other,
441 } 458 }
442 } 459 }
443 } 460 }
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 44af61a19..1b7436477 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -1,3 +1,5 @@
1//! Serial Peripheral Instance in slave mode (SPIS) driver.
2
1#![macro_use] 3#![macro_use]
2use core::future::poll_fn; 4use core::future::poll_fn;
3use core::sync::atomic::{compiler_fence, Ordering}; 5use core::sync::atomic::{compiler_fence, Ordering};
@@ -14,28 +16,43 @@ use crate::interrupt::{Interrupt, InterruptExt};
14use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 16use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
15use crate::{pac, Peripheral}; 17use crate::{pac, Peripheral};
16 18
19/// SPIS error
17#[derive(Debug, Clone, Copy, PartialEq, Eq)] 20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19#[non_exhaustive] 22#[non_exhaustive]
20pub enum Error { 23pub enum Error {
24 /// TX buffer was too long.
21 TxBufferTooLong, 25 TxBufferTooLong,
26 /// RX buffer was too long.
22 RxBufferTooLong, 27 RxBufferTooLong,
23 /// EasyDMA can only read from data memory, read only buffers in flash will fail. 28 /// EasyDMA can only read from data memory, read only buffers in flash will fail.
24 DMABufferNotInDataMemory, 29 BufferNotInRAM,
25} 30}
26 31
27/// Interface for the SPIS peripheral using EasyDMA to offload the transmission and reception workload. 32/// SPIS driver.
28///
29/// For more details about EasyDMA, consult the module documentation.
30pub struct Spis<'d, T: Instance> { 33pub struct Spis<'d, T: Instance> {
31 _p: PeripheralRef<'d, T>, 34 _p: PeripheralRef<'d, T>,
32} 35}
33 36
37/// SPIS configuration.
34#[non_exhaustive] 38#[non_exhaustive]
35pub struct Config { 39pub struct Config {
40 /// SPI mode
36 pub mode: Mode, 41 pub mode: Mode,
42
43 /// Overread character.
44 ///
45 /// If the master keeps clocking the bus after all the bytes in the TX buffer have
46 /// already been transmitted, this byte will be constantly transmitted in the MISO line.
37 pub orc: u8, 47 pub orc: u8,
48
49 /// Default byte.
50 ///
51 /// This is the byte clocked out in the MISO line for ignored transactions (if the master
52 /// sets CSN low while the semaphore is owned by the firmware)
38 pub def: u8, 53 pub def: u8,
54
55 /// Automatically make the firmware side acquire the semaphore on transfer end.
39 pub auto_acquire: bool, 56 pub auto_acquire: bool,
40} 57}
41 58
@@ -51,6 +68,7 @@ impl Default for Config {
51} 68}
52 69
53impl<'d, T: Instance> Spis<'d, T> { 70impl<'d, T: Instance> Spis<'d, T> {
71 /// Create a new SPIS driver.
54 pub fn new( 72 pub fn new(
55 spis: impl Peripheral<P = T> + 'd, 73 spis: impl Peripheral<P = T> + 'd,
56 irq: impl Peripheral<P = T::Interrupt> + 'd, 74 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -72,6 +90,7 @@ impl<'d, T: Instance> Spis<'d, T> {
72 ) 90 )
73 } 91 }
74 92
93 /// Create a new SPIS driver, capable of TX only (MISO only).
75 pub fn new_txonly( 94 pub fn new_txonly(
76 spis: impl Peripheral<P = T> + 'd, 95 spis: impl Peripheral<P = T> + 'd,
77 irq: impl Peripheral<P = T::Interrupt> + 'd, 96 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -92,6 +111,7 @@ impl<'d, T: Instance> Spis<'d, T> {
92 ) 111 )
93 } 112 }
94 113
114 /// Create a new SPIS driver, capable of RX only (MOSI only).
95 pub fn new_rxonly( 115 pub fn new_rxonly(
96 spis: impl Peripheral<P = T> + 'd, 116 spis: impl Peripheral<P = T> + 'd,
97 irq: impl Peripheral<P = T::Interrupt> + 'd, 117 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -212,7 +232,7 @@ impl<'d, T: Instance> Spis<'d, T> {
212 } 232 }
213 233
214 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { 234 fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
215 slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; 235 slice_in_ram_or(tx, Error::BufferNotInRAM)?;
216 // NOTE: RAM slice check for rx is not necessary, as a mutable 236 // NOTE: RAM slice check for rx is not necessary, as a mutable
217 // slice can only be built from data located in RAM. 237 // slice can only be built from data located in RAM.
218 238
@@ -267,7 +287,7 @@ impl<'d, T: Instance> Spis<'d, T> {
267 fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> { 287 fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> {
268 match self.blocking_inner_from_ram(rx, tx) { 288 match self.blocking_inner_from_ram(rx, tx) {
269 Ok(n) => Ok(n), 289 Ok(n) => Ok(n),
270 Err(Error::DMABufferNotInDataMemory) => { 290 Err(Error::BufferNotInRAM) => {
271 trace!("Copying SPIS tx buffer into RAM for DMA"); 291 trace!("Copying SPIS tx buffer into RAM for DMA");
272 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 292 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
273 tx_ram_buf.copy_from_slice(tx); 293 tx_ram_buf.copy_from_slice(tx);
@@ -330,7 +350,7 @@ impl<'d, T: Instance> Spis<'d, T> {
330 async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> { 350 async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> {
331 match self.async_inner_from_ram(rx, tx).await { 351 match self.async_inner_from_ram(rx, tx).await {
332 Ok(n) => Ok(n), 352 Ok(n) => Ok(n),
333 Err(Error::DMABufferNotInDataMemory) => { 353 Err(Error::BufferNotInRAM) => {
334 trace!("Copying SPIS tx buffer into RAM for DMA"); 354 trace!("Copying SPIS tx buffer into RAM for DMA");
335 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; 355 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()];
336 tx_ram_buf.copy_from_slice(tx); 356 tx_ram_buf.copy_from_slice(tx);
@@ -468,7 +488,9 @@ pub(crate) mod sealed {
468 } 488 }
469} 489}
470 490
491/// SPIS peripheral instance
471pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 492pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
493 /// Interrupt for this peripheral.
472 type Interrupt: Interrupt; 494 type Interrupt: Interrupt;
473} 495}
474 496
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index 7a7f61b51..5298faabc 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -1,4 +1,4 @@
1//! Temperature sensor interface. 1//! Builtin temperature sensor driver.
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::task::Poll; 4use core::task::Poll;
@@ -12,7 +12,7 @@ use crate::interrupt::InterruptExt;
12use crate::peripherals::TEMP; 12use crate::peripherals::TEMP;
13use crate::{interrupt, pac, Peripheral}; 13use crate::{interrupt, pac, Peripheral};
14 14
15/// Integrated temperature sensor. 15/// Builtin temperature sensor driver.
16pub struct Temp<'d> { 16pub struct Temp<'d> {
17 _irq: PeripheralRef<'d, interrupt::TEMP>, 17 _irq: PeripheralRef<'d, interrupt::TEMP>,
18} 18}
@@ -20,6 +20,7 @@ pub struct Temp<'d> {
20static WAKER: AtomicWaker = AtomicWaker::new(); 20static WAKER: AtomicWaker = AtomicWaker::new();
21 21
22impl<'d> Temp<'d> { 22impl<'d> Temp<'d> {
23 /// Create a new temperature sensor driver.
23 pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self { 24 pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self {
24 into_ref!(_t, irq); 25 into_ref!(_t, irq);
25 26
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index bc8710640..d1ae57237 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -1,3 +1,9 @@
1//! Timer driver.
2//!
3//! Important note! This driver is very low level. For most time-related use cases, like
4//! "sleep for X seconds", "do something every X seconds", or measuring time, you should
5//! use [`embassy-time`](https://crates.io/crates/embassy-time) instead!
6
1#![macro_use] 7#![macro_use]
2 8
3use core::future::poll_fn; 9use core::future::poll_fn;
@@ -28,9 +34,13 @@ pub(crate) mod sealed {
28 pub trait TimerType {} 34 pub trait TimerType {}
29} 35}
30 36
37/// Basic Timer instance.
31pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 38pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
39 /// Interrupt for this peripheral.
32 type Interrupt: Interrupt; 40 type Interrupt: Interrupt;
33} 41}
42
43/// Extended timer instance.
34pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} 44pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {}
35 45
36macro_rules! impl_timer { 46macro_rules! impl_timer {
@@ -61,18 +71,28 @@ macro_rules! impl_timer {
61 }; 71 };
62} 72}
63 73
74/// Timer frequency
64#[repr(u8)] 75#[repr(u8)]
65pub enum Frequency { 76pub enum Frequency {
66 // I'd prefer not to prefix these with `F`, but Rust identifiers can't start with digits. 77 /// 16MHz
67 F16MHz = 0, 78 F16MHz = 0,
79 /// 8MHz
68 F8MHz = 1, 80 F8MHz = 1,
81 /// 4MHz
69 F4MHz = 2, 82 F4MHz = 2,
83 /// 2MHz
70 F2MHz = 3, 84 F2MHz = 3,
85 /// 1MHz
71 F1MHz = 4, 86 F1MHz = 4,
87 /// 500kHz
72 F500kHz = 5, 88 F500kHz = 5,
89 /// 250kHz
73 F250kHz = 6, 90 F250kHz = 6,
91 /// 125kHz
74 F125kHz = 7, 92 F125kHz = 7,
93 /// 62500Hz
75 F62500Hz = 8, 94 F62500Hz = 8,
95 /// 31250Hz
76 F31250Hz = 9, 96 F31250Hz = 9,
77} 97}
78 98
@@ -86,7 +106,10 @@ pub enum Frequency {
86 106
87pub trait TimerType: sealed::TimerType {} 107pub trait TimerType: sealed::TimerType {}
88 108
109/// Marker type indicating the timer driver can await expiration (it owns the timer interrupt).
89pub enum Awaitable {} 110pub enum Awaitable {}
111
112/// Marker type indicating the timer driver cannot await expiration (it does not own the timer interrupt).
90pub enum NotAwaitable {} 113pub enum NotAwaitable {}
91 114
92impl sealed::TimerType for Awaitable {} 115impl sealed::TimerType for Awaitable {}
@@ -94,12 +117,14 @@ impl sealed::TimerType for NotAwaitable {}
94impl TimerType for Awaitable {} 117impl TimerType for Awaitable {}
95impl TimerType for NotAwaitable {} 118impl TimerType for NotAwaitable {}
96 119
120/// Timer driver.
97pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { 121pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> {
98 _p: PeripheralRef<'d, T>, 122 _p: PeripheralRef<'d, T>,
99 _i: PhantomData<I>, 123 _i: PhantomData<I>,
100} 124}
101 125
102impl<'d, T: Instance> Timer<'d, T, Awaitable> { 126impl<'d, T: Instance> Timer<'d, T, Awaitable> {
127 /// Create a new async-capable timer driver.
103 pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self { 128 pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self {
104 into_ref!(irq); 129 into_ref!(irq);
105 130
@@ -107,16 +132,17 @@ impl<'d, T: Instance> Timer<'d, T, Awaitable> {
107 irq.unpend(); 132 irq.unpend();
108 irq.enable(); 133 irq.enable();
109 134
110 Self::new_irqless(timer) 135 Self::new_inner(timer)
111 } 136 }
112} 137}
138
113impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { 139impl<'d, T: Instance> Timer<'d, T, NotAwaitable> {
114 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. 140 /// Create a `Timer` driver without an interrupt, meaning `Cc::wait` won't work.
115 /// 141 ///
116 /// This can be useful for triggering tasks via PPI 142 /// This can be useful for triggering tasks via PPI
117 /// `Uarte` uses this internally. 143 /// `Uarte` uses this internally.
118 pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self { 144 pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self {
119 Self::new_irqless(timer) 145 Self::new_inner(timer)
120 } 146 }
121} 147}
122 148
@@ -124,7 +150,7 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
124 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. 150 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
125 /// 151 ///
126 /// This is used by the public constructors. 152 /// This is used by the public constructors.
127 fn new_irqless(timer: impl Peripheral<P = T> + 'd) -> Self { 153 fn new_inner(timer: impl Peripheral<P = T> + 'd) -> Self {
128 into_ref!(timer); 154 into_ref!(timer);
129 155
130 let regs = T::regs(); 156 let regs = T::regs();
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 4eafd18c2..0dcb2b0da 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -1,11 +1,7 @@
1//! I2C-compatible Two Wire Interface in master mode (TWIM) driver.
2
1#![macro_use] 3#![macro_use]
2 4
3//! HAL interface to the TWIM peripheral.
4//!
5//! See product specification:
6//!
7//! - nRF52832: Section 33
8//! - nRF52840: Section 6.31
9use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
10use core::sync::atomic::compiler_fence; 6use core::sync::atomic::compiler_fence;
11use core::sync::atomic::Ordering::SeqCst; 7use core::sync::atomic::Ordering::SeqCst;
@@ -23,22 +19,39 @@ use crate::interrupt::{Interrupt, InterruptExt};
23use crate::util::{slice_in_ram, slice_in_ram_or}; 19use crate::util::{slice_in_ram, slice_in_ram_or};
24use crate::{gpio, pac, Peripheral}; 20use crate::{gpio, pac, Peripheral};
25 21
22/// TWI frequency
26#[derive(Clone, Copy)] 23#[derive(Clone, Copy)]
27pub enum Frequency { 24pub enum Frequency {
28 #[doc = "26738688: 100 kbps"] 25 /// 100 kbps
29 K100 = 26738688, 26 K100 = 26738688,
30 #[doc = "67108864: 250 kbps"] 27 /// 250 kbps
31 K250 = 67108864, 28 K250 = 67108864,
32 #[doc = "104857600: 400 kbps"] 29 /// 400 kbps
33 K400 = 104857600, 30 K400 = 104857600,
34} 31}
35 32
33/// TWIM config.
36#[non_exhaustive] 34#[non_exhaustive]
37pub struct Config { 35pub struct Config {
36 /// Frequency
38 pub frequency: Frequency, 37 pub frequency: Frequency,
38
39 /// Enable high drive for the SDA line.
39 pub sda_high_drive: bool, 40 pub sda_high_drive: bool,
41
42 /// Enable internal pullup for the SDA line.
43 ///
44 /// Note that using external pullups is recommended for I2C, and
45 /// most boards already have them.
40 pub sda_pullup: bool, 46 pub sda_pullup: bool,
47
48 /// Enable high drive for the SCL line.
41 pub scl_high_drive: bool, 49 pub scl_high_drive: bool,
50
51 /// Enable internal pullup for the SCL line.
52 ///
53 /// Note that using external pullups is recommended for I2C, and
54 /// most boards already have them.
42 pub scl_pullup: bool, 55 pub scl_pullup: bool,
43} 56}
44 57
@@ -54,29 +67,38 @@ impl Default for Config {
54 } 67 }
55} 68}
56 69
70/// TWI error.
57#[derive(Debug, Copy, Clone, Eq, PartialEq)] 71#[derive(Debug, Copy, Clone, Eq, PartialEq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))] 72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[non_exhaustive] 73#[non_exhaustive]
60pub enum Error { 74pub enum Error {
75 /// TX buffer was too long.
61 TxBufferTooLong, 76 TxBufferTooLong,
77 /// RX buffer was too long.
62 RxBufferTooLong, 78 RxBufferTooLong,
79 /// Data transmit failed.
63 Transmit, 80 Transmit,
81 /// Data reception failed.
64 Receive, 82 Receive,
65 DMABufferNotInDataMemory, 83 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
84 BufferNotInRAM,
85 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly.
66 AddressNack, 86 AddressNack,
87 /// Didn't receive an ACK bit after a data byte.
67 DataNack, 88 DataNack,
89 /// Overrun error.
68 Overrun, 90 Overrun,
91 /// Timeout error.
69 Timeout, 92 Timeout,
70} 93}
71 94
72/// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload. 95/// TWI driver.
73///
74/// For more details about EasyDMA, consult the module documentation.
75pub struct Twim<'d, T: Instance> { 96pub struct Twim<'d, T: Instance> {
76 _p: PeripheralRef<'d, T>, 97 _p: PeripheralRef<'d, T>,
77} 98}
78 99
79impl<'d, T: Instance> Twim<'d, T> { 100impl<'d, T: Instance> Twim<'d, T> {
101 /// Create a new TWI driver.
80 pub fn new( 102 pub fn new(
81 twim: impl Peripheral<P = T> + 'd, 103 twim: impl Peripheral<P = T> + 'd,
82 irq: impl Peripheral<P = T::Interrupt> + 'd, 104 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -153,7 +175,7 @@ impl<'d, T: Instance> Twim<'d, T> {
153 175
154 /// Set TX buffer, checking that it is in RAM and has suitable length. 176 /// Set TX buffer, checking that it is in RAM and has suitable length.
155 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { 177 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
156 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; 178 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
157 179
158 if buffer.len() > EASY_DMA_SIZE { 180 if buffer.len() > EASY_DMA_SIZE {
159 return Err(Error::TxBufferTooLong); 181 return Err(Error::TxBufferTooLong);
@@ -233,7 +255,7 @@ impl<'d, T: Instance> Twim<'d, T> {
233 return Err(Error::DataNack); 255 return Err(Error::DataNack);
234 } 256 }
235 if err.overrun().is_received() { 257 if err.overrun().is_received() {
236 return Err(Error::DataNack); 258 return Err(Error::Overrun);
237 } 259 }
238 Ok(()) 260 Ok(())
239 } 261 }
@@ -435,7 +457,7 @@ impl<'d, T: Instance> Twim<'d, T> {
435 ) -> Result<(), Error> { 457 ) -> Result<(), Error> {
436 match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) { 458 match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) {
437 Ok(_) => Ok(()), 459 Ok(_) => Ok(()),
438 Err(Error::DMABufferNotInDataMemory) => { 460 Err(Error::BufferNotInRAM) => {
439 trace!("Copying TWIM tx buffer into RAM for DMA"); 461 trace!("Copying TWIM tx buffer into RAM for DMA");
440 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; 462 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
441 tx_ram_buf.copy_from_slice(wr_buffer); 463 tx_ram_buf.copy_from_slice(wr_buffer);
@@ -448,7 +470,7 @@ impl<'d, T: Instance> Twim<'d, T> {
448 fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { 470 fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> {
449 match self.setup_write_from_ram(address, wr_buffer, inten) { 471 match self.setup_write_from_ram(address, wr_buffer, inten) {
450 Ok(_) => Ok(()), 472 Ok(_) => Ok(()),
451 Err(Error::DMABufferNotInDataMemory) => { 473 Err(Error::BufferNotInRAM) => {
452 trace!("Copying TWIM tx buffer into RAM for DMA"); 474 trace!("Copying TWIM tx buffer into RAM for DMA");
453 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; 475 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
454 tx_ram_buf.copy_from_slice(wr_buffer); 476 tx_ram_buf.copy_from_slice(wr_buffer);
@@ -612,6 +634,10 @@ impl<'d, T: Instance> Twim<'d, T> {
612 634
613 // =========================================== 635 // ===========================================
614 636
637 /// Read from an I2C slave.
638 ///
639 /// The buffer must have a length of at most 255 bytes on the nRF52832
640 /// and at most 65535 bytes on the nRF52840.
615 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 641 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
616 self.setup_read(address, buffer, true)?; 642 self.setup_read(address, buffer, true)?;
617 self.async_wait().await; 643 self.async_wait().await;
@@ -621,6 +647,10 @@ impl<'d, T: Instance> Twim<'d, T> {
621 Ok(()) 647 Ok(())
622 } 648 }
623 649
650 /// Write to an I2C slave.
651 ///
652 /// The buffer must have a length of at most 255 bytes on the nRF52832
653 /// and at most 65535 bytes on the nRF52840.
624 pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { 654 pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
625 self.setup_write(address, buffer, true)?; 655 self.setup_write(address, buffer, true)?;
626 self.async_wait().await; 656 self.async_wait().await;
@@ -640,6 +670,11 @@ impl<'d, T: Instance> Twim<'d, T> {
640 Ok(()) 670 Ok(())
641 } 671 }
642 672
673 /// Write data to an I2C slave, then read data from the slave without
674 /// triggering a stop condition between the two.
675 ///
676 /// The buffers must have a length of at most 255 bytes on the nRF52832
677 /// and at most 65535 bytes on the nRF52840.
643 pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { 678 pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> {
644 self.setup_write_read(address, wr_buffer, rd_buffer, true)?; 679 self.setup_write_read(address, wr_buffer, rd_buffer, true)?;
645 self.async_wait().await; 680 self.async_wait().await;
@@ -705,7 +740,9 @@ pub(crate) mod sealed {
705 } 740 }
706} 741}
707 742
743/// TWIM peripheral instance.
708pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 744pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
745 /// Interrupt for this peripheral.
709 type Interrupt: Interrupt; 746 type Interrupt: Interrupt;
710} 747}
711 748
@@ -776,7 +813,7 @@ mod eh1 {
776 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, 813 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
777 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, 814 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
778 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, 815 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
779 Self::DMABufferNotInDataMemory => embedded_hal_1::i2c::ErrorKind::Other, 816 Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other,
780 Self::AddressNack => { 817 Self::AddressNack => {
781 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 818 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
782 } 819 }
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index 4091b017e..51a70c308 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -1,11 +1,7 @@
1//! I2C-compatible Two Wire Interface in slave mode (TWIM) driver.
2
1#![macro_use] 3#![macro_use]
2 4
3//! HAL interface to the TWIS peripheral.
4//!
5//! See product specification:
6//!
7//! - nRF52832: Section 33
8//! - nRF52840: Section 6.31
9use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
10use core::sync::atomic::compiler_fence; 6use core::sync::atomic::compiler_fence;
11use core::sync::atomic::Ordering::SeqCst; 7use core::sync::atomic::Ordering::SeqCst;
@@ -22,14 +18,37 @@ use crate::interrupt::{Interrupt, InterruptExt};
22use crate::util::slice_in_ram_or; 18use crate::util::slice_in_ram_or;
23use crate::{gpio, pac, Peripheral}; 19use crate::{gpio, pac, Peripheral};
24 20
21/// TWIS config.
25#[non_exhaustive] 22#[non_exhaustive]
26pub struct Config { 23pub struct Config {
24 /// First address
27 pub address0: u8, 25 pub address0: u8,
26
27 /// Second address, optional.
28 pub address1: Option<u8>, 28 pub address1: Option<u8>,
29
30 /// Overread character.
31 ///
32 /// If the master keeps clocking the bus after all the bytes in the TX buffer have
33 /// already been transmitted, this byte will be constantly transmitted.
29 pub orc: u8, 34 pub orc: u8,
35
36 /// Enable high drive for the SDA line.
30 pub sda_high_drive: bool, 37 pub sda_high_drive: bool,
38
39 /// Enable internal pullup for the SDA line.
40 ///
41 /// Note that using external pullups is recommended for I2C, and
42 /// most boards already have them.
31 pub sda_pullup: bool, 43 pub sda_pullup: bool,
44
45 /// Enable high drive for the SCL line.
32 pub scl_high_drive: bool, 46 pub scl_high_drive: bool,
47
48 /// Enable internal pullup for the SCL line.
49 ///
50 /// Note that using external pullups is recommended for I2C, and
51 /// most boards already have them.
33 pub scl_pullup: bool, 52 pub scl_pullup: bool,
34} 53}
35 54
@@ -54,36 +73,48 @@ enum Status {
54 Write, 73 Write,
55} 74}
56 75
76/// TWIS error.
57#[derive(Debug, Copy, Clone, Eq, PartialEq)] 77#[derive(Debug, Copy, Clone, Eq, PartialEq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))] 78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[non_exhaustive] 79#[non_exhaustive]
60pub enum Error { 80pub enum Error {
81 /// TX buffer was too long.
61 TxBufferTooLong, 82 TxBufferTooLong,
83 /// TX buffer was too long.
62 RxBufferTooLong, 84 RxBufferTooLong,
85 /// Didn't receive an ACK bit after a data byte.
63 DataNack, 86 DataNack,
87 /// Bus error.
64 Bus, 88 Bus,
65 DMABufferNotInDataMemory, 89 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
90 BufferNotInRAM,
91 /// Overflow
66 Overflow, 92 Overflow,
93 /// Overread
67 OverRead, 94 OverRead,
95 /// Timeout
68 Timeout, 96 Timeout,
69} 97}
70 98
99/// Received command
71#[derive(Debug, Copy, Clone, Eq, PartialEq)] 100#[derive(Debug, Copy, Clone, Eq, PartialEq)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))] 101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub enum Command { 102pub enum Command {
103 /// Read
74 Read, 104 Read,
105 /// Write+read
75 WriteRead(usize), 106 WriteRead(usize),
107 /// Write
76 Write(usize), 108 Write(usize),
77} 109}
78 110
79/// Interface to a TWIS instance using EasyDMA to offload the transmission and reception workload. 111/// TWIS driver.
80///
81/// For more details about EasyDMA, consult the module documentation.
82pub struct Twis<'d, T: Instance> { 112pub struct Twis<'d, T: Instance> {
83 _p: PeripheralRef<'d, T>, 113 _p: PeripheralRef<'d, T>,
84} 114}
85 115
86impl<'d, T: Instance> Twis<'d, T> { 116impl<'d, T: Instance> Twis<'d, T> {
117 /// Create a new TWIS driver.
87 pub fn new( 118 pub fn new(
88 twis: impl Peripheral<P = T> + 'd, 119 twis: impl Peripheral<P = T> + 'd,
89 irq: impl Peripheral<P = T::Interrupt> + 'd, 120 irq: impl Peripheral<P = T::Interrupt> + 'd,
@@ -174,7 +205,7 @@ impl<'d, T: Instance> Twis<'d, T> {
174 205
175 /// Set TX buffer, checking that it is in RAM and has suitable length. 206 /// Set TX buffer, checking that it is in RAM and has suitable length.
176 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { 207 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
177 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; 208 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
178 209
179 if buffer.len() > EASY_DMA_SIZE { 210 if buffer.len() > EASY_DMA_SIZE {
180 return Err(Error::TxBufferTooLong); 211 return Err(Error::TxBufferTooLong);
@@ -535,7 +566,7 @@ impl<'d, T: Instance> Twis<'d, T> {
535 fn setup_respond(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { 566 fn setup_respond(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> {
536 match self.setup_respond_from_ram(wr_buffer, inten) { 567 match self.setup_respond_from_ram(wr_buffer, inten) {
537 Ok(_) => Ok(()), 568 Ok(_) => Ok(()),
538 Err(Error::DMABufferNotInDataMemory) => { 569 Err(Error::BufferNotInRAM) => {
539 trace!("Copying TWIS tx buffer into RAM for DMA"); 570 trace!("Copying TWIS tx buffer into RAM for DMA");
540 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; 571 let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()];
541 tx_ram_buf.copy_from_slice(wr_buffer); 572 tx_ram_buf.copy_from_slice(wr_buffer);
@@ -737,7 +768,9 @@ pub(crate) mod sealed {
737 } 768 }
738} 769}
739 770
771/// TWIS peripheral instance.
740pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 772pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
773 /// Interrupt for this peripheral.
741 type Interrupt: Interrupt; 774 type Interrupt: Interrupt;
742} 775}
743 776
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 031cf82fd..48457744b 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -1,8 +1,6 @@
1#![macro_use] 1//! Universal Asynchronous Receiver Transmitter (UART) driver.
2
3//! Async UART
4//! 2//!
5//! Async UART is provided in two flavors - this one and also [crate::buffered_uarte::BufferedUarte]. 3//! The UART driver is provided in two flavors - this one and also [crate::buffered_uarte::BufferedUarte].
6//! The [Uarte] here is useful for those use-cases where reading the UARTE peripheral is 4//! The [Uarte] here is useful for those use-cases where reading the UARTE peripheral is
7//! exclusively awaited on. If the [Uarte] is required to be awaited on with some other future, 5//! exclusively awaited on. If the [Uarte] is required to be awaited on with some other future,
8//! for example when using `futures_util::future::select`, then you should consider 6//! for example when using `futures_util::future::select`, then you should consider
@@ -13,6 +11,8 @@
13//! memory may be used given that buffers are passed in directly to its read and write 11//! memory may be used given that buffers are passed in directly to its read and write
14//! methods. 12//! methods.
15 13
14#![macro_use]
15
16use core::future::poll_fn; 16use core::future::poll_fn;
17use core::sync::atomic::{compiler_fence, Ordering}; 17use core::sync::atomic::{compiler_fence, Ordering};
18use core::task::Poll; 18use core::task::Poll;
@@ -32,10 +32,13 @@ use crate::timer::{Frequency, Instance as TimerInstance, Timer};
32use crate::util::slice_in_ram_or; 32use crate::util::slice_in_ram_or;
33use crate::{pac, Peripheral}; 33use crate::{pac, Peripheral};
34 34
35/// UARTE config.
35#[derive(Clone)] 36#[derive(Clone)]
36#[non_exhaustive] 37#[non_exhaustive]
37pub struct Config { 38pub struct Config {
39 /// Parity bit.
38 pub parity: Parity, 40 pub parity: Parity,
41 /// Baud rate.
39 pub baudrate: Baudrate, 42 pub baudrate: Baudrate,
40} 43}
41 44
@@ -48,31 +51,33 @@ impl Default for Config {
48 } 51 }
49} 52}
50 53
54/// UART error.
51#[derive(Debug, Clone, Copy, PartialEq, Eq)] 55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))] 56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53#[non_exhaustive] 57#[non_exhaustive]
54pub enum Error { 58pub enum Error {
59 /// Buffer was too long.
55 BufferTooLong, 60 BufferTooLong,
56 DMABufferNotInDataMemory, 61 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
57 // TODO: add other error variants. 62 BufferNotInRAM,
58} 63}
59 64
60/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload. 65/// UARTE driver.
61///
62/// For more details about EasyDMA, consult the module documentation.
63pub struct Uarte<'d, T: Instance> { 66pub struct Uarte<'d, T: Instance> {
64 tx: UarteTx<'d, T>, 67 tx: UarteTx<'d, T>,
65 rx: UarteRx<'d, T>, 68 rx: UarteRx<'d, T>,
66} 69}
67 70
68/// Transmitter interface to the UARTE peripheral obtained 71/// Transmitter part of the UARTE driver.
69/// via [Uarte]::split. 72///
73/// This can be obtained via [`Uarte::split`], or created directly.
70pub struct UarteTx<'d, T: Instance> { 74pub struct UarteTx<'d, T: Instance> {
71 _p: PeripheralRef<'d, T>, 75 _p: PeripheralRef<'d, T>,
72} 76}
73 77
74/// Receiver interface to the UARTE peripheral obtained 78/// Receiver part of the UARTE driver.
75/// via [Uarte]::split. 79///
80/// This can be obtained via [`Uarte::split`], or created directly.
76pub struct UarteRx<'d, T: Instance> { 81pub struct UarteRx<'d, T: Instance> {
77 _p: PeripheralRef<'d, T>, 82 _p: PeripheralRef<'d, T>,
78} 83}
@@ -165,16 +170,16 @@ impl<'d, T: Instance> Uarte<'d, T> {
165 } 170 }
166 } 171 }
167 172
168 /// Split the Uarte into a transmitter and receiver, which is 173 /// Split the Uarte into the transmitter and receiver parts.
169 /// particularly useful when having two tasks correlating to 174 ///
170 /// transmitting and receiving. 175 /// This is useful to concurrently transmit and receive from independent tasks.
171 pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) { 176 pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) {
172 (self.tx, self.rx) 177 (self.tx, self.rx)
173 } 178 }
174 179
175 /// Split the Uarte into a transmitter and receiver that will 180 /// Split the Uarte into the transmitter and receiver with idle support parts.
176 /// return on idle, which is determined as the time it takes 181 ///
177 /// for two bytes to be received. 182 /// This is useful to concurrently transmit and receive from independent tasks.
178 pub fn split_with_idle<U: TimerInstance>( 183 pub fn split_with_idle<U: TimerInstance>(
179 self, 184 self,
180 timer: impl Peripheral<P = U> + 'd, 185 timer: impl Peripheral<P = U> + 'd,
@@ -247,10 +252,12 @@ impl<'d, T: Instance> Uarte<'d, T> {
247 } 252 }
248 } 253 }
249 254
255 /// Read bytes until the buffer is filled.
250 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 256 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
251 self.rx.read(buffer).await 257 self.rx.read(buffer).await
252 } 258 }
253 259
260 /// Write all bytes in the buffer.
254 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 261 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
255 self.tx.write(buffer).await 262 self.tx.write(buffer).await
256 } 263 }
@@ -260,10 +267,12 @@ impl<'d, T: Instance> Uarte<'d, T> {
260 self.tx.write_from_ram(buffer).await 267 self.tx.write_from_ram(buffer).await
261 } 268 }
262 269
270 /// Read bytes until the buffer is filled.
263 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 271 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
264 self.rx.blocking_read(buffer) 272 self.rx.blocking_read(buffer)
265 } 273 }
266 274
275 /// Write all bytes in the buffer.
267 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 276 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
268 self.tx.blocking_write(buffer) 277 self.tx.blocking_write(buffer)
269 } 278 }
@@ -355,10 +364,11 @@ impl<'d, T: Instance> UarteTx<'d, T> {
355 Self { _p: uarte } 364 Self { _p: uarte }
356 } 365 }
357 366
367 /// Write all bytes in the buffer.
358 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 368 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
359 match self.write_from_ram(buffer).await { 369 match self.write_from_ram(buffer).await {
360 Ok(_) => Ok(()), 370 Ok(_) => Ok(()),
361 Err(Error::DMABufferNotInDataMemory) => { 371 Err(Error::BufferNotInRAM) => {
362 trace!("Copying UARTE tx buffer into RAM for DMA"); 372 trace!("Copying UARTE tx buffer into RAM for DMA");
363 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; 373 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()];
364 ram_buf.copy_from_slice(buffer); 374 ram_buf.copy_from_slice(buffer);
@@ -368,12 +378,13 @@ impl<'d, T: Instance> UarteTx<'d, T> {
368 } 378 }
369 } 379 }
370 380
381 /// Same as [`write`](Self::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
371 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { 382 pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
372 if buffer.len() == 0 { 383 if buffer.len() == 0 {
373 return Ok(()); 384 return Ok(());
374 } 385 }
375 386
376 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; 387 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
377 if buffer.len() > EASY_DMA_SIZE { 388 if buffer.len() > EASY_DMA_SIZE {
378 return Err(Error::BufferTooLong); 389 return Err(Error::BufferTooLong);
379 } 390 }
@@ -423,10 +434,11 @@ impl<'d, T: Instance> UarteTx<'d, T> {
423 Ok(()) 434 Ok(())
424 } 435 }
425 436
437 /// Write all bytes in the buffer.
426 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 438 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
427 match self.blocking_write_from_ram(buffer) { 439 match self.blocking_write_from_ram(buffer) {
428 Ok(_) => Ok(()), 440 Ok(_) => Ok(()),
429 Err(Error::DMABufferNotInDataMemory) => { 441 Err(Error::BufferNotInRAM) => {
430 trace!("Copying UARTE tx buffer into RAM for DMA"); 442 trace!("Copying UARTE tx buffer into RAM for DMA");
431 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; 443 let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()];
432 ram_buf.copy_from_slice(buffer); 444 ram_buf.copy_from_slice(buffer);
@@ -436,12 +448,13 @@ impl<'d, T: Instance> UarteTx<'d, T> {
436 } 448 }
437 } 449 }
438 450
451 /// Same as [`write_from_ram`](Self::write_from_ram) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
439 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { 452 pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> {
440 if buffer.len() == 0 { 453 if buffer.len() == 0 {
441 return Ok(()); 454 return Ok(());
442 } 455 }
443 456
444 slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; 457 slice_in_ram_or(buffer, Error::BufferNotInRAM)?;
445 if buffer.len() > EASY_DMA_SIZE { 458 if buffer.len() > EASY_DMA_SIZE {
446 return Err(Error::BufferTooLong); 459 return Err(Error::BufferTooLong);
447 } 460 }
@@ -549,6 +562,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
549 Self { _p: uarte } 562 Self { _p: uarte }
550 } 563 }
551 564
565 /// Read bytes until the buffer is filled.
552 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 566 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
553 if buffer.len() == 0 { 567 if buffer.len() == 0 {
554 return Ok(()); 568 return Ok(());
@@ -602,6 +616,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
602 Ok(()) 616 Ok(())
603 } 617 }
604 618
619 /// Read bytes until the buffer is filled.
605 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 620 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
606 if buffer.len() == 0 { 621 if buffer.len() == 0 {
607 return Ok(()); 622 return Ok(());
@@ -653,6 +668,9 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> {
653 } 668 }
654} 669}
655 670
671/// Receiver part of the UARTE driver, with `read_until_idle` support.
672///
673/// This can be obtained via [`Uarte::split_with_idle`].
656pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> { 674pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> {
657 rx: UarteRx<'d, T>, 675 rx: UarteRx<'d, T>,
658 timer: Timer<'d, U>, 676 timer: Timer<'d, U>,
@@ -661,16 +679,21 @@ pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> {
661} 679}
662 680
663impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { 681impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
682 /// Read bytes until the buffer is filled.
664 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 683 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
665 self.ppi_ch1.disable(); 684 self.ppi_ch1.disable();
666 self.rx.read(buffer).await 685 self.rx.read(buffer).await
667 } 686 }
668 687
688 /// Read bytes until the buffer is filled.
669 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 689 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
670 self.ppi_ch1.disable(); 690 self.ppi_ch1.disable();
671 self.rx.blocking_read(buffer) 691 self.rx.blocking_read(buffer)
672 } 692 }
673 693
694 /// Read bytes until the buffer is filled, or the line becomes idle.
695 ///
696 /// Returns the amount of bytes read.
674 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 697 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
675 if buffer.len() == 0 { 698 if buffer.len() == 0 {
676 return Ok(0); 699 return Ok(0);
@@ -727,6 +750,9 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
727 Ok(n) 750 Ok(n)
728 } 751 }
729 752
753 /// Read bytes until the buffer is filled, or the line becomes idle.
754 ///
755 /// Returns the amount of bytes read.
730 pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 756 pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
731 if buffer.len() == 0 { 757 if buffer.len() == 0 {
732 return Ok(0); 758 return Ok(0);
@@ -860,7 +886,9 @@ pub(crate) mod sealed {
860 } 886 }
861} 887}
862 888
889/// UARTE peripheral instance.
863pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 890pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
891 /// Interrupt for this peripheral.
864 type Interrupt: Interrupt; 892 type Interrupt: Interrupt;
865} 893}
866 894
@@ -919,7 +947,7 @@ mod eh1 {
919 fn kind(&self) -> embedded_hal_1::serial::ErrorKind { 947 fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
920 match *self { 948 match *self {
921 Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, 949 Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other,
922 Self::DMABufferNotInDataMemory => embedded_hal_1::serial::ErrorKind::Other, 950 Self::BufferNotInRAM => embedded_hal_1::serial::ErrorKind::Other,
923 } 951 }
924 } 952 }
925 } 953 }
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index f030b909f..cd142f00f 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -1,3 +1,5 @@
1//! Universal Serial Bus (USB) driver.
2
1#![macro_use] 3#![macro_use]
2 4
3use core::future::poll_fn; 5use core::future::poll_fn;
@@ -24,38 +26,38 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
24static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; 26static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8];
25static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); 27static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
26 28
29/// Trait for detecting USB VBUS power.
30///
27/// There are multiple ways to detect USB power. The behavior 31/// There are multiple ways to detect USB power. The behavior
28/// here provides a hook into determining whether it is. 32/// here provides a hook into determining whether it is.
29pub trait UsbSupply { 33pub trait VbusDetect {
34 /// Report whether power is detected.
35 ///
36 /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the
37 /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
30 fn is_usb_detected(&self) -> bool; 38 fn is_usb_detected(&self) -> bool;
31 async fn wait_power_ready(&mut self) -> Result<(), ()>;
32}
33 39
34pub struct Driver<'d, T: Instance, P: UsbSupply> { 40 /// Wait until USB power is ready.
35 _p: PeripheralRef<'d, T>, 41 ///
36 alloc_in: Allocator, 42 /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the
37 alloc_out: Allocator, 43 /// `USBPWRRDY` event from the `POWER` peripheral.
38 usb_supply: P, 44 async fn wait_power_ready(&mut self) -> Result<(), ()>;
39} 45}
40 46
41/// Uses the POWER peripheral to detect when power is available 47/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
42/// for USB. Unsuitable for usage with the nRF softdevice. 48///
49/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
50/// to POWER. In that case, use [`VbusDetectSignal`].
43#[cfg(not(feature = "_nrf5340-app"))] 51#[cfg(not(feature = "_nrf5340-app"))]
44pub struct PowerUsb { 52pub struct HardwareVbusDetect {
45 _private: (), 53 _private: (),
46} 54}
47 55
48/// Can be used to signal that power is available. Particularly suited for
49/// use with the nRF softdevice.
50pub struct SignalledSupply {
51 usb_detected: AtomicBool,
52 power_ready: AtomicBool,
53}
54
55static POWER_WAKER: AtomicWaker = NEW_AW; 56static POWER_WAKER: AtomicWaker = NEW_AW;
56 57
57#[cfg(not(feature = "_nrf5340-app"))] 58#[cfg(not(feature = "_nrf5340-app"))]
58impl PowerUsb { 59impl HardwareVbusDetect {
60 /// Create a new `VbusDetectNative`.
59 pub fn new(power_irq: impl Interrupt) -> Self { 61 pub fn new(power_irq: impl Interrupt) -> Self {
60 let regs = unsafe { &*pac::POWER::ptr() }; 62 let regs = unsafe { &*pac::POWER::ptr() };
61 63
@@ -92,7 +94,7 @@ impl PowerUsb {
92} 94}
93 95
94#[cfg(not(feature = "_nrf5340-app"))] 96#[cfg(not(feature = "_nrf5340-app"))]
95impl UsbSupply for PowerUsb { 97impl VbusDetect for HardwareVbusDetect {
96 fn is_usb_detected(&self) -> bool { 98 fn is_usb_detected(&self) -> bool {
97 let regs = unsafe { &*pac::POWER::ptr() }; 99 let regs = unsafe { &*pac::POWER::ptr() };
98 regs.usbregstatus.read().vbusdetect().is_vbus_present() 100 regs.usbregstatus.read().vbusdetect().is_vbus_present()
@@ -115,7 +117,20 @@ impl UsbSupply for PowerUsb {
115 } 117 }
116} 118}
117 119
118impl SignalledSupply { 120/// Software-backed [`VbusDetect`] implementation.
121///
122/// This implementation does not interact with the hardware, it allows user code
123/// to notify the power events by calling functions instead.
124///
125/// This is suitable for use with the nRF softdevice, by calling the functions
126/// when the softdevice reports power-related events.
127pub struct SoftwareVbusDetect {
128 usb_detected: AtomicBool,
129 power_ready: AtomicBool,
130}
131
132impl SoftwareVbusDetect {
133 /// Create a new `SoftwareVbusDetect`.
119 pub fn new(usb_detected: bool, power_ready: bool) -> Self { 134 pub fn new(usb_detected: bool, power_ready: bool) -> Self {
120 BUS_WAKER.wake(); 135 BUS_WAKER.wake();
121 136
@@ -125,6 +140,9 @@ impl SignalledSupply {
125 } 140 }
126 } 141 }
127 142
143 /// Report whether power was detected.
144 ///
145 /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral.
128 pub fn detected(&self, detected: bool) { 146 pub fn detected(&self, detected: bool) {
129 self.usb_detected.store(detected, Ordering::Relaxed); 147 self.usb_detected.store(detected, Ordering::Relaxed);
130 self.power_ready.store(false, Ordering::Relaxed); 148 self.power_ready.store(false, Ordering::Relaxed);
@@ -132,13 +150,16 @@ impl SignalledSupply {
132 POWER_WAKER.wake(); 150 POWER_WAKER.wake();
133 } 151 }
134 152
153 /// Report when USB power is ready.
154 ///
155 /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral.
135 pub fn ready(&self) { 156 pub fn ready(&self) {
136 self.power_ready.store(true, Ordering::Relaxed); 157 self.power_ready.store(true, Ordering::Relaxed);
137 POWER_WAKER.wake(); 158 POWER_WAKER.wake();
138 } 159 }
139} 160}
140 161
141impl UsbSupply for &SignalledSupply { 162impl VbusDetect for &SoftwareVbusDetect {
142 fn is_usb_detected(&self) -> bool { 163 fn is_usb_detected(&self) -> bool {
143 self.usb_detected.load(Ordering::Relaxed) 164 self.usb_detected.load(Ordering::Relaxed)
144 } 165 }
@@ -159,7 +180,16 @@ impl UsbSupply for &SignalledSupply {
159 } 180 }
160} 181}
161 182
162impl<'d, T: Instance, P: UsbSupply> Driver<'d, T, P> { 183/// USB driver.
184pub struct Driver<'d, T: Instance, P: VbusDetect> {
185 _p: PeripheralRef<'d, T>,
186 alloc_in: Allocator,
187 alloc_out: Allocator,
188 usb_supply: P,
189}
190
191impl<'d, T: Instance, P: VbusDetect> Driver<'d, T, P> {
192 /// Create a new USB driver.
163 pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self { 193 pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self {
164 into_ref!(usb, irq); 194 into_ref!(usb, irq);
165 irq.set_handler(Self::on_interrupt); 195 irq.set_handler(Self::on_interrupt);
@@ -225,7 +255,7 @@ impl<'d, T: Instance, P: UsbSupply> Driver<'d, T, P> {
225 } 255 }
226} 256}
227 257
228impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> { 258impl<'d, T: Instance, P: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, P> {
229 type EndpointOut = Endpoint<'d, T, Out>; 259 type EndpointOut = Endpoint<'d, T, Out>;
230 type EndpointIn = Endpoint<'d, T, In>; 260 type EndpointIn = Endpoint<'d, T, In>;
231 type ControlPipe = ControlPipe<'d, T>; 261 type ControlPipe = ControlPipe<'d, T>;
@@ -278,13 +308,14 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
278 } 308 }
279} 309}
280 310
281pub struct Bus<'d, T: Instance, P: UsbSupply> { 311/// USB bus.
312pub struct Bus<'d, T: Instance, P: VbusDetect> {
282 _p: PeripheralRef<'d, T>, 313 _p: PeripheralRef<'d, T>,
283 power_available: bool, 314 power_available: bool,
284 usb_supply: P, 315 usb_supply: P,
285} 316}
286 317
287impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { 318impl<'d, T: Instance, P: VbusDetect> driver::Bus for Bus<'d, T, P> {
288 async fn enable(&mut self) { 319 async fn enable(&mut self) {
289 let regs = T::regs(); 320 let regs = T::regs();
290 321
@@ -513,7 +544,10 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
513 } 544 }
514} 545}
515 546
547/// Type-level marker for OUT endpoints.
516pub enum Out {} 548pub enum Out {}
549
550/// Type-level marker for IN endpoints.
517pub enum In {} 551pub enum In {}
518 552
519trait EndpointDir { 553trait EndpointDir {
@@ -556,6 +590,7 @@ impl EndpointDir for Out {
556 } 590 }
557} 591}
558 592
593/// USB endpoint.
559pub struct Endpoint<'d, T: Instance, Dir> { 594pub struct Endpoint<'d, T: Instance, Dir> {
560 _phantom: PhantomData<(&'d mut T, Dir)>, 595 _phantom: PhantomData<(&'d mut T, Dir)>,
561 info: EndpointInfo, 596 info: EndpointInfo,
@@ -715,6 +750,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
715 } 750 }
716} 751}
717 752
753/// USB control pipe.
718pub struct ControlPipe<'d, T: Instance> { 754pub struct ControlPipe<'d, T: Instance> {
719 _p: PeripheralRef<'d, T>, 755 _p: PeripheralRef<'d, T>,
720 max_packet_size: u16, 756 max_packet_size: u16,
@@ -905,7 +941,9 @@ pub(crate) mod sealed {
905 } 941 }
906} 942}
907 943
944/// USB peripheral instance.
908pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 945pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
946 /// Interrupt for this peripheral.
909 type Interrupt: Interrupt; 947 type Interrupt: Interrupt;
910} 948}
911 949
diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs
index 330ca98bf..40a674424 100644
--- a/embassy-nrf/src/wdt.rs
+++ b/embassy-nrf/src/wdt.rs
@@ -1,4 +1,4 @@
1//! HAL interface to the WDT peripheral. 1//! Watchdog Timer (WDT) driver.
2//! 2//!
3//! This HAL implements a basic watchdog timer with 1..=8 handles. 3//! This HAL implements a basic watchdog timer with 1..=8 handles.
4//! Once the watchdog has been started, it cannot be stopped. 4//! Once the watchdog has been started, it cannot be stopped.
@@ -8,6 +8,7 @@ use crate::peripherals;
8 8
9const MIN_TICKS: u32 = 15; 9const MIN_TICKS: u32 = 15;
10 10
11/// WDT configuration.
11#[non_exhaustive] 12#[non_exhaustive]
12pub struct Config { 13pub struct Config {
13 /// Number of 32768 Hz ticks in each watchdog period. 14 /// Number of 32768 Hz ticks in each watchdog period.
@@ -57,13 +58,13 @@ impl Default for Config {
57 } 58 }
58} 59}
59 60
60/// An interface to the Watchdog. 61/// Watchdog driver.
61pub struct Watchdog { 62pub struct Watchdog {
62 _private: (), 63 _private: (),
63} 64}
64 65
65impl Watchdog { 66impl Watchdog {
66 /// Try to create a new watchdog instance from the peripheral. 67 /// Try to create a new watchdog driver.
67 /// 68 ///
68 /// This function will return an error if the watchdog is already active 69 /// This function will return an error if the watchdog is already active
69 /// with a `config` different to the requested one, or a different number of 70 /// with a `config` different to the requested one, or a different number of
@@ -155,6 +156,7 @@ impl Watchdog {
155 } 156 }
156} 157}
157 158
159/// Watchdog handle.
158pub struct WatchdogHandle { 160pub struct WatchdogHandle {
159 index: u8, 161 index: u8,
160} 162}