aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorsodo <[email protected]>2024-01-02 01:37:00 +0900
committersodo <[email protected]>2024-01-02 13:34:22 +0900
commit6ee153a3e2eec284c0d9d87f31801265c0604f74 (patch)
tree8b801cbd15f9ad5052d5942c731e75736dc9d7eb /embassy-stm32/src
parentb7cd7952c890f585ff876c622482534e5d58d4a4 (diff)
parent0be9b0599aaf2e425d76ec7852ff4b3535defddf (diff)
Merge remote-tracking branch 'origin'
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/adc/mod.rs8
-rw-r--r--embassy-stm32/src/adc/resolution.rs7
-rw-r--r--embassy-stm32/src/adc/v4.rs11
-rw-r--r--embassy-stm32/src/can/bxcan.rs118
-rw-r--r--embassy-stm32/src/can/fdcan.rs15
-rw-r--r--embassy-stm32/src/can/mod.rs1
-rw-r--r--embassy-stm32/src/crc/mod.rs1
-rw-r--r--embassy-stm32/src/crc/v1.rs4
-rw-r--r--embassy-stm32/src/crc/v2v3.rs13
-rw-r--r--embassy-stm32/src/dac/mod.rs23
-rw-r--r--embassy-stm32/src/dac/tsel.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs25
-rw-r--r--embassy-stm32/src/dma/bdma.rs86
-rw-r--r--embassy-stm32/src/dma/dma.rs110
-rw-r--r--embassy-stm32/src/dma/dmamux.rs4
-rw-r--r--embassy-stm32/src/dma/gpdma.rs18
-rw-r--r--embassy-stm32/src/dma/mod.rs9
-rw-r--r--embassy-stm32/src/dma/word.rs10
-rw-r--r--embassy-stm32/src/eth/generic_smi.rs1
-rw-r--r--embassy-stm32/src/eth/mod.rs26
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs3
-rw-r--r--embassy-stm32/src/exti.rs65
-rw-r--r--embassy-stm32/src/flash/asynch.rs19
-rw-r--r--embassy-stm32/src/flash/common.rs33
-rw-r--r--embassy-stm32/src/flash/f0.rs6
-rw-r--r--embassy-stm32/src/flash/f3.rs6
-rw-r--r--embassy-stm32/src/flash/f4.rs4
-rw-r--r--embassy-stm32/src/flash/f7.rs6
-rw-r--r--embassy-stm32/src/flash/g.rs (renamed from embassy-stm32/src/flash/g0.rs)6
-rw-r--r--embassy-stm32/src/flash/h7.rs6
-rw-r--r--embassy-stm32/src/flash/l.rs6
-rw-r--r--embassy-stm32/src/flash/mod.rs69
-rw-r--r--embassy-stm32/src/flash/other.rs4
-rw-r--r--embassy-stm32/src/fmc.rs5
-rw-r--r--embassy-stm32/src/gpio.rs177
-rw-r--r--embassy-stm32/src/hrtim/mod.rs77
-rw-r--r--embassy-stm32/src/hrtim/traits.rs6
-rw-r--r--embassy-stm32/src/i2c/mod.rs170
-rw-r--r--embassy-stm32/src/i2c/v1.rs171
-rw-r--r--embassy-stm32/src/i2c/v2.rs460
-rw-r--r--embassy-stm32/src/i2s.rs36
-rw-r--r--embassy-stm32/src/ipcc.rs8
-rw-r--r--embassy-stm32/src/lib.rs76
-rw-r--r--embassy-stm32/src/low_power.rs107
-rw-r--r--embassy-stm32/src/opamp.rs9
-rw-r--r--embassy-stm32/src/qspi/enums.rs43
-rw-r--r--embassy-stm32/src/qspi/mod.rs19
-rw-r--r--embassy-stm32/src/rcc/h.rs44
-rw-r--r--embassy-stm32/src/rcc/mod.rs3
-rw-r--r--embassy-stm32/src/rng.rs17
-rw-r--r--embassy-stm32/src/rtc/datetime.rs12
-rw-r--r--embassy-stm32/src/rtc/mod.rs37
-rw-r--r--embassy-stm32/src/rtc/v2.rs8
-rw-r--r--embassy-stm32/src/rtc/v3.rs14
-rw-r--r--embassy-stm32/src/sai/mod.rs540
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs92
-rw-r--r--embassy-stm32/src/spi/mod.rs49
-rw-r--r--embassy-stm32/src/time.rs3
-rw-r--r--embassy-stm32/src/time_driver.rs40
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs33
-rw-r--r--embassy-stm32/src/timer/mod.rs163
-rw-r--r--embassy-stm32/src/timer/qei.rs25
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs47
-rw-r--r--embassy-stm32/src/traits.rs30
-rw-r--r--embassy-stm32/src/uid.rs2
-rw-r--r--embassy-stm32/src/usart/buffered.rs12
-rw-r--r--embassy-stm32/src/usart/mod.rs73
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs9
-rw-r--r--embassy-stm32/src/usb/mod.rs4
-rw-r--r--embassy-stm32/src/usb/usb.rs13
-rw-r--r--embassy-stm32/src/usb_otg/mod.rs4
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs13
-rw-r--r--embassy-stm32/src/wdg/mod.rs5
74 files changed, 2032 insertions, 1351 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index dbe53c807..e4dd35c34 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,4 +1,7 @@
1//! Analog to Digital Converter (ADC)
2
1#![macro_use] 3#![macro_use]
4#![allow(missing_docs)] // TODO
2 5
3#[cfg(not(adc_f3_v2))] 6#[cfg(not(adc_f3_v2))]
4#[cfg_attr(adc_f1, path = "f1.rs")] 7#[cfg_attr(adc_f1, path = "f1.rs")]
@@ -24,6 +27,7 @@ pub use sample_time::SampleTime;
24 27
25use crate::peripherals; 28use crate::peripherals;
26 29
30/// Analog to Digital driver.
27pub struct Adc<'d, T: Instance> { 31pub struct Adc<'d, T: Instance> {
28 #[allow(unused)] 32 #[allow(unused)]
29 adc: crate::PeripheralRef<'d, T>, 33 adc: crate::PeripheralRef<'d, T>,
@@ -75,12 +79,16 @@ pub(crate) mod sealed {
75 } 79 }
76} 80}
77 81
82/// ADC instance.
78#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] 83#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))]
79pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} 84pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
85/// ADC instance.
80#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] 86#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))]
81pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} 87pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
82 88
89/// ADC pin.
83pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 90pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
91/// ADC internal channel.
84pub trait InternalChannel<T>: sealed::InternalChannel<T> {} 92pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
85 93
86foreach_adc!( 94foreach_adc!(
diff --git a/embassy-stm32/src/adc/resolution.rs b/embassy-stm32/src/adc/resolution.rs
index 383980b5a..64c25a776 100644
--- a/embassy-stm32/src/adc/resolution.rs
+++ b/embassy-stm32/src/adc/resolution.rs
@@ -1,3 +1,5 @@
1/// ADC resolution
2#[allow(missing_docs)]
1#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))] 3#[cfg(any(adc_v1, adc_v2, adc_v3, adc_g0, adc_f3, adc_f3_v1_1))]
2#[derive(Clone, Copy, Debug, Eq, PartialEq)] 4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -8,6 +10,8 @@ pub enum Resolution {
8 SixBit, 10 SixBit,
9} 11}
10 12
13/// ADC resolution
14#[allow(missing_docs)]
11#[cfg(adc_v4)] 15#[cfg(adc_v4)]
12#[derive(Clone, Copy, Debug, Eq, PartialEq)] 16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -49,6 +53,9 @@ impl From<Resolution> for crate::pac::adc::vals::Res {
49} 53}
50 54
51impl Resolution { 55impl Resolution {
56 /// Get the maximum reading value for this resolution.
57 ///
58 /// This is `2**n - 1`.
52 pub fn to_max_count(&self) -> u32 { 59 pub fn to_max_count(&self) -> u32 {
53 match self { 60 match self {
54 #[cfg(adc_v4)] 61 #[cfg(adc_v4)]
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index d74617cb3..048e73184 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -32,6 +32,7 @@ const TEMP_CHANNEL: u8 = 18;
32const VBAT_CHANNEL: u8 = 17; 32const VBAT_CHANNEL: u8 = 17;
33 33
34// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 34// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
35/// Internal voltage reference channel.
35pub struct VrefInt; 36pub struct VrefInt;
36impl<T: Instance> InternalChannel<T> for VrefInt {} 37impl<T: Instance> InternalChannel<T> for VrefInt {}
37impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { 38impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
@@ -40,6 +41,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt {
40 } 41 }
41} 42}
42 43
44/// Internal temperature channel.
43pub struct Temperature; 45pub struct Temperature;
44impl<T: Instance> InternalChannel<T> for Temperature {} 46impl<T: Instance> InternalChannel<T> for Temperature {}
45impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { 47impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
@@ -48,6 +50,7 @@ impl<T: Instance> super::sealed::InternalChannel<T> for Temperature {
48 } 50 }
49} 51}
50 52
53/// Internal battery voltage channel.
51pub struct Vbat; 54pub struct Vbat;
52impl<T: Instance> InternalChannel<T> for Vbat {} 55impl<T: Instance> InternalChannel<T> for Vbat {}
53impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { 56impl<T: Instance> super::sealed::InternalChannel<T> for Vbat {
@@ -125,6 +128,7 @@ impl Prescaler {
125} 128}
126 129
127impl<'d, T: Instance> Adc<'d, T> { 130impl<'d, T: Instance> Adc<'d, T> {
131 /// Create a new ADC driver.
128 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { 132 pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
129 embassy_hal_internal::into_ref!(adc); 133 embassy_hal_internal::into_ref!(adc);
130 T::enable_and_reset(); 134 T::enable_and_reset();
@@ -212,6 +216,7 @@ impl<'d, T: Instance> Adc<'d, T> {
212 }); 216 });
213 } 217 }
214 218
219 /// Enable reading the voltage reference internal channel.
215 pub fn enable_vrefint(&self) -> VrefInt { 220 pub fn enable_vrefint(&self) -> VrefInt {
216 T::common_regs().ccr().modify(|reg| { 221 T::common_regs().ccr().modify(|reg| {
217 reg.set_vrefen(true); 222 reg.set_vrefen(true);
@@ -220,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> {
220 VrefInt {} 225 VrefInt {}
221 } 226 }
222 227
228 /// Enable reading the temperature internal channel.
223 pub fn enable_temperature(&self) -> Temperature { 229 pub fn enable_temperature(&self) -> Temperature {
224 T::common_regs().ccr().modify(|reg| { 230 T::common_regs().ccr().modify(|reg| {
225 reg.set_vsenseen(true); 231 reg.set_vsenseen(true);
@@ -228,6 +234,7 @@ impl<'d, T: Instance> Adc<'d, T> {
228 Temperature {} 234 Temperature {}
229 } 235 }
230 236
237 /// Enable reading the vbat internal channel.
231 pub fn enable_vbat(&self) -> Vbat { 238 pub fn enable_vbat(&self) -> Vbat {
232 T::common_regs().ccr().modify(|reg| { 239 T::common_regs().ccr().modify(|reg| {
233 reg.set_vbaten(true); 240 reg.set_vbaten(true);
@@ -236,10 +243,12 @@ impl<'d, T: Instance> Adc<'d, T> {
236 Vbat {} 243 Vbat {}
237 } 244 }
238 245
246 /// Set the ADC sample time.
239 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 247 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
240 self.sample_time = sample_time; 248 self.sample_time = sample_time;
241 } 249 }
242 250
251 /// Set the ADC resolution.
243 pub fn set_resolution(&mut self, resolution: Resolution) { 252 pub fn set_resolution(&mut self, resolution: Resolution) {
244 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 253 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
245 } 254 }
@@ -263,6 +272,7 @@ impl<'d, T: Instance> Adc<'d, T> {
263 T::regs().dr().read().0 as u16 272 T::regs().dr().read().0 as u16
264 } 273 }
265 274
275 /// Read an ADC pin.
266 pub fn read<P>(&mut self, pin: &mut P) -> u16 276 pub fn read<P>(&mut self, pin: &mut P) -> u16
267 where 277 where
268 P: AdcPin<T>, 278 P: AdcPin<T>,
@@ -273,6 +283,7 @@ impl<'d, T: Instance> Adc<'d, T> {
273 self.read_channel(pin.channel()) 283 self.read_channel(pin.channel())
274 } 284 }
275 285
286 /// Read an ADC internal channel.
276 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { 287 pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
277 self.read_channel(channel.channel()) 288 self.read_channel(channel.channel())
278 } 289 }
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 2f7417340..cc87b2565 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -1,3 +1,4 @@
1use core::convert::AsMut;
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut}; 4use core::ops::{Deref, DerefMut};
@@ -10,7 +11,7 @@ use futures::FutureExt;
10 11
11use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
12use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
13use crate::pac::can::vals::{Lec, RirIde}; 14use crate::pac::can::vals::{Ide, Lec};
14use crate::rcc::RccPeripheral; 15use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 16use crate::time::Hertz;
16use crate::{interrupt, peripherals, Peripheral}; 17use crate::{interrupt, peripherals, Peripheral};
@@ -21,8 +22,10 @@ use crate::{interrupt, peripherals, Peripheral};
21#[derive(Debug, Clone, PartialEq, Eq)] 22#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))] 23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub struct Envelope { 24pub struct Envelope {
25 /// Reception time.
24 #[cfg(feature = "time")] 26 #[cfg(feature = "time")]
25 pub ts: embassy_time::Instant, 27 pub ts: embassy_time::Instant,
28 /// The actual CAN frame.
26 pub frame: bxcan::Frame, 29 pub frame: bxcan::Frame,
27} 30}
28 31
@@ -43,6 +46,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH
43 } 46 }
44} 47}
45 48
49/// RX0 interrupt handler.
46pub struct Rx0InterruptHandler<T: Instance> { 50pub struct Rx0InterruptHandler<T: Instance> {
47 _phantom: PhantomData<T>, 51 _phantom: PhantomData<T>,
48} 52}
@@ -54,6 +58,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0Interrup
54 } 58 }
55} 59}
56 60
61/// RX1 interrupt handler.
57pub struct Rx1InterruptHandler<T: Instance> { 62pub struct Rx1InterruptHandler<T: Instance> {
58 _phantom: PhantomData<T>, 63 _phantom: PhantomData<T>,
59} 64}
@@ -65,6 +70,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1Interrup
65 } 70 }
66} 71}
67 72
73/// SCE interrupt handler.
68pub struct SceInterruptHandler<T: Instance> { 74pub struct SceInterruptHandler<T: Instance> {
69 _phantom: PhantomData<T>, 75 _phantom: PhantomData<T>,
70} 76}
@@ -82,10 +88,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
82 } 88 }
83} 89}
84 90
91/// CAN driver
85pub struct Can<'d, T: Instance> { 92pub struct Can<'d, T: Instance> {
86 pub can: bxcan::Can<BxcanInstance<'d, T>>, 93 can: bxcan::Can<BxcanInstance<'d, T>>,
87} 94}
88 95
96/// CAN bus error
97#[allow(missing_docs)]
89#[derive(Debug)] 98#[derive(Debug)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))] 99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91pub enum BusError { 100pub enum BusError {
@@ -101,6 +110,7 @@ pub enum BusError {
101 BusWarning, 110 BusWarning,
102} 111}
103 112
113/// Error returned by `try_read`
104#[derive(Debug)] 114#[derive(Debug)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))] 115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub enum TryReadError { 116pub enum TryReadError {
@@ -110,6 +120,7 @@ pub enum TryReadError {
110 Empty, 120 Empty,
111} 121}
112 122
123/// Error returned by `try_write`
113#[derive(Debug)] 124#[derive(Debug)]
114#[cfg_attr(feature = "defmt", derive(defmt::Format))] 125#[cfg_attr(feature = "defmt", derive(defmt::Format))]
115pub enum TryWriteError { 126pub enum TryWriteError {
@@ -138,15 +149,11 @@ impl<'d, T: Instance> Can<'d, T> {
138 T::enable_and_reset(); 149 T::enable_and_reset();
139 150
140 { 151 {
141 use crate::pac::can::vals::{Errie, Fmpie, Tmeie};
142
143 T::regs().ier().write(|w| { 152 T::regs().ier().write(|w| {
144 // TODO: fix metapac 153 w.set_errie(true);
145 154 w.set_fmpie(0, true);
146 w.set_errie(Errie::from_bits(1)); 155 w.set_fmpie(1, true);
147 w.set_fmpie(0, Fmpie::from_bits(1)); 156 w.set_tmeie(true);
148 w.set_fmpie(1, Fmpie::from_bits(1));
149 w.set_tmeie(Tmeie::from_bits(1));
150 }); 157 });
151 158
152 T::regs().mcr().write(|w| { 159 T::regs().mcr().write(|w| {
@@ -177,6 +184,7 @@ impl<'d, T: Instance> Can<'d, T> {
177 Self { can } 184 Self { can }
178 } 185 }
179 186
187 /// Set CAN bit rate.
180 pub fn set_bitrate(&mut self, bitrate: u32) { 188 pub fn set_bitrate(&mut self, bitrate: u32) {
181 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); 189 let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
182 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); 190 self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
@@ -194,7 +202,9 @@ impl<'d, T: Instance> Can<'d, T> {
194 } 202 }
195 } 203 }
196 204
197 /// Queues the message to be sent but exerts backpressure 205 /// Queues the message to be sent.
206 ///
207 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
198 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { 208 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
199 self.split().0.write(frame).await 209 self.split().0.write(frame).await
200 } 210 }
@@ -221,12 +231,16 @@ impl<'d, T: Instance> Can<'d, T> {
221 CanTx::<T>::flush_all_inner().await 231 CanTx::<T>::flush_all_inner().await
222 } 232 }
223 233
234 /// Read a CAN frame.
235 ///
236 /// If no CAN frame is in the RX buffer, this will wait until there is one.
237 ///
224 /// Returns a tuple of the time the message was received and the message frame 238 /// Returns a tuple of the time the message was received and the message frame
225 pub async fn read(&mut self) -> Result<Envelope, BusError> { 239 pub async fn read(&mut self) -> Result<Envelope, BusError> {
226 self.split().1.read().await 240 self.split().1.read().await
227 } 241 }
228 242
229 /// Attempts to read a can frame without blocking. 243 /// Attempts to read a CAN frame without blocking.
230 /// 244 ///
231 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. 245 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
232 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { 246 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
@@ -259,7 +273,7 @@ impl<'d, T: Instance> Can<'d, T> {
259 } 273 }
260 274
261 let rir = fifo.rir().read(); 275 let rir = fifo.rir().read();
262 let id = if rir.ide() == RirIde::STANDARD { 276 let id = if rir.ide() == Ide::STANDARD {
263 Id::from(StandardId::new_unchecked(rir.stid())) 277 Id::from(StandardId::new_unchecked(rir.stid()))
264 } else { 278 } else {
265 let stid = (rir.stid() & 0x7FF) as u32; 279 let stid = (rir.stid() & 0x7FF) as u32;
@@ -288,7 +302,7 @@ impl<'d, T: Instance> Can<'d, T> {
288 } 302 }
289 } 303 }
290 304
291 pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { 305 const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
292 const BS1_MAX: u8 = 16; 306 const BS1_MAX: u8 = 16;
293 const BS2_MAX: u8 = 8; 307 const BS2_MAX: u8 = 8;
294 const MAX_SAMPLE_POINT_PERMILL: u16 = 900; 308 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
@@ -379,21 +393,31 @@ impl<'d, T: Instance> Can<'d, T> {
379 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) 393 Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
380 } 394 }
381 395
396 /// Split the CAN driver into transmit and receive halves.
397 ///
398 /// Useful for doing separate transmit/receive tasks.
382 pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { 399 pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
383 let (tx, rx0, rx1) = self.can.split_by_ref(); 400 let (tx, rx0, rx1) = self.can.split_by_ref();
384 (CanTx { tx }, CanRx { rx0, rx1 }) 401 (CanTx { tx }, CanRx { rx0, rx1 })
385 } 402 }
403}
386 404
387 pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { 405impl<'d, T: Instance> AsMut<bxcan::Can<BxcanInstance<'d, T>>> for Can<'d, T> {
406 /// Get mutable access to the lower-level driver from the `bxcan` crate.
407 fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> {
388 &mut self.can 408 &mut self.can
389 } 409 }
390} 410}
391 411
412/// CAN driver, transmit half.
392pub struct CanTx<'c, 'd, T: Instance> { 413pub struct CanTx<'c, 'd, T: Instance> {
393 tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, 414 tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>,
394} 415}
395 416
396impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { 417impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
418 /// Queues the message to be sent.
419 ///
420 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
397 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { 421 pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
398 poll_fn(|cx| { 422 poll_fn(|cx| {
399 T::state().tx_waker.register(cx.waker()); 423 T::state().tx_waker.register(cx.waker());
@@ -475,6 +499,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
475 } 499 }
476} 500}
477 501
502/// CAN driver, receive half.
478#[allow(dead_code)] 503#[allow(dead_code)]
479pub struct CanRx<'c, 'd, T: Instance> { 504pub struct CanRx<'c, 'd, T: Instance> {
480 rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, 505 rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>,
@@ -482,6 +507,11 @@ pub struct CanRx<'c, 'd, T: Instance> {
482} 507}
483 508
484impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { 509impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
510 /// Read a CAN frame.
511 ///
512 /// If no CAN frame is in the RX buffer, this will wait until there is one.
513 ///
514 /// Returns a tuple of the time the message was received and the message frame
485 pub async fn read(&mut self) -> Result<Envelope, BusError> { 515 pub async fn read(&mut self) -> Result<Envelope, BusError> {
486 poll_fn(|cx| { 516 poll_fn(|cx| {
487 T::state().err_waker.register(cx.waker()); 517 T::state().err_waker.register(cx.waker());
@@ -585,30 +615,24 @@ pub(crate) mod sealed {
585 pub trait Instance { 615 pub trait Instance {
586 const REGISTERS: *mut bxcan::RegisterBlock; 616 const REGISTERS: *mut bxcan::RegisterBlock;
587 617
588 fn regs() -> &'static crate::pac::can::Can; 618 fn regs() -> crate::pac::can::Can;
589 fn state() -> &'static State; 619 fn state() -> &'static State;
590 } 620 }
591} 621}
592 622
593pub trait TXInstance { 623/// CAN instance trait.
624pub trait Instance: sealed::Instance + RccPeripheral + 'static {
625 /// TX interrupt for this instance.
594 type TXInterrupt: crate::interrupt::typelevel::Interrupt; 626 type TXInterrupt: crate::interrupt::typelevel::Interrupt;
595} 627 /// RX0 interrupt for this instance.
596
597pub trait RX0Instance {
598 type RX0Interrupt: crate::interrupt::typelevel::Interrupt; 628 type RX0Interrupt: crate::interrupt::typelevel::Interrupt;
599} 629 /// RX1 interrupt for this instance.
600
601pub trait RX1Instance {
602 type RX1Interrupt: crate::interrupt::typelevel::Interrupt; 630 type RX1Interrupt: crate::interrupt::typelevel::Interrupt;
603} 631 /// SCE interrupt for this instance.
604
605pub trait SCEInstance {
606 type SCEInterrupt: crate::interrupt::typelevel::Interrupt; 632 type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
607} 633}
608 634
609pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {} 635/// BXCAN instance newtype.
610pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
611
612pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); 636pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
613 637
614unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { 638unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
@@ -620,8 +644,8 @@ foreach_peripheral!(
620 impl sealed::Instance for peripherals::$inst { 644 impl sealed::Instance for peripherals::$inst {
621 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; 645 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
622 646
623 fn regs() -> &'static crate::pac::can::Can { 647 fn regs() -> crate::pac::can::Can {
624 &crate::pac::$inst 648 crate::pac::$inst
625 } 649 }
626 650
627 fn state() -> &'static sealed::State { 651 fn state() -> &'static sealed::State {
@@ -630,32 +654,12 @@ foreach_peripheral!(
630 } 654 }
631 } 655 }
632 656
633 impl Instance for peripherals::$inst {} 657 impl Instance for peripherals::$inst {
634 658 type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX;
635 foreach_interrupt!( 659 type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0;
636 ($inst,can,CAN,TX,$irq:ident) => { 660 type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1;
637 impl TXInstance for peripherals::$inst { 661 type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE;
638 type TXInterrupt = crate::interrupt::typelevel::$irq; 662 }
639 }
640 };
641 ($inst,can,CAN,RX0,$irq:ident) => {
642 impl RX0Instance for peripherals::$inst {
643 type RX0Interrupt = crate::interrupt::typelevel::$irq;
644 }
645 };
646 ($inst,can,CAN,RX1,$irq:ident) => {
647 impl RX1Instance for peripherals::$inst {
648 type RX1Interrupt = crate::interrupt::typelevel::$irq;
649 }
650 };
651 ($inst,can,CAN,SCE,$irq:ident) => {
652 impl SCEInstance for peripherals::$inst {
653 type SCEInterrupt = crate::interrupt::typelevel::$irq;
654 }
655 };
656 );
657
658 impl InterruptableInstance for peripherals::$inst {}
659 }; 663 };
660); 664);
661 665
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index f77788db3..0cc2559cf 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -1,6 +1,3 @@
1pub use bxcan;
2use embassy_hal_internal::PeripheralRef;
3
4use crate::peripherals; 1use crate::peripherals;
5 2
6pub(crate) mod sealed { 3pub(crate) mod sealed {
@@ -25,27 +22,19 @@ pub(crate) mod sealed {
25 } 22 }
26 23
27 pub trait Instance { 24 pub trait Instance {
28 const REGISTERS: *mut bxcan::RegisterBlock;
29
30 fn regs() -> &'static crate::pac::can::Fdcan; 25 fn regs() -> &'static crate::pac::can::Fdcan;
31 fn state() -> &'static State; 26 fn state() -> &'static State;
32 } 27 }
33} 28}
34 29
30/// Interruptable FDCAN instance.
35pub trait InterruptableInstance {} 31pub trait InterruptableInstance {}
32/// FDCAN instance.
36pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} 33pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
37 34
38pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
39
40unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
41 const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS;
42}
43
44foreach_peripheral!( 35foreach_peripheral!(
45 (can, $inst:ident) => { 36 (can, $inst:ident) => {
46 impl sealed::Instance for peripherals::$inst { 37 impl sealed::Instance for peripherals::$inst {
47 const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
48
49 fn regs() -> &'static crate::pac::can::Fdcan { 38 fn regs() -> &'static crate::pac::can::Fdcan {
50 &crate::pac::$inst 39 &crate::pac::$inst
51 } 40 }
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs
index 425f9ac2e..915edb3a6 100644
--- a/embassy-stm32/src/can/mod.rs
+++ b/embassy-stm32/src/can/mod.rs
@@ -1,3 +1,4 @@
1//! Controller Area Network (CAN)
1#![macro_use] 2#![macro_use]
2 3
3#[cfg_attr(can_bxcan, path = "bxcan.rs")] 4#[cfg_attr(can_bxcan, path = "bxcan.rs")]
diff --git a/embassy-stm32/src/crc/mod.rs b/embassy-stm32/src/crc/mod.rs
index 63f7ad9ba..29523b92d 100644
--- a/embassy-stm32/src/crc/mod.rs
+++ b/embassy-stm32/src/crc/mod.rs
@@ -1,3 +1,4 @@
1//! Cyclic Redundancy Check (CRC)
1#[cfg_attr(crc_v1, path = "v1.rs")] 2#[cfg_attr(crc_v1, path = "v1.rs")]
2#[cfg_attr(crc_v2, path = "v2v3.rs")] 3#[cfg_attr(crc_v2, path = "v2v3.rs")]
3#[cfg_attr(crc_v3, path = "v2v3.rs")] 4#[cfg_attr(crc_v3, path = "v2v3.rs")]
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index c0f580830..0166ab819 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -5,6 +5,7 @@ use crate::peripherals::CRC;
5use crate::rcc::sealed::RccPeripheral; 5use crate::rcc::sealed::RccPeripheral;
6use crate::Peripheral; 6use crate::Peripheral;
7 7
8/// CRC driver.
8pub struct Crc<'d> { 9pub struct Crc<'d> {
9 _peri: PeripheralRef<'d, CRC>, 10 _peri: PeripheralRef<'d, CRC>,
10} 11}
@@ -34,6 +35,7 @@ impl<'d> Crc<'d> {
34 PAC_CRC.dr().write_value(word); 35 PAC_CRC.dr().write_value(word);
35 self.read() 36 self.read()
36 } 37 }
38
37 /// Feed a slice of words to the peripheral and return the result. 39 /// Feed a slice of words to the peripheral and return the result.
38 pub fn feed_words(&mut self, words: &[u32]) -> u32 { 40 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
39 for word in words { 41 for word in words {
@@ -42,6 +44,8 @@ impl<'d> Crc<'d> {
42 44
43 self.read() 45 self.read()
44 } 46 }
47
48 /// Read the CRC result value.
45 pub fn read(&self) -> u32 { 49 pub fn read(&self) -> u32 {
46 PAC_CRC.dr().read() 50 PAC_CRC.dr().read()
47 } 51 }
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index b36f6018c..0c4ae55ce 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -6,15 +6,19 @@ use crate::peripherals::CRC;
6use crate::rcc::sealed::RccPeripheral; 6use crate::rcc::sealed::RccPeripheral;
7use crate::Peripheral; 7use crate::Peripheral;
8 8
9/// CRC driver.
9pub struct Crc<'d> { 10pub struct Crc<'d> {
10 _peripheral: PeripheralRef<'d, CRC>, 11 _peripheral: PeripheralRef<'d, CRC>,
11 _config: Config, 12 _config: Config,
12} 13}
13 14
15/// CRC configuration errlr
14pub enum ConfigError { 16pub enum ConfigError {
17 /// The selected polynomial is invalid.
15 InvalidPolynomial, 18 InvalidPolynomial,
16} 19}
17 20
21/// CRC configuration
18pub struct Config { 22pub struct Config {
19 reverse_in: InputReverseConfig, 23 reverse_in: InputReverseConfig,
20 reverse_out: bool, 24 reverse_out: bool,
@@ -25,14 +29,20 @@ pub struct Config {
25 crc_poly: u32, 29 crc_poly: u32,
26} 30}
27 31
32/// Input reverse configuration.
28pub enum InputReverseConfig { 33pub enum InputReverseConfig {
34 /// Don't reverse anything
29 None, 35 None,
36 /// Reverse bytes
30 Byte, 37 Byte,
38 /// Reverse 16-bit halfwords.
31 Halfword, 39 Halfword,
40 /// Reverse 32-bit words.
32 Word, 41 Word,
33} 42}
34 43
35impl Config { 44impl Config {
45 /// Create a new CRC config.
36 pub fn new( 46 pub fn new(
37 reverse_in: InputReverseConfig, 47 reverse_in: InputReverseConfig,
38 reverse_out: bool, 48 reverse_out: bool,
@@ -57,7 +67,9 @@ impl Config {
57 } 67 }
58} 68}
59 69
70/// Polynomial size
60#[cfg(crc_v3)] 71#[cfg(crc_v3)]
72#[allow(missing_docs)]
61pub enum PolySize { 73pub enum PolySize {
62 Width7, 74 Width7,
63 Width8, 75 Width8,
@@ -81,6 +93,7 @@ impl<'d> Crc<'d> {
81 instance 93 instance
82 } 94 }
83 95
96 /// Reset the CRC engine.
84 pub fn reset(&mut self) { 97 pub fn reset(&mut self) {
85 PAC_CRC.cr().modify(|w| w.set_reset(true)); 98 PAC_CRC.cr().modify(|w| w.set_reset(true));
86 } 99 }
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 500eac4c1..31dedf06e 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -1,4 +1,4 @@
1//! Provide access to the STM32 digital-to-analog converter (DAC). 1//! Digital to Analog Converter (DAC)
2#![macro_use] 2#![macro_use]
3 3
4use core::marker::PhantomData; 4use core::marker::PhantomData;
@@ -62,11 +62,11 @@ impl Mode {
62/// 62///
63/// 12-bit values outside the permitted range are silently truncated. 63/// 12-bit values outside the permitted range are silently truncated.
64pub enum Value { 64pub enum Value {
65 // 8 bit value 65 /// 8 bit value
66 Bit8(u8), 66 Bit8(u8),
67 // 12 bit value stored in a u16, left-aligned 67 /// 12 bit value stored in a u16, left-aligned
68 Bit12Left(u16), 68 Bit12Left(u16),
69 // 12 bit value stored in a u16, right-aligned 69 /// 12 bit value stored in a u16, right-aligned
70 Bit12Right(u16), 70 Bit12Right(u16),
71} 71}
72 72
@@ -76,11 +76,11 @@ pub enum Value {
76/// 76///
77/// 12-bit values outside the permitted range are silently truncated. 77/// 12-bit values outside the permitted range are silently truncated.
78pub enum DualValue { 78pub enum DualValue {
79 // 8 bit value 79 /// 8 bit value
80 Bit8(u8, u8), 80 Bit8(u8, u8),
81 // 12 bit value stored in a u16, left-aligned 81 /// 12 bit value stored in a u16, left-aligned
82 Bit12Left(u16, u16), 82 Bit12Left(u16, u16),
83 // 12 bit value stored in a u16, right-aligned 83 /// 12 bit value stored in a u16, right-aligned
84 Bit12Right(u16, u16), 84 Bit12Right(u16, u16),
85} 85}
86 86
@@ -88,11 +88,11 @@ pub enum DualValue {
88#[cfg_attr(feature = "defmt", derive(defmt::Format))] 88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89/// Array variant of [`Value`]. 89/// Array variant of [`Value`].
90pub enum ValueArray<'a> { 90pub enum ValueArray<'a> {
91 // 8 bit values 91 /// 8 bit values
92 Bit8(&'a [u8]), 92 Bit8(&'a [u8]),
93 // 12 bit value stored in a u16, left-aligned 93 /// 12 bit value stored in a u16, left-aligned
94 Bit12Left(&'a [u16]), 94 Bit12Left(&'a [u16]),
95 // 12 bit values stored in a u16, right-aligned 95 /// 12 bit values stored in a u16, right-aligned
96 Bit12Right(&'a [u16]), 96 Bit12Right(&'a [u16]),
97} 97}
98 98
@@ -106,7 +106,9 @@ pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> {
106 dma: PeripheralRef<'d, DMA>, 106 dma: PeripheralRef<'d, DMA>,
107} 107}
108 108
109/// DAC channel 1 type alias.
109pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; 110pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>;
111/// DAC channel 2 type alias.
110pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; 112pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>;
111 113
112impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { 114impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
@@ -492,6 +494,7 @@ pub(crate) mod sealed {
492 } 494 }
493} 495}
494 496
497/// DAC instance.
495pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 498pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
496dma_trait!(DacDma1, Instance); 499dma_trait!(DacDma1, Instance);
497dma_trait!(DacDma2, Instance); 500dma_trait!(DacDma2, Instance);
diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs
index f38dd8fd7..22d8d3dfa 100644
--- a/embassy-stm32/src/dac/tsel.rs
+++ b/embassy-stm32/src/dac/tsel.rs
@@ -1,3 +1,5 @@
1#![allow(missing_docs)]
2
1/// Trigger selection for STM32F0. 3/// Trigger selection for STM32F0.
2#[cfg(stm32f0)] 4#[cfg(stm32f0)]
3#[derive(Debug, Copy, Clone, Eq, PartialEq)] 5#[derive(Debug, Copy, Clone, Eq, PartialEq)]
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index b12230794..4d02284b2 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -1,3 +1,4 @@
1//! Digital Camera Interface (DCMI)
1use core::future::poll_fn; 2use core::future::poll_fn;
2use core::marker::PhantomData; 3use core::marker::PhantomData;
3use core::task::Poll; 4use core::task::Poll;
@@ -36,6 +37,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
36} 37}
37 38
38/// The level on the VSync pin when the data is not valid on the parallel interface. 39/// The level on the VSync pin when the data is not valid on the parallel interface.
40#[allow(missing_docs)]
39#[derive(Clone, Copy, PartialEq)] 41#[derive(Clone, Copy, PartialEq)]
40pub enum VSyncDataInvalidLevel { 42pub enum VSyncDataInvalidLevel {
41 Low, 43 Low,
@@ -43,6 +45,7 @@ pub enum VSyncDataInvalidLevel {
43} 45}
44 46
45/// The level on the VSync pin when the data is not valid on the parallel interface. 47/// The level on the VSync pin when the data is not valid on the parallel interface.
48#[allow(missing_docs)]
46#[derive(Clone, Copy, PartialEq)] 49#[derive(Clone, Copy, PartialEq)]
47pub enum HSyncDataInvalidLevel { 50pub enum HSyncDataInvalidLevel {
48 Low, 51 Low,
@@ -50,14 +53,16 @@ pub enum HSyncDataInvalidLevel {
50} 53}
51 54
52#[derive(Clone, Copy, PartialEq)] 55#[derive(Clone, Copy, PartialEq)]
56#[allow(missing_docs)]
53pub enum PixelClockPolarity { 57pub enum PixelClockPolarity {
54 RisingEdge, 58 RisingEdge,
55 FallingEdge, 59 FallingEdge,
56} 60}
57 61
58pub struct State { 62struct State {
59 waker: AtomicWaker, 63 waker: AtomicWaker,
60} 64}
65
61impl State { 66impl State {
62 const fn new() -> State { 67 const fn new() -> State {
63 State { 68 State {
@@ -68,18 +73,25 @@ impl State {
68 73
69static STATE: State = State::new(); 74static STATE: State = State::new();
70 75
76/// DCMI error.
71#[derive(Debug, Eq, PartialEq, Copy, Clone)] 77#[derive(Debug, Eq, PartialEq, Copy, Clone)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))] 78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[non_exhaustive] 79#[non_exhaustive]
74pub enum Error { 80pub enum Error {
81 /// Overrun error: the hardware generated data faster than we could read it.
75 Overrun, 82 Overrun,
83 /// Internal peripheral error.
76 PeripheralError, 84 PeripheralError,
77} 85}
78 86
87/// DCMI configuration.
79#[non_exhaustive] 88#[non_exhaustive]
80pub struct Config { 89pub struct Config {
90 /// VSYNC level.
81 pub vsync_level: VSyncDataInvalidLevel, 91 pub vsync_level: VSyncDataInvalidLevel,
92 /// HSYNC level.
82 pub hsync_level: HSyncDataInvalidLevel, 93 pub hsync_level: HSyncDataInvalidLevel,
94 /// PIXCLK polarity.
83 pub pixclk_polarity: PixelClockPolarity, 95 pub pixclk_polarity: PixelClockPolarity,
84} 96}
85 97
@@ -105,6 +117,7 @@ macro_rules! config_pins {
105 }; 117 };
106} 118}
107 119
120/// DCMI driver.
108pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { 121pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> {
109 inner: PeripheralRef<'d, T>, 122 inner: PeripheralRef<'d, T>,
110 dma: PeripheralRef<'d, Dma>, 123 dma: PeripheralRef<'d, Dma>,
@@ -115,6 +128,7 @@ where
115 T: Instance, 128 T: Instance,
116 Dma: FrameDma<T>, 129 Dma: FrameDma<T>,
117{ 130{
131 /// Create a new DCMI driver with 8 data bits.
118 pub fn new_8bit( 132 pub fn new_8bit(
119 peri: impl Peripheral<P = T> + 'd, 133 peri: impl Peripheral<P = T> + 'd,
120 dma: impl Peripheral<P = Dma> + 'd, 134 dma: impl Peripheral<P = Dma> + 'd,
@@ -139,6 +153,7 @@ where
139 Self::new_inner(peri, dma, config, false, 0b00) 153 Self::new_inner(peri, dma, config, false, 0b00)
140 } 154 }
141 155
156 /// Create a new DCMI driver with 10 data bits.
142 pub fn new_10bit( 157 pub fn new_10bit(
143 peri: impl Peripheral<P = T> + 'd, 158 peri: impl Peripheral<P = T> + 'd,
144 dma: impl Peripheral<P = Dma> + 'd, 159 dma: impl Peripheral<P = Dma> + 'd,
@@ -165,6 +180,7 @@ where
165 Self::new_inner(peri, dma, config, false, 0b01) 180 Self::new_inner(peri, dma, config, false, 0b01)
166 } 181 }
167 182
183 /// Create a new DCMI driver with 12 data bits.
168 pub fn new_12bit( 184 pub fn new_12bit(
169 peri: impl Peripheral<P = T> + 'd, 185 peri: impl Peripheral<P = T> + 'd,
170 dma: impl Peripheral<P = Dma> + 'd, 186 dma: impl Peripheral<P = Dma> + 'd,
@@ -193,6 +209,7 @@ where
193 Self::new_inner(peri, dma, config, false, 0b10) 209 Self::new_inner(peri, dma, config, false, 0b10)
194 } 210 }
195 211
212 /// Create a new DCMI driver with 14 data bits.
196 pub fn new_14bit( 213 pub fn new_14bit(
197 peri: impl Peripheral<P = T> + 'd, 214 peri: impl Peripheral<P = T> + 'd,
198 dma: impl Peripheral<P = Dma> + 'd, 215 dma: impl Peripheral<P = Dma> + 'd,
@@ -223,6 +240,7 @@ where
223 Self::new_inner(peri, dma, config, false, 0b11) 240 Self::new_inner(peri, dma, config, false, 0b11)
224 } 241 }
225 242
243 /// Create a new DCMI driver with 8 data bits, with embedded synchronization.
226 pub fn new_es_8bit( 244 pub fn new_es_8bit(
227 peri: impl Peripheral<P = T> + 'd, 245 peri: impl Peripheral<P = T> + 'd,
228 dma: impl Peripheral<P = Dma> + 'd, 246 dma: impl Peripheral<P = Dma> + 'd,
@@ -245,6 +263,7 @@ where
245 Self::new_inner(peri, dma, config, true, 0b00) 263 Self::new_inner(peri, dma, config, true, 0b00)
246 } 264 }
247 265
266 /// Create a new DCMI driver with 10 data bits, with embedded synchronization.
248 pub fn new_es_10bit( 267 pub fn new_es_10bit(
249 peri: impl Peripheral<P = T> + 'd, 268 peri: impl Peripheral<P = T> + 'd,
250 dma: impl Peripheral<P = Dma> + 'd, 269 dma: impl Peripheral<P = Dma> + 'd,
@@ -269,6 +288,7 @@ where
269 Self::new_inner(peri, dma, config, true, 0b01) 288 Self::new_inner(peri, dma, config, true, 0b01)
270 } 289 }
271 290
291 /// Create a new DCMI driver with 12 data bits, with embedded synchronization.
272 pub fn new_es_12bit( 292 pub fn new_es_12bit(
273 peri: impl Peripheral<P = T> + 'd, 293 peri: impl Peripheral<P = T> + 'd,
274 dma: impl Peripheral<P = Dma> + 'd, 294 dma: impl Peripheral<P = Dma> + 'd,
@@ -295,6 +315,7 @@ where
295 Self::new_inner(peri, dma, config, true, 0b10) 315 Self::new_inner(peri, dma, config, true, 0b10)
296 } 316 }
297 317
318 /// Create a new DCMI driver with 14 data bits, with embedded synchronization.
298 pub fn new_es_14bit( 319 pub fn new_es_14bit(
299 peri: impl Peripheral<P = T> + 'd, 320 peri: impl Peripheral<P = T> + 'd,
300 dma: impl Peripheral<P = Dma> + 'd, 321 dma: impl Peripheral<P = Dma> + 'd,
@@ -538,7 +559,9 @@ mod sealed {
538 } 559 }
539} 560}
540 561
562/// DCMI instance.
541pub trait Instance: sealed::Instance + 'static { 563pub trait Instance: sealed::Instance + 'static {
564 /// Interrupt for this instance.
542 type Interrupt: interrupt::typelevel::Interrupt; 565 type Interrupt: interrupt::typelevel::Interrupt;
543} 566}
544 567
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a7422f66b..a2b83716d 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -1,4 +1,4 @@
1#![macro_use] 1//! Basic Direct Memory Acccess (BDMA)
2 2
3use core::future::Future; 3use core::future::Future;
4use core::pin::Pin; 4use core::pin::Pin;
@@ -17,11 +17,16 @@ use crate::interrupt::Priority;
17use crate::pac; 17use crate::pac;
18use crate::pac::bdma::{regs, vals}; 18use crate::pac::bdma::{regs, vals};
19 19
20/// BDMA transfer options.
20#[derive(Debug, Copy, Clone, PartialEq, Eq)] 21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))] 22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22#[non_exhaustive] 23#[non_exhaustive]
23pub struct TransferOptions { 24pub struct TransferOptions {
24 /// Enable circular DMA 25 /// Enable circular DMA
26 ///
27 /// Note:
28 /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
29 /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
25 pub circular: bool, 30 pub circular: bool,
26 /// Enable half transfer interrupt 31 /// Enable half transfer interrupt
27 pub half_transfer_ir: bool, 32 pub half_transfer_ir: bool,
@@ -140,13 +145,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
140 STATE.ch_wakers[index].wake(); 145 STATE.ch_wakers[index].wake();
141} 146}
142 147
148/// DMA request type alias.
143#[cfg(any(bdma_v2, dmamux))] 149#[cfg(any(bdma_v2, dmamux))]
144pub type Request = u8; 150pub type Request = u8;
151/// DMA request type alias.
145#[cfg(not(any(bdma_v2, dmamux)))] 152#[cfg(not(any(bdma_v2, dmamux)))]
146pub type Request = (); 153pub type Request = ();
147 154
155/// DMA channel.
148#[cfg(dmamux)] 156#[cfg(dmamux)]
149pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 157pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
158/// DMA channel.
150#[cfg(not(dmamux))] 159#[cfg(not(dmamux))]
151pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 160pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
152 161
@@ -161,12 +170,14 @@ pub(crate) mod sealed {
161 } 170 }
162} 171}
163 172
173/// DMA transfer.
164#[must_use = "futures do nothing unless you `.await` or poll them"] 174#[must_use = "futures do nothing unless you `.await` or poll them"]
165pub struct Transfer<'a, C: Channel> { 175pub struct Transfer<'a, C: Channel> {
166 channel: PeripheralRef<'a, C>, 176 channel: PeripheralRef<'a, C>,
167} 177}
168 178
169impl<'a, C: Channel> Transfer<'a, C> { 179impl<'a, C: Channel> Transfer<'a, C> {
180 /// Create a new read DMA transfer (peripheral to memory).
170 pub unsafe fn new_read<W: Word>( 181 pub unsafe fn new_read<W: Word>(
171 channel: impl Peripheral<P = C> + 'a, 182 channel: impl Peripheral<P = C> + 'a,
172 request: Request, 183 request: Request,
@@ -177,6 +188,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
177 Self::new_read_raw(channel, request, peri_addr, buf, options) 188 Self::new_read_raw(channel, request, peri_addr, buf, options)
178 } 189 }
179 190
191 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
180 pub unsafe fn new_read_raw<W: Word>( 192 pub unsafe fn new_read_raw<W: Word>(
181 channel: impl Peripheral<P = C> + 'a, 193 channel: impl Peripheral<P = C> + 'a,
182 request: Request, 194 request: Request,
@@ -202,6 +214,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
202 ) 214 )
203 } 215 }
204 216
217 /// Create a new write DMA transfer (memory to peripheral).
205 pub unsafe fn new_write<W: Word>( 218 pub unsafe fn new_write<W: Word>(
206 channel: impl Peripheral<P = C> + 'a, 219 channel: impl Peripheral<P = C> + 'a,
207 request: Request, 220 request: Request,
@@ -212,6 +225,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
212 Self::new_write_raw(channel, request, buf, peri_addr, options) 225 Self::new_write_raw(channel, request, buf, peri_addr, options)
213 } 226 }
214 227
228 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
215 pub unsafe fn new_write_raw<W: Word>( 229 pub unsafe fn new_write_raw<W: Word>(
216 channel: impl Peripheral<P = C> + 'a, 230 channel: impl Peripheral<P = C> + 'a,
217 request: Request, 231 request: Request,
@@ -237,6 +251,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
237 ) 251 )
238 } 252 }
239 253
254 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
240 pub unsafe fn new_write_repeated<W: Word>( 255 pub unsafe fn new_write_repeated<W: Word>(
241 channel: impl Peripheral<P = C> + 'a, 256 channel: impl Peripheral<P = C> + 'a,
242 request: Request, 257 request: Request,
@@ -292,20 +307,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
292 ch.cr().write(|w| { 307 ch.cr().write(|w| {
293 w.set_psize(data_size.into()); 308 w.set_psize(data_size.into());
294 w.set_msize(data_size.into()); 309 w.set_msize(data_size.into());
295 if incr_mem { 310 w.set_minc(incr_mem);
296 w.set_minc(vals::Inc::ENABLED);
297 } else {
298 w.set_minc(vals::Inc::DISABLED);
299 }
300 w.set_dir(dir.into()); 311 w.set_dir(dir.into());
301 w.set_teie(true); 312 w.set_teie(true);
302 w.set_tcie(options.complete_transfer_ir); 313 w.set_tcie(options.complete_transfer_ir);
303 w.set_htie(options.half_transfer_ir); 314 w.set_htie(options.half_transfer_ir);
315 w.set_circ(options.circular);
304 if options.circular { 316 if options.circular {
305 w.set_circ(vals::Circ::ENABLED);
306 debug!("Setting circular mode"); 317 debug!("Setting circular mode");
307 } else {
308 w.set_circ(vals::Circ::DISABLED);
309 } 318 }
310 w.set_pl(vals::Pl::VERYHIGH); 319 w.set_pl(vals::Pl::VERYHIGH);
311 w.set_en(true); 320 w.set_en(true);
@@ -321,6 +330,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
321 }); 330 });
322 } 331 }
323 332
333 /// Request the transfer to stop.
334 ///
335 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
324 pub fn request_stop(&mut self) { 336 pub fn request_stop(&mut self) {
325 let ch = self.channel.regs().ch(self.channel.num()); 337 let ch = self.channel.regs().ch(self.channel.num());
326 338
@@ -331,21 +343,27 @@ impl<'a, C: Channel> Transfer<'a, C> {
331 }); 343 });
332 } 344 }
333 345
346 /// Return whether this transfer is still running.
347 ///
348 /// If this returns `false`, it can be because either the transfer finished, or
349 /// it was requested to stop early with [`request_stop`](Self::request_stop).
334 pub fn is_running(&mut self) -> bool { 350 pub fn is_running(&mut self) -> bool {
335 let ch = self.channel.regs().ch(self.channel.num()); 351 let ch = self.channel.regs().ch(self.channel.num());
336 let en = ch.cr().read().en(); 352 let en = ch.cr().read().en();
337 let circular = ch.cr().read().circ() == vals::Circ::ENABLED; 353 let circular = ch.cr().read().circ();
338 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; 354 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
339 en && (circular || !tcif) 355 en && (circular || !tcif)
340 } 356 }
341 357
342 /// Gets the total remaining transfers for the channel 358 /// Get the total remaining transfers for the channel.
343 /// Note: this will be zero for transfers that completed without cancellation. 359 ///
360 /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop).
344 pub fn get_remaining_transfers(&self) -> u16 { 361 pub fn get_remaining_transfers(&self) -> u16 {
345 let ch = self.channel.regs().ch(self.channel.num()); 362 let ch = self.channel.regs().ch(self.channel.num());
346 ch.ndtr().read().ndt() 363 ch.ndtr().read().ndt()
347 } 364 }
348 365
366 /// Blocking wait until the transfer finishes.
349 pub fn blocking_wait(mut self) { 367 pub fn blocking_wait(mut self) {
350 while self.is_running() {} 368 while self.is_running() {}
351 self.request_stop(); 369 self.request_stop();
@@ -411,6 +429,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
411 } 429 }
412} 430}
413 431
432/// Ringbuffer for reading data using DMA circular mode.
414pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 433pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
415 cr: regs::Cr, 434 cr: regs::Cr,
416 channel: PeripheralRef<'a, C>, 435 channel: PeripheralRef<'a, C>,
@@ -418,7 +437,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
418} 437}
419 438
420impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { 439impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
421 pub unsafe fn new_read( 440 /// Create a new ring buffer.
441 pub unsafe fn new(
422 channel: impl Peripheral<P = C> + 'a, 442 channel: impl Peripheral<P = C> + 'a,
423 _request: Request, 443 _request: Request,
424 peri_addr: *mut W, 444 peri_addr: *mut W,
@@ -445,12 +465,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
445 let mut w = regs::Cr(0); 465 let mut w = regs::Cr(0);
446 w.set_psize(data_size.into()); 466 w.set_psize(data_size.into());
447 w.set_msize(data_size.into()); 467 w.set_msize(data_size.into());
448 w.set_minc(vals::Inc::ENABLED); 468 w.set_minc(true);
449 w.set_dir(dir.into()); 469 w.set_dir(dir.into());
450 w.set_teie(true); 470 w.set_teie(true);
451 w.set_htie(true); 471 w.set_htie(true);
452 w.set_tcie(true); 472 w.set_tcie(true);
453 w.set_circ(vals::Circ::ENABLED); 473 w.set_circ(true);
454 w.set_pl(vals::Pl::VERYHIGH); 474 w.set_pl(vals::Pl::VERYHIGH);
455 w.set_en(true); 475 w.set_en(true);
456 476
@@ -473,11 +493,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
473 this 493 this
474 } 494 }
475 495
496 /// Start the ring buffer operation.
497 ///
498 /// You must call this after creating it for it to work.
476 pub fn start(&mut self) { 499 pub fn start(&mut self) {
477 let ch = self.channel.regs().ch(self.channel.num()); 500 let ch = self.channel.regs().ch(self.channel.num());
478 ch.cr().write_value(self.cr) 501 ch.cr().write_value(self.cr)
479 } 502 }
480 503
504 /// Clear all data in the ring buffer.
481 pub fn clear(&mut self) { 505 pub fn clear(&mut self) {
482 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 506 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
483 } 507 }
@@ -509,10 +533,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
509 } 533 }
510 534
511 /// The capacity of the ringbuffer. 535 /// The capacity of the ringbuffer.
512 pub const fn cap(&self) -> usize { 536 pub const fn capacity(&self) -> usize {
513 self.ringbuf.cap() 537 self.ringbuf.cap()
514 } 538 }
515 539
540 /// Set a waker to be woken when at least one byte is received.
516 pub fn set_waker(&mut self, waker: &Waker) { 541 pub fn set_waker(&mut self, waker: &Waker) {
517 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 542 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
518 } 543 }
@@ -526,6 +551,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
526 }); 551 });
527 } 552 }
528 553
554 /// Request DMA to stop.
555 ///
556 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
529 pub fn request_stop(&mut self) { 557 pub fn request_stop(&mut self) {
530 let ch = self.channel.regs().ch(self.channel.num()); 558 let ch = self.channel.regs().ch(self.channel.num());
531 559
@@ -539,6 +567,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
539 }); 567 });
540 } 568 }
541 569
570 /// Return whether DMA is still running.
571 ///
572 /// If this returns `false`, it can be because either the transfer finished, or
573 /// it was requested to stop early with [`request_stop`](Self::request_stop).
542 pub fn is_running(&mut self) -> bool { 574 pub fn is_running(&mut self) -> bool {
543 let ch = self.channel.regs().ch(self.channel.num()); 575 let ch = self.channel.regs().ch(self.channel.num());
544 ch.cr().read().en() 576 ch.cr().read().en()
@@ -555,6 +587,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
555 } 587 }
556} 588}
557 589
590/// Ringbuffer for writing data using DMA circular mode.
558pub struct WritableRingBuffer<'a, C: Channel, W: Word> { 591pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
559 cr: regs::Cr, 592 cr: regs::Cr,
560 channel: PeripheralRef<'a, C>, 593 channel: PeripheralRef<'a, C>,
@@ -562,7 +595,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
562} 595}
563 596
564impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 597impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
565 pub unsafe fn new_write( 598 /// Create a new ring buffer.
599 pub unsafe fn new(
566 channel: impl Peripheral<P = C> + 'a, 600 channel: impl Peripheral<P = C> + 'a,
567 _request: Request, 601 _request: Request,
568 peri_addr: *mut W, 602 peri_addr: *mut W,
@@ -589,12 +623,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
589 let mut w = regs::Cr(0); 623 let mut w = regs::Cr(0);
590 w.set_psize(data_size.into()); 624 w.set_psize(data_size.into());
591 w.set_msize(data_size.into()); 625 w.set_msize(data_size.into());
592 w.set_minc(vals::Inc::ENABLED); 626 w.set_minc(true);
593 w.set_dir(dir.into()); 627 w.set_dir(dir.into());
594 w.set_teie(true); 628 w.set_teie(true);
595 w.set_htie(true); 629 w.set_htie(true);
596 w.set_tcie(true); 630 w.set_tcie(true);
597 w.set_circ(vals::Circ::ENABLED); 631 w.set_circ(true);
598 w.set_pl(vals::Pl::VERYHIGH); 632 w.set_pl(vals::Pl::VERYHIGH);
599 w.set_en(true); 633 w.set_en(true);
600 634
@@ -617,11 +651,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
617 this 651 this
618 } 652 }
619 653
654 /// Start the ring buffer operation.
655 ///
656 /// You must call this after creating it for it to work.
620 pub fn start(&mut self) { 657 pub fn start(&mut self) {
621 let ch = self.channel.regs().ch(self.channel.num()); 658 let ch = self.channel.regs().ch(self.channel.num());
622 ch.cr().write_value(self.cr) 659 ch.cr().write_value(self.cr)
623 } 660 }
624 661
662 /// Clear all data in the ring buffer.
625 pub fn clear(&mut self) { 663 pub fn clear(&mut self) {
626 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 664 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
627 } 665 }
@@ -640,10 +678,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
640 } 678 }
641 679
642 /// The capacity of the ringbuffer. 680 /// The capacity of the ringbuffer.
643 pub const fn cap(&self) -> usize { 681 pub const fn capacity(&self) -> usize {
644 self.ringbuf.cap() 682 self.ringbuf.cap()
645 } 683 }
646 684
685 /// Set a waker to be woken when at least one byte is sent.
647 pub fn set_waker(&mut self, waker: &Waker) { 686 pub fn set_waker(&mut self, waker: &Waker) {
648 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 687 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
649 } 688 }
@@ -657,6 +696,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
657 }); 696 });
658 } 697 }
659 698
699 /// Request DMA to stop.
700 ///
701 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
660 pub fn request_stop(&mut self) { 702 pub fn request_stop(&mut self) {
661 let ch = self.channel.regs().ch(self.channel.num()); 703 let ch = self.channel.regs().ch(self.channel.num());
662 704
@@ -670,6 +712,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
670 }); 712 });
671 } 713 }
672 714
715 /// Return whether DMA is still running.
716 ///
717 /// If this returns `false`, it can be because either the transfer finished, or
718 /// it was requested to stop early with [`request_stop`](Self::request_stop).
673 pub fn is_running(&mut self) -> bool { 719 pub fn is_running(&mut self) -> bool {
674 let ch = self.channel.regs().ch(self.channel.num()); 720 let ch = self.channel.regs().ch(self.channel.num());
675 ch.cr().read().en() 721 ch.cr().read().en()
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index cce0407c1..16d02f273 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -16,6 +16,7 @@ use crate::interrupt::Priority;
16use crate::pac::dma::{regs, vals}; 16use crate::pac::dma::{regs, vals};
17use crate::{interrupt, pac}; 17use crate::{interrupt, pac};
18 18
19/// DMA 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]
@@ -29,6 +30,10 @@ pub struct TransferOptions {
29 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. 30 /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
30 pub fifo_threshold: Option<FifoThreshold>, 31 pub fifo_threshold: Option<FifoThreshold>,
31 /// Enable circular DMA 32 /// Enable circular DMA
33 ///
34 /// Note:
35 /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
36 /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
32 pub circular: bool, 37 pub circular: bool,
33 /// Enable half transfer interrupt 38 /// Enable half transfer interrupt
34 pub half_transfer_ir: bool, 39 pub half_transfer_ir: bool,
@@ -69,6 +74,7 @@ impl From<Dir> for vals::Dir {
69 } 74 }
70} 75}
71 76
77/// DMA transfer burst setting.
72#[derive(Debug, Copy, Clone, PartialEq, Eq)] 78#[derive(Debug, Copy, Clone, PartialEq, Eq)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))] 79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum Burst { 80pub enum Burst {
@@ -93,6 +99,7 @@ impl From<Burst> for vals::Burst {
93 } 99 }
94} 100}
95 101
102/// DMA flow control setting.
96#[derive(Debug, Copy, Clone, PartialEq, Eq)] 103#[derive(Debug, Copy, Clone, PartialEq, Eq)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))] 104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub enum FlowControl { 105pub enum FlowControl {
@@ -111,6 +118,7 @@ impl From<FlowControl> for vals::Pfctrl {
111 } 118 }
112} 119}
113 120
121/// DMA FIFO threshold.
114#[derive(Debug, Copy, Clone, PartialEq, Eq)] 122#[derive(Debug, Copy, Clone, PartialEq, Eq)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))] 123#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub enum FifoThreshold { 124pub enum FifoThreshold {
@@ -208,13 +216,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
208 STATE.ch_wakers[index].wake(); 216 STATE.ch_wakers[index].wake();
209} 217}
210 218
219/// DMA request type alias. (also known as DMA channel number in some chips)
211#[cfg(any(dma_v2, dmamux))] 220#[cfg(any(dma_v2, dmamux))]
212pub type Request = u8; 221pub type Request = u8;
222/// DMA request type alias. (also known as DMA channel number in some chips)
213#[cfg(not(any(dma_v2, dmamux)))] 223#[cfg(not(any(dma_v2, dmamux)))]
214pub type Request = (); 224pub type Request = ();
215 225
226/// DMA channel.
216#[cfg(dmamux)] 227#[cfg(dmamux)]
217pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 228pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
229/// DMA channel.
218#[cfg(not(dmamux))] 230#[cfg(not(dmamux))]
219pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 231pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
220 232
@@ -229,12 +241,14 @@ pub(crate) mod sealed {
229 } 241 }
230} 242}
231 243
244/// DMA transfer.
232#[must_use = "futures do nothing unless you `.await` or poll them"] 245#[must_use = "futures do nothing unless you `.await` or poll them"]
233pub struct Transfer<'a, C: Channel> { 246pub struct Transfer<'a, C: Channel> {
234 channel: PeripheralRef<'a, C>, 247 channel: PeripheralRef<'a, C>,
235} 248}
236 249
237impl<'a, C: Channel> Transfer<'a, C> { 250impl<'a, C: Channel> Transfer<'a, C> {
251 /// Create a new read DMA transfer (peripheral to memory).
238 pub unsafe fn new_read<W: Word>( 252 pub unsafe fn new_read<W: Word>(
239 channel: impl Peripheral<P = C> + 'a, 253 channel: impl Peripheral<P = C> + 'a,
240 request: Request, 254 request: Request,
@@ -245,6 +259,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
245 Self::new_read_raw(channel, request, peri_addr, buf, options) 259 Self::new_read_raw(channel, request, peri_addr, buf, options)
246 } 260 }
247 261
262 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
248 pub unsafe fn new_read_raw<W: Word>( 263 pub unsafe fn new_read_raw<W: Word>(
249 channel: impl Peripheral<P = C> + 'a, 264 channel: impl Peripheral<P = C> + 'a,
250 request: Request, 265 request: Request,
@@ -270,6 +285,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
270 ) 285 )
271 } 286 }
272 287
288 /// Create a new write DMA transfer (memory to peripheral).
273 pub unsafe fn new_write<W: Word>( 289 pub unsafe fn new_write<W: Word>(
274 channel: impl Peripheral<P = C> + 'a, 290 channel: impl Peripheral<P = C> + 'a,
275 request: Request, 291 request: Request,
@@ -280,6 +296,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
280 Self::new_write_raw(channel, request, buf, peri_addr, options) 296 Self::new_write_raw(channel, request, buf, peri_addr, options)
281 } 297 }
282 298
299 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
283 pub unsafe fn new_write_raw<W: Word>( 300 pub unsafe fn new_write_raw<W: Word>(
284 channel: impl Peripheral<P = C> + 'a, 301 channel: impl Peripheral<P = C> + 'a,
285 request: Request, 302 request: Request,
@@ -305,6 +322,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
305 ) 322 )
306 } 323 }
307 324
325 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
308 pub unsafe fn new_write_repeated<W: Word>( 326 pub unsafe fn new_write_repeated<W: Word>(
309 channel: impl Peripheral<P = C> + 'a, 327 channel: impl Peripheral<P = C> + 'a,
310 request: Request, 328 request: Request,
@@ -368,18 +386,13 @@ impl<'a, C: Channel> Transfer<'a, C> {
368 w.set_msize(data_size.into()); 386 w.set_msize(data_size.into());
369 w.set_psize(data_size.into()); 387 w.set_psize(data_size.into());
370 w.set_pl(vals::Pl::VERYHIGH); 388 w.set_pl(vals::Pl::VERYHIGH);
371 w.set_minc(match incr_mem { 389 w.set_minc(incr_mem);
372 true => vals::Inc::INCREMENTED, 390 w.set_pinc(false);
373 false => vals::Inc::FIXED,
374 });
375 w.set_pinc(vals::Inc::FIXED);
376 w.set_teie(true); 391 w.set_teie(true);
377 w.set_tcie(options.complete_transfer_ir); 392 w.set_tcie(options.complete_transfer_ir);
393 w.set_circ(options.circular);
378 if options.circular { 394 if options.circular {
379 w.set_circ(vals::Circ::ENABLED);
380 debug!("Setting circular mode"); 395 debug!("Setting circular mode");
381 } else {
382 w.set_circ(vals::Circ::DISABLED);
383 } 396 }
384 #[cfg(dma_v1)] 397 #[cfg(dma_v1)]
385 w.set_trbuff(true); 398 w.set_trbuff(true);
@@ -407,6 +420,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
407 }); 420 });
408 } 421 }
409 422
423 /// Request the transfer to stop.
424 ///
425 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
410 pub fn request_stop(&mut self) { 426 pub fn request_stop(&mut self) {
411 let ch = self.channel.regs().st(self.channel.num()); 427 let ch = self.channel.regs().st(self.channel.num());
412 428
@@ -417,6 +433,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
417 }); 433 });
418 } 434 }
419 435
436 /// Return whether this transfer is still running.
437 ///
438 /// If this returns `false`, it can be because either the transfer finished, or
439 /// it was requested to stop early with [`request_stop`](Self::request_stop).
420 pub fn is_running(&mut self) -> bool { 440 pub fn is_running(&mut self) -> bool {
421 let ch = self.channel.regs().st(self.channel.num()); 441 let ch = self.channel.regs().st(self.channel.num());
422 ch.cr().read().en() 442 ch.cr().read().en()
@@ -429,6 +449,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
429 ch.ndtr().read().ndt() 449 ch.ndtr().read().ndt()
430 } 450 }
431 451
452 /// Blocking wait until the transfer finishes.
432 pub fn blocking_wait(mut self) { 453 pub fn blocking_wait(mut self) {
433 while self.is_running() {} 454 while self.is_running() {}
434 455
@@ -465,12 +486,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
465 486
466// ================================== 487// ==================================
467 488
489/// Double-buffered DMA transfer.
468pub struct DoubleBuffered<'a, C: Channel, W: Word> { 490pub struct DoubleBuffered<'a, C: Channel, W: Word> {
469 channel: PeripheralRef<'a, C>, 491 channel: PeripheralRef<'a, C>,
470 _phantom: PhantomData<W>, 492 _phantom: PhantomData<W>,
471} 493}
472 494
473impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { 495impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
496 /// Create a new read DMA transfer (peripheral to memory).
474 pub unsafe fn new_read( 497 pub unsafe fn new_read(
475 channel: impl Peripheral<P = C> + 'a, 498 channel: impl Peripheral<P = C> + 'a,
476 _request: Request, 499 _request: Request,
@@ -521,8 +544,8 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
521 w.set_msize(data_size.into()); 544 w.set_msize(data_size.into());
522 w.set_psize(data_size.into()); 545 w.set_psize(data_size.into());
523 w.set_pl(vals::Pl::VERYHIGH); 546 w.set_pl(vals::Pl::VERYHIGH);
524 w.set_minc(vals::Inc::INCREMENTED); 547 w.set_minc(true);
525 w.set_pinc(vals::Inc::FIXED); 548 w.set_pinc(false);
526 w.set_teie(true); 549 w.set_teie(true);
527 w.set_tcie(true); 550 w.set_tcie(true);
528 #[cfg(dma_v1)] 551 #[cfg(dma_v1)]
@@ -554,25 +577,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
554 }); 577 });
555 } 578 }
556 579
580 /// Set the first buffer address.
581 ///
582 /// You may call this while DMA is transferring the other buffer.
557 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { 583 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
558 let ch = self.channel.regs().st(self.channel.num()); 584 let ch = self.channel.regs().st(self.channel.num());
559 ch.m0ar().write_value(buffer as _); 585 ch.m0ar().write_value(buffer as _);
560 } 586 }
561 587
588 /// Set the second buffer address.
589 ///
590 /// You may call this while DMA is transferring the other buffer.
562 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { 591 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
563 let ch = self.channel.regs().st(self.channel.num()); 592 let ch = self.channel.regs().st(self.channel.num());
564 ch.m1ar().write_value(buffer as _); 593 ch.m1ar().write_value(buffer as _);
565 } 594 }
566 595
596 /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now)
567 pub fn is_buffer0_accessible(&mut self) -> bool { 597 pub fn is_buffer0_accessible(&mut self) -> bool {
568 let ch = self.channel.regs().st(self.channel.num()); 598 let ch = self.channel.regs().st(self.channel.num());
569 ch.cr().read().ct() == vals::Ct::MEMORY1 599 ch.cr().read().ct() == vals::Ct::MEMORY1
570 } 600 }
571 601
602 /// Set a waker to be woken when one of the buffers is being transferred.
572 pub fn set_waker(&mut self, waker: &Waker) { 603 pub fn set_waker(&mut self, waker: &Waker) {
573 STATE.ch_wakers[self.channel.index()].register(waker); 604 STATE.ch_wakers[self.channel.index()].register(waker);
574 } 605 }
575 606
607 /// Request the transfer to stop.
608 ///
609 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
576 pub fn request_stop(&mut self) { 610 pub fn request_stop(&mut self) {
577 let ch = self.channel.regs().st(self.channel.num()); 611 let ch = self.channel.regs().st(self.channel.num());
578 612
@@ -583,6 +617,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
583 }); 617 });
584 } 618 }
585 619
620 /// Return whether this transfer is still running.
621 ///
622 /// If this returns `false`, it can be because either the transfer finished, or
623 /// it was requested to stop early with [`request_stop`](Self::request_stop).
586 pub fn is_running(&mut self) -> bool { 624 pub fn is_running(&mut self) -> bool {
587 let ch = self.channel.regs().st(self.channel.num()); 625 let ch = self.channel.regs().st(self.channel.num());
588 ch.cr().read().en() 626 ch.cr().read().en()
@@ -629,6 +667,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
629 } 667 }
630} 668}
631 669
670/// Ringbuffer for receiving data using DMA circular mode.
632pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 671pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
633 cr: regs::Cr, 672 cr: regs::Cr,
634 channel: PeripheralRef<'a, C>, 673 channel: PeripheralRef<'a, C>,
@@ -636,7 +675,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
636} 675}
637 676
638impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { 677impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
639 pub unsafe fn new_read( 678 /// Create a new ring buffer.
679 pub unsafe fn new(
640 channel: impl Peripheral<P = C> + 'a, 680 channel: impl Peripheral<P = C> + 'a,
641 _request: Request, 681 _request: Request,
642 peri_addr: *mut W, 682 peri_addr: *mut W,
@@ -662,12 +702,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
662 w.set_msize(data_size.into()); 702 w.set_msize(data_size.into());
663 w.set_psize(data_size.into()); 703 w.set_psize(data_size.into());
664 w.set_pl(vals::Pl::VERYHIGH); 704 w.set_pl(vals::Pl::VERYHIGH);
665 w.set_minc(vals::Inc::INCREMENTED); 705 w.set_minc(true);
666 w.set_pinc(vals::Inc::FIXED); 706 w.set_pinc(false);
667 w.set_teie(true); 707 w.set_teie(true);
668 w.set_htie(options.half_transfer_ir); 708 w.set_htie(options.half_transfer_ir);
669 w.set_tcie(true); 709 w.set_tcie(true);
670 w.set_circ(vals::Circ::ENABLED); 710 w.set_circ(true);
671 #[cfg(dma_v1)] 711 #[cfg(dma_v1)]
672 w.set_trbuff(true); 712 w.set_trbuff(true);
673 #[cfg(dma_v2)] 713 #[cfg(dma_v2)]
@@ -706,11 +746,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
706 this 746 this
707 } 747 }
708 748
749 /// Start the ring buffer operation.
750 ///
751 /// You must call this after creating it for it to work.
709 pub fn start(&mut self) { 752 pub fn start(&mut self) {
710 let ch = self.channel.regs().st(self.channel.num()); 753 let ch = self.channel.regs().st(self.channel.num());
711 ch.cr().write_value(self.cr); 754 ch.cr().write_value(self.cr);
712 } 755 }
713 756
757 /// Clear all data in the ring buffer.
714 pub fn clear(&mut self) { 758 pub fn clear(&mut self) {
715 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 759 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
716 } 760 }
@@ -741,11 +785,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
741 .await 785 .await
742 } 786 }
743 787
744 // The capacity of the ringbuffer 788 /// The capacity of the ringbuffer
745 pub const fn cap(&self) -> usize { 789 pub const fn capacity(&self) -> usize {
746 self.ringbuf.cap() 790 self.ringbuf.cap()
747 } 791 }
748 792
793 /// Set a waker to be woken when at least one byte is received.
749 pub fn set_waker(&mut self, waker: &Waker) { 794 pub fn set_waker(&mut self, waker: &Waker) {
750 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 795 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
751 } 796 }
@@ -763,6 +808,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
763 }); 808 });
764 } 809 }
765 810
811 /// Request DMA to stop.
812 ///
813 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
766 pub fn request_stop(&mut self) { 814 pub fn request_stop(&mut self) {
767 let ch = self.channel.regs().st(self.channel.num()); 815 let ch = self.channel.regs().st(self.channel.num());
768 816
@@ -774,6 +822,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
774 }); 822 });
775 } 823 }
776 824
825 /// Return whether DMA is still running.
826 ///
827 /// If this returns `false`, it can be because either the transfer finished, or
828 /// it was requested to stop early with [`request_stop`](Self::request_stop).
777 pub fn is_running(&mut self) -> bool { 829 pub fn is_running(&mut self) -> bool {
778 let ch = self.channel.regs().st(self.channel.num()); 830 let ch = self.channel.regs().st(self.channel.num());
779 ch.cr().read().en() 831 ch.cr().read().en()
@@ -790,6 +842,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
790 } 842 }
791} 843}
792 844
845/// Ringbuffer for writing data using DMA circular mode.
793pub struct WritableRingBuffer<'a, C: Channel, W: Word> { 846pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
794 cr: regs::Cr, 847 cr: regs::Cr,
795 channel: PeripheralRef<'a, C>, 848 channel: PeripheralRef<'a, C>,
@@ -797,7 +850,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
797} 850}
798 851
799impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 852impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
800 pub unsafe fn new_write( 853 /// Create a new ring buffer.
854 pub unsafe fn new(
801 channel: impl Peripheral<P = C> + 'a, 855 channel: impl Peripheral<P = C> + 'a,
802 _request: Request, 856 _request: Request,
803 peri_addr: *mut W, 857 peri_addr: *mut W,
@@ -823,12 +877,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
823 w.set_msize(data_size.into()); 877 w.set_msize(data_size.into());
824 w.set_psize(data_size.into()); 878 w.set_psize(data_size.into());
825 w.set_pl(vals::Pl::VERYHIGH); 879 w.set_pl(vals::Pl::VERYHIGH);
826 w.set_minc(vals::Inc::INCREMENTED); 880 w.set_minc(true);
827 w.set_pinc(vals::Inc::FIXED); 881 w.set_pinc(false);
828 w.set_teie(true); 882 w.set_teie(true);
829 w.set_htie(options.half_transfer_ir); 883 w.set_htie(options.half_transfer_ir);
830 w.set_tcie(true); 884 w.set_tcie(true);
831 w.set_circ(vals::Circ::ENABLED); 885 w.set_circ(true);
832 #[cfg(dma_v1)] 886 #[cfg(dma_v1)]
833 w.set_trbuff(true); 887 w.set_trbuff(true);
834 #[cfg(dma_v2)] 888 #[cfg(dma_v2)]
@@ -867,11 +921,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
867 this 921 this
868 } 922 }
869 923
924 /// Start the ring buffer operation.
925 ///
926 /// You must call this after creating it for it to work.
870 pub fn start(&mut self) { 927 pub fn start(&mut self) {
871 let ch = self.channel.regs().st(self.channel.num()); 928 let ch = self.channel.regs().st(self.channel.num());
872 ch.cr().write_value(self.cr); 929 ch.cr().write_value(self.cr);
873 } 930 }
874 931
932 /// Clear all data in the ring buffer.
875 pub fn clear(&mut self) { 933 pub fn clear(&mut self) {
876 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 934 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
877 } 935 }
@@ -889,11 +947,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
889 .await 947 .await
890 } 948 }
891 949
892 // The capacity of the ringbuffer 950 /// The capacity of the ringbuffer
893 pub const fn cap(&self) -> usize { 951 pub const fn capacity(&self) -> usize {
894 self.ringbuf.cap() 952 self.ringbuf.cap()
895 } 953 }
896 954
955 /// Set a waker to be woken when at least one byte is received.
897 pub fn set_waker(&mut self, waker: &Waker) { 956 pub fn set_waker(&mut self, waker: &Waker) {
898 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 957 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
899 } 958 }
@@ -911,6 +970,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
911 }); 970 });
912 } 971 }
913 972
973 /// Request DMA to stop.
974 ///
975 /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
914 pub fn request_stop(&mut self) { 976 pub fn request_stop(&mut self) {
915 let ch = self.channel.regs().st(self.channel.num()); 977 let ch = self.channel.regs().st(self.channel.num());
916 978
@@ -922,6 +984,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
922 }); 984 });
923 } 985 }
924 986
987 /// Return whether DMA is still running.
988 ///
989 /// If this returns `false`, it can be because either the transfer finished, or
990 /// it was requested to stop early with [`request_stop`](Self::request_stop).
925 pub fn is_running(&mut self) -> bool { 991 pub fn is_running(&mut self) -> bool {
926 let ch = self.channel.regs().st(self.channel.num()); 992 let ch = self.channel.regs().st(self.channel.num());
927 ch.cr().read().en() 993 ch.cr().read().en()
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs
index 20601dc86..9cd494724 100644
--- a/embassy-stm32/src/dma/dmamux.rs
+++ b/embassy-stm32/src/dma/dmamux.rs
@@ -22,11 +22,15 @@ pub(crate) mod dmamux_sealed {
22 } 22 }
23} 23}
24 24
25/// DMAMUX1 instance.
25pub struct DMAMUX1; 26pub struct DMAMUX1;
27/// DMAMUX2 instance.
26#[cfg(stm32h7)] 28#[cfg(stm32h7)]
27pub struct DMAMUX2; 29pub struct DMAMUX2;
28 30
31/// DMAMUX channel trait.
29pub trait MuxChannel: dmamux_sealed::MuxChannel { 32pub trait MuxChannel: dmamux_sealed::MuxChannel {
33 /// DMAMUX instance this channel is on.
30 type Mux; 34 type Mux;
31} 35}
32 36
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/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 29fced8fc..38945ac33 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -1,3 +1,5 @@
1//! Direct Memory Access (DMA)
2
1#[cfg(dma)] 3#[cfg(dma)]
2pub(crate) mod dma; 4pub(crate) mod dma;
3#[cfg(dma)] 5#[cfg(dma)]
@@ -39,6 +41,13 @@ enum Dir {
39 PeripheralToMemory, 41 PeripheralToMemory,
40} 42}
41 43
44/// "No DMA" placeholder.
45///
46/// You may pass this in place of a real DMA channel when creating a driver
47/// to indicate it should not use DMA.
48///
49/// This often causes async functionality to not be available on the instance,
50/// leaving only blocking functionality.
42pub struct NoDma; 51pub struct NoDma;
43 52
44impl_peripheral!(NoDma); 53impl_peripheral!(NoDma);
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs
index aef6e9700..a72c4b7d9 100644
--- a/embassy-stm32/src/dma/word.rs
+++ b/embassy-stm32/src/dma/word.rs
@@ -1,3 +1,6 @@
1//! DMA word sizes.
2
3#[allow(missing_docs)]
1#[derive(Debug, Copy, Clone, PartialEq, Eq)] 4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
3pub enum WordSize { 6pub enum WordSize {
@@ -7,6 +10,7 @@ pub enum WordSize {
7} 10}
8 11
9impl WordSize { 12impl WordSize {
13 /// Amount of bytes of this word size.
10 pub fn bytes(&self) -> usize { 14 pub fn bytes(&self) -> usize {
11 match self { 15 match self {
12 Self::OneByte => 1, 16 Self::OneByte => 1,
@@ -20,8 +24,13 @@ mod sealed {
20 pub trait Word {} 24 pub trait Word {}
21} 25}
22 26
27/// DMA word trait.
28///
29/// This is implemented for u8, u16, u32, etc.
23pub trait Word: sealed::Word + Default + Copy + 'static { 30pub trait Word: sealed::Word + Default + Copy + 'static {
31 /// Word size
24 fn size() -> WordSize; 32 fn size() -> WordSize;
33 /// Amount of bits of this word size.
25 fn bits() -> usize; 34 fn bits() -> usize;
26} 35}
27 36
@@ -40,6 +49,7 @@ macro_rules! impl_word {
40 ($T:ident, $uX:ident, $bits:literal, $size:ident) => { 49 ($T:ident, $uX:ident, $bits:literal, $size:ident) => {
41 #[repr(transparent)] 50 #[repr(transparent)]
42 #[derive(Copy, Clone, Default)] 51 #[derive(Copy, Clone, Default)]
52 #[doc = concat!(stringify!($T), " word size")]
43 pub struct $T(pub $uX); 53 pub struct $T(pub $uX);
44 impl_word!(_, $T, $bits, $size); 54 impl_word!(_, $T, $bits, $size);
45 }; 55 };
diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs
index 1e1094a1c..9c26e90f1 100644
--- a/embassy-stm32/src/eth/generic_smi.rs
+++ b/embassy-stm32/src/eth/generic_smi.rs
@@ -102,6 +102,7 @@ unsafe impl PHY for GenericSMI {
102 102
103/// Public functions for the PHY 103/// Public functions for the PHY
104impl GenericSMI { 104impl GenericSMI {
105 /// Set the SMI polling interval.
105 #[cfg(feature = "time")] 106 #[cfg(feature = "time")]
106 pub fn set_poll_interval(&mut self, poll_interval: Duration) { 107 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
107 self.poll_interval = poll_interval 108 self.poll_interval = poll_interval
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 556aadd73..448405507 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -1,3 +1,4 @@
1//! Ethernet (ETH)
1#![macro_use] 2#![macro_use]
2 3
3#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] 4#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")]
@@ -22,6 +23,14 @@ const RX_BUFFER_SIZE: usize = 1536;
22#[derive(Copy, Clone)] 23#[derive(Copy, Clone)]
23pub(crate) struct Packet<const N: usize>([u8; N]); 24pub(crate) struct Packet<const N: usize>([u8; N]);
24 25
26/// Ethernet packet queue.
27///
28/// This struct owns the memory used for reading and writing packets.
29///
30/// `TX` is the number of packets in the transmit queue, `RX` in the receive
31/// queue. A bigger queue allows the hardware to receive more packets while the
32/// CPU is busy doing other things, which may increase performance (especially for RX)
33/// at the cost of more RAM usage.
25pub struct PacketQueue<const TX: usize, const RX: usize> { 34pub struct PacketQueue<const TX: usize, const RX: usize> {
26 tx_desc: [TDes; TX], 35 tx_desc: [TDes; TX],
27 rx_desc: [RDes; RX], 36 rx_desc: [RDes; RX],
@@ -30,6 +39,7 @@ pub struct PacketQueue<const TX: usize, const RX: usize> {
30} 39}
31 40
32impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { 41impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
42 /// Create a new packet queue.
33 pub const fn new() -> Self { 43 pub const fn new() -> Self {
34 const NEW_TDES: TDes = TDes::new(); 44 const NEW_TDES: TDes = TDes::new();
35 const NEW_RDES: RDes = RDes::new(); 45 const NEW_RDES: RDes = RDes::new();
@@ -41,7 +51,18 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
41 } 51 }
42 } 52 }
43 53
44 // Allow to initialize a Self without requiring it to go on the stack 54 /// Initialize a packet queue in-place.
55 ///
56 /// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The
57 /// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()`
58 /// and then store the returned PacketQueue in its final place (like a `static`), the compiler might
59 /// place it temporarily on the stack then move it. Since this struct is quite big, it may result
60 /// in a stack overflow.
61 ///
62 /// With this function, you can create an uninitialized `static` with type `MaybeUninit<PacketQueue<...>>`
63 /// and initialize it in-place, guaranteeing no stack usage.
64 ///
65 /// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe.
45 pub fn init(this: &mut MaybeUninit<Self>) { 66 pub fn init(this: &mut MaybeUninit<Self>) {
46 unsafe { 67 unsafe {
47 this.as_mut_ptr().write_bytes(0u8, 1); 68 this.as_mut_ptr().write_bytes(0u8, 1);
@@ -93,6 +114,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
93 } 114 }
94} 115}
95 116
117/// `embassy-net` RX token.
96pub struct RxToken<'a, 'd> { 118pub struct RxToken<'a, 'd> {
97 rx: &'a mut RDesRing<'d>, 119 rx: &'a mut RDesRing<'d>,
98} 120}
@@ -110,6 +132,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
110 } 132 }
111} 133}
112 134
135/// `embassy-net` TX token.
113pub struct TxToken<'a, 'd> { 136pub struct TxToken<'a, 'd> {
114 tx: &'a mut TDesRing<'d>, 137 tx: &'a mut TDesRing<'d>,
115} 138}
@@ -159,6 +182,7 @@ pub(crate) mod sealed {
159 } 182 }
160} 183}
161 184
185/// Ethernet instance.
162pub trait Instance: sealed::Instance + Send + 'static {} 186pub trait Instance: sealed::Instance + Send + 'static {}
163 187
164impl sealed::Instance for crate::peripherals::ETH { 188impl sealed::Instance for crate::peripherals::ETH {
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 13e53f687..2ce5b3927 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -43,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
43 } 43 }
44} 44}
45 45
46/// Ethernet driver.
46pub struct Ethernet<'d, T: Instance, P: PHY> { 47pub struct Ethernet<'d, T: Instance, P: PHY> {
47 _peri: PeripheralRef<'d, T>, 48 _peri: PeripheralRef<'d, T>,
48 pub(crate) tx: TDesRing<'d>, 49 pub(crate) tx: TDesRing<'d>,
@@ -266,6 +267,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
266 } 267 }
267} 268}
268 269
270/// Ethernet station management interface.
269pub struct EthernetStationManagement<T: Instance> { 271pub struct EthernetStationManagement<T: Instance> {
270 peri: PhantomData<T>, 272 peri: PhantomData<T>,
271 clock_range: Cr, 273 clock_range: Cr,
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index c77155fea..59745cba0 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -34,6 +34,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
34 } 34 }
35} 35}
36 36
37/// Ethernet driver.
37pub struct Ethernet<'d, T: Instance, P: PHY> { 38pub struct Ethernet<'d, T: Instance, P: PHY> {
38 _peri: PeripheralRef<'d, T>, 39 _peri: PeripheralRef<'d, T>,
39 pub(crate) tx: TDesRing<'d>, 40 pub(crate) tx: TDesRing<'d>,
@@ -56,6 +57,7 @@ macro_rules! config_pins {
56} 57}
57 58
58impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { 59impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
60 /// Create a new Ethernet driver.
59 pub fn new<const TX: usize, const RX: usize>( 61 pub fn new<const TX: usize, const RX: usize>(
60 queue: &'d mut PacketQueue<TX, RX>, 62 queue: &'d mut PacketQueue<TX, RX>,
61 peri: impl Peripheral<P = T> + 'd, 63 peri: impl Peripheral<P = T> + 'd,
@@ -237,6 +239,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
237 } 239 }
238} 240}
239 241
242/// Ethernet SMI driver.
240pub struct EthernetStationManagement<T: Instance> { 243pub struct EthernetStationManagement<T: Instance> {
241 peri: PhantomData<T>, 244 peri: PhantomData<T>,
242 clock_range: u8, 245 clock_range: u8,
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index dbd24804f..f83bae3ff 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -1,3 +1,4 @@
1//! External Interrupts (EXTI)
1use core::convert::Infallible; 2use core::convert::Infallible;
2use core::future::Future; 3use core::future::Future;
3use core::marker::PhantomData; 4use core::marker::PhantomData;
@@ -39,7 +40,7 @@ fn exticr_regs() -> pac::afio::Afio {
39 pac::AFIO 40 pac::AFIO
40} 41}
41 42
42pub unsafe fn on_irq() { 43unsafe fn on_irq() {
43 #[cfg(feature = "low-power")] 44 #[cfg(feature = "low-power")]
44 crate::low_power::on_wakeup_irq(); 45 crate::low_power::on_wakeup_irq();
45 46
@@ -85,7 +86,13 @@ impl Iterator for BitIter {
85 } 86 }
86} 87}
87 88
88/// EXTI input driver 89/// EXTI input driver.
90///
91/// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not
92/// built into `Input` itself because it needs to take ownership of the corresponding
93/// EXTI channel, which is a limited resource.
94///
95/// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time.
89pub struct ExtiInput<'d, T: GpioPin> { 96pub struct ExtiInput<'d, T: GpioPin> {
90 pin: Input<'d, T>, 97 pin: Input<'d, T>,
91} 98}
@@ -93,23 +100,30 @@ pub struct ExtiInput<'d, T: GpioPin> {
93impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} 100impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
94 101
95impl<'d, T: GpioPin> ExtiInput<'d, T> { 102impl<'d, T: GpioPin> ExtiInput<'d, T> {
103 /// Create an EXTI input.
96 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { 104 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self {
97 Self { pin } 105 Self { pin }
98 } 106 }
99 107
100 pub fn is_high(&self) -> bool { 108 /// Get whether the pin is high.
109 pub fn is_high(&mut self) -> bool {
101 self.pin.is_high() 110 self.pin.is_high()
102 } 111 }
103 112
104 pub fn is_low(&self) -> bool { 113 /// Get whether the pin is low.
114 pub fn is_low(&mut self) -> bool {
105 self.pin.is_low() 115 self.pin.is_low()
106 } 116 }
107 117
108 pub fn get_level(&self) -> Level { 118 /// Get the pin level.
119 pub fn get_level(&mut self) -> Level {
109 self.pin.get_level() 120 self.pin.get_level()
110 } 121 }
111 122
112 pub async fn wait_for_high<'a>(&'a mut self) { 123 /// Asynchronously wait until the pin is high.
124 ///
125 /// This returns immediately if the pin is already high.
126 pub async fn wait_for_high(&mut self) {
113 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); 127 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
114 if self.is_high() { 128 if self.is_high() {
115 return; 129 return;
@@ -117,7 +131,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
117 fut.await 131 fut.await
118 } 132 }
119 133
120 pub async fn wait_for_low<'a>(&'a mut self) { 134 /// Asynchronously wait until the pin is low.
135 ///
136 /// This returns immediately if the pin is already low.
137 pub async fn wait_for_low(&mut self) {
121 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); 138 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
122 if self.is_low() { 139 if self.is_low() {
123 return; 140 return;
@@ -125,15 +142,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
125 fut.await 142 fut.await
126 } 143 }
127 144
128 pub async fn wait_for_rising_edge<'a>(&'a mut self) { 145 /// Asynchronously wait until the pin sees a rising edge.
146 ///
147 /// If the pin is already high, it will wait for it to go low then back high.
148 pub async fn wait_for_rising_edge(&mut self) {
129 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await 149 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
130 } 150 }
131 151
132 pub async fn wait_for_falling_edge<'a>(&'a mut self) { 152 /// Asynchronously wait until the pin sees a falling edge.
153 ///
154 /// If the pin is already low, it will wait for it to go high then back low.
155 pub async fn wait_for_falling_edge(&mut self) {
133 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await 156 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
134 } 157 }
135 158
136 pub async fn wait_for_any_edge<'a>(&'a mut self) { 159 /// Asynchronously wait until the pin sees any edge (either rising or falling).
160 pub async fn wait_for_any_edge(&mut self) {
137 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await 161 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
138 } 162 }
139} 163}
@@ -142,11 +166,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T>
142 type Error = Infallible; 166 type Error = Infallible;
143 167
144 fn is_high(&self) -> Result<bool, Self::Error> { 168 fn is_high(&self) -> Result<bool, Self::Error> {
145 Ok(self.is_high()) 169 Ok(!self.pin.pin.ref_is_low())
146 } 170 }
147 171
148 fn is_low(&self) -> Result<bool, Self::Error> { 172 fn is_low(&self) -> Result<bool, Self::Error> {
149 Ok(self.is_low()) 173 Ok(self.pin.pin.ref_is_low())
150 } 174 }
151} 175}
152 176
@@ -155,11 +179,11 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> {
155} 179}
156 180
157impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { 181impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> {
158 fn is_high(&self) -> Result<bool, Self::Error> { 182 fn is_high(&mut self) -> Result<bool, Self::Error> {
159 Ok(self.is_high()) 183 Ok(self.is_high())
160 } 184 }
161 185
162 fn is_low(&self) -> Result<bool, Self::Error> { 186 fn is_low(&mut self) -> Result<bool, Self::Error> {
163 Ok(self.is_low()) 187 Ok(self.is_low())
164 } 188 }
165} 189}
@@ -284,6 +308,7 @@ macro_rules! foreach_exti_irq {
284 308
285macro_rules! impl_irq { 309macro_rules! impl_irq {
286 ($e:ident) => { 310 ($e:ident) => {
311 #[allow(non_snake_case)]
287 #[cfg(feature = "rt")] 312 #[cfg(feature = "rt")]
288 #[interrupt] 313 #[interrupt]
289 unsafe fn $e() { 314 unsafe fn $e() {
@@ -298,8 +323,16 @@ pub(crate) mod sealed {
298 pub trait Channel {} 323 pub trait Channel {}
299} 324}
300 325
326/// EXTI channel trait.
301pub trait Channel: sealed::Channel + Sized { 327pub trait Channel: sealed::Channel + Sized {
328 /// Get the EXTI channel number.
302 fn number(&self) -> usize; 329 fn number(&self) -> usize;
330
331 /// Type-erase (degrade) this channel into an `AnyChannel`.
332 ///
333 /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which
334 /// are all different types, into the same type. It is useful for
335 /// creating arrays of channels, or avoiding generics.
303 fn degrade(self) -> AnyChannel { 336 fn degrade(self) -> AnyChannel {
304 AnyChannel { 337 AnyChannel {
305 number: self.number() as u8, 338 number: self.number() as u8,
@@ -307,9 +340,13 @@ pub trait Channel: sealed::Channel + Sized {
307 } 340 }
308} 341}
309 342
343/// Type-erased (degraded) EXTI channel.
344///
345/// This represents ownership over any EXTI channel, known at runtime.
310pub struct AnyChannel { 346pub struct AnyChannel {
311 number: u8, 347 number: u8,
312} 348}
349
313impl_peripheral!(AnyChannel); 350impl_peripheral!(AnyChannel);
314impl sealed::Channel for AnyChannel {} 351impl sealed::Channel for AnyChannel {}
315impl Channel for AnyChannel { 352impl Channel for AnyChannel {
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index eae40c7ec..97eaece81 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -17,6 +17,7 @@ use crate::{interrupt, Peripheral};
17pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); 17pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
18 18
19impl<'d> Flash<'d, Async> { 19impl<'d> Flash<'d, Async> {
20 /// Create a new flash driver with async capabilities.
20 pub fn new( 21 pub fn new(
21 p: impl Peripheral<P = FLASH> + 'd, 22 p: impl Peripheral<P = FLASH> + 'd,
22 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd, 23 _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd,
@@ -32,15 +33,26 @@ impl<'d> Flash<'d, Async> {
32 } 33 }
33 } 34 }
34 35
36 /// Split this flash driver into one instance per flash memory region.
37 ///
38 /// See module-level documentation for details on how memory regions work.
35 pub fn into_regions(self) -> FlashLayout<'d, Async> { 39 pub fn into_regions(self) -> FlashLayout<'d, Async> {
36 assert!(family::is_default_layout()); 40 assert!(family::is_default_layout());
37 FlashLayout::new(self.inner) 41 FlashLayout::new(self.inner)
38 } 42 }
39 43
44 /// Async write.
45 ///
46 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
47 /// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
40 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 48 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
41 unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } 49 unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await }
42 } 50 }
43 51
52 /// Async erase.
53 ///
54 /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
55 /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
44 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 56 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
45 unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } 57 unsafe { erase_sectored(FLASH_BASE as u32, from, to).await }
46 } 58 }
@@ -59,7 +71,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> {
59 const READ_SIZE: usize = super::READ_SIZE; 71 const READ_SIZE: usize = super::READ_SIZE;
60 72
61 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 73 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
62 self.read(offset, bytes) 74 self.blocking_read(offset, bytes)
63 } 75 }
64 76
65 fn capacity(&self) -> usize { 77 fn capacity(&self) -> usize {
@@ -141,15 +153,20 @@ pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Resu
141foreach_flash_region! { 153foreach_flash_region! {
142 ($type_name:ident, $write_size:literal, $erase_size:literal) => { 154 ($type_name:ident, $write_size:literal, $erase_size:literal) => {
143 impl crate::_generated::flash_regions::$type_name<'_, Async> { 155 impl crate::_generated::flash_regions::$type_name<'_, Async> {
156 /// Async read.
157 ///
158 /// Note: reading from flash can't actually block, so this is the same as `blocking_read`.
144 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 159 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
145 blocking_read(self.0.base, self.0.size, offset, bytes) 160 blocking_read(self.0.base, self.0.size, offset, bytes)
146 } 161 }
147 162
163 /// Async write.
148 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 164 pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
149 let _guard = REGION_ACCESS.lock().await; 165 let _guard = REGION_ACCESS.lock().await;
150 unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } 166 unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await }
151 } 167 }
152 168
169 /// Async erase.
153 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 170 pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
154 let _guard = REGION_ACCESS.lock().await; 171 let _guard = REGION_ACCESS.lock().await;
155 unsafe { erase_sectored(self.0.base, from, to).await } 172 unsafe { erase_sectored(self.0.base, from, to).await }
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index 8acad1c7c..f8561edb3 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -12,12 +12,14 @@ use super::{
12use crate::peripherals::FLASH; 12use crate::peripherals::FLASH;
13use crate::Peripheral; 13use crate::Peripheral;
14 14
15/// Internal flash memory driver.
15pub struct Flash<'d, MODE = Async> { 16pub struct Flash<'d, MODE = Async> {
16 pub(crate) inner: PeripheralRef<'d, FLASH>, 17 pub(crate) inner: PeripheralRef<'d, FLASH>,
17 pub(crate) _mode: PhantomData<MODE>, 18 pub(crate) _mode: PhantomData<MODE>,
18} 19}
19 20
20impl<'d> Flash<'d, Blocking> { 21impl<'d> Flash<'d, Blocking> {
22 /// Create a new flash driver, usable in blocking mode.
21 pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self { 23 pub fn new_blocking(p: impl Peripheral<P = FLASH> + 'd) -> Self {
22 into_ref!(p); 24 into_ref!(p);
23 25
@@ -29,15 +31,26 @@ impl<'d> Flash<'d, Blocking> {
29} 31}
30 32
31impl<'d, MODE> Flash<'d, MODE> { 33impl<'d, MODE> Flash<'d, MODE> {
34 /// Split this flash driver into one instance per flash memory region.
35 ///
36 /// See module-level documentation for details on how memory regions work.
32 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { 37 pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> {
33 assert!(family::is_default_layout()); 38 assert!(family::is_default_layout());
34 FlashLayout::new(self.inner) 39 FlashLayout::new(self.inner)
35 } 40 }
36 41
37 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 42 /// Blocking read.
43 ///
44 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
45 /// For example, to read address `0x0800_1234` you have to use offset `0x1234`.
46 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
38 blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes) 47 blocking_read(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes)
39 } 48 }
40 49
50 /// Blocking write.
51 ///
52 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
53 /// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
41 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 54 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
42 unsafe { 55 unsafe {
43 blocking_write( 56 blocking_write(
@@ -50,6 +63,10 @@ impl<'d, MODE> Flash<'d, MODE> {
50 } 63 }
51 } 64 }
52 65
66 /// Blocking erase.
67 ///
68 /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
69 /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
53 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 70 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
54 unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) } 71 unsafe { blocking_erase(FLASH_BASE as u32, from, to, erase_sector_unlocked) }
55 } 72 }
@@ -206,7 +223,7 @@ impl<MODE> embedded_storage::nor_flash::ReadNorFlash for Flash<'_, MODE> {
206 const READ_SIZE: usize = READ_SIZE; 223 const READ_SIZE: usize = READ_SIZE;
207 224
208 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 225 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
209 self.read(offset, bytes) 226 self.blocking_read(offset, bytes)
210 } 227 }
211 228
212 fn capacity(&self) -> usize { 229 fn capacity(&self) -> usize {
@@ -230,16 +247,28 @@ impl<MODE> embedded_storage::nor_flash::NorFlash for Flash<'_, MODE> {
230foreach_flash_region! { 247foreach_flash_region! {
231 ($type_name:ident, $write_size:literal, $erase_size:literal) => { 248 ($type_name:ident, $write_size:literal, $erase_size:literal) => {
232 impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> { 249 impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> {
250 /// Blocking read.
251 ///
252 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
253 /// For example, to read address `0x0800_1234` you have to use offset `0x1234`.
233 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 254 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
234 blocking_read(self.0.base, self.0.size, offset, bytes) 255 blocking_read(self.0.base, self.0.size, offset, bytes)
235 } 256 }
236 } 257 }
237 258
238 impl crate::_generated::flash_regions::$type_name<'_, Blocking> { 259 impl crate::_generated::flash_regions::$type_name<'_, Blocking> {
260 /// Blocking write.
261 ///
262 /// NOTE: `offset` is an offset from the flash start, NOT an absolute address.
263 /// For example, to write address `0x0800_1234` you have to use offset `0x1234`.
239 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { 264 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
240 unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } 265 unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) }
241 } 266 }
242 267
268 /// Blocking erase.
269 ///
270 /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address.
271 /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`.
243 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { 272 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
244 unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } 273 unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) }
245 } 274 }
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 1ab8435a0..c0a8d7022 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
13pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS 14 &FLASH_REGIONS
15} 15}
16 16
@@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
79 79
80pub(crate) unsafe fn clear_all_err() { 80pub(crate) unsafe fn clear_all_err() {
81 // read and write back the same value. 81 // read and write back the same value.
82 // This clears all "write 0 to clear" bits. 82 // This clears all "write 1 to clear" bits.
83 pac::FLASH.sr().modify(|_| {}); 83 pac::FLASH.sr().modify(|_| {});
84} 84}
85 85
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 7e6d7ca26..817ccef4d 100644
--- a/embassy-stm32/src/flash/f3.rs
+++ b/embassy-stm32/src/flash/f3.rs
@@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
13pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS 14 &FLASH_REGIONS
15} 15}
16 16
@@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
79 79
80pub(crate) unsafe fn clear_all_err() { 80pub(crate) unsafe fn clear_all_err() {
81 // read and write back the same value. 81 // read and write back the same value.
82 // This clears all "write 0 to clear" bits. 82 // This clears all "write 1 to clear" bits.
83 pac::FLASH.sr().modify(|_| {}); 83 pac::FLASH.sr().modify(|_| {});
84} 84}
85 85
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 5d07020ce..2671dfb04 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -9,7 +9,7 @@ use pac::FLASH_SIZE;
9use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 9use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
10use crate::flash::Error; 10use crate::flash::Error;
11use crate::pac; 11use crate::pac;
12 12#[allow(missing_docs)] // TODO
13#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] 13#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))]
14mod alt_regions { 14mod alt_regions {
15 use core::marker::PhantomData; 15 use core::marker::PhantomData;
@@ -337,7 +337,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
337 337
338pub(crate) fn clear_all_err() { 338pub(crate) fn clear_all_err() {
339 // read and write back the same value. 339 // read and write back the same value.
340 // This clears all "write 0 to clear" bits. 340 // This clears all "write 1 to clear" bits.
341 pac::FLASH.sr().modify(|_| {}); 341 pac::FLASH.sr().modify(|_| {});
342} 342}
343 343
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index b52231ca8..6b3e66ac6 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
13pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 13pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
14 &FLASH_REGIONS 14 &FLASH_REGIONS
15} 15}
16 16
@@ -69,7 +69,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
69 69
70pub(crate) unsafe fn clear_all_err() { 70pub(crate) unsafe fn clear_all_err() {
71 // read and write back the same value. 71 // read and write back the same value.
72 // This clears all "write 0 to clear" bits. 72 // This clears all "write 1 to clear" bits.
73 pac::FLASH.sr().modify(|_| {}); 73 pac::FLASH.sr().modify(|_| {});
74} 74}
75 75
diff --git a/embassy-stm32/src/flash/g0.rs b/embassy-stm32/src/flash/g.rs
index 19a388970..d97b4a932 100644
--- a/embassy-stm32/src/flash/g0.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -8,11 +8,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
8use crate::flash::Error; 8use crate::flash::Error;
9use crate::pac; 9use crate::pac;
10 10
11pub const fn is_default_layout() -> bool { 11pub(crate) const fn is_default_layout() -> bool {
12 true 12 true
13} 13}
14 14
15pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 15pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
16 &FLASH_REGIONS 16 &FLASH_REGIONS
17} 17}
18 18
@@ -92,6 +92,6 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
92 92
93pub(crate) unsafe fn clear_all_err() { 93pub(crate) unsafe fn clear_all_err() {
94 // read and write back the same value. 94 // read and write back the same value.
95 // This clears all "write 0 to clear" bits. 95 // This clears all "write 1 to clear" bits.
96 pac::FLASH.sr().modify(|_| {}); 96 pac::FLASH.sr().modify(|_| {});
97} 97}
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index b064fd6ea..65d163d29 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE};
6use crate::flash::Error; 6use crate::flash::Error;
7use crate::pac; 7use crate::pac;
8 8
9pub const fn is_default_layout() -> bool { 9pub(crate) const fn is_default_layout() -> bool {
10 true 10 true
11} 11}
12 12
@@ -14,7 +14,7 @@ const fn is_dual_bank() -> bool {
14 FLASH_REGIONS.len() >= 2 14 FLASH_REGIONS.len() >= 2
15} 15}
16 16
17pub fn get_flash_regions() -> &'static [&'static FlashRegion] { 17pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] {
18 &FLASH_REGIONS 18 &FLASH_REGIONS
19} 19}
20 20
@@ -113,7 +113,7 @@ pub(crate) unsafe fn clear_all_err() {
113 113
114unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { 114unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
115 // read and write back the same value. 115 // read and write back the same value.
116 // This clears all "write 0 to clear" bits. 116 // This clears all "write 1 to clear" bits.
117 bank.sr().modify(|_| {}); 117 bank.sr().modify(|_| {});
118} 118}
119 119
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 1db0da923..0b332dc61 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -5,11 +5,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
6use crate::pac; 6use crate::pac;
7 7
8pub const fn is_default_layout() -> bool { 8pub(crate) const fn is_default_layout() -> bool {
9 true 9 true
10} 10}
11 11
12pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 12pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
13 &FLASH_REGIONS 13 &FLASH_REGIONS
14} 14}
15 15
@@ -120,7 +120,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
120 120
121pub(crate) unsafe fn clear_all_err() { 121pub(crate) unsafe fn clear_all_err() {
122 // read and write back the same value. 122 // read and write back the same value.
123 // This clears all "write 0 to clear" bits. 123 // This clears all "write 1 to clear" bits.
124 pac::FLASH.sr().modify(|_| {}); 124 pac::FLASH.sr().modify(|_| {});
125} 125}
126 126
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index fb20dcd38..cbf5c25b2 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,3 +1,4 @@
1//! Flash memory (FLASH)
1use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; 2use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
2 3
3#[cfg(flash_f4)] 4#[cfg(flash_f4)]
@@ -14,62 +15,96 @@ pub use crate::_generated::flash_regions::*;
14pub use crate::_generated::MAX_ERASE_SIZE; 15pub use crate::_generated::MAX_ERASE_SIZE;
15pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 16pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
16 17
18/// Get whether the default flash layout is being used.
19///
20/// In some chips, dual-bank is not default. This will then return `false`
21/// when dual-bank is enabled.
22pub fn is_default_layout() -> bool {
23 family::is_default_layout()
24}
25
26/// Get all flash regions.
27pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
28 family::get_flash_regions()
29}
30
31/// Read size (always 1)
17pub const READ_SIZE: usize = 1; 32pub const READ_SIZE: usize = 1;
18 33
19pub struct Blocking; 34/// Blocking flash mode typestate.
20pub struct Async; 35pub enum Blocking {}
36/// Async flash mode typestate.
37pub enum Async {}
21 38
39/// Flash memory region
22#[derive(Debug)] 40#[derive(Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))] 41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct FlashRegion { 42pub struct FlashRegion {
43 /// Bank number.
25 pub bank: FlashBank, 44 pub bank: FlashBank,
45 /// Absolute base address.
26 pub base: u32, 46 pub base: u32,
47 /// Size in bytes.
27 pub size: u32, 48 pub size: u32,
49 /// Erase size (sector size).
28 pub erase_size: u32, 50 pub erase_size: u32,
51 /// Minimum write size.
29 pub write_size: u32, 52 pub write_size: u32,
53 /// Erase value (usually `0xFF`, but is `0x00` in some chips)
30 pub erase_value: u8, 54 pub erase_value: u8,
31 pub(crate) _ensure_internal: (), 55 pub(crate) _ensure_internal: (),
32} 56}
33 57
58impl FlashRegion {
59 /// Absolute end address.
60 pub const fn end(&self) -> u32 {
61 self.base + self.size
62 }
63
64 /// Number of sectors in the region.
65 pub const fn sectors(&self) -> u8 {
66 (self.size / self.erase_size) as u8
67 }
68}
69
70/// Flash sector.
34#[derive(Debug, PartialEq)] 71#[derive(Debug, PartialEq)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))] 72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct FlashSector { 73pub struct FlashSector {
74 /// Bank number.
37 pub bank: FlashBank, 75 pub bank: FlashBank,
76 /// Sector number within the bank.
38 pub index_in_bank: u8, 77 pub index_in_bank: u8,
78 /// Absolute start address.
39 pub start: u32, 79 pub start: u32,
80 /// Size in bytes.
40 pub size: u32, 81 pub size: u32,
41} 82}
42 83
84/// Flash bank.
43#[derive(Clone, Copy, Debug, PartialEq)] 85#[derive(Clone, Copy, Debug, PartialEq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))] 86#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub enum FlashBank { 87pub enum FlashBank {
88 /// Bank 1
46 Bank1 = 0, 89 Bank1 = 0,
90 /// Bank 2
47 Bank2 = 1, 91 Bank2 = 1,
92 /// OTP region
48 Otp, 93 Otp,
49} 94}
50 95
51impl FlashRegion {
52 pub const fn end(&self) -> u32 {
53 self.base + self.size
54 }
55
56 pub const fn sectors(&self) -> u8 {
57 (self.size / self.erase_size) as u8
58 }
59}
60
61#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] 96#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
62#[cfg_attr(flash_f0, path = "f0.rs")] 97#[cfg_attr(flash_f0, path = "f0.rs")]
63#[cfg_attr(flash_f3, path = "f3.rs")] 98#[cfg_attr(flash_f3, path = "f3.rs")]
64#[cfg_attr(flash_f4, path = "f4.rs")] 99#[cfg_attr(flash_f4, path = "f4.rs")]
65#[cfg_attr(flash_f7, path = "f7.rs")] 100#[cfg_attr(flash_f7, path = "f7.rs")]
66#[cfg_attr(flash_g0, path = "g0.rs")] 101#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")]
67#[cfg_attr(flash_h7, path = "h7.rs")] 102#[cfg_attr(flash_h7, path = "h7.rs")]
68#[cfg_attr(flash_h7ab, path = "h7.rs")] 103#[cfg_attr(flash_h7ab, path = "h7.rs")]
69#[cfg_attr( 104#[cfg_attr(
70 not(any( 105 not(any(
71 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7, 106 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_g4,
72 flash_h7ab 107 flash_h7, flash_h7ab
73 )), 108 )),
74 path = "other.rs" 109 path = "other.rs"
75)] 110)]
@@ -78,6 +113,10 @@ mod family;
78#[allow(unused_imports)] 113#[allow(unused_imports)]
79pub use family::*; 114pub use family::*;
80 115
116/// Flash error
117///
118/// See STM32 Reference Manual for your chip for details.
119#[allow(missing_docs)]
81#[derive(Debug, Copy, Clone, PartialEq, Eq)] 120#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))] 121#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub enum Error { 122pub enum Error {
diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs
index a7e8d1d57..20f84a72f 100644
--- a/embassy-stm32/src/flash/other.rs
+++ b/embassy-stm32/src/flash/other.rs
@@ -2,11 +2,11 @@
2 2
3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; 3use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
4 4
5pub const fn is_default_layout() -> bool { 5pub(crate) const fn is_default_layout() -> bool {
6 true 6 true
7} 7}
8 8
9pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { 9pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
10 &FLASH_REGIONS 10 &FLASH_REGIONS
11} 11}
12 12
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index dd0d27217..873c8a70c 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -1,3 +1,4 @@
1//! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC)
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_hal_internal::into_ref; 4use embassy_hal_internal::into_ref;
@@ -6,6 +7,7 @@ use crate::gpio::sealed::AFType;
6use crate::gpio::{Pull, Speed}; 7use crate::gpio::{Pull, Speed};
7use crate::Peripheral; 8use crate::Peripheral;
8 9
10/// FMC driver
9pub struct Fmc<'d, T: Instance> { 11pub struct Fmc<'d, T: Instance> {
10 peri: PhantomData<&'d mut T>, 12 peri: PhantomData<&'d mut T>,
11} 13}
@@ -38,6 +40,7 @@ where
38 T::REGS.bcr1().modify(|r| r.set_fmcen(true)); 40 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
39 } 41 }
40 42
43 /// Get the kernel clock currently in use for this FMC instance.
41 pub fn source_clock_hz(&self) -> u32 { 44 pub fn source_clock_hz(&self) -> u32 {
42 <T as crate::rcc::sealed::RccPeripheral>::frequency().0 45 <T as crate::rcc::sealed::RccPeripheral>::frequency().0
43 } 46 }
@@ -85,6 +88,7 @@ macro_rules! fmc_sdram_constructor {
85 nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*], 88 nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*],
86 ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*] 89 ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*]
87 )) => { 90 )) => {
91 /// Create a new FMC instance.
88 pub fn $name<CHIP: stm32_fmc::SdramChip>( 92 pub fn $name<CHIP: stm32_fmc::SdramChip>(
89 _instance: impl Peripheral<P = T> + 'd, 93 _instance: impl Peripheral<P = T> + 'd,
90 $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*, 94 $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*,
@@ -199,6 +203,7 @@ pub(crate) mod sealed {
199 } 203 }
200} 204}
201 205
206/// FMC instance trait.
202pub trait Instance: sealed::Instance + 'static {} 207pub trait Instance: sealed::Instance + 'static {}
203 208
204foreach_peripheral!( 209foreach_peripheral!(
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index b863c4ffe..c300a079e 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -1,3 +1,5 @@
1//! General-purpose Input/Output (GPIO)
2
1#![macro_use] 3#![macro_use]
2use core::convert::Infallible; 4use core::convert::Infallible;
3 5
@@ -29,6 +31,11 @@ impl<'d, T: Pin> Flex<'d, T> {
29 Self { pin } 31 Self { pin }
30 } 32 }
31 33
34 /// Type-erase (degrade) this pin into an `AnyPin`.
35 ///
36 /// This converts pin singletons (`PA5`, `PB6`, ...), which
37 /// are all different types, into the same type. It is useful for
38 /// creating arrays of pins, or avoiding generics.
32 #[inline] 39 #[inline]
33 pub fn degrade(self) -> Flex<'d, AnyPin> { 40 pub fn degrade(self) -> Flex<'d, AnyPin> {
34 // Safety: We are about to drop the other copy of this pin, so 41 // Safety: We are about to drop the other copy of this pin, so
@@ -141,40 +148,55 @@ impl<'d, T: Pin> Flex<'d, T> {
141 }); 148 });
142 } 149 }
143 150
151 /// Get whether the pin input level is high.
152 #[inline]
153 pub fn is_high(&mut self) -> bool {
154 !self.ref_is_low()
155 }
156
157 /// Get whether the pin input level is low.
144 #[inline] 158 #[inline]
145 pub fn is_high(&self) -> bool { 159 pub fn is_low(&mut self) -> bool {
146 !self.is_low() 160 self.ref_is_low()
147 } 161 }
148 162
149 #[inline] 163 #[inline]
150 pub fn is_low(&self) -> bool { 164 pub(crate) fn ref_is_low(&self) -> bool {
151 let state = self.pin.block().idr().read().idr(self.pin.pin() as _); 165 let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
152 state == vals::Idr::LOW 166 state == vals::Idr::LOW
153 } 167 }
154 168
169 /// Get the current pin input level.
155 #[inline] 170 #[inline]
156 pub fn get_level(&self) -> Level { 171 pub fn get_level(&mut self) -> Level {
157 self.is_high().into() 172 self.is_high().into()
158 } 173 }
159 174
175 /// Get whether the output level is set to high.
160 #[inline] 176 #[inline]
161 pub fn is_set_high(&self) -> bool { 177 pub fn is_set_high(&mut self) -> bool {
162 !self.is_set_low() 178 !self.ref_is_set_low()
163 } 179 }
164 180
165 /// Is the output pin set as low? 181 /// Get whether the output level is set to low.
166 #[inline] 182 #[inline]
167 pub fn is_set_low(&self) -> bool { 183 pub fn is_set_low(&mut self) -> bool {
184 self.ref_is_set_low()
185 }
186
187 #[inline]
188 pub(crate) fn ref_is_set_low(&self) -> bool {
168 let state = self.pin.block().odr().read().odr(self.pin.pin() as _); 189 let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
169 state == vals::Odr::LOW 190 state == vals::Odr::LOW
170 } 191 }
171 192
172 /// What level output is set to 193 /// Get the current output level.
173 #[inline] 194 #[inline]
174 pub fn get_output_level(&self) -> Level { 195 pub fn get_output_level(&mut self) -> Level {
175 self.is_set_high().into() 196 self.is_set_high().into()
176 } 197 }
177 198
199 /// Set the output as high.
178 #[inline] 200 #[inline]
179 pub fn set_high(&mut self) { 201 pub fn set_high(&mut self) {
180 self.pin.set_high(); 202 self.pin.set_high();
@@ -186,6 +208,7 @@ impl<'d, T: Pin> Flex<'d, T> {
186 self.pin.set_low(); 208 self.pin.set_low();
187 } 209 }
188 210
211 /// Set the output level.
189 #[inline] 212 #[inline]
190 pub fn set_level(&mut self, level: Level) { 213 pub fn set_level(&mut self, level: Level) {
191 match level { 214 match level {
@@ -194,7 +217,7 @@ impl<'d, T: Pin> Flex<'d, T> {
194 } 217 }
195 } 218 }
196 219
197 /// Toggle pin output 220 /// Toggle the output level.
198 #[inline] 221 #[inline]
199 pub fn toggle(&mut self) { 222 pub fn toggle(&mut self) {
200 if self.is_set_low() { 223 if self.is_set_low() {
@@ -232,8 +255,11 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
232#[derive(Debug, Eq, PartialEq, Copy, Clone)] 255#[derive(Debug, Eq, PartialEq, Copy, Clone)]
233#[cfg_attr(feature = "defmt", derive(defmt::Format))] 256#[cfg_attr(feature = "defmt", derive(defmt::Format))]
234pub enum Pull { 257pub enum Pull {
258 /// No pull
235 None, 259 None,
260 /// Pull up
236 Up, 261 Up,
262 /// Pull down
237 Down, 263 Down,
238} 264}
239 265
@@ -251,6 +277,9 @@ impl From<Pull> for vals::Pupdr {
251} 277}
252 278
253/// Speed settings 279/// Speed settings
280///
281/// These vary dpeending on the chip, ceck the reference manual or datasheet for details.
282#[allow(missing_docs)]
254#[derive(Debug, Copy, Clone)] 283#[derive(Debug, Copy, Clone)]
255#[cfg_attr(feature = "defmt", derive(defmt::Format))] 284#[cfg_attr(feature = "defmt", derive(defmt::Format))]
256pub enum Speed { 285pub enum Speed {
@@ -295,6 +324,7 @@ pub struct Input<'d, T: Pin> {
295} 324}
296 325
297impl<'d, T: Pin> Input<'d, T> { 326impl<'d, T: Pin> Input<'d, T> {
327 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
298 #[inline] 328 #[inline]
299 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 329 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self {
300 let mut pin = Flex::new(pin); 330 let mut pin = Flex::new(pin);
@@ -302,6 +332,11 @@ impl<'d, T: Pin> Input<'d, T> {
302 Self { pin } 332 Self { pin }
303 } 333 }
304 334
335 /// Type-erase (degrade) this pin into an `AnyPin`.
336 ///
337 /// This converts pin singletons (`PA5`, `PB6`, ...), which
338 /// are all different types, into the same type. It is useful for
339 /// creating arrays of pins, or avoiding generics.
305 #[inline] 340 #[inline]
306 pub fn degrade(self) -> Input<'d, AnyPin> { 341 pub fn degrade(self) -> Input<'d, AnyPin> {
307 Input { 342 Input {
@@ -309,18 +344,21 @@ impl<'d, T: Pin> Input<'d, T> {
309 } 344 }
310 } 345 }
311 346
347 /// Get whether the pin input level is high.
312 #[inline] 348 #[inline]
313 pub fn is_high(&self) -> bool { 349 pub fn is_high(&mut self) -> bool {
314 self.pin.is_high() 350 self.pin.is_high()
315 } 351 }
316 352
353 /// Get whether the pin input level is low.
317 #[inline] 354 #[inline]
318 pub fn is_low(&self) -> bool { 355 pub fn is_low(&mut self) -> bool {
319 self.pin.is_low() 356 self.pin.is_low()
320 } 357 }
321 358
359 /// Get the current pin input level.
322 #[inline] 360 #[inline]
323 pub fn get_level(&self) -> Level { 361 pub fn get_level(&mut self) -> Level {
324 self.pin.get_level() 362 self.pin.get_level()
325 } 363 }
326} 364}
@@ -329,7 +367,9 @@ impl<'d, T: Pin> Input<'d, T> {
329#[derive(Debug, Eq, PartialEq, Copy, Clone)] 367#[derive(Debug, Eq, PartialEq, Copy, Clone)]
330#[cfg_attr(feature = "defmt", derive(defmt::Format))] 368#[cfg_attr(feature = "defmt", derive(defmt::Format))]
331pub enum Level { 369pub enum Level {
370 /// Low
332 Low, 371 Low,
372 /// High
333 High, 373 High,
334} 374}
335 375
@@ -361,6 +401,7 @@ pub struct Output<'d, T: Pin> {
361} 401}
362 402
363impl<'d, T: Pin> Output<'d, T> { 403impl<'d, T: Pin> Output<'d, T> {
404 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
364 #[inline] 405 #[inline]
365 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { 406 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self {
366 let mut pin = Flex::new(pin); 407 let mut pin = Flex::new(pin);
@@ -372,6 +413,11 @@ impl<'d, T: Pin> Output<'d, T> {
372 Self { pin } 413 Self { pin }
373 } 414 }
374 415
416 /// Type-erase (degrade) this pin into an `AnyPin`.
417 ///
418 /// This converts pin singletons (`PA5`, `PB6`, ...), which
419 /// are all different types, into the same type. It is useful for
420 /// creating arrays of pins, or avoiding generics.
375 #[inline] 421 #[inline]
376 pub fn degrade(self) -> Output<'d, AnyPin> { 422 pub fn degrade(self) -> Output<'d, AnyPin> {
377 Output { 423 Output {
@@ -399,19 +445,19 @@ impl<'d, T: Pin> Output<'d, T> {
399 445
400 /// Is the output pin set as high? 446 /// Is the output pin set as high?
401 #[inline] 447 #[inline]
402 pub fn is_set_high(&self) -> bool { 448 pub fn is_set_high(&mut self) -> bool {
403 self.pin.is_set_high() 449 self.pin.is_set_high()
404 } 450 }
405 451
406 /// Is the output pin set as low? 452 /// Is the output pin set as low?
407 #[inline] 453 #[inline]
408 pub fn is_set_low(&self) -> bool { 454 pub fn is_set_low(&mut self) -> bool {
409 self.pin.is_set_low() 455 self.pin.is_set_low()
410 } 456 }
411 457
412 /// What level output is set to 458 /// What level output is set to
413 #[inline] 459 #[inline]
414 pub fn get_output_level(&self) -> Level { 460 pub fn get_output_level(&mut self) -> Level {
415 self.pin.get_output_level() 461 self.pin.get_output_level()
416 } 462 }
417 463
@@ -432,6 +478,7 @@ pub struct OutputOpenDrain<'d, T: Pin> {
432} 478}
433 479
434impl<'d, T: Pin> OutputOpenDrain<'d, T> { 480impl<'d, T: Pin> OutputOpenDrain<'d, T> {
481 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration.
435 #[inline] 482 #[inline]
436 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { 483 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
437 let mut pin = Flex::new(pin); 484 let mut pin = Flex::new(pin);
@@ -445,6 +492,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
445 Self { pin } 492 Self { pin }
446 } 493 }
447 494
495 /// Type-erase (degrade) this pin into an `AnyPin`.
496 ///
497 /// This converts pin singletons (`PA5`, `PB6`, ...), which
498 /// are all different types, into the same type. It is useful for
499 /// creating arrays of pins, or avoiding generics.
448 #[inline] 500 #[inline]
449 pub fn degrade(self) -> Output<'d, AnyPin> { 501 pub fn degrade(self) -> Output<'d, AnyPin> {
450 Output { 502 Output {
@@ -452,19 +504,21 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
452 } 504 }
453 } 505 }
454 506
507 /// Get whether the pin input level is high.
455 #[inline] 508 #[inline]
456 pub fn is_high(&self) -> bool { 509 pub fn is_high(&mut self) -> bool {
457 !self.pin.is_low() 510 !self.pin.is_low()
458 } 511 }
459 512
513 /// Get whether the pin input level is low.
460 #[inline] 514 #[inline]
461 pub fn is_low(&self) -> bool { 515 pub fn is_low(&mut self) -> bool {
462 self.pin.is_low() 516 self.pin.is_low()
463 } 517 }
464 518
465 /// Returns current pin level 519 /// Get the current pin input level.
466 #[inline] 520 #[inline]
467 pub fn get_level(&self) -> Level { 521 pub fn get_level(&mut self) -> Level {
468 self.pin.get_level() 522 self.pin.get_level()
469 } 523 }
470 524
@@ -486,21 +540,21 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
486 self.pin.set_level(level); 540 self.pin.set_level(level);
487 } 541 }
488 542
489 /// Is the output pin set as high? 543 /// Get whether the output level is set to high.
490 #[inline] 544 #[inline]
491 pub fn is_set_high(&self) -> bool { 545 pub fn is_set_high(&mut self) -> bool {
492 self.pin.is_set_high() 546 self.pin.is_set_high()
493 } 547 }
494 548
495 /// Is the output pin set as low? 549 /// Get whether the output level is set to low.
496 #[inline] 550 #[inline]
497 pub fn is_set_low(&self) -> bool { 551 pub fn is_set_low(&mut self) -> bool {
498 self.pin.is_set_low() 552 self.pin.is_set_low()
499 } 553 }
500 554
501 /// What level output is set to 555 /// Get the current output level.
502 #[inline] 556 #[inline]
503 pub fn get_output_level(&self) -> Level { 557 pub fn get_output_level(&mut self) -> Level {
504 self.pin.get_output_level() 558 self.pin.get_output_level()
505 } 559 }
506 560
@@ -511,8 +565,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
511 } 565 }
512} 566}
513 567
568/// GPIO output type
514pub enum OutputType { 569pub enum OutputType {
570 /// Drive the pin both high or low.
515 PushPull, 571 PushPull,
572 /// Drive the pin low, or don't drive it at all if the output level is high.
516 OpenDrain, 573 OpenDrain,
517} 574}
518 575
@@ -525,6 +582,7 @@ impl From<OutputType> for sealed::AFType {
525 } 582 }
526} 583}
527 584
585#[allow(missing_docs)]
528pub(crate) mod sealed { 586pub(crate) mod sealed {
529 use super::*; 587 use super::*;
530 588
@@ -532,8 +590,11 @@ pub(crate) mod sealed {
532 #[derive(Debug, Copy, Clone)] 590 #[derive(Debug, Copy, Clone)]
533 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 591 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
534 pub enum AFType { 592 pub enum AFType {
593 /// Input
535 Input, 594 Input,
595 /// Output, drive the pin both high or low.
536 OutputPushPull, 596 OutputPushPull,
597 /// Output, drive the pin low, or don't drive it at all if the output level is high.
537 OutputOpenDrain, 598 OutputOpenDrain,
538 } 599 }
539 600
@@ -676,7 +737,11 @@ pub(crate) mod sealed {
676 } 737 }
677} 738}
678 739
740/// GPIO pin trait.
679pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 741pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
742 /// EXTI channel assigned to this pin.
743 ///
744 /// For example, PC4 uses EXTI4.
680 #[cfg(feature = "exti")] 745 #[cfg(feature = "exti")]
681 type ExtiChannel: crate::exti::Channel; 746 type ExtiChannel: crate::exti::Channel;
682 747
@@ -692,7 +757,11 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
692 self._port() 757 self._port()
693 } 758 }
694 759
695 /// Convert from concrete pin type PX_XX to type erased `AnyPin`. 760 /// Type-erase (degrade) this pin into an `AnyPin`.
761 ///
762 /// This converts pin singletons (`PA5`, `PB6`, ...), which
763 /// are all different types, into the same type. It is useful for
764 /// creating arrays of pins, or avoiding generics.
696 #[inline] 765 #[inline]
697 fn degrade(self) -> AnyPin { 766 fn degrade(self) -> AnyPin {
698 AnyPin { 767 AnyPin {
@@ -701,12 +770,15 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
701 } 770 }
702} 771}
703 772
704// Type-erased GPIO pin 773/// Type-erased GPIO pin
705pub struct AnyPin { 774pub struct AnyPin {
706 pin_port: u8, 775 pin_port: u8,
707} 776}
708 777
709impl AnyPin { 778impl AnyPin {
779 /// Unsafely create an `AnyPin` from a pin+port number.
780 ///
781 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
710 #[inline] 782 #[inline]
711 pub unsafe fn steal(pin_port: u8) -> Self { 783 pub unsafe fn steal(pin_port: u8) -> Self {
712 Self { pin_port } 784 Self { pin_port }
@@ -717,6 +789,8 @@ impl AnyPin {
717 self.pin_port / 16 789 self.pin_port / 16
718 } 790 }
719 791
792 /// Get the GPIO register block for this pin.
793 #[cfg(feature = "unstable-pac")]
720 #[inline] 794 #[inline]
721 pub fn block(&self) -> gpio::Gpio { 795 pub fn block(&self) -> gpio::Gpio {
722 pac::GPIO(self._port() as _) 796 pac::GPIO(self._port() as _)
@@ -777,12 +851,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> {
777 851
778 #[inline] 852 #[inline]
779 fn is_high(&self) -> Result<bool, Self::Error> { 853 fn is_high(&self) -> Result<bool, Self::Error> {
780 Ok(self.is_high()) 854 Ok(!self.pin.ref_is_low())
781 } 855 }
782 856
783 #[inline] 857 #[inline]
784 fn is_low(&self) -> Result<bool, Self::Error> { 858 fn is_low(&self) -> Result<bool, Self::Error> {
785 Ok(self.is_low()) 859 Ok(self.pin.ref_is_low())
786 } 860 }
787} 861}
788 862
@@ -805,13 +879,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> {
805impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { 879impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> {
806 #[inline] 880 #[inline]
807 fn is_set_high(&self) -> Result<bool, Self::Error> { 881 fn is_set_high(&self) -> Result<bool, Self::Error> {
808 Ok(self.is_set_high()) 882 Ok(!self.pin.ref_is_set_low())
809 } 883 }
810 884
811 /// Is the output pin set as low? 885 /// Is the output pin set as low?
812 #[inline] 886 #[inline]
813 fn is_set_low(&self) -> Result<bool, Self::Error> { 887 fn is_set_low(&self) -> Result<bool, Self::Error> {
814 Ok(self.is_set_low()) 888 Ok(self.pin.ref_is_set_low())
815 } 889 }
816} 890}
817 891
@@ -843,13 +917,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d,
843impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { 917impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> {
844 #[inline] 918 #[inline]
845 fn is_set_high(&self) -> Result<bool, Self::Error> { 919 fn is_set_high(&self) -> Result<bool, Self::Error> {
846 Ok(self.is_set_high()) 920 Ok(!self.pin.ref_is_set_low())
847 } 921 }
848 922
849 /// Is the output pin set as low? 923 /// Is the output pin set as low?
850 #[inline] 924 #[inline]
851 fn is_set_low(&self) -> Result<bool, Self::Error> { 925 fn is_set_low(&self) -> Result<bool, Self::Error> {
852 Ok(self.is_set_low()) 926 Ok(self.pin.ref_is_set_low())
853 } 927 }
854} 928}
855 929
@@ -867,12 +941,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> {
867 941
868 #[inline] 942 #[inline]
869 fn is_high(&self) -> Result<bool, Self::Error> { 943 fn is_high(&self) -> Result<bool, Self::Error> {
870 Ok(self.is_high()) 944 Ok(!self.ref_is_low())
871 } 945 }
872 946
873 #[inline] 947 #[inline]
874 fn is_low(&self) -> Result<bool, Self::Error> { 948 fn is_low(&self) -> Result<bool, Self::Error> {
875 Ok(self.is_low()) 949 Ok(self.ref_is_low())
876 } 950 }
877} 951}
878 952
@@ -895,13 +969,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> {
895impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { 969impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> {
896 #[inline] 970 #[inline]
897 fn is_set_high(&self) -> Result<bool, Self::Error> { 971 fn is_set_high(&self) -> Result<bool, Self::Error> {
898 Ok(self.is_set_high()) 972 Ok(!self.ref_is_set_low())
899 } 973 }
900 974
901 /// Is the output pin set as low? 975 /// Is the output pin set as low?
902 #[inline] 976 #[inline]
903 fn is_set_low(&self) -> Result<bool, Self::Error> { 977 fn is_set_low(&self) -> Result<bool, Self::Error> {
904 Ok(self.is_set_low()) 978 Ok(self.ref_is_set_low())
905 } 979 }
906} 980}
907 981
@@ -920,12 +994,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
920 994
921impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { 995impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> {
922 #[inline] 996 #[inline]
923 fn is_high(&self) -> Result<bool, Self::Error> { 997 fn is_high(&mut self) -> Result<bool, Self::Error> {
924 Ok(self.is_high()) 998 Ok(self.is_high())
925 } 999 }
926 1000
927 #[inline] 1001 #[inline]
928 fn is_low(&self) -> Result<bool, Self::Error> { 1002 fn is_low(&mut self) -> Result<bool, Self::Error> {
929 Ok(self.is_low()) 1003 Ok(self.is_low())
930 } 1004 }
931} 1005}
@@ -948,13 +1022,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> {
948 1022
949impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { 1023impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> {
950 #[inline] 1024 #[inline]
951 fn is_set_high(&self) -> Result<bool, Self::Error> { 1025 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
952 Ok(self.is_set_high()) 1026 Ok(self.is_set_high())
953 } 1027 }
954 1028
955 /// Is the output pin set as low? 1029 /// Is the output pin set as low?
956 #[inline] 1030 #[inline]
957 fn is_set_low(&self) -> Result<bool, Self::Error> { 1031 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
958 Ok(self.is_set_low()) 1032 Ok(self.is_set_low())
959 } 1033 }
960} 1034}
@@ -972,12 +1046,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> {
972 1046
973impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { 1047impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> {
974 #[inline] 1048 #[inline]
975 fn is_high(&self) -> Result<bool, Self::Error> { 1049 fn is_high(&mut self) -> Result<bool, Self::Error> {
976 Ok(self.is_high()) 1050 Ok(self.is_high())
977 } 1051 }
978 1052
979 #[inline] 1053 #[inline]
980 fn is_low(&self) -> Result<bool, Self::Error> { 1054 fn is_low(&mut self) -> Result<bool, Self::Error> {
981 Ok(self.is_low()) 1055 Ok(self.is_low())
982 } 1056 }
983} 1057}
@@ -996,13 +1070,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> {
996 1070
997impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { 1071impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> {
998 #[inline] 1072 #[inline]
999 fn is_set_high(&self) -> Result<bool, Self::Error> { 1073 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1000 Ok(self.is_set_high()) 1074 Ok(self.is_set_high())
1001 } 1075 }
1002 1076
1003 /// Is the output pin set as low? 1077 /// Is the output pin set as low?
1004 #[inline] 1078 #[inline]
1005 fn is_set_low(&self) -> Result<bool, Self::Error> { 1079 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1006 Ok(self.is_set_low()) 1080 Ok(self.is_set_low())
1007 } 1081 }
1008} 1082}
@@ -1016,12 +1090,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrai
1016 1090
1017impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { 1091impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> {
1018 #[inline] 1092 #[inline]
1019 fn is_high(&self) -> Result<bool, Self::Error> { 1093 fn is_high(&mut self) -> Result<bool, Self::Error> {
1020 Ok(self.is_high()) 1094 Ok(self.is_high())
1021 } 1095 }
1022 1096
1023 #[inline] 1097 #[inline]
1024 fn is_low(&self) -> Result<bool, Self::Error> { 1098 fn is_low(&mut self) -> Result<bool, Self::Error> {
1025 Ok(self.is_low()) 1099 Ok(self.is_low())
1026 } 1100 }
1027} 1101}
@@ -1051,17 +1125,18 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
1051 1125
1052impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { 1126impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
1053 #[inline] 1127 #[inline]
1054 fn is_set_high(&self) -> Result<bool, Self::Error> { 1128 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1055 Ok(self.is_set_high()) 1129 Ok(self.is_set_high())
1056 } 1130 }
1057 1131
1058 /// Is the output pin set as low? 1132 /// Is the output pin set as low?
1059 #[inline] 1133 #[inline]
1060 fn is_set_low(&self) -> Result<bool, Self::Error> { 1134 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1061 Ok(self.is_set_low()) 1135 Ok(self.is_set_low())
1062 } 1136 }
1063} 1137}
1064 1138
1139/// Low-level GPIO manipulation.
1065#[cfg(feature = "unstable-pac")] 1140#[cfg(feature = "unstable-pac")]
1066pub mod low_level { 1141pub mod low_level {
1067 pub use super::sealed::*; 1142 pub use super::sealed::*;
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 17096d48c..faefaabbc 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -1,3 +1,5 @@
1//! High Resolution Timer (HRTIM)
2
1mod traits; 3mod traits;
2 4
3use core::marker::PhantomData; 5use core::marker::PhantomData;
@@ -13,38 +15,42 @@ use crate::rcc::get_freqs;
13use crate::time::Hertz; 15use crate::time::Hertz;
14use crate::Peripheral; 16use crate::Peripheral;
15 17
16pub enum Source { 18/// HRTIM burst controller instance.
17 Master,
18 ChA,
19 ChB,
20 ChC,
21 ChD,
22 ChE,
23 #[cfg(hrtim_v2)]
24 ChF,
25}
26
27pub struct BurstController<T: Instance> { 19pub struct BurstController<T: Instance> {
28 phantom: PhantomData<T>, 20 phantom: PhantomData<T>,
29} 21}
22
23/// HRTIM master instance.
30pub struct Master<T: Instance> { 24pub struct Master<T: Instance> {
31 phantom: PhantomData<T>, 25 phantom: PhantomData<T>,
32} 26}
27
28/// HRTIM channel A instance.
33pub struct ChA<T: Instance> { 29pub struct ChA<T: Instance> {
34 phantom: PhantomData<T>, 30 phantom: PhantomData<T>,
35} 31}
32
33/// HRTIM channel B instance.
36pub struct ChB<T: Instance> { 34pub struct ChB<T: Instance> {
37 phantom: PhantomData<T>, 35 phantom: PhantomData<T>,
38} 36}
37
38/// HRTIM channel C instance.
39pub struct ChC<T: Instance> { 39pub struct ChC<T: Instance> {
40 phantom: PhantomData<T>, 40 phantom: PhantomData<T>,
41} 41}
42
43/// HRTIM channel D instance.
42pub struct ChD<T: Instance> { 44pub struct ChD<T: Instance> {
43 phantom: PhantomData<T>, 45 phantom: PhantomData<T>,
44} 46}
47
48/// HRTIM channel E instance.
45pub struct ChE<T: Instance> { 49pub struct ChE<T: Instance> {
46 phantom: PhantomData<T>, 50 phantom: PhantomData<T>,
47} 51}
52
53/// HRTIM channel F instance.
48#[cfg(hrtim_v2)] 54#[cfg(hrtim_v2)]
49pub struct ChF<T: Instance> { 55pub struct ChF<T: Instance> {
50 phantom: PhantomData<T>, 56 phantom: PhantomData<T>,
@@ -58,22 +64,26 @@ mod sealed {
58 } 64 }
59} 65}
60 66
67/// Advanced channel instance trait.
61pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} 68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
62 69
63pub struct PwmPin<'d, Perip, Channel> { 70/// HRTIM PWM pin.
71pub struct PwmPin<'d, T, C> {
64 _pin: PeripheralRef<'d, AnyPin>, 72 _pin: PeripheralRef<'d, AnyPin>,
65 phantom: PhantomData<(Perip, Channel)>, 73 phantom: PhantomData<(T, C)>,
66} 74}
67 75
68pub struct ComplementaryPwmPin<'d, Perip, Channel> { 76/// HRTIM complementary PWM pin.
77pub struct ComplementaryPwmPin<'d, T, C> {
69 _pin: PeripheralRef<'d, AnyPin>, 78 _pin: PeripheralRef<'d, AnyPin>,
70 phantom: PhantomData<(Perip, Channel)>, 79 phantom: PhantomData<(T, C)>,
71} 80}
72 81
73macro_rules! advanced_channel_impl { 82macro_rules! advanced_channel_impl {
74 ($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) => {
75 impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { 84 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
76 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
77 into_ref!(pin); 87 into_ref!(pin);
78 critical_section::with(|_| { 88 critical_section::with(|_| {
79 pin.set_low(); 89 pin.set_low();
@@ -88,8 +98,9 @@ macro_rules! advanced_channel_impl {
88 } 98 }
89 } 99 }
90 100
91 impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { 101 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
92 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 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<T>> + 'd) -> Self {
93 into_ref!(pin); 104 into_ref!(pin);
94 critical_section::with(|_| { 105 critical_section::with(|_| {
95 pin.set_low(); 106 pin.set_low();
@@ -124,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin);
124/// Struct used to divide a high resolution timer into multiple channels 135/// Struct used to divide a high resolution timer into multiple channels
125pub struct AdvancedPwm<'d, T: Instance> { 136pub struct AdvancedPwm<'d, T: Instance> {
126 _inner: PeripheralRef<'d, T>, 137 _inner: PeripheralRef<'d, T>,
138 /// Master instance.
127 pub master: Master<T>, 139 pub master: Master<T>,
140 /// Burst controller.
128 pub burst_controller: BurstController<T>, 141 pub burst_controller: BurstController<T>,
142 /// Channel A.
129 pub ch_a: ChA<T>, 143 pub ch_a: ChA<T>,
144 /// Channel B.
130 pub ch_b: ChB<T>, 145 pub ch_b: ChB<T>,
146 /// Channel C.
131 pub ch_c: ChC<T>, 147 pub ch_c: ChC<T>,
148 /// Channel D.
132 pub ch_d: ChD<T>, 149 pub ch_d: ChD<T>,
150 /// Channel E.
133 pub ch_e: ChE<T>, 151 pub ch_e: ChE<T>,
152 /// Channel F.
134 #[cfg(hrtim_v2)] 153 #[cfg(hrtim_v2)]
135 pub ch_f: ChF<T>, 154 pub ch_f: ChF<T>,
136} 155}
137 156
138impl<'d, T: Instance> AdvancedPwm<'d, T> { 157impl<'d, T: Instance> AdvancedPwm<'d, T> {
158 /// Create a new HRTIM driver.
159 ///
160 /// This splits the HRTIM into its constituent parts, which you can then use individually.
139 pub fn new( 161 pub fn new(
140 tim: impl Peripheral<P = T> + 'd, 162 tim: impl Peripheral<P = T> + 'd,
141 _cha: Option<PwmPin<'d, T, ChA<T>>>, 163 _cha: Option<PwmPin<'d, T, ChA<T>>>,
@@ -198,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
198 } 220 }
199} 221}
200 222
201impl<T: Instance> BurstController<T> { 223/// Fixed-frequency bridge converter driver.
202 pub fn set_source(&mut self, _source: Source) {
203 todo!("burst mode control registers not implemented")
204 }
205}
206
207/// Represents a fixed-frequency bridge converter
208/// 224///
209/// Our implementation of the bridge converter uses a single channel and three compare registers, 225/// Our implementation of the bridge converter uses a single channel and three compare registers,
210/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous 226/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
@@ -223,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
223} 239}
224 240
225impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { 241impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
242 /// Create a new HRTIM bridge converter driver.
226 pub fn new(_channel: C, frequency: Hertz) -> Self { 243 pub fn new(_channel: C, frequency: Hertz) -> Self {
227 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; 244 use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
228 245
@@ -279,14 +296,17 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
279 } 296 }
280 } 297 }
281 298
299 /// Start HRTIM.
282 pub fn start(&mut self) { 300 pub fn start(&mut self) {
283 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); 301 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
284 } 302 }
285 303
304 /// Stop HRTIM.
286 pub fn stop(&mut self) { 305 pub fn stop(&mut self) {
287 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); 306 T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
288 } 307 }
289 308
309 /// Enable burst mode.
290 pub fn enable_burst_mode(&mut self) { 310 pub fn enable_burst_mode(&mut self) {
291 T::regs().tim(C::raw()).outr().modify(|w| { 311 T::regs().tim(C::raw()).outr().modify(|w| {
292 // Enable Burst Mode 312 // Enable Burst Mode
@@ -299,6 +319,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
299 }) 319 })
300 } 320 }
301 321
322 /// Disable burst mode.
302 pub fn disable_burst_mode(&mut self) { 323 pub fn disable_burst_mode(&mut self) {
303 T::regs().tim(C::raw()).outr().modify(|w| { 324 T::regs().tim(C::raw()).outr().modify(|w| {
304 // Disable Burst Mode 325 // Disable Burst Mode
@@ -355,7 +376,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
355 } 376 }
356} 377}
357 378
358/// Represents a variable-frequency resonant converter 379/// Variable-frequency resonant converter driver.
359/// 380///
360/// This implementation of a resonsant converter is appropriate for a half or full bridge, 381/// This implementation of a resonsant converter is appropriate for a half or full bridge,
361/// but does not include secondary rectification, which is appropriate for applications 382/// but does not include secondary rectification, which is appropriate for applications
@@ -368,6 +389,7 @@ pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> {
368} 389}
369 390
370impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { 391impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
392 /// Create a new variable-frequency resonant converter driver.
371 pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { 393 pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
372 T::set_channel_frequency(C::raw(), min_frequency); 394 T::set_channel_frequency(C::raw(), min_frequency);
373 395
@@ -406,6 +428,7 @@ impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
406 T::set_channel_dead_time(C::raw(), value); 428 T::set_channel_dead_time(C::raw(), value);
407 } 429 }
408 430
431 /// Set the timer period.
409 pub fn set_period(&mut self, period: u16) { 432 pub fn set_period(&mut self, period: u16) {
410 assert!(period < self.max_period); 433 assert!(period < self.max_period);
411 assert!(period > self.min_period); 434 assert!(period > self.min_period);
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs
index 34a363a1f..cfd31c47c 100644
--- a/embassy-stm32/src/hrtim/traits.rs
+++ b/embassy-stm32/src/hrtim/traits.rs
@@ -125,7 +125,6 @@ pub(crate) mod sealed {
125 } 125 }
126 126
127 /// Set the dead time as a proportion of max_duty 127 /// Set the dead time as a proportion of max_duty
128
129 fn set_channel_dead_time(channel: usize, dead_time: u16) { 128 fn set_channel_dead_time(channel: usize, dead_time: u16) {
130 let regs = Self::regs(); 129 let regs = Self::regs();
131 130
@@ -148,13 +147,10 @@ pub(crate) mod sealed {
148 w.set_dtr(dt_val as u16); 147 w.set_dtr(dt_val as u16);
149 }); 148 });
150 } 149 }
151
152 // fn enable_outputs(enable: bool);
153 //
154 // fn enable_channel(&mut self, channel: usize, enable: bool);
155 } 150 }
156} 151}
157 152
153/// HRTIM instance trait.
158pub trait Instance: sealed::Instance + 'static {} 154pub trait Instance: sealed::Instance + 'static {}
159 155
160foreach_interrupt! { 156foreach_interrupt! {
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index d2a50cf7e..2416005b5 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -1,30 +1,180 @@
1//! Inter-Integrated-Circuit (I2C)
1#![macro_use] 2#![macro_use]
2 3
3use core::marker::PhantomData;
4
5use crate::dma::NoDma;
6use crate::interrupt;
7
8#[cfg_attr(i2c_v1, path = "v1.rs")] 4#[cfg_attr(i2c_v1, path = "v1.rs")]
9#[cfg_attr(i2c_v2, path = "v2.rs")] 5#[cfg_attr(i2c_v2, path = "v2.rs")]
10mod _version; 6mod _version;
11pub use _version::*; 7
8use core::future::Future;
9use core::marker::PhantomData;
10
11use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13#[cfg(feature = "time")]
14use embassy_time::{Duration, Instant};
13 15
14use crate::peripherals; 16use crate::dma::NoDma;
17use crate::gpio::sealed::AFType;
18use crate::gpio::Pull;
19use crate::interrupt::typelevel::Interrupt;
20use crate::time::Hertz;
21use crate::{interrupt, peripherals};
15 22
23/// I2C error.
16#[derive(Debug, PartialEq, Eq)] 24#[derive(Debug, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))] 25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Error { 26pub enum Error {
27 /// Bus error
19 Bus, 28 Bus,
29 /// Arbitration lost
20 Arbitration, 30 Arbitration,
31 /// ACK not received (either to the address or to a data byte)
21 Nack, 32 Nack,
33 /// Timeout
22 Timeout, 34 Timeout,
35 /// CRC error
23 Crc, 36 Crc,
37 /// Overrun error
24 Overrun, 38 Overrun,
39 /// Zero-length transfers are not allowed.
25 ZeroLengthTransfer, 40 ZeroLengthTransfer,
26} 41}
27 42
43/// I2C config
44#[non_exhaustive]
45#[derive(Copy, Clone)]
46pub struct Config {
47 /// Enable internal pullup on SDA.
48 ///
49 /// Using external pullup resistors is recommended for I2C. If you do
50 /// have external pullups you should not enable this.
51 pub sda_pullup: bool,
52 /// Enable internal pullup on SCL.
53 ///
54 /// Using external pullup resistors is recommended for I2C. If you do
55 /// have external pullups you should not enable this.
56 pub scl_pullup: bool,
57 /// Timeout.
58 #[cfg(feature = "time")]
59 pub timeout: embassy_time::Duration,
60}
61
62impl Default for Config {
63 fn default() -> Self {
64 Self {
65 sda_pullup: false,
66 scl_pullup: false,
67 #[cfg(feature = "time")]
68 timeout: embassy_time::Duration::from_millis(1000),
69 }
70 }
71}
72
73/// I2C driver.
74pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
75 _peri: PeripheralRef<'d, T>,
76 #[allow(dead_code)]
77 tx_dma: PeripheralRef<'d, TXDMA>,
78 #[allow(dead_code)]
79 rx_dma: PeripheralRef<'d, RXDMA>,
80 #[cfg(feature = "time")]
81 timeout: Duration,
82}
83
84impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
85 /// Create a new I2C driver.
86 pub fn new(
87 peri: impl Peripheral<P = T> + 'd,
88 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
89 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
90 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
91 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
92 + 'd,
93 tx_dma: impl Peripheral<P = TXDMA> + 'd,
94 rx_dma: impl Peripheral<P = RXDMA> + 'd,
95 freq: Hertz,
96 config: Config,
97 ) -> Self {
98 into_ref!(peri, scl, sda, tx_dma, rx_dma);
99
100 T::enable_and_reset();
101
102 scl.set_as_af_pull(
103 scl.af_num(),
104 AFType::OutputOpenDrain,
105 match config.scl_pullup {
106 true => Pull::Up,
107 false => Pull::None,
108 },
109 );
110 sda.set_as_af_pull(
111 sda.af_num(),
112 AFType::OutputOpenDrain,
113 match config.sda_pullup {
114 true => Pull::Up,
115 false => Pull::None,
116 },
117 );
118
119 unsafe { T::EventInterrupt::enable() };
120 unsafe { T::ErrorInterrupt::enable() };
121
122 let mut this = Self {
123 _peri: peri,
124 tx_dma,
125 rx_dma,
126 #[cfg(feature = "time")]
127 timeout: config.timeout,
128 };
129
130 this.init(freq, config);
131
132 this
133 }
134
135 fn timeout(&self) -> Timeout {
136 Timeout {
137 #[cfg(feature = "time")]
138 deadline: Instant::now() + self.timeout,
139 }
140 }
141}
142
143#[derive(Copy, Clone)]
144struct Timeout {
145 #[cfg(feature = "time")]
146 deadline: Instant,
147}
148
149#[allow(dead_code)]
150impl Timeout {
151 #[inline]
152 fn check(self) -> Result<(), Error> {
153 #[cfg(feature = "time")]
154 if Instant::now() > self.deadline {
155 return Err(Error::Timeout);
156 }
157
158 Ok(())
159 }
160
161 #[inline]
162 fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> {
163 #[cfg(feature = "time")]
164 {
165 use futures::FutureExt;
166
167 embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r {
168 embassy_futures::select::Either::First(_) => Err(Error::Timeout),
169 embassy_futures::select::Either::Second(r) => r,
170 })
171 }
172
173 #[cfg(not(feature = "time"))]
174 fut
175 }
176}
177
28pub(crate) mod sealed { 178pub(crate) mod sealed {
29 use super::*; 179 use super::*;
30 180
@@ -47,8 +197,11 @@ pub(crate) mod sealed {
47 } 197 }
48} 198}
49 199
200/// I2C peripheral instance
50pub trait Instance: sealed::Instance + 'static { 201pub trait Instance: sealed::Instance + 'static {
202 /// Event interrupt for this instance
51 type EventInterrupt: interrupt::typelevel::Interrupt; 203 type EventInterrupt: interrupt::typelevel::Interrupt;
204 /// Error interrupt for this instance
52 type ErrorInterrupt: interrupt::typelevel::Interrupt; 205 type ErrorInterrupt: interrupt::typelevel::Interrupt;
53} 206}
54 207
@@ -57,7 +210,7 @@ pin_trait!(SdaPin, Instance);
57dma_trait!(RxDma, Instance); 210dma_trait!(RxDma, Instance);
58dma_trait!(TxDma, Instance); 211dma_trait!(TxDma, Instance);
59 212
60/// Interrupt handler. 213/// Event interrupt handler.
61pub struct EventInterruptHandler<T: Instance> { 214pub struct EventInterruptHandler<T: Instance> {
62 _phantom: PhantomData<T>, 215 _phantom: PhantomData<T>,
63} 216}
@@ -68,6 +221,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInte
68 } 221 }
69} 222}
70 223
224/// Error interrupt handler.
71pub struct ErrorInterruptHandler<T: Instance> { 225pub struct ErrorInterruptHandler<T: Instance> {
72 _phantom: PhantomData<T>, 226 _phantom: PhantomData<T>,
73} 227}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index b62ee8246..cbbc201de 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -1,21 +1,32 @@
1//! # I2Cv1
2//!
3//! This implementation is used for STM32F1, STM32F2, STM32F4, and STM32L1 devices.
4//!
5//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead.
6
1use core::future::poll_fn; 7use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::task::Poll; 8use core::task::Poll;
4 9
5use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
6use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
7use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
8use embassy_hal_internal::{into_ref, PeripheralRef};
9 13
10use super::*; 14use super::*;
11use crate::dma::{NoDma, Transfer}; 15use crate::dma::Transfer;
12use crate::gpio::sealed::AFType;
13use crate::gpio::Pull;
14use crate::interrupt::typelevel::Interrupt;
15use crate::pac::i2c; 16use crate::pac::i2c;
16use crate::time::Hertz; 17use crate::time::Hertz;
17use crate::{interrupt, Peripheral};
18 18
19// /!\ /!\
20// /!\ Implementation note! /!\
21// /!\ /!\
22//
23// It's somewhat unclear whether using interrupts here in a *strictly* one-shot style is actually
24// what we want! If you are looking in this file because you are doing async I2C and your code is
25// just totally hanging (sometimes), maybe swing by this issue:
26// <https://github.com/embassy-rs/embassy/issues/2372>.
27//
28// There's some more details there, and we might have a fix for you. But please let us know if you
29// hit a case like this!
19pub unsafe fn on_interrupt<T: Instance>() { 30pub unsafe fn on_interrupt<T: Instance>() {
20 let regs = T::regs(); 31 let regs = T::regs();
21 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 32 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
@@ -30,55 +41,8 @@ pub unsafe fn on_interrupt<T: Instance>() {
30 }); 41 });
31} 42}
32 43
33#[non_exhaustive]
34#[derive(Copy, Clone, Default)]
35pub struct Config {
36 pub sda_pullup: bool,
37 pub scl_pullup: bool,
38}
39
40pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
41 phantom: PhantomData<&'d mut T>,
42 #[allow(dead_code)]
43 tx_dma: PeripheralRef<'d, TXDMA>,
44 #[allow(dead_code)]
45 rx_dma: PeripheralRef<'d, RXDMA>,
46}
47
48impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
49 pub fn new( 45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
50 _peri: impl Peripheral<P = T> + 'd,
51 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
52 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
53 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
54 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
55 + 'd,
56 tx_dma: impl Peripheral<P = TXDMA> + 'd,
57 rx_dma: impl Peripheral<P = RXDMA> + 'd,
58 freq: Hertz,
59 config: Config,
60 ) -> Self {
61 into_ref!(scl, sda, tx_dma, rx_dma);
62
63 T::enable_and_reset();
64
65 scl.set_as_af_pull(
66 scl.af_num(),
67 AFType::OutputOpenDrain,
68 match config.scl_pullup {
69 true => Pull::Up,
70 false => Pull::None,
71 },
72 );
73 sda.set_as_af_pull(
74 sda.af_num(),
75 AFType::OutputOpenDrain,
76 match config.sda_pullup {
77 true => Pull::Up,
78 false => Pull::None,
79 },
80 );
81
82 T::regs().cr1().modify(|reg| { 46 T::regs().cr1().modify(|reg| {
83 reg.set_pe(false); 47 reg.set_pe(false);
84 //reg.set_anfoff(false); 48 //reg.set_anfoff(false);
@@ -101,15 +65,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
101 T::regs().cr1().modify(|reg| { 65 T::regs().cr1().modify(|reg| {
102 reg.set_pe(true); 66 reg.set_pe(true);
103 }); 67 });
104
105 unsafe { T::EventInterrupt::enable() };
106 unsafe { T::ErrorInterrupt::enable() };
107
108 Self {
109 phantom: PhantomData,
110 tx_dma,
111 rx_dma,
112 }
113 } 68 }
114 69
115 fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { 70 fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> {
@@ -169,12 +124,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
169 Ok(sr1) 124 Ok(sr1)
170 } 125 }
171 126
172 fn write_bytes( 127 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> {
173 &mut self,
174 addr: u8,
175 bytes: &[u8],
176 check_timeout: impl Fn() -> Result<(), Error>,
177 ) -> Result<(), Error> {
178 // Send a START condition 128 // Send a START condition
179 129
180 T::regs().cr1().modify(|reg| { 130 T::regs().cr1().modify(|reg| {
@@ -183,7 +133,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
183 133
184 // Wait until START condition was generated 134 // Wait until START condition was generated
185 while !Self::check_and_clear_error_flags()?.start() { 135 while !Self::check_and_clear_error_flags()?.start() {
186 check_timeout()?; 136 timeout.check()?;
187 } 137 }
188 138
189 // Also wait until signalled we're master and everything is waiting for us 139 // Also wait until signalled we're master and everything is waiting for us
@@ -193,7 +143,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
193 let sr2 = T::regs().sr2().read(); 143 let sr2 = T::regs().sr2().read();
194 !sr2.msl() && !sr2.busy() 144 !sr2.msl() && !sr2.busy()
195 } { 145 } {
196 check_timeout()?; 146 timeout.check()?;
197 } 147 }
198 148
199 // Set up current address, we're trying to talk to 149 // Set up current address, we're trying to talk to
@@ -203,7 +153,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
203 // Wait for the address to be acknowledged 153 // Wait for the address to be acknowledged
204 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 154 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
205 while !Self::check_and_clear_error_flags()?.addr() { 155 while !Self::check_and_clear_error_flags()?.addr() {
206 check_timeout()?; 156 timeout.check()?;
207 } 157 }
208 158
209 // Clear condition by reading SR2 159 // Clear condition by reading SR2
@@ -211,20 +161,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
211 161
212 // Send bytes 162 // Send bytes
213 for c in bytes { 163 for c in bytes {
214 self.send_byte(*c, &check_timeout)?; 164 self.send_byte(*c, timeout)?;
215 } 165 }
216 166
217 // Fallthrough is success 167 // Fallthrough is success
218 Ok(()) 168 Ok(())
219 } 169 }
220 170
221 fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 171 fn send_byte(&self, byte: u8, timeout: Timeout) -> Result<(), Error> {
222 // Wait until we're ready for sending 172 // Wait until we're ready for sending
223 while { 173 while {
224 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. 174 // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
225 !Self::check_and_clear_error_flags()?.txe() 175 !Self::check_and_clear_error_flags()?.txe()
226 } { 176 } {
227 check_timeout()?; 177 timeout.check()?;
228 } 178 }
229 179
230 // Push out a byte of data 180 // Push out a byte of data
@@ -235,32 +185,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
235 // Check for any potential error conditions. 185 // Check for any potential error conditions.
236 !Self::check_and_clear_error_flags()?.btf() 186 !Self::check_and_clear_error_flags()?.btf()
237 } { 187 } {
238 check_timeout()?; 188 timeout.check()?;
239 } 189 }
240 190
241 Ok(()) 191 Ok(())
242 } 192 }
243 193
244 fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { 194 fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> {
245 while { 195 while {
246 // Check for any potential error conditions. 196 // Check for any potential error conditions.
247 Self::check_and_clear_error_flags()?; 197 Self::check_and_clear_error_flags()?;
248 198
249 !T::regs().sr1().read().rxne() 199 !T::regs().sr1().read().rxne()
250 } { 200 } {
251 check_timeout()?; 201 timeout.check()?;
252 } 202 }
253 203
254 let value = T::regs().dr().read().dr(); 204 let value = T::regs().dr().read().dr();
255 Ok(value) 205 Ok(value)
256 } 206 }
257 207
258 pub fn blocking_read_timeout( 208 fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> {
259 &mut self,
260 addr: u8,
261 buffer: &mut [u8],
262 check_timeout: impl Fn() -> Result<(), Error>,
263 ) -> Result<(), Error> {
264 if let Some((last, buffer)) = buffer.split_last_mut() { 209 if let Some((last, buffer)) = buffer.split_last_mut() {
265 // Send a START condition and set ACK bit 210 // Send a START condition and set ACK bit
266 T::regs().cr1().modify(|reg| { 211 T::regs().cr1().modify(|reg| {
@@ -270,7 +215,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
270 215
271 // Wait until START condition was generated 216 // Wait until START condition was generated
272 while !Self::check_and_clear_error_flags()?.start() { 217 while !Self::check_and_clear_error_flags()?.start() {
273 check_timeout()?; 218 timeout.check()?;
274 } 219 }
275 220
276 // Also wait until signalled we're master and everything is waiting for us 221 // Also wait until signalled we're master and everything is waiting for us
@@ -278,7 +223,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
278 let sr2 = T::regs().sr2().read(); 223 let sr2 = T::regs().sr2().read();
279 !sr2.msl() && !sr2.busy() 224 !sr2.msl() && !sr2.busy()
280 } { 225 } {
281 check_timeout()?; 226 timeout.check()?;
282 } 227 }
283 228
284 // Set up current address, we're trying to talk to 229 // Set up current address, we're trying to talk to
@@ -287,7 +232,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
287 // Wait until address was sent 232 // Wait until address was sent
288 // Wait for the address to be acknowledged 233 // Wait for the address to be acknowledged
289 while !Self::check_and_clear_error_flags()?.addr() { 234 while !Self::check_and_clear_error_flags()?.addr() {
290 check_timeout()?; 235 timeout.check()?;
291 } 236 }
292 237
293 // Clear condition by reading SR2 238 // Clear condition by reading SR2
@@ -295,7 +240,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
295 240
296 // Receive bytes into buffer 241 // Receive bytes into buffer
297 for c in buffer { 242 for c in buffer {
298 *c = self.recv_byte(&check_timeout)?; 243 *c = self.recv_byte(timeout)?;
299 } 244 }
300 245
301 // Prepare to send NACK then STOP after next byte 246 // Prepare to send NACK then STOP after next byte
@@ -305,11 +250,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
305 }); 250 });
306 251
307 // Receive last byte 252 // Receive last byte
308 *last = self.recv_byte(&check_timeout)?; 253 *last = self.recv_byte(timeout)?;
309 254
310 // Wait for the STOP to be sent. 255 // Wait for the STOP to be sent.
311 while T::regs().cr1().read().stop() { 256 while T::regs().cr1().read().stop() {
312 check_timeout()?; 257 timeout.check()?;
313 } 258 }
314 259
315 // Fallthrough is success 260 // Fallthrough is success
@@ -319,49 +264,37 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
319 } 264 }
320 } 265 }
321 266
267 /// Blocking read.
322 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 268 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
323 self.blocking_read_timeout(addr, read, || Ok(())) 269 self.blocking_read_timeout(addr, read, self.timeout())
324 } 270 }
325 271
326 pub fn blocking_write_timeout( 272 /// Blocking write.
327 &mut self, 273 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
328 addr: u8, 274 let timeout = self.timeout();
329 write: &[u8], 275
330 check_timeout: impl Fn() -> Result<(), Error>, 276 self.write_bytes(addr, write, timeout)?;
331 ) -> Result<(), Error> {
332 self.write_bytes(addr, write, &check_timeout)?;
333 // Send a STOP condition 277 // Send a STOP condition
334 T::regs().cr1().modify(|reg| reg.set_stop(true)); 278 T::regs().cr1().modify(|reg| reg.set_stop(true));
335 // Wait for STOP condition to transmit. 279 // Wait for STOP condition to transmit.
336 while T::regs().cr1().read().stop() { 280 while T::regs().cr1().read().stop() {
337 check_timeout()?; 281 timeout.check()?;
338 } 282 }
339 283
340 // Fallthrough is success 284 // Fallthrough is success
341 Ok(()) 285 Ok(())
342 } 286 }
343 287
344 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 288 /// Blocking write, restart, read.
345 self.blocking_write_timeout(addr, write, || Ok(())) 289 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
346 } 290 let timeout = self.timeout();
347 291
348 pub fn blocking_write_read_timeout( 292 self.write_bytes(addr, write, timeout)?;
349 &mut self, 293 self.blocking_read_timeout(addr, read, timeout)?;
350 addr: u8,
351 write: &[u8],
352 read: &mut [u8],
353 check_timeout: impl Fn() -> Result<(), Error>,
354 ) -> Result<(), Error> {
355 self.write_bytes(addr, write, &check_timeout)?;
356 self.blocking_read_timeout(addr, read, &check_timeout)?;
357 294
358 Ok(()) 295 Ok(())
359 } 296 }
360 297
361 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
362 self.blocking_write_read_timeout(addr, write, read, || Ok(()))
363 }
364
365 // Async 298 // Async
366 299
367 #[inline] // pretty sure this should always be inlined 300 #[inline] // pretty sure this should always be inlined
@@ -459,6 +392,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
459 T::regs().sr2().read(); 392 T::regs().sr2().read();
460 Poll::Ready(Ok(())) 393 Poll::Ready(Ok(()))
461 } else { 394 } else {
395 // If we need to go around, then re-enable the interrupts, otherwise nothing
396 // can wake us up and we'll hang.
397 Self::enable_interrupts();
462 Poll::Pending 398 Poll::Pending
463 } 399 }
464 } 400 }
@@ -522,6 +458,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
522 Ok(()) 458 Ok(())
523 } 459 }
524 460
461 /// Write.
525 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 462 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
526 where 463 where
527 TXDMA: crate::i2c::TxDma<T>, 464 TXDMA: crate::i2c::TxDma<T>,
@@ -544,6 +481,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
544 Ok(()) 481 Ok(())
545 } 482 }
546 483
484 /// Read.
547 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 485 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
548 where 486 where
549 RXDMA: crate::i2c::RxDma<T>, 487 RXDMA: crate::i2c::RxDma<T>,
@@ -703,6 +641,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
703 Ok(()) 641 Ok(())
704 } 642 }
705 643
644 /// Write, restart, read.
706 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 645 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
707 where 646 where
708 RXDMA: crate::i2c::RxDma<T>, 647 RXDMA: crate::i2c::RxDma<T>,
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 8c20e1c54..bd3abaac1 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -4,37 +4,13 @@ use core::task::Poll;
4 4
5use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
6use embassy_hal_internal::drop::OnDrop; 6use embassy_hal_internal::drop::OnDrop;
7use embassy_hal_internal::{into_ref, PeripheralRef};
8#[cfg(feature = "time")]
9use embassy_time::{Duration, Instant};
10 7
11use super::*; 8use super::*;
12use crate::dma::{NoDma, Transfer}; 9use crate::dma::Transfer;
13use crate::gpio::sealed::AFType;
14use crate::gpio::Pull;
15use crate::interrupt::typelevel::Interrupt;
16use crate::pac::i2c; 10use crate::pac::i2c;
17use crate::time::Hertz; 11use crate::time::Hertz;
18use crate::{interrupt, Peripheral};
19
20#[cfg(feature = "time")]
21fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
22 let deadline = Instant::now() + timeout;
23 move || {
24 if Instant::now() > deadline {
25 Err(Error::Timeout)
26 } else {
27 Ok(())
28 }
29 }
30}
31
32#[cfg(not(feature = "time"))]
33pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> {
34 move || Ok(())
35}
36 12
37pub unsafe fn on_interrupt<T: Instance>() { 13pub(crate) unsafe fn on_interrupt<T: Instance>() {
38 let regs = T::regs(); 14 let regs = T::regs();
39 let isr = regs.isr().read(); 15 let isr = regs.isr().read();
40 16
@@ -48,70 +24,8 @@ pub unsafe fn on_interrupt<T: Instance>() {
48 }); 24 });
49} 25}
50 26
51#[non_exhaustive]
52#[derive(Copy, Clone)]
53pub struct Config {
54 pub sda_pullup: bool,
55 pub scl_pullup: bool,
56 #[cfg(feature = "time")]
57 pub transaction_timeout: Duration,
58}
59
60impl Default for Config {
61 fn default() -> Self {
62 Self {
63 sda_pullup: false,
64 scl_pullup: false,
65 #[cfg(feature = "time")]
66 transaction_timeout: Duration::from_millis(100),
67 }
68 }
69}
70
71pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
72 _peri: PeripheralRef<'d, T>,
73 #[allow(dead_code)]
74 tx_dma: PeripheralRef<'d, TXDMA>,
75 #[allow(dead_code)]
76 rx_dma: PeripheralRef<'d, RXDMA>,
77 #[cfg(feature = "time")]
78 timeout: Duration,
79}
80
81impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 27impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
82 pub fn new( 28 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
83 peri: impl Peripheral<P = T> + 'd,
84 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
85 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
86 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
87 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
88 + 'd,
89 tx_dma: impl Peripheral<P = TXDMA> + 'd,
90 rx_dma: impl Peripheral<P = RXDMA> + 'd,
91 freq: Hertz,
92 config: Config,
93 ) -> Self {
94 into_ref!(peri, scl, sda, tx_dma, rx_dma);
95
96 T::enable_and_reset();
97
98 scl.set_as_af_pull(
99 scl.af_num(),
100 AFType::OutputOpenDrain,
101 match config.scl_pullup {
102 true => Pull::Up,
103 false => Pull::None,
104 },
105 );
106 sda.set_as_af_pull(
107 sda.af_num(),
108 AFType::OutputOpenDrain,
109 match config.sda_pullup {
110 true => Pull::Up,
111 false => Pull::None,
112 },
113 );
114
115 T::regs().cr1().modify(|reg| { 29 T::regs().cr1().modify(|reg| {
116 reg.set_pe(false); 30 reg.set_pe(false);
117 reg.set_anfoff(false); 31 reg.set_anfoff(false);
@@ -130,17 +44,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
130 T::regs().cr1().modify(|reg| { 44 T::regs().cr1().modify(|reg| {
131 reg.set_pe(true); 45 reg.set_pe(true);
132 }); 46 });
133
134 unsafe { T::EventInterrupt::enable() };
135 unsafe { T::ErrorInterrupt::enable() };
136
137 Self {
138 _peri: peri,
139 tx_dma,
140 rx_dma,
141 #[cfg(feature = "time")]
142 timeout: config.transaction_timeout,
143 }
144 } 47 }
145 48
146 fn master_stop(&mut self) { 49 fn master_stop(&mut self) {
@@ -153,7 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
153 stop: Stop, 56 stop: Stop,
154 reload: bool, 57 reload: bool,
155 restart: bool, 58 restart: bool,
156 check_timeout: impl Fn() -> Result<(), Error>, 59 timeout: Timeout,
157 ) -> Result<(), Error> { 60 ) -> Result<(), Error> {
158 assert!(length < 256); 61 assert!(length < 256);
159 62
@@ -162,7 +65,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
162 // automatically. This could be up to 50% of a bus 65 // automatically. This could be up to 50% of a bus
163 // cycle (ie. up to 0.5/freq) 66 // cycle (ie. up to 0.5/freq)
164 while T::regs().cr2().read().start() { 67 while T::regs().cr2().read().start() {
165 check_timeout()?; 68 timeout.check()?;
166 } 69 }
167 } 70 }
168 71
@@ -189,20 +92,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
189 Ok(()) 92 Ok(())
190 } 93 }
191 94
192 fn master_write( 95 fn master_write(address: u8, length: usize, stop: Stop, reload: bool, timeout: Timeout) -> Result<(), Error> {
193 address: u8,
194 length: usize,
195 stop: Stop,
196 reload: bool,
197 check_timeout: impl Fn() -> Result<(), Error>,
198 ) -> Result<(), Error> {
199 assert!(length < 256); 96 assert!(length < 256);
200 97
201 // Wait for any previous address sequence to end 98 // Wait for any previous address sequence to end
202 // automatically. This could be up to 50% of a bus 99 // automatically. This could be up to 50% of a bus
203 // cycle (ie. up to 0.5/freq) 100 // cycle (ie. up to 0.5/freq)
204 while T::regs().cr2().read().start() { 101 while T::regs().cr2().read().start() {
205 check_timeout()?; 102 timeout.check()?;
206 } 103 }
207 104
208 let reload = if reload { 105 let reload = if reload {
@@ -227,15 +124,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
227 Ok(()) 124 Ok(())
228 } 125 }
229 126
230 fn master_continue( 127 fn master_continue(length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> {
231 length: usize,
232 reload: bool,
233 check_timeout: impl Fn() -> Result<(), Error>,
234 ) -> Result<(), Error> {
235 assert!(length < 256 && length > 0); 128 assert!(length < 256 && length > 0);
236 129
237 while !T::regs().isr().read().tcr() { 130 while !T::regs().isr().read().tcr() {
238 check_timeout()?; 131 timeout.check()?;
239 } 132 }
240 133
241 let reload = if reload { 134 let reload = if reload {
@@ -261,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
261 } 154 }
262 } 155 }
263 156
264 fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 157 fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> {
265 loop { 158 loop {
266 let isr = T::regs().isr().read(); 159 let isr = T::regs().isr().read();
267 if isr.txe() { 160 if isr.txe() {
@@ -278,11 +171,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
278 return Err(Error::Nack); 171 return Err(Error::Nack);
279 } 172 }
280 173
281 check_timeout()?; 174 timeout.check()?;
282 } 175 }
283 } 176 }
284 177
285 fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 178 fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> {
286 loop { 179 loop {
287 let isr = T::regs().isr().read(); 180 let isr = T::regs().isr().read();
288 if isr.rxne() { 181 if isr.rxne() {
@@ -299,11 +192,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
299 return Err(Error::Nack); 192 return Err(Error::Nack);
300 } 193 }
301 194
302 check_timeout()?; 195 timeout.check()?;
303 } 196 }
304 } 197 }
305 198
306 fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { 199 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> {
307 loop { 200 loop {
308 let isr = T::regs().isr().read(); 201 let isr = T::regs().isr().read();
309 if isr.tc() { 202 if isr.tc() {
@@ -320,17 +213,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
320 return Err(Error::Nack); 213 return Err(Error::Nack);
321 } 214 }
322 215
323 check_timeout()?; 216 timeout.check()?;
324 } 217 }
325 } 218 }
326 219
327 fn read_internal( 220 fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> {
328 &mut self,
329 address: u8,
330 read: &mut [u8],
331 restart: bool,
332 check_timeout: impl Fn() -> Result<(), Error>,
333 ) -> Result<(), Error> {
334 let completed_chunks = read.len() / 255; 221 let completed_chunks = read.len() / 255;
335 let total_chunks = if completed_chunks * 255 == read.len() { 222 let total_chunks = if completed_chunks * 255 == read.len() {
336 completed_chunks 223 completed_chunks
@@ -345,17 +232,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
345 Stop::Automatic, 232 Stop::Automatic,
346 last_chunk_idx != 0, 233 last_chunk_idx != 0,
347 restart, 234 restart,
348 &check_timeout, 235 timeout,
349 )?; 236 )?;
350 237
351 for (number, chunk) in read.chunks_mut(255).enumerate() { 238 for (number, chunk) in read.chunks_mut(255).enumerate() {
352 if number != 0 { 239 if number != 0 {
353 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; 240 Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?;
354 } 241 }
355 242
356 for byte in chunk { 243 for byte in chunk {
357 // Wait until we have received something 244 // Wait until we have received something
358 self.wait_rxne(&check_timeout)?; 245 self.wait_rxne(timeout)?;
359 246
360 *byte = T::regs().rxdr().read().rxdata(); 247 *byte = T::regs().rxdr().read().rxdata();
361 } 248 }
@@ -363,13 +250,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
363 Ok(()) 250 Ok(())
364 } 251 }
365 252
366 fn write_internal( 253 fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> {
367 &mut self,
368 address: u8,
369 write: &[u8],
370 send_stop: bool,
371 check_timeout: impl Fn() -> Result<(), Error>,
372 ) -> Result<(), Error> {
373 let completed_chunks = write.len() / 255; 254 let completed_chunks = write.len() / 255;
374 let total_chunks = if completed_chunks * 255 == write.len() { 255 let total_chunks = if completed_chunks * 255 == write.len() {
375 completed_chunks 256 completed_chunks
@@ -386,7 +267,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
386 write.len().min(255), 267 write.len().min(255),
387 Stop::Software, 268 Stop::Software,
388 last_chunk_idx != 0, 269 last_chunk_idx != 0,
389 &check_timeout, 270 timeout,
390 ) { 271 ) {
391 if send_stop { 272 if send_stop {
392 self.master_stop(); 273 self.master_stop();
@@ -396,14 +277,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
396 277
397 for (number, chunk) in write.chunks(255).enumerate() { 278 for (number, chunk) in write.chunks(255).enumerate() {
398 if number != 0 { 279 if number != 0 {
399 Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; 280 Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?;
400 } 281 }
401 282
402 for byte in chunk { 283 for byte in chunk {
403 // Wait until we are allowed to send data 284 // Wait until we are allowed to send data
404 // (START has been ACKed or last byte when 285 // (START has been ACKed or last byte when
405 // through) 286 // through)
406 if let Err(err) = self.wait_txe(&check_timeout) { 287 if let Err(err) = self.wait_txe(timeout) {
407 if send_stop { 288 if send_stop {
408 self.master_stop(); 289 self.master_stop();
409 } 290 }
@@ -414,7 +295,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
414 } 295 }
415 } 296 }
416 // Wait until the write finishes 297 // Wait until the write finishes
417 let result = self.wait_tc(&check_timeout); 298 let result = self.wait_tc(timeout);
418 if send_stop { 299 if send_stop {
419 self.master_stop(); 300 self.master_stop();
420 } 301 }
@@ -427,7 +308,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
427 write: &[u8], 308 write: &[u8],
428 first_slice: bool, 309 first_slice: bool,
429 last_slice: bool, 310 last_slice: bool,
430 check_timeout: impl Fn() -> Result<(), Error>, 311 timeout: Timeout,
431 ) -> Result<(), Error> 312 ) -> Result<(), Error>
432 where 313 where
433 TXDMA: crate::i2c::TxDma<T>, 314 TXDMA: crate::i2c::TxDma<T>,
@@ -473,10 +354,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
473 total_len.min(255), 354 total_len.min(255),
474 Stop::Software, 355 Stop::Software,
475 (total_len > 255) || !last_slice, 356 (total_len > 255) || !last_slice,
476 &check_timeout, 357 timeout,
477 )?; 358 )?;
478 } else { 359 } else {
479 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; 360 Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?;
480 T::regs().cr1().modify(|w| w.set_tcie(true)); 361 T::regs().cr1().modify(|w| w.set_tcie(true));
481 } 362 }
482 } else if !(isr.tcr() || isr.tc()) { 363 } else if !(isr.tcr() || isr.tc()) {
@@ -487,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
487 } else { 368 } else {
488 let last_piece = (remaining_len <= 255) && last_slice; 369 let last_piece = (remaining_len <= 255) && last_slice;
489 370
490 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { 371 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
491 return Poll::Ready(Err(e)); 372 return Poll::Ready(Err(e));
492 } 373 }
493 T::regs().cr1().modify(|w| w.set_tcie(true)); 374 T::regs().cr1().modify(|w| w.set_tcie(true));
@@ -502,7 +383,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
502 383
503 if last_slice { 384 if last_slice {
504 // This should be done already 385 // This should be done already
505 self.wait_tc(&check_timeout)?; 386 self.wait_tc(timeout)?;
506 self.master_stop(); 387 self.master_stop();
507 } 388 }
508 389
@@ -516,7 +397,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
516 address: u8, 397 address: u8,
517 buffer: &mut [u8], 398 buffer: &mut [u8],
518 restart: bool, 399 restart: bool,
519 check_timeout: impl Fn() -> Result<(), Error>, 400 timeout: Timeout,
520 ) -> Result<(), Error> 401 ) -> Result<(), Error>
521 where 402 where
522 RXDMA: crate::i2c::RxDma<T>, 403 RXDMA: crate::i2c::RxDma<T>,
@@ -558,7 +439,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
558 Stop::Software, 439 Stop::Software,
559 total_len > 255, 440 total_len > 255,
560 restart, 441 restart,
561 &check_timeout, 442 timeout,
562 )?; 443 )?;
563 } else if !(isr.tcr() || isr.tc()) { 444 } else if !(isr.tcr() || isr.tc()) {
564 // poll_fn was woken without an interrupt present 445 // poll_fn was woken without an interrupt present
@@ -568,7 +449,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
568 } else { 449 } else {
569 let last_piece = remaining_len <= 255; 450 let last_piece = remaining_len <= 255;
570 451
571 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { 452 if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
572 return Poll::Ready(Err(e)); 453 return Poll::Ready(Err(e));
573 } 454 }
574 T::regs().cr1().modify(|w| w.set_tcie(true)); 455 T::regs().cr1().modify(|w| w.set_tcie(true));
@@ -582,7 +463,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
582 dma_transfer.await; 463 dma_transfer.await;
583 464
584 // This should be done already 465 // This should be done already
585 self.wait_tc(&check_timeout)?; 466 self.wait_tc(timeout)?;
586 self.master_stop(); 467 self.master_stop();
587 468
588 drop(on_drop); 469 drop(on_drop);
@@ -592,69 +473,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
592 473
593 // ========================= 474 // =========================
594 // Async public API 475 // Async public API
595 #[cfg(feature = "time")]
596 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
597 where
598 TXDMA: crate::i2c::TxDma<T>,
599 {
600 if write.is_empty() {
601 self.write_internal(address, write, true, timeout_fn(self.timeout))
602 } else {
603 embassy_time::with_timeout(
604 self.timeout,
605 self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)),
606 )
607 .await
608 .unwrap_or(Err(Error::Timeout))
609 }
610 }
611 476
612 #[cfg(not(feature = "time"))] 477 /// Write.
613 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> 478 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
614 where 479 where
615 TXDMA: crate::i2c::TxDma<T>, 480 TXDMA: crate::i2c::TxDma<T>,
616 { 481 {
482 let timeout = self.timeout();
617 if write.is_empty() { 483 if write.is_empty() {
618 self.write_internal(address, write, true, no_timeout_fn()) 484 self.write_internal(address, write, true, timeout)
619 } else { 485 } else {
620 self.write_dma_internal(address, write, true, true, no_timeout_fn()) 486 timeout
487 .with(self.write_dma_internal(address, write, true, true, timeout))
621 .await 488 .await
622 } 489 }
623 } 490 }
624 491
625 #[cfg(feature = "time")] 492 /// Write multiple buffers.
493 ///
494 /// The buffers are concatenated in a single write transaction.
626 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> 495 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
627 where 496 where
628 TXDMA: crate::i2c::TxDma<T>, 497 TXDMA: crate::i2c::TxDma<T>,
629 { 498 {
630 if write.is_empty() { 499 let timeout = self.timeout();
631 return Err(Error::ZeroLengthTransfer);
632 }
633 let mut iter = write.iter();
634
635 let mut first = true;
636 let mut current = iter.next();
637 while let Some(c) = current {
638 let next = iter.next();
639 let is_last = next.is_none();
640
641 embassy_time::with_timeout(
642 self.timeout,
643 self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)),
644 )
645 .await
646 .unwrap_or(Err(Error::Timeout))?;
647 first = false;
648 current = next;
649 }
650 Ok(())
651 }
652 500
653 #[cfg(not(feature = "time"))]
654 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
655 where
656 TXDMA: crate::i2c::TxDma<T>,
657 {
658 if write.is_empty() { 501 if write.is_empty() {
659 return Err(Error::ZeroLengthTransfer); 502 return Err(Error::ZeroLengthTransfer);
660 } 503 }
@@ -666,95 +509,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
666 let next = iter.next(); 509 let next = iter.next();
667 let is_last = next.is_none(); 510 let is_last = next.is_none();
668 511
669 self.write_dma_internal(address, c, first, is_last, no_timeout_fn()) 512 let fut = self.write_dma_internal(address, c, first, is_last, timeout);
670 .await?; 513 timeout.with(fut).await?;
671 first = false; 514 first = false;
672 current = next; 515 current = next;
673 } 516 }
674 Ok(()) 517 Ok(())
675 } 518 }
676 519
677 #[cfg(feature = "time")] 520 /// Read.
678 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> 521 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
679 where 522 where
680 RXDMA: crate::i2c::RxDma<T>, 523 RXDMA: crate::i2c::RxDma<T>,
681 { 524 {
682 if buffer.is_empty() { 525 let timeout = self.timeout();
683 self.read_internal(address, buffer, false, timeout_fn(self.timeout))
684 } else {
685 embassy_time::with_timeout(
686 self.timeout,
687 self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)),
688 )
689 .await
690 .unwrap_or(Err(Error::Timeout))
691 }
692 }
693 526
694 #[cfg(not(feature = "time"))]
695 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
696 where
697 RXDMA: crate::i2c::RxDma<T>,
698 {
699 if buffer.is_empty() { 527 if buffer.is_empty() {
700 self.read_internal(address, buffer, false, no_timeout_fn()) 528 self.read_internal(address, buffer, false, timeout)
701 } else { 529 } else {
702 self.read_dma_internal(address, buffer, false, no_timeout_fn()).await 530 let fut = self.read_dma_internal(address, buffer, false, timeout);
531 timeout.with(fut).await
703 } 532 }
704 } 533 }
705 534
706 #[cfg(feature = "time")] 535 /// Write, restart, read.
707 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> 536 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
708 where 537 where
709 TXDMA: super::TxDma<T>, 538 TXDMA: super::TxDma<T>,
710 RXDMA: super::RxDma<T>, 539 RXDMA: super::RxDma<T>,
711 { 540 {
712 let start_instant = Instant::now(); 541 let timeout = self.timeout();
713 let check_timeout = timeout_fn(self.timeout);
714 if write.is_empty() {
715 self.write_internal(address, write, false, &check_timeout)?;
716 } else {
717 embassy_time::with_timeout(
718 self.timeout,
719 self.write_dma_internal(address, write, true, true, &check_timeout),
720 )
721 .await
722 .unwrap_or(Err(Error::Timeout))?;
723 }
724
725 let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant);
726 542
727 if read.is_empty() {
728 self.read_internal(address, read, true, &check_timeout)?;
729 } else {
730 embassy_time::with_timeout(
731 time_left_until_timeout,
732 self.read_dma_internal(address, read, true, &check_timeout),
733 )
734 .await
735 .unwrap_or(Err(Error::Timeout))?;
736 }
737
738 Ok(())
739 }
740
741 #[cfg(not(feature = "time"))]
742 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
743 where
744 TXDMA: super::TxDma<T>,
745 RXDMA: super::RxDma<T>,
746 {
747 let no_timeout = no_timeout_fn();
748 if write.is_empty() { 543 if write.is_empty() {
749 self.write_internal(address, write, false, &no_timeout)?; 544 self.write_internal(address, write, false, timeout)?;
750 } else { 545 } else {
751 self.write_dma_internal(address, write, true, true, &no_timeout).await?; 546 let fut = self.write_dma_internal(address, write, true, true, timeout);
547 timeout.with(fut).await?;
752 } 548 }
753 549
754 if read.is_empty() { 550 if read.is_empty() {
755 self.read_internal(address, read, true, &no_timeout)?; 551 self.read_internal(address, read, true, timeout)?;
756 } else { 552 } else {
757 self.read_dma_internal(address, read, true, &no_timeout).await?; 553 let fut = self.read_dma_internal(address, read, true, timeout);
554 timeout.with(fut).await?;
758 } 555 }
759 556
760 Ok(()) 557 Ok(())
@@ -763,105 +560,35 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
763 // ========================= 560 // =========================
764 // Blocking public API 561 // Blocking public API
765 562
766 #[cfg(feature = "time")] 563 /// Blocking read.
767 pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> {
768 self.read_internal(address, read, false, timeout_fn(timeout))
769 // Automatic Stop
770 }
771
772 #[cfg(not(feature = "time"))]
773 pub fn blocking_read_timeout(
774 &mut self,
775 address: u8,
776 read: &mut [u8],
777 check_timeout: impl Fn() -> Result<(), Error>,
778 ) -> Result<(), Error> {
779 self.read_internal(address, read, false, check_timeout)
780 // Automatic Stop
781 }
782
783 #[cfg(feature = "time")]
784 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
785 self.blocking_read_timeout(address, read, self.timeout)
786 }
787
788 #[cfg(not(feature = "time"))]
789 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { 564 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
790 self.blocking_read_timeout(address, read, || Ok(())) 565 self.read_internal(address, read, false, self.timeout())
791 }
792
793 #[cfg(feature = "time")]
794 pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
795 self.write_internal(address, write, true, timeout_fn(timeout))
796 }
797
798 #[cfg(not(feature = "time"))]
799 pub fn blocking_write_timeout(
800 &mut self,
801 address: u8,
802 write: &[u8],
803 check_timeout: impl Fn() -> Result<(), Error>,
804 ) -> Result<(), Error> {
805 self.write_internal(address, write, true, check_timeout)
806 }
807
808 #[cfg(feature = "time")]
809 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
810 self.blocking_write_timeout(address, write, self.timeout)
811 }
812
813 #[cfg(not(feature = "time"))]
814 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
815 self.blocking_write_timeout(address, write, || Ok(()))
816 }
817
818 #[cfg(feature = "time")]
819 pub fn blocking_write_read_timeout(
820 &mut self,
821 address: u8,
822 write: &[u8],
823 read: &mut [u8],
824 timeout: Duration,
825 ) -> Result<(), Error> {
826 let check_timeout = timeout_fn(timeout);
827 self.write_internal(address, write, false, &check_timeout)?;
828 self.read_internal(address, read, true, &check_timeout)
829 // Automatic Stop 566 // Automatic Stop
830 } 567 }
831 568
832 #[cfg(not(feature = "time"))] 569 /// Blocking write.
833 pub fn blocking_write_read_timeout( 570 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
834 &mut self, 571 self.write_internal(address, write, true, self.timeout())
835 address: u8,
836 write: &[u8],
837 read: &mut [u8],
838 check_timeout: impl Fn() -> Result<(), Error>,
839 ) -> Result<(), Error> {
840 self.write_internal(address, write, false, &check_timeout)?;
841 self.read_internal(address, read, true, &check_timeout)
842 // Automatic Stop
843 }
844
845 #[cfg(feature = "time")]
846 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
847 self.blocking_write_read_timeout(address, write, read, self.timeout)
848 } 572 }
849 573
850 #[cfg(not(feature = "time"))] 574 /// Blocking write, restart, read.
851 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 575 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
852 self.blocking_write_read_timeout(address, write, read, || Ok(())) 576 let timeout = self.timeout();
577 self.write_internal(address, write, false, timeout)?;
578 self.read_internal(address, read, true, timeout)
579 // Automatic Stop
853 } 580 }
854 581
855 fn blocking_write_vectored_with_timeout( 582 /// Blocking write multiple buffers.
856 &mut self, 583 ///
857 address: u8, 584 /// The buffers are concatenated in a single write transaction.
858 write: &[&[u8]], 585 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
859 check_timeout: impl Fn() -> Result<(), Error>,
860 ) -> Result<(), Error> {
861 if write.is_empty() { 586 if write.is_empty() {
862 return Err(Error::ZeroLengthTransfer); 587 return Err(Error::ZeroLengthTransfer);
863 } 588 }
864 589
590 let timeout = self.timeout();
591
865 let first_length = write[0].len(); 592 let first_length = write[0].len();
866 let last_slice_index = write.len() - 1; 593 let last_slice_index = write.len() - 1;
867 594
@@ -870,7 +597,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
870 first_length.min(255), 597 first_length.min(255),
871 Stop::Software, 598 Stop::Software,
872 (first_length > 255) || (last_slice_index != 0), 599 (first_length > 255) || (last_slice_index != 0),
873 &check_timeout, 600 timeout,
874 ) { 601 ) {
875 self.master_stop(); 602 self.master_stop();
876 return Err(err); 603 return Err(err);
@@ -890,7 +617,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
890 if let Err(err) = Self::master_continue( 617 if let Err(err) = Self::master_continue(
891 slice_len.min(255), 618 slice_len.min(255),
892 (idx != last_slice_index) || (slice_len > 255), 619 (idx != last_slice_index) || (slice_len > 255),
893 &check_timeout, 620 timeout,
894 ) { 621 ) {
895 self.master_stop(); 622 self.master_stop();
896 return Err(err); 623 return Err(err);
@@ -902,7 +629,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
902 if let Err(err) = Self::master_continue( 629 if let Err(err) = Self::master_continue(
903 chunk.len(), 630 chunk.len(),
904 (number != last_chunk_idx) || (idx != last_slice_index), 631 (number != last_chunk_idx) || (idx != last_slice_index),
905 &check_timeout, 632 timeout,
906 ) { 633 ) {
907 self.master_stop(); 634 self.master_stop();
908 return Err(err); 635 return Err(err);
@@ -913,7 +640,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
913 // Wait until we are allowed to send data 640 // Wait until we are allowed to send data
914 // (START has been ACKed or last byte when 641 // (START has been ACKed or last byte when
915 // through) 642 // through)
916 if let Err(err) = self.wait_txe(&check_timeout) { 643 if let Err(err) = self.wait_txe(timeout) {
917 self.master_stop(); 644 self.master_stop();
918 return Err(err); 645 return Err(err);
919 } 646 }
@@ -925,41 +652,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
925 } 652 }
926 } 653 }
927 // Wait until the write finishes 654 // Wait until the write finishes
928 let result = self.wait_tc(&check_timeout); 655 let result = self.wait_tc(timeout);
929 self.master_stop(); 656 self.master_stop();
930 result 657 result
931 } 658 }
932
933 #[cfg(feature = "time")]
934 pub fn blocking_write_vectored_timeout(
935 &mut self,
936 address: u8,
937 write: &[&[u8]],
938 timeout: Duration,
939 ) -> Result<(), Error> {
940 let check_timeout = timeout_fn(timeout);
941 self.blocking_write_vectored_with_timeout(address, write, check_timeout)
942 }
943
944 #[cfg(not(feature = "time"))]
945 pub fn blocking_write_vectored_timeout(
946 &mut self,
947 address: u8,
948 write: &[&[u8]],
949 check_timeout: impl Fn() -> Result<(), Error>,
950 ) -> Result<(), Error> {
951 self.blocking_write_vectored_with_timeout(address, write, check_timeout)
952 }
953
954 #[cfg(feature = "time")]
955 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
956 self.blocking_write_vectored_timeout(address, write, self.timeout)
957 }
958
959 #[cfg(not(feature = "time"))]
960 pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
961 self.blocking_write_vectored_timeout(address, write, || Ok(()))
962 }
963} 659}
964 660
965impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { 661impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index 67d40c479..1f85c0bc5 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -1,3 +1,4 @@
1//! Inter-IC Sound (I2S)
1use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
2 3
3use crate::gpio::sealed::{AFType, Pin as _}; 4use crate::gpio::sealed::{AFType, Pin as _};
@@ -8,30 +9,42 @@ use crate::spi::{Config as SpiConfig, *};
8use crate::time::Hertz; 9use crate::time::Hertz;
9use crate::{Peripheral, PeripheralRef}; 10use crate::{Peripheral, PeripheralRef};
10 11
12/// I2S mode
11#[derive(Copy, Clone)] 13#[derive(Copy, Clone)]
12pub enum Mode { 14pub enum Mode {
15 /// Master mode
13 Master, 16 Master,
17 /// Slave mode
14 Slave, 18 Slave,
15} 19}
16 20
21/// I2S function
17#[derive(Copy, Clone)] 22#[derive(Copy, Clone)]
18pub enum Function { 23pub enum Function {
24 /// Transmit audio data
19 Transmit, 25 Transmit,
26 /// Receive audio data
20 Receive, 27 Receive,
21} 28}
22 29
30/// I2C standard
23#[derive(Copy, Clone)] 31#[derive(Copy, Clone)]
24pub enum Standard { 32pub enum Standard {
33 /// Philips
25 Philips, 34 Philips,
35 /// Most significant bit first.
26 MsbFirst, 36 MsbFirst,
37 /// Least significant bit first.
27 LsbFirst, 38 LsbFirst,
39 /// PCM with long sync.
28 PcmLongSync, 40 PcmLongSync,
41 /// PCM with short sync.
29 PcmShortSync, 42 PcmShortSync,
30} 43}
31 44
32impl Standard { 45impl Standard {
33 #[cfg(any(spi_v1, spi_f1))] 46 #[cfg(any(spi_v1, spi_f1))]
34 pub const fn i2sstd(&self) -> vals::I2sstd { 47 const fn i2sstd(&self) -> vals::I2sstd {
35 match self { 48 match self {
36 Standard::Philips => vals::I2sstd::PHILIPS, 49 Standard::Philips => vals::I2sstd::PHILIPS,
37 Standard::MsbFirst => vals::I2sstd::MSB, 50 Standard::MsbFirst => vals::I2sstd::MSB,
@@ -42,7 +55,7 @@ impl Standard {
42 } 55 }
43 56
44 #[cfg(any(spi_v1, spi_f1))] 57 #[cfg(any(spi_v1, spi_f1))]
45 pub const fn pcmsync(&self) -> vals::Pcmsync { 58 const fn pcmsync(&self) -> vals::Pcmsync {
46 match self { 59 match self {
47 Standard::PcmLongSync => vals::Pcmsync::LONG, 60 Standard::PcmLongSync => vals::Pcmsync::LONG,
48 _ => vals::Pcmsync::SHORT, 61 _ => vals::Pcmsync::SHORT,
@@ -50,6 +63,7 @@ impl Standard {
50 } 63 }
51} 64}
52 65
66/// I2S data format.
53#[derive(Copy, Clone)] 67#[derive(Copy, Clone)]
54pub enum Format { 68pub enum Format {
55 /// 16 bit data length on 16 bit wide channel 69 /// 16 bit data length on 16 bit wide channel
@@ -64,7 +78,7 @@ pub enum Format {
64 78
65impl Format { 79impl Format {
66 #[cfg(any(spi_v1, spi_f1))] 80 #[cfg(any(spi_v1, spi_f1))]
67 pub const fn datlen(&self) -> vals::Datlen { 81 const fn datlen(&self) -> vals::Datlen {
68 match self { 82 match self {
69 Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, 83 Format::Data16Channel16 => vals::Datlen::SIXTEENBIT,
70 Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, 84 Format::Data16Channel32 => vals::Datlen::SIXTEENBIT,
@@ -74,7 +88,7 @@ impl Format {
74 } 88 }
75 89
76 #[cfg(any(spi_v1, spi_f1))] 90 #[cfg(any(spi_v1, spi_f1))]
77 pub const fn chlen(&self) -> vals::Chlen { 91 const fn chlen(&self) -> vals::Chlen {
78 match self { 92 match self {
79 Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, 93 Format::Data16Channel16 => vals::Chlen::SIXTEENBIT,
80 Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, 94 Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT,
@@ -84,15 +98,18 @@ impl Format {
84 } 98 }
85} 99}
86 100
101/// Clock polarity
87#[derive(Copy, Clone)] 102#[derive(Copy, Clone)]
88pub enum ClockPolarity { 103pub enum ClockPolarity {
104 /// Low on idle.
89 IdleLow, 105 IdleLow,
106 /// High on idle.
90 IdleHigh, 107 IdleHigh,
91} 108}
92 109
93impl ClockPolarity { 110impl ClockPolarity {
94 #[cfg(any(spi_v1, spi_f1))] 111 #[cfg(any(spi_v1, spi_f1))]
95 pub const fn ckpol(&self) -> vals::Ckpol { 112 const fn ckpol(&self) -> vals::Ckpol {
96 match self { 113 match self {
97 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, 114 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH,
98 ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, 115 ClockPolarity::IdleLow => vals::Ckpol::IDLELOW,
@@ -109,11 +126,17 @@ impl ClockPolarity {
109#[non_exhaustive] 126#[non_exhaustive]
110#[derive(Copy, Clone)] 127#[derive(Copy, Clone)]
111pub struct Config { 128pub struct Config {
129 /// Mode
112 pub mode: Mode, 130 pub mode: Mode,
131 /// Function (transmit, receive)
113 pub function: Function, 132 pub function: Function,
133 /// Which I2S standard to use.
114 pub standard: Standard, 134 pub standard: Standard,
135 /// Data format.
115 pub format: Format, 136 pub format: Format,
137 /// Clock polarity.
116 pub clock_polarity: ClockPolarity, 138 pub clock_polarity: ClockPolarity,
139 /// True to eanble master clock output from this instance.
117 pub master_clock: bool, 140 pub master_clock: bool,
118} 141}
119 142
@@ -130,6 +153,7 @@ impl Default for Config {
130 } 153 }
131} 154}
132 155
156/// I2S driver.
133pub struct I2S<'d, T: Instance, Tx, Rx> { 157pub struct I2S<'d, T: Instance, Tx, Rx> {
134 _peri: Spi<'d, T, Tx, Rx>, 158 _peri: Spi<'d, T, Tx, Rx>,
135 sd: Option<PeripheralRef<'d, AnyPin>>, 159 sd: Option<PeripheralRef<'d, AnyPin>>,
@@ -242,6 +266,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
242 } 266 }
243 } 267 }
244 268
269 /// Write audio data.
245 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 270 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
246 where 271 where
247 Tx: TxDma<T>, 272 Tx: TxDma<T>,
@@ -249,6 +274,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
249 self._peri.write(data).await 274 self._peri.write(data).await
250 } 275 }
251 276
277 /// Read audio data.
252 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 278 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
253 where 279 where
254 Tx: TxDma<T>, 280 Tx: TxDma<T>,
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..f10e9d50d 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,38 +198,40 @@ 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);
185 209
186 #[cfg(dbgmcu)] 210 #[cfg(dbgmcu)]
187 if config.enable_debug_during_sleep { 211 crate::pac::DBGMCU.cr().modify(|cr| {
188 crate::pac::DBGMCU.cr().modify(|cr| { 212 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
189 #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] 213 {
190 { 214 cr.set_dbg_stop(config.enable_debug_during_sleep);
191 cr.set_dbg_stop(true); 215 cr.set_dbg_standby(config.enable_debug_during_sleep);
192 cr.set_dbg_standby(true); 216 }
193 } 217 #[cfg(any(
194 #[cfg(any( 218 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
195 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 219 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
196 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 220 ))]
197 ))] 221 {
198 { 222 cr.set_dbg_sleep(config.enable_debug_during_sleep);
199 cr.set_dbg_sleep(true); 223 cr.set_dbg_stop(config.enable_debug_during_sleep);
200 cr.set_dbg_stop(true); 224 cr.set_dbg_standby(config.enable_debug_during_sleep);
201 cr.set_dbg_standby(true); 225 }
202 } 226 #[cfg(dbgmcu_h7)]
203 #[cfg(dbgmcu_h7)] 227 {
204 { 228 cr.set_d1dbgcken(config.enable_debug_during_sleep);
205 cr.set_d1dbgcken(true); 229 cr.set_d3dbgcken(config.enable_debug_during_sleep);
206 cr.set_d3dbgcken(true); 230 cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
207 cr.set_dbgsleep_d1(true); 231 cr.set_dbgstby_d1(config.enable_debug_during_sleep);
208 cr.set_dbgstby_d1(true); 232 cr.set_dbgstop_d1(config.enable_debug_during_sleep);
209 cr.set_dbgstop_d1(true); 233 }
210 } 234 });
211 });
212 }
213 235
214 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] 236 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
215 peripherals::SYSCFG::enable_and_reset_with_cs(cs); 237 peripherals::SYSCFG::enable_and_reset_with_cs(cs);
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 20d8f9045..4fab8dae4 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -1,50 +1,54 @@
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::StaticCell;
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//! static RTC: StaticCell<Rtc> = StaticCell::new();
45/// // your application here... 45//! let rtc = RTC.init(rtc);
46/// } 46//! embassy_stm32::low_power::stop_with_rtc(rtc);
47/// ``` 47//!
48//! // your application here...
49//! }
50//! ```
51
48use core::arch::asm; 52use core::arch::asm;
49use core::marker::PhantomData; 53use core::marker::PhantomData;
50use core::sync::atomic::{compiler_fence, Ordering}; 54use core::sync::atomic::{compiler_fence, Ordering};
@@ -64,6 +68,7 @@ static mut EXECUTOR: Option<Executor> = None;
64foreach_interrupt! { 68foreach_interrupt! {
65 (RTC, rtc, $block:ident, WKUP, $irq:ident) => { 69 (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
66 #[interrupt] 70 #[interrupt]
71 #[allow(non_snake_case)]
67 unsafe fn $irq() { 72 unsafe fn $irq() {
68 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 73 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
69 } 74 }
@@ -75,10 +80,15 @@ pub(crate) unsafe fn on_wakeup_irq() {
75 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 80 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
76} 81}
77 82
83/// Configure STOP mode with RTC.
78pub fn stop_with_rtc(rtc: &'static Rtc) { 84pub fn stop_with_rtc(rtc: &'static Rtc) {
79 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) 85 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
80} 86}
81 87
88/// Get whether the core is ready to enter the given stop mode.
89///
90/// This will return false if some peripheral driver is in use that
91/// prevents entering the given stop mode.
82pub fn stop_ready(stop_mode: StopMode) -> bool { 92pub fn stop_ready(stop_mode: StopMode) -> bool {
83 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 93 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
84 Some(StopMode::Stop2) => true, 94 Some(StopMode::Stop2) => true,
@@ -87,10 +97,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
87 } 97 }
88} 98}
89 99
100/// Available stop modes.
90#[non_exhaustive] 101#[non_exhaustive]
91#[derive(PartialEq)] 102#[derive(PartialEq)]
92pub enum StopMode { 103pub enum StopMode {
104 /// STOP 1
93 Stop1, 105 Stop1,
106 /// STOP 2
94 Stop2, 107 Stop2,
95} 108}
96 109
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/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index 0412d991a..ecade9b1a 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -1,3 +1,5 @@
1//! Enums used in QSPI configuration.
2
1#[allow(dead_code)] 3#[allow(dead_code)]
2#[derive(Copy, Clone)] 4#[derive(Copy, Clone)]
3pub(crate) enum QspiMode { 5pub(crate) enum QspiMode {
@@ -18,12 +20,17 @@ impl Into<u8> for QspiMode {
18 } 20 }
19} 21}
20 22
23/// QSPI lane width
21#[allow(dead_code)] 24#[allow(dead_code)]
22#[derive(Copy, Clone)] 25#[derive(Copy, Clone)]
23pub enum QspiWidth { 26pub enum QspiWidth {
27 /// None
24 NONE, 28 NONE,
29 /// Single lane
25 SING, 30 SING,
31 /// Dual lanes
26 DUAL, 32 DUAL,
33 /// Quad lanes
27 QUAD, 34 QUAD,
28} 35}
29 36
@@ -38,10 +45,13 @@ impl Into<u8> for QspiWidth {
38 } 45 }
39} 46}
40 47
48/// Flash bank selection
41#[allow(dead_code)] 49#[allow(dead_code)]
42#[derive(Copy, Clone)] 50#[derive(Copy, Clone)]
43pub enum FlashSelection { 51pub enum FlashSelection {
52 /// Bank 1
44 Flash1, 53 Flash1,
54 /// Bank 2
45 Flash2, 55 Flash2,
46} 56}
47 57
@@ -54,6 +64,8 @@ impl Into<bool> for FlashSelection {
54 } 64 }
55} 65}
56 66
67/// QSPI memory size.
68#[allow(missing_docs)]
57#[derive(Copy, Clone)] 69#[derive(Copy, Clone)]
58pub enum MemorySize { 70pub enum MemorySize {
59 _1KiB, 71 _1KiB,
@@ -113,11 +125,16 @@ impl Into<u8> for MemorySize {
113 } 125 }
114} 126}
115 127
128/// QSPI Address size
116#[derive(Copy, Clone)] 129#[derive(Copy, Clone)]
117pub enum AddressSize { 130pub enum AddressSize {
131 /// 8-bit address
118 _8Bit, 132 _8Bit,
133 /// 16-bit address
119 _16Bit, 134 _16Bit,
135 /// 24-bit address
120 _24bit, 136 _24bit,
137 /// 32-bit address
121 _32bit, 138 _32bit,
122} 139}
123 140
@@ -132,8 +149,10 @@ impl Into<u8> for AddressSize {
132 } 149 }
133} 150}
134 151
152/// Time the Chip Select line stays high.
153#[allow(missing_docs)]
135#[derive(Copy, Clone)] 154#[derive(Copy, Clone)]
136pub enum ChipSelectHightTime { 155pub enum ChipSelectHighTime {
137 _1Cycle, 156 _1Cycle,
138 _2Cycle, 157 _2Cycle,
139 _3Cycle, 158 _3Cycle,
@@ -144,21 +163,23 @@ pub enum ChipSelectHightTime {
144 _8Cycle, 163 _8Cycle,
145} 164}
146 165
147impl Into<u8> for ChipSelectHightTime { 166impl Into<u8> for ChipSelectHighTime {
148 fn into(self) -> u8 { 167 fn into(self) -> u8 {
149 match self { 168 match self {
150 ChipSelectHightTime::_1Cycle => 0, 169 ChipSelectHighTime::_1Cycle => 0,
151 ChipSelectHightTime::_2Cycle => 1, 170 ChipSelectHighTime::_2Cycle => 1,
152 ChipSelectHightTime::_3Cycle => 2, 171 ChipSelectHighTime::_3Cycle => 2,
153 ChipSelectHightTime::_4Cycle => 3, 172 ChipSelectHighTime::_4Cycle => 3,
154 ChipSelectHightTime::_5Cycle => 4, 173 ChipSelectHighTime::_5Cycle => 4,
155 ChipSelectHightTime::_6Cycle => 5, 174 ChipSelectHighTime::_6Cycle => 5,
156 ChipSelectHightTime::_7Cycle => 6, 175 ChipSelectHighTime::_7Cycle => 6,
157 ChipSelectHightTime::_8Cycle => 7, 176 ChipSelectHighTime::_8Cycle => 7,
158 } 177 }
159 } 178 }
160} 179}
161 180
181/// FIFO threshold.
182#[allow(missing_docs)]
162#[derive(Copy, Clone)] 183#[derive(Copy, Clone)]
163pub enum FIFOThresholdLevel { 184pub enum FIFOThresholdLevel {
164 _1Bytes, 185 _1Bytes,
@@ -234,6 +255,8 @@ impl Into<u8> for FIFOThresholdLevel {
234 } 255 }
235} 256}
236 257
258/// Dummy cycle count
259#[allow(missing_docs)]
237#[derive(Copy, Clone)] 260#[derive(Copy, Clone)]
238pub enum DummyCycles { 261pub enum DummyCycles {
239 _0, 262 _0,
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 4b0e8ecef..8a709a89e 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -1,3 +1,5 @@
1//! Quad Serial Peripheral Interface (QSPI)
2
1#![macro_use] 3#![macro_use]
2 4
3pub mod enums; 5pub mod enums;
@@ -12,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs;
12use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
13use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
14 16
17/// QSPI transfer configuration.
15pub struct TransferConfig { 18pub struct TransferConfig {
16 /// Instraction width (IMODE) 19 /// Instraction width (IMODE)
17 pub iwidth: QspiWidth, 20 pub iwidth: QspiWidth,
@@ -43,6 +46,7 @@ impl Default for TransferConfig {
43 } 46 }
44} 47}
45 48
49/// QSPI driver configuration.
46pub struct Config { 50pub struct Config {
47 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 51 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
48 /// If you need other value the whose predefined use `Other` variant. 52 /// If you need other value the whose predefined use `Other` variant.
@@ -54,7 +58,7 @@ pub struct Config {
54 /// Number of bytes to trigger FIFO threshold flag. 58 /// Number of bytes to trigger FIFO threshold flag.
55 pub fifo_threshold: FIFOThresholdLevel, 59 pub fifo_threshold: FIFOThresholdLevel,
56 /// Minimum number of cycles that chip select must be high between issued commands 60 /// Minimum number of cycles that chip select must be high between issued commands
57 pub cs_high_time: ChipSelectHightTime, 61 pub cs_high_time: ChipSelectHighTime,
58} 62}
59 63
60impl Default for Config { 64impl Default for Config {
@@ -64,11 +68,12 @@ impl Default for Config {
64 address_size: AddressSize::_24bit, 68 address_size: AddressSize::_24bit,
65 prescaler: 128, 69 prescaler: 128,
66 fifo_threshold: FIFOThresholdLevel::_17Bytes, 70 fifo_threshold: FIFOThresholdLevel::_17Bytes,
67 cs_high_time: ChipSelectHightTime::_5Cycle, 71 cs_high_time: ChipSelectHighTime::_5Cycle,
68 } 72 }
69 } 73 }
70} 74}
71 75
76/// QSPI driver.
72#[allow(dead_code)] 77#[allow(dead_code)]
73pub struct Qspi<'d, T: Instance, Dma> { 78pub struct Qspi<'d, T: Instance, Dma> {
74 _peri: PeripheralRef<'d, T>, 79 _peri: PeripheralRef<'d, T>,
@@ -83,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> {
83} 88}
84 89
85impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { 90impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
91 /// Create a new QSPI driver for bank 1.
86 pub fn new_bk1( 92 pub fn new_bk1(
87 peri: impl Peripheral<P = T> + 'd, 93 peri: impl Peripheral<P = T> + 'd,
88 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, 94 d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
@@ -119,10 +125,11 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
119 Some(nss.map_into()), 125 Some(nss.map_into()),
120 dma, 126 dma,
121 config, 127 config,
122 FlashSelection::Flash2, 128 FlashSelection::Flash1,
123 ) 129 )
124 } 130 }
125 131
132 /// Create a new QSPI driver for bank 2.
126 pub fn new_bk2( 133 pub fn new_bk2(
127 peri: impl Peripheral<P = T> + 'd, 134 peri: impl Peripheral<P = T> + 'd,
128 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, 135 d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
@@ -221,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
221 } 228 }
222 } 229 }
223 230
231 /// Do a QSPI command.
224 pub fn command(&mut self, transaction: TransferConfig) { 232 pub fn command(&mut self, transaction: TransferConfig) {
225 #[cfg(not(stm32h7))] 233 #[cfg(not(stm32h7))]
226 T::REGS.cr().modify(|v| v.set_dmaen(false)); 234 T::REGS.cr().modify(|v| v.set_dmaen(false));
@@ -230,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
230 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 238 T::REGS.fcr().modify(|v| v.set_ctcf(true));
231 } 239 }
232 240
241 /// Blocking read data.
233 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 242 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
234 #[cfg(not(stm32h7))] 243 #[cfg(not(stm32h7))]
235 T::REGS.cr().modify(|v| v.set_dmaen(false)); 244 T::REGS.cr().modify(|v| v.set_dmaen(false));
@@ -254,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
254 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 263 T::REGS.fcr().modify(|v| v.set_ctcf(true));
255 } 264 }
256 265
266 /// Blocking write data.
257 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { 267 pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
258 // STM32H7 does not have dmaen 268 // STM32H7 does not have dmaen
259 #[cfg(not(stm32h7))] 269 #[cfg(not(stm32h7))]
@@ -276,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
276 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 286 T::REGS.fcr().modify(|v| v.set_ctcf(true));
277 } 287 }
278 288
289 /// Blocking read data, using DMA.
279 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) 290 pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
280 where 291 where
281 Dma: QuadDma<T>, 292 Dma: QuadDma<T>,
@@ -308,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
308 transfer.blocking_wait(); 319 transfer.blocking_wait();
309 } 320 }
310 321
322 /// Blocking write data, using DMA.
311 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) 323 pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
312 where 324 where
313 Dma: QuadDma<T>, 325 Dma: QuadDma<T>,
@@ -377,6 +389,7 @@ pub(crate) mod sealed {
377 } 389 }
378} 390}
379 391
392/// QSPI instance trait.
380pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 393pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
381 394
382pin_trait!(SckPin, Instance); 395pin_trait!(SckPin, Instance);
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 1889eb280..15b51a398 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -70,7 +70,9 @@ pub struct Pll {
70 pub mul: PllMul, 70 pub mul: PllMul,
71 71
72 /// PLL P division factor. If None, PLL P output is disabled. 72 /// PLL P division factor. If None, PLL P output is disabled.
73 /// On PLL1, it must be even (in particular, it cannot be 1.) 73 /// On PLL1, it must be even for most series (in particular,
74 /// it cannot be 1 in series other than STM32H723/733,
75 /// STM32H725/735 and STM32H730.)
74 pub divp: Option<PllDiv>, 76 pub divp: Option<PllDiv>,
75 /// PLL Q division factor. If None, PLL Q output is disabled. 77 /// PLL Q division factor. If None, PLL Q output is disabled.
76 pub divq: Option<PllDiv>, 78 pub divq: Option<PllDiv>,
@@ -476,7 +478,14 @@ pub(crate) unsafe fn init(config: Config) {
476 VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)), 478 VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)),
477 VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)), 479 VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)),
478 }; 480 };
479 #[cfg(all(stm32h7, not(pwr_h7rm0455)))] 481 #[cfg(pwr_h7rm0468)]
482 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
483 VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)),
484 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
485 VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
486 VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)),
487 };
488 #[cfg(all(stm32h7, not(any(pwr_h7rm0455, pwr_h7rm0468))))]
480 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { 489 let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
481 VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), 490 VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
482 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), 491 VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
@@ -729,9 +738,12 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
729 738
730 let p = config.divp.map(|div| { 739 let p = config.divp.map(|div| {
731 if num == 0 { 740 if num == 0 {
732 // on PLL1, DIVP must be even. 741 // on PLL1, DIVP must be even for most series.
733 // The enum value is 1 less than the divider, so check it's odd. 742 // The enum value is 1 less than the divider, so check it's odd.
743 #[cfg(not(pwr_h7rm0468))]
734 assert!(div.to_bits() % 2 == 1); 744 assert!(div.to_bits() % 2 == 1);
745 #[cfg(pwr_h7rm0468)]
746 assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0);
735 } 747 }
736 748
737 vco_clk / div 749 vco_clk / div
@@ -820,7 +832,7 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
820 _ => unreachable!(), 832 _ => unreachable!(),
821 }; 833 };
822 834
823 #[cfg(flash_h7)] 835 #[cfg(all(flash_h7, not(pwr_h7rm0468)))]
824 let (latency, wrhighfreq) = match (vos, clk.0) { 836 let (latency, wrhighfreq) = match (vos, clk.0) {
825 // VOS 0 range VCORE 1.26V - 1.40V 837 // VOS 0 range VCORE 1.26V - 1.40V
826 (VoltageScale::Scale0, ..=70_000_000) => (0, 0), 838 (VoltageScale::Scale0, ..=70_000_000) => (0, 0),
@@ -849,6 +861,30 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
849 _ => unreachable!(), 861 _ => unreachable!(),
850 }; 862 };
851 863
864 // See RM0468 Rev 3 Table 16. FLASH recommended number of wait
865 // states and programming delay
866 #[cfg(all(flash_h7, pwr_h7rm0468))]
867 let (latency, wrhighfreq) = match (vos, clk.0) {
868 // VOS 0 range VCORE 1.26V - 1.40V
869 (VoltageScale::Scale0, ..=70_000_000) => (0, 0),
870 (VoltageScale::Scale0, ..=140_000_000) => (1, 1),
871 (VoltageScale::Scale0, ..=210_000_000) => (2, 2),
872 (VoltageScale::Scale0, ..=275_000_000) => (3, 3),
873 // VOS 1 range VCORE 1.15V - 1.26V
874 (VoltageScale::Scale1, ..=67_000_000) => (0, 0),
875 (VoltageScale::Scale1, ..=133_000_000) => (1, 1),
876 (VoltageScale::Scale1, ..=200_000_000) => (2, 2),
877 // VOS 2 range VCORE 1.05V - 1.15V
878 (VoltageScale::Scale2, ..=50_000_000) => (0, 0),
879 (VoltageScale::Scale2, ..=100_000_000) => (1, 1),
880 (VoltageScale::Scale2, ..=150_000_000) => (2, 2),
881 // VOS 3 range VCORE 0.95V - 1.05V
882 (VoltageScale::Scale3, ..=35_000_000) => (0, 0),
883 (VoltageScale::Scale3, ..=70_000_000) => (1, 1),
884 (VoltageScale::Scale3, ..=85_000_000) => (2, 2),
885 _ => unreachable!(),
886 };
887
852 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait 888 // See RM0455 Rev 10 Table 16. FLASH recommended number of wait
853 // states and programming delay 889 // states and programming delay
854 #[cfg(flash_h7ab)] 890 #[cfg(flash_h7ab)]
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index dc829a9ad..04a51110c 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -1,4 +1,7 @@
1//! Reset and Clock Control (RCC)
2
1#![macro_use] 3#![macro_use]
4#![allow(missing_docs)] // TODO
2 5
3use core::mem::MaybeUninit; 6use core::mem::MaybeUninit;
4 7
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 5e6922e9b..ca641f352 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -1,3 +1,4 @@
1//! Random Number Generator (RNG)
1#![macro_use] 2#![macro_use]
2 3
3use core::future::poll_fn; 4use core::future::poll_fn;
@@ -13,13 +14,19 @@ use crate::{interrupt, pac, peripherals, Peripheral};
13 14
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 15static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 16
17/// RNG error
16#[derive(Debug, PartialEq, Eq)] 18#[derive(Debug, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))] 19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Error { 20pub enum Error {
21 /// Seed error.
19 SeedError, 22 SeedError,
23 /// Clock error. Double-check the RCC configuration,
24 /// see the Reference Manual for details on restrictions
25 /// on RNG clocks.
20 ClockError, 26 ClockError,
21} 27}
22 28
29/// RNG interrupt handler.
23pub struct InterruptHandler<T: Instance> { 30pub struct InterruptHandler<T: Instance> {
24 _phantom: PhantomData<T>, 31 _phantom: PhantomData<T>,
25} 32}
@@ -34,11 +41,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
34 } 41 }
35} 42}
36 43
44/// RNG driver.
37pub struct Rng<'d, T: Instance> { 45pub struct Rng<'d, T: Instance> {
38 _inner: PeripheralRef<'d, T>, 46 _inner: PeripheralRef<'d, T>,
39} 47}
40 48
41impl<'d, T: Instance> Rng<'d, T> { 49impl<'d, T: Instance> Rng<'d, T> {
50 /// Create a new RNG driver.
42 pub fn new( 51 pub fn new(
43 inner: impl Peripheral<P = T> + 'd, 52 inner: impl Peripheral<P = T> + 'd,
44 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 53 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -54,6 +63,7 @@ impl<'d, T: Instance> Rng<'d, T> {
54 random 63 random
55 } 64 }
56 65
66 /// Reset the RNG.
57 #[cfg(rng_v1)] 67 #[cfg(rng_v1)]
58 pub fn reset(&mut self) { 68 pub fn reset(&mut self) {
59 T::regs().cr().write(|reg| { 69 T::regs().cr().write(|reg| {
@@ -70,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> {
70 let _ = self.next_u32(); 80 let _ = self.next_u32();
71 } 81 }
72 82
83 /// Reset the RNG.
73 #[cfg(not(rng_v1))] 84 #[cfg(not(rng_v1))]
74 pub fn reset(&mut self) { 85 pub fn reset(&mut self) {
75 T::regs().cr().write(|reg| { 86 T::regs().cr().write(|reg| {
@@ -106,7 +117,8 @@ impl<'d, T: Instance> Rng<'d, T> {
106 while T::regs().cr().read().condrst() {} 117 while T::regs().cr().read().condrst() {}
107 } 118 }
108 119
109 pub fn recover_seed_error(&mut self) -> () { 120 /// Try to recover from a seed error.
121 pub fn recover_seed_error(&mut self) {
110 self.reset(); 122 self.reset();
111 // reset should also clear the SEIS flag 123 // reset should also clear the SEIS flag
112 if T::regs().sr().read().seis() { 124 if T::regs().sr().read().seis() {
@@ -117,6 +129,7 @@ impl<'d, T: Instance> Rng<'d, T> {
117 while T::regs().sr().read().secs() {} 129 while T::regs().sr().read().secs() {}
118 } 130 }
119 131
132 /// Fill the given slice with random values.
120 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 133 pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
121 for chunk in dest.chunks_mut(4) { 134 for chunk in dest.chunks_mut(4) {
122 let mut bits = T::regs().sr().read(); 135 let mut bits = T::regs().sr().read();
@@ -217,7 +230,9 @@ pub(crate) mod sealed {
217 } 230 }
218} 231}
219 232
233/// RNG instance trait.
220pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { 234pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send {
235 /// Interrupt for this RNG instance.
221 type Interrupt: interrupt::typelevel::Interrupt; 236 type Interrupt: interrupt::typelevel::Interrupt;
222} 237}
223 238
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index f4e86dd87..ef92fa4bb 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -104,45 +104,51 @@ pub struct DateTime {
104} 104}
105 105
106impl DateTime { 106impl DateTime {
107 /// Get the year (0..=4095)
107 pub const fn year(&self) -> u16 { 108 pub const fn year(&self) -> u16 {
108 self.year 109 self.year
109 } 110 }
110 111
112 /// Get the month (1..=12, 1 is January)
111 pub const fn month(&self) -> u8 { 113 pub const fn month(&self) -> u8 {
112 self.month 114 self.month
113 } 115 }
114 116
117 /// Get the day (1..=31)
115 pub const fn day(&self) -> u8 { 118 pub const fn day(&self) -> u8 {
116 self.day 119 self.day
117 } 120 }
118 121
122 /// Get the day of week
119 pub const fn day_of_week(&self) -> DayOfWeek { 123 pub const fn day_of_week(&self) -> DayOfWeek {
120 self.day_of_week 124 self.day_of_week
121 } 125 }
122 126
127 /// Get the hour (0..=23)
123 pub const fn hour(&self) -> u8 { 128 pub const fn hour(&self) -> u8 {
124 self.hour 129 self.hour
125 } 130 }
126 131
132 /// Get the minute (0..=59)
127 pub const fn minute(&self) -> u8 { 133 pub const fn minute(&self) -> u8 {
128 self.minute 134 self.minute
129 } 135 }
130 136
137 /// Get the second (0..=59)
131 pub const fn second(&self) -> u8 { 138 pub const fn second(&self) -> u8 {
132 self.second 139 self.second
133 } 140 }
134 141
142 /// Create a new DateTime with the given information.
135 pub fn from( 143 pub fn from(
136 year: u16, 144 year: u16,
137 month: u8, 145 month: u8,
138 day: u8, 146 day: u8,
139 day_of_week: u8, 147 day_of_week: DayOfWeek,
140 hour: u8, 148 hour: u8,
141 minute: u8, 149 minute: u8,
142 second: u8, 150 second: u8,
143 ) -> Result<Self, Error> { 151 ) -> Result<Self, Error> {
144 let day_of_week = day_of_week_from_u8(day_of_week)?;
145
146 if year > 4095 { 152 if year > 4095 {
147 Err(Error::InvalidYear) 153 Err(Error::InvalidYear)
148 } else if month < 1 || month > 12 { 154 } else if month < 1 || month > 12 {
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index b4315f535..1ffb567b3 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -1,4 +1,4 @@
1//! RTC peripheral abstraction 1//! Real Time Clock (RTC)
2mod datetime; 2mod datetime;
3 3
4#[cfg(feature = "low-power")] 4#[cfg(feature = "low-power")]
@@ -9,9 +9,9 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9#[cfg(feature = "low-power")] 9#[cfg(feature = "low-power")]
10use embassy_sync::blocking_mutex::Mutex; 10use embassy_sync::blocking_mutex::Mutex;
11 11
12use self::datetime::day_of_week_to_u8;
13#[cfg(not(rtc_v2f2))] 12#[cfg(not(rtc_v2f2))]
14use self::datetime::RtcInstant; 13use self::datetime::RtcInstant;
14use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
15pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 15pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
16use crate::pac::rtc::regs::{Dr, Tr}; 16use crate::pac::rtc::regs::{Dr, Tr};
17use crate::time::Hertz; 17use crate::time::Hertz;
@@ -24,7 +24,7 @@ use crate::time::Hertz;
24 ), 24 ),
25 path = "v2.rs" 25 path = "v2.rs"
26)] 26)]
27#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] 27#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")]
28mod _version; 28mod _version;
29#[allow(unused_imports)] 29#[allow(unused_imports)]
30pub use _version::*; 30pub use _version::*;
@@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler {
43 Div16 = 16, 43 Div16 = 16,
44} 44}
45 45
46#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] 46#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
47impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 47impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
48 fn from(val: WakeupPrescaler) -> Self { 48 fn from(val: WakeupPrescaler) -> Self {
49 use crate::pac::rtc::vals::Wucksel; 49 use crate::pac::rtc::vals::Wucksel;
@@ -57,7 +57,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
57 } 57 }
58} 58}
59 59
60#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] 60#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
61impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 61impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
62 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 62 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
63 use crate::pac::rtc::vals::Wucksel; 63 use crate::pac::rtc::vals::Wucksel;
@@ -102,6 +102,7 @@ pub enum RtcError {
102 NotRunning, 102 NotRunning,
103} 103}
104 104
105/// Provides immutable access to the current time of the RTC.
105pub struct RtcTimeProvider { 106pub struct RtcTimeProvider {
106 _private: (), 107 _private: (),
107} 108}
@@ -127,10 +128,10 @@ impl RtcTimeProvider {
127 let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); 128 let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
128 let hour = bcd2_to_byte((tr.ht(), tr.hu())); 129 let hour = bcd2_to_byte((tr.ht(), tr.hu()));
129 130
130 let weekday = dr.wdu(); 131 let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?;
131 let day = bcd2_to_byte((dr.dt(), dr.du())); 132 let day = bcd2_to_byte((dr.dt(), dr.du()));
132 let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); 133 let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
133 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; 134 let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16;
134 135
135 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) 136 DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
136 }) 137 })
@@ -163,7 +164,7 @@ impl RtcTimeProvider {
163 } 164 }
164} 165}
165 166
166/// RTC Abstraction 167/// RTC driver.
167pub struct Rtc { 168pub struct Rtc {
168 #[cfg(feature = "low-power")] 169 #[cfg(feature = "low-power")]
169 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, 170 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
@@ -171,6 +172,7 @@ pub struct Rtc {
171 _private: (), 172 _private: (),
172} 173}
173 174
175/// RTC configuration.
174#[non_exhaustive] 176#[non_exhaustive]
175#[derive(Copy, Clone, PartialEq)] 177#[derive(Copy, Clone, PartialEq)]
176pub struct RtcConfig { 178pub struct RtcConfig {
@@ -188,6 +190,7 @@ impl Default for RtcConfig {
188 } 190 }
189} 191}
190 192
193/// Calibration cycle period.
191#[derive(Copy, Clone, Debug, PartialEq)] 194#[derive(Copy, Clone, Debug, PartialEq)]
192#[repr(u8)] 195#[repr(u8)]
193pub enum RtcCalibrationCyclePeriod { 196pub enum RtcCalibrationCyclePeriod {
@@ -206,6 +209,7 @@ impl Default for RtcCalibrationCyclePeriod {
206} 209}
207 210
208impl Rtc { 211impl Rtc {
212 /// Create a new RTC instance.
209 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { 213 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
210 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 214 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
211 <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset(); 215 <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset();
@@ -258,7 +262,7 @@ impl Rtc {
258 let (dt, du) = byte_to_bcd2(t.day() as u8); 262 let (dt, du) = byte_to_bcd2(t.day() as u8);
259 let (mt, mu) = byte_to_bcd2(t.month() as u8); 263 let (mt, mu) = byte_to_bcd2(t.month() as u8);
260 let yr = t.year() as u16; 264 let yr = t.year() as u16;
261 let yr_offset = (yr - 1970_u16) as u8; 265 let yr_offset = (yr - 2000_u16) as u8;
262 let (yt, yu) = byte_to_bcd2(yr_offset); 266 let (yt, yu) = byte_to_bcd2(yr_offset);
263 267
264 use crate::pac::rtc::vals::Ampm; 268 use crate::pac::rtc::vals::Ampm;
@@ -315,6 +319,7 @@ impl Rtc {
315 }) 319 })
316 } 320 }
317 321
322 /// Number of backup registers of this instance.
318 pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; 323 pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT;
319 324
320 /// Read content of the backup register. 325 /// Read content of the backup register.
@@ -343,7 +348,7 @@ impl Rtc {
343 ) { 348 ) {
344 use embassy_time::{Duration, TICK_HZ}; 349 use embassy_time::{Duration, TICK_HZ};
345 350
346 #[cfg(any(rtc_v3, rtc_v3u5))] 351 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
347 use crate::pac::rtc::vals::Calrf; 352 use crate::pac::rtc::vals::Calrf;
348 353
349 // Panic if the rcc mod knows we're not using low-power rtc 354 // Panic if the rcc mod knows we're not using low-power rtc
@@ -370,7 +375,7 @@ impl Rtc {
370 while !regs.isr().read().wutwf() {} 375 while !regs.isr().read().wutwf() {}
371 } 376 }
372 377
373 #[cfg(any(rtc_v3, rtc_v3u5))] 378 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
374 { 379 {
375 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 380 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
376 while !regs.icsr().read().wutwf() {} 381 while !regs.icsr().read().wutwf() {}
@@ -399,7 +404,7 @@ impl Rtc {
399 /// was called, otherwise none 404 /// was called, otherwise none
400 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 405 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
401 use crate::interrupt::typelevel::Interrupt; 406 use crate::interrupt::typelevel::Interrupt;
402 #[cfg(any(rtc_v3, rtc_v3u5))] 407 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
403 use crate::pac::rtc::vals::Calrf; 408 use crate::pac::rtc::vals::Calrf;
404 409
405 let instant = self.instant().unwrap(); 410 let instant = self.instant().unwrap();
@@ -415,13 +420,19 @@ impl Rtc {
415 ))] 420 ))]
416 regs.isr().modify(|w| w.set_wutf(false)); 421 regs.isr().modify(|w| w.set_wutf(false));
417 422
418 #[cfg(any(rtc_v3, rtc_v3u5))] 423 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
419 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 424 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
420 425
426 #[cfg(not(stm32l5))]
421 crate::pac::EXTI 427 crate::pac::EXTI
422 .pr(0) 428 .pr(0)
423 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); 429 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
424 430
431 #[cfg(stm32l5)]
432 crate::pac::EXTI
433 .fpr(0)
434 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
435
425 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); 436 <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
426 }); 437 });
427 } 438 }
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 91f08fae4..1eda097a7 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Init, Osel, Pol}; 1use stm32_metapac::rtc::vals::{Osel, Pol};
2 2
3use super::sealed; 3use super::sealed;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -49,7 +49,7 @@ impl super::Rtc {
49 clock_drift = RTC_CALR_MAX_PPM; 49 clock_drift = RTC_CALR_MAX_PPM;
50 } 50 }
51 51
52 clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; 52 clock_drift /= RTC_CALR_RESOLUTION_PPM;
53 53
54 self.write(false, |rtc| { 54 self.write(false, |rtc| {
55 rtc.calr().write(|w| { 55 rtc.calr().write(|w| {
@@ -107,7 +107,7 @@ impl super::Rtc {
107 // true if initf bit indicates RTC peripheral is in init mode 107 // true if initf bit indicates RTC peripheral is in init mode
108 if init_mode && !r.isr().read().initf() { 108 if init_mode && !r.isr().read().initf() {
109 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode 109 // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
110 r.isr().modify(|w| w.set_init(Init::INITMODE)); 110 r.isr().modify(|w| w.set_init(true));
111 // wait till init state entered 111 // wait till init state entered
112 // ~2 RTCCLK cycles 112 // ~2 RTCCLK cycles
113 while !r.isr().read().initf() {} 113 while !r.isr().read().initf() {}
@@ -116,7 +116,7 @@ impl super::Rtc {
116 let result = f(&r); 116 let result = f(&r);
117 117
118 if init_mode { 118 if init_mode {
119 r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode 119 r.isr().modify(|w| w.set_init(false)); // Exits init mode
120 } 120 }
121 121
122 // Re-enable write protection. 122 // Re-enable write protection.
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index d2d0d9309..114141b64 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType};
2 2
3use super::{sealed, RtcCalibrationCyclePeriod}; 3use super::{sealed, RtcCalibrationCyclePeriod};
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -26,7 +26,7 @@ impl super::Rtc {
26 rtc.cr().modify(|w| { 26 rtc.cr().modify(|w| {
27 w.set_out2en(false); 27 w.set_out2en(false);
28 w.set_tampalrm_type(TampalrmType::PUSHPULL); 28 w.set_tampalrm_type(TampalrmType::PUSHPULL);
29 w.set_tampalrm_pu(TampalrmPu::NOPULLUP); 29 w.set_tampalrm_pu(false);
30 }); 30 });
31 }); 31 });
32 } 32 }
@@ -106,7 +106,7 @@ impl super::Rtc {
106 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); 106 r.wpr().write(|w| w.set_key(Key::DEACTIVATE2));
107 107
108 if init_mode && !r.icsr().read().initf() { 108 if init_mode && !r.icsr().read().initf() {
109 r.icsr().modify(|w| w.set_init(Init::INITMODE)); 109 r.icsr().modify(|w| w.set_init(true));
110 // wait till init state entered 110 // wait till init state entered
111 // ~2 RTCCLK cycles 111 // ~2 RTCCLK cycles
112 while !r.icsr().read().initf() {} 112 while !r.icsr().read().initf() {}
@@ -115,7 +115,7 @@ impl super::Rtc {
115 let result = f(&r); 115 let result = f(&r);
116 116
117 if init_mode { 117 if init_mode {
118 r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode 118 r.icsr().modify(|w| w.set_init(false)); // Exits init mode
119 } 119 }
120 120
121 // Re-enable write protection. 121 // Re-enable write protection.
@@ -135,6 +135,12 @@ impl sealed::Instance for crate::peripherals::RTC {
135 #[cfg(all(feature = "low-power", stm32g4))] 135 #[cfg(all(feature = "low-power", stm32g4))]
136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 136 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
137 137
138 #[cfg(all(feature = "low-power", stm32l5))]
139 const EXTI_WAKEUP_LINE: usize = 17;
140
141 #[cfg(all(feature = "low-power", stm32l5))]
142 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
143
138 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { 144 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
139 #[allow(clippy::if_same_then_else)] 145 #[allow(clippy::if_same_then_else)]
140 if register < Self::BACKUP_REGISTER_COUNT { 146 if register < Self::BACKUP_REGISTER_COUNT {
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index a16d38af1..ef8802184 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -1,8 +1,11 @@
1//! Serial Audio Interface (SAI)
1#![macro_use] 2#![macro_use]
2 3
3use embassy_embedded_hal::SetConfig; 4use core::marker::PhantomData;
5
4use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::{into_ref, PeripheralRef};
5 7
8use self::sealed::WhichSubBlock;
6pub use crate::dma::word; 9pub use crate::dma::word;
7use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 10use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
8use crate::gpio::sealed::{AFType, Pin as _}; 11use crate::gpio::sealed::{AFType, Pin as _};
@@ -11,48 +14,32 @@ use crate::pac::sai::{vals, Sai as Regs};
11use crate::rcc::RccPeripheral; 14use crate::rcc::RccPeripheral;
12use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
13 16
17/// SAI error
14#[derive(Debug, PartialEq, Eq)] 18#[derive(Debug, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))] 19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub enum Error { 20pub enum Error {
21 /// `write` called on a SAI in receive mode.
17 NotATransmitter, 22 NotATransmitter,
23 /// `read` called on a SAI in transmit mode.
18 NotAReceiver, 24 NotAReceiver,
19 OverrunError, 25 /// Overrun
26 Overrun,
20} 27}
21 28
22impl From<ringbuffer::OverrunError> for Error { 29impl From<ringbuffer::OverrunError> for Error {
23 fn from(_: ringbuffer::OverrunError) -> Self { 30 fn from(_: ringbuffer::OverrunError) -> Self {
24 Self::OverrunError 31 Self::Overrun
25 } 32 }
26} 33}
27 34
35/// Master/slave mode.
28#[derive(Copy, Clone)] 36#[derive(Copy, Clone)]
29pub enum SyncBlock { 37#[allow(missing_docs)]
30 None,
31 Sai1BlockA,
32 Sai1BlockB,
33 Sai2BlockA,
34 Sai2BlockB,
35}
36
37#[derive(Copy, Clone)]
38pub enum SyncIn {
39 None,
40 ChannelZero,
41 ChannelOne,
42}
43
44#[derive(Copy, Clone)]
45pub enum Mode { 38pub enum Mode {
46 Master, 39 Master,
47 Slave, 40 Slave,
48} 41}
49 42
50#[derive(Copy, Clone)]
51pub enum TxRx {
52 Transmitter,
53 Receiver,
54}
55
56impl Mode { 43impl Mode {
57 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 44 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
58 const fn mode(&self, tx_rx: TxRx) -> vals::Mode { 45 const fn mode(&self, tx_rx: TxRx) -> vals::Mode {
@@ -69,7 +56,17 @@ impl Mode {
69 } 56 }
70} 57}
71 58
59/// Direction: transmit or receive
72#[derive(Copy, Clone)] 60#[derive(Copy, Clone)]
61#[allow(missing_docs)]
62pub enum TxRx {
63 Transmitter,
64 Receiver,
65}
66
67/// Data slot size.
68#[derive(Copy, Clone)]
69#[allow(missing_docs)]
73pub enum SlotSize { 70pub enum SlotSize {
74 DataSize, 71 DataSize,
75 /// 16 bit data length on 16 bit wide channel 72 /// 16 bit data length on 16 bit wide channel
@@ -80,7 +77,7 @@ pub enum SlotSize {
80 77
81impl SlotSize { 78impl SlotSize {
82 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 79 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
83 pub const fn slotsz(&self) -> vals::Slotsz { 80 const fn slotsz(&self) -> vals::Slotsz {
84 match self { 81 match self {
85 SlotSize::DataSize => vals::Slotsz::DATASIZE, 82 SlotSize::DataSize => vals::Slotsz::DATASIZE,
86 SlotSize::Channel16 => vals::Slotsz::BIT16, 83 SlotSize::Channel16 => vals::Slotsz::BIT16,
@@ -89,7 +86,9 @@ impl SlotSize {
89 } 86 }
90} 87}
91 88
89/// Data size.
92#[derive(Copy, Clone)] 90#[derive(Copy, Clone)]
91#[allow(missing_docs)]
93pub enum DataSize { 92pub enum DataSize {
94 Data8, 93 Data8,
95 Data10, 94 Data10,
@@ -101,7 +100,7 @@ pub enum DataSize {
101 100
102impl DataSize { 101impl DataSize {
103 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 102 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
104 pub const fn ds(&self) -> vals::Ds { 103 const fn ds(&self) -> vals::Ds {
105 match self { 104 match self {
106 DataSize::Data8 => vals::Ds::BIT8, 105 DataSize::Data8 => vals::Ds::BIT8,
107 DataSize::Data10 => vals::Ds::BIT10, 106 DataSize::Data10 => vals::Ds::BIT10,
@@ -113,7 +112,9 @@ impl DataSize {
113 } 112 }
114} 113}
115 114
115/// FIFO threshold level.
116#[derive(Copy, Clone)] 116#[derive(Copy, Clone)]
117#[allow(missing_docs)]
117pub enum FifoThreshold { 118pub enum FifoThreshold {
118 Empty, 119 Empty,
119 Quarter, 120 Quarter,
@@ -124,7 +125,7 @@ pub enum FifoThreshold {
124 125
125impl FifoThreshold { 126impl FifoThreshold {
126 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 127 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
127 pub const fn fth(&self) -> vals::Fth { 128 const fn fth(&self) -> vals::Fth {
128 match self { 129 match self {
129 FifoThreshold::Empty => vals::Fth::EMPTY, 130 FifoThreshold::Empty => vals::Fth::EMPTY,
130 FifoThreshold::Quarter => vals::Fth::QUARTER1, 131 FifoThreshold::Quarter => vals::Fth::QUARTER1,
@@ -135,38 +136,9 @@ impl FifoThreshold {
135 } 136 }
136} 137}
137 138
139/// Output value on mute.
138#[derive(Copy, Clone)] 140#[derive(Copy, Clone)]
139pub enum FifoLevel { 141#[allow(missing_docs)]
140 Empty,
141 FirstQuarter,
142 SecondQuarter,
143 ThirdQuarter,
144 FourthQuarter,
145 Full,
146}
147
148#[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
149impl From<vals::Flvl> for FifoLevel {
150 fn from(flvl: vals::Flvl) -> Self {
151 match flvl {
152 vals::Flvl::EMPTY => FifoLevel::Empty,
153 vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter,
154 vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter,
155 vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter,
156 vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter,
157 vals::Flvl::FULL => FifoLevel::Full,
158 _ => FifoLevel::Empty,
159 }
160 }
161}
162
163#[derive(Copy, Clone)]
164pub enum MuteDetection {
165 NoMute,
166 Mute,
167}
168
169#[derive(Copy, Clone)]
170pub enum MuteValue { 142pub enum MuteValue {
171 Zero, 143 Zero,
172 LastValue, 144 LastValue,
@@ -174,7 +146,7 @@ pub enum MuteValue {
174 146
175impl MuteValue { 147impl MuteValue {
176 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 148 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
177 pub const fn muteval(&self) -> vals::Muteval { 149 const fn muteval(&self) -> vals::Muteval {
178 match self { 150 match self {
179 MuteValue::Zero => vals::Muteval::SENDZERO, 151 MuteValue::Zero => vals::Muteval::SENDZERO,
180 MuteValue::LastValue => vals::Muteval::SENDLAST, 152 MuteValue::LastValue => vals::Muteval::SENDLAST,
@@ -182,13 +154,9 @@ impl MuteValue {
182 } 154 }
183} 155}
184 156
157/// Protocol variant to use.
185#[derive(Copy, Clone)] 158#[derive(Copy, Clone)]
186pub enum OverUnderStatus { 159#[allow(missing_docs)]
187 NoError,
188 OverUnderRunDetected,
189}
190
191#[derive(Copy, Clone)]
192pub enum Protocol { 160pub enum Protocol {
193 Free, 161 Free,
194 Spdif, 162 Spdif,
@@ -197,7 +165,7 @@ pub enum Protocol {
197 165
198impl Protocol { 166impl Protocol {
199 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 167 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
200 pub const fn prtcfg(&self) -> vals::Prtcfg { 168 const fn prtcfg(&self) -> vals::Prtcfg {
201 match self { 169 match self {
202 Protocol::Free => vals::Prtcfg::FREE, 170 Protocol::Free => vals::Prtcfg::FREE,
203 Protocol::Spdif => vals::Prtcfg::SPDIF, 171 Protocol::Spdif => vals::Prtcfg::SPDIF,
@@ -206,7 +174,9 @@ impl Protocol {
206 } 174 }
207} 175}
208 176
177/// Sync input between SAI units/blocks.
209#[derive(Copy, Clone, PartialEq)] 178#[derive(Copy, Clone, PartialEq)]
179#[allow(missing_docs)]
210pub enum SyncInput { 180pub enum SyncInput {
211 /// Not synced to any other SAI unit. 181 /// Not synced to any other SAI unit.
212 None, 182 None,
@@ -218,7 +188,7 @@ pub enum SyncInput {
218} 188}
219 189
220impl SyncInput { 190impl SyncInput {
221 pub const fn syncen(&self) -> vals::Syncen { 191 const fn syncen(&self) -> vals::Syncen {
222 match self { 192 match self {
223 SyncInput::None => vals::Syncen::ASYNCHRONOUS, 193 SyncInput::None => vals::Syncen::ASYNCHRONOUS,
224 SyncInput::Internal => vals::Syncen::INTERNAL, 194 SyncInput::Internal => vals::Syncen::INTERNAL,
@@ -228,8 +198,10 @@ impl SyncInput {
228 } 198 }
229} 199}
230 200
201/// SAI instance to sync from.
231#[cfg(sai_v4)] 202#[cfg(sai_v4)]
232#[derive(Copy, Clone, PartialEq)] 203#[derive(Copy, Clone, PartialEq)]
204#[allow(missing_docs)]
233pub enum SyncInputInstance { 205pub enum SyncInputInstance {
234 #[cfg(peri_sai1)] 206 #[cfg(peri_sai1)]
235 Sai1 = 0, 207 Sai1 = 0,
@@ -241,7 +213,9 @@ pub enum SyncInputInstance {
241 Sai4 = 3, 213 Sai4 = 3,
242} 214}
243 215
216/// Channels (stereo or mono).
244#[derive(Copy, Clone, PartialEq)] 217#[derive(Copy, Clone, PartialEq)]
218#[allow(missing_docs)]
245pub enum StereoMono { 219pub enum StereoMono {
246 Stereo, 220 Stereo,
247 Mono, 221 Mono,
@@ -249,7 +223,7 @@ pub enum StereoMono {
249 223
250impl StereoMono { 224impl StereoMono {
251 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 225 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
252 pub const fn mono(&self) -> vals::Mono { 226 const fn mono(&self) -> vals::Mono {
253 match self { 227 match self {
254 StereoMono::Stereo => vals::Mono::STEREO, 228 StereoMono::Stereo => vals::Mono::STEREO,
255 StereoMono::Mono => vals::Mono::MONO, 229 StereoMono::Mono => vals::Mono::MONO,
@@ -257,15 +231,18 @@ impl StereoMono {
257 } 231 }
258} 232}
259 233
234/// Bit order
260#[derive(Copy, Clone)] 235#[derive(Copy, Clone)]
261pub enum BitOrder { 236pub enum BitOrder {
237 /// Least significant bit first.
262 LsbFirst, 238 LsbFirst,
239 /// Most significant bit first.
263 MsbFirst, 240 MsbFirst,
264} 241}
265 242
266impl BitOrder { 243impl BitOrder {
267 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 244 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
268 pub const fn lsbfirst(&self) -> vals::Lsbfirst { 245 const fn lsbfirst(&self) -> vals::Lsbfirst {
269 match self { 246 match self {
270 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, 247 BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST,
271 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, 248 BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST,
@@ -273,6 +250,7 @@ impl BitOrder {
273 } 250 }
274} 251}
275 252
253/// Frame sync offset.
276#[derive(Copy, Clone)] 254#[derive(Copy, Clone)]
277pub enum FrameSyncOffset { 255pub enum FrameSyncOffset {
278 /// This is used in modes other than standard I2S phillips mode 256 /// This is used in modes other than standard I2S phillips mode
@@ -283,7 +261,7 @@ pub enum FrameSyncOffset {
283 261
284impl FrameSyncOffset { 262impl FrameSyncOffset {
285 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 263 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
286 pub const fn fsoff(&self) -> vals::Fsoff { 264 const fn fsoff(&self) -> vals::Fsoff {
287 match self { 265 match self {
288 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, 266 FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST,
289 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, 267 FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST,
@@ -291,15 +269,18 @@ impl FrameSyncOffset {
291 } 269 }
292} 270}
293 271
272/// Frame sync polarity
294#[derive(Copy, Clone)] 273#[derive(Copy, Clone)]
295pub enum FrameSyncPolarity { 274pub enum FrameSyncPolarity {
275 /// Sync signal is active low.
296 ActiveLow, 276 ActiveLow,
277 /// Sync signal is active high
297 ActiveHigh, 278 ActiveHigh,
298} 279}
299 280
300impl FrameSyncPolarity { 281impl FrameSyncPolarity {
301 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 282 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
302 pub const fn fspol(&self) -> vals::Fspol { 283 const fn fspol(&self) -> vals::Fspol {
303 match self { 284 match self {
304 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, 285 FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE,
305 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, 286 FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE,
@@ -307,7 +288,9 @@ impl FrameSyncPolarity {
307 } 288 }
308} 289}
309 290
291/// Sync definition.
310#[derive(Copy, Clone)] 292#[derive(Copy, Clone)]
293#[allow(missing_docs)]
311pub enum FrameSyncDefinition { 294pub enum FrameSyncDefinition {
312 StartOfFrame, 295 StartOfFrame,
313 ChannelIdentification, 296 ChannelIdentification,
@@ -315,7 +298,7 @@ pub enum FrameSyncDefinition {
315 298
316impl FrameSyncDefinition { 299impl FrameSyncDefinition {
317 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 300 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
318 pub const fn fsdef(&self) -> bool { 301 const fn fsdef(&self) -> bool {
319 match self { 302 match self {
320 FrameSyncDefinition::StartOfFrame => false, 303 FrameSyncDefinition::StartOfFrame => false,
321 FrameSyncDefinition::ChannelIdentification => true, 304 FrameSyncDefinition::ChannelIdentification => true,
@@ -323,7 +306,9 @@ impl FrameSyncDefinition {
323 } 306 }
324} 307}
325 308
309/// Clock strobe.
326#[derive(Copy, Clone)] 310#[derive(Copy, Clone)]
311#[allow(missing_docs)]
327pub enum ClockStrobe { 312pub enum ClockStrobe {
328 Falling, 313 Falling,
329 Rising, 314 Rising,
@@ -331,7 +316,7 @@ pub enum ClockStrobe {
331 316
332impl ClockStrobe { 317impl ClockStrobe {
333 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 318 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
334 pub const fn ckstr(&self) -> vals::Ckstr { 319 const fn ckstr(&self) -> vals::Ckstr {
335 match self { 320 match self {
336 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, 321 ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE,
337 ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, 322 ClockStrobe::Rising => vals::Ckstr::RISINGEDGE,
@@ -339,7 +324,9 @@ impl ClockStrobe {
339 } 324 }
340} 325}
341 326
327/// Complements format for negative samples.
342#[derive(Copy, Clone)] 328#[derive(Copy, Clone)]
329#[allow(missing_docs)]
343pub enum ComplementFormat { 330pub enum ComplementFormat {
344 OnesComplement, 331 OnesComplement,
345 TwosComplement, 332 TwosComplement,
@@ -347,7 +334,7 @@ pub enum ComplementFormat {
347 334
348impl ComplementFormat { 335impl ComplementFormat {
349 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 336 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
350 pub const fn cpl(&self) -> vals::Cpl { 337 const fn cpl(&self) -> vals::Cpl {
351 match self { 338 match self {
352 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, 339 ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT,
353 ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, 340 ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT,
@@ -355,7 +342,9 @@ impl ComplementFormat {
355 } 342 }
356} 343}
357 344
345/// Companding setting.
358#[derive(Copy, Clone)] 346#[derive(Copy, Clone)]
347#[allow(missing_docs)]
359pub enum Companding { 348pub enum Companding {
360 None, 349 None,
361 MuLaw, 350 MuLaw,
@@ -364,7 +353,7 @@ pub enum Companding {
364 353
365impl Companding { 354impl Companding {
366 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 355 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
367 pub const fn comp(&self) -> vals::Comp { 356 const fn comp(&self) -> vals::Comp {
368 match self { 357 match self {
369 Companding::None => vals::Comp::NOCOMPANDING, 358 Companding::None => vals::Comp::NOCOMPANDING,
370 Companding::MuLaw => vals::Comp::MULAW, 359 Companding::MuLaw => vals::Comp::MULAW,
@@ -373,7 +362,9 @@ impl Companding {
373 } 362 }
374} 363}
375 364
365/// Output drive
376#[derive(Copy, Clone)] 366#[derive(Copy, Clone)]
367#[allow(missing_docs)]
377pub enum OutputDrive { 368pub enum OutputDrive {
378 OnStart, 369 OnStart,
379 Immediately, 370 Immediately,
@@ -381,7 +372,7 @@ pub enum OutputDrive {
381 372
382impl OutputDrive { 373impl OutputDrive {
383 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 374 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
384 pub const fn outdriv(&self) -> vals::Outdriv { 375 const fn outdriv(&self) -> vals::Outdriv {
385 match self { 376 match self {
386 OutputDrive::OnStart => vals::Outdriv::ONSTART, 377 OutputDrive::OnStart => vals::Outdriv::ONSTART,
387 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, 378 OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY,
@@ -389,7 +380,9 @@ impl OutputDrive {
389 } 380 }
390} 381}
391 382
383/// Master clock divider.
392#[derive(Copy, Clone, PartialEq)] 384#[derive(Copy, Clone, PartialEq)]
385#[allow(missing_docs)]
393pub enum MasterClockDivider { 386pub enum MasterClockDivider {
394 MasterClockDisabled, 387 MasterClockDisabled,
395 Div1, 388 Div1,
@@ -412,7 +405,7 @@ pub enum MasterClockDivider {
412 405
413impl MasterClockDivider { 406impl MasterClockDivider {
414 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] 407 #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))]
415 pub const fn mckdiv(&self) -> u8 { 408 const fn mckdiv(&self) -> u8 {
416 match self { 409 match self {
417 MasterClockDivider::MasterClockDisabled => 0, 410 MasterClockDivider::MasterClockDisabled => 0,
418 MasterClockDivider::Div1 => 0, 411 MasterClockDivider::Div1 => 0,
@@ -436,6 +429,7 @@ impl MasterClockDivider {
436} 429}
437 430
438/// [`SAI`] configuration. 431/// [`SAI`] configuration.
432#[allow(missing_docs)]
439#[non_exhaustive] 433#[non_exhaustive]
440#[derive(Copy, Clone)] 434#[derive(Copy, Clone)]
441pub struct Config { 435pub struct Config {
@@ -459,7 +453,7 @@ pub struct Config {
459 pub clock_strobe: ClockStrobe, 453 pub clock_strobe: ClockStrobe,
460 pub output_drive: OutputDrive, 454 pub output_drive: OutputDrive,
461 pub master_clock_divider: MasterClockDivider, 455 pub master_clock_divider: MasterClockDivider,
462 pub is_high_impedenane_on_inactive_slot: bool, 456 pub is_high_impedance_on_inactive_slot: bool,
463 pub fifo_threshold: FifoThreshold, 457 pub fifo_threshold: FifoThreshold,
464 pub companding: Companding, 458 pub companding: Companding,
465 pub complement_format: ComplementFormat, 459 pub complement_format: ComplementFormat,
@@ -490,7 +484,7 @@ impl Default for Config {
490 master_clock_divider: MasterClockDivider::MasterClockDisabled, 484 master_clock_divider: MasterClockDivider::MasterClockDisabled,
491 clock_strobe: ClockStrobe::Rising, 485 clock_strobe: ClockStrobe::Rising,
492 output_drive: OutputDrive::Immediately, 486 output_drive: OutputDrive::Immediately,
493 is_high_impedenane_on_inactive_slot: false, 487 is_high_impedance_on_inactive_slot: false,
494 fifo_threshold: FifoThreshold::ThreeQuarters, 488 fifo_threshold: FifoThreshold::ThreeQuarters,
495 companding: Companding::None, 489 companding: Companding::None,
496 complement_format: ComplementFormat::TwosComplement, 490 complement_format: ComplementFormat::TwosComplement,
@@ -501,23 +495,10 @@ impl Default for Config {
501} 495}
502 496
503impl Config { 497impl Config {
504 pub fn new_i2s() -> Self { 498 /// Create a new config with all default values.
499 pub fn new() -> Self {
505 return Default::default(); 500 return Default::default();
506 } 501 }
507
508 pub fn new_msb_first() -> Self {
509 Self {
510 bit_order: BitOrder::MsbFirst,
511 frame_sync_offset: FrameSyncOffset::OnFirstBit,
512 ..Default::default()
513 }
514 }
515}
516
517#[derive(Copy, Clone)]
518enum WhichSubBlock {
519 A = 0,
520 B = 1,
521} 502}
522 503
523enum RingBuffer<'d, C: Channel, W: word::Word> { 504enum RingBuffer<'d, C: Channel, W: word::Word> {
@@ -531,28 +512,6 @@ fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut
531 ch.dr().as_ptr() as _ 512 ch.dr().as_ptr() as _
532} 513}
533 514
534pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> {
535 _peri: PeripheralRef<'d, T>,
536 sd: Option<PeripheralRef<'d, AnyPin>>,
537 fs: Option<PeripheralRef<'d, AnyPin>>,
538 sck: Option<PeripheralRef<'d, AnyPin>>,
539 mclk: Option<PeripheralRef<'d, AnyPin>>,
540 ring_buffer: RingBuffer<'d, C, W>,
541 sub_block: WhichSubBlock,
542}
543
544pub struct SubBlockA {}
545pub struct SubBlockB {}
546
547pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>);
548pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>);
549
550pub struct Sai<'d, T: Instance> {
551 _peri: PeripheralRef<'d, T>,
552 sub_block_a_peri: Option<SubBlockAPeripheral<'d, T>>,
553 sub_block_b_peri: Option<SubBlockBPeripheral<'d, T>>,
554}
555
556// return the type for (sd, sck) 515// return the type for (sd, sck)
557fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { 516fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) {
558 ( 517 (
@@ -583,42 +542,14 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>(
583 }; 542 };
584 match tx_rx { 543 match tx_rx {
585 TxRx::Transmitter => RingBuffer::Writable(unsafe { 544 TxRx::Transmitter => RingBuffer::Writable(unsafe {
586 WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) 545 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
587 }), 546 }),
588 TxRx::Receiver => RingBuffer::Readable(unsafe { 547 TxRx::Receiver => RingBuffer::Readable(unsafe {
589 ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) 548 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
590 }), 549 }),
591 } 550 }
592} 551}
593 552
594impl<'d, T: Instance> Sai<'d, T> {
595 pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self {
596 T::enable_and_reset();
597
598 Self {
599 _peri: unsafe { peri.clone_unchecked().into_ref() },
600 sub_block_a_peri: Some(SubBlockAPeripheral(unsafe { peri.clone_unchecked().into_ref() })),
601 sub_block_b_peri: Some(SubBlockBPeripheral(peri.into_ref())),
602 }
603 }
604
605 pub fn take_sub_block_a(self: &mut Self) -> Option<SubBlockAPeripheral<'d, T>> {
606 if self.sub_block_a_peri.is_some() {
607 self.sub_block_a_peri.take()
608 } else {
609 None
610 }
611 }
612
613 pub fn take_sub_block_b(self: &mut Self) -> Option<SubBlockBPeripheral<'d, T>> {
614 if self.sub_block_b_peri.is_some() {
615 self.sub_block_b_peri.take()
616 } else {
617 None
618 }
619 }
620}
621
622fn update_synchronous_config(config: &mut Config) { 553fn update_synchronous_config(config: &mut Config) {
623 config.mode = Mode::Slave; 554 config.mode = Mode::Slave;
624 config.sync_output = false; 555 config.sync_output = false;
@@ -636,122 +567,58 @@ fn update_synchronous_config(config: &mut Config) {
636 } 567 }
637} 568}
638 569
639impl SubBlockA { 570/// SAI subblock instance.
640 pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( 571pub struct SubBlock<'d, T, S: SubBlockInstance> {
641 peri: SubBlockAPeripheral<'d, T>, 572 peri: PeripheralRef<'d, T>,
642 sck: impl Peripheral<P = impl SckAPin<T>> + 'd, 573 _phantom: PhantomData<S>,
643 sd: impl Peripheral<P = impl SdAPin<T>> + 'd, 574}
644 fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
645 mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd,
646 dma: impl Peripheral<P = C> + 'd,
647 dma_buf: &'d mut [W],
648 mut config: Config,
649 ) -> SubBlock<'d, T, C, W>
650 where
651 C: Channel + DmaA<T>,
652 {
653 into_ref!(mclk);
654
655 let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
656
657 mclk.set_as_af(mclk.af_num(), ck_af_type);
658 mclk.set_speed(crate::gpio::Speed::VeryHigh);
659
660 if config.master_clock_divider == MasterClockDivider::MasterClockDisabled {
661 config.master_clock_divider = MasterClockDivider::Div1;
662 }
663
664 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
665 }
666
667 pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>(
668 peri: SubBlockAPeripheral<'d, T>,
669 sck: impl Peripheral<P = impl SckAPin<T>> + 'd,
670 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
671 fs: impl Peripheral<P = impl FsAPin<T>> + 'd,
672 dma: impl Peripheral<P = C> + 'd,
673 dma_buf: &'d mut [W],
674 config: Config,
675 ) -> SubBlock<'d, T, C, W>
676 where
677 C: Channel + DmaA<T>,
678 {
679 let peri = peri.0;
680 into_ref!(peri, dma, sck, sd, fs);
681
682 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
683 sd.set_as_af(sd.af_num(), sd_af_type);
684 sd.set_speed(crate::gpio::Speed::VeryHigh);
685
686 sck.set_as_af(sck.af_num(), ck_af_type);
687 sck.set_speed(crate::gpio::Speed::VeryHigh);
688 fs.set_as_af(fs.af_num(), ck_af_type);
689 fs.set_speed(crate::gpio::Speed::VeryHigh);
690 575
691 let sub_block = WhichSubBlock::A; 576/// Split the main SAIx peripheral into the two subblocks.
692 let request = dma.request(); 577///
578/// You can then create a [`Sai`] driver for each each half.
579pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
580 into_ref!(peri);
581 T::enable_and_reset();
693 582
694 SubBlock::new_inner( 583 (
584 SubBlock {
585 peri: unsafe { peri.clone_unchecked() },
586 _phantom: PhantomData,
587 },
588 SubBlock {
695 peri, 589 peri,
696 sub_block, 590 _phantom: PhantomData,
697 Some(sck.map_into()), 591 },
698 None, 592 )
699 Some(sd.map_into()), 593}
700 Some(fs.map_into()),
701 get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx),
702 config,
703 )
704 }
705
706 pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>(
707 peri: SubBlockAPeripheral<'d, T>,
708 sd: impl Peripheral<P = impl SdAPin<T>> + 'd,
709 dma: impl Peripheral<P = C> + 'd,
710 dma_buf: &'d mut [W],
711 mut config: Config,
712 ) -> SubBlock<'d, T, C, W>
713 where
714 C: Channel + DmaA<T>,
715 {
716 update_synchronous_config(&mut config);
717
718 let peri = peri.0;
719 into_ref!(dma, peri, sd);
720
721 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
722
723 sd.set_as_af(sd.af_num(), sd_af_type);
724 sd.set_speed(crate::gpio::Speed::VeryHigh);
725
726 let sub_block = WhichSubBlock::A;
727 let request = dma.request();
728 594
729 SubBlock::new_inner( 595/// SAI sub-block driver.
730 peri, 596pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> {
731 sub_block, 597 _peri: PeripheralRef<'d, T>,
732 None, 598 sd: Option<PeripheralRef<'d, AnyPin>>,
733 None, 599 fs: Option<PeripheralRef<'d, AnyPin>>,
734 Some(sd.map_into()), 600 sck: Option<PeripheralRef<'d, AnyPin>>,
735 None, 601 mclk: Option<PeripheralRef<'d, AnyPin>>,
736 get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), 602 ring_buffer: RingBuffer<'d, C, W>,
737 config, 603 sub_block: WhichSubBlock,
738 )
739 }
740} 604}
741 605
742impl SubBlockB { 606impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> {
743 pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( 607 /// Create a new SAI driver in asynchronous mode with MCLK.
744 peri: SubBlockBPeripheral<'d, T>, 608 ///
745 sck: impl Peripheral<P = impl SckBPin<T>> + 'd, 609 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
746 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 610 pub fn new_asynchronous_with_mclk<S: SubBlockInstance>(
747 fs: impl Peripheral<P = impl FsBPin<T>> + 'd, 611 peri: SubBlock<'d, T, S>,
748 mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd, 612 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
613 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
614 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
615 mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd,
749 dma: impl Peripheral<P = C> + 'd, 616 dma: impl Peripheral<P = C> + 'd,
750 dma_buf: &'d mut [W], 617 dma_buf: &'d mut [W],
751 mut config: Config, 618 mut config: Config,
752 ) -> SubBlock<'d, T, C, W> 619 ) -> Self
753 where 620 where
754 C: Channel + DmaB<T>, 621 C: Channel + Dma<T, S>,
755 { 622 {
756 into_ref!(mclk); 623 into_ref!(mclk);
757 624
@@ -767,23 +634,25 @@ impl SubBlockB {
767 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) 634 Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config)
768 } 635 }
769 636
770 pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( 637 /// Create a new SAI driver in asynchronous mode without MCLK.
771 peri: SubBlockBPeripheral<'d, T>, 638 ///
772 sck: impl Peripheral<P = impl SckBPin<T>> + 'd, 639 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
773 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 640 pub fn new_asynchronous<S: SubBlockInstance>(
774 fs: impl Peripheral<P = impl FsBPin<T>> + 'd, 641 peri: SubBlock<'d, T, S>,
642 sck: impl Peripheral<P = impl SckPin<T, S>> + 'd,
643 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
644 fs: impl Peripheral<P = impl FsPin<T, S>> + 'd,
775 dma: impl Peripheral<P = C> + 'd, 645 dma: impl Peripheral<P = C> + 'd,
776 dma_buf: &'d mut [W], 646 dma_buf: &'d mut [W],
777 config: Config, 647 config: Config,
778 ) -> SubBlock<'d, T, C, W> 648 ) -> Self
779 where 649 where
780 C: Channel + DmaB<T>, 650 C: Channel + Dma<T, S>,
781 { 651 {
782 let peri = peri.0; 652 let peri = peri.peri;
783 into_ref!(dma, peri, sck, sd, fs); 653 into_ref!(peri, dma, sck, sd, fs);
784 654
785 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); 655 let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx);
786
787 sd.set_as_af(sd.af_num(), sd_af_type); 656 sd.set_as_af(sd.af_num(), sd_af_type);
788 sd.set_speed(crate::gpio::Speed::VeryHigh); 657 sd.set_speed(crate::gpio::Speed::VeryHigh);
789 658
@@ -792,10 +661,10 @@ impl SubBlockB {
792 fs.set_as_af(fs.af_num(), ck_af_type); 661 fs.set_as_af(fs.af_num(), ck_af_type);
793 fs.set_speed(crate::gpio::Speed::VeryHigh); 662 fs.set_speed(crate::gpio::Speed::VeryHigh);
794 663
795 let sub_block = WhichSubBlock::B; 664 let sub_block = S::WHICH;
796 let request = dma.request(); 665 let request = dma.request();
797 666
798 SubBlock::new_inner( 667 Self::new_inner(
799 peri, 668 peri,
800 sub_block, 669 sub_block,
801 Some(sck.map_into()), 670 Some(sck.map_into()),
@@ -807,18 +676,22 @@ impl SubBlockB {
807 ) 676 )
808 } 677 }
809 678
810 pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( 679 /// Create a new SAI driver in synchronous mode.
811 peri: SubBlockBPeripheral<'d, T>, 680 ///
812 sd: impl Peripheral<P = impl SdBPin<T>> + 'd, 681 /// You can obtain the [`SubBlock`] with [`split_subblocks`].
682 pub fn new_synchronous<S: SubBlockInstance>(
683 peri: SubBlock<'d, T, S>,
684 sd: impl Peripheral<P = impl SdPin<T, S>> + 'd,
813 dma: impl Peripheral<P = C> + 'd, 685 dma: impl Peripheral<P = C> + 'd,
814 dma_buf: &'d mut [W], 686 dma_buf: &'d mut [W],
815 mut config: Config, 687 mut config: Config,
816 ) -> SubBlock<'d, T, C, W> 688 ) -> Self
817 where 689 where
818 C: Channel + DmaB<T>, 690 C: Channel + Dma<T, S>,
819 { 691 {
820 update_synchronous_config(&mut config); 692 update_synchronous_config(&mut config);
821 let peri = peri.0; 693
694 let peri = peri.peri;
822 into_ref!(dma, peri, sd); 695 into_ref!(dma, peri, sd);
823 696
824 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); 697 let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx);
@@ -826,10 +699,10 @@ impl SubBlockB {
826 sd.set_as_af(sd.af_num(), sd_af_type); 699 sd.set_as_af(sd.af_num(), sd_af_type);
827 sd.set_speed(crate::gpio::Speed::VeryHigh); 700 sd.set_speed(crate::gpio::Speed::VeryHigh);
828 701
829 let sub_block = WhichSubBlock::B; 702 let sub_block = S::WHICH;
830 let request = dma.request(); 703 let request = dma.request();
831 704
832 SubBlock::new_inner( 705 Self::new_inner(
833 peri, 706 peri,
834 sub_block, 707 sub_block,
835 None, 708 None,
@@ -840,26 +713,6 @@ impl SubBlockB {
840 config, 713 config,
841 ) 714 )
842 } 715 }
843}
844
845impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
846 pub fn start(self: &mut Self) {
847 match self.ring_buffer {
848 RingBuffer::Writable(ref mut rb) => {
849 rb.start();
850 }
851 RingBuffer::Readable(ref mut rb) => {
852 rb.start();
853 }
854 }
855 }
856
857 fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool {
858 match ring_buffer {
859 RingBuffer::Writable(_) => true,
860 _ => false,
861 }
862 }
863 716
864 fn new_inner( 717 fn new_inner(
865 peri: impl Peripheral<P = T> + 'd, 718 peri: impl Peripheral<P = T> + 'd,
@@ -929,7 +782,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
929 w.set_cpl(config.complement_format.cpl()); 782 w.set_cpl(config.complement_format.cpl());
930 w.set_muteval(config.mute_value.muteval()); 783 w.set_muteval(config.mute_value.muteval());
931 w.set_mutecnt(config.mute_detection_counter.0 as u8); 784 w.set_mutecnt(config.mute_detection_counter.0 as u8);
932 w.set_tris(config.is_high_impedenane_on_inactive_slot); 785 w.set_tris(config.is_high_impedance_on_inactive_slot);
933 }); 786 });
934 787
935 ch.frcr().modify(|w| { 788 ch.frcr().modify(|w| {
@@ -965,10 +818,31 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
965 } 818 }
966 } 819 }
967 820
821 /// Start the SAI driver.
822 pub fn start(&mut self) {
823 match self.ring_buffer {
824 RingBuffer::Writable(ref mut rb) => {
825 rb.start();
826 }
827 RingBuffer::Readable(ref mut rb) => {
828 rb.start();
829 }
830 }
831 }
832
833 fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool {
834 match ring_buffer {
835 RingBuffer::Writable(_) => true,
836 _ => false,
837 }
838 }
839
840 /// Reset SAI operation.
968 pub fn reset() { 841 pub fn reset() {
969 T::enable_and_reset(); 842 T::enable_and_reset();
970 } 843 }
971 844
845 /// Flush.
972 pub fn flush(&mut self) { 846 pub fn flush(&mut self) {
973 let ch = T::REGS.ch(self.sub_block as usize); 847 let ch = T::REGS.ch(self.sub_block as usize);
974 ch.cr1().modify(|w| w.set_saien(false)); 848 ch.cr1().modify(|w| w.set_saien(false));
@@ -983,19 +857,18 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
983 ch.cr1().modify(|w| w.set_saien(true)); 857 ch.cr1().modify(|w| w.set_saien(true));
984 } 858 }
985 859
860 /// Enable or disable mute.
986 pub fn set_mute(&mut self, value: bool) { 861 pub fn set_mute(&mut self, value: bool) {
987 let ch = T::REGS.ch(self.sub_block as usize); 862 let ch = T::REGS.ch(self.sub_block as usize);
988 ch.cr2().modify(|w| w.set_mute(value)); 863 ch.cr2().modify(|w| w.set_mute(value));
989 } 864 }
990 865
991 #[allow(dead_code)] 866 /// Write data to the SAI ringbuffer.
992 /// Reconfigures it with the supplied config. 867 ///
993 fn reconfigure(&mut self, _config: Config) {} 868 /// This appends the data to the buffer and returns immediately. The
994 869 /// data will be transmitted in the background.
995 pub fn get_current_config(&self) -> Config { 870 ///
996 Config::default() 871 /// If there's no space in the buffer, this waits until there is.
997 }
998
999 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { 872 pub async fn write(&mut self, data: &[W]) -> Result<(), Error> {
1000 match &mut self.ring_buffer { 873 match &mut self.ring_buffer {
1001 RingBuffer::Writable(buffer) => { 874 RingBuffer::Writable(buffer) => {
@@ -1006,6 +879,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
1006 } 879 }
1007 } 880 }
1008 881
882 /// Read data from the SAI ringbuffer.
883 ///
884 /// SAI is always receiving data in the background. This function pops already-received
885 /// data from the buffer.
886 ///
887 /// If there's less than `data.len()` data in the buffer, this waits until there is.
1009 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { 888 pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> {
1010 match &mut self.ring_buffer { 889 match &mut self.ring_buffer {
1011 RingBuffer::Readable(buffer) => { 890 RingBuffer::Readable(buffer) => {
@@ -1017,7 +896,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> {
1017 } 896 }
1018} 897}
1019 898
1020impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { 899impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> {
1021 fn drop(&mut self) { 900 fn drop(&mut self) {
1022 let ch = T::REGS.ch(self.sub_block as usize); 901 let ch = T::REGS.ch(self.sub_block as usize);
1023 ch.cr1().modify(|w| w.set_saien(false)); 902 ch.cr1().modify(|w| w.set_saien(false));
@@ -1034,22 +913,43 @@ pub(crate) mod sealed {
1034 pub trait Instance { 913 pub trait Instance {
1035 const REGS: Regs; 914 const REGS: Regs;
1036 } 915 }
916
917 #[derive(Copy, Clone)]
918 pub enum WhichSubBlock {
919 A = 0,
920 B = 1,
921 }
922
923 pub trait SubBlock {
924 const WHICH: WhichSubBlock;
925 }
1037} 926}
1038 927
1039pub trait Word: word::Word {} 928/// Sub-block instance trait.
929pub trait SubBlockInstance: sealed::SubBlock {}
1040 930
931/// Sub-block A.
932pub enum A {}
933impl sealed::SubBlock for A {
934 const WHICH: WhichSubBlock = WhichSubBlock::A;
935}
936impl SubBlockInstance for A {}
937
938/// Sub-block B.
939pub enum B {}
940impl sealed::SubBlock for B {
941 const WHICH: WhichSubBlock = WhichSubBlock::B;
942}
943impl SubBlockInstance for B {}
944
945/// SAI instance trait.
1041pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 946pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
1042pin_trait!(SckAPin, Instance); 947pin_trait!(SckPin, Instance, SubBlockInstance);
1043pin_trait!(SckBPin, Instance); 948pin_trait!(FsPin, Instance, SubBlockInstance);
1044pin_trait!(FsAPin, Instance); 949pin_trait!(SdPin, Instance, SubBlockInstance);
1045pin_trait!(FsBPin, Instance); 950pin_trait!(MclkPin, Instance, SubBlockInstance);
1046pin_trait!(SdAPin, Instance); 951
1047pin_trait!(SdBPin, Instance); 952dma_trait!(Dma, Instance, SubBlockInstance);
1048pin_trait!(MclkAPin, Instance);
1049pin_trait!(MclkBPin, Instance);
1050
1051dma_trait!(DmaA, Instance);
1052dma_trait!(DmaB, Instance);
1053 953
1054foreach_peripheral!( 954foreach_peripheral!(
1055 (sai, $inst:ident) => { 955 (sai, $inst:ident) => {
@@ -1060,13 +960,3 @@ foreach_peripheral!(
1060 impl Instance for peripherals::$inst {} 960 impl Instance for peripherals::$inst {}
1061 }; 961 };
1062); 962);
1063
1064impl<'d, T: Instance> SetConfig for Sai<'d, T> {
1065 type Config = Config;
1066 type ConfigError = ();
1067 fn set_config(&mut self, _config: &Self::Config) -> Result<(), ()> {
1068 // self.reconfigure(*config);
1069
1070 Ok(())
1071 }
1072}
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 27a12062c..debe26c88 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -1,3 +1,4 @@
1//! Secure Digital / MultiMedia Card (SDMMC)
1#![macro_use] 2#![macro_use]
2 3
3use core::default::Default; 4use core::default::Default;
@@ -53,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000);
53 54
54/// The signalling scheme used on the SDMMC bus 55/// The signalling scheme used on the SDMMC bus
55#[non_exhaustive] 56#[non_exhaustive]
57#[allow(missing_docs)]
56#[derive(Debug, Copy, Clone, PartialEq, Eq)] 58#[derive(Debug, Copy, Clone, PartialEq, Eq)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))] 59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum Signalling { 60pub enum Signalling {
@@ -69,6 +71,9 @@ impl Default for Signalling {
69 } 71 }
70} 72}
71 73
74/// Aligned data block for SDMMC transfers.
75///
76/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
72#[repr(align(4))] 77#[repr(align(4))]
73#[derive(Debug, Clone, PartialEq, Eq)] 78#[derive(Debug, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -93,17 +98,23 @@ impl DerefMut for DataBlock {
93#[derive(Debug, Copy, Clone, PartialEq, Eq)] 98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))] 99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub enum Error { 100pub enum Error {
101 /// Timeout reported by the hardware
96 Timeout, 102 Timeout,
103 /// Timeout reported by the software driver.
97 SoftwareTimeout, 104 SoftwareTimeout,
105 /// Unsupported card version.
98 UnsupportedCardVersion, 106 UnsupportedCardVersion,
107 /// Unsupported card type.
99 UnsupportedCardType, 108 UnsupportedCardType,
109 /// CRC error.
100 Crc, 110 Crc,
101 DataCrcFail, 111 /// No card inserted.
102 RxOverFlow,
103 NoCard, 112 NoCard,
113 /// Bad clock supplied to the SDMMC peripheral.
104 BadClock, 114 BadClock,
115 /// Signaling switch failed.
105 SignalingSwitchFailed, 116 SignalingSwitchFailed,
106 PeripheralBusy, 117 /// ST bit error.
107 #[cfg(sdmmc_v1)] 118 #[cfg(sdmmc_v1)]
108 StBitErr, 119 StBitErr,
109} 120}
@@ -282,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
282 293
283#[cfg(sdmmc_v1)] 294#[cfg(sdmmc_v1)]
284impl<'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.
285 pub fn new_1bit( 297 pub fn new_1bit(
286 sdmmc: impl Peripheral<P = T> + 'd, 298 sdmmc: impl Peripheral<P = T> + 'd,
287 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 299 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -316,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
316 ) 328 )
317 } 329 }
318 330
331 /// Create a new SDMMC driver, with 4 data lanes.
319 pub fn new_4bit( 332 pub fn new_4bit(
320 sdmmc: impl Peripheral<P = T> + 'd, 333 sdmmc: impl Peripheral<P = T> + 'd,
321 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 334 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -362,6 +375,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
362 375
363#[cfg(sdmmc_v2)] 376#[cfg(sdmmc_v2)]
364impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { 377impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
378 /// Create a new SDMMC driver, with 1 data lane.
365 pub fn new_1bit( 379 pub fn new_1bit(
366 sdmmc: impl Peripheral<P = T> + 'd, 380 sdmmc: impl Peripheral<P = T> + 'd,
367 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 381 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -395,6 +409,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
395 ) 409 )
396 } 410 }
397 411
412 /// Create a new SDMMC driver, with 4 data lanes.
398 pub fn new_4bit( 413 pub fn new_4bit(
399 sdmmc: impl Peripheral<P = T> + 'd, 414 sdmmc: impl Peripheral<P = T> + 'd,
400 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 415 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -496,7 +511,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
496 } 511 }
497 512
498 /// Data transfer is in progress 513 /// Data transfer is in progress
499 #[inline(always)] 514 #[inline]
500 fn data_active() -> bool { 515 fn data_active() -> bool {
501 let regs = T::regs(); 516 let regs = T::regs();
502 517
@@ -508,7 +523,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
508 } 523 }
509 524
510 /// Coammand transfer is in progress 525 /// Coammand transfer is in progress
511 #[inline(always)] 526 #[inline]
512 fn cmd_active() -> bool { 527 fn cmd_active() -> bool {
513 let regs = T::regs(); 528 let regs = T::regs();
514 529
@@ -520,7 +535,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
520 } 535 }
521 536
522 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) 537 /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
523 #[inline(always)] 538 #[inline]
524 fn wait_idle() { 539 fn wait_idle() {
525 while Self::data_active() || Self::cmd_active() {} 540 while Self::data_active() || Self::cmd_active() {}
526 } 541 }
@@ -836,7 +851,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
836 } 851 }
837 852
838 /// Clear flags in interrupt clear register 853 /// Clear flags in interrupt clear register
839 #[inline(always)] 854 #[inline]
840 fn clear_interrupt_flags() { 855 fn clear_interrupt_flags() {
841 let regs = T::regs(); 856 let regs = T::regs();
842 regs.icr().write(|w| { 857 regs.icr().write(|w| {
@@ -1151,7 +1166,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1151 Ok(()) 1166 Ok(())
1152 } 1167 }
1153 1168
1154 #[inline(always)] 1169 /// Read a data block.
1170 #[inline]
1155 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { 1171 pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
1156 let card_capacity = self.card()?.card_type; 1172 let card_capacity = self.card()?.card_type;
1157 1173
@@ -1203,6 +1219,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1203 res 1219 res
1204 } 1220 }
1205 1221
1222 /// Write a data block.
1206 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { 1223 pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
1207 let card = self.card.as_mut().ok_or(Error::NoCard)?; 1224 let card = self.card.as_mut().ok_or(Error::NoCard)?;
1208 1225
@@ -1282,7 +1299,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1282 /// 1299 ///
1283 /// Returns Error::NoCard if [`init_card`](#method.init_card) 1300 /// Returns Error::NoCard if [`init_card`](#method.init_card)
1284 /// has not previously succeeded 1301 /// has not previously succeeded
1285 #[inline(always)] 1302 #[inline]
1286 pub fn card(&self) -> Result<&Card, Error> { 1303 pub fn card(&self) -> Result<&Card, Error> {
1287 self.card.as_ref().ok_or(Error::NoCard) 1304 self.card.as_ref().ok_or(Error::NoCard)
1288 } 1305 }
@@ -1418,7 +1435,9 @@ pub(crate) mod sealed {
1418 pub trait Pins<T: Instance> {} 1435 pub trait Pins<T: Instance> {}
1419} 1436}
1420 1437
1438/// SDMMC instance trait.
1421pub trait Instance: sealed::Instance + RccPeripheral + 'static {} 1439pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
1440
1422pin_trait!(CkPin, Instance); 1441pin_trait!(CkPin, Instance);
1423pin_trait!(CmdPin, Instance); 1442pin_trait!(CmdPin, Instance);
1424pin_trait!(D0Pin, Instance); 1443pin_trait!(D0Pin, Instance);
@@ -1433,7 +1452,10 @@ pin_trait!(D7Pin, Instance);
1433#[cfg(sdmmc_v1)] 1452#[cfg(sdmmc_v1)]
1434dma_trait!(SdmmcDma, Instance); 1453dma_trait!(SdmmcDma, Instance);
1435 1454
1436// SDMMCv2 uses internal DMA 1455/// DMA instance trait.
1456///
1457/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of
1458/// using ST's system-wide DMA peripheral.
1437#[cfg(sdmmc_v2)] 1459#[cfg(sdmmc_v2)]
1438pub trait SdmmcDma<T: Instance> {} 1460pub trait SdmmcDma<T: Instance> {}
1439#[cfg(sdmmc_v2)] 1461#[cfg(sdmmc_v2)]
@@ -1516,53 +1538,3 @@ foreach_peripheral!(
1516 impl Instance for peripherals::$inst {} 1538 impl Instance for peripherals::$inst {}
1517 }; 1539 };
1518); 1540);
1519
1520#[cfg(feature = "embedded-sdmmc")]
1521mod sdmmc_rs {
1522 use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
1523
1524 use super::*;
1525
1526 impl<'d, T: Instance, Dma: SdmmcDma<T>> BlockDevice for Sdmmc<'d, T, Dma> {
1527 type Error = Error;
1528
1529 async fn read(
1530 &mut self,
1531 blocks: &mut [Block],
1532 start_block_idx: BlockIdx,
1533 _reason: &str,
1534 ) -> Result<(), Self::Error> {
1535 let mut address = start_block_idx.0;
1536
1537 for block in blocks.iter_mut() {
1538 let block: &mut [u8; 512] = &mut block.contents;
1539
1540 // NOTE(unsafe) Block uses align(4)
1541 let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) };
1542 self.read_block(address, block).await?;
1543 address += 1;
1544 }
1545 Ok(())
1546 }
1547
1548 async fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
1549 let mut address = start_block_idx.0;
1550
1551 for block in blocks.iter() {
1552 let block: &[u8; 512] = &block.contents;
1553
1554 // NOTE(unsafe) DataBlock uses align 4
1555 let block = unsafe { &*(block as *const _ as *const DataBlock) };
1556 self.write_block(address, block).await?;
1557 address += 1;
1558 }
1559 Ok(())
1560 }
1561
1562 fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1563 let card = self.card()?;
1564 let count = card.csd.block_count();
1565 Ok(BlockCount(count))
1566 }
1567 }
1568}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 92599c75e..23f027e70 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1,3 +1,4 @@
1//! Serial Peripheral Interface (SPI)
1#![macro_use] 2#![macro_use]
2 3
3use core::ptr; 4use core::ptr;
@@ -15,27 +16,38 @@ use crate::rcc::RccPeripheral;
15use crate::time::Hertz; 16use crate::time::Hertz;
16use crate::{peripherals, Peripheral}; 17use crate::{peripherals, Peripheral};
17 18
19/// SPI error.
18#[derive(Debug, PartialEq, Eq)] 20#[derive(Debug, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))] 21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Error { 22pub enum Error {
23 /// Invalid framing.
21 Framing, 24 Framing,
25 /// CRC error (only if hardware CRC checking is enabled).
22 Crc, 26 Crc,
27 /// Mode fault
23 ModeFault, 28 ModeFault,
29 /// Overrun.
24 Overrun, 30 Overrun,
25} 31}
26 32
27// TODO move upwards in the tree 33/// SPI bit order
28#[derive(Copy, Clone)] 34#[derive(Copy, Clone)]
29pub enum BitOrder { 35pub enum BitOrder {
36 /// Least significant bit first.
30 LsbFirst, 37 LsbFirst,
38 /// Most significant bit first.
31 MsbFirst, 39 MsbFirst,
32} 40}
33 41
42/// SPI configuration.
34#[non_exhaustive] 43#[non_exhaustive]
35#[derive(Copy, Clone)] 44#[derive(Copy, Clone)]
36pub struct Config { 45pub struct Config {
46 /// SPI mode.
37 pub mode: Mode, 47 pub mode: Mode,
48 /// Bit order.
38 pub bit_order: BitOrder, 49 pub bit_order: BitOrder,
50 /// Clock frequency.
39 pub frequency: Hertz, 51 pub frequency: Hertz,
40} 52}
41 53
@@ -72,6 +84,7 @@ impl Config {
72 } 84 }
73} 85}
74 86
87/// SPI driver.
75pub struct Spi<'d, T: Instance, Tx, Rx> { 88pub struct Spi<'d, T: Instance, Tx, Rx> {
76 _peri: PeripheralRef<'d, T>, 89 _peri: PeripheralRef<'d, T>,
77 sck: Option<PeripheralRef<'d, AnyPin>>, 90 sck: Option<PeripheralRef<'d, AnyPin>>,
@@ -83,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
83} 96}
84 97
85impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { 98impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
99 /// Create a new SPI driver.
86 pub fn new( 100 pub fn new(
87 peri: impl Peripheral<P = T> + 'd, 101 peri: impl Peripheral<P = T> + 'd,
88 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 102 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -117,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
117 ) 131 )
118 } 132 }
119 133
134 /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
120 pub fn new_rxonly( 135 pub fn new_rxonly(
121 peri: impl Peripheral<P = T> + 'd, 136 peri: impl Peripheral<P = T> + 'd,
122 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 137 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -142,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
142 ) 157 )
143 } 158 }
144 159
160 /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
145 pub fn new_txonly( 161 pub fn new_txonly(
146 peri: impl Peripheral<P = T> + 'd, 162 peri: impl Peripheral<P = T> + 'd,
147 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 163 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@@ -167,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
167 ) 183 )
168 } 184 }
169 185
186 /// Create a new SPI driver, in TX-only mode, without SCK pin.
187 ///
188 /// This can be useful for bit-banging non-SPI protocols.
170 pub fn new_txonly_nosck( 189 pub fn new_txonly_nosck(
171 peri: impl Peripheral<P = T> + 'd, 190 peri: impl Peripheral<P = T> + 'd,
172 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, 191 mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@@ -292,7 +311,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
292 w.set_ssom(vals::Ssom::ASSERTED); 311 w.set_ssom(vals::Ssom::ASSERTED);
293 w.set_midi(0); 312 w.set_midi(0);
294 w.set_mssi(0); 313 w.set_mssi(0);
295 w.set_afcntr(vals::Afcntr::CONTROLLED); 314 w.set_afcntr(true);
296 w.set_ssiop(vals::Ssiop::ACTIVEHIGH); 315 w.set_ssiop(vals::Ssiop::ACTIVEHIGH);
297 }); 316 });
298 T::REGS.cfg1().modify(|w| { 317 T::REGS.cfg1().modify(|w| {
@@ -354,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
354 Ok(()) 373 Ok(())
355 } 374 }
356 375
376 /// Get current SPI configuration.
357 pub fn get_current_config(&self) -> Config { 377 pub fn get_current_config(&self) -> Config {
358 #[cfg(any(spi_v1, spi_f1, spi_v2))] 378 #[cfg(any(spi_v1, spi_f1, spi_v2))]
359 let cfg = T::REGS.cr1().read(); 379 let cfg = T::REGS.cr1().read();
@@ -443,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
443 self.current_word_size = word_size; 463 self.current_word_size = word_size;
444 } 464 }
445 465
466 /// SPI write, using DMA.
446 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> 467 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
447 where 468 where
448 Tx: TxDma<T>, 469 Tx: TxDma<T>,
@@ -476,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
476 Ok(()) 497 Ok(())
477 } 498 }
478 499
500 /// SPI read, using DMA.
479 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 501 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
480 where 502 where
481 Tx: TxDma<T>, 503 Tx: TxDma<T>,
@@ -579,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
579 Ok(()) 601 Ok(())
580 } 602 }
581 603
604 /// Bidirectional transfer, using DMA.
605 ///
606 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
607 ///
608 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
609 /// If `write` is shorter it is padded with zero bytes.
582 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> 610 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
583 where 611 where
584 Tx: TxDma<T>, 612 Tx: TxDma<T>,
@@ -587,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
587 self.transfer_inner(read, write).await 615 self.transfer_inner(read, write).await
588 } 616 }
589 617
618 /// In-place bidirectional transfer, using DMA.
619 ///
620 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
590 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> 621 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
591 where 622 where
592 Tx: TxDma<T>, 623 Tx: TxDma<T>,
@@ -595,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
595 self.transfer_inner(data, data).await 626 self.transfer_inner(data, data).await
596 } 627 }
597 628
629 /// Blocking write.
598 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 630 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
599 T::REGS.cr1().modify(|w| w.set_spe(true)); 631 T::REGS.cr1().modify(|w| w.set_spe(true));
600 flush_rx_fifo(T::REGS); 632 flush_rx_fifo(T::REGS);
@@ -605,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
605 Ok(()) 637 Ok(())
606 } 638 }
607 639
640 /// Blocking read.
608 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 641 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
609 T::REGS.cr1().modify(|w| w.set_spe(true)); 642 T::REGS.cr1().modify(|w| w.set_spe(true));
610 flush_rx_fifo(T::REGS); 643 flush_rx_fifo(T::REGS);
@@ -615,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
615 Ok(()) 648 Ok(())
616 } 649 }
617 650
651 /// Blocking in-place bidirectional transfer.
652 ///
653 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
618 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 654 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
619 T::REGS.cr1().modify(|w| w.set_spe(true)); 655 T::REGS.cr1().modify(|w| w.set_spe(true));
620 flush_rx_fifo(T::REGS); 656 flush_rx_fifo(T::REGS);
@@ -625,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
625 Ok(()) 661 Ok(())
626 } 662 }
627 663
664 /// Blocking bidirectional transfer.
665 ///
666 /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
667 ///
668 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
669 /// If `write` is shorter it is padded with zero bytes.
628 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 670 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
629 T::REGS.cr1().modify(|w| w.set_spe(true)); 671 T::REGS.cr1().modify(|w| w.set_spe(true));
630 flush_rx_fifo(T::REGS); 672 flush_rx_fifo(T::REGS);
@@ -945,6 +987,7 @@ pub(crate) mod sealed {
945 } 987 }
946} 988}
947 989
990/// Word sizes usable for SPI.
948pub trait Word: word::Word + sealed::Word {} 991pub trait Word: word::Word + sealed::Word {}
949 992
950macro_rules! impl_word { 993macro_rules! impl_word {
@@ -1024,7 +1067,9 @@ mod word_impl {
1024 impl_word!(u32, 32 - 1); 1067 impl_word!(u32, 32 - 1);
1025} 1068}
1026 1069
1070/// SPI instance trait.
1027pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} 1071pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
1072
1028pin_trait!(SckPin, Instance); 1073pin_trait!(SckPin, Instance);
1029pin_trait!(MosiPin, Instance); 1074pin_trait!(MosiPin, Instance);
1030pin_trait!(MisoPin, Instance); 1075pin_trait!(MisoPin, Instance);
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index a0bc33944..17690aefc 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -8,14 +8,17 @@ use core::ops::{Div, Mul};
8pub struct Hertz(pub u32); 8pub struct Hertz(pub u32);
9 9
10impl Hertz { 10impl Hertz {
11 /// Create a `Hertz` from the given hertz.
11 pub const fn hz(hertz: u32) -> Self { 12 pub const fn hz(hertz: u32) -> Self {
12 Self(hertz) 13 Self(hertz)
13 } 14 }
14 15
16 /// Create a `Hertz` from the given kilohertz.
15 pub const fn khz(kilohertz: u32) -> Self { 17 pub const fn khz(kilohertz: u32) -> Self {
16 Self(kilohertz * 1_000) 18 Self(kilohertz * 1_000)
17 } 19 }
18 20
21 /// Create a `Hertz` from the given megahertz.
19 pub const fn mhz(megahertz: u32) -> Self { 22 pub const fn mhz(megahertz: u32) -> Self {
20 Self(megahertz * 1_000_000) 23 Self(megahertz * 1_000_000)
21 } 24 }
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index e2a4cc4da..9981800b2 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -43,7 +43,10 @@ type T = peripherals::TIM3;
43type T = peripherals::TIM4; 43type T = peripherals::TIM4;
44#[cfg(time_driver_tim5)] 44#[cfg(time_driver_tim5)]
45type T = peripherals::TIM5; 45type T = peripherals::TIM5;
46 46#[cfg(time_driver_tim9)]
47type T = peripherals::TIM9;
48#[cfg(time_driver_tim11)]
49type T = peripherals::TIM11;
47#[cfg(time_driver_tim12)] 50#[cfg(time_driver_tim12)]
48type T = peripherals::TIM12; 51type T = peripherals::TIM12;
49#[cfg(time_driver_tim15)] 52#[cfg(time_driver_tim15)]
@@ -82,6 +85,22 @@ foreach_interrupt! {
82 DRIVER.on_interrupt() 85 DRIVER.on_interrupt()
83 } 86 }
84 }; 87 };
88 (TIM9, timer, $block:ident, UP, $irq:ident) => {
89 #[cfg(time_driver_tim9)]
90 #[cfg(feature = "rt")]
91 #[interrupt]
92 fn $irq() {
93 DRIVER.on_interrupt()
94 }
95 };
96 (TIM11, timer, $block:ident, UP, $irq:ident) => {
97 #[cfg(time_driver_tim11)]
98 #[cfg(feature = "rt")]
99 #[interrupt]
100 fn $irq() {
101 DRIVER.on_interrupt()
102 }
103 };
85 (TIM12, timer, $block:ident, UP, $irq:ident) => { 104 (TIM12, timer, $block:ident, UP, $irq:ident) => {
86 #[cfg(time_driver_tim12)] 105 #[cfg(time_driver_tim12)]
87 #[cfg(feature = "rt")] 106 #[cfg(feature = "rt")]
@@ -455,16 +474,29 @@ impl Driver for RtcDriver {
455 return false; 474 return false;
456 } 475 }
457 476
458 let safe_timestamp = timestamp.max(t + 3);
459
460 // Write the CCR value regardless of whether we're going to enable it now or not. 477 // Write the CCR value regardless of whether we're going to enable it now or not.
461 // This way, when we enable it later, the right value is already set. 478 // This way, when we enable it later, the right value is already set.
462 r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); 479 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
463 480
464 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 481 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
465 let diff = timestamp - t; 482 let diff = timestamp - t;
466 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); 483 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
467 484
485 // Reevaluate if the alarm timestamp is still in the future
486 let t = self.now();
487 if timestamp <= t {
488 // If alarm timestamp has passed since we set it, we have a race condition and
489 // the alarm may or may not have fired.
490 // Disarm the alarm and return `false` to indicate that.
491 // It is the caller's responsibility to handle this ambiguity.
492 r.dier().modify(|w| w.set_ccie(n + 1, false));
493
494 alarm.timestamp.set(u64::MAX);
495
496 return false;
497 }
498
499 // We're confident the alarm will ring in the future.
468 true 500 true
469 }) 501 })
470 } 502 }
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 6654366cd..71d7110b5 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -1,3 +1,5 @@
1//! PWM driver with complementary output support.
2
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -11,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 13use crate::time::Hertz;
12use crate::Peripheral; 14use crate::Peripheral;
13 15
14pub 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> {
15 _pin: PeripheralRef<'d, AnyPin>, 20 _pin: PeripheralRef<'d, AnyPin>,
16 phantom: PhantomData<(Perip, Channel)>, 21 phantom: PhantomData<(T, C)>,
17} 22}
18 23
19macro_rules! complementary_channel_impl { 24macro_rules! complementary_channel_impl {
20 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { 26 impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
22 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 {
23 into_ref!(pin); 29 into_ref!(pin);
24 critical_section::with(|_| { 30 critical_section::with(|_| {
25 pin.set_low(); 31 pin.set_low();
@@ -41,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
41complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); 47complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
42complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 48complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
43 49
50/// PWM driver with support for standard and complementary outputs.
44pub struct ComplementaryPwm<'d, T> { 51pub struct ComplementaryPwm<'d, T> {
45 inner: PeripheralRef<'d, T>, 52 inner: PeripheralRef<'d, T>,
46} 53}
47 54
48impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver.
49 pub fn new( 57 pub fn new(
50 tim: impl Peripheral<P = T> + 'd, 58 tim: impl Peripheral<P = T> + 'd,
51 _ch1: Option<PwmPin<'d, T, Ch1>>, 59 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -70,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
70 let mut this = Self { inner: tim }; 78 let mut this = Self { inner: tim };
71 79
72 this.inner.set_counting_mode(counting_mode); 80 this.inner.set_counting_mode(counting_mode);
73 this.set_freq(freq); 81 this.set_frequency(freq);
74 this.inner.start(); 82 this.inner.start();
75 83
76 this.inner.enable_outputs(); 84 this.inner.enable_outputs();
@@ -86,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
86 this 94 this
87 } 95 }
88 96
97 /// Enable the given channel.
89 pub fn enable(&mut self, channel: Channel) { 98 pub fn enable(&mut self, channel: Channel) {
90 self.inner.enable_channel(channel, true); 99 self.inner.enable_channel(channel, true);
91 self.inner.enable_complementary_channel(channel, true); 100 self.inner.enable_complementary_channel(channel, true);
92 } 101 }
93 102
103 /// Disable the given channel.
94 pub fn disable(&mut self, channel: Channel) { 104 pub fn disable(&mut self, channel: Channel) {
95 self.inner.enable_complementary_channel(channel, false); 105 self.inner.enable_complementary_channel(channel, false);
96 self.inner.enable_channel(channel, false); 106 self.inner.enable_channel(channel, false);
97 } 107 }
98 108
99 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) {
100 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 114 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
101 2u8 115 2u8
102 } else { 116 } else {
@@ -105,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
105 self.inner.set_frequency(freq * multiplier); 119 self.inner.set_frequency(freq * multiplier);
106 } 120 }
107 121
122 /// Get max duty value.
123 ///
124 /// This value depends on the configured frequency and the timer's clock rate from RCC.
108 pub fn get_max_duty(&self) -> u16 { 125 pub fn get_max_duty(&self) -> u16 {
109 self.inner.get_max_compare_value() + 1 126 self.inner.get_max_compare_value() + 1
110 } 127 }
111 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.
112 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 132 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
113 assert!(duty <= self.get_max_duty()); 133 assert!(duty <= self.get_max_duty());
114 self.inner.set_compare_value(channel, duty) 134 self.inner.set_compare_value(channel, duty)
115 } 135 }
116 136
137 /// Set the output polarity for a given channel.
117 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 138 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
118 self.inner.set_output_polarity(channel, polarity); 139 self.inner.set_output_polarity(channel, polarity);
119 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 2313a5b94..74120adad 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,3 +1,5 @@
1//! Timers, PWM, quadrature decoder.
2
1pub mod complementary_pwm; 3pub mod complementary_pwm;
2pub mod qei; 4pub mod qei;
3pub mod simple_pwm; 5pub mod simple_pwm;
@@ -8,23 +10,34 @@ use crate::interrupt;
8use crate::rcc::RccPeripheral; 10use crate::rcc::RccPeripheral;
9use crate::time::Hertz; 11use crate::time::Hertz;
10 12
13/// Low-level timer access.
11#[cfg(feature = "unstable-pac")] 14#[cfg(feature = "unstable-pac")]
12pub mod low_level { 15pub mod low_level {
13 pub use super::sealed::*; 16 pub use super::sealed::*;
14} 17}
15 18
16pub(crate) mod sealed { 19pub(crate) mod sealed {
17
18 use super::*; 20 use super::*;
21
22 /// Basic 16-bit timer instance.
19 pub trait Basic16bitInstance: RccPeripheral { 23 pub trait Basic16bitInstance: RccPeripheral {
24 /// Interrupt for this timer.
20 type Interrupt: interrupt::typelevel::Interrupt; 25 type Interrupt: interrupt::typelevel::Interrupt;
21 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.
22 fn regs() -> crate::pac::timer::TimBasic; 33 fn regs() -> crate::pac::timer::TimBasic;
23 34
35 /// Start the timer.
24 fn start(&mut self) { 36 fn start(&mut self) {
25 Self::regs().cr1().modify(|r| r.set_cen(true)); 37 Self::regs().cr1().modify(|r| r.set_cen(true));
26 } 38 }
27 39
40 /// Stop the timer.
28 fn stop(&mut self) { 41 fn stop(&mut self) {
29 Self::regs().cr1().modify(|r| r.set_cen(false)); 42 Self::regs().cr1().modify(|r| r.set_cen(false));
30 } 43 }
@@ -60,6 +73,9 @@ pub(crate) mod sealed {
60 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 73 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
61 } 74 }
62 75
76 /// Clear update interrupt.
77 ///
78 /// Returns whether the update interrupt flag was set.
63 fn clear_update_interrupt(&mut self) -> bool { 79 fn clear_update_interrupt(&mut self) -> bool {
64 let regs = Self::regs(); 80 let regs = Self::regs();
65 let sr = regs.sr().read(); 81 let sr = regs.sr().read();
@@ -73,14 +89,17 @@ pub(crate) mod sealed {
73 } 89 }
74 } 90 }
75 91
92 /// Enable/disable the update interrupt.
76 fn enable_update_interrupt(&mut self, enable: bool) { 93 fn enable_update_interrupt(&mut self, enable: bool) {
77 Self::regs().dier().write(|r| r.set_uie(enable)); 94 Self::regs().dier().write(|r| r.set_uie(enable));
78 } 95 }
79 96
80 fn set_autoreload_preload(&mut self, enable: vals::Arpe) { 97 /// Enable/disable autoreload preload.
98 fn set_autoreload_preload(&mut self, enable: bool) {
81 Self::regs().cr1().modify(|r| r.set_arpe(enable)); 99 Self::regs().cr1().modify(|r| r.set_arpe(enable));
82 } 100 }
83 101
102 /// Get the timer frequency.
84 fn get_frequency(&self) -> Hertz { 103 fn get_frequency(&self) -> Hertz {
85 let timer_f = Self::frequency(); 104 let timer_f = Self::frequency();
86 105
@@ -92,9 +111,17 @@ pub(crate) mod sealed {
92 } 111 }
93 } 112 }
94 113
114 /// Gneral-purpose 16-bit timer instance.
95 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.
96 fn regs_gp16() -> crate::pac::timer::TimGp16; 122 fn regs_gp16() -> crate::pac::timer::TimGp16;
97 123
124 /// Set counting mode.
98 fn set_counting_mode(&mut self, mode: CountingMode) { 125 fn set_counting_mode(&mut self, mode: CountingMode) {
99 let (cms, dir) = mode.into(); 126 let (cms, dir) = mode.into();
100 127
@@ -107,19 +134,29 @@ pub(crate) mod sealed {
107 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) 134 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
108 } 135 }
109 136
137 /// Get counting mode.
110 fn get_counting_mode(&self) -> CountingMode { 138 fn get_counting_mode(&self) -> CountingMode {
111 let cr1 = Self::regs_gp16().cr1().read(); 139 let cr1 = Self::regs_gp16().cr1().read();
112 (cr1.cms(), cr1.dir()).into() 140 (cr1.cms(), cr1.dir()).into()
113 } 141 }
114 142
143 /// Set clock divider.
115 fn set_clock_division(&mut self, ckd: vals::Ckd) { 144 fn set_clock_division(&mut self, ckd: vals::Ckd) {
116 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); 145 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
117 } 146 }
118 } 147 }
119 148
149 /// Gneral-purpose 32-bit timer instance.
120 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.
121 fn regs_gp32() -> crate::pac::timer::TimGp32; 157 fn regs_gp32() -> crate::pac::timer::TimGp32;
122 158
159 /// Set timer frequency.
123 fn set_frequency(&mut self, frequency: Hertz) { 160 fn set_frequency(&mut self, frequency: Hertz) {
124 let f = frequency.0; 161 let f = frequency.0;
125 assert!(f > 0); 162 assert!(f > 0);
@@ -137,6 +174,7 @@ pub(crate) mod sealed {
137 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 174 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
138 } 175 }
139 176
177 /// Get timer frequency.
140 fn get_frequency(&self) -> Hertz { 178 fn get_frequency(&self) -> Hertz {
141 let timer_f = Self::frequency(); 179 let timer_f = Self::frequency();
142 180
@@ -148,141 +186,177 @@ pub(crate) mod sealed {
148 } 186 }
149 } 187 }
150 188
189 /// Advanced control timer instance.
151 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 190 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
191 /// Get access to the advanced timer registers.
152 fn regs_advanced() -> crate::pac::timer::TimAdv; 192 fn regs_advanced() -> crate::pac::timer::TimAdv;
153 } 193 }
154 194
195 /// Capture/Compare 16-bit timer instance.
155 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { 196 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
197 /// Set input capture filter.
156 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) {
157 let raw_channel = channel.raw(); 199 let raw_channel = channel.index();
158 Self::regs_gp16() 200 Self::regs_gp16()
159 .ccmr_input(raw_channel / 2) 201 .ccmr_input(raw_channel / 2)
160 .modify(|r| r.set_icf(raw_channel % 2, icf)); 202 .modify(|r| r.set_icf(raw_channel % 2, icf));
161 } 203 }
162 204
205 /// Clear input interrupt.
163 fn clear_input_interrupt(&mut self, channel: Channel) { 206 fn clear_input_interrupt(&mut self, channel: Channel) {
164 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));
165 } 208 }
166 209
210 /// Enable input interrupt.
167 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { 211 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
168 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));
169 } 213 }
214
215 /// Set input capture prescaler.
170 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { 216 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
171 let raw_channel = channel.raw(); 217 let raw_channel = channel.index();
172 Self::regs_gp16() 218 Self::regs_gp16()
173 .ccmr_input(raw_channel / 2) 219 .ccmr_input(raw_channel / 2)
174 .modify(|r| r.set_icpsc(raw_channel % 2, factor)); 220 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
175 } 221 }
176 222
223 /// Set input TI selection.
177 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { 224 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
178 let raw_channel = channel.raw(); 225 let raw_channel = channel.index();
179 Self::regs_gp16() 226 Self::regs_gp16()
180 .ccmr_input(raw_channel / 2) 227 .ccmr_input(raw_channel / 2)
181 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); 228 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
182 } 229 }
230
231 /// Set input capture mode.
183 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { 232 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
184 Self::regs_gp16().ccer().modify(|r| match mode { 233 Self::regs_gp16().ccer().modify(|r| match mode {
185 InputCaptureMode::Rising => { 234 InputCaptureMode::Rising => {
186 r.set_ccnp(channel.raw(), false); 235 r.set_ccnp(channel.index(), false);
187 r.set_ccp(channel.raw(), false); 236 r.set_ccp(channel.index(), false);
188 } 237 }
189 InputCaptureMode::Falling => { 238 InputCaptureMode::Falling => {
190 r.set_ccnp(channel.raw(), false); 239 r.set_ccnp(channel.index(), false);
191 r.set_ccp(channel.raw(), true); 240 r.set_ccp(channel.index(), true);
192 } 241 }
193 InputCaptureMode::BothEdges => { 242 InputCaptureMode::BothEdges => {
194 r.set_ccnp(channel.raw(), true); 243 r.set_ccnp(channel.index(), true);
195 r.set_ccp(channel.raw(), true); 244 r.set_ccp(channel.index(), true);
196 } 245 }
197 }); 246 });
198 } 247 }
248
249 /// Enable timer outputs.
199 fn enable_outputs(&mut self); 250 fn enable_outputs(&mut self);
200 251
252 /// Set output compare mode.
201 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 253 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
202 let r = Self::regs_gp16(); 254 let r = Self::regs_gp16();
203 let raw_channel: usize = channel.raw(); 255 let raw_channel: usize = channel.index();
204 r.ccmr_output(raw_channel / 2) 256 r.ccmr_output(raw_channel / 2)
205 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 257 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
206 } 258 }
207 259
260 /// Set output polarity.
208 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 261 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
209 Self::regs_gp16() 262 Self::regs_gp16()
210 .ccer() 263 .ccer()
211 .modify(|w| w.set_ccp(channel.raw(), polarity.into())); 264 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
212 } 265 }
213 266
267 /// Enable/disable a channel.
214 fn enable_channel(&mut self, channel: Channel, enable: bool) { 268 fn enable_channel(&mut self, channel: Channel, enable: bool) {
215 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));
216 } 270 }
217 271
272 /// Set compare value for a channel.
218 fn set_compare_value(&mut self, channel: Channel, value: u16) { 273 fn set_compare_value(&mut self, channel: Channel, value: u16) {
219 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));
220 } 275 }
221 276
277 /// Get capture value for a channel.
222 fn get_capture_value(&mut self, channel: Channel) -> u16 { 278 fn get_capture_value(&mut self, channel: Channel) -> u16 {
223 Self::regs_gp16().ccr(channel.raw()).read().ccr() 279 Self::regs_gp16().ccr(channel.index()).read().ccr()
224 } 280 }
225 281
282 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
226 fn get_max_compare_value(&self) -> u16 { 283 fn get_max_compare_value(&self) -> u16 {
227 Self::regs_gp16().arr().read().arr() 284 Self::regs_gp16().arr().read().arr()
228 } 285 }
229 286
287 /// Get compare value for a channel.
230 fn get_compare_value(&self, channel: Channel) -> u16 { 288 fn get_compare_value(&self, channel: Channel) -> u16 {
231 Self::regs_gp16().ccr(channel.raw()).read().ccr() 289 Self::regs_gp16().ccr(channel.index()).read().ccr()
232 } 290 }
233 } 291 }
234 292
293 /// Capture/Compare 16-bit timer instance with complementary pin support.
235 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { 294 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
295 /// Set complementary output polarity.
236 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 296 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
237 Self::regs_advanced() 297 Self::regs_advanced()
238 .ccer() 298 .ccer()
239 .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); 299 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
240 } 300 }
241 301
302 /// Set clock divider for the dead time.
242 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 303 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
243 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 304 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
244 } 305 }
245 306
307 /// Set dead time, as a fraction of the max duty value.
246 fn set_dead_time_value(&mut self, value: u8) { 308 fn set_dead_time_value(&mut self, value: u8) {
247 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 309 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
248 } 310 }
249 311
312 /// Enable/disable a complementary channel.
250 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 313 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
251 Self::regs_advanced() 314 Self::regs_advanced()
252 .ccer() 315 .ccer()
253 .modify(|w| w.set_ccne(channel.raw(), enable)); 316 .modify(|w| w.set_ccne(channel.index(), enable));
254 } 317 }
255 } 318 }
256 319
320 /// Capture/Compare 32-bit timer instance.
257 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { 321 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
322 /// Set comapre value for a channel.
258 fn set_compare_value(&mut self, channel: Channel, value: u32) { 323 fn set_compare_value(&mut self, channel: Channel, value: u32) {
259 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));
260 } 325 }
261 326
327 /// Get capture value for a channel.
262 fn get_capture_value(&mut self, channel: Channel) -> u32 { 328 fn get_capture_value(&mut self, channel: Channel) -> u32 {
263 Self::regs_gp32().ccr(channel.raw()).read().ccr() 329 Self::regs_gp32().ccr(channel.index()).read().ccr()
264 } 330 }
265 331
332 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
266 fn get_max_compare_value(&self) -> u32 { 333 fn get_max_compare_value(&self) -> u32 {
267 Self::regs_gp32().arr().read().arr() 334 Self::regs_gp32().arr().read().arr()
268 } 335 }
269 336
337 /// Get compare value for a channel.
270 fn get_compare_value(&self, channel: Channel) -> u32 { 338 fn get_compare_value(&self, channel: Channel) -> u32 {
271 Self::regs_gp32().ccr(channel.raw()).read().ccr() 339 Self::regs_gp32().ccr(channel.index()).read().ccr()
272 } 340 }
273 } 341 }
274} 342}
275 343
344/// Timer channel.
276#[derive(Clone, Copy)] 345#[derive(Clone, Copy)]
277pub enum Channel { 346pub enum Channel {
347 /// Channel 1.
278 Ch1, 348 Ch1,
349 /// Channel 2.
279 Ch2, 350 Ch2,
351 /// Channel 3.
280 Ch3, 352 Ch3,
353 /// Channel 4.
281 Ch4, 354 Ch4,
282} 355}
283 356
284impl Channel { 357impl Channel {
285 pub fn raw(&self) -> usize { 358 /// Get the channel index (0..3)
359 pub fn index(&self) -> usize {
286 match self { 360 match self {
287 Channel::Ch1 => 0, 361 Channel::Ch1 => 0,
288 Channel::Ch2 => 1, 362 Channel::Ch2 => 1,
@@ -292,17 +366,25 @@ impl Channel {
292 } 366 }
293} 367}
294 368
369/// Input capture mode.
295#[derive(Clone, Copy)] 370#[derive(Clone, Copy)]
296pub enum InputCaptureMode { 371pub enum InputCaptureMode {
372 /// Rising edge only.
297 Rising, 373 Rising,
374 /// Falling edge only.
298 Falling, 375 Falling,
376 /// Both rising or falling edges.
299 BothEdges, 377 BothEdges,
300} 378}
301 379
380/// Input TI selection.
302#[derive(Clone, Copy)] 381#[derive(Clone, Copy)]
303pub enum InputTISelection { 382pub enum InputTISelection {
383 /// Normal
304 Normal, 384 Normal,
385 /// Alternate
305 Alternate, 386 Alternate,
387 /// TRC
306 TRC, 388 TRC,
307} 389}
308 390
@@ -316,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
316 } 398 }
317} 399}
318 400
401/// Timer counting mode.
319#[repr(u8)] 402#[repr(u8)]
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 403#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
321pub enum CountingMode { 404pub enum CountingMode {
@@ -342,6 +425,7 @@ pub enum CountingMode {
342} 425}
343 426
344impl CountingMode { 427impl CountingMode {
428 /// Return whether this mode is edge-aligned (up or down).
345 pub fn is_edge_aligned(&self) -> bool { 429 pub fn is_edge_aligned(&self) -> bool {
346 match self { 430 match self {
347 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, 431 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
@@ -349,6 +433,7 @@ impl CountingMode {
349 } 433 }
350 } 434 }
351 435
436 /// Return whether this mode is center-aligned.
352 pub fn is_center_aligned(&self) -> bool { 437 pub fn is_center_aligned(&self) -> bool {
353 match self { 438 match self {
354 CountingMode::CenterAlignedDownInterrupts 439 CountingMode::CenterAlignedDownInterrupts
@@ -383,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
383 } 468 }
384} 469}
385 470
471/// Output compare mode.
386#[derive(Clone, Copy)] 472#[derive(Clone, Copy)]
387pub 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).
388 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).
389 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).
390 InactiveOnMatch, 483 InactiveOnMatch,
484 /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
391 Toggle, 485 Toggle,
486 /// Force inactive level - OCxREF is forced low.
392 ForceInactive, 487 ForceInactive,
488 /// Force active level - OCxREF is forced high.
393 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).
394 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.
395 PwmMode2, 497 PwmMode2,
498 // TODO: there's more modes here depending on the chip family.
396} 499}
397 500
398impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 501impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
@@ -410,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
410 } 513 }
411} 514}
412 515
516/// Timer output pin polarity.
413#[derive(Clone, Copy)] 517#[derive(Clone, Copy)]
414pub enum OutputPolarity { 518pub enum OutputPolarity {
519 /// Active high (higher duty value makes the pin spend more time high).
415 ActiveHigh, 520 ActiveHigh,
521 /// Active low (higher duty value makes the pin spend more time low).
416 ActiveLow, 522 ActiveLow,
417} 523}
418 524
@@ -425,24 +531,31 @@ impl From<OutputPolarity> for bool {
425 } 531 }
426} 532}
427 533
534/// Basic 16-bit timer instance.
428pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 535pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
429 536
537/// Gneral-purpose 16-bit timer instance.
430pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 538pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
431 539
540/// Gneral-purpose 32-bit timer instance.
432pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} 541pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
433 542
543/// Advanced control timer instance.
434pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} 544pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
435 545
546/// Capture/Compare 16-bit timer instance.
436pub trait CaptureCompare16bitInstance: 547pub trait CaptureCompare16bitInstance:
437 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static 548 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
438{ 549{
439} 550}
440 551
552/// Capture/Compare 16-bit timer instance with complementary pin support.
441pub trait ComplementaryCaptureCompare16bitInstance: 553pub trait ComplementaryCaptureCompare16bitInstance:
442 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static 554 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
443{ 555{
444} 556}
445 557
558/// Capture/Compare 32-bit timer instance.
446pub trait CaptureCompare32bitInstance: 559pub trait CaptureCompare32bitInstance:
447 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static 560 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
448{ 561{
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 01d028bf9..59efb72ba 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -1,3 +1,5 @@
1//! Quadrature decoder using a timer.
2
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -7,23 +9,30 @@ use crate::gpio::sealed::AFType;
7use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
8use crate::Peripheral; 10use crate::Peripheral;
9 11
12/// Counting direction
10pub enum Direction { 13pub enum Direction {
14 /// Counting up.
11 Upcounting, 15 Upcounting,
16 /// Counting down.
12 Downcounting, 17 Downcounting,
13} 18}
14 19
15pub struct Ch1; 20/// Channel 1 marker type.
16pub struct Ch2; 21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
17 24
18pub struct QeiPin<'d, Perip, Channel> { 25/// Wrapper for using a pin with QEI.
26pub struct QeiPin<'d, T, Channel> {
19 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
20 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, Channel)>,
21} 29}
22 30
23macro_rules! channel_impl { 31macro_rules! channel_impl {
24 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
25 impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> {
26 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 {
27 into_ref!(pin); 36 into_ref!(pin);
28 critical_section::with(|_| { 37 critical_section::with(|_| {
29 pin.set_low(); 38 pin.set_low();
@@ -43,11 +52,13 @@ macro_rules! channel_impl {
43channel_impl!(new_ch1, Ch1, Channel1Pin); 52channel_impl!(new_ch1, Ch1, Channel1Pin);
44channel_impl!(new_ch2, Ch2, Channel2Pin); 53channel_impl!(new_ch2, Ch2, Channel2Pin);
45 54
55/// Quadrature decoder driver.
46pub struct Qei<'d, T> { 56pub struct Qei<'d, T> {
47 _inner: PeripheralRef<'d, T>, 57 _inner: PeripheralRef<'d, T>,
48} 58}
49 59
50impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 60impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
61 /// Create a new quadrature decoder driver.
51 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 {
52 Self::new_inner(tim) 63 Self::new_inner(tim)
53 } 64 }
@@ -82,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
82 Self { _inner: tim } 93 Self { _inner: tim }
83 } 94 }
84 95
96 /// Get direction.
85 pub fn read_direction(&self) -> Direction { 97 pub fn read_direction(&self) -> Direction {
86 match T::regs_gp16().cr1().read().dir() { 98 match T::regs_gp16().cr1().read().dir() {
87 vals::Dir::DOWN => Direction::Downcounting, 99 vals::Dir::DOWN => Direction::Downcounting,
@@ -89,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
89 } 101 }
90 } 102 }
91 103
104 /// Get count.
92 pub fn count(&self) -> u16 { 105 pub fn count(&self) -> u16 {
93 T::regs_gp16().cnt().read().cnt() 106 T::regs_gp16().cnt().read().cnt()
94 } 107 }
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 1cf0ad728..e6072aa15 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -1,3 +1,5 @@
1//! Simple PWM driver.
2
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -9,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
9use crate::time::Hertz; 11use crate::time::Hertz;
10use crate::Peripheral; 12use crate::Peripheral;
11 13
12pub struct Ch1; 14/// Channel 1 marker type.
13pub struct Ch2; 15pub enum Ch1 {}
14pub struct Ch3; 16/// Channel 2 marker type.
15pub struct Ch4; 17pub enum Ch2 {}
16 18/// Channel 3 marker type.
17pub 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> {
18 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
19 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, C)>,
20} 29}
21 30
22macro_rules! channel_impl { 31macro_rules! channel_impl {
23 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
25 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 {
26 into_ref!(pin); 36 into_ref!(pin);
27 critical_section::with(|_| { 37 critical_section::with(|_| {
28 pin.set_low(); 38 pin.set_low();
@@ -44,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
44channel_impl!(new_ch3, Ch3, Channel3Pin); 54channel_impl!(new_ch3, Ch3, Channel3Pin);
45channel_impl!(new_ch4, Ch4, Channel4Pin); 55channel_impl!(new_ch4, Ch4, Channel4Pin);
46 56
57/// Simple PWM driver.
47pub struct SimplePwm<'d, T> { 58pub struct SimplePwm<'d, T> {
48 inner: PeripheralRef<'d, T>, 59 inner: PeripheralRef<'d, T>,
49} 60}
50 61
51impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 62impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
63 /// Create a new simple PWM driver.
52 pub fn new( 64 pub fn new(
53 tim: impl Peripheral<P = T> + 'd, 65 tim: impl Peripheral<P = T> + 'd,
54 _ch1: Option<PwmPin<'d, T, Ch1>>, 66 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -69,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
69 let mut this = Self { inner: tim }; 81 let mut this = Self { inner: tim };
70 82
71 this.inner.set_counting_mode(counting_mode); 83 this.inner.set_counting_mode(counting_mode);
72 this.set_freq(freq); 84 this.set_frequency(freq);
73 this.inner.start(); 85 this.inner.start();
74 86
75 this.inner.enable_outputs(); 87 this.inner.enable_outputs();
@@ -85,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
85 this 97 this
86 } 98 }
87 99
100 /// Enable the given channel.
88 pub fn enable(&mut self, channel: Channel) { 101 pub fn enable(&mut self, channel: Channel) {
89 self.inner.enable_channel(channel, true); 102 self.inner.enable_channel(channel, true);
90 } 103 }
91 104
105 /// Disable the given channel.
92 pub fn disable(&mut self, channel: Channel) { 106 pub fn disable(&mut self, channel: Channel) {
93 self.inner.enable_channel(channel, false); 107 self.inner.enable_channel(channel, false);
94 } 108 }
95 109
96 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) {
97 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 115 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
98 2u8 116 2u8
99 } else { 117 } else {
@@ -102,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
102 self.inner.set_frequency(freq * multiplier); 120 self.inner.set_frequency(freq * multiplier);
103 } 121 }
104 122
123 /// Get max duty value.
124 ///
125 /// This value depends on the configured frequency and the timer's clock rate from RCC.
105 pub fn get_max_duty(&self) -> u16 { 126 pub fn get_max_duty(&self) -> u16 {
106 self.inner.get_max_compare_value() + 1 127 self.inner.get_max_compare_value() + 1
107 } 128 }
108 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.
109 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 133 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
110 assert!(duty <= self.get_max_duty()); 134 assert!(duty <= self.get_max_duty());
111 self.inner.set_compare_value(channel, duty) 135 self.inner.set_compare_value(channel, duty)
112 } 136 }
113 137
138 /// Set the output polarity for a given channel.
114 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 139 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
115 self.inner.set_output_polarity(channel, polarity); 140 self.inner.set_output_polarity(channel, polarity);
116 } 141 }
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs
index ffce7bd42..13f695821 100644
--- a/embassy-stm32/src/traits.rs
+++ b/embassy-stm32/src/traits.rs
@@ -1,16 +1,18 @@
1#![macro_use] 1#![macro_use]
2 2
3macro_rules! pin_trait { 3macro_rules! pin_trait {
4 ($signal:ident, $instance:path) => { 4 ($signal:ident, $instance:path $(, $mode:path)?) => {
5 pub trait $signal<T: $instance>: crate::gpio::Pin { 5 #[doc = concat!(stringify!($signal), " pin trait")]
6 pub trait $signal<T: $instance $(, M: $mode)?>: crate::gpio::Pin {
7 #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))]
6 fn af_num(&self) -> u8; 8 fn af_num(&self) -> u8;
7 } 9 }
8 }; 10 };
9} 11}
10 12
11macro_rules! pin_trait_impl { 13macro_rules! pin_trait_impl {
12 (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { 14 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => {
13 impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$pin { 15 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin {
14 fn af_num(&self) -> u8 { 16 fn af_num(&self) -> u8 {
15 $af 17 $af
16 } 18 }
@@ -21,8 +23,12 @@ macro_rules! pin_trait_impl {
21// ==================== 23// ====================
22 24
23macro_rules! dma_trait { 25macro_rules! dma_trait {
24 ($signal:ident, $instance:path) => { 26 ($signal:ident, $instance:path$(, $mode:path)?) => {
25 pub trait $signal<T: $instance>: crate::dma::Channel { 27 #[doc = concat!(stringify!($signal), " DMA request trait")]
28 pub trait $signal<T: $instance $(, M: $mode)?>: crate::dma::Channel {
29 #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))]
30 /// Note: in some chips, ST calls this the "channel", and calls channels "streams".
31 /// `embassy-stm32` always uses the "channel" and "request number" names.
26 fn request(&self) -> crate::dma::Request; 32 fn request(&self) -> crate::dma::Request;
27 } 33 }
28 }; 34 };
@@ -31,8 +37,8 @@ macro_rules! dma_trait {
31#[allow(unused)] 37#[allow(unused)]
32macro_rules! dma_trait_impl { 38macro_rules! dma_trait_impl {
33 // DMAMUX 39 // DMAMUX
34 (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { 40 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => {
35 impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T 41 impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T
36 where 42 where
37 T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, 43 T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>,
38 { 44 {
@@ -43,8 +49,8 @@ macro_rules! dma_trait_impl {
43 }; 49 };
44 50
45 // DMAMUX 51 // DMAMUX
46 (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { 52 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => {
47 impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T 53 impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T
48 where 54 where
49 T: crate::dma::Channel, 55 T: crate::dma::Channel,
50 { 56 {
@@ -55,8 +61,8 @@ macro_rules! dma_trait_impl {
55 }; 61 };
56 62
57 // DMA/GPDMA, without DMAMUX 63 // DMA/GPDMA, without DMAMUX
58 (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { 64 (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => {
59 impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel { 65 impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel {
60 fn request(&self) -> crate::dma::Request { 66 fn request(&self) -> crate::dma::Request {
61 $request 67 $request
62 } 68 }
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index 6dcfcb96e..aa13586f8 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -1,3 +1,5 @@
1//! Unique ID (UID)
2
1/// Get this device's unique 96-bit ID. 3/// Get this device's unique 96-bit ID.
2pub fn uid() -> &'static [u8; 12] { 4pub fn uid() -> &'static [u8; 12] {
3 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } 5 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index a2e4ceaae..962547bd7 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -82,6 +82,7 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
82 } 82 }
83} 83}
84 84
85/// Buffered UART State
85pub struct State { 86pub struct State {
86 rx_waker: AtomicWaker, 87 rx_waker: AtomicWaker,
87 rx_buf: RingBuffer, 88 rx_buf: RingBuffer,
@@ -91,6 +92,7 @@ pub struct State {
91} 92}
92 93
93impl State { 94impl State {
95 /// Create new state
94 pub const fn new() -> Self { 96 pub const fn new() -> Self {
95 Self { 97 Self {
96 rx_buf: RingBuffer::new(), 98 rx_buf: RingBuffer::new(),
@@ -101,15 +103,18 @@ impl State {
101 } 103 }
102} 104}
103 105
106/// Bidirectional buffered UART
104pub struct BufferedUart<'d, T: BasicInstance> { 107pub struct BufferedUart<'d, T: BasicInstance> {
105 rx: BufferedUartRx<'d, T>, 108 rx: BufferedUartRx<'d, T>,
106 tx: BufferedUartTx<'d, T>, 109 tx: BufferedUartTx<'d, T>,
107} 110}
108 111
112/// Tx-only buffered UART
109pub struct BufferedUartTx<'d, T: BasicInstance> { 113pub struct BufferedUartTx<'d, T: BasicInstance> {
110 phantom: PhantomData<&'d mut T>, 114 phantom: PhantomData<&'d mut T>,
111} 115}
112 116
117/// Rx-only buffered UART
113pub struct BufferedUartRx<'d, T: BasicInstance> { 118pub struct BufferedUartRx<'d, T: BasicInstance> {
114 phantom: PhantomData<&'d mut T>, 119 phantom: PhantomData<&'d mut T>,
115} 120}
@@ -142,6 +147,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
142} 147}
143 148
144impl<'d, T: BasicInstance> BufferedUart<'d, T> { 149impl<'d, T: BasicInstance> BufferedUart<'d, T> {
150 /// Create a new bidirectional buffered UART driver
145 pub fn new( 151 pub fn new(
146 peri: impl Peripheral<P = T> + 'd, 152 peri: impl Peripheral<P = T> + 'd,
147 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 153 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
158 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 164 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
159 } 165 }
160 166
167 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
161 pub fn new_with_rtscts( 168 pub fn new_with_rtscts(
162 peri: impl Peripheral<P = T> + 'd, 169 peri: impl Peripheral<P = T> + 'd,
163 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 170 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
185 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 192 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
186 } 193 }
187 194
195 /// Create a new bidirectional buffered UART driver with a driver-enable pin
188 #[cfg(not(any(usart_v1, usart_v2)))] 196 #[cfg(not(any(usart_v1, usart_v2)))]
189 pub fn new_with_de( 197 pub fn new_with_de(
190 peri: impl Peripheral<P = T> + 'd, 198 peri: impl Peripheral<P = T> + 'd,
@@ -246,10 +254,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
246 }) 254 })
247 } 255 }
248 256
257 /// Split the driver into a Tx and Rx part (useful for sending to separate tasks)
249 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { 258 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
250 (self.tx, self.rx) 259 (self.tx, self.rx)
251 } 260 }
252 261
262 /// Reconfigure the driver
253 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 263 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
254 reconfigure::<T>(config)?; 264 reconfigure::<T>(config)?;
255 265
@@ -337,6 +347,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
337 } 347 }
338 } 348 }
339 349
350 /// Reconfigure the driver
340 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 351 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
341 reconfigure::<T>(config)?; 352 reconfigure::<T>(config)?;
342 353
@@ -418,6 +429,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
418 } 429 }
419 } 430 }
420 431
432 /// Reconfigure the driver
421 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 433 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
422 reconfigure::<T>(config)?; 434 reconfigure::<T>(config)?;
423 435
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index d5828a492..8a0c85d2c 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -1,4 +1,6 @@
1//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
1#![macro_use] 2#![macro_use]
3#![warn(missing_docs)]
2 4
3use core::future::poll_fn; 5use core::future::poll_fn;
4use core::marker::PhantomData; 6use core::marker::PhantomData;
@@ -76,21 +78,29 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
76 78
77#[derive(Clone, Copy, PartialEq, Eq, Debug)] 79#[derive(Clone, Copy, PartialEq, Eq, Debug)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))] 80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81/// Number of data bits
79pub enum DataBits { 82pub enum DataBits {
83 /// 8 Data Bits
80 DataBits8, 84 DataBits8,
85 /// 9 Data Bits
81 DataBits9, 86 DataBits9,
82} 87}
83 88
84#[derive(Clone, Copy, PartialEq, Eq, Debug)] 89#[derive(Clone, Copy, PartialEq, Eq, Debug)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))] 90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91/// Parity
86pub enum Parity { 92pub enum Parity {
93 /// No parity
87 ParityNone, 94 ParityNone,
95 /// Even Parity
88 ParityEven, 96 ParityEven,
97 /// Odd Parity
89 ParityOdd, 98 ParityOdd,
90} 99}
91 100
92#[derive(Clone, Copy, PartialEq, Eq, Debug)] 101#[derive(Clone, Copy, PartialEq, Eq, Debug)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))] 102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103/// Number of stop bits
94pub enum StopBits { 104pub enum StopBits {
95 #[doc = "1 stop bit"] 105 #[doc = "1 stop bit"]
96 STOP1, 106 STOP1,
@@ -105,26 +115,37 @@ pub enum StopBits {
105#[non_exhaustive] 115#[non_exhaustive]
106#[derive(Clone, Copy, PartialEq, Eq, Debug)] 116#[derive(Clone, Copy, PartialEq, Eq, Debug)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))] 117#[cfg_attr(feature = "defmt", derive(defmt::Format))]
118/// Config Error
108pub enum ConfigError { 119pub enum ConfigError {
120 /// Baudrate too low
109 BaudrateTooLow, 121 BaudrateTooLow,
122 /// Baudrate too high
110 BaudrateTooHigh, 123 BaudrateTooHigh,
124 /// Rx or Tx not enabled
111 RxOrTxNotEnabled, 125 RxOrTxNotEnabled,
112} 126}
113 127
114#[non_exhaustive] 128#[non_exhaustive]
115#[derive(Clone, Copy, PartialEq, Eq, Debug)] 129#[derive(Clone, Copy, PartialEq, Eq, Debug)]
130/// Config
116pub struct Config { 131pub struct Config {
132 /// Baud rate
117 pub baudrate: u32, 133 pub baudrate: u32,
134 /// Number of data bits
118 pub data_bits: DataBits, 135 pub data_bits: DataBits,
136 /// Number of stop bits
119 pub stop_bits: StopBits, 137 pub stop_bits: StopBits,
138 /// Parity type
120 pub parity: Parity, 139 pub parity: Parity,
121 /// if true, on read-like method, if there is a latent error pending, 140
122 /// read will abort, the error reported and cleared 141 /// If true: on a read-like method, if there is a latent error pending,
123 /// if false, the error is ignored and cleared 142 /// the read will abort and the error will be reported and cleared
143 ///
144 /// If false: the error is ignored and cleared
124 pub detect_previous_overrun: bool, 145 pub detect_previous_overrun: bool,
125 146
126 /// Set this to true if the line is considered noise free. 147 /// Set this to true if the line is considered noise free.
127 /// This will increase the receivers tolerance to clock deviations, 148 /// This will increase the receiver’s tolerance to clock deviations,
128 /// but will effectively disable noise detection. 149 /// but will effectively disable noise detection.
129 #[cfg(not(usart_v1))] 150 #[cfg(not(usart_v1))]
130 pub assume_noise_free: bool, 151 pub assume_noise_free: bool,
@@ -132,6 +153,14 @@ pub struct Config {
132 /// Set this to true to swap the RX and TX pins. 153 /// Set this to true to swap the RX and TX pins.
133 #[cfg(any(usart_v3, usart_v4))] 154 #[cfg(any(usart_v3, usart_v4))]
134 pub swap_rx_tx: bool, 155 pub swap_rx_tx: bool,
156
157 /// Set this to true to invert TX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
158 #[cfg(any(usart_v3, usart_v4))]
159 pub invert_tx: bool,
160
161 /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
162 #[cfg(any(usart_v3, usart_v4))]
163 pub invert_rx: bool,
135} 164}
136 165
137impl Default for Config { 166impl Default for Config {
@@ -147,6 +176,10 @@ impl Default for Config {
147 assume_noise_free: false, 176 assume_noise_free: false,
148 #[cfg(any(usart_v3, usart_v4))] 177 #[cfg(any(usart_v3, usart_v4))]
149 swap_rx_tx: false, 178 swap_rx_tx: false,
179 #[cfg(any(usart_v3, usart_v4))]
180 invert_tx: false,
181 #[cfg(any(usart_v3, usart_v4))]
182 invert_rx: false,
150 } 183 }
151 } 184 }
152} 185}
@@ -175,6 +208,7 @@ enum ReadCompletionEvent {
175 Idle(usize), 208 Idle(usize),
176} 209}
177 210
211/// Bidirectional UART Driver
178pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { 212pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
179 tx: UartTx<'d, T, TxDma>, 213 tx: UartTx<'d, T, TxDma>,
180 rx: UartRx<'d, T, RxDma>, 214 rx: UartRx<'d, T, RxDma>,
@@ -190,6 +224,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma>
190 } 224 }
191} 225}
192 226
227/// Tx-only UART Driver
193pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { 228pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
194 phantom: PhantomData<&'d mut T>, 229 phantom: PhantomData<&'d mut T>,
195 tx_dma: PeripheralRef<'d, TxDma>, 230 tx_dma: PeripheralRef<'d, TxDma>,
@@ -204,6 +239,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
204 } 239 }
205} 240}
206 241
242/// Rx-only UART Driver
207pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { 243pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
208 _peri: PeripheralRef<'d, T>, 244 _peri: PeripheralRef<'d, T>,
209 rx_dma: PeripheralRef<'d, RxDma>, 245 rx_dma: PeripheralRef<'d, RxDma>,
@@ -234,6 +270,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
234 Self::new_inner(peri, tx, tx_dma, config) 270 Self::new_inner(peri, tx, tx_dma, config)
235 } 271 }
236 272
273 /// Create a new tx-only UART with a clear-to-send pin
237 pub fn new_with_cts( 274 pub fn new_with_cts(
238 peri: impl Peripheral<P = T> + 'd, 275 peri: impl Peripheral<P = T> + 'd,
239 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 276 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@@ -275,10 +312,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
275 }) 312 })
276 } 313 }
277 314
315 /// Reconfigure the driver
278 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 316 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
279 reconfigure::<T>(config) 317 reconfigure::<T>(config)
280 } 318 }
281 319
320 /// Initiate an asynchronous UART write
282 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> 321 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
283 where 322 where
284 TxDma: crate::usart::TxDma<T>, 323 TxDma: crate::usart::TxDma<T>,
@@ -295,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
295 Ok(()) 334 Ok(())
296 } 335 }
297 336
337 /// Perform a blocking UART write
298 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 338 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
299 let r = T::regs(); 339 let r = T::regs();
300 for &b in buffer { 340 for &b in buffer {
@@ -304,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
304 Ok(()) 344 Ok(())
305 } 345 }
306 346
347 /// Block until transmission complete
307 pub fn blocking_flush(&mut self) -> Result<(), Error> { 348 pub fn blocking_flush(&mut self) -> Result<(), Error> {
308 let r = T::regs(); 349 let r = T::regs();
309 while !sr(r).read().tc() {} 350 while !sr(r).read().tc() {}
@@ -325,6 +366,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
325 Self::new_inner(peri, rx, rx_dma, config) 366 Self::new_inner(peri, rx, rx_dma, config)
326 } 367 }
327 368
369 /// Create a new rx-only UART with a request-to-send pin
328 pub fn new_with_rts( 370 pub fn new_with_rts(
329 peri: impl Peripheral<P = T> + 'd, 371 peri: impl Peripheral<P = T> + 'd,
330 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 372 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@@ -374,6 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
374 }) 416 })
375 } 417 }
376 418
419 /// Reconfigure the driver
377 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 420 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
378 reconfigure::<T>(config) 421 reconfigure::<T>(config)
379 } 422 }
@@ -431,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
431 Ok(sr.rxne()) 474 Ok(sr.rxne())
432 } 475 }
433 476
477 /// Initiate an asynchronous UART read
434 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 478 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
435 where 479 where
436 RxDma: crate::usart::RxDma<T>, 480 RxDma: crate::usart::RxDma<T>,
@@ -440,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
440 Ok(()) 484 Ok(())
441 } 485 }
442 486
487 /// Read a single u8 if there is one available, otherwise return WouldBlock
443 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 488 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
444 let r = T::regs(); 489 let r = T::regs();
445 if self.check_rx_flags()? { 490 if self.check_rx_flags()? {
@@ -449,6 +494,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
449 } 494 }
450 } 495 }
451 496
497 /// Perform a blocking read into `buffer`
452 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 498 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
453 let r = T::regs(); 499 let r = T::regs();
454 for b in buffer { 500 for b in buffer {
@@ -458,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
458 Ok(()) 504 Ok(())
459 } 505 }
460 506
507 /// Initiate an asynchronous read with idle line detection enabled
461 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> 508 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
462 where 509 where
463 RxDma: crate::usart::RxDma<T>, 510 RxDma: crate::usart::RxDma<T>,
@@ -682,6 +729,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
682} 729}
683 730
684impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { 731impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
732 /// Create a new bidirectional UART
685 pub fn new( 733 pub fn new(
686 peri: impl Peripheral<P = T> + 'd, 734 peri: impl Peripheral<P = T> + 'd,
687 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 735 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -698,6 +746,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
698 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) 746 Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
699 } 747 }
700 748
749 /// Create a new bidirectional UART with request-to-send and clear-to-send pins
701 pub fn new_with_rtscts( 750 pub fn new_with_rtscts(
702 peri: impl Peripheral<P = T> + 'd, 751 peri: impl Peripheral<P = T> + 'd,
703 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 752 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -725,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
725 } 774 }
726 775
727 #[cfg(not(any(usart_v1, usart_v2)))] 776 #[cfg(not(any(usart_v1, usart_v2)))]
777 /// Create a new bidirectional UART with a driver-enable pin
728 pub fn new_with_de( 778 pub fn new_with_de(
729 peri: impl Peripheral<P = T> + 'd, 779 peri: impl Peripheral<P = T> + 'd,
730 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 780 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -800,6 +850,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
800 }) 850 })
801 } 851 }
802 852
853 /// Initiate an asynchronous write
803 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> 854 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
804 where 855 where
805 TxDma: crate::usart::TxDma<T>, 856 TxDma: crate::usart::TxDma<T>,
@@ -807,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
807 self.tx.write(buffer).await 858 self.tx.write(buffer).await
808 } 859 }
809 860
861 /// Perform a blocking write
810 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 862 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
811 self.tx.blocking_write(buffer) 863 self.tx.blocking_write(buffer)
812 } 864 }
813 865
866 /// Block until transmission complete
814 pub fn blocking_flush(&mut self) -> Result<(), Error> { 867 pub fn blocking_flush(&mut self) -> Result<(), Error> {
815 self.tx.blocking_flush() 868 self.tx.blocking_flush()
816 } 869 }
817 870
871 /// Initiate an asynchronous read into `buffer`
818 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> 872 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
819 where 873 where
820 RxDma: crate::usart::RxDma<T>, 874 RxDma: crate::usart::RxDma<T>,
@@ -822,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
822 self.rx.read(buffer).await 876 self.rx.read(buffer).await
823 } 877 }
824 878
879 /// Read a single `u8` or return `WouldBlock`
825 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { 880 pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
826 self.rx.nb_read() 881 self.rx.nb_read()
827 } 882 }
828 883
884 /// Perform a blocking read into `buffer`
829 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 885 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
830 self.rx.blocking_read(buffer) 886 self.rx.blocking_read(buffer)
831 } 887 }
832 888
889 /// Initiate an an asynchronous read with idle line detection enabled
833 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> 890 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
834 where 891 where
835 RxDma: crate::usart::RxDma<T>, 892 RxDma: crate::usart::RxDma<T>,
@@ -972,7 +1029,11 @@ fn configure(
972 }); 1029 });
973 1030
974 #[cfg(any(usart_v3, usart_v4))] 1031 #[cfg(any(usart_v3, usart_v4))]
975 w.set_swap(config.swap_rx_tx); 1032 {
1033 w.set_txinv(config.invert_tx);
1034 w.set_rxinv(config.invert_rx);
1035 w.set_swap(config.swap_rx_tx);
1036 }
976 }); 1037 });
977 1038
978 #[cfg(not(usart_v1))] 1039 #[cfg(not(usart_v1))]
@@ -1275,8 +1336,10 @@ pub(crate) mod sealed {
1275 } 1336 }
1276} 1337}
1277 1338
1339/// Basic UART driver instance
1278pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} 1340pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
1279 1341
1342/// Full UART driver instance
1280pub trait FullInstance: sealed::FullInstance {} 1343pub trait FullInstance: sealed::FullInstance {}
1281 1344
1282pin_trait!(RxPin, BasicInstance); 1345pin_trait!(RxPin, BasicInstance);
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b8d17e4e4..4391bfef7 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -11,6 +11,7 @@ use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config,
11use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
12use crate::usart::{Regs, Sr}; 12use crate::usart::{Regs, Sr};
13 13
14/// Rx-only Ring-buffered UART Driver
14pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { 15pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
15 _peri: PeripheralRef<'d, T>, 16 _peri: PeripheralRef<'d, T>,
16 ring_buf: ReadableRingBuffer<'d, RxDma, u8>, 17 ring_buf: ReadableRingBuffer<'d, RxDma, u8>,
@@ -27,8 +28,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUar
27 28
28impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { 29impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
29 /// Turn the `UartRx` into a buffered uart which can continously receive in the background 30 /// Turn the `UartRx` into a buffered uart which can continously receive in the background
30 /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the 31 /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
31 /// DMA controller, and must be sufficiently large, such that it will not overflow. 32 /// DMA controller, and must be large enough to prevent overflows.
32 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { 33 pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> {
33 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 34 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
34 35
@@ -39,7 +40,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
39 let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; 40 let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
40 let _peri = unsafe { self._peri.clone_unchecked() }; 41 let _peri = unsafe { self._peri.clone_unchecked() };
41 42
42 let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 43 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
43 44
44 // Don't disable the clock 45 // Don't disable the clock
45 mem::forget(self); 46 mem::forget(self);
@@ -49,6 +50,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
49} 50}
50 51
51impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> { 52impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> {
53 /// Clear the ring buffer and start receiving in the background
52 pub fn start(&mut self) -> Result<(), Error> { 54 pub fn start(&mut self) -> Result<(), Error> {
53 // Clear the ring buffer so that it is ready to receive data 55 // Clear the ring buffer so that it is ready to receive data
54 self.ring_buf.clear(); 56 self.ring_buf.clear();
@@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
64 Err(err) 66 Err(err)
65 } 67 }
66 68
69 /// Cleanly stop and reconfigure the driver
67 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 70 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
68 self.teardown_uart(); 71 self.teardown_uart();
69 reconfigure::<T>(config) 72 reconfigure::<T>(config)
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..04b1b35e8 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,
@@ -695,10 +701,10 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
695 } 701 }
696 702
697 async fn wait_enabled(&mut self) { 703 async fn wait_enabled(&mut self) {
698 trace!("wait_enabled OUT WAITING"); 704 trace!("wait_enabled IN WAITING");
699 let index = self.info.addr.index(); 705 let index = self.info.addr.index();
700 poll_fn(|cx| { 706 poll_fn(|cx| {
701 EP_OUT_WAKERS[index].register(cx.waker()); 707 EP_IN_WAKERS[index].register(cx.waker());
702 let regs = T::regs(); 708 let regs = T::regs();
703 if regs.epr(index).read().stat_tx() == Stat::DISABLED { 709 if regs.epr(index).read().stat_tx() == Stat::DISABLED {
704 Poll::Pending 710 Poll::Pending
@@ -707,7 +713,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
707 } 713 }
708 }) 714 })
709 .await; 715 .await;
710 trace!("wait_enabled OUT OK"); 716 trace!("wait_enabled IN OK");
711 } 717 }
712} 718}
713 719
@@ -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 be54a3d10..0649e684b 100644
--- a/embassy-stm32/src/usb_otg/mod.rs
+++ b/embassy-stm32/src/usb_otg/mod.rs
@@ -1,3 +1,5 @@
1//! USB On The Go (OTG)
2
1use crate::rcc::RccPeripheral; 3use crate::rcc::RccPeripheral;
2use crate::{interrupt, peripherals}; 4use crate::{interrupt, peripherals};
3 5
@@ -18,7 +20,9 @@ pub(crate) mod sealed {
18 } 20 }
19} 21}
20 22
23/// USB OTG instance.
21pub trait Instance: sealed::Instance + RccPeripheral { 24pub trait Instance: sealed::Instance + RccPeripheral {
25 /// Interrupt for this USB OTG instance.
22 type Interrupt: interrupt::typelevel::Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
23} 27}
24 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 c7c2694e0..dc701ef64 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -1,3 +1,4 @@
1//! Watchdog Timer (IWDG, WWDG)
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2 3
3use embassy_hal_internal::{into_ref, Peripheral}; 4use embassy_hal_internal::{into_ref, Peripheral};
@@ -5,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr};
5 6
6use crate::rcc::LSI_FREQ; 7use crate::rcc::LSI_FREQ;
7 8
9/// Independent watchdog (IWDG) driver.
8pub struct IndependentWatchdog<'d, T: Instance> { 10pub struct IndependentWatchdog<'d, T: Instance> {
9 wdg: PhantomData<&'d mut T>, 11 wdg: PhantomData<&'d mut T>,
10} 12}
@@ -63,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
63 IndependentWatchdog { wdg: PhantomData } 65 IndependentWatchdog { wdg: PhantomData }
64 } 66 }
65 67
68 /// Unleash (start) the watchdog.
66 pub fn unleash(&mut self) { 69 pub fn unleash(&mut self) {
67 T::regs().kr().write(|w| w.set_key(Key::START)); 70 T::regs().kr().write(|w| w.set_key(Key::START));
68 } 71 }
69 72
73 /// Pet (reload, refresh) the watchdog.
70 pub fn pet(&mut self) { 74 pub fn pet(&mut self) {
71 T::regs().kr().write(|w| w.set_key(Key::RESET)); 75 T::regs().kr().write(|w| w.set_key(Key::RESET));
72 } 76 }
@@ -78,6 +82,7 @@ mod sealed {
78 } 82 }
79} 83}
80 84
85/// IWDG instance trait.
81pub trait Instance: sealed::Instance {} 86pub trait Instance: sealed::Instance {}
82 87
83foreach_peripheral!( 88foreach_peripheral!(