aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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/uart/buffered.rs20
-rw-r--r--embassy-rp/src/uart/mod.rs4
-rw-r--r--embassy-rp/src/usb.rs10
10 files changed, 253 insertions, 26 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/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..26f21193a 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -938,9 +938,13 @@ macro_rules! impl_instance {
938impl_instance!(UART0, UART0_IRQ, 20, 21); 938impl_instance!(UART0, UART0_IRQ, 20, 21);
939impl_instance!(UART1, UART1_IRQ, 22, 23); 939impl_instance!(UART1, UART1_IRQ, 22, 23);
940 940
941/// Trait for TX pins.
941pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} 942pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
943/// Trait for RX pins.
942pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} 944pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
945/// Trait for Clear To Send (CTS) pins.
943pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {} 946pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {}
947/// Trait for Request To Send (RTS) pins.
944pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {} 948pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {}
945 949
946macro_rules! impl_pin { 950macro_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,