aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-hal-common/src/macros.rs6
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_declare.rs3
-rw-r--r--embassy-nrf/README.md58
-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
-rw-r--r--examples/nrf52840/Cargo.toml2
-rw-r--r--examples/nrf52840/src/bin/i2s_effect.rs6
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs6
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs6
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs4
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs6
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs4
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs4
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs6
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs6
40 files changed, 694 insertions, 245 deletions
diff --git a/embassy-hal-common/src/macros.rs b/embassy-hal-common/src/macros.rs
index 7af85f782..da7913136 100644
--- a/embassy-hal-common/src/macros.rs
+++ b/embassy-hal-common/src/macros.rs
@@ -1,10 +1,12 @@
1#[macro_export] 1#[macro_export]
2macro_rules! peripherals { 2macro_rules! peripherals {
3 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => { 3 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
4 /// Types for the peripheral singletons.
4 pub mod peripherals { 5 pub mod peripherals {
5 $( 6 $(
6 $(#[$cfg])? 7 $(#[$cfg])?
7 #[allow(non_camel_case_types)] 8 #[allow(non_camel_case_types)]
9 #[doc = concat!(stringify!($name), " peripheral")]
8 pub struct $name { _private: () } 10 pub struct $name { _private: () }
9 11
10 $(#[$cfg])? 12 $(#[$cfg])?
@@ -25,9 +27,13 @@ macro_rules! peripherals {
25 )* 27 )*
26 } 28 }
27 29
30 /// Struct containing all the peripheral singletons.
31 ///
32 /// To obtain the peripherals, you must initialize the HAL, by calling [`crate::init`].
28 #[allow(non_snake_case)] 33 #[allow(non_snake_case)]
29 pub struct Peripherals { 34 pub struct Peripherals {
30 $( 35 $(
36 #[doc = concat!(stringify!($name), " peripheral")]
31 $(#[$cfg])? 37 $(#[$cfg])?
32 pub $name: peripherals::$name, 38 pub $name: peripherals::$name,
33 )* 39 )*
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
index ab61ad5da..ebbb47cd7 100644
--- a/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
+++ b/embassy-macros/src/macros/cortex_m_interrupt_declare.rs
@@ -6,7 +6,10 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
6 let name_interrupt = format_ident!("{}", name); 6 let name_interrupt = format_ident!("{}", name);
7 let name_handler = format!("__EMBASSY_{}_HANDLER", name); 7 let name_handler = format!("__EMBASSY_{}_HANDLER", name);
8 8
9 let doc = format!("{} interrupt singleton.", name);
10
9 let result = quote! { 11 let result = quote! {
12 #[doc = #doc]
10 #[allow(non_camel_case_types)] 13 #[allow(non_camel_case_types)]
11 pub struct #name_interrupt(()); 14 pub struct #name_interrupt(());
12 unsafe impl ::embassy_cortex_m::interrupt::Interrupt for #name_interrupt { 15 unsafe impl ::embassy_cortex_m::interrupt::Interrupt for #name_interrupt {
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
new file mode 100644
index 000000000..a31cfae68
--- /dev/null
+++ b/embassy-nrf/README.md
@@ -0,0 +1,58 @@
1# Embassy nRF HAL
2
3HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed.
4
5The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The HAL implements both blocking and async APIs
6for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to
7complete operations in low power mod and handling interrupts, so that applications can focus on more important matters.
8
9## EasyDMA considerations
10
11On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
12with peripherals. It takes care of sending/receiving data over a variety of bus protocols (TWI/I2C, UART, SPI).
13However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust
14slices 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.
21let result = spim.write_from_ram(&[1, 2, 3]);
22assert_eq!(result, Err(Error::BufferNotInRAM));
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.
28let data = [1, 2, 3];
29let result = spim.write_from_ram(&data);
30assert!(result.is_ok());
31```
32
33Each 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
37Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will
38fail and notify you, or the more convenient versions without the suffix which are potentially a little bit
39more inefficient. Be aware that this overhead is not only in terms of instruction count but also in terms of memory usage
40as the methods without the suffix will be allocating a statically sized buffer (up to 512 bytes for the nRF52840).
41
42Note 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
43mutable slices always reside in RAM.
44
45## Minimum supported Rust version (MSRV)
46
47Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
48
49## License
50
51This work is licensed under either of
52
53- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
54 <http://www.apache.org/licenses/LICENSE-2.0>)
55- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
56
57at your option.
58
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}
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index bbd8a5d2f..95d939873 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -14,7 +14,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 14embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
15embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 15embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
16embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 16embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
17embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 17embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
18embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } 18embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
19embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } 19embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
20embedded-io = "0.4.0" 20embedded-io = "0.4.0"
diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs
index 3cca005b1..52d46e4f9 100644
--- a/examples/nrf52840/src/bin/i2s_effect.rs
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -24,9 +24,9 @@ async fn main(_spawner: Spawner) {
24 let sample_rate = master_clock.sample_rate(); 24 let sample_rate = master_clock.sample_rate();
25 info!("Sample rate: {}", sample_rate); 25 info!("Sample rate: {}", sample_rate);
26 26
27 let config = Config::default() 27 let mut config = Config::default();
28 .sample_width(SampleWidth::_16bit) 28 config.sample_width = SampleWidth::_16bit;
29 .channels(Channels::MonoLeft); 29 config.channels = Channels::MonoLeft;
30 30
31 let irq = interrupt::take!(I2S); 31 let irq = interrupt::take!(I2S);
32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new(); 32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
index 48eb7d581..5ebfd9542 100644
--- a/examples/nrf52840/src/bin/i2s_monitor.rs
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -22,9 +22,9 @@ async fn main(_spawner: Spawner) {
22 let sample_rate = master_clock.sample_rate(); 22 let sample_rate = master_clock.sample_rate();
23 info!("Sample rate: {}", sample_rate); 23 info!("Sample rate: {}", sample_rate);
24 24
25 let config = Config::default() 25 let mut config = Config::default();
26 .sample_width(SampleWidth::_16bit) 26 config.sample_width = SampleWidth::_16bit;
27 .channels(Channels::MonoLeft); 27 config.channels = Channels::MonoLeft;
28 28
29 let irq = interrupt::take!(I2S); 29 let irq = interrupt::take!(I2S);
30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); 30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
index 1b0e8ebc8..eda930677 100644
--- a/examples/nrf52840/src/bin/i2s_waveform.rs
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -23,9 +23,9 @@ async fn main(_spawner: Spawner) {
23 let sample_rate = master_clock.sample_rate(); 23 let sample_rate = master_clock.sample_rate();
24 info!("Sample rate: {}", sample_rate); 24 info!("Sample rate: {}", sample_rate);
25 25
26 let config = Config::default() 26 let mut config = Config::default();
27 .sample_width(SampleWidth::_16bit) 27 config.sample_width = SampleWidth::_16bit;
28 .channels(Channels::MonoLeft); 28 config.channels = Channels::MonoLeft;
29 29
30 let irq = interrupt::take!(I2S); 30 let irq = interrupt::take!(I2S);
31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new(); 31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index bb50ac65e..2551d15fd 100644
--- a/examples/nrf52840/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -5,7 +5,7 @@
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt; 7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; 8use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
9use embassy_nrf::timer::Frequency; 9use embassy_nrf::timer::Frequency;
10use embassy_time::Duration; 10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -61,7 +61,7 @@ async fn main(_p: Spawner) {
61 c = 0; 61 c = 0;
62 a = 0; 62 a = 0;
63 } 63 }
64 SamplerState::Sampled 64 CallbackResult::Continue
65 }, 65 },
66 ) 66 )
67 .await; 67 .await;
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index a8d53e460..699666cee 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -9,7 +9,7 @@ use embassy_executor::Spawner;
9use embassy_net::tcp::TcpSocket; 9use embassy_net::tcp::TcpSocket;
10use embassy_net::{Stack, StackResources}; 10use embassy_net::{Stack, StackResources};
11use embassy_nrf::rng::Rng; 11use embassy_nrf::rng::Rng;
12use embassy_nrf::usb::{Driver, PowerUsb}; 12use embassy_nrf::usb::{Driver, HardwareVbusDetect};
13use embassy_nrf::{interrupt, pac, peripherals}; 13use embassy_nrf::{interrupt, pac, peripherals};
14use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 14use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
@@ -18,7 +18,7 @@ use embedded_io::asynch::Write;
18use static_cell::StaticCell; 18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20 20
21type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>; 21type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
22 22
23macro_rules! singleton { 23macro_rules! singleton {
24 ($val:expr) => {{ 24 ($val:expr) => {{
@@ -58,7 +58,7 @@ async fn main(spawner: Spawner) {
58 // Create the driver, from the HAL. 58 // Create the driver, from the HAL.
59 let irq = interrupt::take!(USBD); 59 let irq = interrupt::take!(USBD);
60 let power_irq = interrupt::take!(POWER_CLOCK); 60 let power_irq = interrupt::take!(POWER_CLOCK);
61 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 61 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
62 62
63 // Create embassy-usb Config 63 // Create embassy-usb Config
64 let mut config = Config::new(0xc0de, 0xcafe); 64 let mut config = Config::new(0xc0de, 0xcafe);
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 76e198719..017cac197 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -10,7 +10,7 @@ use embassy_executor::Spawner;
10use embassy_futures::join::join; 10use embassy_futures::join::join;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
12use embassy_nrf::gpio::{Input, Pin, Pull}; 12use embassy_nrf::gpio::{Input, Pin, Pull};
13use embassy_nrf::usb::{Driver, PowerUsb}; 13use embassy_nrf::usb::{Driver, HardwareVbusDetect};
14use embassy_nrf::{interrupt, pac}; 14use embassy_nrf::{interrupt, pac};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
@@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) {
34 // Create the driver, from the HAL. 34 // Create the driver, from the HAL.
35 let irq = interrupt::take!(USBD); 35 let irq = interrupt::take!(USBD);
36 let power_irq = interrupt::take!(POWER_CLOCK); 36 let power_irq = interrupt::take!(POWER_CLOCK);
37 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 37 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
38 38
39 // Create embassy-usb Config 39 // Create embassy-usb Config
40 let mut config = Config::new(0xc0de, 0xcafe); 40 let mut config = Config::new(0xc0de, 0xcafe);
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 4916a38d4..a5849129a 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -7,7 +7,7 @@ use core::mem;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, PowerUsb}; 10use embassy_nrf::usb::{Driver, HardwareVbusDetect};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::{interrupt, pac};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 // Create the driver, from the HAL. 28 // Create the driver, from the HAL.
29 let irq = interrupt::take!(USBD); 29 let irq = interrupt::take!(USBD);
30 let power_irq = interrupt::take!(POWER_CLOCK); 30 let power_irq = interrupt::take!(POWER_CLOCK);
31 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 31 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
32 32
33 // Create embassy-usb Config 33 // Create embassy-usb Config
34 let mut config = Config::new(0xc0de, 0xcafe); 34 let mut config = Config::new(0xc0de, 0xcafe);
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 7c9c4184b..18b6f25b9 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -7,7 +7,7 @@ use core::mem;
7use defmt::{info, panic}; 7use defmt::{info, panic};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply}; 10use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::{interrupt, pac};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
@@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) {
26 // Create the driver, from the HAL. 26 // Create the driver, from the HAL.
27 let irq = interrupt::take!(USBD); 27 let irq = interrupt::take!(USBD);
28 let power_irq = interrupt::take!(POWER_CLOCK); 28 let power_irq = interrupt::take!(POWER_CLOCK);
29 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 29 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
30 30
31 // Create embassy-usb Config 31 // Create embassy-usb Config
32 let mut config = Config::new(0xc0de, 0xcafe); 32 let mut config = Config::new(0xc0de, 0xcafe);
@@ -97,7 +97,7 @@ impl From<EndpointError> for Disconnected {
97 } 97 }
98} 98}
99 99
100async fn echo<'d, T: Instance + 'd, P: UsbSupply + 'd>( 100async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>(
101 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>, 101 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
102) -> Result<(), Disconnected> { 102) -> Result<(), Disconnected> {
103 let mut buf = [0; 64]; 103 let mut buf = [0; 64];
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 93efc2fe6..3532d3f82 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -6,7 +6,7 @@ use core::mem;
6 6
7use defmt::{info, panic, unwrap}; 7use defmt::{info, panic, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::usb::{Driver, PowerUsb}; 9use embassy_nrf::usb::{Driver, HardwareVbusDetect};
10use embassy_nrf::{interrupt, pac, peripherals}; 10use embassy_nrf::{interrupt, pac, peripherals};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
@@ -14,7 +14,7 @@ use embassy_usb::{Builder, Config, UsbDevice};
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>; 17type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
18 18
19#[embassy_executor::task] 19#[embassy_executor::task]
20async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { 20async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
42 // Create the driver, from the HAL. 42 // Create the driver, from the HAL.
43 let irq = interrupt::take!(USBD); 43 let irq = interrupt::take!(USBD);
44 let power_irq = interrupt::take!(POWER_CLOCK); 44 let power_irq = interrupt::take!(POWER_CLOCK);
45 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 45 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
46 46
47 // Create embassy-usb Config 47 // Create embassy-usb Config
48 let mut config = Config::new(0xc0de, 0xcafe); 48 let mut config = Config::new(0xc0de, 0xcafe);