aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2023-12-19 11:28:05 +0000
committerGitHub <[email protected]>2023-12-19 11:28:05 +0000
commitca2e3759ad31f511c239d30132a28714b0e402db (patch)
tree8619875468c1853f1206c7d0eb377a084ca2f1df
parent6f21f0680e480917d4153cd7d62a84e34b423f6c (diff)
parent486b67e89522d7e36f6b1078ff8018d64447b39e (diff)
Merge pull request #2315 from embassy-rs/embassy-rp-rustdoc-1
docs: embassy-rp rustdoc and refactoring
-rw-r--r--cyw43-pio/src/lib.rs20
-rw-r--r--embassy-nrf/README.md2
-rw-r--r--embassy-rp/README.md23
-rw-r--r--embassy-rp/src/clocks.rs26
-rw-r--r--embassy-rp/src/lib.rs12
-rw-r--r--embassy-rp/src/pio/instr.rs (renamed from embassy-rp/src/pio_instr_util.rs)11
-rw-r--r--embassy-rp/src/pio/mod.rs (renamed from embassy-rp/src/pio.rs)151
-rw-r--r--embassy-rp/src/pwm.rs5
-rw-r--r--embassy-rp/src/rtc/mod.rs1
-rw-r--r--embassy-rp/src/spi.rs31
-rw-r--r--embassy-rp/src/uart/buffered.rs20
-rw-r--r--embassy-rp/src/uart/mod.rs52
-rw-r--r--embassy-rp/src/usb.rs10
13 files changed, 336 insertions, 28 deletions
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
index 41b670324..8304740b3 100644
--- a/cyw43-pio/src/lib.rs
+++ b/cyw43-pio/src/lib.rs
@@ -6,8 +6,8 @@ use core::slice;
6use cyw43::SpiBusCyw43; 6use cyw43::SpiBusCyw43;
7use embassy_rp::dma::Channel; 7use embassy_rp::dma::Channel;
8use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate}; 8use embassy_rp::gpio::{Drive, Level, Output, Pin, Pull, SlewRate};
9use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; 9use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine};
10use embassy_rp::{pio_instr_util, Peripheral, PeripheralRef}; 10use embassy_rp::{Peripheral, PeripheralRef};
11use fixed::FixedU32; 11use fixed::FixedU32;
12use pio_proc::pio_asm; 12use pio_proc::pio_asm;
13 13
@@ -152,10 +152,10 @@ where
152 defmt::trace!("write={} read={}", write_bits, read_bits); 152 defmt::trace!("write={} read={}", write_bits, read_bits);
153 153
154 unsafe { 154 unsafe {
155 pio_instr_util::set_x(&mut self.sm, write_bits as u32); 155 instr::set_x(&mut self.sm, write_bits as u32);
156 pio_instr_util::set_y(&mut self.sm, read_bits as u32); 156 instr::set_y(&mut self.sm, read_bits as u32);
157 pio_instr_util::set_pindir(&mut self.sm, 0b1); 157 instr::set_pindir(&mut self.sm, 0b1);
158 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); 158 instr::exec_jmp(&mut self.sm, self.wrap_target);
159 } 159 }
160 160
161 self.sm.set_enable(true); 161 self.sm.set_enable(true);
@@ -179,10 +179,10 @@ where
179 defmt::trace!("write={} read={}", write_bits, read_bits); 179 defmt::trace!("write={} read={}", write_bits, read_bits);
180 180
181 unsafe { 181 unsafe {
182 pio_instr_util::set_y(&mut self.sm, read_bits as u32); 182 instr::set_y(&mut self.sm, read_bits as u32);
183 pio_instr_util::set_x(&mut self.sm, write_bits as u32); 183 instr::set_x(&mut self.sm, write_bits as u32);
184 pio_instr_util::set_pindir(&mut self.sm, 0b1); 184 instr::set_pindir(&mut self.sm, 0b1);
185 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); 185 instr::exec_jmp(&mut self.sm, self.wrap_target);
186 } 186 }
187 187
188 // self.cs.set_low(); 188 // self.cs.set_low();
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
index 129ec0c01..39de3854b 100644
--- a/embassy-nrf/README.md
+++ b/embassy-nrf/README.md
@@ -6,6 +6,8 @@ The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The
6for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to 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. 7complete operations in low power mod and handling interrupts, so that applications can focus on more important matters.
8 8
9NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use.
10
9## EasyDMA considerations 11## EasyDMA considerations
10 12
11On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting 13On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting
diff --git a/embassy-rp/README.md b/embassy-rp/README.md
new file mode 100644
index 000000000..cd79fe501
--- /dev/null
+++ b/embassy-rp/README.md
@@ -0,0 +1,23 @@
1# Embassy RP HAL
2
3HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed.
4
5The Embassy RP HAL targets the Raspberry Pi 2040 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
9NOTE: The Embassy HALs can be used both for non-async and async operations. For async, you can choose which runtime you want to use.
10
11## Minimum supported Rust version (MSRV)
12
13Embassy 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.
14
15## License
16
17This work is licensed under either of
18
19- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
20 <http://www.apache.org/licenses/LICENSE-2.0>)
21- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
22
23at your option.
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 220665462..2f0645615 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,3 +1,4 @@
1//! Clock configuration for the RP2040
1use core::arch::asm; 2use core::arch::asm;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; 4use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
@@ -44,6 +45,7 @@ static CLOCKS: Clocks = Clocks {
44 rtc: AtomicU16::new(0), 45 rtc: AtomicU16::new(0),
45}; 46};
46 47
48/// Enumeration of supported clock sources.
47#[repr(u8)] 49#[repr(u8)]
48#[non_exhaustive] 50#[non_exhaustive]
49#[derive(Clone, Copy, Debug, PartialEq, Eq)] 51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -57,15 +59,24 @@ pub enum PeriClkSrc {
57 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 59 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
58} 60}
59 61
62/// CLock configuration.
60#[non_exhaustive] 63#[non_exhaustive]
61pub struct ClockConfig { 64pub struct ClockConfig {
65 /// Ring oscillator configuration.
62 pub rosc: Option<RoscConfig>, 66 pub rosc: Option<RoscConfig>,
67 /// External oscillator configuration.
63 pub xosc: Option<XoscConfig>, 68 pub xosc: Option<XoscConfig>,
69 /// Reference clock configuration.
64 pub ref_clk: RefClkConfig, 70 pub ref_clk: RefClkConfig,
71 /// System clock configuration.
65 pub sys_clk: SysClkConfig, 72 pub sys_clk: SysClkConfig,
73 /// Peripheral clock source configuration.
66 pub peri_clk_src: Option<PeriClkSrc>, 74 pub peri_clk_src: Option<PeriClkSrc>,
75 /// USB clock configuration.
67 pub usb_clk: Option<UsbClkConfig>, 76 pub usb_clk: Option<UsbClkConfig>,
77 /// ADC clock configuration.
68 pub adc_clk: Option<AdcClkConfig>, 78 pub adc_clk: Option<AdcClkConfig>,
79 /// RTC clock configuration.
69 pub rtc_clk: Option<RtcClkConfig>, 80 pub rtc_clk: Option<RtcClkConfig>,
70 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 81 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
71 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, 82 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -189,31 +200,46 @@ pub enum RoscRange {
189 TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0, 200 TooHigh = pac::rosc::vals::FreqRange::TOOHIGH.0,
190} 201}
191 202
203/// On-chip ring oscillator configuration.
192pub struct RoscConfig { 204pub struct RoscConfig {
193 /// Final frequency of the oscillator, after the divider has been applied. 205 /// Final frequency of the oscillator, after the divider has been applied.
194 /// The oscillator has a nominal frequency of 6.5MHz at medium range with 206 /// The oscillator has a nominal frequency of 6.5MHz at medium range with
195 /// divider 16 and all drive strengths set to 0, other values should be 207 /// divider 16 and all drive strengths set to 0, other values should be
196 /// measured in situ. 208 /// measured in situ.
197 pub hz: u32, 209 pub hz: u32,
210 /// Oscillator range.
198 pub range: RoscRange, 211 pub range: RoscRange,
212 /// Drive strength for oscillator.
199 pub drive_strength: [u8; 8], 213 pub drive_strength: [u8; 8],
214 /// Output divider.
200 pub div: u16, 215 pub div: u16,
201} 216}
202 217
218/// Crystal oscillator configuration.
203pub struct XoscConfig { 219pub struct XoscConfig {
220 /// Final frequency of the oscillator.
204 pub hz: u32, 221 pub hz: u32,
222 /// Configuring PLL for the system clock.
205 pub sys_pll: Option<PllConfig>, 223 pub sys_pll: Option<PllConfig>,
224 /// Configuring PLL for the USB clock.
206 pub usb_pll: Option<PllConfig>, 225 pub usb_pll: Option<PllConfig>,
226 /// Multiplier for the startup delay.
207 pub delay_multiplier: u32, 227 pub delay_multiplier: u32,
208} 228}
209 229
230/// PLL configuration.
210pub struct PllConfig { 231pub struct PllConfig {
232 /// Reference divisor.
211 pub refdiv: u8, 233 pub refdiv: u8,
234 /// Feedback divisor.
212 pub fbdiv: u16, 235 pub fbdiv: u16,
236 /// Output divisor 1.
213 pub post_div1: u8, 237 pub post_div1: u8,
238 /// Output divisor 2.
214 pub post_div2: u8, 239 pub post_div2: u8,
215} 240}
216 241
242/// Reference
217pub struct RefClkConfig { 243pub struct RefClkConfig {
218 pub src: RefClkSrc, 244 pub src: RefClkSrc,
219 pub div: u8, 245 pub div: u8,
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 5151323a9..2c49787df 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -1,5 +1,6 @@
1#![no_std] 1#![no_std]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![doc = include_str!("../README.md")]
3 4
4// This mod MUST go first, so that the others see its macros. 5// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 6pub(crate) mod fmt;
@@ -31,9 +32,7 @@ pub mod usb;
31pub mod watchdog; 32pub mod watchdog;
32 33
33// PIO 34// PIO
34// TODO: move `pio_instr_util` and `relocate` to inside `pio`
35pub mod pio; 35pub mod pio;
36pub mod pio_instr_util;
37pub(crate) mod relocate; 36pub(crate) mod relocate;
38 37
39// Reexports 38// Reexports
@@ -302,11 +301,14 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
302 Ok(()) 301 Ok(())
303} 302}
304 303
304/// HAL configuration for RP.
305pub mod config { 305pub mod config {
306 use crate::clocks::ClockConfig; 306 use crate::clocks::ClockConfig;
307 307
308 /// HAL configuration passed when initializing.
308 #[non_exhaustive] 309 #[non_exhaustive]
309 pub struct Config { 310 pub struct Config {
311 /// Clock configuration.
310 pub clocks: ClockConfig, 312 pub clocks: ClockConfig,
311 } 313 }
312 314
@@ -319,12 +321,18 @@ pub mod config {
319 } 321 }
320 322
321 impl Config { 323 impl Config {
324 /// Create a new configuration with the provided clock config.
322 pub fn new(clocks: ClockConfig) -> Self { 325 pub fn new(clocks: ClockConfig) -> Self {
323 Self { clocks } 326 Self { clocks }
324 } 327 }
325 } 328 }
326} 329}
327 330
331/// Initialize the `embassy-rp` HAL with the provided configuration.
332///
333/// This returns the peripheral singletons that can be used for creating drivers.
334///
335/// This should only be called once at startup, otherwise it panics.
328pub fn init(config: config::Config) -> Peripherals { 336pub fn init(config: config::Config) -> Peripherals {
329 // Do this first, so that it panics if user is calling `init` a second time 337 // Do this first, so that it panics if user is calling `init` a second time
330 // before doing anything important. 338 // before doing anything important.
diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio/instr.rs
index 25393b476..9a44088c6 100644
--- a/embassy-rp/src/pio_instr_util.rs
+++ b/embassy-rp/src/pio/instr.rs
@@ -1,7 +1,9 @@
1//! Instructions controlling the PIO.
1use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; 2use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
2 3
3use crate::pio::{Instance, StateMachine}; 4use crate::pio::{Instance, StateMachine};
4 5
6/// Set value of scratch register X.
5pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) { 7pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
6 const OUT: u16 = InstructionOperands::OUT { 8 const OUT: u16 = InstructionOperands::OUT {
7 destination: OutDestination::X, 9 destination: OutDestination::X,
@@ -12,6 +14,7 @@ pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
12 sm.exec_instr(OUT); 14 sm.exec_instr(OUT);
13} 15}
14 16
17/// Get value of scratch register X.
15pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 { 18pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
16 const IN: u16 = InstructionOperands::IN { 19 const IN: u16 = InstructionOperands::IN {
17 source: InSource::X, 20 source: InSource::X,
@@ -22,6 +25,7 @@ pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
22 sm.rx().pull() 25 sm.rx().pull()
23} 26}
24 27
28/// Set value of scratch register Y.
25pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) { 29pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
26 const OUT: u16 = InstructionOperands::OUT { 30 const OUT: u16 = InstructionOperands::OUT {
27 destination: OutDestination::Y, 31 destination: OutDestination::Y,
@@ -32,6 +36,7 @@ pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
32 sm.exec_instr(OUT); 36 sm.exec_instr(OUT);
33} 37}
34 38
39/// Get value of scratch register Y.
35pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 { 40pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
36 const IN: u16 = InstructionOperands::IN { 41 const IN: u16 = InstructionOperands::IN {
37 source: InSource::Y, 42 source: InSource::Y,
@@ -43,6 +48,7 @@ pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, S
43 sm.rx().pull() 48 sm.rx().pull()
44} 49}
45 50
51/// Set instruction for pindir destination.
46pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) { 52pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
47 let set: u16 = InstructionOperands::SET { 53 let set: u16 = InstructionOperands::SET {
48 destination: SetDestination::PINDIRS, 54 destination: SetDestination::PINDIRS,
@@ -52,6 +58,7 @@ pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<P
52 sm.exec_instr(set); 58 sm.exec_instr(set);
53} 59}
54 60
61/// Set instruction for pin destination.
55pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) { 62pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
56 let set: u16 = InstructionOperands::SET { 63 let set: u16 = InstructionOperands::SET {
57 destination: SetDestination::PINS, 64 destination: SetDestination::PINS,
@@ -61,6 +68,7 @@ pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO,
61 sm.exec_instr(set); 68 sm.exec_instr(set);
62} 69}
63 70
71/// Out instruction for pin destination.
64pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) { 72pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
65 const OUT: u16 = InstructionOperands::OUT { 73 const OUT: u16 = InstructionOperands::OUT {
66 destination: OutDestination::PINS, 74 destination: OutDestination::PINS,
@@ -70,6 +78,8 @@ pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<
70 sm.tx().push(data); 78 sm.tx().push(data);
71 sm.exec_instr(OUT); 79 sm.exec_instr(OUT);
72} 80}
81
82/// Out instruction for pindir destination.
73pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) { 83pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
74 const OUT: u16 = InstructionOperands::OUT { 84 const OUT: u16 = InstructionOperands::OUT {
75 destination: OutDestination::PINDIRS, 85 destination: OutDestination::PINDIRS,
@@ -80,6 +90,7 @@ pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachi
80 sm.exec_instr(OUT); 90 sm.exec_instr(OUT);
81} 91}
82 92
93/// Jump instruction to address.
83pub unsafe fn exec_jmp<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, to_addr: u8) { 94pub unsafe fn exec_jmp<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, to_addr: u8) {
84 let jmp: u16 = InstructionOperands::JMP { 95 let jmp: u16 = InstructionOperands::JMP {
85 address: to_addr, 96 address: to_addr,
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio/mod.rs
index 97dfce2e6..ae91d1e83 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio/mod.rs
@@ -19,8 +19,11 @@ use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
19use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; 19use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
20use crate::pac::dma::vals::TreqSel; 20use crate::pac::dma::vals::TreqSel;
21use crate::relocate::RelocatedProgram; 21use crate::relocate::RelocatedProgram;
22use crate::{pac, peripherals, pio_instr_util, RegExt}; 22use crate::{pac, peripherals, RegExt};
23 23
24pub mod instr;
25
26/// Wakers for interrupts and FIFOs.
24pub struct Wakers([AtomicWaker; 12]); 27pub struct Wakers([AtomicWaker; 12]);
25 28
26impl Wakers { 29impl Wakers {
@@ -38,6 +41,7 @@ impl Wakers {
38 } 41 }
39} 42}
40 43
44/// FIFO config.
41#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 45#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))] 46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43#[repr(u8)] 47#[repr(u8)]
@@ -51,6 +55,8 @@ pub enum FifoJoin {
51 TxOnly, 55 TxOnly,
52} 56}
53 57
58/// Shift direction.
59#[allow(missing_docs)]
54#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 60#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))] 61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56#[repr(u8)] 62#[repr(u8)]
@@ -60,6 +66,8 @@ pub enum ShiftDirection {
60 Left = 0, 66 Left = 0,
61} 67}
62 68
69/// Pin direction.
70#[allow(missing_docs)]
63#[derive(Clone, Copy, PartialEq, Eq, Debug)] 71#[derive(Clone, Copy, PartialEq, Eq, Debug)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65#[repr(u8)] 73#[repr(u8)]
@@ -68,12 +76,15 @@ pub enum Direction {
68 Out = 1, 76 Out = 1,
69} 77}
70 78
79/// Which fifo level to use in status check.
71#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] 80#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))] 81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[repr(u8)] 82#[repr(u8)]
74pub enum StatusSource { 83pub enum StatusSource {
75 #[default] 84 #[default]
85 /// All-ones if TX FIFO level < N, otherwise all-zeroes.
76 TxFifoLevel = 0, 86 TxFifoLevel = 0,
87 /// All-ones if RX FIFO level < N, otherwise all-zeroes.
77 RxFifoLevel = 1, 88 RxFifoLevel = 1,
78} 89}
79 90
@@ -81,6 +92,7 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
81const TXNFULL_MASK: u32 = 1 << 4; 92const TXNFULL_MASK: u32 = 1 << 4;
82const SMIRQ_MASK: u32 = 1 << 8; 93const SMIRQ_MASK: u32 = 1 << 8;
83 94
95/// Interrupt handler for PIO.
84pub struct InterruptHandler<PIO: Instance> { 96pub struct InterruptHandler<PIO: Instance> {
85 _pio: PhantomData<PIO>, 97 _pio: PhantomData<PIO>,
86} 98}
@@ -105,6 +117,7 @@ pub struct FifoOutFuture<'a, 'd, PIO: Instance, const SM: usize> {
105} 117}
106 118
107impl<'a, 'd, PIO: Instance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> { 119impl<'a, 'd, PIO: Instance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> {
120 /// Create a new future waiting for TX-FIFO to become writable.
108 pub fn new(sm: &'a mut StateMachineTx<'d, PIO, SM>, value: u32) -> Self { 121 pub fn new(sm: &'a mut StateMachineTx<'d, PIO, SM>, value: u32) -> Self {
109 FifoOutFuture { sm_tx: sm, value } 122 FifoOutFuture { sm_tx: sm, value }
110 } 123 }
@@ -136,13 +149,14 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO,
136 } 149 }
137} 150}
138 151
139/// Future that waits for RX-FIFO to become readable 152/// Future that waits for RX-FIFO to become readable.
140#[must_use = "futures do nothing unless you `.await` or poll them"] 153#[must_use = "futures do nothing unless you `.await` or poll them"]
141pub struct FifoInFuture<'a, 'd, PIO: Instance, const SM: usize> { 154pub struct FifoInFuture<'a, 'd, PIO: Instance, const SM: usize> {
142 sm_rx: &'a mut StateMachineRx<'d, PIO, SM>, 155 sm_rx: &'a mut StateMachineRx<'d, PIO, SM>,
143} 156}
144 157
145impl<'a, 'd, PIO: Instance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> { 158impl<'a, 'd, PIO: Instance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> {
159 /// Create future that waits for RX-FIFO to become readable.
146 pub fn new(sm: &'a mut StateMachineRx<'d, PIO, SM>) -> Self { 160 pub fn new(sm: &'a mut StateMachineRx<'d, PIO, SM>) -> Self {
147 FifoInFuture { sm_rx: sm } 161 FifoInFuture { sm_rx: sm }
148 } 162 }
@@ -207,6 +221,7 @@ impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
207 } 221 }
208} 222}
209 223
224/// Type representing a PIO pin.
210pub struct Pin<'l, PIO: Instance> { 225pub struct Pin<'l, PIO: Instance> {
211 pin: PeripheralRef<'l, AnyPin>, 226 pin: PeripheralRef<'l, AnyPin>,
212 pio: PhantomData<PIO>, 227 pio: PhantomData<PIO>,
@@ -226,7 +241,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
226 }); 241 });
227 } 242 }
228 243
229 // Set the pin's slew rate. 244 /// Set the pin's slew rate.
230 #[inline] 245 #[inline]
231 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { 246 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
232 self.pin.pad_ctrl().modify(|w| { 247 self.pin.pad_ctrl().modify(|w| {
@@ -251,6 +266,7 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
251 }); 266 });
252 } 267 }
253 268
269 /// Set the pin's input sync bypass.
254 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { 270 pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
255 let mask = 1 << self.pin(); 271 let mask = 1 << self.pin();
256 if bypass { 272 if bypass {
@@ -260,28 +276,34 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
260 } 276 }
261 } 277 }
262 278
279 /// Get the underlying pin number.
263 pub fn pin(&self) -> u8 { 280 pub fn pin(&self) -> u8 {
264 self.pin._pin() 281 self.pin._pin()
265 } 282 }
266} 283}
267 284
285/// Type representing a state machine RX FIFO.
268pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> { 286pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
269 pio: PhantomData<&'d mut PIO>, 287 pio: PhantomData<&'d mut PIO>,
270} 288}
271 289
272impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { 290impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
291 /// Check if RX FIFO is empty.
273 pub fn empty(&self) -> bool { 292 pub fn empty(&self) -> bool {
274 PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 293 PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0
275 } 294 }
276 295
296 /// Check if RX FIFO is full.
277 pub fn full(&self) -> bool { 297 pub fn full(&self) -> bool {
278 PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 298 PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
279 } 299 }
280 300
301 /// Check RX FIFO level.
281 pub fn level(&self) -> u8 { 302 pub fn level(&self) -> u8 {
282 (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f 303 (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f
283 } 304 }
284 305
306 /// Check if state machine has stalled on full RX FIFO.
285 pub fn stalled(&self) -> bool { 307 pub fn stalled(&self) -> bool {
286 let fdebug = PIO::PIO.fdebug(); 308 let fdebug = PIO::PIO.fdebug();
287 let ret = fdebug.read().rxstall() & (1 << SM) != 0; 309 let ret = fdebug.read().rxstall() & (1 << SM) != 0;
@@ -291,6 +313,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
291 ret 313 ret
292 } 314 }
293 315
316 /// Check if RX FIFO underflow (i.e. read-on-empty by the system) has occurred.
294 pub fn underflowed(&self) -> bool { 317 pub fn underflowed(&self) -> bool {
295 let fdebug = PIO::PIO.fdebug(); 318 let fdebug = PIO::PIO.fdebug();
296 let ret = fdebug.read().rxunder() & (1 << SM) != 0; 319 let ret = fdebug.read().rxunder() & (1 << SM) != 0;
@@ -300,10 +323,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
300 ret 323 ret
301 } 324 }
302 325
326 /// Pull data from RX FIFO.
303 pub fn pull(&mut self) -> u32 { 327 pub fn pull(&mut self) -> u32 {
304 PIO::PIO.rxf(SM).read() 328 PIO::PIO.rxf(SM).read()
305 } 329 }
306 330
331 /// Attempt pulling data from RX FIFO.
307 pub fn try_pull(&mut self) -> Option<u32> { 332 pub fn try_pull(&mut self) -> Option<u32> {
308 if self.empty() { 333 if self.empty() {
309 return None; 334 return None;
@@ -311,10 +336,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
311 Some(self.pull()) 336 Some(self.pull())
312 } 337 }
313 338
339 /// Wait for RX FIFO readable.
314 pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> { 340 pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> {
315 FifoInFuture::new(self) 341 FifoInFuture::new(self)
316 } 342 }
317 343
344 /// Prepare DMA transfer from RX FIFO.
318 pub fn dma_pull<'a, C: Channel, W: Word>( 345 pub fn dma_pull<'a, C: Channel, W: Word>(
319 &'a mut self, 346 &'a mut self,
320 ch: PeripheralRef<'a, C>, 347 ch: PeripheralRef<'a, C>,
@@ -340,22 +367,28 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
340 } 367 }
341} 368}
342 369
370/// Type representing a state machine TX FIFO.
343pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> { 371pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
344 pio: PhantomData<&'d mut PIO>, 372 pio: PhantomData<&'d mut PIO>,
345} 373}
346 374
347impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { 375impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
376 /// Check if TX FIFO is empty.
348 pub fn empty(&self) -> bool { 377 pub fn empty(&self) -> bool {
349 PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 378 PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0
350 } 379 }
380
381 /// Check if TX FIFO is full.
351 pub fn full(&self) -> bool { 382 pub fn full(&self) -> bool {
352 PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 383 PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
353 } 384 }
354 385
386 /// Check TX FIFO level.
355 pub fn level(&self) -> u8 { 387 pub fn level(&self) -> u8 {
356 (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f 388 (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f
357 } 389 }
358 390
391 /// Check state machine has stalled on empty TX FIFO.
359 pub fn stalled(&self) -> bool { 392 pub fn stalled(&self) -> bool {
360 let fdebug = PIO::PIO.fdebug(); 393 let fdebug = PIO::PIO.fdebug();
361 let ret = fdebug.read().txstall() & (1 << SM) != 0; 394 let ret = fdebug.read().txstall() & (1 << SM) != 0;
@@ -365,6 +398,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
365 ret 398 ret
366 } 399 }
367 400
401 /// Check if FIFO overflowed.
368 pub fn overflowed(&self) -> bool { 402 pub fn overflowed(&self) -> bool {
369 let fdebug = PIO::PIO.fdebug(); 403 let fdebug = PIO::PIO.fdebug();
370 let ret = fdebug.read().txover() & (1 << SM) != 0; 404 let ret = fdebug.read().txover() & (1 << SM) != 0;
@@ -374,10 +408,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
374 ret 408 ret
375 } 409 }
376 410
411 /// Force push data to TX FIFO.
377 pub fn push(&mut self, v: u32) { 412 pub fn push(&mut self, v: u32) {
378 PIO::PIO.txf(SM).write_value(v); 413 PIO::PIO.txf(SM).write_value(v);
379 } 414 }
380 415
416 /// Attempt to push data to TX FIFO.
381 pub fn try_push(&mut self, v: u32) -> bool { 417 pub fn try_push(&mut self, v: u32) -> bool {
382 if self.full() { 418 if self.full() {
383 return false; 419 return false;
@@ -386,10 +422,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
386 true 422 true
387 } 423 }
388 424
425 /// Wait until FIFO is ready for writing.
389 pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> { 426 pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> {
390 FifoOutFuture::new(self, value) 427 FifoOutFuture::new(self, value)
391 } 428 }
392 429
430 /// Prepare a DMA transfer to TX FIFO.
393 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { 431 pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
394 let pio_no = PIO::PIO_NO; 432 let pio_no = PIO::PIO_NO;
395 let p = ch.regs(); 433 let p = ch.regs();
@@ -411,6 +449,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
411 } 449 }
412} 450}
413 451
452/// A type representing a single PIO state machine.
414pub struct StateMachine<'d, PIO: Instance, const SM: usize> { 453pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
415 rx: StateMachineRx<'d, PIO, SM>, 454 rx: StateMachineRx<'d, PIO, SM>,
416 tx: StateMachineTx<'d, PIO, SM>, 455 tx: StateMachineTx<'d, PIO, SM>,
@@ -430,52 +469,78 @@ fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) {
430 } 469 }
431} 470}
432 471
472/// PIO Execution config.
433#[derive(Clone, Copy, Default, Debug)] 473#[derive(Clone, Copy, Default, Debug)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))] 474#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435#[non_exhaustive] 475#[non_exhaustive]
436pub struct ExecConfig { 476pub struct ExecConfig {
477 /// If true, the MSB of the Delay/Side-set instruction field is used as side-set enable, rather than a side-set data bit.
437 pub side_en: bool, 478 pub side_en: bool,
479 /// If true, side-set data is asserted to pin directions, instead of pin values.
438 pub side_pindir: bool, 480 pub side_pindir: bool,
481 /// Pin to trigger jump.
439 pub jmp_pin: u8, 482 pub jmp_pin: u8,
483 /// After reaching this address, execution is wrapped to wrap_bottom.
440 pub wrap_top: u8, 484 pub wrap_top: u8,
485 /// After reaching wrap_top, execution is wrapped to this address.
441 pub wrap_bottom: u8, 486 pub wrap_bottom: u8,
442} 487}
443 488
489/// PIO shift register config for input or output.
444#[derive(Clone, Copy, Default, Debug)] 490#[derive(Clone, Copy, Default, Debug)]
445#[cfg_attr(feature = "defmt", derive(defmt::Format))] 491#[cfg_attr(feature = "defmt", derive(defmt::Format))]
446pub struct ShiftConfig { 492pub struct ShiftConfig {
493 /// Number of bits shifted out of OSR before autopull.
447 pub threshold: u8, 494 pub threshold: u8,
495 /// Shift direction.
448 pub direction: ShiftDirection, 496 pub direction: ShiftDirection,
497 /// For output: Pull automatically output shift register is emptied.
498 /// For input: Push automatically when the input shift register is filled.
449 pub auto_fill: bool, 499 pub auto_fill: bool,
450} 500}
451 501
502/// PIO pin config.
452#[derive(Clone, Copy, Default, Debug)] 503#[derive(Clone, Copy, Default, Debug)]
453#[cfg_attr(feature = "defmt", derive(defmt::Format))] 504#[cfg_attr(feature = "defmt", derive(defmt::Format))]
454pub struct PinConfig { 505pub struct PinConfig {
506 /// The number of MSBs of the Delay/Side-set instruction field which are used for side-set.
455 pub sideset_count: u8, 507 pub sideset_count: u8,
508 /// The number of pins asserted by a SET. In the range 0 to 5 inclusive.
456 pub set_count: u8, 509 pub set_count: u8,
510 /// The number of pins asserted by an OUT PINS, OUT PINDIRS or MOV PINS instruction. In the range 0 to 32 inclusive.
457 pub out_count: u8, 511 pub out_count: u8,
512 /// The pin which is mapped to the least-significant bit of a state machine's IN data bus.
458 pub in_base: u8, 513 pub in_base: u8,
514 /// The lowest-numbered pin that will be affected by a side-set operation.
459 pub sideset_base: u8, 515 pub sideset_base: u8,
516 /// The lowest-numbered pin that will be affected by a SET PINS or SET PINDIRS instruction.
460 pub set_base: u8, 517 pub set_base: u8,
518 /// The lowest-numbered pin that will be affected by an OUT PINS, OUT PINDIRS or MOV PINS instruction.
461 pub out_base: u8, 519 pub out_base: u8,
462} 520}
463 521
522/// PIO config.
464#[derive(Clone, Copy, Debug)] 523#[derive(Clone, Copy, Debug)]
465pub struct Config<'d, PIO: Instance> { 524pub struct Config<'d, PIO: Instance> {
466 // CLKDIV 525 /// Clock divisor register for state machines.
467 pub clock_divider: FixedU32<U8>, 526 pub clock_divider: FixedU32<U8>,
468 // EXECCTRL 527 /// Which data bit to use for inline OUT enable.
469 pub out_en_sel: u8, 528 pub out_en_sel: u8,
529 /// Use a bit of OUT data as an auxiliary write enable When used in conjunction with OUT_STICKY.
470 pub inline_out_en: bool, 530 pub inline_out_en: bool,
531 /// Continuously assert the most recent OUT/SET to the pins.
471 pub out_sticky: bool, 532 pub out_sticky: bool,
533 /// Which source to use for checking status.
472 pub status_sel: StatusSource, 534 pub status_sel: StatusSource,
535 /// Status comparison level.
473 pub status_n: u8, 536 pub status_n: u8,
474 exec: ExecConfig, 537 exec: ExecConfig,
475 origin: Option<u8>, 538 origin: Option<u8>,
476 // SHIFTCTRL 539 /// Configure FIFO allocation.
477 pub fifo_join: FifoJoin, 540 pub fifo_join: FifoJoin,
541 /// Input shifting config.
478 pub shift_in: ShiftConfig, 542 pub shift_in: ShiftConfig,
543 /// Output shifting config.
479 pub shift_out: ShiftConfig, 544 pub shift_out: ShiftConfig,
480 // PINCTRL 545 // PINCTRL
481 pins: PinConfig, 546 pins: PinConfig,
@@ -505,16 +570,22 @@ impl<'d, PIO: Instance> Default for Config<'d, PIO> {
505} 570}
506 571
507impl<'d, PIO: Instance> Config<'d, PIO> { 572impl<'d, PIO: Instance> Config<'d, PIO> {
573 /// Get execution configuration.
508 pub fn get_exec(&self) -> ExecConfig { 574 pub fn get_exec(&self) -> ExecConfig {
509 self.exec 575 self.exec
510 } 576 }
577
578 /// Update execution configuration.
511 pub unsafe fn set_exec(&mut self, e: ExecConfig) { 579 pub unsafe fn set_exec(&mut self, e: ExecConfig) {
512 self.exec = e; 580 self.exec = e;
513 } 581 }
514 582
583 /// Get pin configuration.
515 pub fn get_pins(&self) -> PinConfig { 584 pub fn get_pins(&self) -> PinConfig {
516 self.pins 585 self.pins
517 } 586 }
587
588 /// Update pin configuration.
518 pub unsafe fn set_pins(&mut self, p: PinConfig) { 589 pub unsafe fn set_pins(&mut self, p: PinConfig) {
519 self.pins = p; 590 self.pins = p;
520 } 591 }
@@ -537,6 +608,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> {
537 self.origin = Some(prog.origin); 608 self.origin = Some(prog.origin);
538 } 609 }
539 610
611 /// Set pin used to signal jump.
540 pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { 612 pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) {
541 self.exec.jmp_pin = pin.pin(); 613 self.exec.jmp_pin = pin.pin();
542 } 614 }
@@ -571,6 +643,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> {
571} 643}
572 644
573impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { 645impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
646 /// Set the config for a given PIO state machine.
574 pub fn set_config(&mut self, config: &Config<'d, PIO>) { 647 pub fn set_config(&mut self, config: &Config<'d, PIO>) {
575 // sm expects 0 for 65536, truncation makes that happen 648 // sm expects 0 for 65536, truncation makes that happen
576 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); 649 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
@@ -617,7 +690,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
617 w.set_out_base(config.pins.out_base); 690 w.set_out_base(config.pins.out_base);
618 }); 691 });
619 if let Some(origin) = config.origin { 692 if let Some(origin) = config.origin {
620 unsafe { pio_instr_util::exec_jmp(self, origin) } 693 unsafe { instr::exec_jmp(self, origin) }
621 } 694 }
622 } 695 }
623 696
@@ -626,10 +699,13 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
626 PIO::PIO.sm(SM) 699 PIO::PIO.sm(SM)
627 } 700 }
628 701
702 /// Restart this state machine.
629 pub fn restart(&mut self) { 703 pub fn restart(&mut self) {
630 let mask = 1u8 << SM; 704 let mask = 1u8 << SM;
631 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); 705 PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
632 } 706 }
707
708 /// Enable state machine.
633 pub fn set_enable(&mut self, enable: bool) { 709 pub fn set_enable(&mut self, enable: bool) {
634 let mask = 1u8 << SM; 710 let mask = 1u8 << SM;
635 if enable { 711 if enable {
@@ -639,10 +715,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
639 } 715 }
640 } 716 }
641 717
718 /// Check if state machine is enabled.
642 pub fn is_enabled(&self) -> bool { 719 pub fn is_enabled(&self) -> bool {
643 PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 720 PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0
644 } 721 }
645 722
723 /// Restart a state machine's clock divider from an initial phase of 0.
646 pub fn clkdiv_restart(&mut self) { 724 pub fn clkdiv_restart(&mut self) {
647 let mask = 1u8 << SM; 725 let mask = 1u8 << SM;
648 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); 726 PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
@@ -690,6 +768,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
690 }); 768 });
691 } 769 }
692 770
771 /// Flush FIFOs for state machine.
693 pub fn clear_fifos(&mut self) { 772 pub fn clear_fifos(&mut self) {
694 // Toggle FJOIN_RX to flush FIFOs 773 // Toggle FJOIN_RX to flush FIFOs
695 let shiftctrl = Self::this_sm().shiftctrl(); 774 let shiftctrl = Self::this_sm().shiftctrl();
@@ -701,21 +780,31 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
701 }); 780 });
702 } 781 }
703 782
783 /// Instruct state machine to execute a given instructions
784 ///
785 /// SAFETY: The state machine must be in a state where executing
786 /// an arbitrary instruction does not crash it.
704 pub unsafe fn exec_instr(&mut self, instr: u16) { 787 pub unsafe fn exec_instr(&mut self, instr: u16) {
705 Self::this_sm().instr().write(|w| w.set_instr(instr)); 788 Self::this_sm().instr().write(|w| w.set_instr(instr));
706 } 789 }
707 790
791 /// Return a read handle for reading state machine outputs.
708 pub fn rx(&mut self) -> &mut StateMachineRx<'d, PIO, SM> { 792 pub fn rx(&mut self) -> &mut StateMachineRx<'d, PIO, SM> {
709 &mut self.rx 793 &mut self.rx
710 } 794 }
795
796 /// Return a handle for writing to inputs.
711 pub fn tx(&mut self) -> &mut StateMachineTx<'d, PIO, SM> { 797 pub fn tx(&mut self) -> &mut StateMachineTx<'d, PIO, SM> {
712 &mut self.tx 798 &mut self.tx
713 } 799 }
800
801 /// Return both read and write handles for the state machine.
714 pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) { 802 pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) {
715 (&mut self.rx, &mut self.tx) 803 (&mut self.rx, &mut self.tx)
716 } 804 }
717} 805}
718 806
807/// PIO handle.
719pub struct Common<'d, PIO: Instance> { 808pub struct Common<'d, PIO: Instance> {
720 instructions_used: u32, 809 instructions_used: u32,
721 pio: PhantomData<&'d mut PIO>, 810 pio: PhantomData<&'d mut PIO>,
@@ -727,18 +816,25 @@ impl<'d, PIO: Instance> Drop for Common<'d, PIO> {
727 } 816 }
728} 817}
729 818
819/// Memory of PIO instance.
730pub struct InstanceMemory<'d, PIO: Instance> { 820pub struct InstanceMemory<'d, PIO: Instance> {
731 used_mask: u32, 821 used_mask: u32,
732 pio: PhantomData<&'d mut PIO>, 822 pio: PhantomData<&'d mut PIO>,
733} 823}
734 824
825/// A loaded PIO program.
735pub struct LoadedProgram<'d, PIO: Instance> { 826pub struct LoadedProgram<'d, PIO: Instance> {
827 /// Memory used by program.
736 pub used_memory: InstanceMemory<'d, PIO>, 828 pub used_memory: InstanceMemory<'d, PIO>,
829 /// Program origin for loading.
737 pub origin: u8, 830 pub origin: u8,
831 /// Wrap controls what to do once program is done executing.
738 pub wrap: Wrap, 832 pub wrap: Wrap,
833 /// Data for 'side' set instruction parameters.
739 pub side_set: SideSet, 834 pub side_set: SideSet,
740} 835}
741 836
837/// Errors loading a PIO program.
742#[derive(Clone, Copy, PartialEq, Eq, Debug)] 838#[derive(Clone, Copy, PartialEq, Eq, Debug)]
743#[cfg_attr(feature = "defmt", derive(defmt::Format))] 839#[cfg_attr(feature = "defmt", derive(defmt::Format))]
744pub enum LoadError { 840pub enum LoadError {
@@ -834,6 +930,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
834 self.instructions_used &= !instrs.used_mask; 930 self.instructions_used &= !instrs.used_mask;
835 } 931 }
836 932
933 /// Bypass flipflop synchronizer on GPIO inputs.
837 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { 934 pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
838 // this can interfere with per-pin bypass functions. splitting the 935 // this can interfere with per-pin bypass functions. splitting the
839 // modification is going to be fine since nothing that relies on 936 // modification is going to be fine since nothing that relies on
@@ -842,6 +939,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
842 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); 939 PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
843 } 940 }
844 941
942 /// Get bypass configuration.
845 pub fn get_input_sync_bypass(&self) -> u32 { 943 pub fn get_input_sync_bypass(&self) -> u32 {
846 PIO::PIO.input_sync_bypass().read() 944 PIO::PIO.input_sync_bypass().read()
847 } 945 }
@@ -861,6 +959,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
861 } 959 }
862 } 960 }
863 961
962 /// Apply changes to all state machines in a batch.
864 pub fn apply_sm_batch(&mut self, f: impl FnOnce(&mut PioBatch<'d, PIO>)) { 963 pub fn apply_sm_batch(&mut self, f: impl FnOnce(&mut PioBatch<'d, PIO>)) {
865 let mut batch = PioBatch { 964 let mut batch = PioBatch {
866 clkdiv_restart: 0, 965 clkdiv_restart: 0,
@@ -878,6 +977,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
878 } 977 }
879} 978}
880 979
980/// Represents multiple state machines in a single type.
881pub struct PioBatch<'a, PIO: Instance> { 981pub struct PioBatch<'a, PIO: Instance> {
882 clkdiv_restart: u8, 982 clkdiv_restart: u8,
883 sm_restart: u8, 983 sm_restart: u8,
@@ -887,25 +987,25 @@ pub struct PioBatch<'a, PIO: Instance> {
887} 987}
888 988
889impl<'a, PIO: Instance> PioBatch<'a, PIO> { 989impl<'a, PIO: Instance> PioBatch<'a, PIO> {
890 pub fn restart_clockdiv<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) { 990 /// Restart a state machine's clock divider from an initial phase of 0.
891 self.clkdiv_restart |= 1 << SM;
892 }
893
894 pub fn restart<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) { 991 pub fn restart<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>) {
895 self.clkdiv_restart |= 1 << SM; 992 self.clkdiv_restart |= 1 << SM;
896 } 993 }
897 994
995 /// Enable a specific state machine.
898 pub fn set_enable<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>, enable: bool) { 996 pub fn set_enable<const SM: usize>(&mut self, _sm: &mut StateMachine<'a, PIO, SM>, enable: bool) {
899 self.sm_enable_mask |= 1 << SM; 997 self.sm_enable_mask |= 1 << SM;
900 self.sm_enable |= (enable as u8) << SM; 998 self.sm_enable |= (enable as u8) << SM;
901 } 999 }
902} 1000}
903 1001
1002/// Type representing a PIO interrupt.
904pub struct Irq<'d, PIO: Instance, const N: usize> { 1003pub struct Irq<'d, PIO: Instance, const N: usize> {
905 pio: PhantomData<&'d mut PIO>, 1004 pio: PhantomData<&'d mut PIO>,
906} 1005}
907 1006
908impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> { 1007impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> {
1008 /// Wait for an IRQ to fire.
909 pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> { 1009 pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> {
910 IrqFuture { 1010 IrqFuture {
911 pio: PhantomData, 1011 pio: PhantomData,
@@ -914,59 +1014,79 @@ impl<'d, PIO: Instance, const N: usize> Irq<'d, PIO, N> {
914 } 1014 }
915} 1015}
916 1016
1017/// Interrupt flags for a PIO instance.
917#[derive(Clone)] 1018#[derive(Clone)]
918pub struct IrqFlags<'d, PIO: Instance> { 1019pub struct IrqFlags<'d, PIO: Instance> {
919 pio: PhantomData<&'d mut PIO>, 1020 pio: PhantomData<&'d mut PIO>,
920} 1021}
921 1022
922impl<'d, PIO: Instance> IrqFlags<'d, PIO> { 1023impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
1024 /// Check if interrupt fired.
923 pub fn check(&self, irq_no: u8) -> bool { 1025 pub fn check(&self, irq_no: u8) -> bool {
924 assert!(irq_no < 8); 1026 assert!(irq_no < 8);
925 self.check_any(1 << irq_no) 1027 self.check_any(1 << irq_no)
926 } 1028 }
927 1029
1030 /// Check if any of the interrupts in the bitmap fired.
928 pub fn check_any(&self, irqs: u8) -> bool { 1031 pub fn check_any(&self, irqs: u8) -> bool {
929 PIO::PIO.irq().read().irq() & irqs != 0 1032 PIO::PIO.irq().read().irq() & irqs != 0
930 } 1033 }
931 1034
1035 /// Check if all interrupts have fired.
932 pub fn check_all(&self, irqs: u8) -> bool { 1036 pub fn check_all(&self, irqs: u8) -> bool {
933 PIO::PIO.irq().read().irq() & irqs == irqs 1037 PIO::PIO.irq().read().irq() & irqs == irqs
934 } 1038 }
935 1039
1040 /// Clear interrupt for interrupt number.
936 pub fn clear(&self, irq_no: usize) { 1041 pub fn clear(&self, irq_no: usize) {
937 assert!(irq_no < 8); 1042 assert!(irq_no < 8);
938 self.clear_all(1 << irq_no); 1043 self.clear_all(1 << irq_no);
939 } 1044 }
940 1045
1046 /// Clear all interrupts set in the bitmap.
941 pub fn clear_all(&self, irqs: u8) { 1047 pub fn clear_all(&self, irqs: u8) {
942 PIO::PIO.irq().write(|w| w.set_irq(irqs)) 1048 PIO::PIO.irq().write(|w| w.set_irq(irqs))
943 } 1049 }
944 1050
1051 /// Fire a given interrupt.
945 pub fn set(&self, irq_no: usize) { 1052 pub fn set(&self, irq_no: usize) {
946 assert!(irq_no < 8); 1053 assert!(irq_no < 8);
947 self.set_all(1 << irq_no); 1054 self.set_all(1 << irq_no);
948 } 1055 }
949 1056
1057 /// Fire all interrupts.
950 pub fn set_all(&self, irqs: u8) { 1058 pub fn set_all(&self, irqs: u8) {
951 PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) 1059 PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs))
952 } 1060 }
953} 1061}
954 1062
1063/// An instance of the PIO driver.
955pub struct Pio<'d, PIO: Instance> { 1064pub struct Pio<'d, PIO: Instance> {
1065 /// PIO handle.
956 pub common: Common<'d, PIO>, 1066 pub common: Common<'d, PIO>,
1067 /// PIO IRQ flags.
957 pub irq_flags: IrqFlags<'d, PIO>, 1068 pub irq_flags: IrqFlags<'d, PIO>,
1069 /// IRQ0 configuration.
958 pub irq0: Irq<'d, PIO, 0>, 1070 pub irq0: Irq<'d, PIO, 0>,
1071 /// IRQ1 configuration.
959 pub irq1: Irq<'d, PIO, 1>, 1072 pub irq1: Irq<'d, PIO, 1>,
1073 /// IRQ2 configuration.
960 pub irq2: Irq<'d, PIO, 2>, 1074 pub irq2: Irq<'d, PIO, 2>,
1075 /// IRQ3 configuration.
961 pub irq3: Irq<'d, PIO, 3>, 1076 pub irq3: Irq<'d, PIO, 3>,
1077 /// State machine 0 handle.
962 pub sm0: StateMachine<'d, PIO, 0>, 1078 pub sm0: StateMachine<'d, PIO, 0>,
1079 /// State machine 1 handle.
963 pub sm1: StateMachine<'d, PIO, 1>, 1080 pub sm1: StateMachine<'d, PIO, 1>,
1081 /// State machine 2 handle.
964 pub sm2: StateMachine<'d, PIO, 2>, 1082 pub sm2: StateMachine<'d, PIO, 2>,
1083 /// State machine 3 handle.
965 pub sm3: StateMachine<'d, PIO, 3>, 1084 pub sm3: StateMachine<'d, PIO, 3>,
966 _pio: PhantomData<&'d mut PIO>, 1085 _pio: PhantomData<&'d mut PIO>,
967} 1086}
968 1087
969impl<'d, PIO: Instance> Pio<'d, PIO> { 1088impl<'d, PIO: Instance> Pio<'d, PIO> {
1089 /// Create a new instance of a PIO peripheral.
970 pub fn new(_pio: impl Peripheral<P = PIO> + 'd, _irq: impl Binding<PIO::Interrupt, InterruptHandler<PIO>>) -> Self { 1090 pub fn new(_pio: impl Peripheral<P = PIO> + 'd, _irq: impl Binding<PIO::Interrupt, InterruptHandler<PIO>>) -> Self {
971 PIO::state().users.store(5, Ordering::Release); 1091 PIO::state().users.store(5, Ordering::Release);
972 PIO::state().used_pins.store(0, Ordering::Release); 1092 PIO::state().used_pins.store(0, Ordering::Release);
@@ -1003,9 +1123,10 @@ impl<'d, PIO: Instance> Pio<'d, PIO> {
1003 } 1123 }
1004} 1124}
1005 1125
1006// we need to keep a record of which pins are assigned to each PIO. make_pio_pin 1126/// Representation of the PIO state keeping a record of which pins are assigned to
1007// notionally takes ownership of the pin it is given, but the wrapped pin cannot 1127/// each PIO.
1008// be treated as an owned resource since dropping it would have to deconfigure 1128// make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin
1129// cannot be treated as an owned resource since dropping it would have to deconfigure
1009// the pin, breaking running state machines in the process. pins are also shared 1130// the pin, breaking running state machines in the process. pins are also shared
1010// between all state machines, which makes ownership even messier to track any 1131// between all state machines, which makes ownership even messier to track any
1011// other way. 1132// other way.
@@ -1059,6 +1180,7 @@ mod sealed {
1059 } 1180 }
1060} 1181}
1061 1182
1183/// PIO instance.
1062pub trait Instance: sealed::Instance + Sized + Unpin {} 1184pub trait Instance: sealed::Instance + Sized + Unpin {}
1063 1185
1064macro_rules! impl_pio { 1186macro_rules! impl_pio {
@@ -1076,6 +1198,7 @@ macro_rules! impl_pio {
1076impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); 1198impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
1077impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); 1199impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1078 1200
1201/// PIO pin.
1079pub trait PioPin: sealed::PioPin + gpio::Pin {} 1202pub trait PioPin: sealed::PioPin + gpio::Pin {}
1080 1203
1081macro_rules! impl_pio_pin { 1204macro_rules! impl_pio_pin {
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 516b8254b..5b96557a3 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -61,9 +61,13 @@ impl Default for Config {
61 } 61 }
62} 62}
63 63
64/// PWM input mode.
64pub enum InputMode { 65pub enum InputMode {
66 /// Level mode.
65 Level, 67 Level,
68 /// Rising edge mode.
66 RisingEdge, 69 RisingEdge,
70 /// Falling edge mode.
67 FallingEdge, 71 FallingEdge,
68} 72}
69 73
@@ -77,6 +81,7 @@ impl From<InputMode> for Divmode {
77 } 81 }
78} 82}
79 83
84/// PWM driver.
80pub struct Pwm<'d, T: Channel> { 85pub struct Pwm<'d, T: Channel> {
81 inner: PeripheralRef<'d, T>, 86 inner: PeripheralRef<'d, T>,
82 pin_a: Option<PeripheralRef<'d, AnyPin>>, 87 pin_a: Option<PeripheralRef<'d, AnyPin>>,
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index 60ca8627b..c3df3ee57 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -194,6 +194,7 @@ mod sealed {
194 } 194 }
195} 195}
196 196
197/// RTC peripheral instance.
197pub trait Instance: sealed::Instance {} 198pub trait Instance: sealed::Instance {}
198 199
199impl sealed::Instance for crate::peripherals::RTC { 200impl sealed::Instance for crate::peripherals::RTC {
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 6ba985a65..a2a22ffe5 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -11,6 +11,7 @@ use crate::gpio::sealed::Pin as _;
11use crate::gpio::{AnyPin, Pin as GpioPin}; 11use crate::gpio::{AnyPin, Pin as GpioPin};
12use crate::{pac, peripherals, Peripheral}; 12use crate::{pac, peripherals, Peripheral};
13 13
14/// SPI errors.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)] 15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))] 16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[non_exhaustive] 17#[non_exhaustive]
@@ -18,11 +19,15 @@ pub enum Error {
18 // No errors for now 19 // No errors for now
19} 20}
20 21
22/// SPI configuration.
21#[non_exhaustive] 23#[non_exhaustive]
22#[derive(Clone)] 24#[derive(Clone)]
23pub struct Config { 25pub struct Config {
26 /// Frequency.
24 pub frequency: u32, 27 pub frequency: u32,
28 /// Phase.
25 pub phase: Phase, 29 pub phase: Phase,
30 /// Polarity.
26 pub polarity: Polarity, 31 pub polarity: Polarity,
27} 32}
28 33
@@ -36,6 +41,7 @@ impl Default for Config {
36 } 41 }
37} 42}
38 43
44/// SPI driver.
39pub struct Spi<'d, T: Instance, M: Mode> { 45pub struct Spi<'d, T: Instance, M: Mode> {
40 inner: PeripheralRef<'d, T>, 46 inner: PeripheralRef<'d, T>,
41 tx_dma: Option<PeripheralRef<'d, AnyChannel>>, 47 tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
@@ -119,6 +125,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
119 } 125 }
120 } 126 }
121 127
128 /// Write data to SPI blocking execution until done.
122 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { 129 pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
123 let p = self.inner.regs(); 130 let p = self.inner.regs();
124 for &b in data { 131 for &b in data {
@@ -131,6 +138,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
131 Ok(()) 138 Ok(())
132 } 139 }
133 140
141 /// Transfer data in place to SPI blocking execution until done.
134 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> { 142 pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
135 let p = self.inner.regs(); 143 let p = self.inner.regs();
136 for b in data { 144 for b in data {
@@ -143,6 +151,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
143 Ok(()) 151 Ok(())
144 } 152 }
145 153
154 /// Read data from SPI blocking execution until done.
146 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> { 155 pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
147 let p = self.inner.regs(); 156 let p = self.inner.regs();
148 for b in data { 157 for b in data {
@@ -155,6 +164,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
155 Ok(()) 164 Ok(())
156 } 165 }
157 166
167 /// Transfer data to SPI blocking execution until done.
158 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> { 168 pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
159 let p = self.inner.regs(); 169 let p = self.inner.regs();
160 let len = read.len().max(write.len()); 170 let len = read.len().max(write.len());
@@ -172,12 +182,14 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
172 Ok(()) 182 Ok(())
173 } 183 }
174 184
185 /// Block execution until SPI is done.
175 pub fn flush(&mut self) -> Result<(), Error> { 186 pub fn flush(&mut self) -> Result<(), Error> {
176 let p = self.inner.regs(); 187 let p = self.inner.regs();
177 while p.sr().read().bsy() {} 188 while p.sr().read().bsy() {}
178 Ok(()) 189 Ok(())
179 } 190 }
180 191
192 /// Set SPI frequency.
181 pub fn set_frequency(&mut self, freq: u32) { 193 pub fn set_frequency(&mut self, freq: u32) {
182 let (presc, postdiv) = calc_prescs(freq); 194 let (presc, postdiv) = calc_prescs(freq);
183 let p = self.inner.regs(); 195 let p = self.inner.regs();
@@ -196,6 +208,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
196} 208}
197 209
198impl<'d, T: Instance> Spi<'d, T, Blocking> { 210impl<'d, T: Instance> Spi<'d, T, Blocking> {
211 /// Create an SPI driver in blocking mode.
199 pub fn new_blocking( 212 pub fn new_blocking(
200 inner: impl Peripheral<P = T> + 'd, 213 inner: impl Peripheral<P = T> + 'd,
201 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 214 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -216,6 +229,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
216 ) 229 )
217 } 230 }
218 231
232 /// Create an SPI driver in blocking mode supporting writes only.
219 pub fn new_blocking_txonly( 233 pub fn new_blocking_txonly(
220 inner: impl Peripheral<P = T> + 'd, 234 inner: impl Peripheral<P = T> + 'd,
221 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 235 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -235,6 +249,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
235 ) 249 )
236 } 250 }
237 251
252 /// Create an SPI driver in blocking mode supporting reads only.
238 pub fn new_blocking_rxonly( 253 pub fn new_blocking_rxonly(
239 inner: impl Peripheral<P = T> + 'd, 254 inner: impl Peripheral<P = T> + 'd,
240 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 255 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -256,6 +271,7 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> {
256} 271}
257 272
258impl<'d, T: Instance> Spi<'d, T, Async> { 273impl<'d, T: Instance> Spi<'d, T, Async> {
274 /// Create an SPI driver in async mode supporting DMA operations.
259 pub fn new( 275 pub fn new(
260 inner: impl Peripheral<P = T> + 'd, 276 inner: impl Peripheral<P = T> + 'd,
261 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 277 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -278,6 +294,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
278 ) 294 )
279 } 295 }
280 296
297 /// Create an SPI driver in async mode supporting DMA write operations only.
281 pub fn new_txonly( 298 pub fn new_txonly(
282 inner: impl Peripheral<P = T> + 'd, 299 inner: impl Peripheral<P = T> + 'd,
283 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 300 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -298,6 +315,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
298 ) 315 )
299 } 316 }
300 317
318 /// Create an SPI driver in async mode supporting DMA read operations only.
301 pub fn new_rxonly( 319 pub fn new_rxonly(
302 inner: impl Peripheral<P = T> + 'd, 320 inner: impl Peripheral<P = T> + 'd,
303 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd, 321 clk: impl Peripheral<P = impl ClkPin<T> + 'd> + 'd,
@@ -318,6 +336,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
318 ) 336 )
319 } 337 }
320 338
339 /// Write data to SPI using DMA.
321 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 340 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
322 let tx_ch = self.tx_dma.as_mut().unwrap(); 341 let tx_ch = self.tx_dma.as_mut().unwrap();
323 let tx_transfer = unsafe { 342 let tx_transfer = unsafe {
@@ -340,6 +359,7 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
340 Ok(()) 359 Ok(())
341 } 360 }
342 361
362 /// Read data from SPI using DMA.
343 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 363 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
344 // Start RX first. Transfer starts when TX starts, if RX 364 // Start RX first. Transfer starts when TX starts, if RX
345 // is not started yet we might lose bytes. 365 // is not started yet we might lose bytes.
@@ -365,10 +385,12 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
365 Ok(()) 385 Ok(())
366 } 386 }
367 387
388 /// Transfer data to SPI using DMA.
368 pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> { 389 pub async fn transfer(&mut self, rx_buffer: &mut [u8], tx_buffer: &[u8]) -> Result<(), Error> {
369 self.transfer_inner(rx_buffer, tx_buffer).await 390 self.transfer_inner(rx_buffer, tx_buffer).await
370 } 391 }
371 392
393 /// Transfer data in place to SPI using DMA.
372 pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { 394 pub async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> {
373 self.transfer_inner(words, words).await 395 self.transfer_inner(words, words).await
374 } 396 }
@@ -434,7 +456,10 @@ mod sealed {
434 } 456 }
435} 457}
436 458
459/// Mode.
437pub trait Mode: sealed::Mode {} 460pub trait Mode: sealed::Mode {}
461
462/// SPI instance trait.
438pub trait Instance: sealed::Instance {} 463pub trait Instance: sealed::Instance {}
439 464
440macro_rules! impl_instance { 465macro_rules! impl_instance {
@@ -454,9 +479,13 @@ macro_rules! impl_instance {
454impl_instance!(SPI0, Spi0, 16, 17); 479impl_instance!(SPI0, Spi0, 16, 17);
455impl_instance!(SPI1, Spi1, 18, 19); 480impl_instance!(SPI1, Spi1, 18, 19);
456 481
482/// CLK pin.
457pub trait ClkPin<T: Instance>: GpioPin {} 483pub trait ClkPin<T: Instance>: GpioPin {}
484/// CS pin.
458pub trait CsPin<T: Instance>: GpioPin {} 485pub trait CsPin<T: Instance>: GpioPin {}
486/// MOSI pin.
459pub trait MosiPin<T: Instance>: GpioPin {} 487pub trait MosiPin<T: Instance>: GpioPin {}
488/// MISO pin.
460pub trait MisoPin<T: Instance>: GpioPin {} 489pub trait MisoPin<T: Instance>: GpioPin {}
461 490
462macro_rules! impl_pin { 491macro_rules! impl_pin {
@@ -503,7 +532,9 @@ macro_rules! impl_mode {
503 }; 532 };
504} 533}
505 534
535/// Blocking mode.
506pub struct Blocking; 536pub struct Blocking;
537/// Async mode.
507pub struct Async; 538pub struct Async;
508 539
509impl_mode!(Blocking); 540impl_mode!(Blocking);
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index ca030f560..f14e08525 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -38,15 +38,18 @@ impl State {
38 } 38 }
39} 39}
40 40
41/// Buffered UART driver.
41pub struct BufferedUart<'d, T: Instance> { 42pub struct BufferedUart<'d, T: Instance> {
42 pub(crate) rx: BufferedUartRx<'d, T>, 43 pub(crate) rx: BufferedUartRx<'d, T>,
43 pub(crate) tx: BufferedUartTx<'d, T>, 44 pub(crate) tx: BufferedUartTx<'d, T>,
44} 45}
45 46
47/// Buffered UART RX handle.
46pub struct BufferedUartRx<'d, T: Instance> { 48pub struct BufferedUartRx<'d, T: Instance> {
47 pub(crate) phantom: PhantomData<&'d mut T>, 49 pub(crate) phantom: PhantomData<&'d mut T>,
48} 50}
49 51
52/// Buffered UART TX handle.
50pub struct BufferedUartTx<'d, T: Instance> { 53pub struct BufferedUartTx<'d, T: Instance> {
51 pub(crate) phantom: PhantomData<&'d mut T>, 54 pub(crate) phantom: PhantomData<&'d mut T>,
52} 55}
@@ -84,6 +87,7 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
84} 87}
85 88
86impl<'d, T: Instance> BufferedUart<'d, T> { 89impl<'d, T: Instance> BufferedUart<'d, T> {
90 /// Create a buffered UART instance.
87 pub fn new( 91 pub fn new(
88 _uart: impl Peripheral<P = T> + 'd, 92 _uart: impl Peripheral<P = T> + 'd,
89 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 93 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -104,6 +108,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
104 } 108 }
105 } 109 }
106 110
111 /// Create a buffered UART instance with flow control.
107 pub fn new_with_rtscts( 112 pub fn new_with_rtscts(
108 _uart: impl Peripheral<P = T> + 'd, 113 _uart: impl Peripheral<P = T> + 'd,
109 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 114 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -132,32 +137,39 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
132 } 137 }
133 } 138 }
134 139
140 /// Write to UART TX buffer blocking execution until done.
135 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> { 141 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<usize, Error> {
136 self.tx.blocking_write(buffer) 142 self.tx.blocking_write(buffer)
137 } 143 }
138 144
145 /// Flush UART TX blocking execution until done.
139 pub fn blocking_flush(&mut self) -> Result<(), Error> { 146 pub fn blocking_flush(&mut self) -> Result<(), Error> {
140 self.tx.blocking_flush() 147 self.tx.blocking_flush()
141 } 148 }
142 149
150 /// Read from UART RX buffer blocking execution until done.
143 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 151 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
144 self.rx.blocking_read(buffer) 152 self.rx.blocking_read(buffer)
145 } 153 }
146 154
155 /// Check if UART is busy transmitting.
147 pub fn busy(&self) -> bool { 156 pub fn busy(&self) -> bool {
148 self.tx.busy() 157 self.tx.busy()
149 } 158 }
150 159
160 /// Wait until TX is empty and send break condition.
151 pub async fn send_break(&mut self, bits: u32) { 161 pub async fn send_break(&mut self, bits: u32) {
152 self.tx.send_break(bits).await 162 self.tx.send_break(bits).await
153 } 163 }
154 164
165 /// Split into separate RX and TX handles.
155 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { 166 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) {
156 (self.rx, self.tx) 167 (self.rx, self.tx)
157 } 168 }
158} 169}
159 170
160impl<'d, T: Instance> BufferedUartRx<'d, T> { 171impl<'d, T: Instance> BufferedUartRx<'d, T> {
172 /// Create a new buffered UART RX.
161 pub fn new( 173 pub fn new(
162 _uart: impl Peripheral<P = T> + 'd, 174 _uart: impl Peripheral<P = T> + 'd,
163 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 175 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -173,6 +185,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
173 Self { phantom: PhantomData } 185 Self { phantom: PhantomData }
174 } 186 }
175 187
188 /// Create a new buffered UART RX with flow control.
176 pub fn new_with_rts( 189 pub fn new_with_rts(
177 _uart: impl Peripheral<P = T> + 'd, 190 _uart: impl Peripheral<P = T> + 'd,
178 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 191 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -253,6 +266,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
253 Poll::Ready(result) 266 Poll::Ready(result)
254 } 267 }
255 268
269 /// Read from UART RX buffer blocking execution until done.
256 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 270 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
257 loop { 271 loop {
258 match Self::try_read(buf) { 272 match Self::try_read(buf) {
@@ -303,6 +317,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
303} 317}
304 318
305impl<'d, T: Instance> BufferedUartTx<'d, T> { 319impl<'d, T: Instance> BufferedUartTx<'d, T> {
320 /// Create a new buffered UART TX.
306 pub fn new( 321 pub fn new(
307 _uart: impl Peripheral<P = T> + 'd, 322 _uart: impl Peripheral<P = T> + 'd,
308 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 323 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -318,6 +333,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
318 Self { phantom: PhantomData } 333 Self { phantom: PhantomData }
319 } 334 }
320 335
336 /// Create a new buffered UART TX with flow control.
321 pub fn new_with_cts( 337 pub fn new_with_cts(
322 _uart: impl Peripheral<P = T> + 'd, 338 _uart: impl Peripheral<P = T> + 'd,
323 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 339 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -373,6 +389,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
373 }) 389 })
374 } 390 }
375 391
392 /// Write to UART TX buffer blocking execution until done.
376 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<usize, Error> { 393 pub fn blocking_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
377 if buf.is_empty() { 394 if buf.is_empty() {
378 return Ok(0); 395 return Ok(0);
@@ -398,6 +415,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
398 } 415 }
399 } 416 }
400 417
418 /// Flush UART TX blocking execution until done.
401 pub fn blocking_flush(&mut self) -> Result<(), Error> { 419 pub fn blocking_flush(&mut self) -> Result<(), Error> {
402 loop { 420 loop {
403 let state = T::buffered_state(); 421 let state = T::buffered_state();
@@ -407,6 +425,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
407 } 425 }
408 } 426 }
409 427
428 /// Check if UART is busy.
410 pub fn busy(&self) -> bool { 429 pub fn busy(&self) -> bool {
411 T::regs().uartfr().read().busy() 430 T::regs().uartfr().read().busy()
412 } 431 }
@@ -466,6 +485,7 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
466 } 485 }
467} 486}
468 487
488/// Interrupt handler.
469pub struct BufferedInterruptHandler<T: Instance> { 489pub struct BufferedInterruptHandler<T: Instance> {
470 _uart: PhantomData<T>, 490 _uart: PhantomData<T>,
471} 491}
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index f82b9036b..32be7661d 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -20,11 +20,16 @@ use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
20mod buffered; 20mod buffered;
21pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; 21pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx};
22 22
23/// Word length.
23#[derive(Clone, Copy, PartialEq, Eq, Debug)] 24#[derive(Clone, Copy, PartialEq, Eq, Debug)]
24pub enum DataBits { 25pub enum DataBits {
26 /// 5 bits.
25 DataBits5, 27 DataBits5,
28 /// 6 bits.
26 DataBits6, 29 DataBits6,
30 /// 7 bits.
27 DataBits7, 31 DataBits7,
32 /// 8 bits.
28 DataBits8, 33 DataBits8,
29} 34}
30 35
@@ -39,13 +44,18 @@ impl DataBits {
39 } 44 }
40} 45}
41 46
47/// Parity bit.
42#[derive(Clone, Copy, PartialEq, Eq, Debug)] 48#[derive(Clone, Copy, PartialEq, Eq, Debug)]
43pub enum Parity { 49pub enum Parity {
50 /// No parity.
44 ParityNone, 51 ParityNone,
52 /// Even parity.
45 ParityEven, 53 ParityEven,
54 /// Odd parity.
46 ParityOdd, 55 ParityOdd,
47} 56}
48 57
58/// Stop bits.
49#[derive(Clone, Copy, PartialEq, Eq, Debug)] 59#[derive(Clone, Copy, PartialEq, Eq, Debug)]
50pub enum StopBits { 60pub enum StopBits {
51 #[doc = "1 stop bit"] 61 #[doc = "1 stop bit"]
@@ -54,20 +64,25 @@ pub enum StopBits {
54 STOP2, 64 STOP2,
55} 65}
56 66
67/// UART config.
57#[non_exhaustive] 68#[non_exhaustive]
58#[derive(Clone, Copy, PartialEq, Eq, Debug)] 69#[derive(Clone, Copy, PartialEq, Eq, Debug)]
59pub struct Config { 70pub struct Config {
71 /// Baud rate.
60 pub baudrate: u32, 72 pub baudrate: u32,
73 /// Word length.
61 pub data_bits: DataBits, 74 pub data_bits: DataBits,
75 /// Stop bits.
62 pub stop_bits: StopBits, 76 pub stop_bits: StopBits,
77 /// Parity bit.
63 pub parity: Parity, 78 pub parity: Parity,
64 /// Invert the tx pin output 79 /// Invert the tx pin output
65 pub invert_tx: bool, 80 pub invert_tx: bool,
66 /// Invert the rx pin input 81 /// Invert the rx pin input
67 pub invert_rx: bool, 82 pub invert_rx: bool,
68 // Invert the rts pin 83 /// Invert the rts pin
69 pub invert_rts: bool, 84 pub invert_rts: bool,
70 // Invert the cts pin 85 /// Invert the cts pin
71 pub invert_cts: bool, 86 pub invert_cts: bool,
72} 87}
73 88
@@ -102,21 +117,25 @@ pub enum Error {
102 Framing, 117 Framing,
103} 118}
104 119
120/// Internal DMA state of UART RX.
105pub struct DmaState { 121pub struct DmaState {
106 rx_err_waker: AtomicWaker, 122 rx_err_waker: AtomicWaker,
107 rx_errs: AtomicU16, 123 rx_errs: AtomicU16,
108} 124}
109 125
126/// UART driver.
110pub struct Uart<'d, T: Instance, M: Mode> { 127pub struct Uart<'d, T: Instance, M: Mode> {
111 tx: UartTx<'d, T, M>, 128 tx: UartTx<'d, T, M>,
112 rx: UartRx<'d, T, M>, 129 rx: UartRx<'d, T, M>,
113} 130}
114 131
132/// UART TX driver.
115pub struct UartTx<'d, T: Instance, M: Mode> { 133pub struct UartTx<'d, T: Instance, M: Mode> {
116 tx_dma: Option<PeripheralRef<'d, AnyChannel>>, 134 tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
117 phantom: PhantomData<(&'d mut T, M)>, 135 phantom: PhantomData<(&'d mut T, M)>,
118} 136}
119 137
138/// UART RX driver.
120pub struct UartRx<'d, T: Instance, M: Mode> { 139pub struct UartRx<'d, T: Instance, M: Mode> {
121 rx_dma: Option<PeripheralRef<'d, AnyChannel>>, 140 rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
122 phantom: PhantomData<(&'d mut T, M)>, 141 phantom: PhantomData<(&'d mut T, M)>,
@@ -142,6 +161,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
142 } 161 }
143 } 162 }
144 163
164 /// Transmit the provided buffer blocking execution until done.
145 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 165 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
146 let r = T::regs(); 166 let r = T::regs();
147 for &b in buffer { 167 for &b in buffer {
@@ -151,12 +171,14 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
151 Ok(()) 171 Ok(())
152 } 172 }
153 173
174 /// Flush UART TX blocking execution until done.
154 pub fn blocking_flush(&mut self) -> Result<(), Error> { 175 pub fn blocking_flush(&mut self) -> Result<(), Error> {
155 let r = T::regs(); 176 let r = T::regs();
156 while !r.uartfr().read().txfe() {} 177 while !r.uartfr().read().txfe() {}
157 Ok(()) 178 Ok(())
158 } 179 }
159 180
181 /// Check if UART is busy transmitting.
160 pub fn busy(&self) -> bool { 182 pub fn busy(&self) -> bool {
161 T::regs().uartfr().read().busy() 183 T::regs().uartfr().read().busy()
162 } 184 }
@@ -191,6 +213,8 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
191} 213}
192 214
193impl<'d, T: Instance> UartTx<'d, T, Blocking> { 215impl<'d, T: Instance> UartTx<'d, T, Blocking> {
216 /// Convert this uart TX instance into a buffered uart using the provided
217 /// irq and transmit buffer.
194 pub fn into_buffered( 218 pub fn into_buffered(
195 self, 219 self,
196 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 220 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -203,6 +227,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
203} 227}
204 228
205impl<'d, T: Instance> UartTx<'d, T, Async> { 229impl<'d, T: Instance> UartTx<'d, T, Async> {
230 /// Write to UART TX from the provided buffer using DMA.
206 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 231 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
207 let ch = self.tx_dma.as_mut().unwrap(); 232 let ch = self.tx_dma.as_mut().unwrap();
208 let transfer = unsafe { 233 let transfer = unsafe {
@@ -246,6 +271,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
246 } 271 }
247 } 272 }
248 273
274 /// Read from UART RX blocking execution until done.
249 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 275 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
250 while buffer.len() > 0 { 276 while buffer.len() > 0 {
251 let received = self.drain_fifo(buffer)?; 277 let received = self.drain_fifo(buffer)?;
@@ -294,6 +320,7 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
294} 320}
295 321
296impl<'d, T: Instance> UartRx<'d, T, Blocking> { 322impl<'d, T: Instance> UartRx<'d, T, Blocking> {
323 /// Create a new UART RX instance for blocking mode operations.
297 pub fn new_blocking( 324 pub fn new_blocking(
298 _uart: impl Peripheral<P = T> + 'd, 325 _uart: impl Peripheral<P = T> + 'd,
299 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 326 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -304,6 +331,8 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
304 Self::new_inner(false, None) 331 Self::new_inner(false, None)
305 } 332 }
306 333
334 /// Convert this uart RX instance into a buffered uart using the provided
335 /// irq and receive buffer.
307 pub fn into_buffered( 336 pub fn into_buffered(
308 self, 337 self,
309 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 338 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -315,6 +344,7 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
315 } 344 }
316} 345}
317 346
347/// Interrupt handler.
318pub struct InterruptHandler<T: Instance> { 348pub struct InterruptHandler<T: Instance> {
319 _uart: PhantomData<T>, 349 _uart: PhantomData<T>,
320} 350}
@@ -338,6 +368,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
338} 368}
339 369
340impl<'d, T: Instance> UartRx<'d, T, Async> { 370impl<'d, T: Instance> UartRx<'d, T, Async> {
371 /// Read from UART RX into the provided buffer.
341 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 372 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
342 // clear error flags before we drain the fifo. errors that have accumulated 373 // clear error flags before we drain the fifo. errors that have accumulated
343 // in the flags will also be present in the fifo. 374 // in the flags will also be present in the fifo.
@@ -458,6 +489,8 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
458 ) 489 )
459 } 490 }
460 491
492 /// Convert this uart instance into a buffered uart using the provided
493 /// irq, transmit and receive buffers.
461 pub fn into_buffered( 494 pub fn into_buffered(
462 self, 495 self,
463 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 496 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
@@ -667,22 +700,27 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
667} 700}
668 701
669impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 702impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
703 /// Transmit the provided buffer blocking execution until done.
670 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 704 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
671 self.tx.blocking_write(buffer) 705 self.tx.blocking_write(buffer)
672 } 706 }
673 707
708 /// Flush UART TX blocking execution until done.
674 pub fn blocking_flush(&mut self) -> Result<(), Error> { 709 pub fn blocking_flush(&mut self) -> Result<(), Error> {
675 self.tx.blocking_flush() 710 self.tx.blocking_flush()
676 } 711 }
677 712
713 /// Read from UART RX blocking execution until done.
678 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 714 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
679 self.rx.blocking_read(buffer) 715 self.rx.blocking_read(buffer)
680 } 716 }
681 717
718 /// Check if UART is busy transmitting.
682 pub fn busy(&self) -> bool { 719 pub fn busy(&self) -> bool {
683 self.tx.busy() 720 self.tx.busy()
684 } 721 }
685 722
723 /// Wait until TX is empty and send break condition.
686 pub async fn send_break(&mut self, bits: u32) { 724 pub async fn send_break(&mut self, bits: u32) {
687 self.tx.send_break(bits).await 725 self.tx.send_break(bits).await
688 } 726 }
@@ -695,10 +733,12 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
695} 733}
696 734
697impl<'d, T: Instance> Uart<'d, T, Async> { 735impl<'d, T: Instance> Uart<'d, T, Async> {
736 /// Write to UART TX from the provided buffer.
698 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 737 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
699 self.tx.write(buffer).await 738 self.tx.write(buffer).await
700 } 739 }
701 740
741 /// Read from UART RX into the provided buffer.
702 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 742 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
703 self.rx.read(buffer).await 743 self.rx.read(buffer).await
704 } 744 }
@@ -889,6 +929,7 @@ mod sealed {
889 pub trait RtsPin<T: Instance> {} 929 pub trait RtsPin<T: Instance> {}
890} 930}
891 931
932/// UART mode.
892pub trait Mode: sealed::Mode {} 933pub trait Mode: sealed::Mode {}
893 934
894macro_rules! impl_mode { 935macro_rules! impl_mode {
@@ -898,12 +939,15 @@ macro_rules! impl_mode {
898 }; 939 };
899} 940}
900 941
942/// Blocking mode.
901pub struct Blocking; 943pub struct Blocking;
944/// Async mode.
902pub struct Async; 945pub struct Async;
903 946
904impl_mode!(Blocking); 947impl_mode!(Blocking);
905impl_mode!(Async); 948impl_mode!(Async);
906 949
950/// UART instance trait.
907pub trait Instance: sealed::Instance {} 951pub trait Instance: sealed::Instance {}
908 952
909macro_rules! impl_instance { 953macro_rules! impl_instance {
@@ -938,9 +982,13 @@ macro_rules! impl_instance {
938impl_instance!(UART0, UART0_IRQ, 20, 21); 982impl_instance!(UART0, UART0_IRQ, 20, 21);
939impl_instance!(UART1, UART1_IRQ, 22, 23); 983impl_instance!(UART1, UART1_IRQ, 22, 23);
940 984
985/// Trait for TX pins.
941pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} 986pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
987/// Trait for RX pins.
942pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} 988pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
989/// Trait for Clear To Send (CTS) pins.
943pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {} 990pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {}
991/// Trait for Request To Send (RTS) pins.
944pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {} 992pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {}
945 993
946macro_rules! impl_pin { 994macro_rules! impl_pin {
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 4a74ee6f7..bcd848222 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -20,7 +20,9 @@ pub(crate) mod sealed {
20 } 20 }
21} 21}
22 22
23/// USB peripheral instance.
23pub trait Instance: sealed::Instance + 'static { 24pub trait Instance: sealed::Instance + 'static {
25 /// Interrupt for this peripheral.
24 type Interrupt: interrupt::typelevel::Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
25} 27}
26 28
@@ -96,6 +98,7 @@ impl EndpointData {
96 } 98 }
97} 99}
98 100
101/// RP2040 USB driver handle.
99pub struct Driver<'d, T: Instance> { 102pub struct Driver<'d, T: Instance> {
100 phantom: PhantomData<&'d mut T>, 103 phantom: PhantomData<&'d mut T>,
101 ep_in: [EndpointData; EP_COUNT], 104 ep_in: [EndpointData; EP_COUNT],
@@ -104,6 +107,7 @@ pub struct Driver<'d, T: Instance> {
104} 107}
105 108
106impl<'d, T: Instance> Driver<'d, T> { 109impl<'d, T: Instance> Driver<'d, T> {
110 /// Create a new USB driver.
107 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self { 111 pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
108 T::Interrupt::unpend(); 112 T::Interrupt::unpend();
109 unsafe { T::Interrupt::enable() }; 113 unsafe { T::Interrupt::enable() };
@@ -240,6 +244,7 @@ impl<'d, T: Instance> Driver<'d, T> {
240 } 244 }
241} 245}
242 246
247/// USB interrupt handler.
243pub struct InterruptHandler<T: Instance> { 248pub struct InterruptHandler<T: Instance> {
244 _uart: PhantomData<T>, 249 _uart: PhantomData<T>,
245} 250}
@@ -342,6 +347,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
342 } 347 }
343} 348}
344 349
350/// Type representing the RP USB bus.
345pub struct Bus<'d, T: Instance> { 351pub struct Bus<'d, T: Instance> {
346 phantom: PhantomData<&'d mut T>, 352 phantom: PhantomData<&'d mut T>,
347 ep_out: [EndpointData; EP_COUNT], 353 ep_out: [EndpointData; EP_COUNT],
@@ -461,6 +467,7 @@ trait Dir {
461 fn waker(i: usize) -> &'static AtomicWaker; 467 fn waker(i: usize) -> &'static AtomicWaker;
462} 468}
463 469
470/// Type for In direction.
464pub enum In {} 471pub enum In {}
465impl Dir for In { 472impl Dir for In {
466 fn dir() -> Direction { 473 fn dir() -> Direction {
@@ -473,6 +480,7 @@ impl Dir for In {
473 } 480 }
474} 481}
475 482
483/// Type for Out direction.
476pub enum Out {} 484pub enum Out {}
477impl Dir for Out { 485impl Dir for Out {
478 fn dir() -> Direction { 486 fn dir() -> Direction {
@@ -485,6 +493,7 @@ impl Dir for Out {
485 } 493 }
486} 494}
487 495
496/// Endpoint for RP USB driver.
488pub struct Endpoint<'d, T: Instance, D> { 497pub struct Endpoint<'d, T: Instance, D> {
489 _phantom: PhantomData<(&'d mut T, D)>, 498 _phantom: PhantomData<(&'d mut T, D)>,
490 info: EndpointInfo, 499 info: EndpointInfo,
@@ -616,6 +625,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
616 } 625 }
617} 626}
618 627
628/// Control pipe for RP USB driver.
619pub struct ControlPipe<'d, T: Instance> { 629pub struct ControlPipe<'d, T: Instance> {
620 _phantom: PhantomData<&'d mut T>, 630 _phantom: PhantomData<&'d mut T>,
621 max_packet_size: u16, 631 max_packet_size: u16,