aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/dma/gpdma.rs18
-rw-r--r--embassy-stm32/src/hrtim/mod.rs16
-rw-r--r--embassy-stm32/src/ipcc.rs8
-rw-r--r--embassy-stm32/src/lib.rs26
-rw-r--r--embassy-stm32/src/low_power.rs106
-rw-r--r--embassy-stm32/src/opamp.rs9
-rw-r--r--embassy-stm32/src/rng.rs1
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs2
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs31
-rw-r--r--embassy-stm32/src/timer/mod.rs158
-rw-r--r--embassy-stm32/src/timer/qei.rs23
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs45
-rw-r--r--embassy-stm32/src/usb/mod.rs4
-rw-r--r--embassy-stm32/src/usb/usb.rs7
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs2
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs13
-rw-r--r--embassy-stm32/src/wdg/mod.rs4
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm_dma.rs2
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs10
19 files changed, 375 insertions, 110 deletions
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index b061415eb..34b2426b9 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -16,6 +16,7 @@ use crate::interrupt::Priority;
16use crate::pac; 16use crate::pac;
17use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
18 18
19/// GPDMA transfer options.
19#[derive(Debug, Copy, Clone, PartialEq, Eq)] 20#[derive(Debug, Copy, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21#[non_exhaustive] 22#[non_exhaustive]
@@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
113 } 114 }
114} 115}
115 116
117/// DMA request type alias. (also known as DMA channel number in some chips)
116pub type Request = u8; 118pub type Request = u8;
117 119
120/// DMA channel.
118#[cfg(dmamux)] 121#[cfg(dmamux)]
119pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 122pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
123/// DMA channel.
120#[cfg(not(dmamux))] 124#[cfg(not(dmamux))]
121pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 125pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
122 126
@@ -131,12 +135,14 @@ pub(crate) mod sealed {
131 } 135 }
132} 136}
133 137
138/// DMA transfer.
134#[must_use = "futures do nothing unless you `.await` or poll them"] 139#[must_use = "futures do nothing unless you `.await` or poll them"]
135pub struct Transfer<'a, C: Channel> { 140pub struct Transfer<'a, C: Channel> {
136 channel: PeripheralRef<'a, C>, 141 channel: PeripheralRef<'a, C>,
137} 142}
138 143
139impl<'a, C: Channel> Transfer<'a, C> { 144impl<'a, C: Channel> Transfer<'a, C> {
145 /// Create a new read DMA transfer (peripheral to memory).
140 pub unsafe fn new_read<W: Word>( 146 pub unsafe fn new_read<W: Word>(
141 channel: impl Peripheral<P = C> + 'a, 147 channel: impl Peripheral<P = C> + 'a,
142 request: Request, 148 request: Request,
@@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
147 Self::new_read_raw(channel, request, peri_addr, buf, options) 153 Self::new_read_raw(channel, request, peri_addr, buf, options)
148 } 154 }
149 155
156 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
150 pub unsafe fn new_read_raw<W: Word>( 157 pub unsafe fn new_read_raw<W: Word>(
151 channel: impl Peripheral<P = C> + 'a, 158 channel: impl Peripheral<P = C> + 'a,
152 request: Request, 159 request: Request,
@@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
172 ) 179 )
173 } 180 }
174 181
182 /// Create a new write DMA transfer (memory to peripheral).
175 pub unsafe fn new_write<W: Word>( 183 pub unsafe fn new_write<W: Word>(
176 channel: impl Peripheral<P = C> + 'a, 184 channel: impl Peripheral<P = C> + 'a,
177 request: Request, 185 request: Request,
@@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
182 Self::new_write_raw(channel, request, buf, peri_addr, options) 190 Self::new_write_raw(channel, request, buf, peri_addr, options)
183 } 191 }
184 192
193 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
185 pub unsafe fn new_write_raw<W: Word>( 194 pub unsafe fn new_write_raw<W: Word>(
186 channel: impl Peripheral<P = C> + 'a, 195 channel: impl Peripheral<P = C> + 'a,
187 request: Request, 196 request: Request,
@@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
207 ) 216 )
208 } 217 }
209 218
219 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
210 pub unsafe fn new_write_repeated<W: Word>( 220 pub unsafe fn new_write_repeated<W: Word>(
211 channel: impl Peripheral<P = C> + 'a, 221 channel: impl Peripheral<P = C> + 'a,
212 request: Request, 222 request: Request,
@@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
297 this 307 this
298 } 308 }
299 309
310 /// Request the transfer to stop.
311 ///
312 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
300 pub fn request_stop(&mut self) { 313 pub fn request_stop(&mut self) {
301 let ch = self.channel.regs().ch(self.channel.num()); 314 let ch = self.channel.regs().ch(self.channel.num());
302 ch.cr().modify(|w| { 315 ch.cr().modify(|w| {
@@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
304 }) 317 })
305 } 318 }
306 319
320 /// Return whether this transfer is still running.
321 ///
322 /// If this returns `false`, it can be because either the transfer finished, or
323 /// it was requested to stop early with [`request_stop`](Self::request_stop).
307 pub fn is_running(&mut self) -> bool { 324 pub fn is_running(&mut self) -> bool {
308 let ch = self.channel.regs().ch(self.channel.num()); 325 let ch = self.channel.regs().ch(self.channel.num());
309 let sr = ch.sr().read(); 326 let sr = ch.sr().read();
@@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
317 ch.br1().read().bndt() 334 ch.br1().read().bndt()
318 } 335 }
319 336
337 /// Blocking wait until the transfer finishes.
320 pub fn blocking_wait(mut self) { 338 pub fn blocking_wait(mut self) {
321 while self.is_running() {} 339 while self.is_running() {}
322 340
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 1e6626a58..faefaabbc 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -68,22 +68,22 @@ mod sealed {
68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} 68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
69 69
70/// HRTIM PWM pin. 70/// HRTIM PWM pin.
71pub struct PwmPin<'d, Perip, Channel> { 71pub struct PwmPin<'d, T, C> {
72 _pin: PeripheralRef<'d, AnyPin>, 72 _pin: PeripheralRef<'d, AnyPin>,
73 phantom: PhantomData<(Perip, Channel)>, 73 phantom: PhantomData<(T, C)>,
74} 74}
75 75
76/// HRTIM complementary PWM pin. 76/// HRTIM complementary PWM pin.
77pub struct ComplementaryPwmPin<'d, Perip, Channel> { 77pub struct ComplementaryPwmPin<'d, T, C> {
78 _pin: PeripheralRef<'d, AnyPin>, 78 _pin: PeripheralRef<'d, AnyPin>,
79 phantom: PhantomData<(Perip, Channel)>, 79 phantom: PhantomData<(T, C)>,
80} 80}
81 81
82macro_rules! advanced_channel_impl { 82macro_rules! advanced_channel_impl {
83 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 83 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
84 impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { 84 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
87 into_ref!(pin); 87 into_ref!(pin);
88 critical_section::with(|_| { 88 critical_section::with(|_| {
89 pin.set_low(); 89 pin.set_low();
@@ -98,9 +98,9 @@ macro_rules! advanced_channel_impl {
98 } 98 }
99 } 99 }
100 100
101 impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { 101 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
102 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 102 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
103 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 103 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self {
104 into_ref!(pin); 104 into_ref!(pin);
105 critical_section::with(|_| { 105 critical_section::with(|_| {
106 pin.set_low(); 106 pin.set_low();
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 4006dee19..663a7f59d 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,3 +1,5 @@
1//! Inter-Process Communication Controller (IPCC)
2
1use core::future::poll_fn; 3use core::future::poll_fn;
2use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
3use core::task::Poll; 5use core::task::Poll;
@@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
41 } 43 }
42} 44}
43 45
46/// TX interrupt handler.
44pub struct TransmitInterruptHandler {} 47pub struct TransmitInterruptHandler {}
45 48
46impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { 49impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
@@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
72 } 75 }
73} 76}
74 77
78/// IPCC config.
75#[non_exhaustive] 79#[non_exhaustive]
76#[derive(Clone, Copy, Default)] 80#[derive(Clone, Copy, Default)]
77pub struct Config { 81pub struct Config {
@@ -79,6 +83,8 @@ pub struct Config {
79 // reserved for future use 83 // reserved for future use
80} 84}
81 85
86/// Channel.
87#[allow(missing_docs)]
82#[derive(Debug, Clone, Copy)] 88#[derive(Debug, Clone, Copy)]
83#[repr(C)] 89#[repr(C)]
84pub enum IpccChannel { 90pub enum IpccChannel {
@@ -90,9 +96,11 @@ pub enum IpccChannel {
90 Channel6 = 5, 96 Channel6 = 5,
91} 97}
92 98
99/// IPCC driver.
93pub struct Ipcc; 100pub struct Ipcc;
94 101
95impl Ipcc { 102impl Ipcc {
103 /// Enable IPCC.
96 pub fn enable(_config: Config) { 104 pub fn enable(_config: Config) {
97 IPCC::enable_and_reset(); 105 IPCC::enable_and_reset();
98 IPCC::set_cpu2(true); 106 IPCC::set_cpu2(true);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 5d9b4e6a0..207f7ed8f 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(test), no_std)] 1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![warn(missing_docs)]
3 4
4//! ## Feature flags 5//! ## Feature flags
5#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] 6#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
@@ -79,6 +80,7 @@ pub(crate) mod _generated {
79 #![allow(dead_code)] 80 #![allow(dead_code)]
80 #![allow(unused_imports)] 81 #![allow(unused_imports)]
81 #![allow(non_snake_case)] 82 #![allow(non_snake_case)]
83 #![allow(missing_docs)]
82 84
83 include!(concat!(env!("OUT_DIR"), "/_generated.rs")); 85 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
84} 86}
@@ -149,15 +151,33 @@ use crate::interrupt::Priority;
149pub use crate::pac::NVIC_PRIO_BITS; 151pub use crate::pac::NVIC_PRIO_BITS;
150use crate::rcc::sealed::RccPeripheral; 152use crate::rcc::sealed::RccPeripheral;
151 153
154/// `embassy-stm32` global configuration.
152#[non_exhaustive] 155#[non_exhaustive]
153pub struct Config { 156pub struct Config {
157 /// RCC config.
154 pub rcc: rcc::Config, 158 pub rcc: rcc::Config,
159
160 /// Enable debug during sleep.
161 ///
162 /// May incrase power consumption. Defaults to true.
155 #[cfg(dbgmcu)] 163 #[cfg(dbgmcu)]
156 pub enable_debug_during_sleep: bool, 164 pub enable_debug_during_sleep: bool,
165
166 /// BDMA interrupt priority.
167 ///
168 /// Defaults to P0 (highest).
157 #[cfg(bdma)] 169 #[cfg(bdma)]
158 pub bdma_interrupt_priority: Priority, 170 pub bdma_interrupt_priority: Priority,
171
172 /// DMA interrupt priority.
173 ///
174 /// Defaults to P0 (highest).
159 #[cfg(dma)] 175 #[cfg(dma)]
160 pub dma_interrupt_priority: Priority, 176 pub dma_interrupt_priority: Priority,
177
178 /// GPDMA interrupt priority.
179 ///
180 /// Defaults to P0 (highest).
161 #[cfg(gpdma)] 181 #[cfg(gpdma)]
162 pub gpdma_interrupt_priority: Priority, 182 pub gpdma_interrupt_priority: Priority,
163} 183}
@@ -178,7 +198,11 @@ impl Default for Config {
178 } 198 }
179} 199}
180 200
181/// Initialize embassy. 201/// Initialize the `embassy-stm32` HAL with the provided configuration.
202///
203/// This returns the peripheral singletons that can be used for creating drivers.
204///
205/// This should only be called once at startup, otherwise it panics.
182pub fn init(config: Config) -> Peripherals { 206pub fn init(config: Config) -> Peripherals {
183 critical_section::with(|cs| { 207 critical_section::with(|cs| {
184 let p = Peripherals::take_with_cs(cs); 208 let p = Peripherals::take_with_cs(cs);
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 20d8f9045..a41c40eba 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -1,50 +1,53 @@
1/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating 1//! Low-power support.
2/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which 2//!
3/// can use knowledge of which peripherals are currently blocked upon to transparently and safely 3//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
4/// enter such low-power modes (currently, only `STOP2`) when idle. 4//! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
5/// 5//! can use knowledge of which peripherals are currently blocked upon to transparently and safely
6/// The executor determines which peripherals are active by their RCC state; consequently, 6//! enter such low-power modes (currently, only `STOP2`) when idle.
7/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few 7//!
8/// exceptions to this rule: 8//! The executor determines which peripherals are active by their RCC state; consequently,
9/// 9//! low-power states can only be entered if all peripherals have been `drop`'d. There are a few
10/// * `GPIO` 10//! exceptions to this rule:
11/// * `RCC` 11//!
12/// 12//! * `GPIO`
13/// Since entering and leaving low-power modes typically incurs a significant latency, the 13//! * `RCC`
14/// low-power executor will only attempt to enter when the next timer event is at least 14//!
15/// [`time_driver::MIN_STOP_PAUSE`] in the future. 15//! Since entering and leaving low-power modes typically incurs a significant latency, the
16/// 16//! low-power executor will only attempt to enter when the next timer event is at least
17/// Currently there is no macro analogous to `embassy_executor::main` for this executor; 17//! [`time_driver::MIN_STOP_PAUSE`] in the future.
18/// consequently one must define their entrypoint manually. Moveover, you must relinquish control 18//!
19/// of the `RTC` peripheral to the executor. This will typically look like 19//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
20/// 20//! consequently one must define their entrypoint manually. Moveover, you must relinquish control
21/// ```rust,no_run 21//! of the `RTC` peripheral to the executor. This will typically look like
22/// use embassy_executor::Spawner; 22//!
23/// use embassy_stm32::low_power::Executor; 23//! ```rust,no_run
24/// use embassy_stm32::rtc::{Rtc, RtcConfig}; 24//! use embassy_executor::Spawner;
25/// use static_cell::make_static; 25//! use embassy_stm32::low_power::Executor;
26/// 26//! use embassy_stm32::rtc::{Rtc, RtcConfig};
27/// #[cortex_m_rt::entry] 27//! use static_cell::make_static;
28/// fn main() -> ! { 28//!
29/// Executor::take().run(|spawner| { 29//! #[cortex_m_rt::entry]
30/// unwrap!(spawner.spawn(async_main(spawner))); 30//! fn main() -> ! {
31/// }); 31//! Executor::take().run(|spawner| {
32/// } 32//! unwrap!(spawner.spawn(async_main(spawner)));
33/// 33//! });
34/// #[embassy_executor::task] 34//! }
35/// async fn async_main(spawner: Spawner) { 35//!
36/// // initialize the platform... 36//! #[embassy_executor::task]
37/// let mut config = embassy_stm32::Config::default(); 37//! async fn async_main(spawner: Spawner) {
38/// let p = embassy_stm32::init(config); 38//! // initialize the platform...
39/// 39//! let mut config = embassy_stm32::Config::default();
40/// // give the RTC to the executor... 40//! let p = embassy_stm32::init(config);
41/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); 41//!
42/// let rtc = make_static!(rtc); 42//! // give the RTC to the executor...
43/// embassy_stm32::low_power::stop_with_rtc(rtc); 43//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
44/// 44//! let rtc = make_static!(rtc);
45/// // your application here... 45//! embassy_stm32::low_power::stop_with_rtc(rtc);
46/// } 46//!
47/// ``` 47//! // your application here...
48//! }
49//! ```
50
48use core::arch::asm; 51use core::arch::asm;
49use core::marker::PhantomData; 52use core::marker::PhantomData;
50use core::sync::atomic::{compiler_fence, Ordering}; 53use core::sync::atomic::{compiler_fence, Ordering};
@@ -64,6 +67,7 @@ static mut EXECUTOR: Option<Executor> = None;
64foreach_interrupt! { 67foreach_interrupt! {
65 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 68 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
66 #[interrupt] 69 #[interrupt]
70 #[allow(non_snake_case)]
67 unsafe fn $irq() { 71 unsafe fn $irq() {
68 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 72 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
69 } 73 }
@@ -75,10 +79,15 @@ pub(crate) unsafe fn on_wakeup_irq() {
75 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 79 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
76} 80}
77 81
82/// Configure STOP mode with RTC.
78pub fn stop_with_rtc(rtc: &'static Rtc) { 83pub fn stop_with_rtc(rtc: &'static Rtc) {
79 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) 84 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
80} 85}
81 86
87/// Get whether the core is ready to enter the given stop mode.
88///
89/// This will return false if some peripheral driver is in use that
90/// prevents entering the given stop mode.
82pub fn stop_ready(stop_mode: StopMode) -> bool { 91pub fn stop_ready(stop_mode: StopMode) -> bool {
83 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 92 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
84 Some(StopMode::Stop2) => true, 93 Some(StopMode::Stop2) => true,
@@ -87,10 +96,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
87 } 96 }
88} 97}
89 98
99/// Available stop modes.
90#[non_exhaustive] 100#[non_exhaustive]
91#[derive(PartialEq)] 101#[derive(PartialEq)]
92pub enum StopMode { 102pub enum StopMode {
103 /// STOP 1
93 Stop1, 104 Stop1,
105 /// STOP 2
94 Stop2, 106 Stop2,
95} 107}
96 108
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index e1eb031d1..df8a78bcc 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -1,9 +1,12 @@
1//! Operational Amplifier (OPAMP)
1#![macro_use] 2#![macro_use]
2 3
3use embassy_hal_internal::{into_ref, PeripheralRef}; 4use embassy_hal_internal::{into_ref, PeripheralRef};
4 5
5use crate::Peripheral; 6use crate::Peripheral;
6 7
8/// Gain
9#[allow(missing_docs)]
7#[derive(Clone, Copy)] 10#[derive(Clone, Copy)]
8pub enum OpAmpGain { 11pub enum OpAmpGain {
9 Mul1, 12 Mul1,
@@ -13,6 +16,8 @@ pub enum OpAmpGain {
13 Mul16, 16 Mul16,
14} 17}
15 18
19/// Speed
20#[allow(missing_docs)]
16#[derive(Clone, Copy)] 21#[derive(Clone, Copy)]
17pub enum OpAmpSpeed { 22pub enum OpAmpSpeed {
18 Normal, 23 Normal,
@@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
180 } 185 }
181} 186}
182 187
188/// Opamp instance trait.
183pub trait Instance: sealed::Instance + 'static {} 189pub trait Instance: sealed::Instance + 'static {}
184 190
185pub(crate) mod sealed { 191pub(crate) mod sealed {
@@ -198,8 +204,11 @@ pub(crate) mod sealed {
198 pub trait OutputPin<T: Instance> {} 204 pub trait OutputPin<T: Instance> {}
199} 205}
200 206
207/// Non-inverting pin trait.
201pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} 208pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
209/// Inverting pin trait.
202pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} 210pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
211/// Output pin trait.
203pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} 212pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {}
204 213
205macro_rules! impl_opamp_external_output { 214macro_rules! impl_opamp_external_output {
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 6ee89a922..ca641f352 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> {
80 let _ = self.next_u32(); 80 let _ = self.next_u32();
81 } 81 }
82 82
83 /// Reset the RNG.
83 #[cfg(not(rng_v1))] 84 #[cfg(not(rng_v1))]
84 pub fn reset(&mut self) { 85 pub fn reset(&mut self) {
85 T::regs().cr().write(|reg| { 86 T::regs().cr().write(|reg| {
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ab142053a..10006baff 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -293,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
293 293
294#[cfg(sdmmc_v1)] 294#[cfg(sdmmc_v1)]
295impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { 295impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
296 /// Create a new SDMMC driver, with 1 data lane.
296 pub fn new_1bit( 297 pub fn new_1bit(
297 sdmmc: impl Peripheral<P = T> + 'd, 298 sdmmc: impl Peripheral<P = T> + 'd,
298 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 299 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -327,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
327 ) 328 )
328 } 329 }
329 330
331 /// Create a new SDMMC driver, with 4 data lanes.
330 pub fn new_4bit( 332 pub fn new_4bit(
331 sdmmc: impl Peripheral<P = T> + 'd, 333 sdmmc: impl Peripheral<P = T> + 'd,
332 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 334 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index e543a5b43..71d7110b5 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
13use crate::time::Hertz; 13use crate::time::Hertz;
14use crate::Peripheral; 14use crate::Peripheral;
15 15
16pub struct ComplementaryPwmPin<'d, Perip, Channel> { 16/// Complementary PWM pin wrapper.
17///
18/// This wraps a pin to make it usable with PWM.
19pub struct ComplementaryPwmPin<'d, T, C> {
17 _pin: PeripheralRef<'d, AnyPin>, 20 _pin: PeripheralRef<'d, AnyPin>,
18 phantom: PhantomData<(Perip, Channel)>, 21 phantom: PhantomData<(T, C)>,
19} 22}
20 23
21macro_rules! complementary_channel_impl { 24macro_rules! complementary_channel_impl {
22 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
23 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { 26 impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
24 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { 27 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
28 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
25 into_ref!(pin); 29 into_ref!(pin);
26 critical_section::with(|_| { 30 critical_section::with(|_| {
27 pin.set_low(); 31 pin.set_low();
@@ -43,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
43complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); 47complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
44complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 48complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
45 49
50/// PWM driver with support for standard and complementary outputs.
46pub struct ComplementaryPwm<'d, T> { 51pub struct ComplementaryPwm<'d, T> {
47 inner: PeripheralRef<'d, T>, 52 inner: PeripheralRef<'d, T>,
48} 53}
49 54
50impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver.
51 pub fn new( 57 pub fn new(
52 tim: impl Peripheral<P = T> + 'd, 58 tim: impl Peripheral<P = T> + 'd,
53 _ch1: Option<PwmPin<'d, T, Ch1>>, 59 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
72 let mut this = Self { inner: tim }; 78 let mut this = Self { inner: tim };
73 79
74 this.inner.set_counting_mode(counting_mode); 80 this.inner.set_counting_mode(counting_mode);
75 this.set_freq(freq); 81 this.set_frequency(freq);
76 this.inner.start(); 82 this.inner.start();
77 83
78 this.inner.enable_outputs(); 84 this.inner.enable_outputs();
@@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
88 this 94 this
89 } 95 }
90 96
97 /// Enable the given channel.
91 pub fn enable(&mut self, channel: Channel) { 98 pub fn enable(&mut self, channel: Channel) {
92 self.inner.enable_channel(channel, true); 99 self.inner.enable_channel(channel, true);
93 self.inner.enable_complementary_channel(channel, true); 100 self.inner.enable_complementary_channel(channel, true);
94 } 101 }
95 102
103 /// Disable the given channel.
96 pub fn disable(&mut self, channel: Channel) { 104 pub fn disable(&mut self, channel: Channel) {
97 self.inner.enable_complementary_channel(channel, false); 105 self.inner.enable_complementary_channel(channel, false);
98 self.inner.enable_channel(channel, false); 106 self.inner.enable_channel(channel, false);
99 } 107 }
100 108
101 pub fn set_freq(&mut self, freq: Hertz) { 109 /// Set PWM frequency.
110 ///
111 /// Note: when you call this, the max duty value changes, so you will have to
112 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
113 pub fn set_frequency(&mut self, freq: Hertz) {
102 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 114 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
103 2u8 115 2u8
104 } else { 116 } else {
@@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
107 self.inner.set_frequency(freq * multiplier); 119 self.inner.set_frequency(freq * multiplier);
108 } 120 }
109 121
122 /// Get max duty value.
123 ///
124 /// This value depends on the configured frequency and the timer's clock rate from RCC.
110 pub fn get_max_duty(&self) -> u16 { 125 pub fn get_max_duty(&self) -> u16 {
111 self.inner.get_max_compare_value() + 1 126 self.inner.get_max_compare_value() + 1
112 } 127 }
113 128
129 /// Set the duty for a given channel.
130 ///
131 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
114 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 132 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
115 assert!(duty <= self.get_max_duty()); 133 assert!(duty <= self.get_max_duty());
116 self.inner.set_compare_value(channel, duty) 134 self.inner.set_compare_value(channel, duty)
117 } 135 }
118 136
137 /// Set the output polarity for a given channel.
119 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 138 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
120 self.inner.set_output_polarity(channel, polarity); 139 self.inner.set_output_polarity(channel, polarity);
121 self.inner.set_complementary_output_polarity(channel, polarity); 140 self.inner.set_complementary_output_polarity(channel, polarity);
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 42ef878f7..74120adad 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -17,17 +17,27 @@ pub mod low_level {
17} 17}
18 18
19pub(crate) mod sealed { 19pub(crate) mod sealed {
20
21 use super::*; 20 use super::*;
21
22 /// Basic 16-bit timer instance.
22 pub trait Basic16bitInstance: RccPeripheral { 23 pub trait Basic16bitInstance: RccPeripheral {
24 /// Interrupt for this timer.
23 type Interrupt: interrupt::typelevel::Interrupt; 25 type Interrupt: interrupt::typelevel::Interrupt;
24 26
27 /// Get access to the basic 16bit timer registers.
28 ///
29 /// Note: This works even if the timer is more capable, because registers
30 /// for the less capable timers are a subset. This allows writing a driver
31 /// for a given set of capabilities, and having it transparently work with
32 /// more capable timers.
25 fn regs() -> crate::pac::timer::TimBasic; 33 fn regs() -> crate::pac::timer::TimBasic;
26 34
35 /// Start the timer.
27 fn start(&mut self) { 36 fn start(&mut self) {
28 Self::regs().cr1().modify(|r| r.set_cen(true)); 37 Self::regs().cr1().modify(|r| r.set_cen(true));
29 } 38 }
30 39
40 /// Stop the timer.
31 fn stop(&mut self) { 41 fn stop(&mut self) {
32 Self::regs().cr1().modify(|r| r.set_cen(false)); 42 Self::regs().cr1().modify(|r| r.set_cen(false));
33 } 43 }
@@ -63,6 +73,9 @@ pub(crate) mod sealed {
63 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 73 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
64 } 74 }
65 75
76 /// Clear update interrupt.
77 ///
78 /// Returns whether the update interrupt flag was set.
66 fn clear_update_interrupt(&mut self) -> bool { 79 fn clear_update_interrupt(&mut self) -> bool {
67 let regs = Self::regs(); 80 let regs = Self::regs();
68 let sr = regs.sr().read(); 81 let sr = regs.sr().read();
@@ -76,14 +89,17 @@ pub(crate) mod sealed {
76 } 89 }
77 } 90 }
78 91
92 /// Enable/disable the update interrupt.
79 fn enable_update_interrupt(&mut self, enable: bool) { 93 fn enable_update_interrupt(&mut self, enable: bool) {
80 Self::regs().dier().write(|r| r.set_uie(enable)); 94 Self::regs().dier().write(|r| r.set_uie(enable));
81 } 95 }
82 96
97 /// Enable/disable autoreload preload.
83 fn set_autoreload_preload(&mut self, enable: bool) { 98 fn set_autoreload_preload(&mut self, enable: bool) {
84 Self::regs().cr1().modify(|r| r.set_arpe(enable)); 99 Self::regs().cr1().modify(|r| r.set_arpe(enable));
85 } 100 }
86 101
102 /// Get the timer frequency.
87 fn get_frequency(&self) -> Hertz { 103 fn get_frequency(&self) -> Hertz {
88 let timer_f = Self::frequency(); 104 let timer_f = Self::frequency();
89 105
@@ -95,9 +111,17 @@ pub(crate) mod sealed {
95 } 111 }
96 } 112 }
97 113
114 /// Gneral-purpose 16-bit timer instance.
98 pub trait GeneralPurpose16bitInstance: Basic16bitInstance { 115 pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
116 /// Get access to the general purpose 16bit timer registers.
117 ///
118 /// Note: This works even if the timer is more capable, because registers
119 /// for the less capable timers are a subset. This allows writing a driver
120 /// for a given set of capabilities, and having it transparently work with
121 /// more capable timers.
99 fn regs_gp16() -> crate::pac::timer::TimGp16; 122 fn regs_gp16() -> crate::pac::timer::TimGp16;
100 123
124 /// Set counting mode.
101 fn set_counting_mode(&mut self, mode: CountingMode) { 125 fn set_counting_mode(&mut self, mode: CountingMode) {
102 let (cms, dir) = mode.into(); 126 let (cms, dir) = mode.into();
103 127
@@ -110,19 +134,29 @@ pub(crate) mod sealed {
110 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) 134 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
111 } 135 }
112 136
137 /// Get counting mode.
113 fn get_counting_mode(&self) -> CountingMode { 138 fn get_counting_mode(&self) -> CountingMode {
114 let cr1 = Self::regs_gp16().cr1().read(); 139 let cr1 = Self::regs_gp16().cr1().read();
115 (cr1.cms(), cr1.dir()).into() 140 (cr1.cms(), cr1.dir()).into()
116 } 141 }
117 142
143 /// Set clock divider.
118 fn set_clock_division(&mut self, ckd: vals::Ckd) { 144 fn set_clock_division(&mut self, ckd: vals::Ckd) {
119 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); 145 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
120 } 146 }
121 } 147 }
122 148
149 /// Gneral-purpose 32-bit timer instance.
123 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { 150 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
151 /// Get access to the general purpose 32bit timer registers.
152 ///
153 /// Note: This works even if the timer is more capable, because registers
154 /// for the less capable timers are a subset. This allows writing a driver
155 /// for a given set of capabilities, and having it transparently work with
156 /// more capable timers.
124 fn regs_gp32() -> crate::pac::timer::TimGp32; 157 fn regs_gp32() -> crate::pac::timer::TimGp32;
125 158
159 /// Set timer frequency.
126 fn set_frequency(&mut self, frequency: Hertz) { 160 fn set_frequency(&mut self, frequency: Hertz) {
127 let f = frequency.0; 161 let f = frequency.0;
128 assert!(f > 0); 162 assert!(f > 0);
@@ -140,6 +174,7 @@ pub(crate) mod sealed {
140 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 174 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
141 } 175 }
142 176
177 /// Get timer frequency.
143 fn get_frequency(&self) -> Hertz { 178 fn get_frequency(&self) -> Hertz {
144 let timer_f = Self::frequency(); 179 let timer_f = Self::frequency();
145 180
@@ -151,141 +186,177 @@ pub(crate) mod sealed {
151 } 186 }
152 } 187 }
153 188
189 /// Advanced control timer instance.
154 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 190 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
191 /// Get access to the advanced timer registers.
155 fn regs_advanced() -> crate::pac::timer::TimAdv; 192 fn regs_advanced() -> crate::pac::timer::TimAdv;
156 } 193 }
157 194
195 /// Capture/Compare 16-bit timer instance.
158 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { 196 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
197 /// Set input capture filter.
159 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { 198 fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
160 let raw_channel = channel.raw(); 199 let raw_channel = channel.index();
161 Self::regs_gp16() 200 Self::regs_gp16()
162 .ccmr_input(raw_channel / 2) 201 .ccmr_input(raw_channel / 2)
163 .modify(|r| r.set_icf(raw_channel % 2, icf)); 202 .modify(|r| r.set_icf(raw_channel % 2, icf));
164 } 203 }
165 204
205 /// Clear input interrupt.
166 fn clear_input_interrupt(&mut self, channel: Channel) { 206 fn clear_input_interrupt(&mut self, channel: Channel) {
167 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); 207 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
168 } 208 }
169 209
210 /// Enable input interrupt.
170 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { 211 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
171 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); 212 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
172 } 213 }
214
215 /// Set input capture prescaler.
173 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { 216 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
174 let raw_channel = channel.raw(); 217 let raw_channel = channel.index();
175 Self::regs_gp16() 218 Self::regs_gp16()
176 .ccmr_input(raw_channel / 2) 219 .ccmr_input(raw_channel / 2)
177 .modify(|r| r.set_icpsc(raw_channel % 2, factor)); 220 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
178 } 221 }
179 222
223 /// Set input TI selection.
180 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { 224 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
181 let raw_channel = channel.raw(); 225 let raw_channel = channel.index();
182 Self::regs_gp16() 226 Self::regs_gp16()
183 .ccmr_input(raw_channel / 2) 227 .ccmr_input(raw_channel / 2)
184 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); 228 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
185 } 229 }
230
231 /// Set input capture mode.
186 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { 232 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
187 Self::regs_gp16().ccer().modify(|r| match mode { 233 Self::regs_gp16().ccer().modify(|r| match mode {
188 InputCaptureMode::Rising => { 234 InputCaptureMode::Rising => {
189 r.set_ccnp(channel.raw(), false); 235 r.set_ccnp(channel.index(), false);
190 r.set_ccp(channel.raw(), false); 236 r.set_ccp(channel.index(), false);
191 } 237 }
192 InputCaptureMode::Falling => { 238 InputCaptureMode::Falling => {
193 r.set_ccnp(channel.raw(), false); 239 r.set_ccnp(channel.index(), false);
194 r.set_ccp(channel.raw(), true); 240 r.set_ccp(channel.index(), true);
195 } 241 }
196 InputCaptureMode::BothEdges => { 242 InputCaptureMode::BothEdges => {
197 r.set_ccnp(channel.raw(), true); 243 r.set_ccnp(channel.index(), true);
198 r.set_ccp(channel.raw(), true); 244 r.set_ccp(channel.index(), true);
199 } 245 }
200 }); 246 });
201 } 247 }
248
249 /// Enable timer outputs.
202 fn enable_outputs(&mut self); 250 fn enable_outputs(&mut self);
203 251
252 /// Set output compare mode.
204 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 253 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
205 let r = Self::regs_gp16(); 254 let r = Self::regs_gp16();
206 let raw_channel: usize = channel.raw(); 255 let raw_channel: usize = channel.index();
207 r.ccmr_output(raw_channel / 2) 256 r.ccmr_output(raw_channel / 2)
208 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 257 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
209 } 258 }
210 259
260 /// Set output polarity.
211 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 261 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
212 Self::regs_gp16() 262 Self::regs_gp16()
213 .ccer() 263 .ccer()
214 .modify(|w| w.set_ccp(channel.raw(), polarity.into())); 264 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
215 } 265 }
216 266
267 /// Enable/disable a channel.
217 fn enable_channel(&mut self, channel: Channel, enable: bool) { 268 fn enable_channel(&mut self, channel: Channel, enable: bool) {
218 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); 269 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
219 } 270 }
220 271
272 /// Set compare value for a channel.
221 fn set_compare_value(&mut self, channel: Channel, value: u16) { 273 fn set_compare_value(&mut self, channel: Channel, value: u16) {
222 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 274 Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
223 } 275 }
224 276
277 /// Get capture value for a channel.
225 fn get_capture_value(&mut self, channel: Channel) -> u16 { 278 fn get_capture_value(&mut self, channel: Channel) -> u16 {
226 Self::regs_gp16().ccr(channel.raw()).read().ccr() 279 Self::regs_gp16().ccr(channel.index()).read().ccr()
227 } 280 }
228 281
282 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
229 fn get_max_compare_value(&self) -> u16 { 283 fn get_max_compare_value(&self) -> u16 {
230 Self::regs_gp16().arr().read().arr() 284 Self::regs_gp16().arr().read().arr()
231 } 285 }
232 286
287 /// Get compare value for a channel.
233 fn get_compare_value(&self, channel: Channel) -> u16 { 288 fn get_compare_value(&self, channel: Channel) -> u16 {
234 Self::regs_gp16().ccr(channel.raw()).read().ccr() 289 Self::regs_gp16().ccr(channel.index()).read().ccr()
235 } 290 }
236 } 291 }
237 292
293 /// Capture/Compare 16-bit timer instance with complementary pin support.
238 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { 294 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
295 /// Set complementary output polarity.
239 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 296 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
240 Self::regs_advanced() 297 Self::regs_advanced()
241 .ccer() 298 .ccer()
242 .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); 299 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
243 } 300 }
244 301
302 /// Set clock divider for the dead time.
245 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 303 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
246 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 304 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
247 } 305 }
248 306
307 /// Set dead time, as a fraction of the max duty value.
249 fn set_dead_time_value(&mut self, value: u8) { 308 fn set_dead_time_value(&mut self, value: u8) {
250 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 309 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
251 } 310 }
252 311
312 /// Enable/disable a complementary channel.
253 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 313 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
254 Self::regs_advanced() 314 Self::regs_advanced()
255 .ccer() 315 .ccer()
256 .modify(|w| w.set_ccne(channel.raw(), enable)); 316 .modify(|w| w.set_ccne(channel.index(), enable));
257 } 317 }
258 } 318 }
259 319
320 /// Capture/Compare 32-bit timer instance.
260 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { 321 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
322 /// Set comapre value for a channel.
261 fn set_compare_value(&mut self, channel: Channel, value: u32) { 323 fn set_compare_value(&mut self, channel: Channel, value: u32) {
262 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); 324 Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value));
263 } 325 }
264 326
327 /// Get capture value for a channel.
265 fn get_capture_value(&mut self, channel: Channel) -> u32 { 328 fn get_capture_value(&mut self, channel: Channel) -> u32 {
266 Self::regs_gp32().ccr(channel.raw()).read().ccr() 329 Self::regs_gp32().ccr(channel.index()).read().ccr()
267 } 330 }
268 331
332 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
269 fn get_max_compare_value(&self) -> u32 { 333 fn get_max_compare_value(&self) -> u32 {
270 Self::regs_gp32().arr().read().arr() 334 Self::regs_gp32().arr().read().arr()
271 } 335 }
272 336
337 /// Get compare value for a channel.
273 fn get_compare_value(&self, channel: Channel) -> u32 { 338 fn get_compare_value(&self, channel: Channel) -> u32 {
274 Self::regs_gp32().ccr(channel.raw()).read().ccr() 339 Self::regs_gp32().ccr(channel.index()).read().ccr()
275 } 340 }
276 } 341 }
277} 342}
278 343
344/// Timer channel.
279#[derive(Clone, Copy)] 345#[derive(Clone, Copy)]
280pub enum Channel { 346pub enum Channel {
347 /// Channel 1.
281 Ch1, 348 Ch1,
349 /// Channel 2.
282 Ch2, 350 Ch2,
351 /// Channel 3.
283 Ch3, 352 Ch3,
353 /// Channel 4.
284 Ch4, 354 Ch4,
285} 355}
286 356
287impl Channel { 357impl Channel {
288 pub fn raw(&self) -> usize { 358 /// Get the channel index (0..3)
359 pub fn index(&self) -> usize {
289 match self { 360 match self {
290 Channel::Ch1 => 0, 361 Channel::Ch1 => 0,
291 Channel::Ch2 => 1, 362 Channel::Ch2 => 1,
@@ -295,17 +366,25 @@ impl Channel {
295 } 366 }
296} 367}
297 368
369/// Input capture mode.
298#[derive(Clone, Copy)] 370#[derive(Clone, Copy)]
299pub enum InputCaptureMode { 371pub enum InputCaptureMode {
372 /// Rising edge only.
300 Rising, 373 Rising,
374 /// Falling edge only.
301 Falling, 375 Falling,
376 /// Both rising or falling edges.
302 BothEdges, 377 BothEdges,
303} 378}
304 379
380/// Input TI selection.
305#[derive(Clone, Copy)] 381#[derive(Clone, Copy)]
306pub enum InputTISelection { 382pub enum InputTISelection {
383 /// Normal
307 Normal, 384 Normal,
385 /// Alternate
308 Alternate, 386 Alternate,
387 /// TRC
309 TRC, 388 TRC,
310} 389}
311 390
@@ -319,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
319 } 398 }
320} 399}
321 400
401/// Timer counting mode.
322#[repr(u8)] 402#[repr(u8)]
323#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 403#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
324pub enum CountingMode { 404pub enum CountingMode {
@@ -345,6 +425,7 @@ pub enum CountingMode {
345} 425}
346 426
347impl CountingMode { 427impl CountingMode {
428 /// Return whether this mode is edge-aligned (up or down).
348 pub fn is_edge_aligned(&self) -> bool { 429 pub fn is_edge_aligned(&self) -> bool {
349 match self { 430 match self {
350 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, 431 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
@@ -352,6 +433,7 @@ impl CountingMode {
352 } 433 }
353 } 434 }
354 435
436 /// Return whether this mode is center-aligned.
355 pub fn is_center_aligned(&self) -> bool { 437 pub fn is_center_aligned(&self) -> bool {
356 match self { 438 match self {
357 CountingMode::CenterAlignedDownInterrupts 439 CountingMode::CenterAlignedDownInterrupts
@@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
386 } 468 }
387} 469}
388 470
471/// Output compare mode.
389#[derive(Clone, Copy)] 472#[derive(Clone, Copy)]
390pub enum OutputCompareMode { 473pub enum OutputCompareMode {
474 /// The comparison between the output compare register TIMx_CCRx and
475 /// the counter TIMx_CNT has no effect on the outputs.
476 /// (this mode is used to generate a timing base).
391 Frozen, 477 Frozen,
478 /// Set channel to active level on match. OCxREF signal is forced high when the
479 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
392 ActiveOnMatch, 480 ActiveOnMatch,
481 /// Set channel to inactive level on match. OCxREF signal is forced low when the
482 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
393 InactiveOnMatch, 483 InactiveOnMatch,
484 /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
394 Toggle, 485 Toggle,
486 /// Force inactive level - OCxREF is forced low.
395 ForceInactive, 487 ForceInactive,
488 /// Force active level - OCxREF is forced high.
396 ForceActive, 489 ForceActive,
490 /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
491 /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
492 /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
397 PwmMode1, 493 PwmMode1,
494 /// PWM mode 2 - In upcounting, channel is inactive as long as
495 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
496 /// TIMx_CNT>TIMx_CCRx else inactive.
398 PwmMode2, 497 PwmMode2,
498 // TODO: there's more modes here depending on the chip family.
399} 499}
400 500
401impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 501impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
@@ -413,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
413 } 513 }
414} 514}
415 515
516/// Timer output pin polarity.
416#[derive(Clone, Copy)] 517#[derive(Clone, Copy)]
417pub enum OutputPolarity { 518pub enum OutputPolarity {
519 /// Active high (higher duty value makes the pin spend more time high).
418 ActiveHigh, 520 ActiveHigh,
521 /// Active low (higher duty value makes the pin spend more time low).
419 ActiveLow, 522 ActiveLow,
420} 523}
421 524
@@ -428,24 +531,31 @@ impl From<OutputPolarity> for bool {
428 } 531 }
429} 532}
430 533
534/// Basic 16-bit timer instance.
431pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 535pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
432 536
537/// Gneral-purpose 16-bit timer instance.
433pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 538pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
434 539
540/// Gneral-purpose 32-bit timer instance.
435pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} 541pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
436 542
543/// Advanced control timer instance.
437pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} 544pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
438 545
546/// Capture/Compare 16-bit timer instance.
439pub trait CaptureCompare16bitInstance: 547pub trait CaptureCompare16bitInstance:
440 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static 548 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
441{ 549{
442} 550}
443 551
552/// Capture/Compare 16-bit timer instance with complementary pin support.
444pub trait ComplementaryCaptureCompare16bitInstance: 553pub trait ComplementaryCaptureCompare16bitInstance:
445 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static 554 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
446{ 555{
447} 556}
448 557
558/// Capture/Compare 32-bit timer instance.
449pub trait CaptureCompare32bitInstance: 559pub trait CaptureCompare32bitInstance:
450 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static 560 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
451{ 561{
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 9f9379c20..59efb72ba 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -9,23 +9,30 @@ use crate::gpio::sealed::AFType;
9use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
10use crate::Peripheral; 10use crate::Peripheral;
11 11
12/// Counting direction
12pub enum Direction { 13pub enum Direction {
14 /// Counting up.
13 Upcounting, 15 Upcounting,
16 /// Counting down.
14 Downcounting, 17 Downcounting,
15} 18}
16 19
17pub struct Ch1; 20/// Channel 1 marker type.
18pub struct Ch2; 21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
19 24
20pub struct QeiPin<'d, Perip, Channel> { 25/// Wrapper for using a pin with QEI.
26pub struct QeiPin<'d, T, Channel> {
21 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
22 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, Channel)>,
23} 29}
24 30
25macro_rules! channel_impl { 31macro_rules! channel_impl {
26 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
27 impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> {
28 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 34 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")]
35 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
29 into_ref!(pin); 36 into_ref!(pin);
30 critical_section::with(|_| { 37 critical_section::with(|_| {
31 pin.set_low(); 38 pin.set_low();
@@ -45,11 +52,13 @@ macro_rules! channel_impl {
45channel_impl!(new_ch1, Ch1, Channel1Pin); 52channel_impl!(new_ch1, Ch1, Channel1Pin);
46channel_impl!(new_ch2, Ch2, Channel2Pin); 53channel_impl!(new_ch2, Ch2, Channel2Pin);
47 54
55/// Quadrature decoder driver.
48pub struct Qei<'d, T> { 56pub struct Qei<'d, T> {
49 _inner: PeripheralRef<'d, T>, 57 _inner: PeripheralRef<'d, T>,
50} 58}
51 59
52impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 60impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
61 /// Create a new quadrature decoder driver.
53 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { 62 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
54 Self::new_inner(tim) 63 Self::new_inner(tim)
55 } 64 }
@@ -84,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
84 Self { _inner: tim } 93 Self { _inner: tim }
85 } 94 }
86 95
96 /// Get direction.
87 pub fn read_direction(&self) -> Direction { 97 pub fn read_direction(&self) -> Direction {
88 match T::regs_gp16().cr1().read().dir() { 98 match T::regs_gp16().cr1().read().dir() {
89 vals::Dir::DOWN => Direction::Downcounting, 99 vals::Dir::DOWN => Direction::Downcounting,
@@ -91,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
91 } 101 }
92 } 102 }
93 103
104 /// Get count.
94 pub fn count(&self) -> u16 { 105 pub fn count(&self) -> u16 {
95 T::regs_gp16().cnt().read().cnt() 106 T::regs_gp16().cnt().read().cnt()
96 } 107 }
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 234bbaff0..e6072aa15 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::Peripheral; 12use crate::Peripheral;
13 13
14pub struct Ch1; 14/// Channel 1 marker type.
15pub struct Ch2; 15pub enum Ch1 {}
16pub struct Ch3; 16/// Channel 2 marker type.
17pub struct Ch4; 17pub enum Ch2 {}
18 18/// Channel 3 marker type.
19pub struct PwmPin<'d, Perip, Channel> { 19pub enum Ch3 {}
20/// Channel 4 marker type.
21pub enum Ch4 {}
22
23/// PWM pin wrapper.
24///
25/// This wraps a pin to make it usable with PWM.
26pub struct PwmPin<'d, T, C> {
20 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
21 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, C)>,
22} 29}
23 30
24macro_rules! channel_impl { 31macro_rules! channel_impl {
25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
26 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
27 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { 34 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
35 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
28 into_ref!(pin); 36 into_ref!(pin);
29 critical_section::with(|_| { 37 critical_section::with(|_| {
30 pin.set_low(); 38 pin.set_low();
@@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
46channel_impl!(new_ch3, Ch3, Channel3Pin); 54channel_impl!(new_ch3, Ch3, Channel3Pin);
47channel_impl!(new_ch4, Ch4, Channel4Pin); 55channel_impl!(new_ch4, Ch4, Channel4Pin);
48 56
57/// Simple PWM driver.
49pub struct SimplePwm<'d, T> { 58pub struct SimplePwm<'d, T> {
50 inner: PeripheralRef<'d, T>, 59 inner: PeripheralRef<'d, T>,
51} 60}
52 61
53impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 62impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
63 /// Create a new simple PWM driver.
54 pub fn new( 64 pub fn new(
55 tim: impl Peripheral<P = T> + 'd, 65 tim: impl Peripheral<P = T> + 'd,
56 _ch1: Option<PwmPin<'d, T, Ch1>>, 66 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
71 let mut this = Self { inner: tim }; 81 let mut this = Self { inner: tim };
72 82
73 this.inner.set_counting_mode(counting_mode); 83 this.inner.set_counting_mode(counting_mode);
74 this.set_freq(freq); 84 this.set_frequency(freq);
75 this.inner.start(); 85 this.inner.start();
76 86
77 this.inner.enable_outputs(); 87 this.inner.enable_outputs();
@@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
87 this 97 this
88 } 98 }
89 99
100 /// Enable the given channel.
90 pub fn enable(&mut self, channel: Channel) { 101 pub fn enable(&mut self, channel: Channel) {
91 self.inner.enable_channel(channel, true); 102 self.inner.enable_channel(channel, true);
92 } 103 }
93 104
105 /// Disable the given channel.
94 pub fn disable(&mut self, channel: Channel) { 106 pub fn disable(&mut self, channel: Channel) {
95 self.inner.enable_channel(channel, false); 107 self.inner.enable_channel(channel, false);
96 } 108 }
97 109
98 pub fn set_freq(&mut self, freq: Hertz) { 110 /// Set PWM frequency.
111 ///
112 /// Note: when you call this, the max duty value changes, so you will have to
113 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
114 pub fn set_frequency(&mut self, freq: Hertz) {
99 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 115 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
100 2u8 116 2u8
101 } else { 117 } else {
@@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
104 self.inner.set_frequency(freq * multiplier); 120 self.inner.set_frequency(freq * multiplier);
105 } 121 }
106 122
123 /// Get max duty value.
124 ///
125 /// This value depends on the configured frequency and the timer's clock rate from RCC.
107 pub fn get_max_duty(&self) -> u16 { 126 pub fn get_max_duty(&self) -> u16 {
108 self.inner.get_max_compare_value() + 1 127 self.inner.get_max_compare_value() + 1
109 } 128 }
110 129
130 /// Set the duty for a given channel.
131 ///
132 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
111 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 133 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
112 assert!(duty <= self.get_max_duty()); 134 assert!(duty <= self.get_max_duty());
113 self.inner.set_compare_value(channel, duty) 135 self.inner.set_compare_value(channel, duty)
114 } 136 }
115 137
138 /// Set the output polarity for a given channel.
116 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 139 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
117 self.inner.set_output_polarity(channel, polarity); 140 self.inner.set_output_polarity(channel, polarity);
118 } 141 }
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index d0b289462..4debd4e54 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -1,3 +1,5 @@
1//! Universal Serial Bus (USB)
2
1use crate::interrupt; 3use crate::interrupt;
2use crate::rcc::RccPeripheral; 4use crate::rcc::RccPeripheral;
3 5
@@ -10,7 +12,9 @@ pub(crate) mod sealed {
10 } 12 }
11} 13}
12 14
15/// USB instance trait.
13pub trait Instance: sealed::Instance + RccPeripheral + 'static { 16pub trait Instance: sealed::Instance + RccPeripheral + 'static {
17 /// Interrupt for this USB instance.
14 type Interrupt: interrupt::typelevel::Interrupt; 18 type Interrupt: interrupt::typelevel::Interrupt;
15} 19}
16 20
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 295dc9198..a8aebfe1f 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -244,6 +244,7 @@ struct EndpointData {
244 used_out: bool, 244 used_out: bool,
245} 245}
246 246
247/// USB driver.
247pub struct Driver<'d, T: Instance> { 248pub struct Driver<'d, T: Instance> {
248 phantom: PhantomData<&'d mut T>, 249 phantom: PhantomData<&'d mut T>,
249 alloc: [EndpointData; EP_COUNT], 250 alloc: [EndpointData; EP_COUNT],
@@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> {
251} 252}
252 253
253impl<'d, T: Instance> Driver<'d, T> { 254impl<'d, T: Instance> Driver<'d, T> {
255 /// Create a new USB driver.
254 pub fn new( 256 pub fn new(
255 _usb: impl Peripheral<P = T> + 'd, 257 _usb: impl Peripheral<P = T> + 'd,
256 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 258 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
465 } 467 }
466} 468}
467 469
470/// USB bus.
468pub struct Bus<'d, T: Instance> { 471pub struct Bus<'d, T: Instance> {
469 phantom: PhantomData<&'d mut T>, 472 phantom: PhantomData<&'d mut T>,
470 ep_types: [EpType; EP_COUNT - 1], 473 ep_types: [EpType; EP_COUNT - 1],
@@ -640,6 +643,7 @@ trait Dir {
640 fn waker(i: usize) -> &'static AtomicWaker; 643 fn waker(i: usize) -> &'static AtomicWaker;
641} 644}
642 645
646/// Marker type for the "IN" direction.
643pub enum In {} 647pub enum In {}
644impl Dir for In { 648impl Dir for In {
645 fn dir() -> Direction { 649 fn dir() -> Direction {
@@ -652,6 +656,7 @@ impl Dir for In {
652 } 656 }
653} 657}
654 658
659/// Marker type for the "OUT" direction.
655pub enum Out {} 660pub enum Out {}
656impl Dir for Out { 661impl Dir for Out {
657 fn dir() -> Direction { 662 fn dir() -> Direction {
@@ -664,6 +669,7 @@ impl Dir for Out {
664 } 669 }
665} 670}
666 671
672/// USB endpoint.
667pub struct Endpoint<'d, T: Instance, D> { 673pub struct Endpoint<'d, T: Instance, D> {
668 _phantom: PhantomData<(&'d mut T, D)>, 674 _phantom: PhantomData<(&'d mut T, D)>,
669 info: EndpointInfo, 675 info: EndpointInfo,
@@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
813 } 819 }
814} 820}
815 821
822/// USB control pipe.
816pub struct ControlPipe<'d, T: Instance> { 823pub struct ControlPipe<'d, T: Instance> {
817 _phantom: PhantomData<&'d mut T>, 824 _phantom: PhantomData<&'d mut T>,
818 max_packet_size: u16, 825 max_packet_size: u16,
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs
index 1abd031dd..0649e684b 100644
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ b/embassy-stm32/src/usb_otg/mod.rs
@@ -20,7 +20,9 @@ pub(crate) mod sealed {
20 } 20 }
21} 21}
22 22
23/// USB OTG instance.
23pub trait Instance: sealed::Instance + RccPeripheral { 24pub trait Instance: sealed::Instance + RccPeripheral {
25 /// Interrupt for this USB OTG instance.
24 type Interrupt: interrupt::typelevel::Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
25} 27}
26 28
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index ba77bfb16..190fb274f 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -204,6 +204,7 @@ pub enum PhyType {
204} 204}
205 205
206impl PhyType { 206impl PhyType {
207 /// Get whether this PHY is any of the internal types.
207 pub fn internal(&self) -> bool { 208 pub fn internal(&self) -> bool {
208 match self { 209 match self {
209 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, 210 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
@@ -211,6 +212,7 @@ impl PhyType {
211 } 212 }
212 } 213 }
213 214
215 /// Get whether this PHY is any of the high-speed types.
214 pub fn high_speed(&self) -> bool { 216 pub fn high_speed(&self) -> bool {
215 match self { 217 match self {
216 PhyType::InternalFullSpeed => false, 218 PhyType::InternalFullSpeed => false,
@@ -218,7 +220,7 @@ impl PhyType {
218 } 220 }
219 } 221 }
220 222
221 pub fn to_dspd(&self) -> vals::Dspd { 223 fn to_dspd(&self) -> vals::Dspd {
222 match self { 224 match self {
223 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, 225 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
224 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, 226 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
@@ -230,6 +232,7 @@ impl PhyType {
230/// Indicates that [State::ep_out_buffers] is empty. 232/// Indicates that [State::ep_out_buffers] is empty.
231const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; 233const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
232 234
235/// USB OTG driver state.
233pub struct State<const EP_COUNT: usize> { 236pub struct State<const EP_COUNT: usize> {
234 /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. 237 /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true.
235 ep0_setup_data: UnsafeCell<[u8; 8]>, 238 ep0_setup_data: UnsafeCell<[u8; 8]>,
@@ -247,6 +250,7 @@ unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {}
247unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} 250unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
248 251
249impl<const EP_COUNT: usize> State<EP_COUNT> { 252impl<const EP_COUNT: usize> State<EP_COUNT> {
253 /// Create a new State.
250 pub const fn new() -> Self { 254 pub const fn new() -> Self {
251 const NEW_AW: AtomicWaker = AtomicWaker::new(); 255 const NEW_AW: AtomicWaker = AtomicWaker::new();
252 const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); 256 const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _);
@@ -271,6 +275,7 @@ struct EndpointData {
271 fifo_size_words: u16, 275 fifo_size_words: u16,
272} 276}
273 277
278/// USB driver config.
274#[non_exhaustive] 279#[non_exhaustive]
275#[derive(Clone, Copy, PartialEq, Eq, Debug)] 280#[derive(Clone, Copy, PartialEq, Eq, Debug)]
276pub struct Config { 281pub struct Config {
@@ -297,6 +302,7 @@ impl Default for Config {
297 } 302 }
298} 303}
299 304
305/// USB driver.
300pub struct Driver<'d, T: Instance> { 306pub struct Driver<'d, T: Instance> {
301 config: Config, 307 config: Config,
302 phantom: PhantomData<&'d mut T>, 308 phantom: PhantomData<&'d mut T>,
@@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
527 } 533 }
528} 534}
529 535
536/// USB bus.
530pub struct Bus<'d, T: Instance> { 537pub struct Bus<'d, T: Instance> {
531 config: Config, 538 config: Config,
532 phantom: PhantomData<&'d mut T>, 539 phantom: PhantomData<&'d mut T>,
@@ -1092,6 +1099,7 @@ trait Dir {
1092 fn dir() -> Direction; 1099 fn dir() -> Direction;
1093} 1100}
1094 1101
1102/// Marker type for the "IN" direction.
1095pub enum In {} 1103pub enum In {}
1096impl Dir for In { 1104impl Dir for In {
1097 fn dir() -> Direction { 1105 fn dir() -> Direction {
@@ -1099,6 +1107,7 @@ impl Dir for In {
1099 } 1107 }
1100} 1108}
1101 1109
1110/// Marker type for the "OUT" direction.
1102pub enum Out {} 1111pub enum Out {}
1103impl Dir for Out { 1112impl Dir for Out {
1104 fn dir() -> Direction { 1113 fn dir() -> Direction {
@@ -1106,6 +1115,7 @@ impl Dir for Out {
1106 } 1115 }
1107} 1116}
1108 1117
1118/// USB endpoint.
1109pub struct Endpoint<'d, T: Instance, D> { 1119pub struct Endpoint<'d, T: Instance, D> {
1110 _phantom: PhantomData<(&'d mut T, D)>, 1120 _phantom: PhantomData<(&'d mut T, D)>,
1111 info: EndpointInfo, 1121 info: EndpointInfo,
@@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1299 } 1309 }
1300} 1310}
1301 1311
1312/// USB control pipe.
1302pub struct ControlPipe<'d, T: Instance> { 1313pub struct ControlPipe<'d, T: Instance> {
1303 _phantom: PhantomData<&'d mut T>, 1314 _phantom: PhantomData<&'d mut T>,
1304 max_packet_size: u16, 1315 max_packet_size: u16,
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 5751a9ff3..dc701ef64 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -6,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr};
6 6
7use crate::rcc::LSI_FREQ; 7use crate::rcc::LSI_FREQ;
8 8
9/// Independent watchdog (IWDG) driver.
9pub struct IndependentWatchdog<'d, T: Instance> { 10pub struct IndependentWatchdog<'d, T: Instance> {
10 wdg: PhantomData<&'d mut T>, 11 wdg: PhantomData<&'d mut T>,
11} 12}
@@ -64,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
64 IndependentWatchdog { wdg: PhantomData } 65 IndependentWatchdog { wdg: PhantomData }
65 } 66 }
66 67
68 /// Unleash (start) the watchdog.
67 pub fn unleash(&mut self) { 69 pub fn unleash(&mut self) {
68 T::regs().kr().write(|w| w.set_key(Key::START)); 70 T::regs().kr().write(|w| w.set_key(Key::START));
69 } 71 }
70 72
73 /// Pet (reload, refresh) the watchdog.
71 pub fn pet(&mut self) { 74 pub fn pet(&mut self) {
72 T::regs().kr().write(|w| w.set_key(Key::RESET)); 75 T::regs().kr().write(|w| w.set_key(Key::RESET));
73 } 76 }
@@ -79,6 +82,7 @@ mod sealed {
79 } 82 }
80} 83}
81 84
85/// IWDG instance trait.
82pub trait Instance: sealed::Instance {} 86pub trait Instance: sealed::Instance {}
83 87
84foreach_peripheral!( 88foreach_peripheral!(
diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
index 52cc665c7..39f5d3421 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
@@ -110,7 +110,7 @@ async fn main(_spawner: Spawner) {
110 &mut dp.DMA1_CH2, 110 &mut dp.DMA1_CH2,
111 5, 111 5,
112 color_list[color_list_index], 112 color_list[color_list_index],
113 pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, 113 pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _,
114 dma_transfer_option, 114 dma_transfer_option,
115 ) 115 )
116 .await; 116 .await;
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index e0be495d1..394ed3281 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -85,7 +85,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
85 85
86 let mut this = Self { inner: tim }; 86 let mut this = Self { inner: tim };
87 87
88 this.set_freq(freq); 88 this.set_frequency(freq);
89 this.inner.start(); 89 this.inner.start();
90 90
91 let r = T::regs_gp32(); 91 let r = T::regs_gp32();
@@ -102,14 +102,14 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
102 } 102 }
103 103
104 pub fn enable(&mut self, channel: Channel) { 104 pub fn enable(&mut self, channel: Channel) {
105 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); 105 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true));
106 } 106 }
107 107
108 pub fn disable(&mut self, channel: Channel) { 108 pub fn disable(&mut self, channel: Channel) {
109 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); 109 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false));
110 } 110 }
111 111
112 pub fn set_freq(&mut self, freq: Hertz) { 112 pub fn set_frequency(&mut self, freq: Hertz) {
113 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); 113 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
114 } 114 }
115 115
@@ -119,6 +119,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
119 119
120 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 120 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
121 defmt::assert!(duty < self.get_max_duty()); 121 defmt::assert!(duty < self.get_max_duty());
122 T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) 122 T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty))
123 } 123 }
124} 124}