aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-12-17 22:09:14 +0100
committerDario Nieuwenhuis <[email protected]>2023-12-18 00:53:18 +0100
commit80c9d04bbd83367340a4f3a1e991df825a0b6029 (patch)
treed79b74b0ca17dd943dfcb3b809e895918f4ae629
parenta2d4bab2f8a4a9b994bc0289938a9f725950715f (diff)
stm32: add some docs.
-rw-r--r--embassy-nrf/src/gpio.rs25
-rw-r--r--embassy-stm32/src/adc/mod.rs6
-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/fdcan.rs15
-rw-r--r--embassy-stm32/src/crc/v2v3.rs13
-rw-r--r--embassy-stm32/src/dac/mod.rs21
-rw-r--r--embassy-stm32/src/dac/tsel.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs24
-rw-r--r--embassy-stm32/src/dma/bdma.rs62
-rw-r--r--embassy-stm32/src/dma/dma.rs79
-rw-r--r--embassy-stm32/src/dma/dmamux.rs4
-rw-r--r--embassy-stm32/src/dma/mod.rs7
-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.rs25
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs3
-rw-r--r--embassy-stm32/src/exti.rs50
-rw-r--r--embassy-stm32/src/flash/asynch.rs2
-rw-r--r--embassy-stm32/src/flash/common.rs33
-rw-r--r--embassy-stm32/src/flash/f0.rs4
-rw-r--r--embassy-stm32/src/flash/f3.rs4
-rw-r--r--embassy-stm32/src/flash/f7.rs4
-rw-r--r--embassy-stm32/src/flash/g.rs4
-rw-r--r--embassy-stm32/src/flash/h7.rs4
-rw-r--r--embassy-stm32/src/flash/l.rs4
-rw-r--r--embassy-stm32/src/flash/mod.rs62
-rw-r--r--embassy-stm32/src/flash/other.rs4
-rw-r--r--embassy-stm32/src/gpio.rs81
-rw-r--r--embassy-stm32/src/i2c/mod.rs14
-rw-r--r--embassy-stm32/src/qspi/enums.rs41
-rw-r--r--embassy-stm32/src/qspi/mod.rs4
-rw-r--r--embassy-stm32/src/sai/mod.rs4
-rw-r--r--embassy-stm32/src/traits.rs6
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs2
-rw-r--r--examples/stm32f4/src/bin/flash.rs6
-rw-r--r--examples/stm32f4/src/bin/flash_async.rs6
37 files changed, 537 insertions, 117 deletions
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index 85977a804..a47fb8350 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -50,19 +50,19 @@ impl<'d, T: Pin> Input<'d, T> {
50 Self { pin } 50 Self { pin }
51 } 51 }
52 52
53 /// Test if current pin level is high. 53 /// Get whether the pin input level is high.
54 #[inline] 54 #[inline]
55 pub fn is_high(&mut self) -> bool { 55 pub fn is_high(&mut self) -> bool {
56 self.pin.is_high() 56 self.pin.is_high()
57 } 57 }
58 58
59 /// Test if current pin level is low. 59 /// Get whether the pin input level is low.
60 #[inline] 60 #[inline]
61 pub fn is_low(&mut self) -> bool { 61 pub fn is_low(&mut self) -> bool {
62 self.pin.is_low() 62 self.pin.is_low()
63 } 63 }
64 64
65 /// Returns current pin level 65 /// Get the pin input level.
66 #[inline] 66 #[inline]
67 pub fn get_level(&mut self) -> Level { 67 pub fn get_level(&mut self) -> Level {
68 self.pin.get_level() 68 self.pin.get_level()
@@ -158,19 +158,19 @@ impl<'d, T: Pin> Output<'d, T> {
158 self.pin.set_level(level) 158 self.pin.set_level(level)
159 } 159 }
160 160
161 /// Is the output pin set as high? 161 /// Get whether the output level is set to high.
162 #[inline] 162 #[inline]
163 pub fn is_set_high(&mut self) -> bool { 163 pub fn is_set_high(&mut self) -> bool {
164 self.pin.is_set_high() 164 self.pin.is_set_high()
165 } 165 }
166 166
167 /// Is the output pin set as low? 167 /// Get whether the output level is set to low.
168 #[inline] 168 #[inline]
169 pub fn is_set_low(&mut self) -> bool { 169 pub fn is_set_low(&mut self) -> bool {
170 self.pin.is_set_low() 170 self.pin.is_set_low()
171 } 171 }
172 172
173 /// What level output is set to 173 /// Get the current output level.
174 #[inline] 174 #[inline]
175 pub fn get_output_level(&mut self) -> Level { 175 pub fn get_output_level(&mut self) -> Level {
176 self.pin.get_output_level() 176 self.pin.get_output_level()
@@ -275,13 +275,13 @@ impl<'d, T: Pin> Flex<'d, T> {
275 self.pin.conf().reset(); 275 self.pin.conf().reset();
276 } 276 }
277 277
278 /// Test if current pin level is high. 278 /// Get whether the pin input level is high.
279 #[inline] 279 #[inline]
280 pub fn is_high(&mut self) -> bool { 280 pub fn is_high(&mut self) -> bool {
281 !self.is_low() 281 !self.is_low()
282 } 282 }
283 283
284 /// Test if current pin level is low. 284 /// Get whether the pin input level is low.
285 #[inline] 285 #[inline]
286 pub fn is_low(&mut self) -> bool { 286 pub fn is_low(&mut self) -> bool {
287 self.ref_is_low() 287 self.ref_is_low()
@@ -292,7 +292,7 @@ impl<'d, T: Pin> Flex<'d, T> {
292 self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 292 self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0
293 } 293 }
294 294
295 /// Returns current pin level 295 /// Get the pin input level.
296 #[inline] 296 #[inline]
297 pub fn get_level(&mut self) -> Level { 297 pub fn get_level(&mut self) -> Level {
298 self.is_high().into() 298 self.is_high().into()
@@ -319,25 +319,24 @@ impl<'d, T: Pin> Flex<'d, T> {
319 } 319 }
320 } 320 }
321 321
322 /// Is the output pin set as high? 322 /// Get whether the output level is set to high.
323 #[inline] 323 #[inline]
324 pub fn is_set_high(&mut self) -> bool { 324 pub fn is_set_high(&mut self) -> bool {
325 !self.is_set_low() 325 !self.is_set_low()
326 } 326 }
327 327
328 /// Is the output pin set as low? 328 /// Get whether the output level is set to low.
329 #[inline] 329 #[inline]
330 pub fn is_set_low(&mut self) -> bool { 330 pub fn is_set_low(&mut self) -> bool {
331 self.ref_is_set_low() 331 self.ref_is_set_low()
332 } 332 }
333 333
334 /// Is the output pin set as low?
335 #[inline] 334 #[inline]
336 pub(crate) fn ref_is_set_low(&self) -> bool { 335 pub(crate) fn ref_is_set_low(&self) -> bool {
337 self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 336 self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0
338 } 337 }
339 338
340 /// What level output is set to 339 /// Get the current output level.
341 #[inline] 340 #[inline]
342 pub fn get_output_level(&mut self) -> Level { 341 pub fn get_output_level(&mut self) -> Level {
343 self.is_set_high().into() 342 self.is_set_high().into()
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index dbe53c807..2e470662d 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -1,3 +1,4 @@
1//! Analog to Digital (ADC) converter driver.
1#![macro_use] 2#![macro_use]
2 3
3#[cfg(not(adc_f3_v2))] 4#[cfg(not(adc_f3_v2))]
@@ -24,6 +25,7 @@ pub use sample_time::SampleTime;
24 25
25use crate::peripherals; 26use crate::peripherals;
26 27
28/// Analog to Digital driver.
27pub struct Adc<'d, T: Instance> { 29pub struct Adc<'d, T: Instance> {
28 #[allow(unused)] 30 #[allow(unused)]
29 adc: crate::PeripheralRef<'d, T>, 31 adc: crate::PeripheralRef<'d, T>,
@@ -75,12 +77,16 @@ pub(crate) mod sealed {
75 } 77 }
76} 78}
77 79
80/// ADC instance.
78#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] 81#[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> {} 82pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
83/// ADC instance.
80#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] 84#[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 {} 85pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
82 86
87/// ADC pin.
83pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} 88pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
89/// ADC internal channel.
84pub trait InternalChannel<T>: sealed::InternalChannel<T> {} 90pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
85 91
86foreach_adc!( 92foreach_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/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/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..9c670195d 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -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..139d8fd1b 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -36,6 +36,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
36} 36}
37 37
38/// The level on the VSync pin when the data is not valid on the parallel interface. 38/// The level on the VSync pin when the data is not valid on the parallel interface.
39#[allow(missing_docs)]
39#[derive(Clone, Copy, PartialEq)] 40#[derive(Clone, Copy, PartialEq)]
40pub enum VSyncDataInvalidLevel { 41pub enum VSyncDataInvalidLevel {
41 Low, 42 Low,
@@ -43,6 +44,7 @@ pub enum VSyncDataInvalidLevel {
43} 44}
44 45
45/// The level on the VSync pin when the data is not valid on the parallel interface. 46/// The level on the VSync pin when the data is not valid on the parallel interface.
47#[allow(missing_docs)]
46#[derive(Clone, Copy, PartialEq)] 48#[derive(Clone, Copy, PartialEq)]
47pub enum HSyncDataInvalidLevel { 49pub enum HSyncDataInvalidLevel {
48 Low, 50 Low,
@@ -50,14 +52,16 @@ pub enum HSyncDataInvalidLevel {
50} 52}
51 53
52#[derive(Clone, Copy, PartialEq)] 54#[derive(Clone, Copy, PartialEq)]
55#[allow(missing_docs)]
53pub enum PixelClockPolarity { 56pub enum PixelClockPolarity {
54 RisingEdge, 57 RisingEdge,
55 FallingEdge, 58 FallingEdge,
56} 59}
57 60
58pub struct State { 61struct State {
59 waker: AtomicWaker, 62 waker: AtomicWaker,
60} 63}
64
61impl State { 65impl State {
62 const fn new() -> State { 66 const fn new() -> State {
63 State { 67 State {
@@ -68,18 +72,25 @@ impl State {
68 72
69static STATE: State = State::new(); 73static STATE: State = State::new();
70 74
75/// DCMI error.
71#[derive(Debug, Eq, PartialEq, Copy, Clone)] 76#[derive(Debug, Eq, PartialEq, Copy, Clone)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))] 77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[non_exhaustive] 78#[non_exhaustive]
74pub enum Error { 79pub enum Error {
80 /// Overrun error: the hardware generated data faster than we could read it.
75 Overrun, 81 Overrun,
82 /// Internal peripheral error.
76 PeripheralError, 83 PeripheralError,
77} 84}
78 85
86/// DCMI configuration.
79#[non_exhaustive] 87#[non_exhaustive]
80pub struct Config { 88pub struct Config {
89 /// VSYNC level.
81 pub vsync_level: VSyncDataInvalidLevel, 90 pub vsync_level: VSyncDataInvalidLevel,
91 /// HSYNC level.
82 pub hsync_level: HSyncDataInvalidLevel, 92 pub hsync_level: HSyncDataInvalidLevel,
93 /// PIXCLK polarity.
83 pub pixclk_polarity: PixelClockPolarity, 94 pub pixclk_polarity: PixelClockPolarity,
84} 95}
85 96
@@ -105,6 +116,7 @@ macro_rules! config_pins {
105 }; 116 };
106} 117}
107 118
119/// DCMI driver.
108pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { 120pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> {
109 inner: PeripheralRef<'d, T>, 121 inner: PeripheralRef<'d, T>,
110 dma: PeripheralRef<'d, Dma>, 122 dma: PeripheralRef<'d, Dma>,
@@ -115,6 +127,7 @@ where
115 T: Instance, 127 T: Instance,
116 Dma: FrameDma<T>, 128 Dma: FrameDma<T>,
117{ 129{
130 /// Create a new DCMI driver with 8 data bits.
118 pub fn new_8bit( 131 pub fn new_8bit(
119 peri: impl Peripheral<P = T> + 'd, 132 peri: impl Peripheral<P = T> + 'd,
120 dma: impl Peripheral<P = Dma> + 'd, 133 dma: impl Peripheral<P = Dma> + 'd,
@@ -139,6 +152,7 @@ where
139 Self::new_inner(peri, dma, config, false, 0b00) 152 Self::new_inner(peri, dma, config, false, 0b00)
140 } 153 }
141 154
155 /// Create a new DCMI driver with 10 data bits.
142 pub fn new_10bit( 156 pub fn new_10bit(
143 peri: impl Peripheral<P = T> + 'd, 157 peri: impl Peripheral<P = T> + 'd,
144 dma: impl Peripheral<P = Dma> + 'd, 158 dma: impl Peripheral<P = Dma> + 'd,
@@ -165,6 +179,7 @@ where
165 Self::new_inner(peri, dma, config, false, 0b01) 179 Self::new_inner(peri, dma, config, false, 0b01)
166 } 180 }
167 181
182 /// Create a new DCMI driver with 12 data bits.
168 pub fn new_12bit( 183 pub fn new_12bit(
169 peri: impl Peripheral<P = T> + 'd, 184 peri: impl Peripheral<P = T> + 'd,
170 dma: impl Peripheral<P = Dma> + 'd, 185 dma: impl Peripheral<P = Dma> + 'd,
@@ -193,6 +208,7 @@ where
193 Self::new_inner(peri, dma, config, false, 0b10) 208 Self::new_inner(peri, dma, config, false, 0b10)
194 } 209 }
195 210
211 /// Create a new DCMI driver with 14 data bits.
196 pub fn new_14bit( 212 pub fn new_14bit(
197 peri: impl Peripheral<P = T> + 'd, 213 peri: impl Peripheral<P = T> + 'd,
198 dma: impl Peripheral<P = Dma> + 'd, 214 dma: impl Peripheral<P = Dma> + 'd,
@@ -223,6 +239,7 @@ where
223 Self::new_inner(peri, dma, config, false, 0b11) 239 Self::new_inner(peri, dma, config, false, 0b11)
224 } 240 }
225 241
242 /// Create a new DCMI driver with 8 data bits, with embedded synchronization.
226 pub fn new_es_8bit( 243 pub fn new_es_8bit(
227 peri: impl Peripheral<P = T> + 'd, 244 peri: impl Peripheral<P = T> + 'd,
228 dma: impl Peripheral<P = Dma> + 'd, 245 dma: impl Peripheral<P = Dma> + 'd,
@@ -245,6 +262,7 @@ where
245 Self::new_inner(peri, dma, config, true, 0b00) 262 Self::new_inner(peri, dma, config, true, 0b00)
246 } 263 }
247 264
265 /// Create a new DCMI driver with 10 data bits, with embedded synchronization.
248 pub fn new_es_10bit( 266 pub fn new_es_10bit(
249 peri: impl Peripheral<P = T> + 'd, 267 peri: impl Peripheral<P = T> + 'd,
250 dma: impl Peripheral<P = Dma> + 'd, 268 dma: impl Peripheral<P = Dma> + 'd,
@@ -269,6 +287,7 @@ where
269 Self::new_inner(peri, dma, config, true, 0b01) 287 Self::new_inner(peri, dma, config, true, 0b01)
270 } 288 }
271 289
290 /// Create a new DCMI driver with 12 data bits, with embedded synchronization.
272 pub fn new_es_12bit( 291 pub fn new_es_12bit(
273 peri: impl Peripheral<P = T> + 'd, 292 peri: impl Peripheral<P = T> + 'd,
274 dma: impl Peripheral<P = Dma> + 'd, 293 dma: impl Peripheral<P = Dma> + 'd,
@@ -295,6 +314,7 @@ where
295 Self::new_inner(peri, dma, config, true, 0b10) 314 Self::new_inner(peri, dma, config, true, 0b10)
296 } 315 }
297 316
317 /// Create a new DCMI driver with 14 data bits, with embedded synchronization.
298 pub fn new_es_14bit( 318 pub fn new_es_14bit(
299 peri: impl Peripheral<P = T> + 'd, 319 peri: impl Peripheral<P = T> + 'd,
300 dma: impl Peripheral<P = Dma> + 'd, 320 dma: impl Peripheral<P = Dma> + 'd,
@@ -538,7 +558,9 @@ mod sealed {
538 } 558 }
539} 559}
540 560
561/// DCMI instance.
541pub trait Instance: sealed::Instance + 'static { 562pub trait Instance: sealed::Instance + 'static {
563 /// Interrupt for this instance.
542 type Interrupt: interrupt::typelevel::Interrupt; 564 type Interrupt: interrupt::typelevel::Interrupt;
543} 565}
544 566
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a7422f66b..5102330c0 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,6 +17,7 @@ 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]
@@ -140,13 +141,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
140 STATE.ch_wakers[index].wake(); 141 STATE.ch_wakers[index].wake();
141} 142}
142 143
144/// DMA request type alias.
143#[cfg(any(bdma_v2, dmamux))] 145#[cfg(any(bdma_v2, dmamux))]
144pub type Request = u8; 146pub type Request = u8;
147/// DMA request type alias.
145#[cfg(not(any(bdma_v2, dmamux)))] 148#[cfg(not(any(bdma_v2, dmamux)))]
146pub type Request = (); 149pub type Request = ();
147 150
151/// DMA channel.
148#[cfg(dmamux)] 152#[cfg(dmamux)]
149pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 153pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
154/// DMA channel.
150#[cfg(not(dmamux))] 155#[cfg(not(dmamux))]
151pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 156pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
152 157
@@ -161,12 +166,14 @@ pub(crate) mod sealed {
161 } 166 }
162} 167}
163 168
169/// DMA transfer.
164#[must_use = "futures do nothing unless you `.await` or poll them"] 170#[must_use = "futures do nothing unless you `.await` or poll them"]
165pub struct Transfer<'a, C: Channel> { 171pub struct Transfer<'a, C: Channel> {
166 channel: PeripheralRef<'a, C>, 172 channel: PeripheralRef<'a, C>,
167} 173}
168 174
169impl<'a, C: Channel> Transfer<'a, C> { 175impl<'a, C: Channel> Transfer<'a, C> {
176 /// Create a new read DMA transfer (peripheral to memory).
170 pub unsafe fn new_read<W: Word>( 177 pub unsafe fn new_read<W: Word>(
171 channel: impl Peripheral<P = C> + 'a, 178 channel: impl Peripheral<P = C> + 'a,
172 request: Request, 179 request: Request,
@@ -177,6 +184,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
177 Self::new_read_raw(channel, request, peri_addr, buf, options) 184 Self::new_read_raw(channel, request, peri_addr, buf, options)
178 } 185 }
179 186
187 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
180 pub unsafe fn new_read_raw<W: Word>( 188 pub unsafe fn new_read_raw<W: Word>(
181 channel: impl Peripheral<P = C> + 'a, 189 channel: impl Peripheral<P = C> + 'a,
182 request: Request, 190 request: Request,
@@ -202,6 +210,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
202 ) 210 )
203 } 211 }
204 212
213 /// Create a new write DMA transfer (memory to peripheral).
205 pub unsafe fn new_write<W: Word>( 214 pub unsafe fn new_write<W: Word>(
206 channel: impl Peripheral<P = C> + 'a, 215 channel: impl Peripheral<P = C> + 'a,
207 request: Request, 216 request: Request,
@@ -212,6 +221,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
212 Self::new_write_raw(channel, request, buf, peri_addr, options) 221 Self::new_write_raw(channel, request, buf, peri_addr, options)
213 } 222 }
214 223
224 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
215 pub unsafe fn new_write_raw<W: Word>( 225 pub unsafe fn new_write_raw<W: Word>(
216 channel: impl Peripheral<P = C> + 'a, 226 channel: impl Peripheral<P = C> + 'a,
217 request: Request, 227 request: Request,
@@ -237,6 +247,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
237 ) 247 )
238 } 248 }
239 249
250 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
240 pub unsafe fn new_write_repeated<W: Word>( 251 pub unsafe fn new_write_repeated<W: Word>(
241 channel: impl Peripheral<P = C> + 'a, 252 channel: impl Peripheral<P = C> + 'a,
242 request: Request, 253 request: Request,
@@ -321,6 +332,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
321 }); 332 });
322 } 333 }
323 334
335 /// Request the transfer to stop.
336 ///
337 /// 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) { 338 pub fn request_stop(&mut self) {
325 let ch = self.channel.regs().ch(self.channel.num()); 339 let ch = self.channel.regs().ch(self.channel.num());
326 340
@@ -331,6 +345,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
331 }); 345 });
332 } 346 }
333 347
348 /// Return whether this transfer is still running.
349 ///
350 /// If this returns `false`, it can be because either the transfer finished, or
351 /// it was requested to stop early with [`request_stop`](Self::request_stop).
334 pub fn is_running(&mut self) -> bool { 352 pub fn is_running(&mut self) -> bool {
335 let ch = self.channel.regs().ch(self.channel.num()); 353 let ch = self.channel.regs().ch(self.channel.num());
336 let en = ch.cr().read().en(); 354 let en = ch.cr().read().en();
@@ -339,13 +357,15 @@ impl<'a, C: Channel> Transfer<'a, C> {
339 en && (circular || !tcif) 357 en && (circular || !tcif)
340 } 358 }
341 359
342 /// Gets the total remaining transfers for the channel 360 /// Get the total remaining transfers for the channel.
343 /// Note: this will be zero for transfers that completed without cancellation. 361 ///
362 /// 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 { 363 pub fn get_remaining_transfers(&self) -> u16 {
345 let ch = self.channel.regs().ch(self.channel.num()); 364 let ch = self.channel.regs().ch(self.channel.num());
346 ch.ndtr().read().ndt() 365 ch.ndtr().read().ndt()
347 } 366 }
348 367
368 /// Blocking wait until the transfer finishes.
349 pub fn blocking_wait(mut self) { 369 pub fn blocking_wait(mut self) {
350 while self.is_running() {} 370 while self.is_running() {}
351 self.request_stop(); 371 self.request_stop();
@@ -411,6 +431,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
411 } 431 }
412} 432}
413 433
434/// Ringbuffer for reading data using DMA circular mode.
414pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 435pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
415 cr: regs::Cr, 436 cr: regs::Cr,
416 channel: PeripheralRef<'a, C>, 437 channel: PeripheralRef<'a, C>,
@@ -418,7 +439,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
418} 439}
419 440
420impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { 441impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
421 pub unsafe fn new_read( 442 /// Create a new ring buffer.
443 pub unsafe fn new(
422 channel: impl Peripheral<P = C> + 'a, 444 channel: impl Peripheral<P = C> + 'a,
423 _request: Request, 445 _request: Request,
424 peri_addr: *mut W, 446 peri_addr: *mut W,
@@ -473,11 +495,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
473 this 495 this
474 } 496 }
475 497
498 /// Start the ring buffer operation.
499 ///
500 /// You must call this after creating it for it to work.
476 pub fn start(&mut self) { 501 pub fn start(&mut self) {
477 let ch = self.channel.regs().ch(self.channel.num()); 502 let ch = self.channel.regs().ch(self.channel.num());
478 ch.cr().write_value(self.cr) 503 ch.cr().write_value(self.cr)
479 } 504 }
480 505
506 /// Clear all data in the ring buffer.
481 pub fn clear(&mut self) { 507 pub fn clear(&mut self) {
482 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 508 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
483 } 509 }
@@ -509,10 +535,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
509 } 535 }
510 536
511 /// The capacity of the ringbuffer. 537 /// The capacity of the ringbuffer.
512 pub const fn cap(&self) -> usize { 538 pub const fn capacity(&self) -> usize {
513 self.ringbuf.cap() 539 self.ringbuf.cap()
514 } 540 }
515 541
542 /// Set a waker to be woken when at least one byte is received.
516 pub fn set_waker(&mut self, waker: &Waker) { 543 pub fn set_waker(&mut self, waker: &Waker) {
517 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 544 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
518 } 545 }
@@ -526,6 +553,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
526 }); 553 });
527 } 554 }
528 555
556 /// Request DMA to stop.
557 ///
558 /// 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) { 559 pub fn request_stop(&mut self) {
530 let ch = self.channel.regs().ch(self.channel.num()); 560 let ch = self.channel.regs().ch(self.channel.num());
531 561
@@ -539,6 +569,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
539 }); 569 });
540 } 570 }
541 571
572 /// Return whether DMA is still running.
573 ///
574 /// If this returns `false`, it can be because either the transfer finished, or
575 /// it was requested to stop early with [`request_stop`](Self::request_stop).
542 pub fn is_running(&mut self) -> bool { 576 pub fn is_running(&mut self) -> bool {
543 let ch = self.channel.regs().ch(self.channel.num()); 577 let ch = self.channel.regs().ch(self.channel.num());
544 ch.cr().read().en() 578 ch.cr().read().en()
@@ -555,6 +589,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
555 } 589 }
556} 590}
557 591
592/// Ringbuffer for writing data using DMA circular mode.
558pub struct WritableRingBuffer<'a, C: Channel, W: Word> { 593pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
559 cr: regs::Cr, 594 cr: regs::Cr,
560 channel: PeripheralRef<'a, C>, 595 channel: PeripheralRef<'a, C>,
@@ -562,7 +597,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
562} 597}
563 598
564impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 599impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
565 pub unsafe fn new_write( 600 /// Create a new ring buffer.
601 pub unsafe fn new(
566 channel: impl Peripheral<P = C> + 'a, 602 channel: impl Peripheral<P = C> + 'a,
567 _request: Request, 603 _request: Request,
568 peri_addr: *mut W, 604 peri_addr: *mut W,
@@ -617,11 +653,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
617 this 653 this
618 } 654 }
619 655
656 /// Start the ring buffer operation.
657 ///
658 /// You must call this after creating it for it to work.
620 pub fn start(&mut self) { 659 pub fn start(&mut self) {
621 let ch = self.channel.regs().ch(self.channel.num()); 660 let ch = self.channel.regs().ch(self.channel.num());
622 ch.cr().write_value(self.cr) 661 ch.cr().write_value(self.cr)
623 } 662 }
624 663
664 /// Clear all data in the ring buffer.
625 pub fn clear(&mut self) { 665 pub fn clear(&mut self) {
626 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 666 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
627 } 667 }
@@ -640,10 +680,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
640 } 680 }
641 681
642 /// The capacity of the ringbuffer. 682 /// The capacity of the ringbuffer.
643 pub const fn cap(&self) -> usize { 683 pub const fn capacity(&self) -> usize {
644 self.ringbuf.cap() 684 self.ringbuf.cap()
645 } 685 }
646 686
687 /// Set a waker to be woken when at least one byte is sent.
647 pub fn set_waker(&mut self, waker: &Waker) { 688 pub fn set_waker(&mut self, waker: &Waker) {
648 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 689 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
649 } 690 }
@@ -657,6 +698,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
657 }); 698 });
658 } 699 }
659 700
701 /// Request DMA to stop.
702 ///
703 /// 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) { 704 pub fn request_stop(&mut self) {
661 let ch = self.channel.regs().ch(self.channel.num()); 705 let ch = self.channel.regs().ch(self.channel.num());
662 706
@@ -670,6 +714,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
670 }); 714 });
671 } 715 }
672 716
717 /// Return whether DMA is still running.
718 ///
719 /// If this returns `false`, it can be because either the transfer finished, or
720 /// it was requested to stop early with [`request_stop`](Self::request_stop).
673 pub fn is_running(&mut self) -> bool { 721 pub fn is_running(&mut self) -> bool {
674 let ch = self.channel.regs().ch(self.channel.num()); 722 let ch = self.channel.regs().ch(self.channel.num());
675 ch.cr().read().en() 723 ch.cr().read().en()
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index cce0407c1..64e492c10 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]
@@ -69,6 +70,7 @@ impl From<Dir> for vals::Dir {
69 } 70 }
70} 71}
71 72
73/// DMA transfer burst setting.
72#[derive(Debug, Copy, Clone, PartialEq, Eq)] 74#[derive(Debug, Copy, Clone, PartialEq, Eq)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))] 75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum Burst { 76pub enum Burst {
@@ -93,6 +95,7 @@ impl From<Burst> for vals::Burst {
93 } 95 }
94} 96}
95 97
98/// DMA flow control setting.
96#[derive(Debug, Copy, Clone, PartialEq, Eq)] 99#[derive(Debug, Copy, Clone, PartialEq, Eq)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))] 100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub enum FlowControl { 101pub enum FlowControl {
@@ -111,6 +114,7 @@ impl From<FlowControl> for vals::Pfctrl {
111 } 114 }
112} 115}
113 116
117/// DMA FIFO threshold.
114#[derive(Debug, Copy, Clone, PartialEq, Eq)] 118#[derive(Debug, Copy, Clone, PartialEq, Eq)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))] 119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub enum FifoThreshold { 120pub enum FifoThreshold {
@@ -208,13 +212,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
208 STATE.ch_wakers[index].wake(); 212 STATE.ch_wakers[index].wake();
209} 213}
210 214
215/// DMA request type alias. (also known as DMA channel number in some chips)
211#[cfg(any(dma_v2, dmamux))] 216#[cfg(any(dma_v2, dmamux))]
212pub type Request = u8; 217pub type Request = u8;
218/// DMA request type alias. (also known as DMA channel number in some chips)
213#[cfg(not(any(dma_v2, dmamux)))] 219#[cfg(not(any(dma_v2, dmamux)))]
214pub type Request = (); 220pub type Request = ();
215 221
222/// DMA channel.
216#[cfg(dmamux)] 223#[cfg(dmamux)]
217pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} 224pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
225/// DMA channel.
218#[cfg(not(dmamux))] 226#[cfg(not(dmamux))]
219pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} 227pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
220 228
@@ -229,12 +237,14 @@ pub(crate) mod sealed {
229 } 237 }
230} 238}
231 239
240/// DMA transfer.
232#[must_use = "futures do nothing unless you `.await` or poll them"] 241#[must_use = "futures do nothing unless you `.await` or poll them"]
233pub struct Transfer<'a, C: Channel> { 242pub struct Transfer<'a, C: Channel> {
234 channel: PeripheralRef<'a, C>, 243 channel: PeripheralRef<'a, C>,
235} 244}
236 245
237impl<'a, C: Channel> Transfer<'a, C> { 246impl<'a, C: Channel> Transfer<'a, C> {
247 /// Create a new read DMA transfer (peripheral to memory).
238 pub unsafe fn new_read<W: Word>( 248 pub unsafe fn new_read<W: Word>(
239 channel: impl Peripheral<P = C> + 'a, 249 channel: impl Peripheral<P = C> + 'a,
240 request: Request, 250 request: Request,
@@ -245,6 +255,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
245 Self::new_read_raw(channel, request, peri_addr, buf, options) 255 Self::new_read_raw(channel, request, peri_addr, buf, options)
246 } 256 }
247 257
258 /// Create a new read DMA transfer (peripheral to memory), using raw pointers.
248 pub unsafe fn new_read_raw<W: Word>( 259 pub unsafe fn new_read_raw<W: Word>(
249 channel: impl Peripheral<P = C> + 'a, 260 channel: impl Peripheral<P = C> + 'a,
250 request: Request, 261 request: Request,
@@ -270,6 +281,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
270 ) 281 )
271 } 282 }
272 283
284 /// Create a new write DMA transfer (memory to peripheral).
273 pub unsafe fn new_write<W: Word>( 285 pub unsafe fn new_write<W: Word>(
274 channel: impl Peripheral<P = C> + 'a, 286 channel: impl Peripheral<P = C> + 'a,
275 request: Request, 287 request: Request,
@@ -280,6 +292,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
280 Self::new_write_raw(channel, request, buf, peri_addr, options) 292 Self::new_write_raw(channel, request, buf, peri_addr, options)
281 } 293 }
282 294
295 /// Create a new write DMA transfer (memory to peripheral), using raw pointers.
283 pub unsafe fn new_write_raw<W: Word>( 296 pub unsafe fn new_write_raw<W: Word>(
284 channel: impl Peripheral<P = C> + 'a, 297 channel: impl Peripheral<P = C> + 'a,
285 request: Request, 298 request: Request,
@@ -305,6 +318,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
305 ) 318 )
306 } 319 }
307 320
321 /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
308 pub unsafe fn new_write_repeated<W: Word>( 322 pub unsafe fn new_write_repeated<W: Word>(
309 channel: impl Peripheral<P = C> + 'a, 323 channel: impl Peripheral<P = C> + 'a,
310 request: Request, 324 request: Request,
@@ -407,6 +421,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
407 }); 421 });
408 } 422 }
409 423
424 /// Request the transfer to stop.
425 ///
426 /// 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) { 427 pub fn request_stop(&mut self) {
411 let ch = self.channel.regs().st(self.channel.num()); 428 let ch = self.channel.regs().st(self.channel.num());
412 429
@@ -417,6 +434,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
417 }); 434 });
418 } 435 }
419 436
437 /// Return whether this transfer is still running.
438 ///
439 /// If this returns `false`, it can be because either the transfer finished, or
440 /// it was requested to stop early with [`request_stop`](Self::request_stop).
420 pub fn is_running(&mut self) -> bool { 441 pub fn is_running(&mut self) -> bool {
421 let ch = self.channel.regs().st(self.channel.num()); 442 let ch = self.channel.regs().st(self.channel.num());
422 ch.cr().read().en() 443 ch.cr().read().en()
@@ -429,6 +450,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
429 ch.ndtr().read().ndt() 450 ch.ndtr().read().ndt()
430 } 451 }
431 452
453 /// Blocking wait until the transfer finishes.
432 pub fn blocking_wait(mut self) { 454 pub fn blocking_wait(mut self) {
433 while self.is_running() {} 455 while self.is_running() {}
434 456
@@ -465,12 +487,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
465 487
466// ================================== 488// ==================================
467 489
490/// Double-buffered DMA transfer.
468pub struct DoubleBuffered<'a, C: Channel, W: Word> { 491pub struct DoubleBuffered<'a, C: Channel, W: Word> {
469 channel: PeripheralRef<'a, C>, 492 channel: PeripheralRef<'a, C>,
470 _phantom: PhantomData<W>, 493 _phantom: PhantomData<W>,
471} 494}
472 495
473impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { 496impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
497 /// Create a new read DMA transfer (peripheral to memory).
474 pub unsafe fn new_read( 498 pub unsafe fn new_read(
475 channel: impl Peripheral<P = C> + 'a, 499 channel: impl Peripheral<P = C> + 'a,
476 _request: Request, 500 _request: Request,
@@ -554,25 +578,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
554 }); 578 });
555 } 579 }
556 580
581 /// Set the first buffer address.
582 ///
583 /// You may call this while DMA is transferring the other buffer.
557 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { 584 pub unsafe fn set_buffer0(&mut self, buffer: *mut W) {
558 let ch = self.channel.regs().st(self.channel.num()); 585 let ch = self.channel.regs().st(self.channel.num());
559 ch.m0ar().write_value(buffer as _); 586 ch.m0ar().write_value(buffer as _);
560 } 587 }
561 588
589 /// Set the second buffer address.
590 ///
591 /// You may call this while DMA is transferring the other buffer.
562 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { 592 pub unsafe fn set_buffer1(&mut self, buffer: *mut W) {
563 let ch = self.channel.regs().st(self.channel.num()); 593 let ch = self.channel.regs().st(self.channel.num());
564 ch.m1ar().write_value(buffer as _); 594 ch.m1ar().write_value(buffer as _);
565 } 595 }
566 596
597 /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now)
567 pub fn is_buffer0_accessible(&mut self) -> bool { 598 pub fn is_buffer0_accessible(&mut self) -> bool {
568 let ch = self.channel.regs().st(self.channel.num()); 599 let ch = self.channel.regs().st(self.channel.num());
569 ch.cr().read().ct() == vals::Ct::MEMORY1 600 ch.cr().read().ct() == vals::Ct::MEMORY1
570 } 601 }
571 602
603 /// Set a waker to be woken when one of the buffers is being transferred.
572 pub fn set_waker(&mut self, waker: &Waker) { 604 pub fn set_waker(&mut self, waker: &Waker) {
573 STATE.ch_wakers[self.channel.index()].register(waker); 605 STATE.ch_wakers[self.channel.index()].register(waker);
574 } 606 }
575 607
608 /// Request the transfer to stop.
609 ///
610 /// 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) { 611 pub fn request_stop(&mut self) {
577 let ch = self.channel.regs().st(self.channel.num()); 612 let ch = self.channel.regs().st(self.channel.num());
578 613
@@ -583,6 +618,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
583 }); 618 });
584 } 619 }
585 620
621 /// Return whether this transfer is still running.
622 ///
623 /// If this returns `false`, it can be because either the transfer finished, or
624 /// it was requested to stop early with [`request_stop`](Self::request_stop).
586 pub fn is_running(&mut self) -> bool { 625 pub fn is_running(&mut self) -> bool {
587 let ch = self.channel.regs().st(self.channel.num()); 626 let ch = self.channel.regs().st(self.channel.num());
588 ch.cr().read().en() 627 ch.cr().read().en()
@@ -629,6 +668,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
629 } 668 }
630} 669}
631 670
671/// Ringbuffer for receiving data using DMA circular mode.
632pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { 672pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
633 cr: regs::Cr, 673 cr: regs::Cr,
634 channel: PeripheralRef<'a, C>, 674 channel: PeripheralRef<'a, C>,
@@ -636,7 +676,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
636} 676}
637 677
638impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { 678impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
639 pub unsafe fn new_read( 679 /// Create a new ring buffer.
680 pub unsafe fn new(
640 channel: impl Peripheral<P = C> + 'a, 681 channel: impl Peripheral<P = C> + 'a,
641 _request: Request, 682 _request: Request,
642 peri_addr: *mut W, 683 peri_addr: *mut W,
@@ -706,11 +747,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
706 this 747 this
707 } 748 }
708 749
750 /// Start the ring buffer operation.
751 ///
752 /// You must call this after creating it for it to work.
709 pub fn start(&mut self) { 753 pub fn start(&mut self) {
710 let ch = self.channel.regs().st(self.channel.num()); 754 let ch = self.channel.regs().st(self.channel.num());
711 ch.cr().write_value(self.cr); 755 ch.cr().write_value(self.cr);
712 } 756 }
713 757
758 /// Clear all data in the ring buffer.
714 pub fn clear(&mut self) { 759 pub fn clear(&mut self) {
715 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 760 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
716 } 761 }
@@ -741,11 +786,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
741 .await 786 .await
742 } 787 }
743 788
744 // The capacity of the ringbuffer 789 /// The capacity of the ringbuffer
745 pub const fn cap(&self) -> usize { 790 pub const fn capacity(&self) -> usize {
746 self.ringbuf.cap() 791 self.ringbuf.cap()
747 } 792 }
748 793
794 /// Set a waker to be woken when at least one byte is received.
749 pub fn set_waker(&mut self, waker: &Waker) { 795 pub fn set_waker(&mut self, waker: &Waker) {
750 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 796 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
751 } 797 }
@@ -763,6 +809,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
763 }); 809 });
764 } 810 }
765 811
812 /// Request DMA to stop.
813 ///
814 /// 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) { 815 pub fn request_stop(&mut self) {
767 let ch = self.channel.regs().st(self.channel.num()); 816 let ch = self.channel.regs().st(self.channel.num());
768 817
@@ -774,6 +823,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
774 }); 823 });
775 } 824 }
776 825
826 /// Return whether DMA is still running.
827 ///
828 /// If this returns `false`, it can be because either the transfer finished, or
829 /// it was requested to stop early with [`request_stop`](Self::request_stop).
777 pub fn is_running(&mut self) -> bool { 830 pub fn is_running(&mut self) -> bool {
778 let ch = self.channel.regs().st(self.channel.num()); 831 let ch = self.channel.regs().st(self.channel.num());
779 ch.cr().read().en() 832 ch.cr().read().en()
@@ -790,6 +843,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> {
790 } 843 }
791} 844}
792 845
846/// Ringbuffer for writing data using DMA circular mode.
793pub struct WritableRingBuffer<'a, C: Channel, W: Word> { 847pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
794 cr: regs::Cr, 848 cr: regs::Cr,
795 channel: PeripheralRef<'a, C>, 849 channel: PeripheralRef<'a, C>,
@@ -797,7 +851,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> {
797} 851}
798 852
799impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { 853impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
800 pub unsafe fn new_write( 854 /// Create a new ring buffer.
855 pub unsafe fn new(
801 channel: impl Peripheral<P = C> + 'a, 856 channel: impl Peripheral<P = C> + 'a,
802 _request: Request, 857 _request: Request,
803 peri_addr: *mut W, 858 peri_addr: *mut W,
@@ -867,11 +922,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
867 this 922 this
868 } 923 }
869 924
925 /// Start the ring buffer operation.
926 ///
927 /// You must call this after creating it for it to work.
870 pub fn start(&mut self) { 928 pub fn start(&mut self) {
871 let ch = self.channel.regs().st(self.channel.num()); 929 let ch = self.channel.regs().st(self.channel.num());
872 ch.cr().write_value(self.cr); 930 ch.cr().write_value(self.cr);
873 } 931 }
874 932
933 /// Clear all data in the ring buffer.
875 pub fn clear(&mut self) { 934 pub fn clear(&mut self) {
876 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); 935 self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
877 } 936 }
@@ -889,11 +948,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
889 .await 948 .await
890 } 949 }
891 950
892 // The capacity of the ringbuffer 951 /// The capacity of the ringbuffer
893 pub const fn cap(&self) -> usize { 952 pub const fn capacity(&self) -> usize {
894 self.ringbuf.cap() 953 self.ringbuf.cap()
895 } 954 }
896 955
956 /// Set a waker to be woken when at least one byte is received.
897 pub fn set_waker(&mut self, waker: &Waker) { 957 pub fn set_waker(&mut self, waker: &Waker) {
898 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); 958 DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
899 } 959 }
@@ -911,6 +971,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
911 }); 971 });
912 } 972 }
913 973
974 /// Request DMA to stop.
975 ///
976 /// 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) { 977 pub fn request_stop(&mut self) {
915 let ch = self.channel.regs().st(self.channel.num()); 978 let ch = self.channel.regs().st(self.channel.num());
916 979
@@ -922,6 +985,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
922 }); 985 });
923 } 986 }
924 987
988 /// Return whether DMA is still running.
989 ///
990 /// If this returns `false`, it can be because either the transfer finished, or
991 /// it was requested to stop early with [`request_stop`](Self::request_stop).
925 pub fn is_running(&mut self) -> bool { 992 pub fn is_running(&mut self) -> bool {
926 let ch = self.channel.regs().st(self.channel.num()); 993 let ch = self.channel.regs().st(self.channel.num());
927 ch.cr().read().en() 994 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/mod.rs b/embassy-stm32/src/dma/mod.rs
index 29fced8fc..fb40a4b5e 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -39,6 +39,13 @@ enum Dir {
39 PeripheralToMemory, 39 PeripheralToMemory,
40} 40}
41 41
42/// "No DMA" placeholder.
43///
44/// You may pass this in place of a real DMA channel when creating a driver
45/// to indicate it should not use DMA.
46///
47/// This often causes async functionality to not be available on the instance,
48/// leaving only blocking functionality.
42pub struct NoDma; 49pub struct NoDma;
43 50
44impl_peripheral!(NoDma); 51impl_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..dbf91eedc 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -22,6 +22,14 @@ const RX_BUFFER_SIZE: usize = 1536;
22#[derive(Copy, Clone)] 22#[derive(Copy, Clone)]
23pub(crate) struct Packet<const N: usize>([u8; N]); 23pub(crate) struct Packet<const N: usize>([u8; N]);
24 24
25/// Ethernet packet queue.
26///
27/// This struct owns the memory used for reading and writing packets.
28///
29/// `TX` is the number of packets in the transmit queue, `RX` in the receive
30/// queue. A bigger queue allows the hardware to receive more packets while the
31/// CPU is busy doing other things, which may increase performance (especially for RX)
32/// at the cost of more RAM usage.
25pub struct PacketQueue<const TX: usize, const RX: usize> { 33pub struct PacketQueue<const TX: usize, const RX: usize> {
26 tx_desc: [TDes; TX], 34 tx_desc: [TDes; TX],
27 rx_desc: [RDes; RX], 35 rx_desc: [RDes; RX],
@@ -30,6 +38,7 @@ pub struct PacketQueue<const TX: usize, const RX: usize> {
30} 38}
31 39
32impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { 40impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
41 /// Create a new packet queue.
33 pub const fn new() -> Self { 42 pub const fn new() -> Self {
34 const NEW_TDES: TDes = TDes::new(); 43 const NEW_TDES: TDes = TDes::new();
35 const NEW_RDES: RDes = RDes::new(); 44 const NEW_RDES: RDes = RDes::new();
@@ -41,7 +50,18 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> {
41 } 50 }
42 } 51 }
43 52
44 // Allow to initialize a Self without requiring it to go on the stack 53 /// Initialize a packet queue in-place.
54 ///
55 /// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The
56 /// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()`
57 /// and then store the returned PacketQueue in its final place (like a `static`), the compiler might
58 /// place it temporarily on the stack then move it. Since this struct is quite big, it may result
59 /// in a stack overflow.
60 ///
61 /// With this function, you can create an uninitialized `static` with type `MaybeUninit<PacketQueue<...>>`
62 /// and initialize it in-place, guaranteeing no stack usage.
63 ///
64 /// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe.
45 pub fn init(this: &mut MaybeUninit<Self>) { 65 pub fn init(this: &mut MaybeUninit<Self>) {
46 unsafe { 66 unsafe {
47 this.as_mut_ptr().write_bytes(0u8, 1); 67 this.as_mut_ptr().write_bytes(0u8, 1);
@@ -93,6 +113,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
93 } 113 }
94} 114}
95 115
116/// `embassy-net` RX token.
96pub struct RxToken<'a, 'd> { 117pub struct RxToken<'a, 'd> {
97 rx: &'a mut RDesRing<'d>, 118 rx: &'a mut RDesRing<'d>,
98} 119}
@@ -110,6 +131,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> {
110 } 131 }
111} 132}
112 133
134/// `embassy-net` TX token.
113pub struct TxToken<'a, 'd> { 135pub struct TxToken<'a, 'd> {
114 tx: &'a mut TDesRing<'d>, 136 tx: &'a mut TDesRing<'d>,
115} 137}
@@ -159,6 +181,7 @@ pub(crate) mod sealed {
159 } 181 }
160} 182}
161 183
184/// Ethernet instance.
162pub trait Instance: sealed::Instance + Send + 'static {} 185pub trait Instance: sealed::Instance + Send + 'static {}
163 186
164impl sealed::Instance for crate::peripherals::ETH { 187impl sealed::Instance for crate::peripherals::ETH {
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 e77ac30fb..371be913e 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -39,7 +39,7 @@ fn exticr_regs() -> pac::afio::Afio {
39 pac::AFIO 39 pac::AFIO
40} 40}
41 41
42pub unsafe fn on_irq() { 42unsafe fn on_irq() {
43 #[cfg(feature = "low-power")] 43 #[cfg(feature = "low-power")]
44 crate::low_power::on_wakeup_irq(); 44 crate::low_power::on_wakeup_irq();
45 45
@@ -85,7 +85,13 @@ impl Iterator for BitIter {
85 } 85 }
86} 86}
87 87
88/// EXTI input driver 88/// EXTI input driver.
89///
90/// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not
91/// built into `Input` itself because it needs to take ownership of the corresponding
92/// EXTI channel, which is a limited resource.
93///
94/// 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> { 95pub struct ExtiInput<'d, T: GpioPin> {
90 pin: Input<'d, T>, 96 pin: Input<'d, T>,
91} 97}
@@ -93,23 +99,30 @@ pub struct ExtiInput<'d, T: GpioPin> {
93impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} 99impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {}
94 100
95impl<'d, T: GpioPin> ExtiInput<'d, T> { 101impl<'d, T: GpioPin> ExtiInput<'d, T> {
102 /// Create an EXTI input.
96 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { 103 pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self {
97 Self { pin } 104 Self { pin }
98 } 105 }
99 106
107 /// Get whether the pin is high.
100 pub fn is_high(&mut self) -> bool { 108 pub fn is_high(&mut self) -> bool {
101 self.pin.is_high() 109 self.pin.is_high()
102 } 110 }
103 111
112 /// Get whether the pin is low.
104 pub fn is_low(&mut self) -> bool { 113 pub fn is_low(&mut self) -> bool {
105 self.pin.is_low() 114 self.pin.is_low()
106 } 115 }
107 116
117 /// Get the pin level.
108 pub fn get_level(&mut self) -> Level { 118 pub fn get_level(&mut self) -> Level {
109 self.pin.get_level() 119 self.pin.get_level()
110 } 120 }
111 121
112 pub async fn wait_for_high<'a>(&'a mut self) { 122 /// Asynchronously wait until the pin is high.
123 ///
124 /// This returns immediately if the pin is already high.
125 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); 126 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
114 if self.is_high() { 127 if self.is_high() {
115 return; 128 return;
@@ -117,7 +130,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
117 fut.await 130 fut.await
118 } 131 }
119 132
120 pub async fn wait_for_low<'a>(&'a mut self) { 133 /// Asynchronously wait until the pin is low.
134 ///
135 /// This returns immediately if the pin is already low.
136 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); 137 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
122 if self.is_low() { 138 if self.is_low() {
123 return; 139 return;
@@ -125,15 +141,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
125 fut.await 141 fut.await
126 } 142 }
127 143
128 pub async fn wait_for_rising_edge<'a>(&'a mut self) { 144 /// Asynchronously wait until the pin sees a rising edge.
145 ///
146 /// If the pin is already high, it will wait for it to go low then back high.
147 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 148 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
130 } 149 }
131 150
132 pub async fn wait_for_falling_edge<'a>(&'a mut self) { 151 /// Asynchronously wait until the pin sees a falling edge.
152 ///
153 /// If the pin is already low, it will wait for it to go high then back low.
154 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 155 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
134 } 156 }
135 157
136 pub async fn wait_for_any_edge<'a>(&'a mut self) { 158 /// Asynchronously wait until the pin sees any edge (either rising or falling).
159 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 160 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
138 } 161 }
139} 162}
@@ -284,6 +307,7 @@ macro_rules! foreach_exti_irq {
284 307
285macro_rules! impl_irq { 308macro_rules! impl_irq {
286 ($e:ident) => { 309 ($e:ident) => {
310 #[allow(non_snake_case)]
287 #[cfg(feature = "rt")] 311 #[cfg(feature = "rt")]
288 #[interrupt] 312 #[interrupt]
289 unsafe fn $e() { 313 unsafe fn $e() {
@@ -298,8 +322,16 @@ pub(crate) mod sealed {
298 pub trait Channel {} 322 pub trait Channel {}
299} 323}
300 324
325/// EXTI channel trait.
301pub trait Channel: sealed::Channel + Sized { 326pub trait Channel: sealed::Channel + Sized {
327 /// Get the EXTI channel number.
302 fn number(&self) -> usize; 328 fn number(&self) -> usize;
329
330 /// Type-erase (degrade) this channel into an `AnyChannel`.
331 ///
332 /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which
333 /// are all different types, into the same type. It is useful for
334 /// creating arrays of channels, or avoiding generics.
303 fn degrade(self) -> AnyChannel { 335 fn degrade(self) -> AnyChannel {
304 AnyChannel { 336 AnyChannel {
305 number: self.number() as u8, 337 number: self.number() as u8,
@@ -307,9 +339,13 @@ pub trait Channel: sealed::Channel + Sized {
307 } 339 }
308} 340}
309 341
342/// Type-erased (degraded) EXTI channel.
343///
344/// This represents ownership over any EXTI channel, known at runtime.
310pub struct AnyChannel { 345pub struct AnyChannel {
311 number: u8, 346 number: u8,
312} 347}
348
313impl_peripheral!(AnyChannel); 349impl_peripheral!(AnyChannel);
314impl sealed::Channel for AnyChannel {} 350impl sealed::Channel for AnyChannel {}
315impl Channel for AnyChannel { 351impl Channel for AnyChannel {
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index eae40c7ec..e3c6d4d67 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -59,7 +59,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> {
59 const READ_SIZE: usize = super::READ_SIZE; 59 const READ_SIZE: usize = super::READ_SIZE;
60 60
61 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 61 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
62 self.read(offset, bytes) 62 self.blocking_read(offset, bytes)
63 } 63 }
64 64
65 fn capacity(&self) -> usize { 65 fn capacity(&self) -> usize {
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 80d2a8166..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
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs
index 27d5281a7..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
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 017393e80..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
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index 08145e9c4..d97b4a932 100644
--- a/embassy-stm32/src/flash/g.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
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index 555f8d155..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
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index e0159a3f6..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
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 3e8f2830b..6b6b4d41c 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -14,50 +14,84 @@ pub use crate::_generated::flash_regions::*;
14pub use crate::_generated::MAX_ERASE_SIZE; 14pub use crate::_generated::MAX_ERASE_SIZE;
15pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; 15pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE};
16 16
17/// Get whether the default flash layout is being used.
18///
19/// In some chips, dual-bank is not default. This will then return `false`
20/// when dual-bank is enabled.
21pub fn is_default_layout() -> bool {
22 family::is_default_layout()
23}
24
25/// Get all flash regions.
26pub fn get_flash_regions() -> &'static [&'static FlashRegion] {
27 family::get_flash_regions()
28}
29
30/// Read size (always 1)
17pub const READ_SIZE: usize = 1; 31pub const READ_SIZE: usize = 1;
18 32
19pub struct Blocking; 33/// Blocking flash mode typestate.
20pub struct Async; 34pub enum Blocking {}
35/// Async flash mode typestate.
36pub enum Async {}
21 37
38/// Flash memory region
22#[derive(Debug)] 39#[derive(Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))] 40#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub struct FlashRegion { 41pub struct FlashRegion {
42 /// Bank number.
25 pub bank: FlashBank, 43 pub bank: FlashBank,
44 /// Absolute base address.
26 pub base: u32, 45 pub base: u32,
46 /// Size in bytes.
27 pub size: u32, 47 pub size: u32,
48 /// Erase size (sector size).
28 pub erase_size: u32, 49 pub erase_size: u32,
50 /// Minimum write size.
29 pub write_size: u32, 51 pub write_size: u32,
52 /// Erase value (usually `0xFF`, but is `0x00` in some chips)
30 pub erase_value: u8, 53 pub erase_value: u8,
31 pub(crate) _ensure_internal: (), 54 pub(crate) _ensure_internal: (),
32} 55}
33 56
57impl FlashRegion {
58 /// Absolute end address.
59 pub const fn end(&self) -> u32 {
60 self.base + self.size
61 }
62
63 /// Number of sectors in the region.
64 pub const fn sectors(&self) -> u8 {
65 (self.size / self.erase_size) as u8
66 }
67}
68
69/// Flash sector.
34#[derive(Debug, PartialEq)] 70#[derive(Debug, PartialEq)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))] 71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct FlashSector { 72pub struct FlashSector {
73 /// Bank number.
37 pub bank: FlashBank, 74 pub bank: FlashBank,
75 /// Sector number within the bank.
38 pub index_in_bank: u8, 76 pub index_in_bank: u8,
77 /// Absolute start address.
39 pub start: u32, 78 pub start: u32,
79 /// Size in bytes.
40 pub size: u32, 80 pub size: u32,
41} 81}
42 82
83/// Flash bank.
43#[derive(Clone, Copy, Debug, PartialEq)] 84#[derive(Clone, Copy, Debug, PartialEq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))] 85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub enum FlashBank { 86pub enum FlashBank {
87 /// Bank 1
46 Bank1 = 0, 88 Bank1 = 0,
89 /// Bank 2
47 Bank2 = 1, 90 Bank2 = 1,
91 /// OTP region
48 Otp, 92 Otp,
49} 93}
50 94
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")] 95#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
62#[cfg_attr(flash_f0, path = "f0.rs")] 96#[cfg_attr(flash_f0, path = "f0.rs")]
63#[cfg_attr(flash_f3, path = "f3.rs")] 97#[cfg_attr(flash_f3, path = "f3.rs")]
@@ -78,6 +112,10 @@ mod family;
78#[allow(unused_imports)] 112#[allow(unused_imports)]
79pub use family::*; 113pub use family::*;
80 114
115/// Flash error
116///
117/// See STM32 Reference Manual for your chip for details.
118#[allow(missing_docs)]
81#[derive(Debug, Copy, Clone, PartialEq, Eq)] 119#[derive(Debug, Copy, Clone, PartialEq, Eq)]
82#[cfg_attr(feature = "defmt", derive(defmt::Format))] 120#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub enum Error { 121pub 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/gpio.rs b/embassy-stm32/src/gpio.rs
index bb3cf2bc4..083b3237c 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -29,6 +29,11 @@ impl<'d, T: Pin> Flex<'d, T> {
29 Self { pin } 29 Self { pin }
30 } 30 }
31 31
32 /// Type-erase (degrade) this pin into an `AnyPin`.
33 ///
34 /// This converts pin singletons (`PA5`, `PB6`, ...), which
35 /// are all different types, into the same type. It is useful for
36 /// creating arrays of pins, or avoiding generics.
32 #[inline] 37 #[inline]
33 pub fn degrade(self) -> Flex<'d, AnyPin> { 38 pub fn degrade(self) -> Flex<'d, AnyPin> {
34 // Safety: We are about to drop the other copy of this pin, so 39 // Safety: We are about to drop the other copy of this pin, so
@@ -141,11 +146,13 @@ impl<'d, T: Pin> Flex<'d, T> {
141 }); 146 });
142 } 147 }
143 148
149 /// Get whether the pin input level is high.
144 #[inline] 150 #[inline]
145 pub fn is_high(&mut self) -> bool { 151 pub fn is_high(&mut self) -> bool {
146 !self.ref_is_low() 152 !self.ref_is_low()
147 } 153 }
148 154
155 /// Get whether the pin input level is low.
149 #[inline] 156 #[inline]
150 pub fn is_low(&mut self) -> bool { 157 pub fn is_low(&mut self) -> bool {
151 self.ref_is_low() 158 self.ref_is_low()
@@ -157,17 +164,19 @@ impl<'d, T: Pin> Flex<'d, T> {
157 state == vals::Idr::LOW 164 state == vals::Idr::LOW
158 } 165 }
159 166
167 /// Get the current pin input level.
160 #[inline] 168 #[inline]
161 pub fn get_level(&mut self) -> Level { 169 pub fn get_level(&mut self) -> Level {
162 self.is_high().into() 170 self.is_high().into()
163 } 171 }
164 172
173 /// Get whether the output level is set to high.
165 #[inline] 174 #[inline]
166 pub fn is_set_high(&mut self) -> bool { 175 pub fn is_set_high(&mut self) -> bool {
167 !self.ref_is_set_low() 176 !self.ref_is_set_low()
168 } 177 }
169 178
170 /// Is the output pin set as low? 179 /// Get whether the output level is set to low.
171 #[inline] 180 #[inline]
172 pub fn is_set_low(&mut self) -> bool { 181 pub fn is_set_low(&mut self) -> bool {
173 self.ref_is_set_low() 182 self.ref_is_set_low()
@@ -179,12 +188,13 @@ impl<'d, T: Pin> Flex<'d, T> {
179 state == vals::Odr::LOW 188 state == vals::Odr::LOW
180 } 189 }
181 190
182 /// What level output is set to 191 /// Get the current output level.
183 #[inline] 192 #[inline]
184 pub fn get_output_level(&mut self) -> Level { 193 pub fn get_output_level(&mut self) -> Level {
185 self.is_set_high().into() 194 self.is_set_high().into()
186 } 195 }
187 196
197 /// Set the output as high.
188 #[inline] 198 #[inline]
189 pub fn set_high(&mut self) { 199 pub fn set_high(&mut self) {
190 self.pin.set_high(); 200 self.pin.set_high();
@@ -196,6 +206,7 @@ impl<'d, T: Pin> Flex<'d, T> {
196 self.pin.set_low(); 206 self.pin.set_low();
197 } 207 }
198 208
209 /// Set the output level.
199 #[inline] 210 #[inline]
200 pub fn set_level(&mut self, level: Level) { 211 pub fn set_level(&mut self, level: Level) {
201 match level { 212 match level {
@@ -204,7 +215,7 @@ impl<'d, T: Pin> Flex<'d, T> {
204 } 215 }
205 } 216 }
206 217
207 /// Toggle pin output 218 /// Toggle the output level.
208 #[inline] 219 #[inline]
209 pub fn toggle(&mut self) { 220 pub fn toggle(&mut self) {
210 if self.is_set_low() { 221 if self.is_set_low() {
@@ -242,8 +253,11 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
242#[derive(Debug, Eq, PartialEq, Copy, Clone)] 253#[derive(Debug, Eq, PartialEq, Copy, Clone)]
243#[cfg_attr(feature = "defmt", derive(defmt::Format))] 254#[cfg_attr(feature = "defmt", derive(defmt::Format))]
244pub enum Pull { 255pub enum Pull {
256 /// No pull
245 None, 257 None,
258 /// Pull up
246 Up, 259 Up,
260 /// Pull down
247 Down, 261 Down,
248} 262}
249 263
@@ -261,6 +275,9 @@ impl From<Pull> for vals::Pupdr {
261} 275}
262 276
263/// Speed settings 277/// Speed settings
278///
279/// These vary dpeending on the chip, ceck the reference manual or datasheet for details.
280#[allow(missing_docs)]
264#[derive(Debug, Copy, Clone)] 281#[derive(Debug, Copy, Clone)]
265#[cfg_attr(feature = "defmt", derive(defmt::Format))] 282#[cfg_attr(feature = "defmt", derive(defmt::Format))]
266pub enum Speed { 283pub enum Speed {
@@ -305,6 +322,7 @@ pub struct Input<'d, T: Pin> {
305} 322}
306 323
307impl<'d, T: Pin> Input<'d, T> { 324impl<'d, T: Pin> Input<'d, T> {
325 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
308 #[inline] 326 #[inline]
309 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { 327 pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self {
310 let mut pin = Flex::new(pin); 328 let mut pin = Flex::new(pin);
@@ -312,6 +330,11 @@ impl<'d, T: Pin> Input<'d, T> {
312 Self { pin } 330 Self { pin }
313 } 331 }
314 332
333 /// Type-erase (degrade) this pin into an `AnyPin`.
334 ///
335 /// This converts pin singletons (`PA5`, `PB6`, ...), which
336 /// are all different types, into the same type. It is useful for
337 /// creating arrays of pins, or avoiding generics.
315 #[inline] 338 #[inline]
316 pub fn degrade(self) -> Input<'d, AnyPin> { 339 pub fn degrade(self) -> Input<'d, AnyPin> {
317 Input { 340 Input {
@@ -319,16 +342,19 @@ impl<'d, T: Pin> Input<'d, T> {
319 } 342 }
320 } 343 }
321 344
345 /// Get whether the pin input level is high.
322 #[inline] 346 #[inline]
323 pub fn is_high(&mut self) -> bool { 347 pub fn is_high(&mut self) -> bool {
324 self.pin.is_high() 348 self.pin.is_high()
325 } 349 }
326 350
351 /// Get whether the pin input level is low.
327 #[inline] 352 #[inline]
328 pub fn is_low(&mut self) -> bool { 353 pub fn is_low(&mut self) -> bool {
329 self.pin.is_low() 354 self.pin.is_low()
330 } 355 }
331 356
357 /// Get the current pin input level.
332 #[inline] 358 #[inline]
333 pub fn get_level(&mut self) -> Level { 359 pub fn get_level(&mut self) -> Level {
334 self.pin.get_level() 360 self.pin.get_level()
@@ -339,7 +365,9 @@ impl<'d, T: Pin> Input<'d, T> {
339#[derive(Debug, Eq, PartialEq, Copy, Clone)] 365#[derive(Debug, Eq, PartialEq, Copy, Clone)]
340#[cfg_attr(feature = "defmt", derive(defmt::Format))] 366#[cfg_attr(feature = "defmt", derive(defmt::Format))]
341pub enum Level { 367pub enum Level {
368 /// Low
342 Low, 369 Low,
370 /// High
343 High, 371 High,
344} 372}
345 373
@@ -371,6 +399,7 @@ pub struct Output<'d, T: Pin> {
371} 399}
372 400
373impl<'d, T: Pin> Output<'d, T> { 401impl<'d, T: Pin> Output<'d, T> {
402 /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
374 #[inline] 403 #[inline]
375 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { 404 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self {
376 let mut pin = Flex::new(pin); 405 let mut pin = Flex::new(pin);
@@ -382,6 +411,11 @@ impl<'d, T: Pin> Output<'d, T> {
382 Self { pin } 411 Self { pin }
383 } 412 }
384 413
414 /// Type-erase (degrade) this pin into an `AnyPin`.
415 ///
416 /// This converts pin singletons (`PA5`, `PB6`, ...), which
417 /// are all different types, into the same type. It is useful for
418 /// creating arrays of pins, or avoiding generics.
385 #[inline] 419 #[inline]
386 pub fn degrade(self) -> Output<'d, AnyPin> { 420 pub fn degrade(self) -> Output<'d, AnyPin> {
387 Output { 421 Output {
@@ -442,6 +476,7 @@ pub struct OutputOpenDrain<'d, T: Pin> {
442} 476}
443 477
444impl<'d, T: Pin> OutputOpenDrain<'d, T> { 478impl<'d, T: Pin> OutputOpenDrain<'d, T> {
479 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration.
445 #[inline] 480 #[inline]
446 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { 481 pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
447 let mut pin = Flex::new(pin); 482 let mut pin = Flex::new(pin);
@@ -455,6 +490,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
455 Self { pin } 490 Self { pin }
456 } 491 }
457 492
493 /// Type-erase (degrade) this pin into an `AnyPin`.
494 ///
495 /// This converts pin singletons (`PA5`, `PB6`, ...), which
496 /// are all different types, into the same type. It is useful for
497 /// creating arrays of pins, or avoiding generics.
458 #[inline] 498 #[inline]
459 pub fn degrade(self) -> Output<'d, AnyPin> { 499 pub fn degrade(self) -> Output<'d, AnyPin> {
460 Output { 500 Output {
@@ -462,17 +502,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
462 } 502 }
463 } 503 }
464 504
505 /// Get whether the pin input level is high.
465 #[inline] 506 #[inline]
466 pub fn is_high(&mut self) -> bool { 507 pub fn is_high(&mut self) -> bool {
467 !self.pin.is_low() 508 !self.pin.is_low()
468 } 509 }
469 510
511 /// Get whether the pin input level is low.
470 #[inline] 512 #[inline]
471 pub fn is_low(&mut self) -> bool { 513 pub fn is_low(&mut self) -> bool {
472 self.pin.is_low() 514 self.pin.is_low()
473 } 515 }
474 516
475 /// Returns current pin level 517 /// Get the current pin input level.
476 #[inline] 518 #[inline]
477 pub fn get_level(&mut self) -> Level { 519 pub fn get_level(&mut self) -> Level {
478 self.pin.get_level() 520 self.pin.get_level()
@@ -496,19 +538,19 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
496 self.pin.set_level(level); 538 self.pin.set_level(level);
497 } 539 }
498 540
499 /// Is the output pin set as high? 541 /// Get whether the output level is set to high.
500 #[inline] 542 #[inline]
501 pub fn is_set_high(&mut self) -> bool { 543 pub fn is_set_high(&mut self) -> bool {
502 self.pin.is_set_high() 544 self.pin.is_set_high()
503 } 545 }
504 546
505 /// Is the output pin set as low? 547 /// Get whether the output level is set to low.
506 #[inline] 548 #[inline]
507 pub fn is_set_low(&mut self) -> bool { 549 pub fn is_set_low(&mut self) -> bool {
508 self.pin.is_set_low() 550 self.pin.is_set_low()
509 } 551 }
510 552
511 /// What level output is set to 553 /// Get the current output level.
512 #[inline] 554 #[inline]
513 pub fn get_output_level(&mut self) -> Level { 555 pub fn get_output_level(&mut self) -> Level {
514 self.pin.get_output_level() 556 self.pin.get_output_level()
@@ -521,8 +563,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
521 } 563 }
522} 564}
523 565
566/// GPIO output type
524pub enum OutputType { 567pub enum OutputType {
568 /// Drive the pin both high or low.
525 PushPull, 569 PushPull,
570 /// Drive the pin low, or don't drive it at all if the output level is high.
526 OpenDrain, 571 OpenDrain,
527} 572}
528 573
@@ -535,6 +580,7 @@ impl From<OutputType> for sealed::AFType {
535 } 580 }
536} 581}
537 582
583#[allow(missing_docs)]
538pub(crate) mod sealed { 584pub(crate) mod sealed {
539 use super::*; 585 use super::*;
540 586
@@ -542,8 +588,11 @@ pub(crate) mod sealed {
542 #[derive(Debug, Copy, Clone)] 588 #[derive(Debug, Copy, Clone)]
543 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 589 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
544 pub enum AFType { 590 pub enum AFType {
591 /// Input
545 Input, 592 Input,
593 /// Output, drive the pin both high or low.
546 OutputPushPull, 594 OutputPushPull,
595 /// Output, drive the pin low, or don't drive it at all if the output level is high.
547 OutputOpenDrain, 596 OutputOpenDrain,
548 } 597 }
549 598
@@ -686,7 +735,11 @@ pub(crate) mod sealed {
686 } 735 }
687} 736}
688 737
738/// GPIO pin trait.
689pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 739pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static {
740 /// EXTI channel assigned to this pin.
741 ///
742 /// For example, PC4 uses EXTI4.
690 #[cfg(feature = "exti")] 743 #[cfg(feature = "exti")]
691 type ExtiChannel: crate::exti::Channel; 744 type ExtiChannel: crate::exti::Channel;
692 745
@@ -702,7 +755,11 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
702 self._port() 755 self._port()
703 } 756 }
704 757
705 /// Convert from concrete pin type PX_XX to type erased `AnyPin`. 758 /// Type-erase (degrade) this pin into an `AnyPin`.
759 ///
760 /// This converts pin singletons (`PA5`, `PB6`, ...), which
761 /// are all different types, into the same type. It is useful for
762 /// creating arrays of pins, or avoiding generics.
706 #[inline] 763 #[inline]
707 fn degrade(self) -> AnyPin { 764 fn degrade(self) -> AnyPin {
708 AnyPin { 765 AnyPin {
@@ -711,12 +768,15 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat
711 } 768 }
712} 769}
713 770
714// Type-erased GPIO pin 771/// Type-erased GPIO pin
715pub struct AnyPin { 772pub struct AnyPin {
716 pin_port: u8, 773 pin_port: u8,
717} 774}
718 775
719impl AnyPin { 776impl AnyPin {
777 /// Unsafely create an `AnyPin` from a pin+port number.
778 ///
779 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
720 #[inline] 780 #[inline]
721 pub unsafe fn steal(pin_port: u8) -> Self { 781 pub unsafe fn steal(pin_port: u8) -> Self {
722 Self { pin_port } 782 Self { pin_port }
@@ -727,6 +787,8 @@ impl AnyPin {
727 self.pin_port / 16 787 self.pin_port / 16
728 } 788 }
729 789
790 /// Get the GPIO register block for this pin.
791 #[cfg(feature = "unstable-pac")]
730 #[inline] 792 #[inline]
731 pub fn block(&self) -> gpio::Gpio { 793 pub fn block(&self) -> gpio::Gpio {
732 pac::GPIO(self._port() as _) 794 pac::GPIO(self._port() as _)
@@ -1072,6 +1134,7 @@ impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> {
1072 } 1134 }
1073} 1135}
1074 1136
1137/// Low-level GPIO manipulation.
1075#[cfg(feature = "unstable-pac")] 1138#[cfg(feature = "unstable-pac")]
1076pub mod low_level { 1139pub mod low_level {
1077 pub use super::sealed::*; 1140 pub use super::sealed::*;
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index d2a50cf7e..a8dc8e0e5 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -13,15 +13,23 @@ use embassy_sync::waitqueue::AtomicWaker;
13 13
14use crate::peripherals; 14use crate::peripherals;
15 15
16/// I2C error.
16#[derive(Debug, PartialEq, Eq)] 17#[derive(Debug, PartialEq, Eq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))] 18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Error { 19pub enum Error {
20 /// Bus error
19 Bus, 21 Bus,
22 /// Arbitration lost
20 Arbitration, 23 Arbitration,
24 /// ACK not received (either to the address or to a data byte)
21 Nack, 25 Nack,
26 /// Timeout
22 Timeout, 27 Timeout,
28 /// CRC error
23 Crc, 29 Crc,
30 /// Overrun error
24 Overrun, 31 Overrun,
32 /// Zero-length transfers are not allowed.
25 ZeroLengthTransfer, 33 ZeroLengthTransfer,
26} 34}
27 35
@@ -47,8 +55,11 @@ pub(crate) mod sealed {
47 } 55 }
48} 56}
49 57
58/// I2C peripheral instance
50pub trait Instance: sealed::Instance + 'static { 59pub trait Instance: sealed::Instance + 'static {
60 /// Event interrupt for this instance
51 type EventInterrupt: interrupt::typelevel::Interrupt; 61 type EventInterrupt: interrupt::typelevel::Interrupt;
62 /// Error interrupt for this instance
52 type ErrorInterrupt: interrupt::typelevel::Interrupt; 63 type ErrorInterrupt: interrupt::typelevel::Interrupt;
53} 64}
54 65
@@ -57,7 +68,7 @@ pin_trait!(SdaPin, Instance);
57dma_trait!(RxDma, Instance); 68dma_trait!(RxDma, Instance);
58dma_trait!(TxDma, Instance); 69dma_trait!(TxDma, Instance);
59 70
60/// Interrupt handler. 71/// Event interrupt handler.
61pub struct EventInterruptHandler<T: Instance> { 72pub struct EventInterruptHandler<T: Instance> {
62 _phantom: PhantomData<T>, 73 _phantom: PhantomData<T>,
63} 74}
@@ -68,6 +79,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInte
68 } 79 }
69} 80}
70 81
82/// Error interrupt handler.
71pub struct ErrorInterruptHandler<T: Instance> { 83pub struct ErrorInterruptHandler<T: Instance> {
72 _phantom: PhantomData<T>, 84 _phantom: PhantomData<T>,
73} 85}
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index 0412d991a..e9e7fd482 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -18,12 +18,17 @@ impl Into<u8> for QspiMode {
18 } 18 }
19} 19}
20 20
21/// QSPI lane width
21#[allow(dead_code)] 22#[allow(dead_code)]
22#[derive(Copy, Clone)] 23#[derive(Copy, Clone)]
23pub enum QspiWidth { 24pub enum QspiWidth {
25 /// None
24 NONE, 26 NONE,
27 /// Single lane
25 SING, 28 SING,
29 /// Dual lanes
26 DUAL, 30 DUAL,
31 /// Quad lanes
27 QUAD, 32 QUAD,
28} 33}
29 34
@@ -38,10 +43,13 @@ impl Into<u8> for QspiWidth {
38 } 43 }
39} 44}
40 45
46/// Flash bank selection
41#[allow(dead_code)] 47#[allow(dead_code)]
42#[derive(Copy, Clone)] 48#[derive(Copy, Clone)]
43pub enum FlashSelection { 49pub enum FlashSelection {
50 /// Bank 1
44 Flash1, 51 Flash1,
52 /// Bank 2
45 Flash2, 53 Flash2,
46} 54}
47 55
@@ -54,6 +62,8 @@ impl Into<bool> for FlashSelection {
54 } 62 }
55} 63}
56 64
65/// QSPI memory size.
66#[allow(missing_docs)]
57#[derive(Copy, Clone)] 67#[derive(Copy, Clone)]
58pub enum MemorySize { 68pub enum MemorySize {
59 _1KiB, 69 _1KiB,
@@ -113,11 +123,16 @@ impl Into<u8> for MemorySize {
113 } 123 }
114} 124}
115 125
126/// QSPI Address size
116#[derive(Copy, Clone)] 127#[derive(Copy, Clone)]
117pub enum AddressSize { 128pub enum AddressSize {
129 /// 8-bit address
118 _8Bit, 130 _8Bit,
131 /// 16-bit address
119 _16Bit, 132 _16Bit,
133 /// 24-bit address
120 _24bit, 134 _24bit,
135 /// 32-bit address
121 _32bit, 136 _32bit,
122} 137}
123 138
@@ -132,8 +147,10 @@ impl Into<u8> for AddressSize {
132 } 147 }
133} 148}
134 149
150/// Time the Chip Select line stays high.
151#[allow(missing_docs)]
135#[derive(Copy, Clone)] 152#[derive(Copy, Clone)]
136pub enum ChipSelectHightTime { 153pub enum ChipSelectHighTime {
137 _1Cycle, 154 _1Cycle,
138 _2Cycle, 155 _2Cycle,
139 _3Cycle, 156 _3Cycle,
@@ -144,21 +161,23 @@ pub enum ChipSelectHightTime {
144 _8Cycle, 161 _8Cycle,
145} 162}
146 163
147impl Into<u8> for ChipSelectHightTime { 164impl Into<u8> for ChipSelectHighTime {
148 fn into(self) -> u8 { 165 fn into(self) -> u8 {
149 match self { 166 match self {
150 ChipSelectHightTime::_1Cycle => 0, 167 ChipSelectHighTime::_1Cycle => 0,
151 ChipSelectHightTime::_2Cycle => 1, 168 ChipSelectHighTime::_2Cycle => 1,
152 ChipSelectHightTime::_3Cycle => 2, 169 ChipSelectHighTime::_3Cycle => 2,
153 ChipSelectHightTime::_4Cycle => 3, 170 ChipSelectHighTime::_4Cycle => 3,
154 ChipSelectHightTime::_5Cycle => 4, 171 ChipSelectHighTime::_5Cycle => 4,
155 ChipSelectHightTime::_6Cycle => 5, 172 ChipSelectHighTime::_6Cycle => 5,
156 ChipSelectHightTime::_7Cycle => 6, 173 ChipSelectHighTime::_7Cycle => 6,
157 ChipSelectHightTime::_8Cycle => 7, 174 ChipSelectHighTime::_8Cycle => 7,
158 } 175 }
159 } 176 }
160} 177}
161 178
179/// FIFO threshold.
180#[allow(missing_docs)]
162#[derive(Copy, Clone)] 181#[derive(Copy, Clone)]
163pub enum FIFOThresholdLevel { 182pub enum FIFOThresholdLevel {
164 _1Bytes, 183 _1Bytes,
@@ -234,6 +253,8 @@ impl Into<u8> for FIFOThresholdLevel {
234 } 253 }
235} 254}
236 255
256/// Dummy cycle count
257#[allow(missing_docs)]
237#[derive(Copy, Clone)] 258#[derive(Copy, Clone)]
238pub enum DummyCycles { 259pub enum DummyCycles {
239 _0, 260 _0,
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 1153455c7..bac91f300 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -54,7 +54,7 @@ pub struct Config {
54 /// Number of bytes to trigger FIFO threshold flag. 54 /// Number of bytes to trigger FIFO threshold flag.
55 pub fifo_threshold: FIFOThresholdLevel, 55 pub fifo_threshold: FIFOThresholdLevel,
56 /// Minimum number of cycles that chip select must be high between issued commands 56 /// Minimum number of cycles that chip select must be high between issued commands
57 pub cs_high_time: ChipSelectHightTime, 57 pub cs_high_time: ChipSelectHighTime,
58} 58}
59 59
60impl Default for Config { 60impl Default for Config {
@@ -64,7 +64,7 @@ impl Default for Config {
64 address_size: AddressSize::_24bit, 64 address_size: AddressSize::_24bit,
65 prescaler: 128, 65 prescaler: 128,
66 fifo_threshold: FIFOThresholdLevel::_17Bytes, 66 fifo_threshold: FIFOThresholdLevel::_17Bytes,
67 cs_high_time: ChipSelectHightTime::_5Cycle, 67 cs_high_time: ChipSelectHighTime::_5Cycle,
68 } 68 }
69 } 69 }
70} 70}
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index a16d38af1..3d7f65996 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -583,10 +583,10 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>(
583 }; 583 };
584 match tx_rx { 584 match tx_rx {
585 TxRx::Transmitter => RingBuffer::Writable(unsafe { 585 TxRx::Transmitter => RingBuffer::Writable(unsafe {
586 WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) 586 WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
587 }), 587 }),
588 TxRx::Receiver => RingBuffer::Readable(unsafe { 588 TxRx::Receiver => RingBuffer::Readable(unsafe {
589 ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) 589 ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts)
590 }), 590 }),
591 } 591 }
592} 592}
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs
index ffce7bd42..b4166e71a 100644
--- a/embassy-stm32/src/traits.rs
+++ b/embassy-stm32/src/traits.rs
@@ -2,7 +2,9 @@
2 2
3macro_rules! pin_trait { 3macro_rules! pin_trait {
4 ($signal:ident, $instance:path) => { 4 ($signal:ident, $instance:path) => {
5 #[doc = concat!(stringify!($signal), " pin trait")]
5 pub trait $signal<T: $instance>: crate::gpio::Pin { 6 pub trait $signal<T: $instance>: 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 };
@@ -22,7 +24,11 @@ macro_rules! pin_trait_impl {
22 24
23macro_rules! dma_trait { 25macro_rules! dma_trait {
24 ($signal:ident, $instance:path) => { 26 ($signal:ident, $instance:path) => {
27 #[doc = concat!(stringify!($signal), " DMA request trait")]
25 pub trait $signal<T: $instance>: crate::dma::Channel { 28 pub trait $signal<T: $instance>: 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 };
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index b8d17e4e4..f8ada3926 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -39,7 +39,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
39 let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; 39 let rx_dma = unsafe { self.rx_dma.clone_unchecked() };
40 let _peri = unsafe { self._peri.clone_unchecked() }; 40 let _peri = unsafe { self._peri.clone_unchecked() };
41 41
42 let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; 42 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
43 43
44 // Don't disable the clock 44 // Don't disable the clock
45 mem::forget(self); 45 mem::forget(self);
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index 93c54e943..56a35ddee 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -31,7 +31,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
31 31
32 info!("Reading..."); 32 info!("Reading...");
33 let mut buf = [0u8; 32]; 33 let mut buf = [0u8; 32];
34 unwrap!(f.read(offset, &mut buf)); 34 unwrap!(f.blocking_read(offset, &mut buf));
35 info!("Read: {=[u8]:x}", buf); 35 info!("Read: {=[u8]:x}", buf);
36 36
37 info!("Erasing..."); 37 info!("Erasing...");
@@ -39,7 +39,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
39 39
40 info!("Reading..."); 40 info!("Reading...");
41 let mut buf = [0u8; 32]; 41 let mut buf = [0u8; 32];
42 unwrap!(f.read(offset, &mut buf)); 42 unwrap!(f.blocking_read(offset, &mut buf));
43 info!("Read after erase: {=[u8]:x}", buf); 43 info!("Read after erase: {=[u8]:x}", buf);
44 44
45 info!("Writing..."); 45 info!("Writing...");
@@ -53,7 +53,7 @@ fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
53 53
54 info!("Reading..."); 54 info!("Reading...");
55 let mut buf = [0u8; 32]; 55 let mut buf = [0u8; 32];
56 unwrap!(f.read(offset, &mut buf)); 56 unwrap!(f.blocking_read(offset, &mut buf));
57 info!("Read: {=[u8]:x}", buf); 57 info!("Read: {=[u8]:x}", buf);
58 assert_eq!( 58 assert_eq!(
59 &buf[..], 59 &buf[..],
diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
index f0a65a725..1624d842e 100644
--- a/examples/stm32f4/src/bin/flash_async.rs
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -48,7 +48,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
48 48
49 info!("Reading..."); 49 info!("Reading...");
50 let mut buf = [0u8; 32]; 50 let mut buf = [0u8; 32];
51 unwrap!(f.read(offset, &mut buf)); 51 unwrap!(f.blocking_read(offset, &mut buf));
52 info!("Read: {=[u8]:x}", buf); 52 info!("Read: {=[u8]:x}", buf);
53 53
54 info!("Erasing..."); 54 info!("Erasing...");
@@ -56,7 +56,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
56 56
57 info!("Reading..."); 57 info!("Reading...");
58 let mut buf = [0u8; 32]; 58 let mut buf = [0u8; 32];
59 unwrap!(f.read(offset, &mut buf)); 59 unwrap!(f.blocking_read(offset, &mut buf));
60 info!("Read after erase: {=[u8]:x}", buf); 60 info!("Read after erase: {=[u8]:x}", buf);
61 61
62 info!("Writing..."); 62 info!("Writing...");
@@ -73,7 +73,7 @@ async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
73 73
74 info!("Reading..."); 74 info!("Reading...");
75 let mut buf = [0u8; 32]; 75 let mut buf = [0u8; 32];
76 unwrap!(f.read(offset, &mut buf)); 76 unwrap!(f.blocking_read(offset, &mut buf));
77 info!("Read: {=[u8]:x}", buf); 77 info!("Read: {=[u8]:x}", buf);
78 assert_eq!( 78 assert_eq!(
79 &buf[..], 79 &buf[..],