diff options
| author | sodo <[email protected]> | 2024-01-02 01:37:00 +0900 |
|---|---|---|
| committer | sodo <[email protected]> | 2024-01-02 13:34:22 +0900 |
| commit | 6ee153a3e2eec284c0d9d87f31801265c0604f74 (patch) | |
| tree | 8b801cbd15f9ad5052d5942c731e75736dc9d7eb /embassy-stm32/src | |
| parent | b7cd7952c890f585ff876c622482534e5d58d4a4 (diff) | |
| parent | 0be9b0599aaf2e425d76ec7852ff4b3535defddf (diff) | |
Merge remote-tracking branch 'origin'
Diffstat (limited to 'embassy-stm32/src')
74 files changed, 2032 insertions, 1351 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index dbe53c807..e4dd35c34 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -1,4 +1,7 @@ | |||
| 1 | //! Analog to Digital Converter (ADC) | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 4 | #![allow(missing_docs)] // TODO | ||
| 2 | 5 | ||
| 3 | #[cfg(not(adc_f3_v2))] | 6 | #[cfg(not(adc_f3_v2))] |
| 4 | #[cfg_attr(adc_f1, path = "f1.rs")] | 7 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| @@ -24,6 +27,7 @@ pub use sample_time::SampleTime; | |||
| 24 | 27 | ||
| 25 | use crate::peripherals; | 28 | use crate::peripherals; |
| 26 | 29 | ||
| 30 | /// Analog to Digital driver. | ||
| 27 | pub struct Adc<'d, T: Instance> { | 31 | pub struct Adc<'d, T: Instance> { |
| 28 | #[allow(unused)] | 32 | #[allow(unused)] |
| 29 | adc: crate::PeripheralRef<'d, T>, | 33 | adc: crate::PeripheralRef<'d, T>, |
| @@ -75,12 +79,16 @@ pub(crate) mod sealed { | |||
| 75 | } | 79 | } |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 82 | /// ADC instance. | ||
| 78 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] | 83 | #[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0)))] |
| 79 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} | 84 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {} |
| 85 | /// ADC instance. | ||
| 80 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] | 86 | #[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0))] |
| 81 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} | 87 | pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {} |
| 82 | 88 | ||
| 89 | /// ADC pin. | ||
| 83 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} | 90 | pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} |
| 91 | /// ADC internal channel. | ||
| 84 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} | 92 | pub trait InternalChannel<T>: sealed::InternalChannel<T> {} |
| 85 | 93 | ||
| 86 | foreach_adc!( | 94 | foreach_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 | ||
| 51 | impl Resolution { | 55 | impl 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; | |||
| 32 | const VBAT_CHANNEL: u8 = 17; | 32 | const 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. | ||
| 35 | pub struct VrefInt; | 36 | pub struct VrefInt; |
| 36 | impl<T: Instance> InternalChannel<T> for VrefInt {} | 37 | impl<T: Instance> InternalChannel<T> for VrefInt {} |
| 37 | impl<T: Instance> super::sealed::InternalChannel<T> for VrefInt { | 38 | impl<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. | ||
| 43 | pub struct Temperature; | 45 | pub struct Temperature; |
| 44 | impl<T: Instance> InternalChannel<T> for Temperature {} | 46 | impl<T: Instance> InternalChannel<T> for Temperature {} |
| 45 | impl<T: Instance> super::sealed::InternalChannel<T> for Temperature { | 47 | impl<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. | ||
| 51 | pub struct Vbat; | 54 | pub struct Vbat; |
| 52 | impl<T: Instance> InternalChannel<T> for Vbat {} | 55 | impl<T: Instance> InternalChannel<T> for Vbat {} |
| 53 | impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { | 56 | impl<T: Instance> super::sealed::InternalChannel<T> for Vbat { |
| @@ -125,6 +128,7 @@ impl Prescaler { | |||
| 125 | } | 128 | } |
| 126 | 129 | ||
| 127 | impl<'d, T: Instance> Adc<'d, T> { | 130 | impl<'d, T: Instance> Adc<'d, T> { |
| 131 | /// Create a new ADC driver. | ||
| 128 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { | 132 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { |
| 129 | embassy_hal_internal::into_ref!(adc); | 133 | embassy_hal_internal::into_ref!(adc); |
| 130 | T::enable_and_reset(); | 134 | T::enable_and_reset(); |
| @@ -212,6 +216,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 212 | }); | 216 | }); |
| 213 | } | 217 | } |
| 214 | 218 | ||
| 219 | /// Enable reading the voltage reference internal channel. | ||
| 215 | pub fn enable_vrefint(&self) -> VrefInt { | 220 | pub fn enable_vrefint(&self) -> VrefInt { |
| 216 | T::common_regs().ccr().modify(|reg| { | 221 | T::common_regs().ccr().modify(|reg| { |
| 217 | reg.set_vrefen(true); | 222 | reg.set_vrefen(true); |
| @@ -220,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 220 | VrefInt {} | 225 | VrefInt {} |
| 221 | } | 226 | } |
| 222 | 227 | ||
| 228 | /// Enable reading the temperature internal channel. | ||
| 223 | pub fn enable_temperature(&self) -> Temperature { | 229 | pub fn enable_temperature(&self) -> Temperature { |
| 224 | T::common_regs().ccr().modify(|reg| { | 230 | T::common_regs().ccr().modify(|reg| { |
| 225 | reg.set_vsenseen(true); | 231 | reg.set_vsenseen(true); |
| @@ -228,6 +234,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 228 | Temperature {} | 234 | Temperature {} |
| 229 | } | 235 | } |
| 230 | 236 | ||
| 237 | /// Enable reading the vbat internal channel. | ||
| 231 | pub fn enable_vbat(&self) -> Vbat { | 238 | pub fn enable_vbat(&self) -> Vbat { |
| 232 | T::common_regs().ccr().modify(|reg| { | 239 | T::common_regs().ccr().modify(|reg| { |
| 233 | reg.set_vbaten(true); | 240 | reg.set_vbaten(true); |
| @@ -236,10 +243,12 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 236 | Vbat {} | 243 | Vbat {} |
| 237 | } | 244 | } |
| 238 | 245 | ||
| 246 | /// Set the ADC sample time. | ||
| 239 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | 247 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
| 240 | self.sample_time = sample_time; | 248 | self.sample_time = sample_time; |
| 241 | } | 249 | } |
| 242 | 250 | ||
| 251 | /// Set the ADC resolution. | ||
| 243 | pub fn set_resolution(&mut self, resolution: Resolution) { | 252 | pub fn set_resolution(&mut self, resolution: Resolution) { |
| 244 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); | 253 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
| 245 | } | 254 | } |
| @@ -263,6 +272,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 263 | T::regs().dr().read().0 as u16 | 272 | T::regs().dr().read().0 as u16 |
| 264 | } | 273 | } |
| 265 | 274 | ||
| 275 | /// Read an ADC pin. | ||
| 266 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 276 | pub fn read<P>(&mut self, pin: &mut P) -> u16 |
| 267 | where | 277 | where |
| 268 | P: AdcPin<T>, | 278 | P: AdcPin<T>, |
| @@ -273,6 +283,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 273 | self.read_channel(pin.channel()) | 283 | self.read_channel(pin.channel()) |
| 274 | } | 284 | } |
| 275 | 285 | ||
| 286 | /// Read an ADC internal channel. | ||
| 276 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | 287 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { |
| 277 | self.read_channel(channel.channel()) | 288 | self.read_channel(channel.channel()) |
| 278 | } | 289 | } |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 2f7417340..cc87b2565 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | use core::convert::AsMut; | ||
| 1 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 3 | use core::ops::{Deref, DerefMut}; | 4 | use core::ops::{Deref, DerefMut}; |
| @@ -10,7 +11,7 @@ use futures::FutureExt; | |||
| 10 | 11 | ||
| 11 | use crate::gpio::sealed::AFType; | 12 | use crate::gpio::sealed::AFType; |
| 12 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::pac::can::vals::{Lec, RirIde}; | 14 | use crate::pac::can::vals::{Ide, Lec}; |
| 14 | use crate::rcc::RccPeripheral; | 15 | use crate::rcc::RccPeripheral; |
| 15 | use crate::time::Hertz; | 16 | use crate::time::Hertz; |
| 16 | use crate::{interrupt, peripherals, Peripheral}; | 17 | use crate::{interrupt, peripherals, Peripheral}; |
| @@ -21,8 +22,10 @@ use crate::{interrupt, peripherals, Peripheral}; | |||
| 21 | #[derive(Debug, Clone, PartialEq, Eq)] | 22 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 22 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 23 | pub struct Envelope { | 24 | pub struct Envelope { |
| 25 | /// Reception time. | ||
| 24 | #[cfg(feature = "time")] | 26 | #[cfg(feature = "time")] |
| 25 | pub ts: embassy_time::Instant, | 27 | pub ts: embassy_time::Instant, |
| 28 | /// The actual CAN frame. | ||
| 26 | pub frame: bxcan::Frame, | 29 | pub frame: bxcan::Frame, |
| 27 | } | 30 | } |
| 28 | 31 | ||
| @@ -43,6 +46,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH | |||
| 43 | } | 46 | } |
| 44 | } | 47 | } |
| 45 | 48 | ||
| 49 | /// RX0 interrupt handler. | ||
| 46 | pub struct Rx0InterruptHandler<T: Instance> { | 50 | pub struct Rx0InterruptHandler<T: Instance> { |
| 47 | _phantom: PhantomData<T>, | 51 | _phantom: PhantomData<T>, |
| 48 | } | 52 | } |
| @@ -54,6 +58,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0Interrup | |||
| 54 | } | 58 | } |
| 55 | } | 59 | } |
| 56 | 60 | ||
| 61 | /// RX1 interrupt handler. | ||
| 57 | pub struct Rx1InterruptHandler<T: Instance> { | 62 | pub struct Rx1InterruptHandler<T: Instance> { |
| 58 | _phantom: PhantomData<T>, | 63 | _phantom: PhantomData<T>, |
| 59 | } | 64 | } |
| @@ -65,6 +70,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1Interrup | |||
| 65 | } | 70 | } |
| 66 | } | 71 | } |
| 67 | 72 | ||
| 73 | /// SCE interrupt handler. | ||
| 68 | pub struct SceInterruptHandler<T: Instance> { | 74 | pub struct SceInterruptHandler<T: Instance> { |
| 69 | _phantom: PhantomData<T>, | 75 | _phantom: PhantomData<T>, |
| 70 | } | 76 | } |
| @@ -82,10 +88,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup | |||
| 82 | } | 88 | } |
| 83 | } | 89 | } |
| 84 | 90 | ||
| 91 | /// CAN driver | ||
| 85 | pub struct Can<'d, T: Instance> { | 92 | pub struct Can<'d, T: Instance> { |
| 86 | pub can: bxcan::Can<BxcanInstance<'d, T>>, | 93 | can: bxcan::Can<BxcanInstance<'d, T>>, |
| 87 | } | 94 | } |
| 88 | 95 | ||
| 96 | /// CAN bus error | ||
| 97 | #[allow(missing_docs)] | ||
| 89 | #[derive(Debug)] | 98 | #[derive(Debug)] |
| 90 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 99 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 91 | pub enum BusError { | 100 | pub enum BusError { |
| @@ -101,6 +110,7 @@ pub enum BusError { | |||
| 101 | BusWarning, | 110 | BusWarning, |
| 102 | } | 111 | } |
| 103 | 112 | ||
| 113 | /// Error returned by `try_read` | ||
| 104 | #[derive(Debug)] | 114 | #[derive(Debug)] |
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 115 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 106 | pub enum TryReadError { | 116 | pub enum TryReadError { |
| @@ -110,6 +120,7 @@ pub enum TryReadError { | |||
| 110 | Empty, | 120 | Empty, |
| 111 | } | 121 | } |
| 112 | 122 | ||
| 123 | /// Error returned by `try_write` | ||
| 113 | #[derive(Debug)] | 124 | #[derive(Debug)] |
| 114 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 125 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 115 | pub enum TryWriteError { | 126 | pub enum TryWriteError { |
| @@ -138,15 +149,11 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 138 | T::enable_and_reset(); | 149 | T::enable_and_reset(); |
| 139 | 150 | ||
| 140 | { | 151 | { |
| 141 | use crate::pac::can::vals::{Errie, Fmpie, Tmeie}; | ||
| 142 | |||
| 143 | T::regs().ier().write(|w| { | 152 | T::regs().ier().write(|w| { |
| 144 | // TODO: fix metapac | 153 | w.set_errie(true); |
| 145 | 154 | w.set_fmpie(0, true); | |
| 146 | w.set_errie(Errie::from_bits(1)); | 155 | w.set_fmpie(1, true); |
| 147 | w.set_fmpie(0, Fmpie::from_bits(1)); | 156 | w.set_tmeie(true); |
| 148 | w.set_fmpie(1, Fmpie::from_bits(1)); | ||
| 149 | w.set_tmeie(Tmeie::from_bits(1)); | ||
| 150 | }); | 157 | }); |
| 151 | 158 | ||
| 152 | T::regs().mcr().write(|w| { | 159 | T::regs().mcr().write(|w| { |
| @@ -177,6 +184,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 177 | Self { can } | 184 | Self { can } |
| 178 | } | 185 | } |
| 179 | 186 | ||
| 187 | /// Set CAN bit rate. | ||
| 180 | pub fn set_bitrate(&mut self, bitrate: u32) { | 188 | pub fn set_bitrate(&mut self, bitrate: u32) { |
| 181 | let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); | 189 | let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); |
| 182 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | 190 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); |
| @@ -194,7 +202,9 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 194 | } | 202 | } |
| 195 | } | 203 | } |
| 196 | 204 | ||
| 197 | /// Queues the message to be sent but exerts backpressure | 205 | /// Queues the message to be sent. |
| 206 | /// | ||
| 207 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 198 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | 208 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 199 | self.split().0.write(frame).await | 209 | self.split().0.write(frame).await |
| 200 | } | 210 | } |
| @@ -221,12 +231,16 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 221 | CanTx::<T>::flush_all_inner().await | 231 | CanTx::<T>::flush_all_inner().await |
| 222 | } | 232 | } |
| 223 | 233 | ||
| 234 | /// Read a CAN frame. | ||
| 235 | /// | ||
| 236 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 237 | /// | ||
| 224 | /// Returns a tuple of the time the message was received and the message frame | 238 | /// Returns a tuple of the time the message was received and the message frame |
| 225 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 239 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 226 | self.split().1.read().await | 240 | self.split().1.read().await |
| 227 | } | 241 | } |
| 228 | 242 | ||
| 229 | /// Attempts to read a can frame without blocking. | 243 | /// Attempts to read a CAN frame without blocking. |
| 230 | /// | 244 | /// |
| 231 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 245 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 232 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 246 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| @@ -259,7 +273,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 259 | } | 273 | } |
| 260 | 274 | ||
| 261 | let rir = fifo.rir().read(); | 275 | let rir = fifo.rir().read(); |
| 262 | let id = if rir.ide() == RirIde::STANDARD { | 276 | let id = if rir.ide() == Ide::STANDARD { |
| 263 | Id::from(StandardId::new_unchecked(rir.stid())) | 277 | Id::from(StandardId::new_unchecked(rir.stid())) |
| 264 | } else { | 278 | } else { |
| 265 | let stid = (rir.stid() & 0x7FF) as u32; | 279 | let stid = (rir.stid() & 0x7FF) as u32; |
| @@ -288,7 +302,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 288 | } | 302 | } |
| 289 | } | 303 | } |
| 290 | 304 | ||
| 291 | pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { | 305 | const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { |
| 292 | const BS1_MAX: u8 = 16; | 306 | const BS1_MAX: u8 = 16; |
| 293 | const BS2_MAX: u8 = 8; | 307 | const BS2_MAX: u8 = 8; |
| 294 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | 308 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; |
| @@ -379,21 +393,31 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 379 | Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) | 393 | Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) |
| 380 | } | 394 | } |
| 381 | 395 | ||
| 396 | /// Split the CAN driver into transmit and receive halves. | ||
| 397 | /// | ||
| 398 | /// Useful for doing separate transmit/receive tasks. | ||
| 382 | pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { | 399 | pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { |
| 383 | let (tx, rx0, rx1) = self.can.split_by_ref(); | 400 | let (tx, rx0, rx1) = self.can.split_by_ref(); |
| 384 | (CanTx { tx }, CanRx { rx0, rx1 }) | 401 | (CanTx { tx }, CanRx { rx0, rx1 }) |
| 385 | } | 402 | } |
| 403 | } | ||
| 386 | 404 | ||
| 387 | pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { | 405 | impl<'d, T: Instance> AsMut<bxcan::Can<BxcanInstance<'d, T>>> for Can<'d, T> { |
| 406 | /// Get mutable access to the lower-level driver from the `bxcan` crate. | ||
| 407 | fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { | ||
| 388 | &mut self.can | 408 | &mut self.can |
| 389 | } | 409 | } |
| 390 | } | 410 | } |
| 391 | 411 | ||
| 412 | /// CAN driver, transmit half. | ||
| 392 | pub struct CanTx<'c, 'd, T: Instance> { | 413 | pub struct CanTx<'c, 'd, T: Instance> { |
| 393 | tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, | 414 | tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, |
| 394 | } | 415 | } |
| 395 | 416 | ||
| 396 | impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | 417 | impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { |
| 418 | /// Queues the message to be sent. | ||
| 419 | /// | ||
| 420 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 397 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | 421 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 398 | poll_fn(|cx| { | 422 | poll_fn(|cx| { |
| 399 | T::state().tx_waker.register(cx.waker()); | 423 | T::state().tx_waker.register(cx.waker()); |
| @@ -475,6 +499,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | |||
| 475 | } | 499 | } |
| 476 | } | 500 | } |
| 477 | 501 | ||
| 502 | /// CAN driver, receive half. | ||
| 478 | #[allow(dead_code)] | 503 | #[allow(dead_code)] |
| 479 | pub struct CanRx<'c, 'd, T: Instance> { | 504 | pub struct CanRx<'c, 'd, T: Instance> { |
| 480 | rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, | 505 | rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, |
| @@ -482,6 +507,11 @@ pub struct CanRx<'c, 'd, T: Instance> { | |||
| 482 | } | 507 | } |
| 483 | 508 | ||
| 484 | impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | 509 | impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { |
| 510 | /// Read a CAN frame. | ||
| 511 | /// | ||
| 512 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 513 | /// | ||
| 514 | /// Returns a tuple of the time the message was received and the message frame | ||
| 485 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 515 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 486 | poll_fn(|cx| { | 516 | poll_fn(|cx| { |
| 487 | T::state().err_waker.register(cx.waker()); | 517 | T::state().err_waker.register(cx.waker()); |
| @@ -585,30 +615,24 @@ pub(crate) mod sealed { | |||
| 585 | pub trait Instance { | 615 | pub trait Instance { |
| 586 | const REGISTERS: *mut bxcan::RegisterBlock; | 616 | const REGISTERS: *mut bxcan::RegisterBlock; |
| 587 | 617 | ||
| 588 | fn regs() -> &'static crate::pac::can::Can; | 618 | fn regs() -> crate::pac::can::Can; |
| 589 | fn state() -> &'static State; | 619 | fn state() -> &'static State; |
| 590 | } | 620 | } |
| 591 | } | 621 | } |
| 592 | 622 | ||
| 593 | pub trait TXInstance { | 623 | /// CAN instance trait. |
| 624 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | ||
| 625 | /// TX interrupt for this instance. | ||
| 594 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | 626 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; |
| 595 | } | 627 | /// RX0 interrupt for this instance. |
| 596 | |||
| 597 | pub trait RX0Instance { | ||
| 598 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; | 628 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; |
| 599 | } | 629 | /// RX1 interrupt for this instance. |
| 600 | |||
| 601 | pub trait RX1Instance { | ||
| 602 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; | 630 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; |
| 603 | } | 631 | /// SCE interrupt for this instance. |
| 604 | |||
| 605 | pub trait SCEInstance { | ||
| 606 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | 632 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; |
| 607 | } | 633 | } |
| 608 | 634 | ||
| 609 | pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {} | 635 | /// BXCAN instance newtype. |
| 610 | pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {} | ||
| 611 | |||
| 612 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | 636 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); |
| 613 | 637 | ||
| 614 | unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { | 638 | unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { |
| @@ -620,8 +644,8 @@ foreach_peripheral!( | |||
| 620 | impl sealed::Instance for peripherals::$inst { | 644 | impl sealed::Instance for peripherals::$inst { |
| 621 | const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; | 645 | const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; |
| 622 | 646 | ||
| 623 | fn regs() -> &'static crate::pac::can::Can { | 647 | fn regs() -> crate::pac::can::Can { |
| 624 | &crate::pac::$inst | 648 | crate::pac::$inst |
| 625 | } | 649 | } |
| 626 | 650 | ||
| 627 | fn state() -> &'static sealed::State { | 651 | fn state() -> &'static sealed::State { |
| @@ -630,32 +654,12 @@ foreach_peripheral!( | |||
| 630 | } | 654 | } |
| 631 | } | 655 | } |
| 632 | 656 | ||
| 633 | impl Instance for peripherals::$inst {} | 657 | impl Instance for peripherals::$inst { |
| 634 | 658 | type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX; | |
| 635 | foreach_interrupt!( | 659 | type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0; |
| 636 | ($inst,can,CAN,TX,$irq:ident) => { | 660 | type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1; |
| 637 | impl TXInstance for peripherals::$inst { | 661 | type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE; |
| 638 | type TXInterrupt = crate::interrupt::typelevel::$irq; | 662 | } |
| 639 | } | ||
| 640 | }; | ||
| 641 | ($inst,can,CAN,RX0,$irq:ident) => { | ||
| 642 | impl RX0Instance for peripherals::$inst { | ||
| 643 | type RX0Interrupt = crate::interrupt::typelevel::$irq; | ||
| 644 | } | ||
| 645 | }; | ||
| 646 | ($inst,can,CAN,RX1,$irq:ident) => { | ||
| 647 | impl RX1Instance for peripherals::$inst { | ||
| 648 | type RX1Interrupt = crate::interrupt::typelevel::$irq; | ||
| 649 | } | ||
| 650 | }; | ||
| 651 | ($inst,can,CAN,SCE,$irq:ident) => { | ||
| 652 | impl SCEInstance for peripherals::$inst { | ||
| 653 | type SCEInterrupt = crate::interrupt::typelevel::$irq; | ||
| 654 | } | ||
| 655 | }; | ||
| 656 | ); | ||
| 657 | |||
| 658 | impl InterruptableInstance for peripherals::$inst {} | ||
| 659 | }; | 663 | }; |
| 660 | ); | 664 | ); |
| 661 | 665 | ||
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index f77788db3..0cc2559cf 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | pub use bxcan; | ||
| 2 | use embassy_hal_internal::PeripheralRef; | ||
| 3 | |||
| 4 | use crate::peripherals; | 1 | use crate::peripherals; |
| 5 | 2 | ||
| 6 | pub(crate) mod sealed { | 3 | pub(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. | ||
| 35 | pub trait InterruptableInstance {} | 31 | pub trait InterruptableInstance {} |
| 32 | /// FDCAN instance. | ||
| 36 | pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} | 33 | pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} |
| 37 | 34 | ||
| 38 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | ||
| 39 | |||
| 40 | unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { | ||
| 41 | const REGISTERS: *mut bxcan::RegisterBlock = T::REGISTERS; | ||
| 42 | } | ||
| 43 | |||
| 44 | foreach_peripheral!( | 35 | foreach_peripheral!( |
| 45 | (can, $inst:ident) => { | 36 | (can, $inst:ident) => { |
| 46 | impl sealed::Instance for peripherals::$inst { | 37 | impl sealed::Instance for peripherals::$inst { |
| 47 | const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; | ||
| 48 | |||
| 49 | fn regs() -> &'static crate::pac::can::Fdcan { | 38 | fn regs() -> &'static crate::pac::can::Fdcan { |
| 50 | &crate::pac::$inst | 39 | &crate::pac::$inst |
| 51 | } | 40 | } |
diff --git a/embassy-stm32/src/can/mod.rs b/embassy-stm32/src/can/mod.rs index 425f9ac2e..915edb3a6 100644 --- a/embassy-stm32/src/can/mod.rs +++ b/embassy-stm32/src/can/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Controller Area Network (CAN) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | #[cfg_attr(can_bxcan, path = "bxcan.rs")] | 4 | #[cfg_attr(can_bxcan, path = "bxcan.rs")] |
diff --git a/embassy-stm32/src/crc/mod.rs b/embassy-stm32/src/crc/mod.rs index 63f7ad9ba..29523b92d 100644 --- a/embassy-stm32/src/crc/mod.rs +++ b/embassy-stm32/src/crc/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Cyclic Redundancy Check (CRC) | ||
| 1 | #[cfg_attr(crc_v1, path = "v1.rs")] | 2 | #[cfg_attr(crc_v1, path = "v1.rs")] |
| 2 | #[cfg_attr(crc_v2, path = "v2v3.rs")] | 3 | #[cfg_attr(crc_v2, path = "v2v3.rs")] |
| 3 | #[cfg_attr(crc_v3, path = "v2v3.rs")] | 4 | #[cfg_attr(crc_v3, path = "v2v3.rs")] |
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index c0f580830..0166ab819 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs | |||
| @@ -5,6 +5,7 @@ use crate::peripherals::CRC; | |||
| 5 | use crate::rcc::sealed::RccPeripheral; | 5 | use crate::rcc::sealed::RccPeripheral; |
| 6 | use crate::Peripheral; | 6 | use crate::Peripheral; |
| 7 | 7 | ||
| 8 | /// CRC driver. | ||
| 8 | pub struct Crc<'d> { | 9 | pub struct Crc<'d> { |
| 9 | _peri: PeripheralRef<'d, CRC>, | 10 | _peri: PeripheralRef<'d, CRC>, |
| 10 | } | 11 | } |
| @@ -34,6 +35,7 @@ impl<'d> Crc<'d> { | |||
| 34 | PAC_CRC.dr().write_value(word); | 35 | PAC_CRC.dr().write_value(word); |
| 35 | self.read() | 36 | self.read() |
| 36 | } | 37 | } |
| 38 | |||
| 37 | /// Feed a slice of words to the peripheral and return the result. | 39 | /// Feed a slice of words to the peripheral and return the result. |
| 38 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { | 40 | pub fn feed_words(&mut self, words: &[u32]) -> u32 { |
| 39 | for word in words { | 41 | for word in words { |
| @@ -42,6 +44,8 @@ impl<'d> Crc<'d> { | |||
| 42 | 44 | ||
| 43 | self.read() | 45 | self.read() |
| 44 | } | 46 | } |
| 47 | |||
| 48 | /// Read the CRC result value. | ||
| 45 | pub fn read(&self) -> u32 { | 49 | pub fn read(&self) -> u32 { |
| 46 | PAC_CRC.dr().read() | 50 | PAC_CRC.dr().read() |
| 47 | } | 51 | } |
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index b36f6018c..0c4ae55ce 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs | |||
| @@ -6,15 +6,19 @@ use crate::peripherals::CRC; | |||
| 6 | use crate::rcc::sealed::RccPeripheral; | 6 | use crate::rcc::sealed::RccPeripheral; |
| 7 | use crate::Peripheral; | 7 | use crate::Peripheral; |
| 8 | 8 | ||
| 9 | /// CRC driver. | ||
| 9 | pub struct Crc<'d> { | 10 | pub 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 | ||
| 14 | pub enum ConfigError { | 16 | pub enum ConfigError { |
| 17 | /// The selected polynomial is invalid. | ||
| 15 | InvalidPolynomial, | 18 | InvalidPolynomial, |
| 16 | } | 19 | } |
| 17 | 20 | ||
| 21 | /// CRC configuration | ||
| 18 | pub struct Config { | 22 | pub 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. | ||
| 28 | pub enum InputReverseConfig { | 33 | pub 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 | ||
| 35 | impl Config { | 44 | impl 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)] | ||
| 61 | pub enum PolySize { | 73 | pub enum PolySize { |
| 62 | Width7, | 74 | Width7, |
| 63 | Width8, | 75 | Width8, |
| @@ -81,6 +93,7 @@ impl<'d> Crc<'d> { | |||
| 81 | instance | 93 | instance |
| 82 | } | 94 | } |
| 83 | 95 | ||
| 96 | /// Reset the CRC engine. | ||
| 84 | pub fn reset(&mut self) { | 97 | pub fn reset(&mut self) { |
| 85 | PAC_CRC.cr().modify(|w| w.set_reset(true)); | 98 | PAC_CRC.cr().modify(|w| w.set_reset(true)); |
| 86 | } | 99 | } |
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 500eac4c1..31dedf06e 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! Provide access to the STM32 digital-to-analog converter (DAC). | 1 | //! Digital to Analog Converter (DAC) |
| 2 | #![macro_use] | 2 | #![macro_use] |
| 3 | 3 | ||
| 4 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| @@ -62,11 +62,11 @@ impl Mode { | |||
| 62 | /// | 62 | /// |
| 63 | /// 12-bit values outside the permitted range are silently truncated. | 63 | /// 12-bit values outside the permitted range are silently truncated. |
| 64 | pub enum Value { | 64 | pub 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. |
| 78 | pub enum DualValue { | 78 | pub 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`]. |
| 90 | pub enum ValueArray<'a> { | 90 | pub 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. | ||
| 109 | pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; | 110 | pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; |
| 111 | /// DAC channel 2 type alias. | ||
| 110 | pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; | 112 | pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; |
| 111 | 113 | ||
| 112 | impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { | 114 | impl<'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. | ||
| 495 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | 498 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} |
| 496 | dma_trait!(DacDma1, Instance); | 499 | dma_trait!(DacDma1, Instance); |
| 497 | dma_trait!(DacDma2, Instance); | 500 | dma_trait!(DacDma2, Instance); |
diff --git a/embassy-stm32/src/dac/tsel.rs b/embassy-stm32/src/dac/tsel.rs index f38dd8fd7..22d8d3dfa 100644 --- a/embassy-stm32/src/dac/tsel.rs +++ b/embassy-stm32/src/dac/tsel.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #![allow(missing_docs)] | ||
| 2 | |||
| 1 | /// Trigger selection for STM32F0. | 3 | /// Trigger selection for STM32F0. |
| 2 | #[cfg(stm32f0)] | 4 | #[cfg(stm32f0)] |
| 3 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 5 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index b12230794..4d02284b2 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Digital Camera Interface (DCMI) | ||
| 1 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 3 | use core::task::Poll; | 4 | use core::task::Poll; |
| @@ -36,6 +37,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | /// The level on the VSync pin when the data is not valid on the parallel interface. | 39 | /// The level on the VSync pin when the data is not valid on the parallel interface. |
| 40 | #[allow(missing_docs)] | ||
| 39 | #[derive(Clone, Copy, PartialEq)] | 41 | #[derive(Clone, Copy, PartialEq)] |
| 40 | pub enum VSyncDataInvalidLevel { | 42 | pub enum VSyncDataInvalidLevel { |
| 41 | Low, | 43 | Low, |
| @@ -43,6 +45,7 @@ pub enum VSyncDataInvalidLevel { | |||
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | /// The level on the VSync pin when the data is not valid on the parallel interface. | 47 | /// The level on the VSync pin when the data is not valid on the parallel interface. |
| 48 | #[allow(missing_docs)] | ||
| 46 | #[derive(Clone, Copy, PartialEq)] | 49 | #[derive(Clone, Copy, PartialEq)] |
| 47 | pub enum HSyncDataInvalidLevel { | 50 | pub enum HSyncDataInvalidLevel { |
| 48 | Low, | 51 | Low, |
| @@ -50,14 +53,16 @@ pub enum HSyncDataInvalidLevel { | |||
| 50 | } | 53 | } |
| 51 | 54 | ||
| 52 | #[derive(Clone, Copy, PartialEq)] | 55 | #[derive(Clone, Copy, PartialEq)] |
| 56 | #[allow(missing_docs)] | ||
| 53 | pub enum PixelClockPolarity { | 57 | pub enum PixelClockPolarity { |
| 54 | RisingEdge, | 58 | RisingEdge, |
| 55 | FallingEdge, | 59 | FallingEdge, |
| 56 | } | 60 | } |
| 57 | 61 | ||
| 58 | pub struct State { | 62 | struct State { |
| 59 | waker: AtomicWaker, | 63 | waker: AtomicWaker, |
| 60 | } | 64 | } |
| 65 | |||
| 61 | impl State { | 66 | impl State { |
| 62 | const fn new() -> State { | 67 | const fn new() -> State { |
| 63 | State { | 68 | State { |
| @@ -68,18 +73,25 @@ impl State { | |||
| 68 | 73 | ||
| 69 | static STATE: State = State::new(); | 74 | static STATE: State = State::new(); |
| 70 | 75 | ||
| 76 | /// DCMI error. | ||
| 71 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | 77 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
| 72 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 78 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 73 | #[non_exhaustive] | 79 | #[non_exhaustive] |
| 74 | pub enum Error { | 80 | pub enum Error { |
| 81 | /// Overrun error: the hardware generated data faster than we could read it. | ||
| 75 | Overrun, | 82 | Overrun, |
| 83 | /// Internal peripheral error. | ||
| 76 | PeripheralError, | 84 | PeripheralError, |
| 77 | } | 85 | } |
| 78 | 86 | ||
| 87 | /// DCMI configuration. | ||
| 79 | #[non_exhaustive] | 88 | #[non_exhaustive] |
| 80 | pub struct Config { | 89 | pub struct Config { |
| 90 | /// VSYNC level. | ||
| 81 | pub vsync_level: VSyncDataInvalidLevel, | 91 | pub vsync_level: VSyncDataInvalidLevel, |
| 92 | /// HSYNC level. | ||
| 82 | pub hsync_level: HSyncDataInvalidLevel, | 93 | pub hsync_level: HSyncDataInvalidLevel, |
| 94 | /// PIXCLK polarity. | ||
| 83 | pub pixclk_polarity: PixelClockPolarity, | 95 | pub pixclk_polarity: PixelClockPolarity, |
| 84 | } | 96 | } |
| 85 | 97 | ||
| @@ -105,6 +117,7 @@ macro_rules! config_pins { | |||
| 105 | }; | 117 | }; |
| 106 | } | 118 | } |
| 107 | 119 | ||
| 120 | /// DCMI driver. | ||
| 108 | pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { | 121 | pub struct Dcmi<'d, T: Instance, Dma: FrameDma<T>> { |
| 109 | inner: PeripheralRef<'d, T>, | 122 | inner: PeripheralRef<'d, T>, |
| 110 | dma: PeripheralRef<'d, Dma>, | 123 | dma: PeripheralRef<'d, Dma>, |
| @@ -115,6 +128,7 @@ where | |||
| 115 | T: Instance, | 128 | T: Instance, |
| 116 | Dma: FrameDma<T>, | 129 | Dma: FrameDma<T>, |
| 117 | { | 130 | { |
| 131 | /// Create a new DCMI driver with 8 data bits. | ||
| 118 | pub fn new_8bit( | 132 | pub fn new_8bit( |
| 119 | peri: impl Peripheral<P = T> + 'd, | 133 | peri: impl Peripheral<P = T> + 'd, |
| 120 | dma: impl Peripheral<P = Dma> + 'd, | 134 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -139,6 +153,7 @@ where | |||
| 139 | Self::new_inner(peri, dma, config, false, 0b00) | 153 | Self::new_inner(peri, dma, config, false, 0b00) |
| 140 | } | 154 | } |
| 141 | 155 | ||
| 156 | /// Create a new DCMI driver with 10 data bits. | ||
| 142 | pub fn new_10bit( | 157 | pub fn new_10bit( |
| 143 | peri: impl Peripheral<P = T> + 'd, | 158 | peri: impl Peripheral<P = T> + 'd, |
| 144 | dma: impl Peripheral<P = Dma> + 'd, | 159 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -165,6 +180,7 @@ where | |||
| 165 | Self::new_inner(peri, dma, config, false, 0b01) | 180 | Self::new_inner(peri, dma, config, false, 0b01) |
| 166 | } | 181 | } |
| 167 | 182 | ||
| 183 | /// Create a new DCMI driver with 12 data bits. | ||
| 168 | pub fn new_12bit( | 184 | pub fn new_12bit( |
| 169 | peri: impl Peripheral<P = T> + 'd, | 185 | peri: impl Peripheral<P = T> + 'd, |
| 170 | dma: impl Peripheral<P = Dma> + 'd, | 186 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -193,6 +209,7 @@ where | |||
| 193 | Self::new_inner(peri, dma, config, false, 0b10) | 209 | Self::new_inner(peri, dma, config, false, 0b10) |
| 194 | } | 210 | } |
| 195 | 211 | ||
| 212 | /// Create a new DCMI driver with 14 data bits. | ||
| 196 | pub fn new_14bit( | 213 | pub fn new_14bit( |
| 197 | peri: impl Peripheral<P = T> + 'd, | 214 | peri: impl Peripheral<P = T> + 'd, |
| 198 | dma: impl Peripheral<P = Dma> + 'd, | 215 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -223,6 +240,7 @@ where | |||
| 223 | Self::new_inner(peri, dma, config, false, 0b11) | 240 | Self::new_inner(peri, dma, config, false, 0b11) |
| 224 | } | 241 | } |
| 225 | 242 | ||
| 243 | /// Create a new DCMI driver with 8 data bits, with embedded synchronization. | ||
| 226 | pub fn new_es_8bit( | 244 | pub fn new_es_8bit( |
| 227 | peri: impl Peripheral<P = T> + 'd, | 245 | peri: impl Peripheral<P = T> + 'd, |
| 228 | dma: impl Peripheral<P = Dma> + 'd, | 246 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -245,6 +263,7 @@ where | |||
| 245 | Self::new_inner(peri, dma, config, true, 0b00) | 263 | Self::new_inner(peri, dma, config, true, 0b00) |
| 246 | } | 264 | } |
| 247 | 265 | ||
| 266 | /// Create a new DCMI driver with 10 data bits, with embedded synchronization. | ||
| 248 | pub fn new_es_10bit( | 267 | pub fn new_es_10bit( |
| 249 | peri: impl Peripheral<P = T> + 'd, | 268 | peri: impl Peripheral<P = T> + 'd, |
| 250 | dma: impl Peripheral<P = Dma> + 'd, | 269 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -269,6 +288,7 @@ where | |||
| 269 | Self::new_inner(peri, dma, config, true, 0b01) | 288 | Self::new_inner(peri, dma, config, true, 0b01) |
| 270 | } | 289 | } |
| 271 | 290 | ||
| 291 | /// Create a new DCMI driver with 12 data bits, with embedded synchronization. | ||
| 272 | pub fn new_es_12bit( | 292 | pub fn new_es_12bit( |
| 273 | peri: impl Peripheral<P = T> + 'd, | 293 | peri: impl Peripheral<P = T> + 'd, |
| 274 | dma: impl Peripheral<P = Dma> + 'd, | 294 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -295,6 +315,7 @@ where | |||
| 295 | Self::new_inner(peri, dma, config, true, 0b10) | 315 | Self::new_inner(peri, dma, config, true, 0b10) |
| 296 | } | 316 | } |
| 297 | 317 | ||
| 318 | /// Create a new DCMI driver with 14 data bits, with embedded synchronization. | ||
| 298 | pub fn new_es_14bit( | 319 | pub fn new_es_14bit( |
| 299 | peri: impl Peripheral<P = T> + 'd, | 320 | peri: impl Peripheral<P = T> + 'd, |
| 300 | dma: impl Peripheral<P = Dma> + 'd, | 321 | dma: impl Peripheral<P = Dma> + 'd, |
| @@ -538,7 +559,9 @@ mod sealed { | |||
| 538 | } | 559 | } |
| 539 | } | 560 | } |
| 540 | 561 | ||
| 562 | /// DCMI instance. | ||
| 541 | pub trait Instance: sealed::Instance + 'static { | 563 | pub trait Instance: sealed::Instance + 'static { |
| 564 | /// Interrupt for this instance. | ||
| 542 | type Interrupt: interrupt::typelevel::Interrupt; | 565 | type Interrupt: interrupt::typelevel::Interrupt; |
| 543 | } | 566 | } |
| 544 | 567 | ||
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index a7422f66b..a2b83716d 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #![macro_use] | 1 | //! Basic Direct Memory Acccess (BDMA) |
| 2 | 2 | ||
| 3 | use core::future::Future; | 3 | use core::future::Future; |
| 4 | use core::pin::Pin; | 4 | use core::pin::Pin; |
| @@ -17,11 +17,16 @@ use crate::interrupt::Priority; | |||
| 17 | use crate::pac; | 17 | use crate::pac; |
| 18 | use crate::pac::bdma::{regs, vals}; | 18 | use 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] |
| 23 | pub struct TransferOptions { | 24 | pub struct TransferOptions { |
| 24 | /// Enable circular DMA | 25 | /// Enable circular DMA |
| 26 | /// | ||
| 27 | /// Note: | ||
| 28 | /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. | ||
| 29 | /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. | ||
| 25 | pub circular: bool, | 30 | pub circular: bool, |
| 26 | /// Enable half transfer interrupt | 31 | /// Enable half transfer interrupt |
| 27 | pub half_transfer_ir: bool, | 32 | pub half_transfer_ir: bool, |
| @@ -140,13 +145,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index | |||
| 140 | STATE.ch_wakers[index].wake(); | 145 | STATE.ch_wakers[index].wake(); |
| 141 | } | 146 | } |
| 142 | 147 | ||
| 148 | /// DMA request type alias. | ||
| 143 | #[cfg(any(bdma_v2, dmamux))] | 149 | #[cfg(any(bdma_v2, dmamux))] |
| 144 | pub type Request = u8; | 150 | pub type Request = u8; |
| 151 | /// DMA request type alias. | ||
| 145 | #[cfg(not(any(bdma_v2, dmamux)))] | 152 | #[cfg(not(any(bdma_v2, dmamux)))] |
| 146 | pub type Request = (); | 153 | pub type Request = (); |
| 147 | 154 | ||
| 155 | /// DMA channel. | ||
| 148 | #[cfg(dmamux)] | 156 | #[cfg(dmamux)] |
| 149 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} | 157 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 158 | /// DMA channel. | ||
| 150 | #[cfg(not(dmamux))] | 159 | #[cfg(not(dmamux))] |
| 151 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | 160 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} |
| 152 | 161 | ||
| @@ -161,12 +170,14 @@ pub(crate) mod sealed { | |||
| 161 | } | 170 | } |
| 162 | } | 171 | } |
| 163 | 172 | ||
| 173 | /// DMA transfer. | ||
| 164 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 174 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 165 | pub struct Transfer<'a, C: Channel> { | 175 | pub struct Transfer<'a, C: Channel> { |
| 166 | channel: PeripheralRef<'a, C>, | 176 | channel: PeripheralRef<'a, C>, |
| 167 | } | 177 | } |
| 168 | 178 | ||
| 169 | impl<'a, C: Channel> Transfer<'a, C> { | 179 | impl<'a, C: Channel> Transfer<'a, C> { |
| 180 | /// Create a new read DMA transfer (peripheral to memory). | ||
| 170 | pub unsafe fn new_read<W: Word>( | 181 | pub unsafe fn new_read<W: Word>( |
| 171 | channel: impl Peripheral<P = C> + 'a, | 182 | channel: impl Peripheral<P = C> + 'a, |
| 172 | request: Request, | 183 | request: Request, |
| @@ -177,6 +188,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 177 | Self::new_read_raw(channel, request, peri_addr, buf, options) | 188 | Self::new_read_raw(channel, request, peri_addr, buf, options) |
| 178 | } | 189 | } |
| 179 | 190 | ||
| 191 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. | ||
| 180 | pub unsafe fn new_read_raw<W: Word>( | 192 | pub unsafe fn new_read_raw<W: Word>( |
| 181 | channel: impl Peripheral<P = C> + 'a, | 193 | channel: impl Peripheral<P = C> + 'a, |
| 182 | request: Request, | 194 | request: Request, |
| @@ -202,6 +214,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 202 | ) | 214 | ) |
| 203 | } | 215 | } |
| 204 | 216 | ||
| 217 | /// Create a new write DMA transfer (memory to peripheral). | ||
| 205 | pub unsafe fn new_write<W: Word>( | 218 | pub unsafe fn new_write<W: Word>( |
| 206 | channel: impl Peripheral<P = C> + 'a, | 219 | channel: impl Peripheral<P = C> + 'a, |
| 207 | request: Request, | 220 | request: Request, |
| @@ -212,6 +225,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 212 | Self::new_write_raw(channel, request, buf, peri_addr, options) | 225 | Self::new_write_raw(channel, request, buf, peri_addr, options) |
| 213 | } | 226 | } |
| 214 | 227 | ||
| 228 | /// Create a new write DMA transfer (memory to peripheral), using raw pointers. | ||
| 215 | pub unsafe fn new_write_raw<W: Word>( | 229 | pub unsafe fn new_write_raw<W: Word>( |
| 216 | channel: impl Peripheral<P = C> + 'a, | 230 | channel: impl Peripheral<P = C> + 'a, |
| 217 | request: Request, | 231 | request: Request, |
| @@ -237,6 +251,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 237 | ) | 251 | ) |
| 238 | } | 252 | } |
| 239 | 253 | ||
| 254 | /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. | ||
| 240 | pub unsafe fn new_write_repeated<W: Word>( | 255 | pub unsafe fn new_write_repeated<W: Word>( |
| 241 | channel: impl Peripheral<P = C> + 'a, | 256 | channel: impl Peripheral<P = C> + 'a, |
| 242 | request: Request, | 257 | request: Request, |
| @@ -292,20 +307,14 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 292 | ch.cr().write(|w| { | 307 | ch.cr().write(|w| { |
| 293 | w.set_psize(data_size.into()); | 308 | w.set_psize(data_size.into()); |
| 294 | w.set_msize(data_size.into()); | 309 | w.set_msize(data_size.into()); |
| 295 | if incr_mem { | 310 | w.set_minc(incr_mem); |
| 296 | w.set_minc(vals::Inc::ENABLED); | ||
| 297 | } else { | ||
| 298 | w.set_minc(vals::Inc::DISABLED); | ||
| 299 | } | ||
| 300 | w.set_dir(dir.into()); | 311 | w.set_dir(dir.into()); |
| 301 | w.set_teie(true); | 312 | w.set_teie(true); |
| 302 | w.set_tcie(options.complete_transfer_ir); | 313 | w.set_tcie(options.complete_transfer_ir); |
| 303 | w.set_htie(options.half_transfer_ir); | 314 | w.set_htie(options.half_transfer_ir); |
| 315 | w.set_circ(options.circular); | ||
| 304 | if options.circular { | 316 | if options.circular { |
| 305 | w.set_circ(vals::Circ::ENABLED); | ||
| 306 | debug!("Setting circular mode"); | 317 | debug!("Setting circular mode"); |
| 307 | } else { | ||
| 308 | w.set_circ(vals::Circ::DISABLED); | ||
| 309 | } | 318 | } |
| 310 | w.set_pl(vals::Pl::VERYHIGH); | 319 | w.set_pl(vals::Pl::VERYHIGH); |
| 311 | w.set_en(true); | 320 | w.set_en(true); |
| @@ -321,6 +330,9 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 321 | }); | 330 | }); |
| 322 | } | 331 | } |
| 323 | 332 | ||
| 333 | /// Request the transfer to stop. | ||
| 334 | /// | ||
| 335 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 324 | pub fn request_stop(&mut self) { | 336 | pub fn request_stop(&mut self) { |
| 325 | let ch = self.channel.regs().ch(self.channel.num()); | 337 | let ch = self.channel.regs().ch(self.channel.num()); |
| 326 | 338 | ||
| @@ -331,21 +343,27 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 331 | }); | 343 | }); |
| 332 | } | 344 | } |
| 333 | 345 | ||
| 346 | /// Return whether this transfer is still running. | ||
| 347 | /// | ||
| 348 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 349 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 334 | pub fn is_running(&mut self) -> bool { | 350 | pub fn is_running(&mut self) -> bool { |
| 335 | let ch = self.channel.regs().ch(self.channel.num()); | 351 | let ch = self.channel.regs().ch(self.channel.num()); |
| 336 | let en = ch.cr().read().en(); | 352 | let en = ch.cr().read().en(); |
| 337 | let circular = ch.cr().read().circ() == vals::Circ::ENABLED; | 353 | let circular = ch.cr().read().circ(); |
| 338 | let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; | 354 | let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; |
| 339 | en && (circular || !tcif) | 355 | en && (circular || !tcif) |
| 340 | } | 356 | } |
| 341 | 357 | ||
| 342 | /// Gets the total remaining transfers for the channel | 358 | /// Get the total remaining transfers for the channel. |
| 343 | /// Note: this will be zero for transfers that completed without cancellation. | 359 | /// |
| 360 | /// This will be zero for transfers that completed instead of being canceled with [`request_stop`](Self::request_stop). | ||
| 344 | pub fn get_remaining_transfers(&self) -> u16 { | 361 | pub fn get_remaining_transfers(&self) -> u16 { |
| 345 | let ch = self.channel.regs().ch(self.channel.num()); | 362 | let ch = self.channel.regs().ch(self.channel.num()); |
| 346 | ch.ndtr().read().ndt() | 363 | ch.ndtr().read().ndt() |
| 347 | } | 364 | } |
| 348 | 365 | ||
| 366 | /// Blocking wait until the transfer finishes. | ||
| 349 | pub fn blocking_wait(mut self) { | 367 | pub fn blocking_wait(mut self) { |
| 350 | while self.is_running() {} | 368 | while self.is_running() {} |
| 351 | self.request_stop(); | 369 | self.request_stop(); |
| @@ -411,6 +429,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | |||
| 411 | } | 429 | } |
| 412 | } | 430 | } |
| 413 | 431 | ||
| 432 | /// Ringbuffer for reading data using DMA circular mode. | ||
| 414 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { | 433 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { |
| 415 | cr: regs::Cr, | 434 | cr: regs::Cr, |
| 416 | channel: PeripheralRef<'a, C>, | 435 | channel: PeripheralRef<'a, C>, |
| @@ -418,7 +437,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { | |||
| 418 | } | 437 | } |
| 419 | 438 | ||
| 420 | impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | 439 | impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { |
| 421 | pub unsafe fn new_read( | 440 | /// Create a new ring buffer. |
| 441 | pub unsafe fn new( | ||
| 422 | channel: impl Peripheral<P = C> + 'a, | 442 | channel: impl Peripheral<P = C> + 'a, |
| 423 | _request: Request, | 443 | _request: Request, |
| 424 | peri_addr: *mut W, | 444 | peri_addr: *mut W, |
| @@ -445,12 +465,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 445 | let mut w = regs::Cr(0); | 465 | let mut w = regs::Cr(0); |
| 446 | w.set_psize(data_size.into()); | 466 | w.set_psize(data_size.into()); |
| 447 | w.set_msize(data_size.into()); | 467 | w.set_msize(data_size.into()); |
| 448 | w.set_minc(vals::Inc::ENABLED); | 468 | w.set_minc(true); |
| 449 | w.set_dir(dir.into()); | 469 | w.set_dir(dir.into()); |
| 450 | w.set_teie(true); | 470 | w.set_teie(true); |
| 451 | w.set_htie(true); | 471 | w.set_htie(true); |
| 452 | w.set_tcie(true); | 472 | w.set_tcie(true); |
| 453 | w.set_circ(vals::Circ::ENABLED); | 473 | w.set_circ(true); |
| 454 | w.set_pl(vals::Pl::VERYHIGH); | 474 | w.set_pl(vals::Pl::VERYHIGH); |
| 455 | w.set_en(true); | 475 | w.set_en(true); |
| 456 | 476 | ||
| @@ -473,11 +493,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 473 | this | 493 | this |
| 474 | } | 494 | } |
| 475 | 495 | ||
| 496 | /// Start the ring buffer operation. | ||
| 497 | /// | ||
| 498 | /// You must call this after creating it for it to work. | ||
| 476 | pub fn start(&mut self) { | 499 | pub fn start(&mut self) { |
| 477 | let ch = self.channel.regs().ch(self.channel.num()); | 500 | let ch = self.channel.regs().ch(self.channel.num()); |
| 478 | ch.cr().write_value(self.cr) | 501 | ch.cr().write_value(self.cr) |
| 479 | } | 502 | } |
| 480 | 503 | ||
| 504 | /// Clear all data in the ring buffer. | ||
| 481 | pub fn clear(&mut self) { | 505 | pub fn clear(&mut self) { |
| 482 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); | 506 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 483 | } | 507 | } |
| @@ -509,10 +533,11 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 509 | } | 533 | } |
| 510 | 534 | ||
| 511 | /// The capacity of the ringbuffer. | 535 | /// The capacity of the ringbuffer. |
| 512 | pub const fn cap(&self) -> usize { | 536 | pub const fn capacity(&self) -> usize { |
| 513 | self.ringbuf.cap() | 537 | self.ringbuf.cap() |
| 514 | } | 538 | } |
| 515 | 539 | ||
| 540 | /// Set a waker to be woken when at least one byte is received. | ||
| 516 | pub fn set_waker(&mut self, waker: &Waker) { | 541 | pub fn set_waker(&mut self, waker: &Waker) { |
| 517 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); | 542 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 518 | } | 543 | } |
| @@ -526,6 +551,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 526 | }); | 551 | }); |
| 527 | } | 552 | } |
| 528 | 553 | ||
| 554 | /// Request DMA to stop. | ||
| 555 | /// | ||
| 556 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 529 | pub fn request_stop(&mut self) { | 557 | pub fn request_stop(&mut self) { |
| 530 | let ch = self.channel.regs().ch(self.channel.num()); | 558 | let ch = self.channel.regs().ch(self.channel.num()); |
| 531 | 559 | ||
| @@ -539,6 +567,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 539 | }); | 567 | }); |
| 540 | } | 568 | } |
| 541 | 569 | ||
| 570 | /// Return whether DMA is still running. | ||
| 571 | /// | ||
| 572 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 573 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 542 | pub fn is_running(&mut self) -> bool { | 574 | pub fn is_running(&mut self) -> bool { |
| 543 | let ch = self.channel.regs().ch(self.channel.num()); | 575 | let ch = self.channel.regs().ch(self.channel.num()); |
| 544 | ch.cr().read().en() | 576 | ch.cr().read().en() |
| @@ -555,6 +587,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { | |||
| 555 | } | 587 | } |
| 556 | } | 588 | } |
| 557 | 589 | ||
| 590 | /// Ringbuffer for writing data using DMA circular mode. | ||
| 558 | pub struct WritableRingBuffer<'a, C: Channel, W: Word> { | 591 | pub struct WritableRingBuffer<'a, C: Channel, W: Word> { |
| 559 | cr: regs::Cr, | 592 | cr: regs::Cr, |
| 560 | channel: PeripheralRef<'a, C>, | 593 | channel: PeripheralRef<'a, C>, |
| @@ -562,7 +595,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { | |||
| 562 | } | 595 | } |
| 563 | 596 | ||
| 564 | impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | 597 | impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { |
| 565 | pub unsafe fn new_write( | 598 | /// Create a new ring buffer. |
| 599 | pub unsafe fn new( | ||
| 566 | channel: impl Peripheral<P = C> + 'a, | 600 | channel: impl Peripheral<P = C> + 'a, |
| 567 | _request: Request, | 601 | _request: Request, |
| 568 | peri_addr: *mut W, | 602 | peri_addr: *mut W, |
| @@ -589,12 +623,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 589 | let mut w = regs::Cr(0); | 623 | let mut w = regs::Cr(0); |
| 590 | w.set_psize(data_size.into()); | 624 | w.set_psize(data_size.into()); |
| 591 | w.set_msize(data_size.into()); | 625 | w.set_msize(data_size.into()); |
| 592 | w.set_minc(vals::Inc::ENABLED); | 626 | w.set_minc(true); |
| 593 | w.set_dir(dir.into()); | 627 | w.set_dir(dir.into()); |
| 594 | w.set_teie(true); | 628 | w.set_teie(true); |
| 595 | w.set_htie(true); | 629 | w.set_htie(true); |
| 596 | w.set_tcie(true); | 630 | w.set_tcie(true); |
| 597 | w.set_circ(vals::Circ::ENABLED); | 631 | w.set_circ(true); |
| 598 | w.set_pl(vals::Pl::VERYHIGH); | 632 | w.set_pl(vals::Pl::VERYHIGH); |
| 599 | w.set_en(true); | 633 | w.set_en(true); |
| 600 | 634 | ||
| @@ -617,11 +651,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 617 | this | 651 | this |
| 618 | } | 652 | } |
| 619 | 653 | ||
| 654 | /// Start the ring buffer operation. | ||
| 655 | /// | ||
| 656 | /// You must call this after creating it for it to work. | ||
| 620 | pub fn start(&mut self) { | 657 | pub fn start(&mut self) { |
| 621 | let ch = self.channel.regs().ch(self.channel.num()); | 658 | let ch = self.channel.regs().ch(self.channel.num()); |
| 622 | ch.cr().write_value(self.cr) | 659 | ch.cr().write_value(self.cr) |
| 623 | } | 660 | } |
| 624 | 661 | ||
| 662 | /// Clear all data in the ring buffer. | ||
| 625 | pub fn clear(&mut self) { | 663 | pub fn clear(&mut self) { |
| 626 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); | 664 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 627 | } | 665 | } |
| @@ -640,10 +678,11 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 640 | } | 678 | } |
| 641 | 679 | ||
| 642 | /// The capacity of the ringbuffer. | 680 | /// The capacity of the ringbuffer. |
| 643 | pub const fn cap(&self) -> usize { | 681 | pub const fn capacity(&self) -> usize { |
| 644 | self.ringbuf.cap() | 682 | self.ringbuf.cap() |
| 645 | } | 683 | } |
| 646 | 684 | ||
| 685 | /// Set a waker to be woken when at least one byte is sent. | ||
| 647 | pub fn set_waker(&mut self, waker: &Waker) { | 686 | pub fn set_waker(&mut self, waker: &Waker) { |
| 648 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); | 687 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 649 | } | 688 | } |
| @@ -657,6 +696,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 657 | }); | 696 | }); |
| 658 | } | 697 | } |
| 659 | 698 | ||
| 699 | /// Request DMA to stop. | ||
| 700 | /// | ||
| 701 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 660 | pub fn request_stop(&mut self) { | 702 | pub fn request_stop(&mut self) { |
| 661 | let ch = self.channel.regs().ch(self.channel.num()); | 703 | let ch = self.channel.regs().ch(self.channel.num()); |
| 662 | 704 | ||
| @@ -670,6 +712,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 670 | }); | 712 | }); |
| 671 | } | 713 | } |
| 672 | 714 | ||
| 715 | /// Return whether DMA is still running. | ||
| 716 | /// | ||
| 717 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 718 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 673 | pub fn is_running(&mut self) -> bool { | 719 | pub fn is_running(&mut self) -> bool { |
| 674 | let ch = self.channel.regs().ch(self.channel.num()); | 720 | let ch = self.channel.regs().ch(self.channel.num()); |
| 675 | ch.cr().read().en() | 721 | ch.cr().read().en() |
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index cce0407c1..16d02f273 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -16,6 +16,7 @@ use crate::interrupt::Priority; | |||
| 16 | use crate::pac::dma::{regs, vals}; | 16 | use crate::pac::dma::{regs, vals}; |
| 17 | use crate::{interrupt, pac}; | 17 | use crate::{interrupt, pac}; |
| 18 | 18 | ||
| 19 | /// DMA transfer options. | ||
| 19 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 21 | #[non_exhaustive] | 22 | #[non_exhaustive] |
| @@ -29,6 +30,10 @@ pub struct TransferOptions { | |||
| 29 | /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. | 30 | /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. |
| 30 | pub fifo_threshold: Option<FifoThreshold>, | 31 | pub fifo_threshold: Option<FifoThreshold>, |
| 31 | /// Enable circular DMA | 32 | /// Enable circular DMA |
| 33 | /// | ||
| 34 | /// Note: | ||
| 35 | /// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task. | ||
| 36 | /// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever. | ||
| 32 | pub circular: bool, | 37 | pub circular: bool, |
| 33 | /// Enable half transfer interrupt | 38 | /// Enable half transfer interrupt |
| 34 | pub half_transfer_ir: bool, | 39 | pub half_transfer_ir: bool, |
| @@ -69,6 +74,7 @@ impl From<Dir> for vals::Dir { | |||
| 69 | } | 74 | } |
| 70 | } | 75 | } |
| 71 | 76 | ||
| 77 | /// DMA transfer burst setting. | ||
| 72 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 78 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 73 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 79 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 74 | pub enum Burst { | 80 | pub enum Burst { |
| @@ -93,6 +99,7 @@ impl From<Burst> for vals::Burst { | |||
| 93 | } | 99 | } |
| 94 | } | 100 | } |
| 95 | 101 | ||
| 102 | /// DMA flow control setting. | ||
| 96 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 103 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 97 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 104 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 98 | pub enum FlowControl { | 105 | pub enum FlowControl { |
| @@ -111,6 +118,7 @@ impl From<FlowControl> for vals::Pfctrl { | |||
| 111 | } | 118 | } |
| 112 | } | 119 | } |
| 113 | 120 | ||
| 121 | /// DMA FIFO threshold. | ||
| 114 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 122 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 115 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 123 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 116 | pub enum FifoThreshold { | 124 | pub enum FifoThreshold { |
| @@ -208,13 +216,17 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index: | |||
| 208 | STATE.ch_wakers[index].wake(); | 216 | STATE.ch_wakers[index].wake(); |
| 209 | } | 217 | } |
| 210 | 218 | ||
| 219 | /// DMA request type alias. (also known as DMA channel number in some chips) | ||
| 211 | #[cfg(any(dma_v2, dmamux))] | 220 | #[cfg(any(dma_v2, dmamux))] |
| 212 | pub type Request = u8; | 221 | pub type Request = u8; |
| 222 | /// DMA request type alias. (also known as DMA channel number in some chips) | ||
| 213 | #[cfg(not(any(dma_v2, dmamux)))] | 223 | #[cfg(not(any(dma_v2, dmamux)))] |
| 214 | pub type Request = (); | 224 | pub type Request = (); |
| 215 | 225 | ||
| 226 | /// DMA channel. | ||
| 216 | #[cfg(dmamux)] | 227 | #[cfg(dmamux)] |
| 217 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} | 228 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 229 | /// DMA channel. | ||
| 218 | #[cfg(not(dmamux))] | 230 | #[cfg(not(dmamux))] |
| 219 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | 231 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} |
| 220 | 232 | ||
| @@ -229,12 +241,14 @@ pub(crate) mod sealed { | |||
| 229 | } | 241 | } |
| 230 | } | 242 | } |
| 231 | 243 | ||
| 244 | /// DMA transfer. | ||
| 232 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 245 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 233 | pub struct Transfer<'a, C: Channel> { | 246 | pub struct Transfer<'a, C: Channel> { |
| 234 | channel: PeripheralRef<'a, C>, | 247 | channel: PeripheralRef<'a, C>, |
| 235 | } | 248 | } |
| 236 | 249 | ||
| 237 | impl<'a, C: Channel> Transfer<'a, C> { | 250 | impl<'a, C: Channel> Transfer<'a, C> { |
| 251 | /// Create a new read DMA transfer (peripheral to memory). | ||
| 238 | pub unsafe fn new_read<W: Word>( | 252 | pub unsafe fn new_read<W: Word>( |
| 239 | channel: impl Peripheral<P = C> + 'a, | 253 | channel: impl Peripheral<P = C> + 'a, |
| 240 | request: Request, | 254 | request: Request, |
| @@ -245,6 +259,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 245 | Self::new_read_raw(channel, request, peri_addr, buf, options) | 259 | Self::new_read_raw(channel, request, peri_addr, buf, options) |
| 246 | } | 260 | } |
| 247 | 261 | ||
| 262 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. | ||
| 248 | pub unsafe fn new_read_raw<W: Word>( | 263 | pub unsafe fn new_read_raw<W: Word>( |
| 249 | channel: impl Peripheral<P = C> + 'a, | 264 | channel: impl Peripheral<P = C> + 'a, |
| 250 | request: Request, | 265 | request: Request, |
| @@ -270,6 +285,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 270 | ) | 285 | ) |
| 271 | } | 286 | } |
| 272 | 287 | ||
| 288 | /// Create a new write DMA transfer (memory to peripheral). | ||
| 273 | pub unsafe fn new_write<W: Word>( | 289 | pub unsafe fn new_write<W: Word>( |
| 274 | channel: impl Peripheral<P = C> + 'a, | 290 | channel: impl Peripheral<P = C> + 'a, |
| 275 | request: Request, | 291 | request: Request, |
| @@ -280,6 +296,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 280 | Self::new_write_raw(channel, request, buf, peri_addr, options) | 296 | Self::new_write_raw(channel, request, buf, peri_addr, options) |
| 281 | } | 297 | } |
| 282 | 298 | ||
| 299 | /// Create a new write DMA transfer (memory to peripheral), using raw pointers. | ||
| 283 | pub unsafe fn new_write_raw<W: Word>( | 300 | pub unsafe fn new_write_raw<W: Word>( |
| 284 | channel: impl Peripheral<P = C> + 'a, | 301 | channel: impl Peripheral<P = C> + 'a, |
| 285 | request: Request, | 302 | request: Request, |
| @@ -305,6 +322,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 305 | ) | 322 | ) |
| 306 | } | 323 | } |
| 307 | 324 | ||
| 325 | /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. | ||
| 308 | pub unsafe fn new_write_repeated<W: Word>( | 326 | pub unsafe fn new_write_repeated<W: Word>( |
| 309 | channel: impl Peripheral<P = C> + 'a, | 327 | channel: impl Peripheral<P = C> + 'a, |
| 310 | request: Request, | 328 | request: Request, |
| @@ -368,18 +386,13 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 368 | w.set_msize(data_size.into()); | 386 | w.set_msize(data_size.into()); |
| 369 | w.set_psize(data_size.into()); | 387 | w.set_psize(data_size.into()); |
| 370 | w.set_pl(vals::Pl::VERYHIGH); | 388 | w.set_pl(vals::Pl::VERYHIGH); |
| 371 | w.set_minc(match incr_mem { | 389 | w.set_minc(incr_mem); |
| 372 | true => vals::Inc::INCREMENTED, | 390 | w.set_pinc(false); |
| 373 | false => vals::Inc::FIXED, | ||
| 374 | }); | ||
| 375 | w.set_pinc(vals::Inc::FIXED); | ||
| 376 | w.set_teie(true); | 391 | w.set_teie(true); |
| 377 | w.set_tcie(options.complete_transfer_ir); | 392 | w.set_tcie(options.complete_transfer_ir); |
| 393 | w.set_circ(options.circular); | ||
| 378 | if options.circular { | 394 | if options.circular { |
| 379 | w.set_circ(vals::Circ::ENABLED); | ||
| 380 | debug!("Setting circular mode"); | 395 | debug!("Setting circular mode"); |
| 381 | } else { | ||
| 382 | w.set_circ(vals::Circ::DISABLED); | ||
| 383 | } | 396 | } |
| 384 | #[cfg(dma_v1)] | 397 | #[cfg(dma_v1)] |
| 385 | w.set_trbuff(true); | 398 | w.set_trbuff(true); |
| @@ -407,6 +420,9 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 407 | }); | 420 | }); |
| 408 | } | 421 | } |
| 409 | 422 | ||
| 423 | /// Request the transfer to stop. | ||
| 424 | /// | ||
| 425 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 410 | pub fn request_stop(&mut self) { | 426 | pub fn request_stop(&mut self) { |
| 411 | let ch = self.channel.regs().st(self.channel.num()); | 427 | let ch = self.channel.regs().st(self.channel.num()); |
| 412 | 428 | ||
| @@ -417,6 +433,10 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 417 | }); | 433 | }); |
| 418 | } | 434 | } |
| 419 | 435 | ||
| 436 | /// Return whether this transfer is still running. | ||
| 437 | /// | ||
| 438 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 439 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 420 | pub fn is_running(&mut self) -> bool { | 440 | pub fn is_running(&mut self) -> bool { |
| 421 | let ch = self.channel.regs().st(self.channel.num()); | 441 | let ch = self.channel.regs().st(self.channel.num()); |
| 422 | ch.cr().read().en() | 442 | ch.cr().read().en() |
| @@ -429,6 +449,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 429 | ch.ndtr().read().ndt() | 449 | ch.ndtr().read().ndt() |
| 430 | } | 450 | } |
| 431 | 451 | ||
| 452 | /// Blocking wait until the transfer finishes. | ||
| 432 | pub fn blocking_wait(mut self) { | 453 | pub fn blocking_wait(mut self) { |
| 433 | while self.is_running() {} | 454 | while self.is_running() {} |
| 434 | 455 | ||
| @@ -465,12 +486,14 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { | |||
| 465 | 486 | ||
| 466 | // ================================== | 487 | // ================================== |
| 467 | 488 | ||
| 489 | /// Double-buffered DMA transfer. | ||
| 468 | pub struct DoubleBuffered<'a, C: Channel, W: Word> { | 490 | pub struct DoubleBuffered<'a, C: Channel, W: Word> { |
| 469 | channel: PeripheralRef<'a, C>, | 491 | channel: PeripheralRef<'a, C>, |
| 470 | _phantom: PhantomData<W>, | 492 | _phantom: PhantomData<W>, |
| 471 | } | 493 | } |
| 472 | 494 | ||
| 473 | impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | 495 | impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { |
| 496 | /// Create a new read DMA transfer (peripheral to memory). | ||
| 474 | pub unsafe fn new_read( | 497 | pub unsafe fn new_read( |
| 475 | channel: impl Peripheral<P = C> + 'a, | 498 | channel: impl Peripheral<P = C> + 'a, |
| 476 | _request: Request, | 499 | _request: Request, |
| @@ -521,8 +544,8 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 521 | w.set_msize(data_size.into()); | 544 | w.set_msize(data_size.into()); |
| 522 | w.set_psize(data_size.into()); | 545 | w.set_psize(data_size.into()); |
| 523 | w.set_pl(vals::Pl::VERYHIGH); | 546 | w.set_pl(vals::Pl::VERYHIGH); |
| 524 | w.set_minc(vals::Inc::INCREMENTED); | 547 | w.set_minc(true); |
| 525 | w.set_pinc(vals::Inc::FIXED); | 548 | w.set_pinc(false); |
| 526 | w.set_teie(true); | 549 | w.set_teie(true); |
| 527 | w.set_tcie(true); | 550 | w.set_tcie(true); |
| 528 | #[cfg(dma_v1)] | 551 | #[cfg(dma_v1)] |
| @@ -554,25 +577,36 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 554 | }); | 577 | }); |
| 555 | } | 578 | } |
| 556 | 579 | ||
| 580 | /// Set the first buffer address. | ||
| 581 | /// | ||
| 582 | /// You may call this while DMA is transferring the other buffer. | ||
| 557 | pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { | 583 | pub unsafe fn set_buffer0(&mut self, buffer: *mut W) { |
| 558 | let ch = self.channel.regs().st(self.channel.num()); | 584 | let ch = self.channel.regs().st(self.channel.num()); |
| 559 | ch.m0ar().write_value(buffer as _); | 585 | ch.m0ar().write_value(buffer as _); |
| 560 | } | 586 | } |
| 561 | 587 | ||
| 588 | /// Set the second buffer address. | ||
| 589 | /// | ||
| 590 | /// You may call this while DMA is transferring the other buffer. | ||
| 562 | pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { | 591 | pub unsafe fn set_buffer1(&mut self, buffer: *mut W) { |
| 563 | let ch = self.channel.regs().st(self.channel.num()); | 592 | let ch = self.channel.regs().st(self.channel.num()); |
| 564 | ch.m1ar().write_value(buffer as _); | 593 | ch.m1ar().write_value(buffer as _); |
| 565 | } | 594 | } |
| 566 | 595 | ||
| 596 | /// Returh whether buffer0 is accessible (i.e. whether DMA is transferring buffer1 now) | ||
| 567 | pub fn is_buffer0_accessible(&mut self) -> bool { | 597 | pub fn is_buffer0_accessible(&mut self) -> bool { |
| 568 | let ch = self.channel.regs().st(self.channel.num()); | 598 | let ch = self.channel.regs().st(self.channel.num()); |
| 569 | ch.cr().read().ct() == vals::Ct::MEMORY1 | 599 | ch.cr().read().ct() == vals::Ct::MEMORY1 |
| 570 | } | 600 | } |
| 571 | 601 | ||
| 602 | /// Set a waker to be woken when one of the buffers is being transferred. | ||
| 572 | pub fn set_waker(&mut self, waker: &Waker) { | 603 | pub fn set_waker(&mut self, waker: &Waker) { |
| 573 | STATE.ch_wakers[self.channel.index()].register(waker); | 604 | STATE.ch_wakers[self.channel.index()].register(waker); |
| 574 | } | 605 | } |
| 575 | 606 | ||
| 607 | /// Request the transfer to stop. | ||
| 608 | /// | ||
| 609 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 576 | pub fn request_stop(&mut self) { | 610 | pub fn request_stop(&mut self) { |
| 577 | let ch = self.channel.regs().st(self.channel.num()); | 611 | let ch = self.channel.regs().st(self.channel.num()); |
| 578 | 612 | ||
| @@ -583,6 +617,10 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> { | |||
| 583 | }); | 617 | }); |
| 584 | } | 618 | } |
| 585 | 619 | ||
| 620 | /// Return whether this transfer is still running. | ||
| 621 | /// | ||
| 622 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 623 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 586 | pub fn is_running(&mut self) -> bool { | 624 | pub fn is_running(&mut self) -> bool { |
| 587 | let ch = self.channel.regs().st(self.channel.num()); | 625 | let ch = self.channel.regs().st(self.channel.num()); |
| 588 | ch.cr().read().en() | 626 | ch.cr().read().en() |
| @@ -629,6 +667,7 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | |||
| 629 | } | 667 | } |
| 630 | } | 668 | } |
| 631 | 669 | ||
| 670 | /// Ringbuffer for receiving data using DMA circular mode. | ||
| 632 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { | 671 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { |
| 633 | cr: regs::Cr, | 672 | cr: regs::Cr, |
| 634 | channel: PeripheralRef<'a, C>, | 673 | channel: PeripheralRef<'a, C>, |
| @@ -636,7 +675,8 @@ pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { | |||
| 636 | } | 675 | } |
| 637 | 676 | ||
| 638 | impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | 677 | impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { |
| 639 | pub unsafe fn new_read( | 678 | /// Create a new ring buffer. |
| 679 | pub unsafe fn new( | ||
| 640 | channel: impl Peripheral<P = C> + 'a, | 680 | channel: impl Peripheral<P = C> + 'a, |
| 641 | _request: Request, | 681 | _request: Request, |
| 642 | peri_addr: *mut W, | 682 | peri_addr: *mut W, |
| @@ -662,12 +702,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 662 | w.set_msize(data_size.into()); | 702 | w.set_msize(data_size.into()); |
| 663 | w.set_psize(data_size.into()); | 703 | w.set_psize(data_size.into()); |
| 664 | w.set_pl(vals::Pl::VERYHIGH); | 704 | w.set_pl(vals::Pl::VERYHIGH); |
| 665 | w.set_minc(vals::Inc::INCREMENTED); | 705 | w.set_minc(true); |
| 666 | w.set_pinc(vals::Inc::FIXED); | 706 | w.set_pinc(false); |
| 667 | w.set_teie(true); | 707 | w.set_teie(true); |
| 668 | w.set_htie(options.half_transfer_ir); | 708 | w.set_htie(options.half_transfer_ir); |
| 669 | w.set_tcie(true); | 709 | w.set_tcie(true); |
| 670 | w.set_circ(vals::Circ::ENABLED); | 710 | w.set_circ(true); |
| 671 | #[cfg(dma_v1)] | 711 | #[cfg(dma_v1)] |
| 672 | w.set_trbuff(true); | 712 | w.set_trbuff(true); |
| 673 | #[cfg(dma_v2)] | 713 | #[cfg(dma_v2)] |
| @@ -706,11 +746,15 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 706 | this | 746 | this |
| 707 | } | 747 | } |
| 708 | 748 | ||
| 749 | /// Start the ring buffer operation. | ||
| 750 | /// | ||
| 751 | /// You must call this after creating it for it to work. | ||
| 709 | pub fn start(&mut self) { | 752 | pub fn start(&mut self) { |
| 710 | let ch = self.channel.regs().st(self.channel.num()); | 753 | let ch = self.channel.regs().st(self.channel.num()); |
| 711 | ch.cr().write_value(self.cr); | 754 | ch.cr().write_value(self.cr); |
| 712 | } | 755 | } |
| 713 | 756 | ||
| 757 | /// Clear all data in the ring buffer. | ||
| 714 | pub fn clear(&mut self) { | 758 | pub fn clear(&mut self) { |
| 715 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); | 759 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 716 | } | 760 | } |
| @@ -741,11 +785,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 741 | .await | 785 | .await |
| 742 | } | 786 | } |
| 743 | 787 | ||
| 744 | // The capacity of the ringbuffer | 788 | /// The capacity of the ringbuffer |
| 745 | pub const fn cap(&self) -> usize { | 789 | pub const fn capacity(&self) -> usize { |
| 746 | self.ringbuf.cap() | 790 | self.ringbuf.cap() |
| 747 | } | 791 | } |
| 748 | 792 | ||
| 793 | /// Set a waker to be woken when at least one byte is received. | ||
| 749 | pub fn set_waker(&mut self, waker: &Waker) { | 794 | pub fn set_waker(&mut self, waker: &Waker) { |
| 750 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); | 795 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 751 | } | 796 | } |
| @@ -763,6 +808,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 763 | }); | 808 | }); |
| 764 | } | 809 | } |
| 765 | 810 | ||
| 811 | /// Request DMA to stop. | ||
| 812 | /// | ||
| 813 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 766 | pub fn request_stop(&mut self) { | 814 | pub fn request_stop(&mut self) { |
| 767 | let ch = self.channel.regs().st(self.channel.num()); | 815 | let ch = self.channel.regs().st(self.channel.num()); |
| 768 | 816 | ||
| @@ -774,6 +822,10 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 774 | }); | 822 | }); |
| 775 | } | 823 | } |
| 776 | 824 | ||
| 825 | /// Return whether DMA is still running. | ||
| 826 | /// | ||
| 827 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 828 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 777 | pub fn is_running(&mut self) -> bool { | 829 | pub fn is_running(&mut self) -> bool { |
| 778 | let ch = self.channel.regs().st(self.channel.num()); | 830 | let ch = self.channel.regs().st(self.channel.num()); |
| 779 | ch.cr().read().en() | 831 | ch.cr().read().en() |
| @@ -790,6 +842,7 @@ impl<'a, C: Channel, W: Word> Drop for ReadableRingBuffer<'a, C, W> { | |||
| 790 | } | 842 | } |
| 791 | } | 843 | } |
| 792 | 844 | ||
| 845 | /// Ringbuffer for writing data using DMA circular mode. | ||
| 793 | pub struct WritableRingBuffer<'a, C: Channel, W: Word> { | 846 | pub struct WritableRingBuffer<'a, C: Channel, W: Word> { |
| 794 | cr: regs::Cr, | 847 | cr: regs::Cr, |
| 795 | channel: PeripheralRef<'a, C>, | 848 | channel: PeripheralRef<'a, C>, |
| @@ -797,7 +850,8 @@ pub struct WritableRingBuffer<'a, C: Channel, W: Word> { | |||
| 797 | } | 850 | } |
| 798 | 851 | ||
| 799 | impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | 852 | impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { |
| 800 | pub unsafe fn new_write( | 853 | /// Create a new ring buffer. |
| 854 | pub unsafe fn new( | ||
| 801 | channel: impl Peripheral<P = C> + 'a, | 855 | channel: impl Peripheral<P = C> + 'a, |
| 802 | _request: Request, | 856 | _request: Request, |
| 803 | peri_addr: *mut W, | 857 | peri_addr: *mut W, |
| @@ -823,12 +877,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 823 | w.set_msize(data_size.into()); | 877 | w.set_msize(data_size.into()); |
| 824 | w.set_psize(data_size.into()); | 878 | w.set_psize(data_size.into()); |
| 825 | w.set_pl(vals::Pl::VERYHIGH); | 879 | w.set_pl(vals::Pl::VERYHIGH); |
| 826 | w.set_minc(vals::Inc::INCREMENTED); | 880 | w.set_minc(true); |
| 827 | w.set_pinc(vals::Inc::FIXED); | 881 | w.set_pinc(false); |
| 828 | w.set_teie(true); | 882 | w.set_teie(true); |
| 829 | w.set_htie(options.half_transfer_ir); | 883 | w.set_htie(options.half_transfer_ir); |
| 830 | w.set_tcie(true); | 884 | w.set_tcie(true); |
| 831 | w.set_circ(vals::Circ::ENABLED); | 885 | w.set_circ(true); |
| 832 | #[cfg(dma_v1)] | 886 | #[cfg(dma_v1)] |
| 833 | w.set_trbuff(true); | 887 | w.set_trbuff(true); |
| 834 | #[cfg(dma_v2)] | 888 | #[cfg(dma_v2)] |
| @@ -867,11 +921,15 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 867 | this | 921 | this |
| 868 | } | 922 | } |
| 869 | 923 | ||
| 924 | /// Start the ring buffer operation. | ||
| 925 | /// | ||
| 926 | /// You must call this after creating it for it to work. | ||
| 870 | pub fn start(&mut self) { | 927 | pub fn start(&mut self) { |
| 871 | let ch = self.channel.regs().st(self.channel.num()); | 928 | let ch = self.channel.regs().st(self.channel.num()); |
| 872 | ch.cr().write_value(self.cr); | 929 | ch.cr().write_value(self.cr); |
| 873 | } | 930 | } |
| 874 | 931 | ||
| 932 | /// Clear all data in the ring buffer. | ||
| 875 | pub fn clear(&mut self) { | 933 | pub fn clear(&mut self) { |
| 876 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); | 934 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 877 | } | 935 | } |
| @@ -889,11 +947,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 889 | .await | 947 | .await |
| 890 | } | 948 | } |
| 891 | 949 | ||
| 892 | // The capacity of the ringbuffer | 950 | /// The capacity of the ringbuffer |
| 893 | pub const fn cap(&self) -> usize { | 951 | pub const fn capacity(&self) -> usize { |
| 894 | self.ringbuf.cap() | 952 | self.ringbuf.cap() |
| 895 | } | 953 | } |
| 896 | 954 | ||
| 955 | /// Set a waker to be woken when at least one byte is received. | ||
| 897 | pub fn set_waker(&mut self, waker: &Waker) { | 956 | pub fn set_waker(&mut self, waker: &Waker) { |
| 898 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); | 957 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 899 | } | 958 | } |
| @@ -911,6 +970,9 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 911 | }); | 970 | }); |
| 912 | } | 971 | } |
| 913 | 972 | ||
| 973 | /// Request DMA to stop. | ||
| 974 | /// | ||
| 975 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 914 | pub fn request_stop(&mut self) { | 976 | pub fn request_stop(&mut self) { |
| 915 | let ch = self.channel.regs().st(self.channel.num()); | 977 | let ch = self.channel.regs().st(self.channel.num()); |
| 916 | 978 | ||
| @@ -922,6 +984,10 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 922 | }); | 984 | }); |
| 923 | } | 985 | } |
| 924 | 986 | ||
| 987 | /// Return whether DMA is still running. | ||
| 988 | /// | ||
| 989 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 990 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 925 | pub fn is_running(&mut self) -> bool { | 991 | pub fn is_running(&mut self) -> bool { |
| 926 | let ch = self.channel.regs().st(self.channel.num()); | 992 | let ch = self.channel.regs().st(self.channel.num()); |
| 927 | ch.cr().read().en() | 993 | ch.cr().read().en() |
diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 20601dc86..9cd494724 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs | |||
| @@ -22,11 +22,15 @@ pub(crate) mod dmamux_sealed { | |||
| 22 | } | 22 | } |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | /// DMAMUX1 instance. | ||
| 25 | pub struct DMAMUX1; | 26 | pub struct DMAMUX1; |
| 27 | /// DMAMUX2 instance. | ||
| 26 | #[cfg(stm32h7)] | 28 | #[cfg(stm32h7)] |
| 27 | pub struct DMAMUX2; | 29 | pub struct DMAMUX2; |
| 28 | 30 | ||
| 31 | /// DMAMUX channel trait. | ||
| 29 | pub trait MuxChannel: dmamux_sealed::MuxChannel { | 32 | pub trait MuxChannel: dmamux_sealed::MuxChannel { |
| 33 | /// DMAMUX instance this channel is on. | ||
| 30 | type Mux; | 34 | type Mux; |
| 31 | } | 35 | } |
| 32 | 36 | ||
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index b061415eb..34b2426b9 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs | |||
| @@ -16,6 +16,7 @@ use crate::interrupt::Priority; | |||
| 16 | use crate::pac; | 16 | use crate::pac; |
| 17 | use crate::pac::gpdma::vals; | 17 | use crate::pac::gpdma::vals; |
| 18 | 18 | ||
| 19 | /// GPDMA transfer options. | ||
| 19 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 21 | #[non_exhaustive] | 22 | #[non_exhaustive] |
| @@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in | |||
| 113 | } | 114 | } |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 117 | /// DMA request type alias. (also known as DMA channel number in some chips) | ||
| 116 | pub type Request = u8; | 118 | pub type Request = u8; |
| 117 | 119 | ||
| 120 | /// DMA channel. | ||
| 118 | #[cfg(dmamux)] | 121 | #[cfg(dmamux)] |
| 119 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} | 122 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} |
| 123 | /// DMA channel. | ||
| 120 | #[cfg(not(dmamux))] | 124 | #[cfg(not(dmamux))] |
| 121 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} | 125 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} |
| 122 | 126 | ||
| @@ -131,12 +135,14 @@ pub(crate) mod sealed { | |||
| 131 | } | 135 | } |
| 132 | } | 136 | } |
| 133 | 137 | ||
| 138 | /// DMA transfer. | ||
| 134 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 139 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 135 | pub struct Transfer<'a, C: Channel> { | 140 | pub struct Transfer<'a, C: Channel> { |
| 136 | channel: PeripheralRef<'a, C>, | 141 | channel: PeripheralRef<'a, C>, |
| 137 | } | 142 | } |
| 138 | 143 | ||
| 139 | impl<'a, C: Channel> Transfer<'a, C> { | 144 | impl<'a, C: Channel> Transfer<'a, C> { |
| 145 | /// Create a new read DMA transfer (peripheral to memory). | ||
| 140 | pub unsafe fn new_read<W: Word>( | 146 | pub unsafe fn new_read<W: Word>( |
| 141 | channel: impl Peripheral<P = C> + 'a, | 147 | channel: impl Peripheral<P = C> + 'a, |
| 142 | request: Request, | 148 | request: Request, |
| @@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 147 | Self::new_read_raw(channel, request, peri_addr, buf, options) | 153 | Self::new_read_raw(channel, request, peri_addr, buf, options) |
| 148 | } | 154 | } |
| 149 | 155 | ||
| 156 | /// Create a new read DMA transfer (peripheral to memory), using raw pointers. | ||
| 150 | pub unsafe fn new_read_raw<W: Word>( | 157 | pub unsafe fn new_read_raw<W: Word>( |
| 151 | channel: impl Peripheral<P = C> + 'a, | 158 | channel: impl Peripheral<P = C> + 'a, |
| 152 | request: Request, | 159 | request: Request, |
| @@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 172 | ) | 179 | ) |
| 173 | } | 180 | } |
| 174 | 181 | ||
| 182 | /// Create a new write DMA transfer (memory to peripheral). | ||
| 175 | pub unsafe fn new_write<W: Word>( | 183 | pub unsafe fn new_write<W: Word>( |
| 176 | channel: impl Peripheral<P = C> + 'a, | 184 | channel: impl Peripheral<P = C> + 'a, |
| 177 | request: Request, | 185 | request: Request, |
| @@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 182 | Self::new_write_raw(channel, request, buf, peri_addr, options) | 190 | Self::new_write_raw(channel, request, buf, peri_addr, options) |
| 183 | } | 191 | } |
| 184 | 192 | ||
| 193 | /// Create a new write DMA transfer (memory to peripheral), using raw pointers. | ||
| 185 | pub unsafe fn new_write_raw<W: Word>( | 194 | pub unsafe fn new_write_raw<W: Word>( |
| 186 | channel: impl Peripheral<P = C> + 'a, | 195 | channel: impl Peripheral<P = C> + 'a, |
| 187 | request: Request, | 196 | request: Request, |
| @@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 207 | ) | 216 | ) |
| 208 | } | 217 | } |
| 209 | 218 | ||
| 219 | /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. | ||
| 210 | pub unsafe fn new_write_repeated<W: Word>( | 220 | pub unsafe fn new_write_repeated<W: Word>( |
| 211 | channel: impl Peripheral<P = C> + 'a, | 221 | channel: impl Peripheral<P = C> + 'a, |
| 212 | request: Request, | 222 | request: Request, |
| @@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 297 | this | 307 | this |
| 298 | } | 308 | } |
| 299 | 309 | ||
| 310 | /// Request the transfer to stop. | ||
| 311 | /// | ||
| 312 | /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. | ||
| 300 | pub fn request_stop(&mut self) { | 313 | pub fn request_stop(&mut self) { |
| 301 | let ch = self.channel.regs().ch(self.channel.num()); | 314 | let ch = self.channel.regs().ch(self.channel.num()); |
| 302 | ch.cr().modify(|w| { | 315 | ch.cr().modify(|w| { |
| @@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 304 | }) | 317 | }) |
| 305 | } | 318 | } |
| 306 | 319 | ||
| 320 | /// Return whether this transfer is still running. | ||
| 321 | /// | ||
| 322 | /// If this returns `false`, it can be because either the transfer finished, or | ||
| 323 | /// it was requested to stop early with [`request_stop`](Self::request_stop). | ||
| 307 | pub fn is_running(&mut self) -> bool { | 324 | pub fn is_running(&mut self) -> bool { |
| 308 | let ch = self.channel.regs().ch(self.channel.num()); | 325 | let ch = self.channel.regs().ch(self.channel.num()); |
| 309 | let sr = ch.sr().read(); | 326 | let sr = ch.sr().read(); |
| @@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> { | |||
| 317 | ch.br1().read().bndt() | 334 | ch.br1().read().bndt() |
| 318 | } | 335 | } |
| 319 | 336 | ||
| 337 | /// Blocking wait until the transfer finishes. | ||
| 320 | pub fn blocking_wait(mut self) { | 338 | pub fn blocking_wait(mut self) { |
| 321 | while self.is_running() {} | 339 | while self.is_running() {} |
| 322 | 340 | ||
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 29fced8fc..38945ac33 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Direct Memory Access (DMA) | ||
| 2 | |||
| 1 | #[cfg(dma)] | 3 | #[cfg(dma)] |
| 2 | pub(crate) mod dma; | 4 | pub(crate) mod dma; |
| 3 | #[cfg(dma)] | 5 | #[cfg(dma)] |
| @@ -39,6 +41,13 @@ enum Dir { | |||
| 39 | PeripheralToMemory, | 41 | PeripheralToMemory, |
| 40 | } | 42 | } |
| 41 | 43 | ||
| 44 | /// "No DMA" placeholder. | ||
| 45 | /// | ||
| 46 | /// You may pass this in place of a real DMA channel when creating a driver | ||
| 47 | /// to indicate it should not use DMA. | ||
| 48 | /// | ||
| 49 | /// This often causes async functionality to not be available on the instance, | ||
| 50 | /// leaving only blocking functionality. | ||
| 42 | pub struct NoDma; | 51 | pub struct NoDma; |
| 43 | 52 | ||
| 44 | impl_peripheral!(NoDma); | 53 | impl_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))] |
| 3 | pub enum WordSize { | 6 | pub enum WordSize { |
| @@ -7,6 +10,7 @@ pub enum WordSize { | |||
| 7 | } | 10 | } |
| 8 | 11 | ||
| 9 | impl WordSize { | 12 | impl 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. | ||
| 23 | pub trait Word: sealed::Word + Default + Copy + 'static { | 30 | pub 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 |
| 104 | impl GenericSMI { | 104 | impl GenericSMI { |
| 105 | /// Set the SMI polling interval. | ||
| 105 | #[cfg(feature = "time")] | 106 | #[cfg(feature = "time")] |
| 106 | pub fn set_poll_interval(&mut self, poll_interval: Duration) { | 107 | pub fn set_poll_interval(&mut self, poll_interval: Duration) { |
| 107 | self.poll_interval = poll_interval | 108 | self.poll_interval = poll_interval |
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 556aadd73..448405507 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Ethernet (ETH) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] | 4 | #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] |
| @@ -22,6 +23,14 @@ const RX_BUFFER_SIZE: usize = 1536; | |||
| 22 | #[derive(Copy, Clone)] | 23 | #[derive(Copy, Clone)] |
| 23 | pub(crate) struct Packet<const N: usize>([u8; N]); | 24 | pub(crate) struct Packet<const N: usize>([u8; N]); |
| 24 | 25 | ||
| 26 | /// Ethernet packet queue. | ||
| 27 | /// | ||
| 28 | /// This struct owns the memory used for reading and writing packets. | ||
| 29 | /// | ||
| 30 | /// `TX` is the number of packets in the transmit queue, `RX` in the receive | ||
| 31 | /// queue. A bigger queue allows the hardware to receive more packets while the | ||
| 32 | /// CPU is busy doing other things, which may increase performance (especially for RX) | ||
| 33 | /// at the cost of more RAM usage. | ||
| 25 | pub struct PacketQueue<const TX: usize, const RX: usize> { | 34 | pub struct PacketQueue<const TX: usize, const RX: usize> { |
| 26 | tx_desc: [TDes; TX], | 35 | tx_desc: [TDes; TX], |
| 27 | rx_desc: [RDes; RX], | 36 | rx_desc: [RDes; RX], |
| @@ -30,6 +39,7 @@ pub struct PacketQueue<const TX: usize, const RX: usize> { | |||
| 30 | } | 39 | } |
| 31 | 40 | ||
| 32 | impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { | 41 | impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { |
| 42 | /// Create a new packet queue. | ||
| 33 | pub const fn new() -> Self { | 43 | pub const fn new() -> Self { |
| 34 | const NEW_TDES: TDes = TDes::new(); | 44 | const NEW_TDES: TDes = TDes::new(); |
| 35 | const NEW_RDES: RDes = RDes::new(); | 45 | const NEW_RDES: RDes = RDes::new(); |
| @@ -41,7 +51,18 @@ impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { | |||
| 41 | } | 51 | } |
| 42 | } | 52 | } |
| 43 | 53 | ||
| 44 | // Allow to initialize a Self without requiring it to go on the stack | 54 | /// Initialize a packet queue in-place. |
| 55 | /// | ||
| 56 | /// This can be helpful to avoid accidentally stack-allocating the packet queue in the stack. The | ||
| 57 | /// Rust compiler can sometimes be a bit dumb when working with large owned values: if you call `new()` | ||
| 58 | /// and then store the returned PacketQueue in its final place (like a `static`), the compiler might | ||
| 59 | /// place it temporarily on the stack then move it. Since this struct is quite big, it may result | ||
| 60 | /// in a stack overflow. | ||
| 61 | /// | ||
| 62 | /// With this function, you can create an uninitialized `static` with type `MaybeUninit<PacketQueue<...>>` | ||
| 63 | /// and initialize it in-place, guaranteeing no stack usage. | ||
| 64 | /// | ||
| 65 | /// After calling this function, calling `assume_init` on the MaybeUninit is guaranteed safe. | ||
| 45 | pub fn init(this: &mut MaybeUninit<Self>) { | 66 | pub fn init(this: &mut MaybeUninit<Self>) { |
| 46 | unsafe { | 67 | unsafe { |
| 47 | this.as_mut_ptr().write_bytes(0u8, 1); | 68 | this.as_mut_ptr().write_bytes(0u8, 1); |
| @@ -93,6 +114,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> | |||
| 93 | } | 114 | } |
| 94 | } | 115 | } |
| 95 | 116 | ||
| 117 | /// `embassy-net` RX token. | ||
| 96 | pub struct RxToken<'a, 'd> { | 118 | pub struct RxToken<'a, 'd> { |
| 97 | rx: &'a mut RDesRing<'d>, | 119 | rx: &'a mut RDesRing<'d>, |
| 98 | } | 120 | } |
| @@ -110,6 +132,7 @@ impl<'a, 'd> embassy_net_driver::RxToken for RxToken<'a, 'd> { | |||
| 110 | } | 132 | } |
| 111 | } | 133 | } |
| 112 | 134 | ||
| 135 | /// `embassy-net` TX token. | ||
| 113 | pub struct TxToken<'a, 'd> { | 136 | pub struct TxToken<'a, 'd> { |
| 114 | tx: &'a mut TDesRing<'d>, | 137 | tx: &'a mut TDesRing<'d>, |
| 115 | } | 138 | } |
| @@ -159,6 +182,7 @@ pub(crate) mod sealed { | |||
| 159 | } | 182 | } |
| 160 | } | 183 | } |
| 161 | 184 | ||
| 185 | /// Ethernet instance. | ||
| 162 | pub trait Instance: sealed::Instance + Send + 'static {} | 186 | pub trait Instance: sealed::Instance + Send + 'static {} |
| 163 | 187 | ||
| 164 | impl sealed::Instance for crate::peripherals::ETH { | 188 | impl sealed::Instance for crate::peripherals::ETH { |
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 13e53f687..2ce5b3927 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -43,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl | |||
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | /// Ethernet driver. | ||
| 46 | pub struct Ethernet<'d, T: Instance, P: PHY> { | 47 | pub struct Ethernet<'d, T: Instance, P: PHY> { |
| 47 | _peri: PeripheralRef<'d, T>, | 48 | _peri: PeripheralRef<'d, T>, |
| 48 | pub(crate) tx: TDesRing<'d>, | 49 | pub(crate) tx: TDesRing<'d>, |
| @@ -266,6 +267,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | |||
| 266 | } | 267 | } |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 270 | /// Ethernet station management interface. | ||
| 269 | pub struct EthernetStationManagement<T: Instance> { | 271 | pub struct EthernetStationManagement<T: Instance> { |
| 270 | peri: PhantomData<T>, | 272 | peri: PhantomData<T>, |
| 271 | clock_range: Cr, | 273 | clock_range: Cr, |
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index c77155fea..59745cba0 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs | |||
| @@ -34,6 +34,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl | |||
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | /// Ethernet driver. | ||
| 37 | pub struct Ethernet<'d, T: Instance, P: PHY> { | 38 | pub 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 | ||
| 58 | impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { | 59 | impl<'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. | ||
| 240 | pub struct EthernetStationManagement<T: Instance> { | 243 | pub struct EthernetStationManagement<T: Instance> { |
| 241 | peri: PhantomData<T>, | 244 | peri: PhantomData<T>, |
| 242 | clock_range: u8, | 245 | clock_range: u8, |
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index dbd24804f..f83bae3ff 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! External Interrupts (EXTI) | ||
| 1 | use core::convert::Infallible; | 2 | use core::convert::Infallible; |
| 2 | use core::future::Future; | 3 | use core::future::Future; |
| 3 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| @@ -39,7 +40,7 @@ fn exticr_regs() -> pac::afio::Afio { | |||
| 39 | pac::AFIO | 40 | pac::AFIO |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | pub unsafe fn on_irq() { | 43 | unsafe fn on_irq() { |
| 43 | #[cfg(feature = "low-power")] | 44 | #[cfg(feature = "low-power")] |
| 44 | crate::low_power::on_wakeup_irq(); | 45 | crate::low_power::on_wakeup_irq(); |
| 45 | 46 | ||
| @@ -85,7 +86,13 @@ impl Iterator for BitIter { | |||
| 85 | } | 86 | } |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | /// EXTI input driver | 89 | /// EXTI input driver. |
| 90 | /// | ||
| 91 | /// This driver augments a GPIO `Input` with EXTI functionality. EXTI is not | ||
| 92 | /// built into `Input` itself because it needs to take ownership of the corresponding | ||
| 93 | /// EXTI channel, which is a limited resource. | ||
| 94 | /// | ||
| 95 | /// Pins PA5, PB5, PC5... all use EXTI channel 5, so you can't use EXTI on, say, PA5 and PC5 at the same time. | ||
| 89 | pub struct ExtiInput<'d, T: GpioPin> { | 96 | pub struct ExtiInput<'d, T: GpioPin> { |
| 90 | pin: Input<'d, T>, | 97 | pin: Input<'d, T>, |
| 91 | } | 98 | } |
| @@ -93,23 +100,30 @@ pub struct ExtiInput<'d, T: GpioPin> { | |||
| 93 | impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} | 100 | impl<'d, T: GpioPin> Unpin for ExtiInput<'d, T> {} |
| 94 | 101 | ||
| 95 | impl<'d, T: GpioPin> ExtiInput<'d, T> { | 102 | impl<'d, T: GpioPin> ExtiInput<'d, T> { |
| 103 | /// Create an EXTI input. | ||
| 96 | pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { | 104 | pub fn new(pin: Input<'d, T>, _ch: impl Peripheral<P = T::ExtiChannel> + 'd) -> Self { |
| 97 | Self { pin } | 105 | Self { pin } |
| 98 | } | 106 | } |
| 99 | 107 | ||
| 100 | pub fn is_high(&self) -> bool { | 108 | /// Get whether the pin is high. |
| 109 | pub fn is_high(&mut self) -> bool { | ||
| 101 | self.pin.is_high() | 110 | self.pin.is_high() |
| 102 | } | 111 | } |
| 103 | 112 | ||
| 104 | pub fn is_low(&self) -> bool { | 113 | /// Get whether the pin is low. |
| 114 | pub fn is_low(&mut self) -> bool { | ||
| 105 | self.pin.is_low() | 115 | self.pin.is_low() |
| 106 | } | 116 | } |
| 107 | 117 | ||
| 108 | pub fn get_level(&self) -> Level { | 118 | /// Get the pin level. |
| 119 | pub fn get_level(&mut self) -> Level { | ||
| 109 | self.pin.get_level() | 120 | self.pin.get_level() |
| 110 | } | 121 | } |
| 111 | 122 | ||
| 112 | pub async fn wait_for_high<'a>(&'a mut self) { | 123 | /// Asynchronously wait until the pin is high. |
| 124 | /// | ||
| 125 | /// This returns immediately if the pin is already high. | ||
| 126 | pub async fn wait_for_high(&mut self) { | ||
| 113 | let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); | 127 | let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); |
| 114 | if self.is_high() { | 128 | if self.is_high() { |
| 115 | return; | 129 | return; |
| @@ -117,7 +131,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { | |||
| 117 | fut.await | 131 | fut.await |
| 118 | } | 132 | } |
| 119 | 133 | ||
| 120 | pub async fn wait_for_low<'a>(&'a mut self) { | 134 | /// Asynchronously wait until the pin is low. |
| 135 | /// | ||
| 136 | /// This returns immediately if the pin is already low. | ||
| 137 | pub async fn wait_for_low(&mut self) { | ||
| 121 | let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); | 138 | let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); |
| 122 | if self.is_low() { | 139 | if self.is_low() { |
| 123 | return; | 140 | return; |
| @@ -125,15 +142,22 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> { | |||
| 125 | fut.await | 142 | fut.await |
| 126 | } | 143 | } |
| 127 | 144 | ||
| 128 | pub async fn wait_for_rising_edge<'a>(&'a mut self) { | 145 | /// Asynchronously wait until the pin sees a rising edge. |
| 146 | /// | ||
| 147 | /// If the pin is already high, it will wait for it to go low then back high. | ||
| 148 | pub async fn wait_for_rising_edge(&mut self) { | ||
| 129 | ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await | 149 | ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await |
| 130 | } | 150 | } |
| 131 | 151 | ||
| 132 | pub async fn wait_for_falling_edge<'a>(&'a mut self) { | 152 | /// Asynchronously wait until the pin sees a falling edge. |
| 153 | /// | ||
| 154 | /// If the pin is already low, it will wait for it to go high then back low. | ||
| 155 | pub async fn wait_for_falling_edge(&mut self) { | ||
| 133 | ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await | 156 | ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await |
| 134 | } | 157 | } |
| 135 | 158 | ||
| 136 | pub async fn wait_for_any_edge<'a>(&'a mut self) { | 159 | /// Asynchronously wait until the pin sees any edge (either rising or falling). |
| 160 | pub async fn wait_for_any_edge(&mut self) { | ||
| 137 | ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await | 161 | ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await |
| 138 | } | 162 | } |
| 139 | } | 163 | } |
| @@ -142,11 +166,11 @@ impl<'d, T: GpioPin> embedded_hal_02::digital::v2::InputPin for ExtiInput<'d, T> | |||
| 142 | type Error = Infallible; | 166 | type Error = Infallible; |
| 143 | 167 | ||
| 144 | fn is_high(&self) -> Result<bool, Self::Error> { | 168 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 145 | Ok(self.is_high()) | 169 | Ok(!self.pin.pin.ref_is_low()) |
| 146 | } | 170 | } |
| 147 | 171 | ||
| 148 | fn is_low(&self) -> Result<bool, Self::Error> { | 172 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 149 | Ok(self.is_low()) | 173 | Ok(self.pin.pin.ref_is_low()) |
| 150 | } | 174 | } |
| 151 | } | 175 | } |
| 152 | 176 | ||
| @@ -155,11 +179,11 @@ impl<'d, T: GpioPin> embedded_hal_1::digital::ErrorType for ExtiInput<'d, T> { | |||
| 155 | } | 179 | } |
| 156 | 180 | ||
| 157 | impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { | 181 | impl<'d, T: GpioPin> embedded_hal_1::digital::InputPin for ExtiInput<'d, T> { |
| 158 | fn is_high(&self) -> Result<bool, Self::Error> { | 182 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 159 | Ok(self.is_high()) | 183 | Ok(self.is_high()) |
| 160 | } | 184 | } |
| 161 | 185 | ||
| 162 | fn is_low(&self) -> Result<bool, Self::Error> { | 186 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 163 | Ok(self.is_low()) | 187 | Ok(self.is_low()) |
| 164 | } | 188 | } |
| 165 | } | 189 | } |
| @@ -284,6 +308,7 @@ macro_rules! foreach_exti_irq { | |||
| 284 | 308 | ||
| 285 | macro_rules! impl_irq { | 309 | macro_rules! impl_irq { |
| 286 | ($e:ident) => { | 310 | ($e:ident) => { |
| 311 | #[allow(non_snake_case)] | ||
| 287 | #[cfg(feature = "rt")] | 312 | #[cfg(feature = "rt")] |
| 288 | #[interrupt] | 313 | #[interrupt] |
| 289 | unsafe fn $e() { | 314 | unsafe fn $e() { |
| @@ -298,8 +323,16 @@ pub(crate) mod sealed { | |||
| 298 | pub trait Channel {} | 323 | pub trait Channel {} |
| 299 | } | 324 | } |
| 300 | 325 | ||
| 326 | /// EXTI channel trait. | ||
| 301 | pub trait Channel: sealed::Channel + Sized { | 327 | pub trait Channel: sealed::Channel + Sized { |
| 328 | /// Get the EXTI channel number. | ||
| 302 | fn number(&self) -> usize; | 329 | fn number(&self) -> usize; |
| 330 | |||
| 331 | /// Type-erase (degrade) this channel into an `AnyChannel`. | ||
| 332 | /// | ||
| 333 | /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which | ||
| 334 | /// are all different types, into the same type. It is useful for | ||
| 335 | /// creating arrays of channels, or avoiding generics. | ||
| 303 | fn degrade(self) -> AnyChannel { | 336 | fn degrade(self) -> AnyChannel { |
| 304 | AnyChannel { | 337 | AnyChannel { |
| 305 | number: self.number() as u8, | 338 | number: self.number() as u8, |
| @@ -307,9 +340,13 @@ pub trait Channel: sealed::Channel + Sized { | |||
| 307 | } | 340 | } |
| 308 | } | 341 | } |
| 309 | 342 | ||
| 343 | /// Type-erased (degraded) EXTI channel. | ||
| 344 | /// | ||
| 345 | /// This represents ownership over any EXTI channel, known at runtime. | ||
| 310 | pub struct AnyChannel { | 346 | pub struct AnyChannel { |
| 311 | number: u8, | 347 | number: u8, |
| 312 | } | 348 | } |
| 349 | |||
| 313 | impl_peripheral!(AnyChannel); | 350 | impl_peripheral!(AnyChannel); |
| 314 | impl sealed::Channel for AnyChannel {} | 351 | impl sealed::Channel for AnyChannel {} |
| 315 | impl Channel for AnyChannel { | 352 | impl Channel for AnyChannel { |
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index eae40c7ec..97eaece81 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs | |||
| @@ -17,6 +17,7 @@ use crate::{interrupt, Peripheral}; | |||
| 17 | pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); | 17 | pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); |
| 18 | 18 | ||
| 19 | impl<'d> Flash<'d, Async> { | 19 | impl<'d> Flash<'d, Async> { |
| 20 | /// Create a new flash driver with async capabilities. | ||
| 20 | pub fn new( | 21 | pub fn new( |
| 21 | p: impl Peripheral<P = FLASH> + 'd, | 22 | p: impl Peripheral<P = FLASH> + 'd, |
| 22 | _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd, | 23 | _irq: impl interrupt::typelevel::Binding<crate::interrupt::typelevel::FLASH, InterruptHandler> + 'd, |
| @@ -32,15 +33,26 @@ impl<'d> Flash<'d, Async> { | |||
| 32 | } | 33 | } |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 36 | /// Split this flash driver into one instance per flash memory region. | ||
| 37 | /// | ||
| 38 | /// See module-level documentation for details on how memory regions work. | ||
| 35 | pub fn into_regions(self) -> FlashLayout<'d, Async> { | 39 | pub fn into_regions(self) -> FlashLayout<'d, Async> { |
| 36 | assert!(family::is_default_layout()); | 40 | assert!(family::is_default_layout()); |
| 37 | FlashLayout::new(self.inner) | 41 | FlashLayout::new(self.inner) |
| 38 | } | 42 | } |
| 39 | 43 | ||
| 44 | /// Async write. | ||
| 45 | /// | ||
| 46 | /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||
| 47 | /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. | ||
| 40 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 48 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 41 | unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } | 49 | unsafe { write_chunked(FLASH_BASE as u32, FLASH_SIZE as u32, offset, bytes).await } |
| 42 | } | 50 | } |
| 43 | 51 | ||
| 52 | /// Async erase. | ||
| 53 | /// | ||
| 54 | /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. | ||
| 55 | /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. | ||
| 44 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 56 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 45 | unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } | 57 | unsafe { erase_sectored(FLASH_BASE as u32, from, to).await } |
| 46 | } | 58 | } |
| @@ -59,7 +71,7 @@ impl embedded_storage_async::nor_flash::ReadNorFlash for Flash<'_, Async> { | |||
| 59 | const READ_SIZE: usize = super::READ_SIZE; | 71 | const READ_SIZE: usize = super::READ_SIZE; |
| 60 | 72 | ||
| 61 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 73 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 62 | self.read(offset, bytes) | 74 | self.blocking_read(offset, bytes) |
| 63 | } | 75 | } |
| 64 | 76 | ||
| 65 | fn capacity(&self) -> usize { | 77 | fn capacity(&self) -> usize { |
| @@ -141,15 +153,20 @@ pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Resu | |||
| 141 | foreach_flash_region! { | 153 | foreach_flash_region! { |
| 142 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { | 154 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { |
| 143 | impl crate::_generated::flash_regions::$type_name<'_, Async> { | 155 | impl crate::_generated::flash_regions::$type_name<'_, Async> { |
| 156 | /// Async read. | ||
| 157 | /// | ||
| 158 | /// Note: reading from flash can't actually block, so this is the same as `blocking_read`. | ||
| 144 | pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 159 | pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 145 | blocking_read(self.0.base, self.0.size, offset, bytes) | 160 | blocking_read(self.0.base, self.0.size, offset, bytes) |
| 146 | } | 161 | } |
| 147 | 162 | ||
| 163 | /// Async write. | ||
| 148 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 164 | pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 149 | let _guard = REGION_ACCESS.lock().await; | 165 | let _guard = REGION_ACCESS.lock().await; |
| 150 | unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } | 166 | unsafe { write_chunked(self.0.base, self.0.size, offset, bytes).await } |
| 151 | } | 167 | } |
| 152 | 168 | ||
| 169 | /// Async erase. | ||
| 153 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 170 | pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 154 | let _guard = REGION_ACCESS.lock().await; | 171 | let _guard = REGION_ACCESS.lock().await; |
| 155 | unsafe { erase_sectored(self.0.base, from, to).await } | 172 | unsafe { erase_sectored(self.0.base, from, to).await } |
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 8acad1c7c..f8561edb3 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs | |||
| @@ -12,12 +12,14 @@ use super::{ | |||
| 12 | use crate::peripherals::FLASH; | 12 | use crate::peripherals::FLASH; |
| 13 | use crate::Peripheral; | 13 | use crate::Peripheral; |
| 14 | 14 | ||
| 15 | /// Internal flash memory driver. | ||
| 15 | pub struct Flash<'d, MODE = Async> { | 16 | pub 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 | ||
| 20 | impl<'d> Flash<'d, Blocking> { | 21 | impl<'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 | ||
| 31 | impl<'d, MODE> Flash<'d, MODE> { | 33 | impl<'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> { | |||
| 230 | foreach_flash_region! { | 247 | foreach_flash_region! { |
| 231 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { | 248 | ($type_name:ident, $write_size:literal, $erase_size:literal) => { |
| 232 | impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> { | 249 | impl<MODE> crate::_generated::flash_regions::$type_name<'_, MODE> { |
| 250 | /// Blocking read. | ||
| 251 | /// | ||
| 252 | /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||
| 253 | /// For example, to read address `0x0800_1234` you have to use offset `0x1234`. | ||
| 233 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 254 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 234 | blocking_read(self.0.base, self.0.size, offset, bytes) | 255 | blocking_read(self.0.base, self.0.size, offset, bytes) |
| 235 | } | 256 | } |
| 236 | } | 257 | } |
| 237 | 258 | ||
| 238 | impl crate::_generated::flash_regions::$type_name<'_, Blocking> { | 259 | impl crate::_generated::flash_regions::$type_name<'_, Blocking> { |
| 260 | /// Blocking write. | ||
| 261 | /// | ||
| 262 | /// NOTE: `offset` is an offset from the flash start, NOT an absolute address. | ||
| 263 | /// For example, to write address `0x0800_1234` you have to use offset `0x1234`. | ||
| 239 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 264 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 240 | unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } | 265 | unsafe { blocking_write(self.0.base, self.0.size, offset, bytes, write_chunk_with_critical_section) } |
| 241 | } | 266 | } |
| 242 | 267 | ||
| 268 | /// Blocking erase. | ||
| 269 | /// | ||
| 270 | /// NOTE: `from` and `to` are offsets from the flash start, NOT an absolute address. | ||
| 271 | /// For example, to erase address `0x0801_0000` you have to use offset `0x1_0000`. | ||
| 243 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 272 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 244 | unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } | 273 | unsafe { blocking_erase(self.0.base, from, to, erase_sector_with_critical_section) } |
| 245 | } | 274 | } |
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 1ab8435a0..c0a8d7022 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs | |||
| @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | |||
| 6 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 7 | use crate::pac; | 7 | use crate::pac; |
| 8 | 8 | ||
| 9 | pub const fn is_default_layout() -> bool { | 9 | pub(crate) const fn is_default_layout() -> bool { |
| 10 | true | 10 | true |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | 13 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 14 | &FLASH_REGIONS | 14 | &FLASH_REGIONS |
| 15 | } | 15 | } |
| 16 | 16 | ||
| @@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 79 | 79 | ||
| 80 | pub(crate) unsafe fn clear_all_err() { | 80 | pub(crate) unsafe fn clear_all_err() { |
| 81 | // read and write back the same value. | 81 | // read and write back the same value. |
| 82 | // This clears all "write 0 to clear" bits. | 82 | // This clears all "write 1 to clear" bits. |
| 83 | pac::FLASH.sr().modify(|_| {}); | 83 | pac::FLASH.sr().modify(|_| {}); |
| 84 | } | 84 | } |
| 85 | 85 | ||
diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 7e6d7ca26..817ccef4d 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs | |||
| @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | |||
| 6 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 7 | use crate::pac; | 7 | use crate::pac; |
| 8 | 8 | ||
| 9 | pub const fn is_default_layout() -> bool { | 9 | pub(crate) const fn is_default_layout() -> bool { |
| 10 | true | 10 | true |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | 13 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 14 | &FLASH_REGIONS | 14 | &FLASH_REGIONS |
| 15 | } | 15 | } |
| 16 | 16 | ||
| @@ -79,7 +79,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 79 | 79 | ||
| 80 | pub(crate) unsafe fn clear_all_err() { | 80 | pub(crate) unsafe fn clear_all_err() { |
| 81 | // read and write back the same value. | 81 | // read and write back the same value. |
| 82 | // This clears all "write 0 to clear" bits. | 82 | // This clears all "write 1 to clear" bits. |
| 83 | pac::FLASH.sr().modify(|_| {}); | 83 | pac::FLASH.sr().modify(|_| {}); |
| 84 | } | 84 | } |
| 85 | 85 | ||
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 5d07020ce..2671dfb04 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs | |||
| @@ -9,7 +9,7 @@ use pac::FLASH_SIZE; | |||
| 9 | use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | 9 | use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 10 | use crate::flash::Error; | 10 | use crate::flash::Error; |
| 11 | use crate::pac; | 11 | use crate::pac; |
| 12 | 12 | #[allow(missing_docs)] // TODO | |
| 13 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] | 13 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] |
| 14 | mod alt_regions { | 14 | mod alt_regions { |
| 15 | use core::marker::PhantomData; | 15 | use core::marker::PhantomData; |
| @@ -337,7 +337,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 337 | 337 | ||
| 338 | pub(crate) fn clear_all_err() { | 338 | pub(crate) fn clear_all_err() { |
| 339 | // read and write back the same value. | 339 | // read and write back the same value. |
| 340 | // This clears all "write 0 to clear" bits. | 340 | // This clears all "write 1 to clear" bits. |
| 341 | pac::FLASH.sr().modify(|_| {}); | 341 | pac::FLASH.sr().modify(|_| {}); |
| 342 | } | 342 | } |
| 343 | 343 | ||
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index b52231ca8..6b3e66ac6 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs | |||
| @@ -6,11 +6,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | |||
| 6 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 7 | use crate::pac; | 7 | use crate::pac; |
| 8 | 8 | ||
| 9 | pub const fn is_default_layout() -> bool { | 9 | pub(crate) const fn is_default_layout() -> bool { |
| 10 | true | 10 | true |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | 13 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 14 | &FLASH_REGIONS | 14 | &FLASH_REGIONS |
| 15 | } | 15 | } |
| 16 | 16 | ||
| @@ -69,7 +69,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 69 | 69 | ||
| 70 | pub(crate) unsafe fn clear_all_err() { | 70 | pub(crate) unsafe fn clear_all_err() { |
| 71 | // read and write back the same value. | 71 | // read and write back the same value. |
| 72 | // This clears all "write 0 to clear" bits. | 72 | // This clears all "write 1 to clear" bits. |
| 73 | pac::FLASH.sr().modify(|_| {}); | 73 | pac::FLASH.sr().modify(|_| {}); |
| 74 | } | 74 | } |
| 75 | 75 | ||
diff --git a/embassy-stm32/src/flash/g0.rs b/embassy-stm32/src/flash/g.rs index 19a388970..d97b4a932 100644 --- a/embassy-stm32/src/flash/g0.rs +++ b/embassy-stm32/src/flash/g.rs | |||
| @@ -8,11 +8,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | |||
| 8 | use crate::flash::Error; | 8 | use crate::flash::Error; |
| 9 | use crate::pac; | 9 | use crate::pac; |
| 10 | 10 | ||
| 11 | pub const fn is_default_layout() -> bool { | 11 | pub(crate) const fn is_default_layout() -> bool { |
| 12 | true | 12 | true |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | 15 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 16 | &FLASH_REGIONS | 16 | &FLASH_REGIONS |
| 17 | } | 17 | } |
| 18 | 18 | ||
| @@ -92,6 +92,6 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { | |||
| 92 | 92 | ||
| 93 | pub(crate) unsafe fn clear_all_err() { | 93 | pub(crate) unsafe fn clear_all_err() { |
| 94 | // read and write back the same value. | 94 | // read and write back the same value. |
| 95 | // This clears all "write 0 to clear" bits. | 95 | // This clears all "write 1 to clear" bits. |
| 96 | pac::FLASH.sr().modify(|_| {}); | 96 | pac::FLASH.sr().modify(|_| {}); |
| 97 | } | 97 | } |
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index b064fd6ea..65d163d29 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs | |||
| @@ -6,7 +6,7 @@ use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; | |||
| 6 | use crate::flash::Error; | 6 | use crate::flash::Error; |
| 7 | use crate::pac; | 7 | use crate::pac; |
| 8 | 8 | ||
| 9 | pub const fn is_default_layout() -> bool { | 9 | pub(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 | ||
| 17 | pub fn get_flash_regions() -> &'static [&'static FlashRegion] { | 17 | pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 18 | &FLASH_REGIONS | 18 | &FLASH_REGIONS |
| 19 | } | 19 | } |
| 20 | 20 | ||
| @@ -113,7 +113,7 @@ pub(crate) unsafe fn clear_all_err() { | |||
| 113 | 113 | ||
| 114 | unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { | 114 | unsafe fn bank_clear_all_err(bank: pac::flash::Bank) { |
| 115 | // read and write back the same value. | 115 | // read and write back the same value. |
| 116 | // This clears all "write 0 to clear" bits. | 116 | // This clears all "write 1 to clear" bits. |
| 117 | bank.sr().modify(|_| {}); | 117 | bank.sr().modify(|_| {}); |
| 118 | } | 118 | } |
| 119 | 119 | ||
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 1db0da923..0b332dc61 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs | |||
| @@ -5,11 +5,11 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | |||
| 5 | use crate::flash::Error; | 5 | use crate::flash::Error; |
| 6 | use crate::pac; | 6 | use crate::pac; |
| 7 | 7 | ||
| 8 | pub const fn is_default_layout() -> bool { | 8 | pub(crate) const fn is_default_layout() -> bool { |
| 9 | true | 9 | true |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | 12 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 13 | &FLASH_REGIONS | 13 | &FLASH_REGIONS |
| 14 | } | 14 | } |
| 15 | 15 | ||
| @@ -120,7 +120,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 120 | 120 | ||
| 121 | pub(crate) unsafe fn clear_all_err() { | 121 | pub(crate) unsafe fn clear_all_err() { |
| 122 | // read and write back the same value. | 122 | // read and write back the same value. |
| 123 | // This clears all "write 0 to clear" bits. | 123 | // This clears all "write 1 to clear" bits. |
| 124 | pac::FLASH.sr().modify(|_| {}); | 124 | pac::FLASH.sr().modify(|_| {}); |
| 125 | } | 125 | } |
| 126 | 126 | ||
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index fb20dcd38..cbf5c25b2 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Flash memory (FLASH) | ||
| 1 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; | 2 | use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; |
| 2 | 3 | ||
| 3 | #[cfg(flash_f4)] | 4 | #[cfg(flash_f4)] |
| @@ -14,62 +15,96 @@ pub use crate::_generated::flash_regions::*; | |||
| 14 | pub use crate::_generated::MAX_ERASE_SIZE; | 15 | pub use crate::_generated::MAX_ERASE_SIZE; |
| 15 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; | 16 | pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; |
| 16 | 17 | ||
| 18 | /// Get whether the default flash layout is being used. | ||
| 19 | /// | ||
| 20 | /// In some chips, dual-bank is not default. This will then return `false` | ||
| 21 | /// when dual-bank is enabled. | ||
| 22 | pub fn is_default_layout() -> bool { | ||
| 23 | family::is_default_layout() | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Get all flash regions. | ||
| 27 | pub fn get_flash_regions() -> &'static [&'static FlashRegion] { | ||
| 28 | family::get_flash_regions() | ||
| 29 | } | ||
| 30 | |||
| 31 | /// Read size (always 1) | ||
| 17 | pub const READ_SIZE: usize = 1; | 32 | pub const READ_SIZE: usize = 1; |
| 18 | 33 | ||
| 19 | pub struct Blocking; | 34 | /// Blocking flash mode typestate. |
| 20 | pub struct Async; | 35 | pub enum Blocking {} |
| 36 | /// Async flash mode typestate. | ||
| 37 | pub enum Async {} | ||
| 21 | 38 | ||
| 39 | /// Flash memory region | ||
| 22 | #[derive(Debug)] | 40 | #[derive(Debug)] |
| 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 41 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 24 | pub struct FlashRegion { | 42 | pub struct FlashRegion { |
| 43 | /// Bank number. | ||
| 25 | pub bank: FlashBank, | 44 | pub bank: FlashBank, |
| 45 | /// Absolute base address. | ||
| 26 | pub base: u32, | 46 | pub base: u32, |
| 47 | /// Size in bytes. | ||
| 27 | pub size: u32, | 48 | pub size: u32, |
| 49 | /// Erase size (sector size). | ||
| 28 | pub erase_size: u32, | 50 | pub erase_size: u32, |
| 51 | /// Minimum write size. | ||
| 29 | pub write_size: u32, | 52 | pub write_size: u32, |
| 53 | /// Erase value (usually `0xFF`, but is `0x00` in some chips) | ||
| 30 | pub erase_value: u8, | 54 | pub erase_value: u8, |
| 31 | pub(crate) _ensure_internal: (), | 55 | pub(crate) _ensure_internal: (), |
| 32 | } | 56 | } |
| 33 | 57 | ||
| 58 | impl FlashRegion { | ||
| 59 | /// Absolute end address. | ||
| 60 | pub const fn end(&self) -> u32 { | ||
| 61 | self.base + self.size | ||
| 62 | } | ||
| 63 | |||
| 64 | /// Number of sectors in the region. | ||
| 65 | pub const fn sectors(&self) -> u8 { | ||
| 66 | (self.size / self.erase_size) as u8 | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | /// Flash sector. | ||
| 34 | #[derive(Debug, PartialEq)] | 71 | #[derive(Debug, PartialEq)] |
| 35 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 72 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 36 | pub struct FlashSector { | 73 | pub struct FlashSector { |
| 74 | /// Bank number. | ||
| 37 | pub bank: FlashBank, | 75 | pub bank: FlashBank, |
| 76 | /// Sector number within the bank. | ||
| 38 | pub index_in_bank: u8, | 77 | pub index_in_bank: u8, |
| 78 | /// Absolute start address. | ||
| 39 | pub start: u32, | 79 | pub start: u32, |
| 80 | /// Size in bytes. | ||
| 40 | pub size: u32, | 81 | pub size: u32, |
| 41 | } | 82 | } |
| 42 | 83 | ||
| 84 | /// Flash bank. | ||
| 43 | #[derive(Clone, Copy, Debug, PartialEq)] | 85 | #[derive(Clone, Copy, Debug, PartialEq)] |
| 44 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 86 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 45 | pub enum FlashBank { | 87 | pub enum FlashBank { |
| 88 | /// Bank 1 | ||
| 46 | Bank1 = 0, | 89 | Bank1 = 0, |
| 90 | /// Bank 2 | ||
| 47 | Bank2 = 1, | 91 | Bank2 = 1, |
| 92 | /// OTP region | ||
| 48 | Otp, | 93 | Otp, |
| 49 | } | 94 | } |
| 50 | 95 | ||
| 51 | impl FlashRegion { | ||
| 52 | pub const fn end(&self) -> u32 { | ||
| 53 | self.base + self.size | ||
| 54 | } | ||
| 55 | |||
| 56 | pub const fn sectors(&self) -> u8 { | ||
| 57 | (self.size / self.erase_size) as u8 | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] | 96 | #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] |
| 62 | #[cfg_attr(flash_f0, path = "f0.rs")] | 97 | #[cfg_attr(flash_f0, path = "f0.rs")] |
| 63 | #[cfg_attr(flash_f3, path = "f3.rs")] | 98 | #[cfg_attr(flash_f3, path = "f3.rs")] |
| 64 | #[cfg_attr(flash_f4, path = "f4.rs")] | 99 | #[cfg_attr(flash_f4, path = "f4.rs")] |
| 65 | #[cfg_attr(flash_f7, path = "f7.rs")] | 100 | #[cfg_attr(flash_f7, path = "f7.rs")] |
| 66 | #[cfg_attr(flash_g0, path = "g0.rs")] | 101 | #[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")] |
| 67 | #[cfg_attr(flash_h7, path = "h7.rs")] | 102 | #[cfg_attr(flash_h7, path = "h7.rs")] |
| 68 | #[cfg_attr(flash_h7ab, path = "h7.rs")] | 103 | #[cfg_attr(flash_h7ab, path = "h7.rs")] |
| 69 | #[cfg_attr( | 104 | #[cfg_attr( |
| 70 | not(any( | 105 | not(any( |
| 71 | flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7, | 106 | flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_g4, |
| 72 | flash_h7ab | 107 | flash_h7, flash_h7ab |
| 73 | )), | 108 | )), |
| 74 | path = "other.rs" | 109 | path = "other.rs" |
| 75 | )] | 110 | )] |
| @@ -78,6 +113,10 @@ mod family; | |||
| 78 | #[allow(unused_imports)] | 113 | #[allow(unused_imports)] |
| 79 | pub use family::*; | 114 | pub use family::*; |
| 80 | 115 | ||
| 116 | /// Flash error | ||
| 117 | /// | ||
| 118 | /// See STM32 Reference Manual for your chip for details. | ||
| 119 | #[allow(missing_docs)] | ||
| 81 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 120 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 82 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 121 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 83 | pub enum Error { | 122 | pub 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 | ||
| 3 | use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; | 3 | use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 4 | 4 | ||
| 5 | pub const fn is_default_layout() -> bool { | 5 | pub(crate) const fn is_default_layout() -> bool { |
| 6 | true | 6 | true |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { | 9 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 10 | &FLASH_REGIONS | 10 | &FLASH_REGIONS |
| 11 | } | 11 | } |
| 12 | 12 | ||
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index dd0d27217..873c8a70c 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC) | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | 3 | ||
| 3 | use embassy_hal_internal::into_ref; | 4 | use embassy_hal_internal::into_ref; |
| @@ -6,6 +7,7 @@ use crate::gpio::sealed::AFType; | |||
| 6 | use crate::gpio::{Pull, Speed}; | 7 | use crate::gpio::{Pull, Speed}; |
| 7 | use crate::Peripheral; | 8 | use crate::Peripheral; |
| 8 | 9 | ||
| 10 | /// FMC driver | ||
| 9 | pub struct Fmc<'d, T: Instance> { | 11 | pub struct Fmc<'d, T: Instance> { |
| 10 | peri: PhantomData<&'d mut T>, | 12 | peri: PhantomData<&'d mut T>, |
| 11 | } | 13 | } |
| @@ -38,6 +40,7 @@ where | |||
| 38 | T::REGS.bcr1().modify(|r| r.set_fmcen(true)); | 40 | T::REGS.bcr1().modify(|r| r.set_fmcen(true)); |
| 39 | } | 41 | } |
| 40 | 42 | ||
| 43 | /// Get the kernel clock currently in use for this FMC instance. | ||
| 41 | pub fn source_clock_hz(&self) -> u32 { | 44 | pub fn source_clock_hz(&self) -> u32 { |
| 42 | <T as crate::rcc::sealed::RccPeripheral>::frequency().0 | 45 | <T as crate::rcc::sealed::RccPeripheral>::frequency().0 |
| 43 | } | 46 | } |
| @@ -85,6 +88,7 @@ macro_rules! fmc_sdram_constructor { | |||
| 85 | nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*], | 88 | nbl: [$(($nbl_pin_name:ident: $nbl_signal:ident)),*], |
| 86 | ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*] | 89 | ctrl: [$(($ctrl_pin_name:ident: $ctrl_signal:ident)),*] |
| 87 | )) => { | 90 | )) => { |
| 91 | /// Create a new FMC instance. | ||
| 88 | pub fn $name<CHIP: stm32_fmc::SdramChip>( | 92 | pub fn $name<CHIP: stm32_fmc::SdramChip>( |
| 89 | _instance: impl Peripheral<P = T> + 'd, | 93 | _instance: impl Peripheral<P = T> + 'd, |
| 90 | $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*, | 94 | $($addr_pin_name: impl Peripheral<P = impl $addr_signal<T>> + 'd),*, |
| @@ -199,6 +203,7 @@ pub(crate) mod sealed { | |||
| 199 | } | 203 | } |
| 200 | } | 204 | } |
| 201 | 205 | ||
| 206 | /// FMC instance trait. | ||
| 202 | pub trait Instance: sealed::Instance + 'static {} | 207 | pub trait Instance: sealed::Instance + 'static {} |
| 203 | 208 | ||
| 204 | foreach_peripheral!( | 209 | foreach_peripheral!( |
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index b863c4ffe..c300a079e 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! General-purpose Input/Output (GPIO) | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | use core::convert::Infallible; | 4 | use core::convert::Infallible; |
| 3 | 5 | ||
| @@ -29,6 +31,11 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 29 | Self { pin } | 31 | Self { pin } |
| 30 | } | 32 | } |
| 31 | 33 | ||
| 34 | /// Type-erase (degrade) this pin into an `AnyPin`. | ||
| 35 | /// | ||
| 36 | /// This converts pin singletons (`PA5`, `PB6`, ...), which | ||
| 37 | /// are all different types, into the same type. It is useful for | ||
| 38 | /// creating arrays of pins, or avoiding generics. | ||
| 32 | #[inline] | 39 | #[inline] |
| 33 | pub fn degrade(self) -> Flex<'d, AnyPin> { | 40 | pub fn degrade(self) -> Flex<'d, AnyPin> { |
| 34 | // Safety: We are about to drop the other copy of this pin, so | 41 | // Safety: We are about to drop the other copy of this pin, so |
| @@ -141,40 +148,55 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 141 | }); | 148 | }); |
| 142 | } | 149 | } |
| 143 | 150 | ||
| 151 | /// Get whether the pin input level is high. | ||
| 152 | #[inline] | ||
| 153 | pub fn is_high(&mut self) -> bool { | ||
| 154 | !self.ref_is_low() | ||
| 155 | } | ||
| 156 | |||
| 157 | /// Get whether the pin input level is low. | ||
| 144 | #[inline] | 158 | #[inline] |
| 145 | pub fn is_high(&self) -> bool { | 159 | pub fn is_low(&mut self) -> bool { |
| 146 | !self.is_low() | 160 | self.ref_is_low() |
| 147 | } | 161 | } |
| 148 | 162 | ||
| 149 | #[inline] | 163 | #[inline] |
| 150 | pub fn is_low(&self) -> bool { | 164 | pub(crate) fn ref_is_low(&self) -> bool { |
| 151 | let state = self.pin.block().idr().read().idr(self.pin.pin() as _); | 165 | let state = self.pin.block().idr().read().idr(self.pin.pin() as _); |
| 152 | state == vals::Idr::LOW | 166 | state == vals::Idr::LOW |
| 153 | } | 167 | } |
| 154 | 168 | ||
| 169 | /// Get the current pin input level. | ||
| 155 | #[inline] | 170 | #[inline] |
| 156 | pub fn get_level(&self) -> Level { | 171 | pub fn get_level(&mut self) -> Level { |
| 157 | self.is_high().into() | 172 | self.is_high().into() |
| 158 | } | 173 | } |
| 159 | 174 | ||
| 175 | /// Get whether the output level is set to high. | ||
| 160 | #[inline] | 176 | #[inline] |
| 161 | pub fn is_set_high(&self) -> bool { | 177 | pub fn is_set_high(&mut self) -> bool { |
| 162 | !self.is_set_low() | 178 | !self.ref_is_set_low() |
| 163 | } | 179 | } |
| 164 | 180 | ||
| 165 | /// Is the output pin set as low? | 181 | /// Get whether the output level is set to low. |
| 166 | #[inline] | 182 | #[inline] |
| 167 | pub fn is_set_low(&self) -> bool { | 183 | pub fn is_set_low(&mut self) -> bool { |
| 184 | self.ref_is_set_low() | ||
| 185 | } | ||
| 186 | |||
| 187 | #[inline] | ||
| 188 | pub(crate) fn ref_is_set_low(&self) -> bool { | ||
| 168 | let state = self.pin.block().odr().read().odr(self.pin.pin() as _); | 189 | let state = self.pin.block().odr().read().odr(self.pin.pin() as _); |
| 169 | state == vals::Odr::LOW | 190 | state == vals::Odr::LOW |
| 170 | } | 191 | } |
| 171 | 192 | ||
| 172 | /// What level output is set to | 193 | /// Get the current output level. |
| 173 | #[inline] | 194 | #[inline] |
| 174 | pub fn get_output_level(&self) -> Level { | 195 | pub fn get_output_level(&mut self) -> Level { |
| 175 | self.is_set_high().into() | 196 | self.is_set_high().into() |
| 176 | } | 197 | } |
| 177 | 198 | ||
| 199 | /// Set the output as high. | ||
| 178 | #[inline] | 200 | #[inline] |
| 179 | pub fn set_high(&mut self) { | 201 | pub fn set_high(&mut self) { |
| 180 | self.pin.set_high(); | 202 | self.pin.set_high(); |
| @@ -186,6 +208,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 186 | self.pin.set_low(); | 208 | self.pin.set_low(); |
| 187 | } | 209 | } |
| 188 | 210 | ||
| 211 | /// Set the output level. | ||
| 189 | #[inline] | 212 | #[inline] |
| 190 | pub fn set_level(&mut self, level: Level) { | 213 | pub fn set_level(&mut self, level: Level) { |
| 191 | match level { | 214 | match level { |
| @@ -194,7 +217,7 @@ impl<'d, T: Pin> Flex<'d, T> { | |||
| 194 | } | 217 | } |
| 195 | } | 218 | } |
| 196 | 219 | ||
| 197 | /// Toggle pin output | 220 | /// Toggle the output level. |
| 198 | #[inline] | 221 | #[inline] |
| 199 | pub fn toggle(&mut self) { | 222 | pub fn toggle(&mut self) { |
| 200 | if self.is_set_low() { | 223 | if self.is_set_low() { |
| @@ -232,8 +255,11 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { | |||
| 232 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | 255 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
| 233 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 256 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 234 | pub enum Pull { | 257 | pub enum Pull { |
| 258 | /// No pull | ||
| 235 | None, | 259 | None, |
| 260 | /// Pull up | ||
| 236 | Up, | 261 | Up, |
| 262 | /// Pull down | ||
| 237 | Down, | 263 | Down, |
| 238 | } | 264 | } |
| 239 | 265 | ||
| @@ -251,6 +277,9 @@ impl From<Pull> for vals::Pupdr { | |||
| 251 | } | 277 | } |
| 252 | 278 | ||
| 253 | /// Speed settings | 279 | /// Speed settings |
| 280 | /// | ||
| 281 | /// These vary dpeending on the chip, ceck the reference manual or datasheet for details. | ||
| 282 | #[allow(missing_docs)] | ||
| 254 | #[derive(Debug, Copy, Clone)] | 283 | #[derive(Debug, Copy, Clone)] |
| 255 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 284 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 256 | pub enum Speed { | 285 | pub enum Speed { |
| @@ -295,6 +324,7 @@ pub struct Input<'d, T: Pin> { | |||
| 295 | } | 324 | } |
| 296 | 325 | ||
| 297 | impl<'d, T: Pin> Input<'d, T> { | 326 | impl<'d, T: Pin> Input<'d, T> { |
| 327 | /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. | ||
| 298 | #[inline] | 328 | #[inline] |
| 299 | pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { | 329 | pub fn new(pin: impl Peripheral<P = T> + 'd, pull: Pull) -> Self { |
| 300 | let mut pin = Flex::new(pin); | 330 | let mut pin = Flex::new(pin); |
| @@ -302,6 +332,11 @@ impl<'d, T: Pin> Input<'d, T> { | |||
| 302 | Self { pin } | 332 | Self { pin } |
| 303 | } | 333 | } |
| 304 | 334 | ||
| 335 | /// Type-erase (degrade) this pin into an `AnyPin`. | ||
| 336 | /// | ||
| 337 | /// This converts pin singletons (`PA5`, `PB6`, ...), which | ||
| 338 | /// are all different types, into the same type. It is useful for | ||
| 339 | /// creating arrays of pins, or avoiding generics. | ||
| 305 | #[inline] | 340 | #[inline] |
| 306 | pub fn degrade(self) -> Input<'d, AnyPin> { | 341 | pub fn degrade(self) -> Input<'d, AnyPin> { |
| 307 | Input { | 342 | Input { |
| @@ -309,18 +344,21 @@ impl<'d, T: Pin> Input<'d, T> { | |||
| 309 | } | 344 | } |
| 310 | } | 345 | } |
| 311 | 346 | ||
| 347 | /// Get whether the pin input level is high. | ||
| 312 | #[inline] | 348 | #[inline] |
| 313 | pub fn is_high(&self) -> bool { | 349 | pub fn is_high(&mut self) -> bool { |
| 314 | self.pin.is_high() | 350 | self.pin.is_high() |
| 315 | } | 351 | } |
| 316 | 352 | ||
| 353 | /// Get whether the pin input level is low. | ||
| 317 | #[inline] | 354 | #[inline] |
| 318 | pub fn is_low(&self) -> bool { | 355 | pub fn is_low(&mut self) -> bool { |
| 319 | self.pin.is_low() | 356 | self.pin.is_low() |
| 320 | } | 357 | } |
| 321 | 358 | ||
| 359 | /// Get the current pin input level. | ||
| 322 | #[inline] | 360 | #[inline] |
| 323 | pub fn get_level(&self) -> Level { | 361 | pub fn get_level(&mut self) -> Level { |
| 324 | self.pin.get_level() | 362 | self.pin.get_level() |
| 325 | } | 363 | } |
| 326 | } | 364 | } |
| @@ -329,7 +367,9 @@ impl<'d, T: Pin> Input<'d, T> { | |||
| 329 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] | 367 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
| 330 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 368 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 331 | pub enum Level { | 369 | pub enum Level { |
| 370 | /// Low | ||
| 332 | Low, | 371 | Low, |
| 372 | /// High | ||
| 333 | High, | 373 | High, |
| 334 | } | 374 | } |
| 335 | 375 | ||
| @@ -361,6 +401,7 @@ pub struct Output<'d, T: Pin> { | |||
| 361 | } | 401 | } |
| 362 | 402 | ||
| 363 | impl<'d, T: Pin> Output<'d, T> { | 403 | impl<'d, T: Pin> Output<'d, T> { |
| 404 | /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. | ||
| 364 | #[inline] | 405 | #[inline] |
| 365 | pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { | 406 | pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed) -> Self { |
| 366 | let mut pin = Flex::new(pin); | 407 | let mut pin = Flex::new(pin); |
| @@ -372,6 +413,11 @@ impl<'d, T: Pin> Output<'d, T> { | |||
| 372 | Self { pin } | 413 | Self { pin } |
| 373 | } | 414 | } |
| 374 | 415 | ||
| 416 | /// Type-erase (degrade) this pin into an `AnyPin`. | ||
| 417 | /// | ||
| 418 | /// This converts pin singletons (`PA5`, `PB6`, ...), which | ||
| 419 | /// are all different types, into the same type. It is useful for | ||
| 420 | /// creating arrays of pins, or avoiding generics. | ||
| 375 | #[inline] | 421 | #[inline] |
| 376 | pub fn degrade(self) -> Output<'d, AnyPin> { | 422 | pub fn degrade(self) -> Output<'d, AnyPin> { |
| 377 | Output { | 423 | Output { |
| @@ -399,19 +445,19 @@ impl<'d, T: Pin> Output<'d, T> { | |||
| 399 | 445 | ||
| 400 | /// Is the output pin set as high? | 446 | /// Is the output pin set as high? |
| 401 | #[inline] | 447 | #[inline] |
| 402 | pub fn is_set_high(&self) -> bool { | 448 | pub fn is_set_high(&mut self) -> bool { |
| 403 | self.pin.is_set_high() | 449 | self.pin.is_set_high() |
| 404 | } | 450 | } |
| 405 | 451 | ||
| 406 | /// Is the output pin set as low? | 452 | /// Is the output pin set as low? |
| 407 | #[inline] | 453 | #[inline] |
| 408 | pub fn is_set_low(&self) -> bool { | 454 | pub fn is_set_low(&mut self) -> bool { |
| 409 | self.pin.is_set_low() | 455 | self.pin.is_set_low() |
| 410 | } | 456 | } |
| 411 | 457 | ||
| 412 | /// What level output is set to | 458 | /// What level output is set to |
| 413 | #[inline] | 459 | #[inline] |
| 414 | pub fn get_output_level(&self) -> Level { | 460 | pub fn get_output_level(&mut self) -> Level { |
| 415 | self.pin.get_output_level() | 461 | self.pin.get_output_level() |
| 416 | } | 462 | } |
| 417 | 463 | ||
| @@ -432,6 +478,7 @@ pub struct OutputOpenDrain<'d, T: Pin> { | |||
| 432 | } | 478 | } |
| 433 | 479 | ||
| 434 | impl<'d, T: Pin> OutputOpenDrain<'d, T> { | 480 | impl<'d, T: Pin> OutputOpenDrain<'d, T> { |
| 481 | /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed], [Pull] configuration. | ||
| 435 | #[inline] | 482 | #[inline] |
| 436 | pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { | 483 | pub fn new(pin: impl Peripheral<P = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { |
| 437 | let mut pin = Flex::new(pin); | 484 | let mut pin = Flex::new(pin); |
| @@ -445,6 +492,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||
| 445 | Self { pin } | 492 | Self { pin } |
| 446 | } | 493 | } |
| 447 | 494 | ||
| 495 | /// Type-erase (degrade) this pin into an `AnyPin`. | ||
| 496 | /// | ||
| 497 | /// This converts pin singletons (`PA5`, `PB6`, ...), which | ||
| 498 | /// are all different types, into the same type. It is useful for | ||
| 499 | /// creating arrays of pins, or avoiding generics. | ||
| 448 | #[inline] | 500 | #[inline] |
| 449 | pub fn degrade(self) -> Output<'d, AnyPin> { | 501 | pub fn degrade(self) -> Output<'d, AnyPin> { |
| 450 | Output { | 502 | Output { |
| @@ -452,19 +504,21 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||
| 452 | } | 504 | } |
| 453 | } | 505 | } |
| 454 | 506 | ||
| 507 | /// Get whether the pin input level is high. | ||
| 455 | #[inline] | 508 | #[inline] |
| 456 | pub fn is_high(&self) -> bool { | 509 | pub fn is_high(&mut self) -> bool { |
| 457 | !self.pin.is_low() | 510 | !self.pin.is_low() |
| 458 | } | 511 | } |
| 459 | 512 | ||
| 513 | /// Get whether the pin input level is low. | ||
| 460 | #[inline] | 514 | #[inline] |
| 461 | pub fn is_low(&self) -> bool { | 515 | pub fn is_low(&mut self) -> bool { |
| 462 | self.pin.is_low() | 516 | self.pin.is_low() |
| 463 | } | 517 | } |
| 464 | 518 | ||
| 465 | /// Returns current pin level | 519 | /// Get the current pin input level. |
| 466 | #[inline] | 520 | #[inline] |
| 467 | pub fn get_level(&self) -> Level { | 521 | pub fn get_level(&mut self) -> Level { |
| 468 | self.pin.get_level() | 522 | self.pin.get_level() |
| 469 | } | 523 | } |
| 470 | 524 | ||
| @@ -486,21 +540,21 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||
| 486 | self.pin.set_level(level); | 540 | self.pin.set_level(level); |
| 487 | } | 541 | } |
| 488 | 542 | ||
| 489 | /// Is the output pin set as high? | 543 | /// Get whether the output level is set to high. |
| 490 | #[inline] | 544 | #[inline] |
| 491 | pub fn is_set_high(&self) -> bool { | 545 | pub fn is_set_high(&mut self) -> bool { |
| 492 | self.pin.is_set_high() | 546 | self.pin.is_set_high() |
| 493 | } | 547 | } |
| 494 | 548 | ||
| 495 | /// Is the output pin set as low? | 549 | /// Get whether the output level is set to low. |
| 496 | #[inline] | 550 | #[inline] |
| 497 | pub fn is_set_low(&self) -> bool { | 551 | pub fn is_set_low(&mut self) -> bool { |
| 498 | self.pin.is_set_low() | 552 | self.pin.is_set_low() |
| 499 | } | 553 | } |
| 500 | 554 | ||
| 501 | /// What level output is set to | 555 | /// Get the current output level. |
| 502 | #[inline] | 556 | #[inline] |
| 503 | pub fn get_output_level(&self) -> Level { | 557 | pub fn get_output_level(&mut self) -> Level { |
| 504 | self.pin.get_output_level() | 558 | self.pin.get_output_level() |
| 505 | } | 559 | } |
| 506 | 560 | ||
| @@ -511,8 +565,11 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { | |||
| 511 | } | 565 | } |
| 512 | } | 566 | } |
| 513 | 567 | ||
| 568 | /// GPIO output type | ||
| 514 | pub enum OutputType { | 569 | pub enum OutputType { |
| 570 | /// Drive the pin both high or low. | ||
| 515 | PushPull, | 571 | PushPull, |
| 572 | /// Drive the pin low, or don't drive it at all if the output level is high. | ||
| 516 | OpenDrain, | 573 | OpenDrain, |
| 517 | } | 574 | } |
| 518 | 575 | ||
| @@ -525,6 +582,7 @@ impl From<OutputType> for sealed::AFType { | |||
| 525 | } | 582 | } |
| 526 | } | 583 | } |
| 527 | 584 | ||
| 585 | #[allow(missing_docs)] | ||
| 528 | pub(crate) mod sealed { | 586 | pub(crate) mod sealed { |
| 529 | use super::*; | 587 | use super::*; |
| 530 | 588 | ||
| @@ -532,8 +590,11 @@ pub(crate) mod sealed { | |||
| 532 | #[derive(Debug, Copy, Clone)] | 590 | #[derive(Debug, Copy, Clone)] |
| 533 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 591 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 534 | pub enum AFType { | 592 | pub enum AFType { |
| 593 | /// Input | ||
| 535 | Input, | 594 | Input, |
| 595 | /// Output, drive the pin both high or low. | ||
| 536 | OutputPushPull, | 596 | OutputPushPull, |
| 597 | /// Output, drive the pin low, or don't drive it at all if the output level is high. | ||
| 537 | OutputOpenDrain, | 598 | OutputOpenDrain, |
| 538 | } | 599 | } |
| 539 | 600 | ||
| @@ -676,7 +737,11 @@ pub(crate) mod sealed { | |||
| 676 | } | 737 | } |
| 677 | } | 738 | } |
| 678 | 739 | ||
| 740 | /// GPIO pin trait. | ||
| 679 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { | 741 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { |
| 742 | /// EXTI channel assigned to this pin. | ||
| 743 | /// | ||
| 744 | /// For example, PC4 uses EXTI4. | ||
| 680 | #[cfg(feature = "exti")] | 745 | #[cfg(feature = "exti")] |
| 681 | type ExtiChannel: crate::exti::Channel; | 746 | type ExtiChannel: crate::exti::Channel; |
| 682 | 747 | ||
| @@ -692,7 +757,11 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat | |||
| 692 | self._port() | 757 | self._port() |
| 693 | } | 758 | } |
| 694 | 759 | ||
| 695 | /// Convert from concrete pin type PX_XX to type erased `AnyPin`. | 760 | /// Type-erase (degrade) this pin into an `AnyPin`. |
| 761 | /// | ||
| 762 | /// This converts pin singletons (`PA5`, `PB6`, ...), which | ||
| 763 | /// are all different types, into the same type. It is useful for | ||
| 764 | /// creating arrays of pins, or avoiding generics. | ||
| 696 | #[inline] | 765 | #[inline] |
| 697 | fn degrade(self) -> AnyPin { | 766 | fn degrade(self) -> AnyPin { |
| 698 | AnyPin { | 767 | AnyPin { |
| @@ -701,12 +770,15 @@ pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'stat | |||
| 701 | } | 770 | } |
| 702 | } | 771 | } |
| 703 | 772 | ||
| 704 | // Type-erased GPIO pin | 773 | /// Type-erased GPIO pin |
| 705 | pub struct AnyPin { | 774 | pub struct AnyPin { |
| 706 | pin_port: u8, | 775 | pin_port: u8, |
| 707 | } | 776 | } |
| 708 | 777 | ||
| 709 | impl AnyPin { | 778 | impl AnyPin { |
| 779 | /// Unsafely create an `AnyPin` from a pin+port number. | ||
| 780 | /// | ||
| 781 | /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... | ||
| 710 | #[inline] | 782 | #[inline] |
| 711 | pub unsafe fn steal(pin_port: u8) -> Self { | 783 | pub unsafe fn steal(pin_port: u8) -> Self { |
| 712 | Self { pin_port } | 784 | Self { pin_port } |
| @@ -717,6 +789,8 @@ impl AnyPin { | |||
| 717 | self.pin_port / 16 | 789 | self.pin_port / 16 |
| 718 | } | 790 | } |
| 719 | 791 | ||
| 792 | /// Get the GPIO register block for this pin. | ||
| 793 | #[cfg(feature = "unstable-pac")] | ||
| 720 | #[inline] | 794 | #[inline] |
| 721 | pub fn block(&self) -> gpio::Gpio { | 795 | pub fn block(&self) -> gpio::Gpio { |
| 722 | pac::GPIO(self._port() as _) | 796 | pac::GPIO(self._port() as _) |
| @@ -777,12 +851,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Input<'d, T> { | |||
| 777 | 851 | ||
| 778 | #[inline] | 852 | #[inline] |
| 779 | fn is_high(&self) -> Result<bool, Self::Error> { | 853 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 780 | Ok(self.is_high()) | 854 | Ok(!self.pin.ref_is_low()) |
| 781 | } | 855 | } |
| 782 | 856 | ||
| 783 | #[inline] | 857 | #[inline] |
| 784 | fn is_low(&self) -> Result<bool, Self::Error> { | 858 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 785 | Ok(self.is_low()) | 859 | Ok(self.pin.ref_is_low()) |
| 786 | } | 860 | } |
| 787 | } | 861 | } |
| 788 | 862 | ||
| @@ -805,13 +879,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Output<'d, T> { | |||
| 805 | impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { | 879 | impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d, T> { |
| 806 | #[inline] | 880 | #[inline] |
| 807 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 881 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 808 | Ok(self.is_set_high()) | 882 | Ok(!self.pin.ref_is_set_low()) |
| 809 | } | 883 | } |
| 810 | 884 | ||
| 811 | /// Is the output pin set as low? | 885 | /// Is the output pin set as low? |
| 812 | #[inline] | 886 | #[inline] |
| 813 | fn is_set_low(&self) -> Result<bool, Self::Error> { | 887 | fn is_set_low(&self) -> Result<bool, Self::Error> { |
| 814 | Ok(self.is_set_low()) | 888 | Ok(self.pin.ref_is_set_low()) |
| 815 | } | 889 | } |
| 816 | } | 890 | } |
| 817 | 891 | ||
| @@ -843,13 +917,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d, | |||
| 843 | impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { | 917 | impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d, T> { |
| 844 | #[inline] | 918 | #[inline] |
| 845 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 919 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 846 | Ok(self.is_set_high()) | 920 | Ok(!self.pin.ref_is_set_low()) |
| 847 | } | 921 | } |
| 848 | 922 | ||
| 849 | /// Is the output pin set as low? | 923 | /// Is the output pin set as low? |
| 850 | #[inline] | 924 | #[inline] |
| 851 | fn is_set_low(&self) -> Result<bool, Self::Error> { | 925 | fn is_set_low(&self) -> Result<bool, Self::Error> { |
| 852 | Ok(self.is_set_low()) | 926 | Ok(self.pin.ref_is_set_low()) |
| 853 | } | 927 | } |
| 854 | } | 928 | } |
| 855 | 929 | ||
| @@ -867,12 +941,12 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> { | |||
| 867 | 941 | ||
| 868 | #[inline] | 942 | #[inline] |
| 869 | fn is_high(&self) -> Result<bool, Self::Error> { | 943 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 870 | Ok(self.is_high()) | 944 | Ok(!self.ref_is_low()) |
| 871 | } | 945 | } |
| 872 | 946 | ||
| 873 | #[inline] | 947 | #[inline] |
| 874 | fn is_low(&self) -> Result<bool, Self::Error> { | 948 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 875 | Ok(self.is_low()) | 949 | Ok(self.ref_is_low()) |
| 876 | } | 950 | } |
| 877 | } | 951 | } |
| 878 | 952 | ||
| @@ -895,13 +969,13 @@ impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> { | |||
| 895 | impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { | 969 | impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> { |
| 896 | #[inline] | 970 | #[inline] |
| 897 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 971 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 898 | Ok(self.is_set_high()) | 972 | Ok(!self.ref_is_set_low()) |
| 899 | } | 973 | } |
| 900 | 974 | ||
| 901 | /// Is the output pin set as low? | 975 | /// Is the output pin set as low? |
| 902 | #[inline] | 976 | #[inline] |
| 903 | fn is_set_low(&self) -> Result<bool, Self::Error> { | 977 | fn is_set_low(&self) -> Result<bool, Self::Error> { |
| 904 | Ok(self.is_set_low()) | 978 | Ok(self.ref_is_set_low()) |
| 905 | } | 979 | } |
| 906 | } | 980 | } |
| 907 | 981 | ||
| @@ -920,12 +994,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> { | |||
| 920 | 994 | ||
| 921 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { | 995 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { |
| 922 | #[inline] | 996 | #[inline] |
| 923 | fn is_high(&self) -> Result<bool, Self::Error> { | 997 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 924 | Ok(self.is_high()) | 998 | Ok(self.is_high()) |
| 925 | } | 999 | } |
| 926 | 1000 | ||
| 927 | #[inline] | 1001 | #[inline] |
| 928 | fn is_low(&self) -> Result<bool, Self::Error> { | 1002 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 929 | Ok(self.is_low()) | 1003 | Ok(self.is_low()) |
| 930 | } | 1004 | } |
| 931 | } | 1005 | } |
| @@ -948,13 +1022,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { | |||
| 948 | 1022 | ||
| 949 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { | 1023 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { |
| 950 | #[inline] | 1024 | #[inline] |
| 951 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 1025 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
| 952 | Ok(self.is_set_high()) | 1026 | Ok(self.is_set_high()) |
| 953 | } | 1027 | } |
| 954 | 1028 | ||
| 955 | /// Is the output pin set as low? | 1029 | /// Is the output pin set as low? |
| 956 | #[inline] | 1030 | #[inline] |
| 957 | fn is_set_low(&self) -> Result<bool, Self::Error> { | 1031 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
| 958 | Ok(self.is_set_low()) | 1032 | Ok(self.is_set_low()) |
| 959 | } | 1033 | } |
| 960 | } | 1034 | } |
| @@ -972,12 +1046,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> { | |||
| 972 | 1046 | ||
| 973 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { | 1047 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d, T> { |
| 974 | #[inline] | 1048 | #[inline] |
| 975 | fn is_high(&self) -> Result<bool, Self::Error> { | 1049 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 976 | Ok(self.is_high()) | 1050 | Ok(self.is_high()) |
| 977 | } | 1051 | } |
| 978 | 1052 | ||
| 979 | #[inline] | 1053 | #[inline] |
| 980 | fn is_low(&self) -> Result<bool, Self::Error> { | 1054 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 981 | Ok(self.is_low()) | 1055 | Ok(self.is_low()) |
| 982 | } | 1056 | } |
| 983 | } | 1057 | } |
| @@ -996,13 +1070,13 @@ impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d, T> { | |||
| 996 | 1070 | ||
| 997 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { | 1071 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d, T> { |
| 998 | #[inline] | 1072 | #[inline] |
| 999 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 1073 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
| 1000 | Ok(self.is_set_high()) | 1074 | Ok(self.is_set_high()) |
| 1001 | } | 1075 | } |
| 1002 | 1076 | ||
| 1003 | /// Is the output pin set as low? | 1077 | /// Is the output pin set as low? |
| 1004 | #[inline] | 1078 | #[inline] |
| 1005 | fn is_set_low(&self) -> Result<bool, Self::Error> { | 1079 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
| 1006 | Ok(self.is_set_low()) | 1080 | Ok(self.is_set_low()) |
| 1007 | } | 1081 | } |
| 1008 | } | 1082 | } |
| @@ -1016,12 +1090,12 @@ impl<'d, T: Pin> embedded_hal_1::digital::ToggleableOutputPin for OutputOpenDrai | |||
| 1016 | 1090 | ||
| 1017 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { | 1091 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { |
| 1018 | #[inline] | 1092 | #[inline] |
| 1019 | fn is_high(&self) -> Result<bool, Self::Error> { | 1093 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 1020 | Ok(self.is_high()) | 1094 | Ok(self.is_high()) |
| 1021 | } | 1095 | } |
| 1022 | 1096 | ||
| 1023 | #[inline] | 1097 | #[inline] |
| 1024 | fn is_low(&self) -> Result<bool, Self::Error> { | 1098 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 1025 | Ok(self.is_low()) | 1099 | Ok(self.is_low()) |
| 1026 | } | 1100 | } |
| 1027 | } | 1101 | } |
| @@ -1051,17 +1125,18 @@ impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> { | |||
| 1051 | 1125 | ||
| 1052 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { | 1126 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { |
| 1053 | #[inline] | 1127 | #[inline] |
| 1054 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 1128 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
| 1055 | Ok(self.is_set_high()) | 1129 | Ok(self.is_set_high()) |
| 1056 | } | 1130 | } |
| 1057 | 1131 | ||
| 1058 | /// Is the output pin set as low? | 1132 | /// Is the output pin set as low? |
| 1059 | #[inline] | 1133 | #[inline] |
| 1060 | fn is_set_low(&self) -> Result<bool, Self::Error> { | 1134 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
| 1061 | Ok(self.is_set_low()) | 1135 | Ok(self.is_set_low()) |
| 1062 | } | 1136 | } |
| 1063 | } | 1137 | } |
| 1064 | 1138 | ||
| 1139 | /// Low-level GPIO manipulation. | ||
| 1065 | #[cfg(feature = "unstable-pac")] | 1140 | #[cfg(feature = "unstable-pac")] |
| 1066 | pub mod low_level { | 1141 | pub mod low_level { |
| 1067 | pub use super::sealed::*; | 1142 | pub use super::sealed::*; |
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 17096d48c..faefaabbc 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! High Resolution Timer (HRTIM) | ||
| 2 | |||
| 1 | mod traits; | 3 | mod traits; |
| 2 | 4 | ||
| 3 | use core::marker::PhantomData; | 5 | use core::marker::PhantomData; |
| @@ -13,38 +15,42 @@ use crate::rcc::get_freqs; | |||
| 13 | use crate::time::Hertz; | 15 | use crate::time::Hertz; |
| 14 | use crate::Peripheral; | 16 | use crate::Peripheral; |
| 15 | 17 | ||
| 16 | pub enum Source { | 18 | /// HRTIM burst controller instance. |
| 17 | Master, | ||
| 18 | ChA, | ||
| 19 | ChB, | ||
| 20 | ChC, | ||
| 21 | ChD, | ||
| 22 | ChE, | ||
| 23 | #[cfg(hrtim_v2)] | ||
| 24 | ChF, | ||
| 25 | } | ||
| 26 | |||
| 27 | pub struct BurstController<T: Instance> { | 19 | pub struct BurstController<T: Instance> { |
| 28 | phantom: PhantomData<T>, | 20 | phantom: PhantomData<T>, |
| 29 | } | 21 | } |
| 22 | |||
| 23 | /// HRTIM master instance. | ||
| 30 | pub struct Master<T: Instance> { | 24 | pub struct Master<T: Instance> { |
| 31 | phantom: PhantomData<T>, | 25 | phantom: PhantomData<T>, |
| 32 | } | 26 | } |
| 27 | |||
| 28 | /// HRTIM channel A instance. | ||
| 33 | pub struct ChA<T: Instance> { | 29 | pub struct ChA<T: Instance> { |
| 34 | phantom: PhantomData<T>, | 30 | phantom: PhantomData<T>, |
| 35 | } | 31 | } |
| 32 | |||
| 33 | /// HRTIM channel B instance. | ||
| 36 | pub struct ChB<T: Instance> { | 34 | pub struct ChB<T: Instance> { |
| 37 | phantom: PhantomData<T>, | 35 | phantom: PhantomData<T>, |
| 38 | } | 36 | } |
| 37 | |||
| 38 | /// HRTIM channel C instance. | ||
| 39 | pub struct ChC<T: Instance> { | 39 | pub struct ChC<T: Instance> { |
| 40 | phantom: PhantomData<T>, | 40 | phantom: PhantomData<T>, |
| 41 | } | 41 | } |
| 42 | |||
| 43 | /// HRTIM channel D instance. | ||
| 42 | pub struct ChD<T: Instance> { | 44 | pub struct ChD<T: Instance> { |
| 43 | phantom: PhantomData<T>, | 45 | phantom: PhantomData<T>, |
| 44 | } | 46 | } |
| 47 | |||
| 48 | /// HRTIM channel E instance. | ||
| 45 | pub struct ChE<T: Instance> { | 49 | pub struct ChE<T: Instance> { |
| 46 | phantom: PhantomData<T>, | 50 | phantom: PhantomData<T>, |
| 47 | } | 51 | } |
| 52 | |||
| 53 | /// HRTIM channel F instance. | ||
| 48 | #[cfg(hrtim_v2)] | 54 | #[cfg(hrtim_v2)] |
| 49 | pub struct ChF<T: Instance> { | 55 | pub struct ChF<T: Instance> { |
| 50 | phantom: PhantomData<T>, | 56 | phantom: PhantomData<T>, |
| @@ -58,22 +64,26 @@ mod sealed { | |||
| 58 | } | 64 | } |
| 59 | } | 65 | } |
| 60 | 66 | ||
| 67 | /// Advanced channel instance trait. | ||
| 61 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} | 68 | pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} |
| 62 | 69 | ||
| 63 | pub struct PwmPin<'d, Perip, Channel> { | 70 | /// HRTIM PWM pin. |
| 71 | pub struct PwmPin<'d, T, C> { | ||
| 64 | _pin: PeripheralRef<'d, AnyPin>, | 72 | _pin: PeripheralRef<'d, AnyPin>, |
| 65 | phantom: PhantomData<(Perip, Channel)>, | 73 | phantom: PhantomData<(T, C)>, |
| 66 | } | 74 | } |
| 67 | 75 | ||
| 68 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | 76 | /// HRTIM complementary PWM pin. |
| 77 | pub struct ComplementaryPwmPin<'d, T, C> { | ||
| 69 | _pin: PeripheralRef<'d, AnyPin>, | 78 | _pin: PeripheralRef<'d, AnyPin>, |
| 70 | phantom: PhantomData<(Perip, Channel)>, | 79 | phantom: PhantomData<(T, C)>, |
| 71 | } | 80 | } |
| 72 | 81 | ||
| 73 | macro_rules! advanced_channel_impl { | 82 | macro_rules! advanced_channel_impl { |
| 74 | ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { | 83 | ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { |
| 75 | impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { | 84 | impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { |
| 76 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | 85 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 86 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { | ||
| 77 | into_ref!(pin); | 87 | into_ref!(pin); |
| 78 | critical_section::with(|_| { | 88 | critical_section::with(|_| { |
| 79 | pin.set_low(); | 89 | pin.set_low(); |
| @@ -88,8 +98,9 @@ macro_rules! advanced_channel_impl { | |||
| 88 | } | 98 | } |
| 89 | } | 99 | } |
| 90 | 100 | ||
| 91 | impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { | 101 | impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { |
| 92 | pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { | 102 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 103 | pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self { | ||
| 93 | into_ref!(pin); | 104 | into_ref!(pin); |
| 94 | critical_section::with(|_| { | 105 | critical_section::with(|_| { |
| 95 | pin.set_low(); | 106 | pin.set_low(); |
| @@ -124,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); | |||
| 124 | /// Struct used to divide a high resolution timer into multiple channels | 135 | /// Struct used to divide a high resolution timer into multiple channels |
| 125 | pub struct AdvancedPwm<'d, T: Instance> { | 136 | pub struct AdvancedPwm<'d, T: Instance> { |
| 126 | _inner: PeripheralRef<'d, T>, | 137 | _inner: PeripheralRef<'d, T>, |
| 138 | /// Master instance. | ||
| 127 | pub master: Master<T>, | 139 | pub master: Master<T>, |
| 140 | /// Burst controller. | ||
| 128 | pub burst_controller: BurstController<T>, | 141 | pub burst_controller: BurstController<T>, |
| 142 | /// Channel A. | ||
| 129 | pub ch_a: ChA<T>, | 143 | pub ch_a: ChA<T>, |
| 144 | /// Channel B. | ||
| 130 | pub ch_b: ChB<T>, | 145 | pub ch_b: ChB<T>, |
| 146 | /// Channel C. | ||
| 131 | pub ch_c: ChC<T>, | 147 | pub ch_c: ChC<T>, |
| 148 | /// Channel D. | ||
| 132 | pub ch_d: ChD<T>, | 149 | pub ch_d: ChD<T>, |
| 150 | /// Channel E. | ||
| 133 | pub ch_e: ChE<T>, | 151 | pub ch_e: ChE<T>, |
| 152 | /// Channel F. | ||
| 134 | #[cfg(hrtim_v2)] | 153 | #[cfg(hrtim_v2)] |
| 135 | pub ch_f: ChF<T>, | 154 | pub ch_f: ChF<T>, |
| 136 | } | 155 | } |
| 137 | 156 | ||
| 138 | impl<'d, T: Instance> AdvancedPwm<'d, T> { | 157 | impl<'d, T: Instance> AdvancedPwm<'d, T> { |
| 158 | /// Create a new HRTIM driver. | ||
| 159 | /// | ||
| 160 | /// This splits the HRTIM into its constituent parts, which you can then use individually. | ||
| 139 | pub fn new( | 161 | pub fn new( |
| 140 | tim: impl Peripheral<P = T> + 'd, | 162 | tim: impl Peripheral<P = T> + 'd, |
| 141 | _cha: Option<PwmPin<'d, T, ChA<T>>>, | 163 | _cha: Option<PwmPin<'d, T, ChA<T>>>, |
| @@ -198,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { | |||
| 198 | } | 220 | } |
| 199 | } | 221 | } |
| 200 | 222 | ||
| 201 | impl<T: Instance> BurstController<T> { | 223 | /// Fixed-frequency bridge converter driver. |
| 202 | pub fn set_source(&mut self, _source: Source) { | ||
| 203 | todo!("burst mode control registers not implemented") | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /// Represents a fixed-frequency bridge converter | ||
| 208 | /// | 224 | /// |
| 209 | /// Our implementation of the bridge converter uses a single channel and three compare registers, | 225 | /// Our implementation of the bridge converter uses a single channel and three compare registers, |
| 210 | /// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous | 226 | /// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous |
| @@ -223,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> { | |||
| 223 | } | 239 | } |
| 224 | 240 | ||
| 225 | impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { | 241 | impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { |
| 242 | /// Create a new HRTIM bridge converter driver. | ||
| 226 | pub fn new(_channel: C, frequency: Hertz) -> Self { | 243 | pub fn new(_channel: C, frequency: Hertz) -> Self { |
| 227 | use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; | 244 | use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; |
| 228 | 245 | ||
| @@ -279,14 +296,17 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { | |||
| 279 | } | 296 | } |
| 280 | } | 297 | } |
| 281 | 298 | ||
| 299 | /// Start HRTIM. | ||
| 282 | pub fn start(&mut self) { | 300 | pub fn start(&mut self) { |
| 283 | T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); | 301 | T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); |
| 284 | } | 302 | } |
| 285 | 303 | ||
| 304 | /// Stop HRTIM. | ||
| 286 | pub fn stop(&mut self) { | 305 | pub fn stop(&mut self) { |
| 287 | T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); | 306 | T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); |
| 288 | } | 307 | } |
| 289 | 308 | ||
| 309 | /// Enable burst mode. | ||
| 290 | pub fn enable_burst_mode(&mut self) { | 310 | pub fn enable_burst_mode(&mut self) { |
| 291 | T::regs().tim(C::raw()).outr().modify(|w| { | 311 | T::regs().tim(C::raw()).outr().modify(|w| { |
| 292 | // Enable Burst Mode | 312 | // Enable Burst Mode |
| @@ -299,6 +319,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { | |||
| 299 | }) | 319 | }) |
| 300 | } | 320 | } |
| 301 | 321 | ||
| 322 | /// Disable burst mode. | ||
| 302 | pub fn disable_burst_mode(&mut self) { | 323 | pub fn disable_burst_mode(&mut self) { |
| 303 | T::regs().tim(C::raw()).outr().modify(|w| { | 324 | T::regs().tim(C::raw()).outr().modify(|w| { |
| 304 | // Disable Burst Mode | 325 | // Disable Burst Mode |
| @@ -355,7 +376,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { | |||
| 355 | } | 376 | } |
| 356 | } | 377 | } |
| 357 | 378 | ||
| 358 | /// Represents a variable-frequency resonant converter | 379 | /// Variable-frequency resonant converter driver. |
| 359 | /// | 380 | /// |
| 360 | /// This implementation of a resonsant converter is appropriate for a half or full bridge, | 381 | /// This implementation of a resonsant converter is appropriate for a half or full bridge, |
| 361 | /// but does not include secondary rectification, which is appropriate for applications | 382 | /// but does not include secondary rectification, which is appropriate for applications |
| @@ -368,6 +389,7 @@ pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> { | |||
| 368 | } | 389 | } |
| 369 | 390 | ||
| 370 | impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { | 391 | impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { |
| 392 | /// Create a new variable-frequency resonant converter driver. | ||
| 371 | pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { | 393 | pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { |
| 372 | T::set_channel_frequency(C::raw(), min_frequency); | 394 | T::set_channel_frequency(C::raw(), min_frequency); |
| 373 | 395 | ||
| @@ -406,6 +428,7 @@ impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { | |||
| 406 | T::set_channel_dead_time(C::raw(), value); | 428 | T::set_channel_dead_time(C::raw(), value); |
| 407 | } | 429 | } |
| 408 | 430 | ||
| 431 | /// Set the timer period. | ||
| 409 | pub fn set_period(&mut self, period: u16) { | 432 | pub fn set_period(&mut self, period: u16) { |
| 410 | assert!(period < self.max_period); | 433 | assert!(period < self.max_period); |
| 411 | assert!(period > self.min_period); | 434 | assert!(period > self.min_period); |
diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 34a363a1f..cfd31c47c 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs | |||
| @@ -125,7 +125,6 @@ pub(crate) mod sealed { | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | /// Set the dead time as a proportion of max_duty | 127 | /// Set the dead time as a proportion of max_duty |
| 128 | |||
| 129 | fn set_channel_dead_time(channel: usize, dead_time: u16) { | 128 | fn set_channel_dead_time(channel: usize, dead_time: u16) { |
| 130 | let regs = Self::regs(); | 129 | let regs = Self::regs(); |
| 131 | 130 | ||
| @@ -148,13 +147,10 @@ pub(crate) mod sealed { | |||
| 148 | w.set_dtr(dt_val as u16); | 147 | w.set_dtr(dt_val as u16); |
| 149 | }); | 148 | }); |
| 150 | } | 149 | } |
| 151 | |||
| 152 | // fn enable_outputs(enable: bool); | ||
| 153 | // | ||
| 154 | // fn enable_channel(&mut self, channel: usize, enable: bool); | ||
| 155 | } | 150 | } |
| 156 | } | 151 | } |
| 157 | 152 | ||
| 153 | /// HRTIM instance trait. | ||
| 158 | pub trait Instance: sealed::Instance + 'static {} | 154 | pub trait Instance: sealed::Instance + 'static {} |
| 159 | 155 | ||
| 160 | foreach_interrupt! { | 156 | foreach_interrupt! { |
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index d2a50cf7e..2416005b5 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -1,30 +1,180 @@ | |||
| 1 | //! Inter-Integrated-Circuit (I2C) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use crate::dma::NoDma; | ||
| 6 | use crate::interrupt; | ||
| 7 | |||
| 8 | #[cfg_attr(i2c_v1, path = "v1.rs")] | 4 | #[cfg_attr(i2c_v1, path = "v1.rs")] |
| 9 | #[cfg_attr(i2c_v2, path = "v2.rs")] | 5 | #[cfg_attr(i2c_v2, path = "v2.rs")] |
| 10 | mod _version; | 6 | mod _version; |
| 11 | pub use _version::*; | 7 | |
| 8 | use core::future::Future; | ||
| 9 | use core::marker::PhantomData; | ||
| 10 | |||
| 11 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| 13 | #[cfg(feature = "time")] | ||
| 14 | use embassy_time::{Duration, Instant}; | ||
| 13 | 15 | ||
| 14 | use crate::peripherals; | 16 | use crate::dma::NoDma; |
| 17 | use crate::gpio::sealed::AFType; | ||
| 18 | use crate::gpio::Pull; | ||
| 19 | use crate::interrupt::typelevel::Interrupt; | ||
| 20 | use crate::time::Hertz; | ||
| 21 | use crate::{interrupt, peripherals}; | ||
| 15 | 22 | ||
| 23 | /// I2C error. | ||
| 16 | #[derive(Debug, PartialEq, Eq)] | 24 | #[derive(Debug, PartialEq, Eq)] |
| 17 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 25 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 18 | pub enum Error { | 26 | pub enum Error { |
| 27 | /// Bus error | ||
| 19 | Bus, | 28 | Bus, |
| 29 | /// Arbitration lost | ||
| 20 | Arbitration, | 30 | Arbitration, |
| 31 | /// ACK not received (either to the address or to a data byte) | ||
| 21 | Nack, | 32 | Nack, |
| 33 | /// Timeout | ||
| 22 | Timeout, | 34 | Timeout, |
| 35 | /// CRC error | ||
| 23 | Crc, | 36 | Crc, |
| 37 | /// Overrun error | ||
| 24 | Overrun, | 38 | Overrun, |
| 39 | /// Zero-length transfers are not allowed. | ||
| 25 | ZeroLengthTransfer, | 40 | ZeroLengthTransfer, |
| 26 | } | 41 | } |
| 27 | 42 | ||
| 43 | /// I2C config | ||
| 44 | #[non_exhaustive] | ||
| 45 | #[derive(Copy, Clone)] | ||
| 46 | pub struct Config { | ||
| 47 | /// Enable internal pullup on SDA. | ||
| 48 | /// | ||
| 49 | /// Using external pullup resistors is recommended for I2C. If you do | ||
| 50 | /// have external pullups you should not enable this. | ||
| 51 | pub sda_pullup: bool, | ||
| 52 | /// Enable internal pullup on SCL. | ||
| 53 | /// | ||
| 54 | /// Using external pullup resistors is recommended for I2C. If you do | ||
| 55 | /// have external pullups you should not enable this. | ||
| 56 | pub scl_pullup: bool, | ||
| 57 | /// Timeout. | ||
| 58 | #[cfg(feature = "time")] | ||
| 59 | pub timeout: embassy_time::Duration, | ||
| 60 | } | ||
| 61 | |||
| 62 | impl Default for Config { | ||
| 63 | fn default() -> Self { | ||
| 64 | Self { | ||
| 65 | sda_pullup: false, | ||
| 66 | scl_pullup: false, | ||
| 67 | #[cfg(feature = "time")] | ||
| 68 | timeout: embassy_time::Duration::from_millis(1000), | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | /// I2C driver. | ||
| 74 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | ||
| 75 | _peri: PeripheralRef<'d, T>, | ||
| 76 | #[allow(dead_code)] | ||
| 77 | tx_dma: PeripheralRef<'d, TXDMA>, | ||
| 78 | #[allow(dead_code)] | ||
| 79 | rx_dma: PeripheralRef<'d, RXDMA>, | ||
| 80 | #[cfg(feature = "time")] | ||
| 81 | timeout: Duration, | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | ||
| 85 | /// Create a new I2C driver. | ||
| 86 | pub fn new( | ||
| 87 | peri: impl Peripheral<P = T> + 'd, | ||
| 88 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 89 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 90 | _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> | ||
| 91 | + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> | ||
| 92 | + 'd, | ||
| 93 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||
| 94 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||
| 95 | freq: Hertz, | ||
| 96 | config: Config, | ||
| 97 | ) -> Self { | ||
| 98 | into_ref!(peri, scl, sda, tx_dma, rx_dma); | ||
| 99 | |||
| 100 | T::enable_and_reset(); | ||
| 101 | |||
| 102 | scl.set_as_af_pull( | ||
| 103 | scl.af_num(), | ||
| 104 | AFType::OutputOpenDrain, | ||
| 105 | match config.scl_pullup { | ||
| 106 | true => Pull::Up, | ||
| 107 | false => Pull::None, | ||
| 108 | }, | ||
| 109 | ); | ||
| 110 | sda.set_as_af_pull( | ||
| 111 | sda.af_num(), | ||
| 112 | AFType::OutputOpenDrain, | ||
| 113 | match config.sda_pullup { | ||
| 114 | true => Pull::Up, | ||
| 115 | false => Pull::None, | ||
| 116 | }, | ||
| 117 | ); | ||
| 118 | |||
| 119 | unsafe { T::EventInterrupt::enable() }; | ||
| 120 | unsafe { T::ErrorInterrupt::enable() }; | ||
| 121 | |||
| 122 | let mut this = Self { | ||
| 123 | _peri: peri, | ||
| 124 | tx_dma, | ||
| 125 | rx_dma, | ||
| 126 | #[cfg(feature = "time")] | ||
| 127 | timeout: config.timeout, | ||
| 128 | }; | ||
| 129 | |||
| 130 | this.init(freq, config); | ||
| 131 | |||
| 132 | this | ||
| 133 | } | ||
| 134 | |||
| 135 | fn timeout(&self) -> Timeout { | ||
| 136 | Timeout { | ||
| 137 | #[cfg(feature = "time")] | ||
| 138 | deadline: Instant::now() + self.timeout, | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | #[derive(Copy, Clone)] | ||
| 144 | struct Timeout { | ||
| 145 | #[cfg(feature = "time")] | ||
| 146 | deadline: Instant, | ||
| 147 | } | ||
| 148 | |||
| 149 | #[allow(dead_code)] | ||
| 150 | impl Timeout { | ||
| 151 | #[inline] | ||
| 152 | fn check(self) -> Result<(), Error> { | ||
| 153 | #[cfg(feature = "time")] | ||
| 154 | if Instant::now() > self.deadline { | ||
| 155 | return Err(Error::Timeout); | ||
| 156 | } | ||
| 157 | |||
| 158 | Ok(()) | ||
| 159 | } | ||
| 160 | |||
| 161 | #[inline] | ||
| 162 | fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> { | ||
| 163 | #[cfg(feature = "time")] | ||
| 164 | { | ||
| 165 | use futures::FutureExt; | ||
| 166 | |||
| 167 | embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r { | ||
| 168 | embassy_futures::select::Either::First(_) => Err(Error::Timeout), | ||
| 169 | embassy_futures::select::Either::Second(r) => r, | ||
| 170 | }) | ||
| 171 | } | ||
| 172 | |||
| 173 | #[cfg(not(feature = "time"))] | ||
| 174 | fut | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 28 | pub(crate) mod sealed { | 178 | pub(crate) mod sealed { |
| 29 | use super::*; | 179 | use super::*; |
| 30 | 180 | ||
| @@ -47,8 +197,11 @@ pub(crate) mod sealed { | |||
| 47 | } | 197 | } |
| 48 | } | 198 | } |
| 49 | 199 | ||
| 200 | /// I2C peripheral instance | ||
| 50 | pub trait Instance: sealed::Instance + 'static { | 201 | pub trait Instance: sealed::Instance + 'static { |
| 202 | /// Event interrupt for this instance | ||
| 51 | type EventInterrupt: interrupt::typelevel::Interrupt; | 203 | type EventInterrupt: interrupt::typelevel::Interrupt; |
| 204 | /// Error interrupt for this instance | ||
| 52 | type ErrorInterrupt: interrupt::typelevel::Interrupt; | 205 | type ErrorInterrupt: interrupt::typelevel::Interrupt; |
| 53 | } | 206 | } |
| 54 | 207 | ||
| @@ -57,7 +210,7 @@ pin_trait!(SdaPin, Instance); | |||
| 57 | dma_trait!(RxDma, Instance); | 210 | dma_trait!(RxDma, Instance); |
| 58 | dma_trait!(TxDma, Instance); | 211 | dma_trait!(TxDma, Instance); |
| 59 | 212 | ||
| 60 | /// Interrupt handler. | 213 | /// Event interrupt handler. |
| 61 | pub struct EventInterruptHandler<T: Instance> { | 214 | pub struct EventInterruptHandler<T: Instance> { |
| 62 | _phantom: PhantomData<T>, | 215 | _phantom: PhantomData<T>, |
| 63 | } | 216 | } |
| @@ -68,6 +221,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::EventInterrupt> for EventInte | |||
| 68 | } | 221 | } |
| 69 | } | 222 | } |
| 70 | 223 | ||
| 224 | /// Error interrupt handler. | ||
| 71 | pub struct ErrorInterruptHandler<T: Instance> { | 225 | pub struct ErrorInterruptHandler<T: Instance> { |
| 72 | _phantom: PhantomData<T>, | 226 | _phantom: PhantomData<T>, |
| 73 | } | 227 | } |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index b62ee8246..cbbc201de 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -1,21 +1,32 @@ | |||
| 1 | //! # I2Cv1 | ||
| 2 | //! | ||
| 3 | //! This implementation is used for STM32F1, STM32F2, STM32F4, and STM32L1 devices. | ||
| 4 | //! | ||
| 5 | //! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead. | ||
| 6 | |||
| 1 | use core::future::poll_fn; | 7 | use core::future::poll_fn; |
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | 8 | use core::task::Poll; |
| 4 | 9 | ||
| 5 | use embassy_embedded_hal::SetConfig; | 10 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_futures::select::{select, Either}; | 11 | use embassy_futures::select::{select, Either}; |
| 7 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 9 | 13 | ||
| 10 | use super::*; | 14 | use super::*; |
| 11 | use crate::dma::{NoDma, Transfer}; | 15 | use crate::dma::Transfer; |
| 12 | use crate::gpio::sealed::AFType; | ||
| 13 | use crate::gpio::Pull; | ||
| 14 | use crate::interrupt::typelevel::Interrupt; | ||
| 15 | use crate::pac::i2c; | 16 | use crate::pac::i2c; |
| 16 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 17 | use crate::{interrupt, Peripheral}; | ||
| 18 | 18 | ||
| 19 | // /!\ /!\ | ||
| 20 | // /!\ Implementation note! /!\ | ||
| 21 | // /!\ /!\ | ||
| 22 | // | ||
| 23 | // It's somewhat unclear whether using interrupts here in a *strictly* one-shot style is actually | ||
| 24 | // what we want! If you are looking in this file because you are doing async I2C and your code is | ||
| 25 | // just totally hanging (sometimes), maybe swing by this issue: | ||
| 26 | // <https://github.com/embassy-rs/embassy/issues/2372>. | ||
| 27 | // | ||
| 28 | // There's some more details there, and we might have a fix for you. But please let us know if you | ||
| 29 | // hit a case like this! | ||
| 19 | pub unsafe fn on_interrupt<T: Instance>() { | 30 | pub unsafe fn on_interrupt<T: Instance>() { |
| 20 | let regs = T::regs(); | 31 | let regs = T::regs(); |
| 21 | // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of | 32 | // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of |
| @@ -30,55 +41,8 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 30 | }); | 41 | }); |
| 31 | } | 42 | } |
| 32 | 43 | ||
| 33 | #[non_exhaustive] | ||
| 34 | #[derive(Copy, Clone, Default)] | ||
| 35 | pub struct Config { | ||
| 36 | pub sda_pullup: bool, | ||
| 37 | pub scl_pullup: bool, | ||
| 38 | } | ||
| 39 | |||
| 40 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | ||
| 41 | phantom: PhantomData<&'d mut T>, | ||
| 42 | #[allow(dead_code)] | ||
| 43 | tx_dma: PeripheralRef<'d, TXDMA>, | ||
| 44 | #[allow(dead_code)] | ||
| 45 | rx_dma: PeripheralRef<'d, RXDMA>, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 44 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 49 | pub fn new( | 45 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 50 | _peri: impl Peripheral<P = T> + 'd, | ||
| 51 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 52 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 53 | _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> | ||
| 54 | + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> | ||
| 55 | + 'd, | ||
| 56 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||
| 57 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||
| 58 | freq: Hertz, | ||
| 59 | config: Config, | ||
| 60 | ) -> Self { | ||
| 61 | into_ref!(scl, sda, tx_dma, rx_dma); | ||
| 62 | |||
| 63 | T::enable_and_reset(); | ||
| 64 | |||
| 65 | scl.set_as_af_pull( | ||
| 66 | scl.af_num(), | ||
| 67 | AFType::OutputOpenDrain, | ||
| 68 | match config.scl_pullup { | ||
| 69 | true => Pull::Up, | ||
| 70 | false => Pull::None, | ||
| 71 | }, | ||
| 72 | ); | ||
| 73 | sda.set_as_af_pull( | ||
| 74 | sda.af_num(), | ||
| 75 | AFType::OutputOpenDrain, | ||
| 76 | match config.sda_pullup { | ||
| 77 | true => Pull::Up, | ||
| 78 | false => Pull::None, | ||
| 79 | }, | ||
| 80 | ); | ||
| 81 | |||
| 82 | T::regs().cr1().modify(|reg| { | 46 | T::regs().cr1().modify(|reg| { |
| 83 | reg.set_pe(false); | 47 | reg.set_pe(false); |
| 84 | //reg.set_anfoff(false); | 48 | //reg.set_anfoff(false); |
| @@ -101,15 +65,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 101 | T::regs().cr1().modify(|reg| { | 65 | T::regs().cr1().modify(|reg| { |
| 102 | reg.set_pe(true); | 66 | reg.set_pe(true); |
| 103 | }); | 67 | }); |
| 104 | |||
| 105 | unsafe { T::EventInterrupt::enable() }; | ||
| 106 | unsafe { T::ErrorInterrupt::enable() }; | ||
| 107 | |||
| 108 | Self { | ||
| 109 | phantom: PhantomData, | ||
| 110 | tx_dma, | ||
| 111 | rx_dma, | ||
| 112 | } | ||
| 113 | } | 68 | } |
| 114 | 69 | ||
| 115 | fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { | 70 | fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { |
| @@ -169,12 +124,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 169 | Ok(sr1) | 124 | Ok(sr1) |
| 170 | } | 125 | } |
| 171 | 126 | ||
| 172 | fn write_bytes( | 127 | fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> { |
| 173 | &mut self, | ||
| 174 | addr: u8, | ||
| 175 | bytes: &[u8], | ||
| 176 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 177 | ) -> Result<(), Error> { | ||
| 178 | // Send a START condition | 128 | // Send a START condition |
| 179 | 129 | ||
| 180 | T::regs().cr1().modify(|reg| { | 130 | T::regs().cr1().modify(|reg| { |
| @@ -183,7 +133,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 183 | 133 | ||
| 184 | // Wait until START condition was generated | 134 | // Wait until START condition was generated |
| 185 | while !Self::check_and_clear_error_flags()?.start() { | 135 | while !Self::check_and_clear_error_flags()?.start() { |
| 186 | check_timeout()?; | 136 | timeout.check()?; |
| 187 | } | 137 | } |
| 188 | 138 | ||
| 189 | // Also wait until signalled we're master and everything is waiting for us | 139 | // Also wait until signalled we're master and everything is waiting for us |
| @@ -193,7 +143,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 193 | let sr2 = T::regs().sr2().read(); | 143 | let sr2 = T::regs().sr2().read(); |
| 194 | !sr2.msl() && !sr2.busy() | 144 | !sr2.msl() && !sr2.busy() |
| 195 | } { | 145 | } { |
| 196 | check_timeout()?; | 146 | timeout.check()?; |
| 197 | } | 147 | } |
| 198 | 148 | ||
| 199 | // Set up current address, we're trying to talk to | 149 | // Set up current address, we're trying to talk to |
| @@ -203,7 +153,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 203 | // Wait for the address to be acknowledged | 153 | // Wait for the address to be acknowledged |
| 204 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 154 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 205 | while !Self::check_and_clear_error_flags()?.addr() { | 155 | while !Self::check_and_clear_error_flags()?.addr() { |
| 206 | check_timeout()?; | 156 | timeout.check()?; |
| 207 | } | 157 | } |
| 208 | 158 | ||
| 209 | // Clear condition by reading SR2 | 159 | // Clear condition by reading SR2 |
| @@ -211,20 +161,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 211 | 161 | ||
| 212 | // Send bytes | 162 | // Send bytes |
| 213 | for c in bytes { | 163 | for c in bytes { |
| 214 | self.send_byte(*c, &check_timeout)?; | 164 | self.send_byte(*c, timeout)?; |
| 215 | } | 165 | } |
| 216 | 166 | ||
| 217 | // Fallthrough is success | 167 | // Fallthrough is success |
| 218 | Ok(()) | 168 | Ok(()) |
| 219 | } | 169 | } |
| 220 | 170 | ||
| 221 | fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 171 | fn send_byte(&self, byte: u8, timeout: Timeout) -> Result<(), Error> { |
| 222 | // Wait until we're ready for sending | 172 | // Wait until we're ready for sending |
| 223 | while { | 173 | while { |
| 224 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 174 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 225 | !Self::check_and_clear_error_flags()?.txe() | 175 | !Self::check_and_clear_error_flags()?.txe() |
| 226 | } { | 176 | } { |
| 227 | check_timeout()?; | 177 | timeout.check()?; |
| 228 | } | 178 | } |
| 229 | 179 | ||
| 230 | // Push out a byte of data | 180 | // Push out a byte of data |
| @@ -235,32 +185,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 235 | // Check for any potential error conditions. | 185 | // Check for any potential error conditions. |
| 236 | !Self::check_and_clear_error_flags()?.btf() | 186 | !Self::check_and_clear_error_flags()?.btf() |
| 237 | } { | 187 | } { |
| 238 | check_timeout()?; | 188 | timeout.check()?; |
| 239 | } | 189 | } |
| 240 | 190 | ||
| 241 | Ok(()) | 191 | Ok(()) |
| 242 | } | 192 | } |
| 243 | 193 | ||
| 244 | fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { | 194 | fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> { |
| 245 | while { | 195 | while { |
| 246 | // Check for any potential error conditions. | 196 | // Check for any potential error conditions. |
| 247 | Self::check_and_clear_error_flags()?; | 197 | Self::check_and_clear_error_flags()?; |
| 248 | 198 | ||
| 249 | !T::regs().sr1().read().rxne() | 199 | !T::regs().sr1().read().rxne() |
| 250 | } { | 200 | } { |
| 251 | check_timeout()?; | 201 | timeout.check()?; |
| 252 | } | 202 | } |
| 253 | 203 | ||
| 254 | let value = T::regs().dr().read().dr(); | 204 | let value = T::regs().dr().read().dr(); |
| 255 | Ok(value) | 205 | Ok(value) |
| 256 | } | 206 | } |
| 257 | 207 | ||
| 258 | pub fn blocking_read_timeout( | 208 | fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> { |
| 259 | &mut self, | ||
| 260 | addr: u8, | ||
| 261 | buffer: &mut [u8], | ||
| 262 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 263 | ) -> Result<(), Error> { | ||
| 264 | if let Some((last, buffer)) = buffer.split_last_mut() { | 209 | if let Some((last, buffer)) = buffer.split_last_mut() { |
| 265 | // Send a START condition and set ACK bit | 210 | // Send a START condition and set ACK bit |
| 266 | T::regs().cr1().modify(|reg| { | 211 | T::regs().cr1().modify(|reg| { |
| @@ -270,7 +215,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 270 | 215 | ||
| 271 | // Wait until START condition was generated | 216 | // Wait until START condition was generated |
| 272 | while !Self::check_and_clear_error_flags()?.start() { | 217 | while !Self::check_and_clear_error_flags()?.start() { |
| 273 | check_timeout()?; | 218 | timeout.check()?; |
| 274 | } | 219 | } |
| 275 | 220 | ||
| 276 | // Also wait until signalled we're master and everything is waiting for us | 221 | // Also wait until signalled we're master and everything is waiting for us |
| @@ -278,7 +223,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 278 | let sr2 = T::regs().sr2().read(); | 223 | let sr2 = T::regs().sr2().read(); |
| 279 | !sr2.msl() && !sr2.busy() | 224 | !sr2.msl() && !sr2.busy() |
| 280 | } { | 225 | } { |
| 281 | check_timeout()?; | 226 | timeout.check()?; |
| 282 | } | 227 | } |
| 283 | 228 | ||
| 284 | // Set up current address, we're trying to talk to | 229 | // Set up current address, we're trying to talk to |
| @@ -287,7 +232,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 287 | // Wait until address was sent | 232 | // Wait until address was sent |
| 288 | // Wait for the address to be acknowledged | 233 | // Wait for the address to be acknowledged |
| 289 | while !Self::check_and_clear_error_flags()?.addr() { | 234 | while !Self::check_and_clear_error_flags()?.addr() { |
| 290 | check_timeout()?; | 235 | timeout.check()?; |
| 291 | } | 236 | } |
| 292 | 237 | ||
| 293 | // Clear condition by reading SR2 | 238 | // Clear condition by reading SR2 |
| @@ -295,7 +240,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 295 | 240 | ||
| 296 | // Receive bytes into buffer | 241 | // Receive bytes into buffer |
| 297 | for c in buffer { | 242 | for c in buffer { |
| 298 | *c = self.recv_byte(&check_timeout)?; | 243 | *c = self.recv_byte(timeout)?; |
| 299 | } | 244 | } |
| 300 | 245 | ||
| 301 | // Prepare to send NACK then STOP after next byte | 246 | // Prepare to send NACK then STOP after next byte |
| @@ -305,11 +250,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 305 | }); | 250 | }); |
| 306 | 251 | ||
| 307 | // Receive last byte | 252 | // Receive last byte |
| 308 | *last = self.recv_byte(&check_timeout)?; | 253 | *last = self.recv_byte(timeout)?; |
| 309 | 254 | ||
| 310 | // Wait for the STOP to be sent. | 255 | // Wait for the STOP to be sent. |
| 311 | while T::regs().cr1().read().stop() { | 256 | while T::regs().cr1().read().stop() { |
| 312 | check_timeout()?; | 257 | timeout.check()?; |
| 313 | } | 258 | } |
| 314 | 259 | ||
| 315 | // Fallthrough is success | 260 | // Fallthrough is success |
| @@ -319,49 +264,37 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 319 | } | 264 | } |
| 320 | } | 265 | } |
| 321 | 266 | ||
| 267 | /// Blocking read. | ||
| 322 | pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { | 268 | pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { |
| 323 | self.blocking_read_timeout(addr, read, || Ok(())) | 269 | self.blocking_read_timeout(addr, read, self.timeout()) |
| 324 | } | 270 | } |
| 325 | 271 | ||
| 326 | pub fn blocking_write_timeout( | 272 | /// Blocking write. |
| 327 | &mut self, | 273 | pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { |
| 328 | addr: u8, | 274 | let timeout = self.timeout(); |
| 329 | write: &[u8], | 275 | |
| 330 | check_timeout: impl Fn() -> Result<(), Error>, | 276 | self.write_bytes(addr, write, timeout)?; |
| 331 | ) -> Result<(), Error> { | ||
| 332 | self.write_bytes(addr, write, &check_timeout)?; | ||
| 333 | // Send a STOP condition | 277 | // Send a STOP condition |
| 334 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | 278 | T::regs().cr1().modify(|reg| reg.set_stop(true)); |
| 335 | // Wait for STOP condition to transmit. | 279 | // Wait for STOP condition to transmit. |
| 336 | while T::regs().cr1().read().stop() { | 280 | while T::regs().cr1().read().stop() { |
| 337 | check_timeout()?; | 281 | timeout.check()?; |
| 338 | } | 282 | } |
| 339 | 283 | ||
| 340 | // Fallthrough is success | 284 | // Fallthrough is success |
| 341 | Ok(()) | 285 | Ok(()) |
| 342 | } | 286 | } |
| 343 | 287 | ||
| 344 | pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { | 288 | /// Blocking write, restart, read. |
| 345 | self.blocking_write_timeout(addr, write, || Ok(())) | 289 | pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 346 | } | 290 | let timeout = self.timeout(); |
| 347 | 291 | ||
| 348 | pub fn blocking_write_read_timeout( | 292 | self.write_bytes(addr, write, timeout)?; |
| 349 | &mut self, | 293 | self.blocking_read_timeout(addr, read, timeout)?; |
| 350 | addr: u8, | ||
| 351 | write: &[u8], | ||
| 352 | read: &mut [u8], | ||
| 353 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 354 | ) -> Result<(), Error> { | ||
| 355 | self.write_bytes(addr, write, &check_timeout)?; | ||
| 356 | self.blocking_read_timeout(addr, read, &check_timeout)?; | ||
| 357 | 294 | ||
| 358 | Ok(()) | 295 | Ok(()) |
| 359 | } | 296 | } |
| 360 | 297 | ||
| 361 | pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | ||
| 362 | self.blocking_write_read_timeout(addr, write, read, || Ok(())) | ||
| 363 | } | ||
| 364 | |||
| 365 | // Async | 298 | // Async |
| 366 | 299 | ||
| 367 | #[inline] // pretty sure this should always be inlined | 300 | #[inline] // pretty sure this should always be inlined |
| @@ -459,6 +392,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 459 | T::regs().sr2().read(); | 392 | T::regs().sr2().read(); |
| 460 | Poll::Ready(Ok(())) | 393 | Poll::Ready(Ok(())) |
| 461 | } else { | 394 | } else { |
| 395 | // If we need to go around, then re-enable the interrupts, otherwise nothing | ||
| 396 | // can wake us up and we'll hang. | ||
| 397 | Self::enable_interrupts(); | ||
| 462 | Poll::Pending | 398 | Poll::Pending |
| 463 | } | 399 | } |
| 464 | } | 400 | } |
| @@ -522,6 +458,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 522 | Ok(()) | 458 | Ok(()) |
| 523 | } | 459 | } |
| 524 | 460 | ||
| 461 | /// Write. | ||
| 525 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> | 462 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> |
| 526 | where | 463 | where |
| 527 | TXDMA: crate::i2c::TxDma<T>, | 464 | TXDMA: crate::i2c::TxDma<T>, |
| @@ -544,6 +481,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 544 | Ok(()) | 481 | Ok(()) |
| 545 | } | 482 | } |
| 546 | 483 | ||
| 484 | /// Read. | ||
| 547 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> | 485 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> |
| 548 | where | 486 | where |
| 549 | RXDMA: crate::i2c::RxDma<T>, | 487 | RXDMA: crate::i2c::RxDma<T>, |
| @@ -703,6 +641,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 703 | Ok(()) | 641 | Ok(()) |
| 704 | } | 642 | } |
| 705 | 643 | ||
| 644 | /// Write, restart, read. | ||
| 706 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> | 645 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> |
| 707 | where | 646 | where |
| 708 | RXDMA: crate::i2c::RxDma<T>, | 647 | RXDMA: crate::i2c::RxDma<T>, |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8c20e1c54..bd3abaac1 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -4,37 +4,13 @@ use core::task::Poll; | |||
| 4 | 4 | ||
| 5 | use embassy_embedded_hal::SetConfig; | 5 | use embassy_embedded_hal::SetConfig; |
| 6 | use embassy_hal_internal::drop::OnDrop; | 6 | use embassy_hal_internal::drop::OnDrop; |
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 8 | #[cfg(feature = "time")] | ||
| 9 | use embassy_time::{Duration, Instant}; | ||
| 10 | 7 | ||
| 11 | use super::*; | 8 | use super::*; |
| 12 | use crate::dma::{NoDma, Transfer}; | 9 | use crate::dma::Transfer; |
| 13 | use crate::gpio::sealed::AFType; | ||
| 14 | use crate::gpio::Pull; | ||
| 15 | use crate::interrupt::typelevel::Interrupt; | ||
| 16 | use crate::pac::i2c; | 10 | use crate::pac::i2c; |
| 17 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 18 | use crate::{interrupt, Peripheral}; | ||
| 19 | |||
| 20 | #[cfg(feature = "time")] | ||
| 21 | fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { | ||
| 22 | let deadline = Instant::now() + timeout; | ||
| 23 | move || { | ||
| 24 | if Instant::now() > deadline { | ||
| 25 | Err(Error::Timeout) | ||
| 26 | } else { | ||
| 27 | Ok(()) | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | #[cfg(not(feature = "time"))] | ||
| 33 | pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> { | ||
| 34 | move || Ok(()) | ||
| 35 | } | ||
| 36 | 12 | ||
| 37 | pub unsafe fn on_interrupt<T: Instance>() { | 13 | pub(crate) unsafe fn on_interrupt<T: Instance>() { |
| 38 | let regs = T::regs(); | 14 | let regs = T::regs(); |
| 39 | let isr = regs.isr().read(); | 15 | let isr = regs.isr().read(); |
| 40 | 16 | ||
| @@ -48,70 +24,8 @@ pub unsafe fn on_interrupt<T: Instance>() { | |||
| 48 | }); | 24 | }); |
| 49 | } | 25 | } |
| 50 | 26 | ||
| 51 | #[non_exhaustive] | ||
| 52 | #[derive(Copy, Clone)] | ||
| 53 | pub struct Config { | ||
| 54 | pub sda_pullup: bool, | ||
| 55 | pub scl_pullup: bool, | ||
| 56 | #[cfg(feature = "time")] | ||
| 57 | pub transaction_timeout: Duration, | ||
| 58 | } | ||
| 59 | |||
| 60 | impl Default for Config { | ||
| 61 | fn default() -> Self { | ||
| 62 | Self { | ||
| 63 | sda_pullup: false, | ||
| 64 | scl_pullup: false, | ||
| 65 | #[cfg(feature = "time")] | ||
| 66 | transaction_timeout: Duration::from_millis(100), | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { | ||
| 72 | _peri: PeripheralRef<'d, T>, | ||
| 73 | #[allow(dead_code)] | ||
| 74 | tx_dma: PeripheralRef<'d, TXDMA>, | ||
| 75 | #[allow(dead_code)] | ||
| 76 | rx_dma: PeripheralRef<'d, RXDMA>, | ||
| 77 | #[cfg(feature = "time")] | ||
| 78 | timeout: Duration, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 27 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 82 | pub fn new( | 28 | pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { |
| 83 | peri: impl Peripheral<P = T> + 'd, | ||
| 84 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | ||
| 85 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | ||
| 86 | _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> | ||
| 87 | + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> | ||
| 88 | + 'd, | ||
| 89 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||
| 90 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||
| 91 | freq: Hertz, | ||
| 92 | config: Config, | ||
| 93 | ) -> Self { | ||
| 94 | into_ref!(peri, scl, sda, tx_dma, rx_dma); | ||
| 95 | |||
| 96 | T::enable_and_reset(); | ||
| 97 | |||
| 98 | scl.set_as_af_pull( | ||
| 99 | scl.af_num(), | ||
| 100 | AFType::OutputOpenDrain, | ||
| 101 | match config.scl_pullup { | ||
| 102 | true => Pull::Up, | ||
| 103 | false => Pull::None, | ||
| 104 | }, | ||
| 105 | ); | ||
| 106 | sda.set_as_af_pull( | ||
| 107 | sda.af_num(), | ||
| 108 | AFType::OutputOpenDrain, | ||
| 109 | match config.sda_pullup { | ||
| 110 | true => Pull::Up, | ||
| 111 | false => Pull::None, | ||
| 112 | }, | ||
| 113 | ); | ||
| 114 | |||
| 115 | T::regs().cr1().modify(|reg| { | 29 | T::regs().cr1().modify(|reg| { |
| 116 | reg.set_pe(false); | 30 | reg.set_pe(false); |
| 117 | reg.set_anfoff(false); | 31 | reg.set_anfoff(false); |
| @@ -130,17 +44,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 130 | T::regs().cr1().modify(|reg| { | 44 | T::regs().cr1().modify(|reg| { |
| 131 | reg.set_pe(true); | 45 | reg.set_pe(true); |
| 132 | }); | 46 | }); |
| 133 | |||
| 134 | unsafe { T::EventInterrupt::enable() }; | ||
| 135 | unsafe { T::ErrorInterrupt::enable() }; | ||
| 136 | |||
| 137 | Self { | ||
| 138 | _peri: peri, | ||
| 139 | tx_dma, | ||
| 140 | rx_dma, | ||
| 141 | #[cfg(feature = "time")] | ||
| 142 | timeout: config.transaction_timeout, | ||
| 143 | } | ||
| 144 | } | 47 | } |
| 145 | 48 | ||
| 146 | fn master_stop(&mut self) { | 49 | fn master_stop(&mut self) { |
| @@ -153,7 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 153 | stop: Stop, | 56 | stop: Stop, |
| 154 | reload: bool, | 57 | reload: bool, |
| 155 | restart: bool, | 58 | restart: bool, |
| 156 | check_timeout: impl Fn() -> Result<(), Error>, | 59 | timeout: Timeout, |
| 157 | ) -> Result<(), Error> { | 60 | ) -> Result<(), Error> { |
| 158 | assert!(length < 256); | 61 | assert!(length < 256); |
| 159 | 62 | ||
| @@ -162,7 +65,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 162 | // automatically. This could be up to 50% of a bus | 65 | // automatically. This could be up to 50% of a bus |
| 163 | // cycle (ie. up to 0.5/freq) | 66 | // cycle (ie. up to 0.5/freq) |
| 164 | while T::regs().cr2().read().start() { | 67 | while T::regs().cr2().read().start() { |
| 165 | check_timeout()?; | 68 | timeout.check()?; |
| 166 | } | 69 | } |
| 167 | } | 70 | } |
| 168 | 71 | ||
| @@ -189,20 +92,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 189 | Ok(()) | 92 | Ok(()) |
| 190 | } | 93 | } |
| 191 | 94 | ||
| 192 | fn master_write( | 95 | fn master_write(address: u8, length: usize, stop: Stop, reload: bool, timeout: Timeout) -> Result<(), Error> { |
| 193 | address: u8, | ||
| 194 | length: usize, | ||
| 195 | stop: Stop, | ||
| 196 | reload: bool, | ||
| 197 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 198 | ) -> Result<(), Error> { | ||
| 199 | assert!(length < 256); | 96 | assert!(length < 256); |
| 200 | 97 | ||
| 201 | // Wait for any previous address sequence to end | 98 | // Wait for any previous address sequence to end |
| 202 | // automatically. This could be up to 50% of a bus | 99 | // automatically. This could be up to 50% of a bus |
| 203 | // cycle (ie. up to 0.5/freq) | 100 | // cycle (ie. up to 0.5/freq) |
| 204 | while T::regs().cr2().read().start() { | 101 | while T::regs().cr2().read().start() { |
| 205 | check_timeout()?; | 102 | timeout.check()?; |
| 206 | } | 103 | } |
| 207 | 104 | ||
| 208 | let reload = if reload { | 105 | let reload = if reload { |
| @@ -227,15 +124,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 227 | Ok(()) | 124 | Ok(()) |
| 228 | } | 125 | } |
| 229 | 126 | ||
| 230 | fn master_continue( | 127 | fn master_continue(length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> { |
| 231 | length: usize, | ||
| 232 | reload: bool, | ||
| 233 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 234 | ) -> Result<(), Error> { | ||
| 235 | assert!(length < 256 && length > 0); | 128 | assert!(length < 256 && length > 0); |
| 236 | 129 | ||
| 237 | while !T::regs().isr().read().tcr() { | 130 | while !T::regs().isr().read().tcr() { |
| 238 | check_timeout()?; | 131 | timeout.check()?; |
| 239 | } | 132 | } |
| 240 | 133 | ||
| 241 | let reload = if reload { | 134 | let reload = if reload { |
| @@ -261,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 261 | } | 154 | } |
| 262 | } | 155 | } |
| 263 | 156 | ||
| 264 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 157 | fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { |
| 265 | loop { | 158 | loop { |
| 266 | let isr = T::regs().isr().read(); | 159 | let isr = T::regs().isr().read(); |
| 267 | if isr.txe() { | 160 | if isr.txe() { |
| @@ -278,11 +171,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 278 | return Err(Error::Nack); | 171 | return Err(Error::Nack); |
| 279 | } | 172 | } |
| 280 | 173 | ||
| 281 | check_timeout()?; | 174 | timeout.check()?; |
| 282 | } | 175 | } |
| 283 | } | 176 | } |
| 284 | 177 | ||
| 285 | fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 178 | fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { |
| 286 | loop { | 179 | loop { |
| 287 | let isr = T::regs().isr().read(); | 180 | let isr = T::regs().isr().read(); |
| 288 | if isr.rxne() { | 181 | if isr.rxne() { |
| @@ -299,11 +192,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 299 | return Err(Error::Nack); | 192 | return Err(Error::Nack); |
| 300 | } | 193 | } |
| 301 | 194 | ||
| 302 | check_timeout()?; | 195 | timeout.check()?; |
| 303 | } | 196 | } |
| 304 | } | 197 | } |
| 305 | 198 | ||
| 306 | fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 199 | fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { |
| 307 | loop { | 200 | loop { |
| 308 | let isr = T::regs().isr().read(); | 201 | let isr = T::regs().isr().read(); |
| 309 | if isr.tc() { | 202 | if isr.tc() { |
| @@ -320,17 +213,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 320 | return Err(Error::Nack); | 213 | return Err(Error::Nack); |
| 321 | } | 214 | } |
| 322 | 215 | ||
| 323 | check_timeout()?; | 216 | timeout.check()?; |
| 324 | } | 217 | } |
| 325 | } | 218 | } |
| 326 | 219 | ||
| 327 | fn read_internal( | 220 | fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> { |
| 328 | &mut self, | ||
| 329 | address: u8, | ||
| 330 | read: &mut [u8], | ||
| 331 | restart: bool, | ||
| 332 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 333 | ) -> Result<(), Error> { | ||
| 334 | let completed_chunks = read.len() / 255; | 221 | let completed_chunks = read.len() / 255; |
| 335 | let total_chunks = if completed_chunks * 255 == read.len() { | 222 | let total_chunks = if completed_chunks * 255 == read.len() { |
| 336 | completed_chunks | 223 | completed_chunks |
| @@ -345,17 +232,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 345 | Stop::Automatic, | 232 | Stop::Automatic, |
| 346 | last_chunk_idx != 0, | 233 | last_chunk_idx != 0, |
| 347 | restart, | 234 | restart, |
| 348 | &check_timeout, | 235 | timeout, |
| 349 | )?; | 236 | )?; |
| 350 | 237 | ||
| 351 | for (number, chunk) in read.chunks_mut(255).enumerate() { | 238 | for (number, chunk) in read.chunks_mut(255).enumerate() { |
| 352 | if number != 0 { | 239 | if number != 0 { |
| 353 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | 240 | Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?; |
| 354 | } | 241 | } |
| 355 | 242 | ||
| 356 | for byte in chunk { | 243 | for byte in chunk { |
| 357 | // Wait until we have received something | 244 | // Wait until we have received something |
| 358 | self.wait_rxne(&check_timeout)?; | 245 | self.wait_rxne(timeout)?; |
| 359 | 246 | ||
| 360 | *byte = T::regs().rxdr().read().rxdata(); | 247 | *byte = T::regs().rxdr().read().rxdata(); |
| 361 | } | 248 | } |
| @@ -363,13 +250,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 363 | Ok(()) | 250 | Ok(()) |
| 364 | } | 251 | } |
| 365 | 252 | ||
| 366 | fn write_internal( | 253 | fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> { |
| 367 | &mut self, | ||
| 368 | address: u8, | ||
| 369 | write: &[u8], | ||
| 370 | send_stop: bool, | ||
| 371 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 372 | ) -> Result<(), Error> { | ||
| 373 | let completed_chunks = write.len() / 255; | 254 | let completed_chunks = write.len() / 255; |
| 374 | let total_chunks = if completed_chunks * 255 == write.len() { | 255 | let total_chunks = if completed_chunks * 255 == write.len() { |
| 375 | completed_chunks | 256 | completed_chunks |
| @@ -386,7 +267,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 386 | write.len().min(255), | 267 | write.len().min(255), |
| 387 | Stop::Software, | 268 | Stop::Software, |
| 388 | last_chunk_idx != 0, | 269 | last_chunk_idx != 0, |
| 389 | &check_timeout, | 270 | timeout, |
| 390 | ) { | 271 | ) { |
| 391 | if send_stop { | 272 | if send_stop { |
| 392 | self.master_stop(); | 273 | self.master_stop(); |
| @@ -396,14 +277,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 396 | 277 | ||
| 397 | for (number, chunk) in write.chunks(255).enumerate() { | 278 | for (number, chunk) in write.chunks(255).enumerate() { |
| 398 | if number != 0 { | 279 | if number != 0 { |
| 399 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; | 280 | Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?; |
| 400 | } | 281 | } |
| 401 | 282 | ||
| 402 | for byte in chunk { | 283 | for byte in chunk { |
| 403 | // Wait until we are allowed to send data | 284 | // Wait until we are allowed to send data |
| 404 | // (START has been ACKed or last byte when | 285 | // (START has been ACKed or last byte when |
| 405 | // through) | 286 | // through) |
| 406 | if let Err(err) = self.wait_txe(&check_timeout) { | 287 | if let Err(err) = self.wait_txe(timeout) { |
| 407 | if send_stop { | 288 | if send_stop { |
| 408 | self.master_stop(); | 289 | self.master_stop(); |
| 409 | } | 290 | } |
| @@ -414,7 +295,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 414 | } | 295 | } |
| 415 | } | 296 | } |
| 416 | // Wait until the write finishes | 297 | // Wait until the write finishes |
| 417 | let result = self.wait_tc(&check_timeout); | 298 | let result = self.wait_tc(timeout); |
| 418 | if send_stop { | 299 | if send_stop { |
| 419 | self.master_stop(); | 300 | self.master_stop(); |
| 420 | } | 301 | } |
| @@ -427,7 +308,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 427 | write: &[u8], | 308 | write: &[u8], |
| 428 | first_slice: bool, | 309 | first_slice: bool, |
| 429 | last_slice: bool, | 310 | last_slice: bool, |
| 430 | check_timeout: impl Fn() -> Result<(), Error>, | 311 | timeout: Timeout, |
| 431 | ) -> Result<(), Error> | 312 | ) -> Result<(), Error> |
| 432 | where | 313 | where |
| 433 | TXDMA: crate::i2c::TxDma<T>, | 314 | TXDMA: crate::i2c::TxDma<T>, |
| @@ -473,10 +354,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 473 | total_len.min(255), | 354 | total_len.min(255), |
| 474 | Stop::Software, | 355 | Stop::Software, |
| 475 | (total_len > 255) || !last_slice, | 356 | (total_len > 255) || !last_slice, |
| 476 | &check_timeout, | 357 | timeout, |
| 477 | )?; | 358 | )?; |
| 478 | } else { | 359 | } else { |
| 479 | Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; | 360 | Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?; |
| 480 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 361 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 481 | } | 362 | } |
| 482 | } else if !(isr.tcr() || isr.tc()) { | 363 | } else if !(isr.tcr() || isr.tc()) { |
| @@ -487,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 487 | } else { | 368 | } else { |
| 488 | let last_piece = (remaining_len <= 255) && last_slice; | 369 | let last_piece = (remaining_len <= 255) && last_slice; |
| 489 | 370 | ||
| 490 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | 371 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) { |
| 491 | return Poll::Ready(Err(e)); | 372 | return Poll::Ready(Err(e)); |
| 492 | } | 373 | } |
| 493 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 374 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| @@ -502,7 +383,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 502 | 383 | ||
| 503 | if last_slice { | 384 | if last_slice { |
| 504 | // This should be done already | 385 | // This should be done already |
| 505 | self.wait_tc(&check_timeout)?; | 386 | self.wait_tc(timeout)?; |
| 506 | self.master_stop(); | 387 | self.master_stop(); |
| 507 | } | 388 | } |
| 508 | 389 | ||
| @@ -516,7 +397,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 516 | address: u8, | 397 | address: u8, |
| 517 | buffer: &mut [u8], | 398 | buffer: &mut [u8], |
| 518 | restart: bool, | 399 | restart: bool, |
| 519 | check_timeout: impl Fn() -> Result<(), Error>, | 400 | timeout: Timeout, |
| 520 | ) -> Result<(), Error> | 401 | ) -> Result<(), Error> |
| 521 | where | 402 | where |
| 522 | RXDMA: crate::i2c::RxDma<T>, | 403 | RXDMA: crate::i2c::RxDma<T>, |
| @@ -558,7 +439,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 558 | Stop::Software, | 439 | Stop::Software, |
| 559 | total_len > 255, | 440 | total_len > 255, |
| 560 | restart, | 441 | restart, |
| 561 | &check_timeout, | 442 | timeout, |
| 562 | )?; | 443 | )?; |
| 563 | } else if !(isr.tcr() || isr.tc()) { | 444 | } else if !(isr.tcr() || isr.tc()) { |
| 564 | // poll_fn was woken without an interrupt present | 445 | // poll_fn was woken without an interrupt present |
| @@ -568,7 +449,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 568 | } else { | 449 | } else { |
| 569 | let last_piece = remaining_len <= 255; | 450 | let last_piece = remaining_len <= 255; |
| 570 | 451 | ||
| 571 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { | 452 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) { |
| 572 | return Poll::Ready(Err(e)); | 453 | return Poll::Ready(Err(e)); |
| 573 | } | 454 | } |
| 574 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 455 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| @@ -582,7 +463,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 582 | dma_transfer.await; | 463 | dma_transfer.await; |
| 583 | 464 | ||
| 584 | // This should be done already | 465 | // This should be done already |
| 585 | self.wait_tc(&check_timeout)?; | 466 | self.wait_tc(timeout)?; |
| 586 | self.master_stop(); | 467 | self.master_stop(); |
| 587 | 468 | ||
| 588 | drop(on_drop); | 469 | drop(on_drop); |
| @@ -592,69 +473,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 592 | 473 | ||
| 593 | // ========================= | 474 | // ========================= |
| 594 | // Async public API | 475 | // Async public API |
| 595 | #[cfg(feature = "time")] | ||
| 596 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> | ||
| 597 | where | ||
| 598 | TXDMA: crate::i2c::TxDma<T>, | ||
| 599 | { | ||
| 600 | if write.is_empty() { | ||
| 601 | self.write_internal(address, write, true, timeout_fn(self.timeout)) | ||
| 602 | } else { | ||
| 603 | embassy_time::with_timeout( | ||
| 604 | self.timeout, | ||
| 605 | self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)), | ||
| 606 | ) | ||
| 607 | .await | ||
| 608 | .unwrap_or(Err(Error::Timeout)) | ||
| 609 | } | ||
| 610 | } | ||
| 611 | 476 | ||
| 612 | #[cfg(not(feature = "time"))] | 477 | /// Write. |
| 613 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> | 478 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> |
| 614 | where | 479 | where |
| 615 | TXDMA: crate::i2c::TxDma<T>, | 480 | TXDMA: crate::i2c::TxDma<T>, |
| 616 | { | 481 | { |
| 482 | let timeout = self.timeout(); | ||
| 617 | if write.is_empty() { | 483 | if write.is_empty() { |
| 618 | self.write_internal(address, write, true, no_timeout_fn()) | 484 | self.write_internal(address, write, true, timeout) |
| 619 | } else { | 485 | } else { |
| 620 | self.write_dma_internal(address, write, true, true, no_timeout_fn()) | 486 | timeout |
| 487 | .with(self.write_dma_internal(address, write, true, true, timeout)) | ||
| 621 | .await | 488 | .await |
| 622 | } | 489 | } |
| 623 | } | 490 | } |
| 624 | 491 | ||
| 625 | #[cfg(feature = "time")] | 492 | /// Write multiple buffers. |
| 493 | /// | ||
| 494 | /// The buffers are concatenated in a single write transaction. | ||
| 626 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> | 495 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> |
| 627 | where | 496 | where |
| 628 | TXDMA: crate::i2c::TxDma<T>, | 497 | TXDMA: crate::i2c::TxDma<T>, |
| 629 | { | 498 | { |
| 630 | if write.is_empty() { | 499 | let timeout = self.timeout(); |
| 631 | return Err(Error::ZeroLengthTransfer); | ||
| 632 | } | ||
| 633 | let mut iter = write.iter(); | ||
| 634 | |||
| 635 | let mut first = true; | ||
| 636 | let mut current = iter.next(); | ||
| 637 | while let Some(c) = current { | ||
| 638 | let next = iter.next(); | ||
| 639 | let is_last = next.is_none(); | ||
| 640 | |||
| 641 | embassy_time::with_timeout( | ||
| 642 | self.timeout, | ||
| 643 | self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)), | ||
| 644 | ) | ||
| 645 | .await | ||
| 646 | .unwrap_or(Err(Error::Timeout))?; | ||
| 647 | first = false; | ||
| 648 | current = next; | ||
| 649 | } | ||
| 650 | Ok(()) | ||
| 651 | } | ||
| 652 | 500 | ||
| 653 | #[cfg(not(feature = "time"))] | ||
| 654 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> | ||
| 655 | where | ||
| 656 | TXDMA: crate::i2c::TxDma<T>, | ||
| 657 | { | ||
| 658 | if write.is_empty() { | 501 | if write.is_empty() { |
| 659 | return Err(Error::ZeroLengthTransfer); | 502 | return Err(Error::ZeroLengthTransfer); |
| 660 | } | 503 | } |
| @@ -666,95 +509,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 666 | let next = iter.next(); | 509 | let next = iter.next(); |
| 667 | let is_last = next.is_none(); | 510 | let is_last = next.is_none(); |
| 668 | 511 | ||
| 669 | self.write_dma_internal(address, c, first, is_last, no_timeout_fn()) | 512 | let fut = self.write_dma_internal(address, c, first, is_last, timeout); |
| 670 | .await?; | 513 | timeout.with(fut).await?; |
| 671 | first = false; | 514 | first = false; |
| 672 | current = next; | 515 | current = next; |
| 673 | } | 516 | } |
| 674 | Ok(()) | 517 | Ok(()) |
| 675 | } | 518 | } |
| 676 | 519 | ||
| 677 | #[cfg(feature = "time")] | 520 | /// Read. |
| 678 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> | 521 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> |
| 679 | where | 522 | where |
| 680 | RXDMA: crate::i2c::RxDma<T>, | 523 | RXDMA: crate::i2c::RxDma<T>, |
| 681 | { | 524 | { |
| 682 | if buffer.is_empty() { | 525 | let timeout = self.timeout(); |
| 683 | self.read_internal(address, buffer, false, timeout_fn(self.timeout)) | ||
| 684 | } else { | ||
| 685 | embassy_time::with_timeout( | ||
| 686 | self.timeout, | ||
| 687 | self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)), | ||
| 688 | ) | ||
| 689 | .await | ||
| 690 | .unwrap_or(Err(Error::Timeout)) | ||
| 691 | } | ||
| 692 | } | ||
| 693 | 526 | ||
| 694 | #[cfg(not(feature = "time"))] | ||
| 695 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> | ||
| 696 | where | ||
| 697 | RXDMA: crate::i2c::RxDma<T>, | ||
| 698 | { | ||
| 699 | if buffer.is_empty() { | 527 | if buffer.is_empty() { |
| 700 | self.read_internal(address, buffer, false, no_timeout_fn()) | 528 | self.read_internal(address, buffer, false, timeout) |
| 701 | } else { | 529 | } else { |
| 702 | self.read_dma_internal(address, buffer, false, no_timeout_fn()).await | 530 | let fut = self.read_dma_internal(address, buffer, false, timeout); |
| 531 | timeout.with(fut).await | ||
| 703 | } | 532 | } |
| 704 | } | 533 | } |
| 705 | 534 | ||
| 706 | #[cfg(feature = "time")] | 535 | /// Write, restart, read. |
| 707 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> | 536 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> |
| 708 | where | 537 | where |
| 709 | TXDMA: super::TxDma<T>, | 538 | TXDMA: super::TxDma<T>, |
| 710 | RXDMA: super::RxDma<T>, | 539 | RXDMA: super::RxDma<T>, |
| 711 | { | 540 | { |
| 712 | let start_instant = Instant::now(); | 541 | let timeout = self.timeout(); |
| 713 | let check_timeout = timeout_fn(self.timeout); | ||
| 714 | if write.is_empty() { | ||
| 715 | self.write_internal(address, write, false, &check_timeout)?; | ||
| 716 | } else { | ||
| 717 | embassy_time::with_timeout( | ||
| 718 | self.timeout, | ||
| 719 | self.write_dma_internal(address, write, true, true, &check_timeout), | ||
| 720 | ) | ||
| 721 | .await | ||
| 722 | .unwrap_or(Err(Error::Timeout))?; | ||
| 723 | } | ||
| 724 | |||
| 725 | let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant); | ||
| 726 | 542 | ||
| 727 | if read.is_empty() { | ||
| 728 | self.read_internal(address, read, true, &check_timeout)?; | ||
| 729 | } else { | ||
| 730 | embassy_time::with_timeout( | ||
| 731 | time_left_until_timeout, | ||
| 732 | self.read_dma_internal(address, read, true, &check_timeout), | ||
| 733 | ) | ||
| 734 | .await | ||
| 735 | .unwrap_or(Err(Error::Timeout))?; | ||
| 736 | } | ||
| 737 | |||
| 738 | Ok(()) | ||
| 739 | } | ||
| 740 | |||
| 741 | #[cfg(not(feature = "time"))] | ||
| 742 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> | ||
| 743 | where | ||
| 744 | TXDMA: super::TxDma<T>, | ||
| 745 | RXDMA: super::RxDma<T>, | ||
| 746 | { | ||
| 747 | let no_timeout = no_timeout_fn(); | ||
| 748 | if write.is_empty() { | 543 | if write.is_empty() { |
| 749 | self.write_internal(address, write, false, &no_timeout)?; | 544 | self.write_internal(address, write, false, timeout)?; |
| 750 | } else { | 545 | } else { |
| 751 | self.write_dma_internal(address, write, true, true, &no_timeout).await?; | 546 | let fut = self.write_dma_internal(address, write, true, true, timeout); |
| 547 | timeout.with(fut).await?; | ||
| 752 | } | 548 | } |
| 753 | 549 | ||
| 754 | if read.is_empty() { | 550 | if read.is_empty() { |
| 755 | self.read_internal(address, read, true, &no_timeout)?; | 551 | self.read_internal(address, read, true, timeout)?; |
| 756 | } else { | 552 | } else { |
| 757 | self.read_dma_internal(address, read, true, &no_timeout).await?; | 553 | let fut = self.read_dma_internal(address, read, true, timeout); |
| 554 | timeout.with(fut).await?; | ||
| 758 | } | 555 | } |
| 759 | 556 | ||
| 760 | Ok(()) | 557 | Ok(()) |
| @@ -763,105 +560,35 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 763 | // ========================= | 560 | // ========================= |
| 764 | // Blocking public API | 561 | // Blocking public API |
| 765 | 562 | ||
| 766 | #[cfg(feature = "time")] | 563 | /// Blocking read. |
| 767 | pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> { | ||
| 768 | self.read_internal(address, read, false, timeout_fn(timeout)) | ||
| 769 | // Automatic Stop | ||
| 770 | } | ||
| 771 | |||
| 772 | #[cfg(not(feature = "time"))] | ||
| 773 | pub fn blocking_read_timeout( | ||
| 774 | &mut self, | ||
| 775 | address: u8, | ||
| 776 | read: &mut [u8], | ||
| 777 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 778 | ) -> Result<(), Error> { | ||
| 779 | self.read_internal(address, read, false, check_timeout) | ||
| 780 | // Automatic Stop | ||
| 781 | } | ||
| 782 | |||
| 783 | #[cfg(feature = "time")] | ||
| 784 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { | ||
| 785 | self.blocking_read_timeout(address, read, self.timeout) | ||
| 786 | } | ||
| 787 | |||
| 788 | #[cfg(not(feature = "time"))] | ||
| 789 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { | 564 | pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { |
| 790 | self.blocking_read_timeout(address, read, || Ok(())) | 565 | self.read_internal(address, read, false, self.timeout()) |
| 791 | } | ||
| 792 | |||
| 793 | #[cfg(feature = "time")] | ||
| 794 | pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> { | ||
| 795 | self.write_internal(address, write, true, timeout_fn(timeout)) | ||
| 796 | } | ||
| 797 | |||
| 798 | #[cfg(not(feature = "time"))] | ||
| 799 | pub fn blocking_write_timeout( | ||
| 800 | &mut self, | ||
| 801 | address: u8, | ||
| 802 | write: &[u8], | ||
| 803 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 804 | ) -> Result<(), Error> { | ||
| 805 | self.write_internal(address, write, true, check_timeout) | ||
| 806 | } | ||
| 807 | |||
| 808 | #[cfg(feature = "time")] | ||
| 809 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | ||
| 810 | self.blocking_write_timeout(address, write, self.timeout) | ||
| 811 | } | ||
| 812 | |||
| 813 | #[cfg(not(feature = "time"))] | ||
| 814 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { | ||
| 815 | self.blocking_write_timeout(address, write, || Ok(())) | ||
| 816 | } | ||
| 817 | |||
| 818 | #[cfg(feature = "time")] | ||
| 819 | pub fn blocking_write_read_timeout( | ||
| 820 | &mut self, | ||
| 821 | address: u8, | ||
| 822 | write: &[u8], | ||
| 823 | read: &mut [u8], | ||
| 824 | timeout: Duration, | ||
| 825 | ) -> Result<(), Error> { | ||
| 826 | let check_timeout = timeout_fn(timeout); | ||
| 827 | self.write_internal(address, write, false, &check_timeout)?; | ||
| 828 | self.read_internal(address, read, true, &check_timeout) | ||
| 829 | // Automatic Stop | 566 | // Automatic Stop |
| 830 | } | 567 | } |
| 831 | 568 | ||
| 832 | #[cfg(not(feature = "time"))] | 569 | /// Blocking write. |
| 833 | pub fn blocking_write_read_timeout( | 570 | pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { |
| 834 | &mut self, | 571 | self.write_internal(address, write, true, self.timeout()) |
| 835 | address: u8, | ||
| 836 | write: &[u8], | ||
| 837 | read: &mut [u8], | ||
| 838 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 839 | ) -> Result<(), Error> { | ||
| 840 | self.write_internal(address, write, false, &check_timeout)?; | ||
| 841 | self.read_internal(address, read, true, &check_timeout) | ||
| 842 | // Automatic Stop | ||
| 843 | } | ||
| 844 | |||
| 845 | #[cfg(feature = "time")] | ||
| 846 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | ||
| 847 | self.blocking_write_read_timeout(address, write, read, self.timeout) | ||
| 848 | } | 572 | } |
| 849 | 573 | ||
| 850 | #[cfg(not(feature = "time"))] | 574 | /// Blocking write, restart, read. |
| 851 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { | 575 | pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { |
| 852 | self.blocking_write_read_timeout(address, write, read, || Ok(())) | 576 | let timeout = self.timeout(); |
| 577 | self.write_internal(address, write, false, timeout)?; | ||
| 578 | self.read_internal(address, read, true, timeout) | ||
| 579 | // Automatic Stop | ||
| 853 | } | 580 | } |
| 854 | 581 | ||
| 855 | fn blocking_write_vectored_with_timeout( | 582 | /// Blocking write multiple buffers. |
| 856 | &mut self, | 583 | /// |
| 857 | address: u8, | 584 | /// The buffers are concatenated in a single write transaction. |
| 858 | write: &[&[u8]], | 585 | pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { |
| 859 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 860 | ) -> Result<(), Error> { | ||
| 861 | if write.is_empty() { | 586 | if write.is_empty() { |
| 862 | return Err(Error::ZeroLengthTransfer); | 587 | return Err(Error::ZeroLengthTransfer); |
| 863 | } | 588 | } |
| 864 | 589 | ||
| 590 | let timeout = self.timeout(); | ||
| 591 | |||
| 865 | let first_length = write[0].len(); | 592 | let first_length = write[0].len(); |
| 866 | let last_slice_index = write.len() - 1; | 593 | let last_slice_index = write.len() - 1; |
| 867 | 594 | ||
| @@ -870,7 +597,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 870 | first_length.min(255), | 597 | first_length.min(255), |
| 871 | Stop::Software, | 598 | Stop::Software, |
| 872 | (first_length > 255) || (last_slice_index != 0), | 599 | (first_length > 255) || (last_slice_index != 0), |
| 873 | &check_timeout, | 600 | timeout, |
| 874 | ) { | 601 | ) { |
| 875 | self.master_stop(); | 602 | self.master_stop(); |
| 876 | return Err(err); | 603 | return Err(err); |
| @@ -890,7 +617,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 890 | if let Err(err) = Self::master_continue( | 617 | if let Err(err) = Self::master_continue( |
| 891 | slice_len.min(255), | 618 | slice_len.min(255), |
| 892 | (idx != last_slice_index) || (slice_len > 255), | 619 | (idx != last_slice_index) || (slice_len > 255), |
| 893 | &check_timeout, | 620 | timeout, |
| 894 | ) { | 621 | ) { |
| 895 | self.master_stop(); | 622 | self.master_stop(); |
| 896 | return Err(err); | 623 | return Err(err); |
| @@ -902,7 +629,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 902 | if let Err(err) = Self::master_continue( | 629 | if let Err(err) = Self::master_continue( |
| 903 | chunk.len(), | 630 | chunk.len(), |
| 904 | (number != last_chunk_idx) || (idx != last_slice_index), | 631 | (number != last_chunk_idx) || (idx != last_slice_index), |
| 905 | &check_timeout, | 632 | timeout, |
| 906 | ) { | 633 | ) { |
| 907 | self.master_stop(); | 634 | self.master_stop(); |
| 908 | return Err(err); | 635 | return Err(err); |
| @@ -913,7 +640,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 913 | // Wait until we are allowed to send data | 640 | // Wait until we are allowed to send data |
| 914 | // (START has been ACKed or last byte when | 641 | // (START has been ACKed or last byte when |
| 915 | // through) | 642 | // through) |
| 916 | if let Err(err) = self.wait_txe(&check_timeout) { | 643 | if let Err(err) = self.wait_txe(timeout) { |
| 917 | self.master_stop(); | 644 | self.master_stop(); |
| 918 | return Err(err); | 645 | return Err(err); |
| 919 | } | 646 | } |
| @@ -925,41 +652,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 925 | } | 652 | } |
| 926 | } | 653 | } |
| 927 | // Wait until the write finishes | 654 | // Wait until the write finishes |
| 928 | let result = self.wait_tc(&check_timeout); | 655 | let result = self.wait_tc(timeout); |
| 929 | self.master_stop(); | 656 | self.master_stop(); |
| 930 | result | 657 | result |
| 931 | } | 658 | } |
| 932 | |||
| 933 | #[cfg(feature = "time")] | ||
| 934 | pub fn blocking_write_vectored_timeout( | ||
| 935 | &mut self, | ||
| 936 | address: u8, | ||
| 937 | write: &[&[u8]], | ||
| 938 | timeout: Duration, | ||
| 939 | ) -> Result<(), Error> { | ||
| 940 | let check_timeout = timeout_fn(timeout); | ||
| 941 | self.blocking_write_vectored_with_timeout(address, write, check_timeout) | ||
| 942 | } | ||
| 943 | |||
| 944 | #[cfg(not(feature = "time"))] | ||
| 945 | pub fn blocking_write_vectored_timeout( | ||
| 946 | &mut self, | ||
| 947 | address: u8, | ||
| 948 | write: &[&[u8]], | ||
| 949 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 950 | ) -> Result<(), Error> { | ||
| 951 | self.blocking_write_vectored_with_timeout(address, write, check_timeout) | ||
| 952 | } | ||
| 953 | |||
| 954 | #[cfg(feature = "time")] | ||
| 955 | pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { | ||
| 956 | self.blocking_write_vectored_timeout(address, write, self.timeout) | ||
| 957 | } | ||
| 958 | |||
| 959 | #[cfg(not(feature = "time"))] | ||
| 960 | pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { | ||
| 961 | self.blocking_write_vectored_timeout(address, write, || Ok(())) | ||
| 962 | } | ||
| 963 | } | 659 | } |
| 964 | 660 | ||
| 965 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { | 661 | impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { |
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 67d40c479..1f85c0bc5 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Inter-IC Sound (I2S) | ||
| 1 | use embassy_hal_internal::into_ref; | 2 | use embassy_hal_internal::into_ref; |
| 2 | 3 | ||
| 3 | use crate::gpio::sealed::{AFType, Pin as _}; | 4 | use crate::gpio::sealed::{AFType, Pin as _}; |
| @@ -8,30 +9,42 @@ use crate::spi::{Config as SpiConfig, *}; | |||
| 8 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 9 | use crate::{Peripheral, PeripheralRef}; | 10 | use crate::{Peripheral, PeripheralRef}; |
| 10 | 11 | ||
| 12 | /// I2S mode | ||
| 11 | #[derive(Copy, Clone)] | 13 | #[derive(Copy, Clone)] |
| 12 | pub enum Mode { | 14 | pub enum Mode { |
| 15 | /// Master mode | ||
| 13 | Master, | 16 | Master, |
| 17 | /// Slave mode | ||
| 14 | Slave, | 18 | Slave, |
| 15 | } | 19 | } |
| 16 | 20 | ||
| 21 | /// I2S function | ||
| 17 | #[derive(Copy, Clone)] | 22 | #[derive(Copy, Clone)] |
| 18 | pub enum Function { | 23 | pub enum Function { |
| 24 | /// Transmit audio data | ||
| 19 | Transmit, | 25 | Transmit, |
| 26 | /// Receive audio data | ||
| 20 | Receive, | 27 | Receive, |
| 21 | } | 28 | } |
| 22 | 29 | ||
| 30 | /// I2C standard | ||
| 23 | #[derive(Copy, Clone)] | 31 | #[derive(Copy, Clone)] |
| 24 | pub enum Standard { | 32 | pub enum Standard { |
| 33 | /// Philips | ||
| 25 | Philips, | 34 | Philips, |
| 35 | /// Most significant bit first. | ||
| 26 | MsbFirst, | 36 | MsbFirst, |
| 37 | /// Least significant bit first. | ||
| 27 | LsbFirst, | 38 | LsbFirst, |
| 39 | /// PCM with long sync. | ||
| 28 | PcmLongSync, | 40 | PcmLongSync, |
| 41 | /// PCM with short sync. | ||
| 29 | PcmShortSync, | 42 | PcmShortSync, |
| 30 | } | 43 | } |
| 31 | 44 | ||
| 32 | impl Standard { | 45 | impl Standard { |
| 33 | #[cfg(any(spi_v1, spi_f1))] | 46 | #[cfg(any(spi_v1, spi_f1))] |
| 34 | pub const fn i2sstd(&self) -> vals::I2sstd { | 47 | const fn i2sstd(&self) -> vals::I2sstd { |
| 35 | match self { | 48 | match self { |
| 36 | Standard::Philips => vals::I2sstd::PHILIPS, | 49 | Standard::Philips => vals::I2sstd::PHILIPS, |
| 37 | Standard::MsbFirst => vals::I2sstd::MSB, | 50 | Standard::MsbFirst => vals::I2sstd::MSB, |
| @@ -42,7 +55,7 @@ impl Standard { | |||
| 42 | } | 55 | } |
| 43 | 56 | ||
| 44 | #[cfg(any(spi_v1, spi_f1))] | 57 | #[cfg(any(spi_v1, spi_f1))] |
| 45 | pub const fn pcmsync(&self) -> vals::Pcmsync { | 58 | const fn pcmsync(&self) -> vals::Pcmsync { |
| 46 | match self { | 59 | match self { |
| 47 | Standard::PcmLongSync => vals::Pcmsync::LONG, | 60 | Standard::PcmLongSync => vals::Pcmsync::LONG, |
| 48 | _ => vals::Pcmsync::SHORT, | 61 | _ => vals::Pcmsync::SHORT, |
| @@ -50,6 +63,7 @@ impl Standard { | |||
| 50 | } | 63 | } |
| 51 | } | 64 | } |
| 52 | 65 | ||
| 66 | /// I2S data format. | ||
| 53 | #[derive(Copy, Clone)] | 67 | #[derive(Copy, Clone)] |
| 54 | pub enum Format { | 68 | pub enum Format { |
| 55 | /// 16 bit data length on 16 bit wide channel | 69 | /// 16 bit data length on 16 bit wide channel |
| @@ -64,7 +78,7 @@ pub enum Format { | |||
| 64 | 78 | ||
| 65 | impl Format { | 79 | impl Format { |
| 66 | #[cfg(any(spi_v1, spi_f1))] | 80 | #[cfg(any(spi_v1, spi_f1))] |
| 67 | pub const fn datlen(&self) -> vals::Datlen { | 81 | const fn datlen(&self) -> vals::Datlen { |
| 68 | match self { | 82 | match self { |
| 69 | Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, | 83 | Format::Data16Channel16 => vals::Datlen::SIXTEENBIT, |
| 70 | Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, | 84 | Format::Data16Channel32 => vals::Datlen::SIXTEENBIT, |
| @@ -74,7 +88,7 @@ impl Format { | |||
| 74 | } | 88 | } |
| 75 | 89 | ||
| 76 | #[cfg(any(spi_v1, spi_f1))] | 90 | #[cfg(any(spi_v1, spi_f1))] |
| 77 | pub const fn chlen(&self) -> vals::Chlen { | 91 | const fn chlen(&self) -> vals::Chlen { |
| 78 | match self { | 92 | match self { |
| 79 | Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, | 93 | Format::Data16Channel16 => vals::Chlen::SIXTEENBIT, |
| 80 | Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, | 94 | Format::Data16Channel32 => vals::Chlen::THIRTYTWOBIT, |
| @@ -84,15 +98,18 @@ impl Format { | |||
| 84 | } | 98 | } |
| 85 | } | 99 | } |
| 86 | 100 | ||
| 101 | /// Clock polarity | ||
| 87 | #[derive(Copy, Clone)] | 102 | #[derive(Copy, Clone)] |
| 88 | pub enum ClockPolarity { | 103 | pub enum ClockPolarity { |
| 104 | /// Low on idle. | ||
| 89 | IdleLow, | 105 | IdleLow, |
| 106 | /// High on idle. | ||
| 90 | IdleHigh, | 107 | IdleHigh, |
| 91 | } | 108 | } |
| 92 | 109 | ||
| 93 | impl ClockPolarity { | 110 | impl ClockPolarity { |
| 94 | #[cfg(any(spi_v1, spi_f1))] | 111 | #[cfg(any(spi_v1, spi_f1))] |
| 95 | pub const fn ckpol(&self) -> vals::Ckpol { | 112 | const fn ckpol(&self) -> vals::Ckpol { |
| 96 | match self { | 113 | match self { |
| 97 | ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, | 114 | ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, |
| 98 | ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, | 115 | ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, |
| @@ -109,11 +126,17 @@ impl ClockPolarity { | |||
| 109 | #[non_exhaustive] | 126 | #[non_exhaustive] |
| 110 | #[derive(Copy, Clone)] | 127 | #[derive(Copy, Clone)] |
| 111 | pub struct Config { | 128 | pub struct Config { |
| 129 | /// Mode | ||
| 112 | pub mode: Mode, | 130 | pub mode: Mode, |
| 131 | /// Function (transmit, receive) | ||
| 113 | pub function: Function, | 132 | pub function: Function, |
| 133 | /// Which I2S standard to use. | ||
| 114 | pub standard: Standard, | 134 | pub standard: Standard, |
| 135 | /// Data format. | ||
| 115 | pub format: Format, | 136 | pub format: Format, |
| 137 | /// Clock polarity. | ||
| 116 | pub clock_polarity: ClockPolarity, | 138 | pub clock_polarity: ClockPolarity, |
| 139 | /// True to eanble master clock output from this instance. | ||
| 117 | pub master_clock: bool, | 140 | pub master_clock: bool, |
| 118 | } | 141 | } |
| 119 | 142 | ||
| @@ -130,6 +153,7 @@ impl Default for Config { | |||
| 130 | } | 153 | } |
| 131 | } | 154 | } |
| 132 | 155 | ||
| 156 | /// I2S driver. | ||
| 133 | pub struct I2S<'d, T: Instance, Tx, Rx> { | 157 | pub struct I2S<'d, T: Instance, Tx, Rx> { |
| 134 | _peri: Spi<'d, T, Tx, Rx>, | 158 | _peri: Spi<'d, T, Tx, Rx>, |
| 135 | sd: Option<PeripheralRef<'d, AnyPin>>, | 159 | sd: Option<PeripheralRef<'d, AnyPin>>, |
| @@ -242,6 +266,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | |||
| 242 | } | 266 | } |
| 243 | } | 267 | } |
| 244 | 268 | ||
| 269 | /// Write audio data. | ||
| 245 | pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> | 270 | pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> |
| 246 | where | 271 | where |
| 247 | Tx: TxDma<T>, | 272 | Tx: TxDma<T>, |
| @@ -249,6 +274,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> { | |||
| 249 | self._peri.write(data).await | 274 | self._peri.write(data).await |
| 250 | } | 275 | } |
| 251 | 276 | ||
| 277 | /// Read audio data. | ||
| 252 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> | 278 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> |
| 253 | where | 279 | where |
| 254 | Tx: TxDma<T>, | 280 | Tx: TxDma<T>, |
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 4006dee19..663a7f59d 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Inter-Process Communication Controller (IPCC) | ||
| 2 | |||
| 1 | use core::future::poll_fn; | 3 | use core::future::poll_fn; |
| 2 | use core::sync::atomic::{compiler_fence, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 3 | use core::task::Poll; | 5 | use core::task::Poll; |
| @@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive | |||
| 41 | } | 43 | } |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 46 | /// TX interrupt handler. | ||
| 44 | pub struct TransmitInterruptHandler {} | 47 | pub struct TransmitInterruptHandler {} |
| 45 | 48 | ||
| 46 | impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { | 49 | impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { |
| @@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi | |||
| 72 | } | 75 | } |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 78 | /// IPCC config. | ||
| 75 | #[non_exhaustive] | 79 | #[non_exhaustive] |
| 76 | #[derive(Clone, Copy, Default)] | 80 | #[derive(Clone, Copy, Default)] |
| 77 | pub struct Config { | 81 | pub struct Config { |
| @@ -79,6 +83,8 @@ pub struct Config { | |||
| 79 | // reserved for future use | 83 | // reserved for future use |
| 80 | } | 84 | } |
| 81 | 85 | ||
| 86 | /// Channel. | ||
| 87 | #[allow(missing_docs)] | ||
| 82 | #[derive(Debug, Clone, Copy)] | 88 | #[derive(Debug, Clone, Copy)] |
| 83 | #[repr(C)] | 89 | #[repr(C)] |
| 84 | pub enum IpccChannel { | 90 | pub enum IpccChannel { |
| @@ -90,9 +96,11 @@ pub enum IpccChannel { | |||
| 90 | Channel6 = 5, | 96 | Channel6 = 5, |
| 91 | } | 97 | } |
| 92 | 98 | ||
| 99 | /// IPCC driver. | ||
| 93 | pub struct Ipcc; | 100 | pub struct Ipcc; |
| 94 | 101 | ||
| 95 | impl Ipcc { | 102 | impl Ipcc { |
| 103 | /// Enable IPCC. | ||
| 96 | pub fn enable(_config: Config) { | 104 | pub fn enable(_config: Config) { |
| 97 | IPCC::enable_and_reset(); | 105 | IPCC::enable_and_reset(); |
| 98 | IPCC::set_cpu2(true); | 106 | IPCC::set_cpu2(true); |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 5d9b4e6a0..f10e9d50d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #![cfg_attr(not(test), no_std)] | 1 | #![cfg_attr(not(test), no_std)] |
| 2 | #![allow(async_fn_in_trait)] | 2 | #![allow(async_fn_in_trait)] |
| 3 | #![warn(missing_docs)] | ||
| 3 | 4 | ||
| 4 | //! ## Feature flags | 5 | //! ## Feature flags |
| 5 | #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] | 6 | #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] |
| @@ -79,6 +80,7 @@ pub(crate) mod _generated { | |||
| 79 | #![allow(dead_code)] | 80 | #![allow(dead_code)] |
| 80 | #![allow(unused_imports)] | 81 | #![allow(unused_imports)] |
| 81 | #![allow(non_snake_case)] | 82 | #![allow(non_snake_case)] |
| 83 | #![allow(missing_docs)] | ||
| 82 | 84 | ||
| 83 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); | 85 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); |
| 84 | } | 86 | } |
| @@ -149,15 +151,33 @@ use crate::interrupt::Priority; | |||
| 149 | pub use crate::pac::NVIC_PRIO_BITS; | 151 | pub use crate::pac::NVIC_PRIO_BITS; |
| 150 | use crate::rcc::sealed::RccPeripheral; | 152 | use crate::rcc::sealed::RccPeripheral; |
| 151 | 153 | ||
| 154 | /// `embassy-stm32` global configuration. | ||
| 152 | #[non_exhaustive] | 155 | #[non_exhaustive] |
| 153 | pub struct Config { | 156 | pub struct Config { |
| 157 | /// RCC config. | ||
| 154 | pub rcc: rcc::Config, | 158 | pub rcc: rcc::Config, |
| 159 | |||
| 160 | /// Enable debug during sleep. | ||
| 161 | /// | ||
| 162 | /// May incrase power consumption. Defaults to true. | ||
| 155 | #[cfg(dbgmcu)] | 163 | #[cfg(dbgmcu)] |
| 156 | pub enable_debug_during_sleep: bool, | 164 | pub enable_debug_during_sleep: bool, |
| 165 | |||
| 166 | /// BDMA interrupt priority. | ||
| 167 | /// | ||
| 168 | /// Defaults to P0 (highest). | ||
| 157 | #[cfg(bdma)] | 169 | #[cfg(bdma)] |
| 158 | pub bdma_interrupt_priority: Priority, | 170 | pub bdma_interrupt_priority: Priority, |
| 171 | |||
| 172 | /// DMA interrupt priority. | ||
| 173 | /// | ||
| 174 | /// Defaults to P0 (highest). | ||
| 159 | #[cfg(dma)] | 175 | #[cfg(dma)] |
| 160 | pub dma_interrupt_priority: Priority, | 176 | pub dma_interrupt_priority: Priority, |
| 177 | |||
| 178 | /// GPDMA interrupt priority. | ||
| 179 | /// | ||
| 180 | /// Defaults to P0 (highest). | ||
| 161 | #[cfg(gpdma)] | 181 | #[cfg(gpdma)] |
| 162 | pub gpdma_interrupt_priority: Priority, | 182 | pub gpdma_interrupt_priority: Priority, |
| 163 | } | 183 | } |
| @@ -178,38 +198,40 @@ impl Default for Config { | |||
| 178 | } | 198 | } |
| 179 | } | 199 | } |
| 180 | 200 | ||
| 181 | /// Initialize embassy. | 201 | /// Initialize the `embassy-stm32` HAL with the provided configuration. |
| 202 | /// | ||
| 203 | /// This returns the peripheral singletons that can be used for creating drivers. | ||
| 204 | /// | ||
| 205 | /// This should only be called once at startup, otherwise it panics. | ||
| 182 | pub fn init(config: Config) -> Peripherals { | 206 | pub fn init(config: Config) -> Peripherals { |
| 183 | critical_section::with(|cs| { | 207 | critical_section::with(|cs| { |
| 184 | let p = Peripherals::take_with_cs(cs); | 208 | let p = Peripherals::take_with_cs(cs); |
| 185 | 209 | ||
| 186 | #[cfg(dbgmcu)] | 210 | #[cfg(dbgmcu)] |
| 187 | if config.enable_debug_during_sleep { | 211 | crate::pac::DBGMCU.cr().modify(|cr| { |
| 188 | crate::pac::DBGMCU.cr().modify(|cr| { | 212 | #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] |
| 189 | #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] | 213 | { |
| 190 | { | 214 | cr.set_dbg_stop(config.enable_debug_during_sleep); |
| 191 | cr.set_dbg_stop(true); | 215 | cr.set_dbg_standby(config.enable_debug_during_sleep); |
| 192 | cr.set_dbg_standby(true); | 216 | } |
| 193 | } | 217 | #[cfg(any( |
| 194 | #[cfg(any( | 218 | dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, |
| 195 | dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, | 219 | dbgmcu_l4, dbgmcu_wb, dbgmcu_wl |
| 196 | dbgmcu_l4, dbgmcu_wb, dbgmcu_wl | 220 | ))] |
| 197 | ))] | 221 | { |
| 198 | { | 222 | cr.set_dbg_sleep(config.enable_debug_during_sleep); |
| 199 | cr.set_dbg_sleep(true); | 223 | cr.set_dbg_stop(config.enable_debug_during_sleep); |
| 200 | cr.set_dbg_stop(true); | 224 | cr.set_dbg_standby(config.enable_debug_during_sleep); |
| 201 | cr.set_dbg_standby(true); | 225 | } |
| 202 | } | 226 | #[cfg(dbgmcu_h7)] |
| 203 | #[cfg(dbgmcu_h7)] | 227 | { |
| 204 | { | 228 | cr.set_d1dbgcken(config.enable_debug_during_sleep); |
| 205 | cr.set_d1dbgcken(true); | 229 | cr.set_d3dbgcken(config.enable_debug_during_sleep); |
| 206 | cr.set_d3dbgcken(true); | 230 | cr.set_dbgsleep_d1(config.enable_debug_during_sleep); |
| 207 | cr.set_dbgsleep_d1(true); | 231 | cr.set_dbgstby_d1(config.enable_debug_during_sleep); |
| 208 | cr.set_dbgstby_d1(true); | 232 | cr.set_dbgstop_d1(config.enable_debug_during_sleep); |
| 209 | cr.set_dbgstop_d1(true); | 233 | } |
| 210 | } | 234 | }); |
| 211 | }); | ||
| 212 | } | ||
| 213 | 235 | ||
| 214 | #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] | 236 | #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] |
| 215 | peripherals::SYSCFG::enable_and_reset_with_cs(cs); | 237 | peripherals::SYSCFG::enable_and_reset_with_cs(cs); |
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 20d8f9045..4fab8dae4 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs | |||
| @@ -1,50 +1,54 @@ | |||
| 1 | /// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating | 1 | //! Low-power support. |
| 2 | /// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which | 2 | //! |
| 3 | /// can use knowledge of which peripherals are currently blocked upon to transparently and safely | 3 | //! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating |
| 4 | /// enter such low-power modes (currently, only `STOP2`) when idle. | 4 | //! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which |
| 5 | /// | 5 | //! can use knowledge of which peripherals are currently blocked upon to transparently and safely |
| 6 | /// The executor determines which peripherals are active by their RCC state; consequently, | 6 | //! enter such low-power modes (currently, only `STOP2`) when idle. |
| 7 | /// low-power states can only be entered if all peripherals have been `drop`'d. There are a few | 7 | //! |
| 8 | /// exceptions to this rule: | 8 | //! The executor determines which peripherals are active by their RCC state; consequently, |
| 9 | /// | 9 | //! low-power states can only be entered if all peripherals have been `drop`'d. There are a few |
| 10 | /// * `GPIO` | 10 | //! exceptions to this rule: |
| 11 | /// * `RCC` | 11 | //! |
| 12 | /// | 12 | //! * `GPIO` |
| 13 | /// Since entering and leaving low-power modes typically incurs a significant latency, the | 13 | //! * `RCC` |
| 14 | /// low-power executor will only attempt to enter when the next timer event is at least | 14 | //! |
| 15 | /// [`time_driver::MIN_STOP_PAUSE`] in the future. | 15 | //! Since entering and leaving low-power modes typically incurs a significant latency, the |
| 16 | /// | 16 | //! low-power executor will only attempt to enter when the next timer event is at least |
| 17 | /// Currently there is no macro analogous to `embassy_executor::main` for this executor; | 17 | //! [`time_driver::MIN_STOP_PAUSE`] in the future. |
| 18 | /// consequently one must define their entrypoint manually. Moveover, you must relinquish control | 18 | //! |
| 19 | /// of the `RTC` peripheral to the executor. This will typically look like | 19 | //! Currently there is no macro analogous to `embassy_executor::main` for this executor; |
| 20 | /// | 20 | //! consequently one must define their entrypoint manually. Moveover, you must relinquish control |
| 21 | /// ```rust,no_run | 21 | //! of the `RTC` peripheral to the executor. This will typically look like |
| 22 | /// use embassy_executor::Spawner; | 22 | //! |
| 23 | /// use embassy_stm32::low_power::Executor; | 23 | //! ```rust,no_run |
| 24 | /// use embassy_stm32::rtc::{Rtc, RtcConfig}; | 24 | //! use embassy_executor::Spawner; |
| 25 | /// use static_cell::make_static; | 25 | //! use embassy_stm32::low_power::Executor; |
| 26 | /// | 26 | //! use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 27 | /// #[cortex_m_rt::entry] | 27 | //! use static_cell::StaticCell; |
| 28 | /// fn main() -> ! { | 28 | //! |
| 29 | /// Executor::take().run(|spawner| { | 29 | //! #[cortex_m_rt::entry] |
| 30 | /// unwrap!(spawner.spawn(async_main(spawner))); | 30 | //! fn main() -> ! { |
| 31 | /// }); | 31 | //! Executor::take().run(|spawner| { |
| 32 | /// } | 32 | //! unwrap!(spawner.spawn(async_main(spawner))); |
| 33 | /// | 33 | //! }); |
| 34 | /// #[embassy_executor::task] | 34 | //! } |
| 35 | /// async fn async_main(spawner: Spawner) { | 35 | //! |
| 36 | /// // initialize the platform... | 36 | //! #[embassy_executor::task] |
| 37 | /// let mut config = embassy_stm32::Config::default(); | 37 | //! async fn async_main(spawner: Spawner) { |
| 38 | /// let p = embassy_stm32::init(config); | 38 | //! // initialize the platform... |
| 39 | /// | 39 | //! let mut config = embassy_stm32::Config::default(); |
| 40 | /// // give the RTC to the executor... | 40 | //! let p = embassy_stm32::init(config); |
| 41 | /// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | 41 | //! |
| 42 | /// let rtc = make_static!(rtc); | 42 | //! // give the RTC to the executor... |
| 43 | /// embassy_stm32::low_power::stop_with_rtc(rtc); | 43 | //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); |
| 44 | /// | 44 | //! static RTC: StaticCell<Rtc> = StaticCell::new(); |
| 45 | /// // your application here... | 45 | //! let rtc = RTC.init(rtc); |
| 46 | /// } | 46 | //! embassy_stm32::low_power::stop_with_rtc(rtc); |
| 47 | /// ``` | 47 | //! |
| 48 | //! // your application here... | ||
| 49 | //! } | ||
| 50 | //! ``` | ||
| 51 | |||
| 48 | use core::arch::asm; | 52 | use core::arch::asm; |
| 49 | use core::marker::PhantomData; | 53 | use core::marker::PhantomData; |
| 50 | use core::sync::atomic::{compiler_fence, Ordering}; | 54 | use core::sync::atomic::{compiler_fence, Ordering}; |
| @@ -64,6 +68,7 @@ static mut EXECUTOR: Option<Executor> = None; | |||
| 64 | foreach_interrupt! { | 68 | foreach_interrupt! { |
| 65 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { | 69 | (RTC, rtc, $block:ident, WKUP, $irq:ident) => { |
| 66 | #[interrupt] | 70 | #[interrupt] |
| 71 | #[allow(non_snake_case)] | ||
| 67 | unsafe fn $irq() { | 72 | unsafe fn $irq() { |
| 68 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 73 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); |
| 69 | } | 74 | } |
| @@ -75,10 +80,15 @@ pub(crate) unsafe fn on_wakeup_irq() { | |||
| 75 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); | 80 | EXECUTOR.as_mut().unwrap().on_wakeup_irq(); |
| 76 | } | 81 | } |
| 77 | 82 | ||
| 83 | /// Configure STOP mode with RTC. | ||
| 78 | pub fn stop_with_rtc(rtc: &'static Rtc) { | 84 | pub fn stop_with_rtc(rtc: &'static Rtc) { |
| 79 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) | 85 | unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) |
| 80 | } | 86 | } |
| 81 | 87 | ||
| 88 | /// Get whether the core is ready to enter the given stop mode. | ||
| 89 | /// | ||
| 90 | /// This will return false if some peripheral driver is in use that | ||
| 91 | /// prevents entering the given stop mode. | ||
| 82 | pub fn stop_ready(stop_mode: StopMode) -> bool { | 92 | pub fn stop_ready(stop_mode: StopMode) -> bool { |
| 83 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { | 93 | match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { |
| 84 | Some(StopMode::Stop2) => true, | 94 | Some(StopMode::Stop2) => true, |
| @@ -87,10 +97,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool { | |||
| 87 | } | 97 | } |
| 88 | } | 98 | } |
| 89 | 99 | ||
| 100 | /// Available stop modes. | ||
| 90 | #[non_exhaustive] | 101 | #[non_exhaustive] |
| 91 | #[derive(PartialEq)] | 102 | #[derive(PartialEq)] |
| 92 | pub enum StopMode { | 103 | pub enum StopMode { |
| 104 | /// STOP 1 | ||
| 93 | Stop1, | 105 | Stop1, |
| 106 | /// STOP 2 | ||
| 94 | Stop2, | 107 | Stop2, |
| 95 | } | 108 | } |
| 96 | 109 | ||
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index e1eb031d1..df8a78bcc 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | //! Operational Amplifier (OPAMP) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 4 | 5 | ||
| 5 | use crate::Peripheral; | 6 | use crate::Peripheral; |
| 6 | 7 | ||
| 8 | /// Gain | ||
| 9 | #[allow(missing_docs)] | ||
| 7 | #[derive(Clone, Copy)] | 10 | #[derive(Clone, Copy)] |
| 8 | pub enum OpAmpGain { | 11 | pub enum OpAmpGain { |
| 9 | Mul1, | 12 | Mul1, |
| @@ -13,6 +16,8 @@ pub enum OpAmpGain { | |||
| 13 | Mul16, | 16 | Mul16, |
| 14 | } | 17 | } |
| 15 | 18 | ||
| 19 | /// Speed | ||
| 20 | #[allow(missing_docs)] | ||
| 16 | #[derive(Clone, Copy)] | 21 | #[derive(Clone, Copy)] |
| 17 | pub enum OpAmpSpeed { | 22 | pub enum OpAmpSpeed { |
| 18 | Normal, | 23 | Normal, |
| @@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { | |||
| 180 | } | 185 | } |
| 181 | } | 186 | } |
| 182 | 187 | ||
| 188 | /// Opamp instance trait. | ||
| 183 | pub trait Instance: sealed::Instance + 'static {} | 189 | pub trait Instance: sealed::Instance + 'static {} |
| 184 | 190 | ||
| 185 | pub(crate) mod sealed { | 191 | pub(crate) mod sealed { |
| @@ -198,8 +204,11 @@ pub(crate) mod sealed { | |||
| 198 | pub trait OutputPin<T: Instance> {} | 204 | pub trait OutputPin<T: Instance> {} |
| 199 | } | 205 | } |
| 200 | 206 | ||
| 207 | /// Non-inverting pin trait. | ||
| 201 | pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} | 208 | pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} |
| 209 | /// Inverting pin trait. | ||
| 202 | pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} | 210 | pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} |
| 211 | /// Output pin trait. | ||
| 203 | pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} | 212 | pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} |
| 204 | 213 | ||
| 205 | macro_rules! impl_opamp_external_output { | 214 | macro_rules! impl_opamp_external_output { |
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index 0412d991a..ecade9b1a 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Enums used in QSPI configuration. | ||
| 2 | |||
| 1 | #[allow(dead_code)] | 3 | #[allow(dead_code)] |
| 2 | #[derive(Copy, Clone)] | 4 | #[derive(Copy, Clone)] |
| 3 | pub(crate) enum QspiMode { | 5 | pub(crate) enum QspiMode { |
| @@ -18,12 +20,17 @@ impl Into<u8> for QspiMode { | |||
| 18 | } | 20 | } |
| 19 | } | 21 | } |
| 20 | 22 | ||
| 23 | /// QSPI lane width | ||
| 21 | #[allow(dead_code)] | 24 | #[allow(dead_code)] |
| 22 | #[derive(Copy, Clone)] | 25 | #[derive(Copy, Clone)] |
| 23 | pub enum QspiWidth { | 26 | pub enum QspiWidth { |
| 27 | /// None | ||
| 24 | NONE, | 28 | NONE, |
| 29 | /// Single lane | ||
| 25 | SING, | 30 | SING, |
| 31 | /// Dual lanes | ||
| 26 | DUAL, | 32 | DUAL, |
| 33 | /// Quad lanes | ||
| 27 | QUAD, | 34 | QUAD, |
| 28 | } | 35 | } |
| 29 | 36 | ||
| @@ -38,10 +45,13 @@ impl Into<u8> for QspiWidth { | |||
| 38 | } | 45 | } |
| 39 | } | 46 | } |
| 40 | 47 | ||
| 48 | /// Flash bank selection | ||
| 41 | #[allow(dead_code)] | 49 | #[allow(dead_code)] |
| 42 | #[derive(Copy, Clone)] | 50 | #[derive(Copy, Clone)] |
| 43 | pub enum FlashSelection { | 51 | pub enum FlashSelection { |
| 52 | /// Bank 1 | ||
| 44 | Flash1, | 53 | Flash1, |
| 54 | /// Bank 2 | ||
| 45 | Flash2, | 55 | Flash2, |
| 46 | } | 56 | } |
| 47 | 57 | ||
| @@ -54,6 +64,8 @@ impl Into<bool> for FlashSelection { | |||
| 54 | } | 64 | } |
| 55 | } | 65 | } |
| 56 | 66 | ||
| 67 | /// QSPI memory size. | ||
| 68 | #[allow(missing_docs)] | ||
| 57 | #[derive(Copy, Clone)] | 69 | #[derive(Copy, Clone)] |
| 58 | pub enum MemorySize { | 70 | pub enum MemorySize { |
| 59 | _1KiB, | 71 | _1KiB, |
| @@ -113,11 +125,16 @@ impl Into<u8> for MemorySize { | |||
| 113 | } | 125 | } |
| 114 | } | 126 | } |
| 115 | 127 | ||
| 128 | /// QSPI Address size | ||
| 116 | #[derive(Copy, Clone)] | 129 | #[derive(Copy, Clone)] |
| 117 | pub enum AddressSize { | 130 | pub enum AddressSize { |
| 131 | /// 8-bit address | ||
| 118 | _8Bit, | 132 | _8Bit, |
| 133 | /// 16-bit address | ||
| 119 | _16Bit, | 134 | _16Bit, |
| 135 | /// 24-bit address | ||
| 120 | _24bit, | 136 | _24bit, |
| 137 | /// 32-bit address | ||
| 121 | _32bit, | 138 | _32bit, |
| 122 | } | 139 | } |
| 123 | 140 | ||
| @@ -132,8 +149,10 @@ impl Into<u8> for AddressSize { | |||
| 132 | } | 149 | } |
| 133 | } | 150 | } |
| 134 | 151 | ||
| 152 | /// Time the Chip Select line stays high. | ||
| 153 | #[allow(missing_docs)] | ||
| 135 | #[derive(Copy, Clone)] | 154 | #[derive(Copy, Clone)] |
| 136 | pub enum ChipSelectHightTime { | 155 | pub enum ChipSelectHighTime { |
| 137 | _1Cycle, | 156 | _1Cycle, |
| 138 | _2Cycle, | 157 | _2Cycle, |
| 139 | _3Cycle, | 158 | _3Cycle, |
| @@ -144,21 +163,23 @@ pub enum ChipSelectHightTime { | |||
| 144 | _8Cycle, | 163 | _8Cycle, |
| 145 | } | 164 | } |
| 146 | 165 | ||
| 147 | impl Into<u8> for ChipSelectHightTime { | 166 | impl Into<u8> for ChipSelectHighTime { |
| 148 | fn into(self) -> u8 { | 167 | fn into(self) -> u8 { |
| 149 | match self { | 168 | match self { |
| 150 | ChipSelectHightTime::_1Cycle => 0, | 169 | ChipSelectHighTime::_1Cycle => 0, |
| 151 | ChipSelectHightTime::_2Cycle => 1, | 170 | ChipSelectHighTime::_2Cycle => 1, |
| 152 | ChipSelectHightTime::_3Cycle => 2, | 171 | ChipSelectHighTime::_3Cycle => 2, |
| 153 | ChipSelectHightTime::_4Cycle => 3, | 172 | ChipSelectHighTime::_4Cycle => 3, |
| 154 | ChipSelectHightTime::_5Cycle => 4, | 173 | ChipSelectHighTime::_5Cycle => 4, |
| 155 | ChipSelectHightTime::_6Cycle => 5, | 174 | ChipSelectHighTime::_6Cycle => 5, |
| 156 | ChipSelectHightTime::_7Cycle => 6, | 175 | ChipSelectHighTime::_7Cycle => 6, |
| 157 | ChipSelectHightTime::_8Cycle => 7, | 176 | ChipSelectHighTime::_8Cycle => 7, |
| 158 | } | 177 | } |
| 159 | } | 178 | } |
| 160 | } | 179 | } |
| 161 | 180 | ||
| 181 | /// FIFO threshold. | ||
| 182 | #[allow(missing_docs)] | ||
| 162 | #[derive(Copy, Clone)] | 183 | #[derive(Copy, Clone)] |
| 163 | pub enum FIFOThresholdLevel { | 184 | pub enum FIFOThresholdLevel { |
| 164 | _1Bytes, | 185 | _1Bytes, |
| @@ -234,6 +255,8 @@ impl Into<u8> for FIFOThresholdLevel { | |||
| 234 | } | 255 | } |
| 235 | } | 256 | } |
| 236 | 257 | ||
| 258 | /// Dummy cycle count | ||
| 259 | #[allow(missing_docs)] | ||
| 237 | #[derive(Copy, Clone)] | 260 | #[derive(Copy, Clone)] |
| 238 | pub enum DummyCycles { | 261 | pub enum DummyCycles { |
| 239 | _0, | 262 | _0, |
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 4b0e8ecef..8a709a89e 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Quad Serial Peripheral Interface (QSPI) | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 3 | pub mod enums; | 5 | pub mod enums; |
| @@ -12,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs; | |||
| 12 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 13 | use crate::{peripherals, Peripheral}; | 15 | use crate::{peripherals, Peripheral}; |
| 14 | 16 | ||
| 17 | /// QSPI transfer configuration. | ||
| 15 | pub struct TransferConfig { | 18 | pub struct TransferConfig { |
| 16 | /// Instraction width (IMODE) | 19 | /// Instraction width (IMODE) |
| 17 | pub iwidth: QspiWidth, | 20 | pub iwidth: QspiWidth, |
| @@ -43,6 +46,7 @@ impl Default for TransferConfig { | |||
| 43 | } | 46 | } |
| 44 | } | 47 | } |
| 45 | 48 | ||
| 49 | /// QSPI driver configuration. | ||
| 46 | pub struct Config { | 50 | pub struct Config { |
| 47 | /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. | 51 | /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. |
| 48 | /// If you need other value the whose predefined use `Other` variant. | 52 | /// If you need other value the whose predefined use `Other` variant. |
| @@ -54,7 +58,7 @@ pub struct Config { | |||
| 54 | /// Number of bytes to trigger FIFO threshold flag. | 58 | /// Number of bytes to trigger FIFO threshold flag. |
| 55 | pub fifo_threshold: FIFOThresholdLevel, | 59 | pub fifo_threshold: FIFOThresholdLevel, |
| 56 | /// Minimum number of cycles that chip select must be high between issued commands | 60 | /// Minimum number of cycles that chip select must be high between issued commands |
| 57 | pub cs_high_time: ChipSelectHightTime, | 61 | pub cs_high_time: ChipSelectHighTime, |
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | impl Default for Config { | 64 | impl Default for Config { |
| @@ -64,11 +68,12 @@ impl Default for Config { | |||
| 64 | address_size: AddressSize::_24bit, | 68 | address_size: AddressSize::_24bit, |
| 65 | prescaler: 128, | 69 | prescaler: 128, |
| 66 | fifo_threshold: FIFOThresholdLevel::_17Bytes, | 70 | fifo_threshold: FIFOThresholdLevel::_17Bytes, |
| 67 | cs_high_time: ChipSelectHightTime::_5Cycle, | 71 | cs_high_time: ChipSelectHighTime::_5Cycle, |
| 68 | } | 72 | } |
| 69 | } | 73 | } |
| 70 | } | 74 | } |
| 71 | 75 | ||
| 76 | /// QSPI driver. | ||
| 72 | #[allow(dead_code)] | 77 | #[allow(dead_code)] |
| 73 | pub struct Qspi<'d, T: Instance, Dma> { | 78 | pub struct Qspi<'d, T: Instance, Dma> { |
| 74 | _peri: PeripheralRef<'d, T>, | 79 | _peri: PeripheralRef<'d, T>, |
| @@ -83,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> { | |||
| 83 | } | 88 | } |
| 84 | 89 | ||
| 85 | impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | 90 | impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { |
| 91 | /// Create a new QSPI driver for bank 1. | ||
| 86 | pub fn new_bk1( | 92 | pub fn new_bk1( |
| 87 | peri: impl Peripheral<P = T> + 'd, | 93 | peri: impl Peripheral<P = T> + 'd, |
| 88 | d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, | 94 | d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, |
| @@ -119,10 +125,11 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 119 | Some(nss.map_into()), | 125 | Some(nss.map_into()), |
| 120 | dma, | 126 | dma, |
| 121 | config, | 127 | config, |
| 122 | FlashSelection::Flash2, | 128 | FlashSelection::Flash1, |
| 123 | ) | 129 | ) |
| 124 | } | 130 | } |
| 125 | 131 | ||
| 132 | /// Create a new QSPI driver for bank 2. | ||
| 126 | pub fn new_bk2( | 133 | pub fn new_bk2( |
| 127 | peri: impl Peripheral<P = T> + 'd, | 134 | peri: impl Peripheral<P = T> + 'd, |
| 128 | d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, | 135 | d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, |
| @@ -221,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 221 | } | 228 | } |
| 222 | } | 229 | } |
| 223 | 230 | ||
| 231 | /// Do a QSPI command. | ||
| 224 | pub fn command(&mut self, transaction: TransferConfig) { | 232 | pub fn command(&mut self, transaction: TransferConfig) { |
| 225 | #[cfg(not(stm32h7))] | 233 | #[cfg(not(stm32h7))] |
| 226 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 234 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| @@ -230,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 230 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 238 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 231 | } | 239 | } |
| 232 | 240 | ||
| 241 | /// Blocking read data. | ||
| 233 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { | 242 | pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { |
| 234 | #[cfg(not(stm32h7))] | 243 | #[cfg(not(stm32h7))] |
| 235 | T::REGS.cr().modify(|v| v.set_dmaen(false)); | 244 | T::REGS.cr().modify(|v| v.set_dmaen(false)); |
| @@ -254,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 254 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 263 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 255 | } | 264 | } |
| 256 | 265 | ||
| 266 | /// Blocking write data. | ||
| 257 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { | 267 | pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { |
| 258 | // STM32H7 does not have dmaen | 268 | // STM32H7 does not have dmaen |
| 259 | #[cfg(not(stm32h7))] | 269 | #[cfg(not(stm32h7))] |
| @@ -276,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 276 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); | 286 | T::REGS.fcr().modify(|v| v.set_ctcf(true)); |
| 277 | } | 287 | } |
| 278 | 288 | ||
| 289 | /// Blocking read data, using DMA. | ||
| 279 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) | 290 | pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) |
| 280 | where | 291 | where |
| 281 | Dma: QuadDma<T>, | 292 | Dma: QuadDma<T>, |
| @@ -308,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { | |||
| 308 | transfer.blocking_wait(); | 319 | transfer.blocking_wait(); |
| 309 | } | 320 | } |
| 310 | 321 | ||
| 322 | /// Blocking write data, using DMA. | ||
| 311 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) | 323 | pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) |
| 312 | where | 324 | where |
| 313 | Dma: QuadDma<T>, | 325 | Dma: QuadDma<T>, |
| @@ -377,6 +389,7 @@ pub(crate) mod sealed { | |||
| 377 | } | 389 | } |
| 378 | } | 390 | } |
| 379 | 391 | ||
| 392 | /// QSPI instance trait. | ||
| 380 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 393 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} |
| 381 | 394 | ||
| 382 | pin_trait!(SckPin, Instance); | 395 | pin_trait!(SckPin, Instance); |
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 1889eb280..15b51a398 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs | |||
| @@ -70,7 +70,9 @@ pub struct Pll { | |||
| 70 | pub mul: PllMul, | 70 | pub mul: PllMul, |
| 71 | 71 | ||
| 72 | /// PLL P division factor. If None, PLL P output is disabled. | 72 | /// PLL P division factor. If None, PLL P output is disabled. |
| 73 | /// On PLL1, it must be even (in particular, it cannot be 1.) | 73 | /// On PLL1, it must be even for most series (in particular, |
| 74 | /// it cannot be 1 in series other than STM32H723/733, | ||
| 75 | /// STM32H725/735 and STM32H730.) | ||
| 74 | pub divp: Option<PllDiv>, | 76 | pub divp: Option<PllDiv>, |
| 75 | /// PLL Q division factor. If None, PLL Q output is disabled. | 77 | /// PLL Q division factor. If None, PLL Q output is disabled. |
| 76 | pub divq: Option<PllDiv>, | 78 | pub divq: Option<PllDiv>, |
| @@ -476,7 +478,14 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 476 | VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)), | 478 | VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)), |
| 477 | VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)), | 479 | VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)), |
| 478 | }; | 480 | }; |
| 479 | #[cfg(all(stm32h7, not(pwr_h7rm0455)))] | 481 | #[cfg(pwr_h7rm0468)] |
| 482 | let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { | ||
| 483 | VoltageScale::Scale0 => (Hertz(520_000_000), Hertz(275_000_000), Hertz(137_500_000)), | ||
| 484 | VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), | ||
| 485 | VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)), | ||
| 486 | VoltageScale::Scale3 => (Hertz(170_000_000), Hertz(85_000_000), Hertz(42_500_000)), | ||
| 487 | }; | ||
| 488 | #[cfg(all(stm32h7, not(any(pwr_h7rm0455, pwr_h7rm0468))))] | ||
| 480 | let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { | 489 | let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale { |
| 481 | VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), | 490 | VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)), |
| 482 | VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), | 491 | VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)), |
| @@ -729,9 +738,12 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { | |||
| 729 | 738 | ||
| 730 | let p = config.divp.map(|div| { | 739 | let p = config.divp.map(|div| { |
| 731 | if num == 0 { | 740 | if num == 0 { |
| 732 | // on PLL1, DIVP must be even. | 741 | // on PLL1, DIVP must be even for most series. |
| 733 | // The enum value is 1 less than the divider, so check it's odd. | 742 | // The enum value is 1 less than the divider, so check it's odd. |
| 743 | #[cfg(not(pwr_h7rm0468))] | ||
| 734 | assert!(div.to_bits() % 2 == 1); | 744 | assert!(div.to_bits() % 2 == 1); |
| 745 | #[cfg(pwr_h7rm0468)] | ||
| 746 | assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0); | ||
| 735 | } | 747 | } |
| 736 | 748 | ||
| 737 | vco_clk / div | 749 | vco_clk / div |
| @@ -820,7 +832,7 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { | |||
| 820 | _ => unreachable!(), | 832 | _ => unreachable!(), |
| 821 | }; | 833 | }; |
| 822 | 834 | ||
| 823 | #[cfg(flash_h7)] | 835 | #[cfg(all(flash_h7, not(pwr_h7rm0468)))] |
| 824 | let (latency, wrhighfreq) = match (vos, clk.0) { | 836 | let (latency, wrhighfreq) = match (vos, clk.0) { |
| 825 | // VOS 0 range VCORE 1.26V - 1.40V | 837 | // VOS 0 range VCORE 1.26V - 1.40V |
| 826 | (VoltageScale::Scale0, ..=70_000_000) => (0, 0), | 838 | (VoltageScale::Scale0, ..=70_000_000) => (0, 0), |
| @@ -849,6 +861,30 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) { | |||
| 849 | _ => unreachable!(), | 861 | _ => unreachable!(), |
| 850 | }; | 862 | }; |
| 851 | 863 | ||
| 864 | // See RM0468 Rev 3 Table 16. FLASH recommended number of wait | ||
| 865 | // states and programming delay | ||
| 866 | #[cfg(all(flash_h7, pwr_h7rm0468))] | ||
| 867 | let (latency, wrhighfreq) = match (vos, clk.0) { | ||
| 868 | // VOS 0 range VCORE 1.26V - 1.40V | ||
| 869 | (VoltageScale::Scale0, ..=70_000_000) => (0, 0), | ||
| 870 | (VoltageScale::Scale0, ..=140_000_000) => (1, 1), | ||
| 871 | (VoltageScale::Scale0, ..=210_000_000) => (2, 2), | ||
| 872 | (VoltageScale::Scale0, ..=275_000_000) => (3, 3), | ||
| 873 | // VOS 1 range VCORE 1.15V - 1.26V | ||
| 874 | (VoltageScale::Scale1, ..=67_000_000) => (0, 0), | ||
| 875 | (VoltageScale::Scale1, ..=133_000_000) => (1, 1), | ||
| 876 | (VoltageScale::Scale1, ..=200_000_000) => (2, 2), | ||
| 877 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 878 | (VoltageScale::Scale2, ..=50_000_000) => (0, 0), | ||
| 879 | (VoltageScale::Scale2, ..=100_000_000) => (1, 1), | ||
| 880 | (VoltageScale::Scale2, ..=150_000_000) => (2, 2), | ||
| 881 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 882 | (VoltageScale::Scale3, ..=35_000_000) => (0, 0), | ||
| 883 | (VoltageScale::Scale3, ..=70_000_000) => (1, 1), | ||
| 884 | (VoltageScale::Scale3, ..=85_000_000) => (2, 2), | ||
| 885 | _ => unreachable!(), | ||
| 886 | }; | ||
| 887 | |||
| 852 | // See RM0455 Rev 10 Table 16. FLASH recommended number of wait | 888 | // See RM0455 Rev 10 Table 16. FLASH recommended number of wait |
| 853 | // states and programming delay | 889 | // states and programming delay |
| 854 | #[cfg(flash_h7ab)] | 890 | #[cfg(flash_h7ab)] |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index dc829a9ad..04a51110c 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -1,4 +1,7 @@ | |||
| 1 | //! Reset and Clock Control (RCC) | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 4 | #![allow(missing_docs)] // TODO | ||
| 2 | 5 | ||
| 3 | use core::mem::MaybeUninit; | 6 | use core::mem::MaybeUninit; |
| 4 | 7 | ||
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 5e6922e9b..ca641f352 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Random Number Generator (RNG) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use core::future::poll_fn; | 4 | use core::future::poll_fn; |
| @@ -13,13 +14,19 @@ use crate::{interrupt, pac, peripherals, Peripheral}; | |||
| 13 | 14 | ||
| 14 | static RNG_WAKER: AtomicWaker = AtomicWaker::new(); | 15 | static RNG_WAKER: AtomicWaker = AtomicWaker::new(); |
| 15 | 16 | ||
| 17 | /// RNG error | ||
| 16 | #[derive(Debug, PartialEq, Eq)] | 18 | #[derive(Debug, PartialEq, Eq)] |
| 17 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 19 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 18 | pub enum Error { | 20 | pub enum Error { |
| 21 | /// Seed error. | ||
| 19 | SeedError, | 22 | SeedError, |
| 23 | /// Clock error. Double-check the RCC configuration, | ||
| 24 | /// see the Reference Manual for details on restrictions | ||
| 25 | /// on RNG clocks. | ||
| 20 | ClockError, | 26 | ClockError, |
| 21 | } | 27 | } |
| 22 | 28 | ||
| 29 | /// RNG interrupt handler. | ||
| 23 | pub struct InterruptHandler<T: Instance> { | 30 | pub struct InterruptHandler<T: Instance> { |
| 24 | _phantom: PhantomData<T>, | 31 | _phantom: PhantomData<T>, |
| 25 | } | 32 | } |
| @@ -34,11 +41,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 34 | } | 41 | } |
| 35 | } | 42 | } |
| 36 | 43 | ||
| 44 | /// RNG driver. | ||
| 37 | pub struct Rng<'d, T: Instance> { | 45 | pub struct Rng<'d, T: Instance> { |
| 38 | _inner: PeripheralRef<'d, T>, | 46 | _inner: PeripheralRef<'d, T>, |
| 39 | } | 47 | } |
| 40 | 48 | ||
| 41 | impl<'d, T: Instance> Rng<'d, T> { | 49 | impl<'d, T: Instance> Rng<'d, T> { |
| 50 | /// Create a new RNG driver. | ||
| 42 | pub fn new( | 51 | pub fn new( |
| 43 | inner: impl Peripheral<P = T> + 'd, | 52 | inner: impl Peripheral<P = T> + 'd, |
| 44 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 53 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -54,6 +63,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 54 | random | 63 | random |
| 55 | } | 64 | } |
| 56 | 65 | ||
| 66 | /// Reset the RNG. | ||
| 57 | #[cfg(rng_v1)] | 67 | #[cfg(rng_v1)] |
| 58 | pub fn reset(&mut self) { | 68 | pub fn reset(&mut self) { |
| 59 | T::regs().cr().write(|reg| { | 69 | T::regs().cr().write(|reg| { |
| @@ -70,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 70 | let _ = self.next_u32(); | 80 | let _ = self.next_u32(); |
| 71 | } | 81 | } |
| 72 | 82 | ||
| 83 | /// Reset the RNG. | ||
| 73 | #[cfg(not(rng_v1))] | 84 | #[cfg(not(rng_v1))] |
| 74 | pub fn reset(&mut self) { | 85 | pub fn reset(&mut self) { |
| 75 | T::regs().cr().write(|reg| { | 86 | T::regs().cr().write(|reg| { |
| @@ -106,7 +117,8 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 106 | while T::regs().cr().read().condrst() {} | 117 | while T::regs().cr().read().condrst() {} |
| 107 | } | 118 | } |
| 108 | 119 | ||
| 109 | pub fn recover_seed_error(&mut self) -> () { | 120 | /// Try to recover from a seed error. |
| 121 | pub fn recover_seed_error(&mut self) { | ||
| 110 | self.reset(); | 122 | self.reset(); |
| 111 | // reset should also clear the SEIS flag | 123 | // reset should also clear the SEIS flag |
| 112 | if T::regs().sr().read().seis() { | 124 | if T::regs().sr().read().seis() { |
| @@ -117,6 +129,7 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 117 | while T::regs().sr().read().secs() {} | 129 | while T::regs().sr().read().secs() {} |
| 118 | } | 130 | } |
| 119 | 131 | ||
| 132 | /// Fill the given slice with random values. | ||
| 120 | pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { | 133 | pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
| 121 | for chunk in dest.chunks_mut(4) { | 134 | for chunk in dest.chunks_mut(4) { |
| 122 | let mut bits = T::regs().sr().read(); | 135 | let mut bits = T::regs().sr().read(); |
| @@ -217,7 +230,9 @@ pub(crate) mod sealed { | |||
| 217 | } | 230 | } |
| 218 | } | 231 | } |
| 219 | 232 | ||
| 233 | /// RNG instance trait. | ||
| 220 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { | 234 | pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPeripheral + 'static + Send { |
| 235 | /// Interrupt for this RNG instance. | ||
| 221 | type Interrupt: interrupt::typelevel::Interrupt; | 236 | type Interrupt: interrupt::typelevel::Interrupt; |
| 222 | } | 237 | } |
| 223 | 238 | ||
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index f4e86dd87..ef92fa4bb 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs | |||
| @@ -104,45 +104,51 @@ pub struct DateTime { | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | impl DateTime { | 106 | impl DateTime { |
| 107 | /// Get the year (0..=4095) | ||
| 107 | pub const fn year(&self) -> u16 { | 108 | pub const fn year(&self) -> u16 { |
| 108 | self.year | 109 | self.year |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 112 | /// Get the month (1..=12, 1 is January) | ||
| 111 | pub const fn month(&self) -> u8 { | 113 | pub const fn month(&self) -> u8 { |
| 112 | self.month | 114 | self.month |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 117 | /// Get the day (1..=31) | ||
| 115 | pub const fn day(&self) -> u8 { | 118 | pub const fn day(&self) -> u8 { |
| 116 | self.day | 119 | self.day |
| 117 | } | 120 | } |
| 118 | 121 | ||
| 122 | /// Get the day of week | ||
| 119 | pub const fn day_of_week(&self) -> DayOfWeek { | 123 | pub const fn day_of_week(&self) -> DayOfWeek { |
| 120 | self.day_of_week | 124 | self.day_of_week |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 127 | /// Get the hour (0..=23) | ||
| 123 | pub const fn hour(&self) -> u8 { | 128 | pub const fn hour(&self) -> u8 { |
| 124 | self.hour | 129 | self.hour |
| 125 | } | 130 | } |
| 126 | 131 | ||
| 132 | /// Get the minute (0..=59) | ||
| 127 | pub const fn minute(&self) -> u8 { | 133 | pub const fn minute(&self) -> u8 { |
| 128 | self.minute | 134 | self.minute |
| 129 | } | 135 | } |
| 130 | 136 | ||
| 137 | /// Get the second (0..=59) | ||
| 131 | pub const fn second(&self) -> u8 { | 138 | pub const fn second(&self) -> u8 { |
| 132 | self.second | 139 | self.second |
| 133 | } | 140 | } |
| 134 | 141 | ||
| 142 | /// Create a new DateTime with the given information. | ||
| 135 | pub fn from( | 143 | pub fn from( |
| 136 | year: u16, | 144 | year: u16, |
| 137 | month: u8, | 145 | month: u8, |
| 138 | day: u8, | 146 | day: u8, |
| 139 | day_of_week: u8, | 147 | day_of_week: DayOfWeek, |
| 140 | hour: u8, | 148 | hour: u8, |
| 141 | minute: u8, | 149 | minute: u8, |
| 142 | second: u8, | 150 | second: u8, |
| 143 | ) -> Result<Self, Error> { | 151 | ) -> Result<Self, Error> { |
| 144 | let day_of_week = day_of_week_from_u8(day_of_week)?; | ||
| 145 | |||
| 146 | if year > 4095 { | 152 | if year > 4095 { |
| 147 | Err(Error::InvalidYear) | 153 | Err(Error::InvalidYear) |
| 148 | } else if month < 1 || month > 12 { | 154 | } else if month < 1 || month > 12 { |
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index b4315f535..1ffb567b3 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! RTC peripheral abstraction | 1 | //! Real Time Clock (RTC) |
| 2 | mod datetime; | 2 | mod datetime; |
| 3 | 3 | ||
| 4 | #[cfg(feature = "low-power")] | 4 | #[cfg(feature = "low-power")] |
| @@ -9,9 +9,9 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |||
| 9 | #[cfg(feature = "low-power")] | 9 | #[cfg(feature = "low-power")] |
| 10 | use embassy_sync::blocking_mutex::Mutex; | 10 | use embassy_sync::blocking_mutex::Mutex; |
| 11 | 11 | ||
| 12 | use self::datetime::day_of_week_to_u8; | ||
| 13 | #[cfg(not(rtc_v2f2))] | 12 | #[cfg(not(rtc_v2f2))] |
| 14 | use self::datetime::RtcInstant; | 13 | use self::datetime::RtcInstant; |
| 14 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; | ||
| 15 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; | 15 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; |
| 16 | use crate::pac::rtc::regs::{Dr, Tr}; | 16 | use crate::pac::rtc::regs::{Dr, Tr}; |
| 17 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| @@ -24,7 +24,7 @@ use crate::time::Hertz; | |||
| 24 | ), | 24 | ), |
| 25 | path = "v2.rs" | 25 | path = "v2.rs" |
| 26 | )] | 26 | )] |
| 27 | #[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")] | 27 | #[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")] |
| 28 | mod _version; | 28 | mod _version; |
| 29 | #[allow(unused_imports)] | 29 | #[allow(unused_imports)] |
| 30 | pub use _version::*; | 30 | pub use _version::*; |
| @@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler { | |||
| 43 | Div16 = 16, | 43 | Div16 = 16, |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | #[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] | 46 | #[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))] |
| 47 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | 47 | impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { |
| 48 | fn from(val: WakeupPrescaler) -> Self { | 48 | fn from(val: WakeupPrescaler) -> Self { |
| 49 | use crate::pac::rtc::vals::Wucksel; | 49 | use crate::pac::rtc::vals::Wucksel; |
| @@ -57,7 +57,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { | |||
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | #[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))] | 60 | #[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))] |
| 61 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { | 61 | impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { |
| 62 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { | 62 | fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { |
| 63 | use crate::pac::rtc::vals::Wucksel; | 63 | use crate::pac::rtc::vals::Wucksel; |
| @@ -102,6 +102,7 @@ pub enum RtcError { | |||
| 102 | NotRunning, | 102 | NotRunning, |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | /// Provides immutable access to the current time of the RTC. | ||
| 105 | pub struct RtcTimeProvider { | 106 | pub struct RtcTimeProvider { |
| 106 | _private: (), | 107 | _private: (), |
| 107 | } | 108 | } |
| @@ -127,10 +128,10 @@ impl RtcTimeProvider { | |||
| 127 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); | 128 | let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); |
| 128 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); | 129 | let hour = bcd2_to_byte((tr.ht(), tr.hu())); |
| 129 | 130 | ||
| 130 | let weekday = dr.wdu(); | 131 | let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?; |
| 131 | let day = bcd2_to_byte((dr.dt(), dr.du())); | 132 | let day = bcd2_to_byte((dr.dt(), dr.du())); |
| 132 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); | 133 | let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); |
| 133 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; | 134 | let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; |
| 134 | 135 | ||
| 135 | DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) | 136 | DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) |
| 136 | }) | 137 | }) |
| @@ -163,7 +164,7 @@ impl RtcTimeProvider { | |||
| 163 | } | 164 | } |
| 164 | } | 165 | } |
| 165 | 166 | ||
| 166 | /// RTC Abstraction | 167 | /// RTC driver. |
| 167 | pub struct Rtc { | 168 | pub struct Rtc { |
| 168 | #[cfg(feature = "low-power")] | 169 | #[cfg(feature = "low-power")] |
| 169 | stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, | 170 | stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, |
| @@ -171,6 +172,7 @@ pub struct Rtc { | |||
| 171 | _private: (), | 172 | _private: (), |
| 172 | } | 173 | } |
| 173 | 174 | ||
| 175 | /// RTC configuration. | ||
| 174 | #[non_exhaustive] | 176 | #[non_exhaustive] |
| 175 | #[derive(Copy, Clone, PartialEq)] | 177 | #[derive(Copy, Clone, PartialEq)] |
| 176 | pub struct RtcConfig { | 178 | pub struct RtcConfig { |
| @@ -188,6 +190,7 @@ impl Default for RtcConfig { | |||
| 188 | } | 190 | } |
| 189 | } | 191 | } |
| 190 | 192 | ||
| 193 | /// Calibration cycle period. | ||
| 191 | #[derive(Copy, Clone, Debug, PartialEq)] | 194 | #[derive(Copy, Clone, Debug, PartialEq)] |
| 192 | #[repr(u8)] | 195 | #[repr(u8)] |
| 193 | pub enum RtcCalibrationCyclePeriod { | 196 | pub enum RtcCalibrationCyclePeriod { |
| @@ -206,6 +209,7 @@ impl Default for RtcCalibrationCyclePeriod { | |||
| 206 | } | 209 | } |
| 207 | 210 | ||
| 208 | impl Rtc { | 211 | impl Rtc { |
| 212 | /// Create a new RTC instance. | ||
| 209 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { | 213 | pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { |
| 210 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] | 214 | #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] |
| 211 | <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset(); | 215 | <RTC as crate::rcc::sealed::RccPeripheral>::enable_and_reset(); |
| @@ -258,7 +262,7 @@ impl Rtc { | |||
| 258 | let (dt, du) = byte_to_bcd2(t.day() as u8); | 262 | let (dt, du) = byte_to_bcd2(t.day() as u8); |
| 259 | let (mt, mu) = byte_to_bcd2(t.month() as u8); | 263 | let (mt, mu) = byte_to_bcd2(t.month() as u8); |
| 260 | let yr = t.year() as u16; | 264 | let yr = t.year() as u16; |
| 261 | let yr_offset = (yr - 1970_u16) as u8; | 265 | let yr_offset = (yr - 2000_u16) as u8; |
| 262 | let (yt, yu) = byte_to_bcd2(yr_offset); | 266 | let (yt, yu) = byte_to_bcd2(yr_offset); |
| 263 | 267 | ||
| 264 | use crate::pac::rtc::vals::Ampm; | 268 | use crate::pac::rtc::vals::Ampm; |
| @@ -315,6 +319,7 @@ impl Rtc { | |||
| 315 | }) | 319 | }) |
| 316 | } | 320 | } |
| 317 | 321 | ||
| 322 | /// Number of backup registers of this instance. | ||
| 318 | pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; | 323 | pub const BACKUP_REGISTER_COUNT: usize = RTC::BACKUP_REGISTER_COUNT; |
| 319 | 324 | ||
| 320 | /// Read content of the backup register. | 325 | /// Read content of the backup register. |
| @@ -343,7 +348,7 @@ impl Rtc { | |||
| 343 | ) { | 348 | ) { |
| 344 | use embassy_time::{Duration, TICK_HZ}; | 349 | use embassy_time::{Duration, TICK_HZ}; |
| 345 | 350 | ||
| 346 | #[cfg(any(rtc_v3, rtc_v3u5))] | 351 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] |
| 347 | use crate::pac::rtc::vals::Calrf; | 352 | use crate::pac::rtc::vals::Calrf; |
| 348 | 353 | ||
| 349 | // Panic if the rcc mod knows we're not using low-power rtc | 354 | // Panic if the rcc mod knows we're not using low-power rtc |
| @@ -370,7 +375,7 @@ impl Rtc { | |||
| 370 | while !regs.isr().read().wutwf() {} | 375 | while !regs.isr().read().wutwf() {} |
| 371 | } | 376 | } |
| 372 | 377 | ||
| 373 | #[cfg(any(rtc_v3, rtc_v3u5))] | 378 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] |
| 374 | { | 379 | { |
| 375 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); | 380 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); |
| 376 | while !regs.icsr().read().wutwf() {} | 381 | while !regs.icsr().read().wutwf() {} |
| @@ -399,7 +404,7 @@ impl Rtc { | |||
| 399 | /// was called, otherwise none | 404 | /// was called, otherwise none |
| 400 | pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { | 405 | pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { |
| 401 | use crate::interrupt::typelevel::Interrupt; | 406 | use crate::interrupt::typelevel::Interrupt; |
| 402 | #[cfg(any(rtc_v3, rtc_v3u5))] | 407 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] |
| 403 | use crate::pac::rtc::vals::Calrf; | 408 | use crate::pac::rtc::vals::Calrf; |
| 404 | 409 | ||
| 405 | let instant = self.instant().unwrap(); | 410 | let instant = self.instant().unwrap(); |
| @@ -415,13 +420,19 @@ impl Rtc { | |||
| 415 | ))] | 420 | ))] |
| 416 | regs.isr().modify(|w| w.set_wutf(false)); | 421 | regs.isr().modify(|w| w.set_wutf(false)); |
| 417 | 422 | ||
| 418 | #[cfg(any(rtc_v3, rtc_v3u5))] | 423 | #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] |
| 419 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); | 424 | regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); |
| 420 | 425 | ||
| 426 | #[cfg(not(stm32l5))] | ||
| 421 | crate::pac::EXTI | 427 | crate::pac::EXTI |
| 422 | .pr(0) | 428 | .pr(0) |
| 423 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | 429 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); |
| 424 | 430 | ||
| 431 | #[cfg(stm32l5)] | ||
| 432 | crate::pac::EXTI | ||
| 433 | .fpr(0) | ||
| 434 | .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); | ||
| 435 | |||
| 425 | <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); | 436 | <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend(); |
| 426 | }); | 437 | }); |
| 427 | } | 438 | } |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 91f08fae4..1eda097a7 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Init, Osel, Pol}; | 1 | use stm32_metapac::rtc::vals::{Osel, Pol}; |
| 2 | 2 | ||
| 3 | use super::sealed; | 3 | use super::sealed; |
| 4 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| @@ -49,7 +49,7 @@ impl super::Rtc { | |||
| 49 | clock_drift = RTC_CALR_MAX_PPM; | 49 | clock_drift = RTC_CALR_MAX_PPM; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | clock_drift = clock_drift / RTC_CALR_RESOLUTION_PPM; | 52 | clock_drift /= RTC_CALR_RESOLUTION_PPM; |
| 53 | 53 | ||
| 54 | self.write(false, |rtc| { | 54 | self.write(false, |rtc| { |
| 55 | rtc.calr().write(|w| { | 55 | rtc.calr().write(|w| { |
| @@ -107,7 +107,7 @@ impl super::Rtc { | |||
| 107 | // true if initf bit indicates RTC peripheral is in init mode | 107 | // true if initf bit indicates RTC peripheral is in init mode |
| 108 | if init_mode && !r.isr().read().initf() { | 108 | if init_mode && !r.isr().read().initf() { |
| 109 | // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode | 109 | // to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode |
| 110 | r.isr().modify(|w| w.set_init(Init::INITMODE)); | 110 | r.isr().modify(|w| w.set_init(true)); |
| 111 | // wait till init state entered | 111 | // wait till init state entered |
| 112 | // ~2 RTCCLK cycles | 112 | // ~2 RTCCLK cycles |
| 113 | while !r.isr().read().initf() {} | 113 | while !r.isr().read().initf() {} |
| @@ -116,7 +116,7 @@ impl super::Rtc { | |||
| 116 | let result = f(&r); | 116 | let result = f(&r); |
| 117 | 117 | ||
| 118 | if init_mode { | 118 | if init_mode { |
| 119 | r.isr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | 119 | r.isr().modify(|w| w.set_init(false)); // Exits init mode |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | // Re-enable write protection. | 122 | // Re-enable write protection. |
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index d2d0d9309..114141b64 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Init, Key, Osel, Pol, TampalrmPu, TampalrmType}; | 1 | use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; |
| 2 | 2 | ||
| 3 | use super::{sealed, RtcCalibrationCyclePeriod}; | 3 | use super::{sealed, RtcCalibrationCyclePeriod}; |
| 4 | use crate::pac::rtc::Rtc; | 4 | use crate::pac::rtc::Rtc; |
| @@ -26,7 +26,7 @@ impl super::Rtc { | |||
| 26 | rtc.cr().modify(|w| { | 26 | rtc.cr().modify(|w| { |
| 27 | w.set_out2en(false); | 27 | w.set_out2en(false); |
| 28 | w.set_tampalrm_type(TampalrmType::PUSHPULL); | 28 | w.set_tampalrm_type(TampalrmType::PUSHPULL); |
| 29 | w.set_tampalrm_pu(TampalrmPu::NOPULLUP); | 29 | w.set_tampalrm_pu(false); |
| 30 | }); | 30 | }); |
| 31 | }); | 31 | }); |
| 32 | } | 32 | } |
| @@ -106,7 +106,7 @@ impl super::Rtc { | |||
| 106 | r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); | 106 | r.wpr().write(|w| w.set_key(Key::DEACTIVATE2)); |
| 107 | 107 | ||
| 108 | if init_mode && !r.icsr().read().initf() { | 108 | if init_mode && !r.icsr().read().initf() { |
| 109 | r.icsr().modify(|w| w.set_init(Init::INITMODE)); | 109 | r.icsr().modify(|w| w.set_init(true)); |
| 110 | // wait till init state entered | 110 | // wait till init state entered |
| 111 | // ~2 RTCCLK cycles | 111 | // ~2 RTCCLK cycles |
| 112 | while !r.icsr().read().initf() {} | 112 | while !r.icsr().read().initf() {} |
| @@ -115,7 +115,7 @@ impl super::Rtc { | |||
| 115 | let result = f(&r); | 115 | let result = f(&r); |
| 116 | 116 | ||
| 117 | if init_mode { | 117 | if init_mode { |
| 118 | r.icsr().modify(|w| w.set_init(Init::FREERUNNINGMODE)); // Exits init mode | 118 | r.icsr().modify(|w| w.set_init(false)); // Exits init mode |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | // Re-enable write protection. | 121 | // Re-enable write protection. |
| @@ -135,6 +135,12 @@ impl sealed::Instance for crate::peripherals::RTC { | |||
| 135 | #[cfg(all(feature = "low-power", stm32g4))] | 135 | #[cfg(all(feature = "low-power", stm32g4))] |
| 136 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; | 136 | type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; |
| 137 | 137 | ||
| 138 | #[cfg(all(feature = "low-power", stm32l5))] | ||
| 139 | const EXTI_WAKEUP_LINE: usize = 17; | ||
| 140 | |||
| 141 | #[cfg(all(feature = "low-power", stm32l5))] | ||
| 142 | type WakeupInterrupt = crate::interrupt::typelevel::RTC; | ||
| 143 | |||
| 138 | fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { | 144 | fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { |
| 139 | #[allow(clippy::if_same_then_else)] | 145 | #[allow(clippy::if_same_then_else)] |
| 140 | if register < Self::BACKUP_REGISTER_COUNT { | 146 | if register < Self::BACKUP_REGISTER_COUNT { |
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index a16d38af1..ef8802184 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs | |||
| @@ -1,8 +1,11 @@ | |||
| 1 | //! Serial Audio Interface (SAI) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use embassy_embedded_hal::SetConfig; | 4 | use core::marker::PhantomData; |
| 5 | |||
| 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 5 | 7 | ||
| 8 | use self::sealed::WhichSubBlock; | ||
| 6 | pub use crate::dma::word; | 9 | pub use crate::dma::word; |
| 7 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; | 10 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; |
| 8 | use crate::gpio::sealed::{AFType, Pin as _}; | 11 | use crate::gpio::sealed::{AFType, Pin as _}; |
| @@ -11,48 +14,32 @@ use crate::pac::sai::{vals, Sai as Regs}; | |||
| 11 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::RccPeripheral; |
| 12 | use crate::{peripherals, Peripheral}; | 15 | use crate::{peripherals, Peripheral}; |
| 13 | 16 | ||
| 17 | /// SAI error | ||
| 14 | #[derive(Debug, PartialEq, Eq)] | 18 | #[derive(Debug, PartialEq, Eq)] |
| 15 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 19 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 16 | pub enum Error { | 20 | pub enum Error { |
| 21 | /// `write` called on a SAI in receive mode. | ||
| 17 | NotATransmitter, | 22 | NotATransmitter, |
| 23 | /// `read` called on a SAI in transmit mode. | ||
| 18 | NotAReceiver, | 24 | NotAReceiver, |
| 19 | OverrunError, | 25 | /// Overrun |
| 26 | Overrun, | ||
| 20 | } | 27 | } |
| 21 | 28 | ||
| 22 | impl From<ringbuffer::OverrunError> for Error { | 29 | impl From<ringbuffer::OverrunError> for Error { |
| 23 | fn from(_: ringbuffer::OverrunError) -> Self { | 30 | fn from(_: ringbuffer::OverrunError) -> Self { |
| 24 | Self::OverrunError | 31 | Self::Overrun |
| 25 | } | 32 | } |
| 26 | } | 33 | } |
| 27 | 34 | ||
| 35 | /// Master/slave mode. | ||
| 28 | #[derive(Copy, Clone)] | 36 | #[derive(Copy, Clone)] |
| 29 | pub enum SyncBlock { | 37 | #[allow(missing_docs)] |
| 30 | None, | ||
| 31 | Sai1BlockA, | ||
| 32 | Sai1BlockB, | ||
| 33 | Sai2BlockA, | ||
| 34 | Sai2BlockB, | ||
| 35 | } | ||
| 36 | |||
| 37 | #[derive(Copy, Clone)] | ||
| 38 | pub enum SyncIn { | ||
| 39 | None, | ||
| 40 | ChannelZero, | ||
| 41 | ChannelOne, | ||
| 42 | } | ||
| 43 | |||
| 44 | #[derive(Copy, Clone)] | ||
| 45 | pub enum Mode { | 38 | pub enum Mode { |
| 46 | Master, | 39 | Master, |
| 47 | Slave, | 40 | Slave, |
| 48 | } | 41 | } |
| 49 | 42 | ||
| 50 | #[derive(Copy, Clone)] | ||
| 51 | pub enum TxRx { | ||
| 52 | Transmitter, | ||
| 53 | Receiver, | ||
| 54 | } | ||
| 55 | |||
| 56 | impl Mode { | 43 | impl Mode { |
| 57 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 44 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 58 | const fn mode(&self, tx_rx: TxRx) -> vals::Mode { | 45 | const fn mode(&self, tx_rx: TxRx) -> vals::Mode { |
| @@ -69,7 +56,17 @@ impl Mode { | |||
| 69 | } | 56 | } |
| 70 | } | 57 | } |
| 71 | 58 | ||
| 59 | /// Direction: transmit or receive | ||
| 72 | #[derive(Copy, Clone)] | 60 | #[derive(Copy, Clone)] |
| 61 | #[allow(missing_docs)] | ||
| 62 | pub enum TxRx { | ||
| 63 | Transmitter, | ||
| 64 | Receiver, | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Data slot size. | ||
| 68 | #[derive(Copy, Clone)] | ||
| 69 | #[allow(missing_docs)] | ||
| 73 | pub enum SlotSize { | 70 | pub enum SlotSize { |
| 74 | DataSize, | 71 | DataSize, |
| 75 | /// 16 bit data length on 16 bit wide channel | 72 | /// 16 bit data length on 16 bit wide channel |
| @@ -80,7 +77,7 @@ pub enum SlotSize { | |||
| 80 | 77 | ||
| 81 | impl SlotSize { | 78 | impl SlotSize { |
| 82 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 79 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 83 | pub const fn slotsz(&self) -> vals::Slotsz { | 80 | const fn slotsz(&self) -> vals::Slotsz { |
| 84 | match self { | 81 | match self { |
| 85 | SlotSize::DataSize => vals::Slotsz::DATASIZE, | 82 | SlotSize::DataSize => vals::Slotsz::DATASIZE, |
| 86 | SlotSize::Channel16 => vals::Slotsz::BIT16, | 83 | SlotSize::Channel16 => vals::Slotsz::BIT16, |
| @@ -89,7 +86,9 @@ impl SlotSize { | |||
| 89 | } | 86 | } |
| 90 | } | 87 | } |
| 91 | 88 | ||
| 89 | /// Data size. | ||
| 92 | #[derive(Copy, Clone)] | 90 | #[derive(Copy, Clone)] |
| 91 | #[allow(missing_docs)] | ||
| 93 | pub enum DataSize { | 92 | pub enum DataSize { |
| 94 | Data8, | 93 | Data8, |
| 95 | Data10, | 94 | Data10, |
| @@ -101,7 +100,7 @@ pub enum DataSize { | |||
| 101 | 100 | ||
| 102 | impl DataSize { | 101 | impl DataSize { |
| 103 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 102 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 104 | pub const fn ds(&self) -> vals::Ds { | 103 | const fn ds(&self) -> vals::Ds { |
| 105 | match self { | 104 | match self { |
| 106 | DataSize::Data8 => vals::Ds::BIT8, | 105 | DataSize::Data8 => vals::Ds::BIT8, |
| 107 | DataSize::Data10 => vals::Ds::BIT10, | 106 | DataSize::Data10 => vals::Ds::BIT10, |
| @@ -113,7 +112,9 @@ impl DataSize { | |||
| 113 | } | 112 | } |
| 114 | } | 113 | } |
| 115 | 114 | ||
| 115 | /// FIFO threshold level. | ||
| 116 | #[derive(Copy, Clone)] | 116 | #[derive(Copy, Clone)] |
| 117 | #[allow(missing_docs)] | ||
| 117 | pub enum FifoThreshold { | 118 | pub enum FifoThreshold { |
| 118 | Empty, | 119 | Empty, |
| 119 | Quarter, | 120 | Quarter, |
| @@ -124,7 +125,7 @@ pub enum FifoThreshold { | |||
| 124 | 125 | ||
| 125 | impl FifoThreshold { | 126 | impl FifoThreshold { |
| 126 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 127 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 127 | pub const fn fth(&self) -> vals::Fth { | 128 | const fn fth(&self) -> vals::Fth { |
| 128 | match self { | 129 | match self { |
| 129 | FifoThreshold::Empty => vals::Fth::EMPTY, | 130 | FifoThreshold::Empty => vals::Fth::EMPTY, |
| 130 | FifoThreshold::Quarter => vals::Fth::QUARTER1, | 131 | FifoThreshold::Quarter => vals::Fth::QUARTER1, |
| @@ -135,38 +136,9 @@ impl FifoThreshold { | |||
| 135 | } | 136 | } |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 139 | /// Output value on mute. | ||
| 138 | #[derive(Copy, Clone)] | 140 | #[derive(Copy, Clone)] |
| 139 | pub enum FifoLevel { | 141 | #[allow(missing_docs)] |
| 140 | Empty, | ||
| 141 | FirstQuarter, | ||
| 142 | SecondQuarter, | ||
| 143 | ThirdQuarter, | ||
| 144 | FourthQuarter, | ||
| 145 | Full, | ||
| 146 | } | ||
| 147 | |||
| 148 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | ||
| 149 | impl From<vals::Flvl> for FifoLevel { | ||
| 150 | fn from(flvl: vals::Flvl) -> Self { | ||
| 151 | match flvl { | ||
| 152 | vals::Flvl::EMPTY => FifoLevel::Empty, | ||
| 153 | vals::Flvl::QUARTER1 => FifoLevel::FirstQuarter, | ||
| 154 | vals::Flvl::QUARTER2 => FifoLevel::SecondQuarter, | ||
| 155 | vals::Flvl::QUARTER3 => FifoLevel::ThirdQuarter, | ||
| 156 | vals::Flvl::QUARTER4 => FifoLevel::FourthQuarter, | ||
| 157 | vals::Flvl::FULL => FifoLevel::Full, | ||
| 158 | _ => FifoLevel::Empty, | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | #[derive(Copy, Clone)] | ||
| 164 | pub enum MuteDetection { | ||
| 165 | NoMute, | ||
| 166 | Mute, | ||
| 167 | } | ||
| 168 | |||
| 169 | #[derive(Copy, Clone)] | ||
| 170 | pub enum MuteValue { | 142 | pub enum MuteValue { |
| 171 | Zero, | 143 | Zero, |
| 172 | LastValue, | 144 | LastValue, |
| @@ -174,7 +146,7 @@ pub enum MuteValue { | |||
| 174 | 146 | ||
| 175 | impl MuteValue { | 147 | impl MuteValue { |
| 176 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 148 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 177 | pub const fn muteval(&self) -> vals::Muteval { | 149 | const fn muteval(&self) -> vals::Muteval { |
| 178 | match self { | 150 | match self { |
| 179 | MuteValue::Zero => vals::Muteval::SENDZERO, | 151 | MuteValue::Zero => vals::Muteval::SENDZERO, |
| 180 | MuteValue::LastValue => vals::Muteval::SENDLAST, | 152 | MuteValue::LastValue => vals::Muteval::SENDLAST, |
| @@ -182,13 +154,9 @@ impl MuteValue { | |||
| 182 | } | 154 | } |
| 183 | } | 155 | } |
| 184 | 156 | ||
| 157 | /// Protocol variant to use. | ||
| 185 | #[derive(Copy, Clone)] | 158 | #[derive(Copy, Clone)] |
| 186 | pub enum OverUnderStatus { | 159 | #[allow(missing_docs)] |
| 187 | NoError, | ||
| 188 | OverUnderRunDetected, | ||
| 189 | } | ||
| 190 | |||
| 191 | #[derive(Copy, Clone)] | ||
| 192 | pub enum Protocol { | 160 | pub enum Protocol { |
| 193 | Free, | 161 | Free, |
| 194 | Spdif, | 162 | Spdif, |
| @@ -197,7 +165,7 @@ pub enum Protocol { | |||
| 197 | 165 | ||
| 198 | impl Protocol { | 166 | impl Protocol { |
| 199 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 167 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 200 | pub const fn prtcfg(&self) -> vals::Prtcfg { | 168 | const fn prtcfg(&self) -> vals::Prtcfg { |
| 201 | match self { | 169 | match self { |
| 202 | Protocol::Free => vals::Prtcfg::FREE, | 170 | Protocol::Free => vals::Prtcfg::FREE, |
| 203 | Protocol::Spdif => vals::Prtcfg::SPDIF, | 171 | Protocol::Spdif => vals::Prtcfg::SPDIF, |
| @@ -206,7 +174,9 @@ impl Protocol { | |||
| 206 | } | 174 | } |
| 207 | } | 175 | } |
| 208 | 176 | ||
| 177 | /// Sync input between SAI units/blocks. | ||
| 209 | #[derive(Copy, Clone, PartialEq)] | 178 | #[derive(Copy, Clone, PartialEq)] |
| 179 | #[allow(missing_docs)] | ||
| 210 | pub enum SyncInput { | 180 | pub enum SyncInput { |
| 211 | /// Not synced to any other SAI unit. | 181 | /// Not synced to any other SAI unit. |
| 212 | None, | 182 | None, |
| @@ -218,7 +188,7 @@ pub enum SyncInput { | |||
| 218 | } | 188 | } |
| 219 | 189 | ||
| 220 | impl SyncInput { | 190 | impl SyncInput { |
| 221 | pub const fn syncen(&self) -> vals::Syncen { | 191 | const fn syncen(&self) -> vals::Syncen { |
| 222 | match self { | 192 | match self { |
| 223 | SyncInput::None => vals::Syncen::ASYNCHRONOUS, | 193 | SyncInput::None => vals::Syncen::ASYNCHRONOUS, |
| 224 | SyncInput::Internal => vals::Syncen::INTERNAL, | 194 | SyncInput::Internal => vals::Syncen::INTERNAL, |
| @@ -228,8 +198,10 @@ impl SyncInput { | |||
| 228 | } | 198 | } |
| 229 | } | 199 | } |
| 230 | 200 | ||
| 201 | /// SAI instance to sync from. | ||
| 231 | #[cfg(sai_v4)] | 202 | #[cfg(sai_v4)] |
| 232 | #[derive(Copy, Clone, PartialEq)] | 203 | #[derive(Copy, Clone, PartialEq)] |
| 204 | #[allow(missing_docs)] | ||
| 233 | pub enum SyncInputInstance { | 205 | pub enum SyncInputInstance { |
| 234 | #[cfg(peri_sai1)] | 206 | #[cfg(peri_sai1)] |
| 235 | Sai1 = 0, | 207 | Sai1 = 0, |
| @@ -241,7 +213,9 @@ pub enum SyncInputInstance { | |||
| 241 | Sai4 = 3, | 213 | Sai4 = 3, |
| 242 | } | 214 | } |
| 243 | 215 | ||
| 216 | /// Channels (stereo or mono). | ||
| 244 | #[derive(Copy, Clone, PartialEq)] | 217 | #[derive(Copy, Clone, PartialEq)] |
| 218 | #[allow(missing_docs)] | ||
| 245 | pub enum StereoMono { | 219 | pub enum StereoMono { |
| 246 | Stereo, | 220 | Stereo, |
| 247 | Mono, | 221 | Mono, |
| @@ -249,7 +223,7 @@ pub enum StereoMono { | |||
| 249 | 223 | ||
| 250 | impl StereoMono { | 224 | impl StereoMono { |
| 251 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 225 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 252 | pub const fn mono(&self) -> vals::Mono { | 226 | const fn mono(&self) -> vals::Mono { |
| 253 | match self { | 227 | match self { |
| 254 | StereoMono::Stereo => vals::Mono::STEREO, | 228 | StereoMono::Stereo => vals::Mono::STEREO, |
| 255 | StereoMono::Mono => vals::Mono::MONO, | 229 | StereoMono::Mono => vals::Mono::MONO, |
| @@ -257,15 +231,18 @@ impl StereoMono { | |||
| 257 | } | 231 | } |
| 258 | } | 232 | } |
| 259 | 233 | ||
| 234 | /// Bit order | ||
| 260 | #[derive(Copy, Clone)] | 235 | #[derive(Copy, Clone)] |
| 261 | pub enum BitOrder { | 236 | pub enum BitOrder { |
| 237 | /// Least significant bit first. | ||
| 262 | LsbFirst, | 238 | LsbFirst, |
| 239 | /// Most significant bit first. | ||
| 263 | MsbFirst, | 240 | MsbFirst, |
| 264 | } | 241 | } |
| 265 | 242 | ||
| 266 | impl BitOrder { | 243 | impl BitOrder { |
| 267 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 244 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 268 | pub const fn lsbfirst(&self) -> vals::Lsbfirst { | 245 | const fn lsbfirst(&self) -> vals::Lsbfirst { |
| 269 | match self { | 246 | match self { |
| 270 | BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, | 247 | BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, |
| 271 | BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, | 248 | BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, |
| @@ -273,6 +250,7 @@ impl BitOrder { | |||
| 273 | } | 250 | } |
| 274 | } | 251 | } |
| 275 | 252 | ||
| 253 | /// Frame sync offset. | ||
| 276 | #[derive(Copy, Clone)] | 254 | #[derive(Copy, Clone)] |
| 277 | pub enum FrameSyncOffset { | 255 | pub enum FrameSyncOffset { |
| 278 | /// This is used in modes other than standard I2S phillips mode | 256 | /// This is used in modes other than standard I2S phillips mode |
| @@ -283,7 +261,7 @@ pub enum FrameSyncOffset { | |||
| 283 | 261 | ||
| 284 | impl FrameSyncOffset { | 262 | impl FrameSyncOffset { |
| 285 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 263 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 286 | pub const fn fsoff(&self) -> vals::Fsoff { | 264 | const fn fsoff(&self) -> vals::Fsoff { |
| 287 | match self { | 265 | match self { |
| 288 | FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, | 266 | FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, |
| 289 | FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, | 267 | FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, |
| @@ -291,15 +269,18 @@ impl FrameSyncOffset { | |||
| 291 | } | 269 | } |
| 292 | } | 270 | } |
| 293 | 271 | ||
| 272 | /// Frame sync polarity | ||
| 294 | #[derive(Copy, Clone)] | 273 | #[derive(Copy, Clone)] |
| 295 | pub enum FrameSyncPolarity { | 274 | pub enum FrameSyncPolarity { |
| 275 | /// Sync signal is active low. | ||
| 296 | ActiveLow, | 276 | ActiveLow, |
| 277 | /// Sync signal is active high | ||
| 297 | ActiveHigh, | 278 | ActiveHigh, |
| 298 | } | 279 | } |
| 299 | 280 | ||
| 300 | impl FrameSyncPolarity { | 281 | impl FrameSyncPolarity { |
| 301 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 282 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 302 | pub const fn fspol(&self) -> vals::Fspol { | 283 | const fn fspol(&self) -> vals::Fspol { |
| 303 | match self { | 284 | match self { |
| 304 | FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, | 285 | FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, |
| 305 | FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, | 286 | FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, |
| @@ -307,7 +288,9 @@ impl FrameSyncPolarity { | |||
| 307 | } | 288 | } |
| 308 | } | 289 | } |
| 309 | 290 | ||
| 291 | /// Sync definition. | ||
| 310 | #[derive(Copy, Clone)] | 292 | #[derive(Copy, Clone)] |
| 293 | #[allow(missing_docs)] | ||
| 311 | pub enum FrameSyncDefinition { | 294 | pub enum FrameSyncDefinition { |
| 312 | StartOfFrame, | 295 | StartOfFrame, |
| 313 | ChannelIdentification, | 296 | ChannelIdentification, |
| @@ -315,7 +298,7 @@ pub enum FrameSyncDefinition { | |||
| 315 | 298 | ||
| 316 | impl FrameSyncDefinition { | 299 | impl FrameSyncDefinition { |
| 317 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 300 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 318 | pub const fn fsdef(&self) -> bool { | 301 | const fn fsdef(&self) -> bool { |
| 319 | match self { | 302 | match self { |
| 320 | FrameSyncDefinition::StartOfFrame => false, | 303 | FrameSyncDefinition::StartOfFrame => false, |
| 321 | FrameSyncDefinition::ChannelIdentification => true, | 304 | FrameSyncDefinition::ChannelIdentification => true, |
| @@ -323,7 +306,9 @@ impl FrameSyncDefinition { | |||
| 323 | } | 306 | } |
| 324 | } | 307 | } |
| 325 | 308 | ||
| 309 | /// Clock strobe. | ||
| 326 | #[derive(Copy, Clone)] | 310 | #[derive(Copy, Clone)] |
| 311 | #[allow(missing_docs)] | ||
| 327 | pub enum ClockStrobe { | 312 | pub enum ClockStrobe { |
| 328 | Falling, | 313 | Falling, |
| 329 | Rising, | 314 | Rising, |
| @@ -331,7 +316,7 @@ pub enum ClockStrobe { | |||
| 331 | 316 | ||
| 332 | impl ClockStrobe { | 317 | impl ClockStrobe { |
| 333 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 318 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 334 | pub const fn ckstr(&self) -> vals::Ckstr { | 319 | const fn ckstr(&self) -> vals::Ckstr { |
| 335 | match self { | 320 | match self { |
| 336 | ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, | 321 | ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, |
| 337 | ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, | 322 | ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, |
| @@ -339,7 +324,9 @@ impl ClockStrobe { | |||
| 339 | } | 324 | } |
| 340 | } | 325 | } |
| 341 | 326 | ||
| 327 | /// Complements format for negative samples. | ||
| 342 | #[derive(Copy, Clone)] | 328 | #[derive(Copy, Clone)] |
| 329 | #[allow(missing_docs)] | ||
| 343 | pub enum ComplementFormat { | 330 | pub enum ComplementFormat { |
| 344 | OnesComplement, | 331 | OnesComplement, |
| 345 | TwosComplement, | 332 | TwosComplement, |
| @@ -347,7 +334,7 @@ pub enum ComplementFormat { | |||
| 347 | 334 | ||
| 348 | impl ComplementFormat { | 335 | impl ComplementFormat { |
| 349 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 336 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 350 | pub const fn cpl(&self) -> vals::Cpl { | 337 | const fn cpl(&self) -> vals::Cpl { |
| 351 | match self { | 338 | match self { |
| 352 | ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, | 339 | ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, |
| 353 | ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, | 340 | ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, |
| @@ -355,7 +342,9 @@ impl ComplementFormat { | |||
| 355 | } | 342 | } |
| 356 | } | 343 | } |
| 357 | 344 | ||
| 345 | /// Companding setting. | ||
| 358 | #[derive(Copy, Clone)] | 346 | #[derive(Copy, Clone)] |
| 347 | #[allow(missing_docs)] | ||
| 359 | pub enum Companding { | 348 | pub enum Companding { |
| 360 | None, | 349 | None, |
| 361 | MuLaw, | 350 | MuLaw, |
| @@ -364,7 +353,7 @@ pub enum Companding { | |||
| 364 | 353 | ||
| 365 | impl Companding { | 354 | impl Companding { |
| 366 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 355 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 367 | pub const fn comp(&self) -> vals::Comp { | 356 | const fn comp(&self) -> vals::Comp { |
| 368 | match self { | 357 | match self { |
| 369 | Companding::None => vals::Comp::NOCOMPANDING, | 358 | Companding::None => vals::Comp::NOCOMPANDING, |
| 370 | Companding::MuLaw => vals::Comp::MULAW, | 359 | Companding::MuLaw => vals::Comp::MULAW, |
| @@ -373,7 +362,9 @@ impl Companding { | |||
| 373 | } | 362 | } |
| 374 | } | 363 | } |
| 375 | 364 | ||
| 365 | /// Output drive | ||
| 376 | #[derive(Copy, Clone)] | 366 | #[derive(Copy, Clone)] |
| 367 | #[allow(missing_docs)] | ||
| 377 | pub enum OutputDrive { | 368 | pub enum OutputDrive { |
| 378 | OnStart, | 369 | OnStart, |
| 379 | Immediately, | 370 | Immediately, |
| @@ -381,7 +372,7 @@ pub enum OutputDrive { | |||
| 381 | 372 | ||
| 382 | impl OutputDrive { | 373 | impl OutputDrive { |
| 383 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 374 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 384 | pub const fn outdriv(&self) -> vals::Outdriv { | 375 | const fn outdriv(&self) -> vals::Outdriv { |
| 385 | match self { | 376 | match self { |
| 386 | OutputDrive::OnStart => vals::Outdriv::ONSTART, | 377 | OutputDrive::OnStart => vals::Outdriv::ONSTART, |
| 387 | OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, | 378 | OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, |
| @@ -389,7 +380,9 @@ impl OutputDrive { | |||
| 389 | } | 380 | } |
| 390 | } | 381 | } |
| 391 | 382 | ||
| 383 | /// Master clock divider. | ||
| 392 | #[derive(Copy, Clone, PartialEq)] | 384 | #[derive(Copy, Clone, PartialEq)] |
| 385 | #[allow(missing_docs)] | ||
| 393 | pub enum MasterClockDivider { | 386 | pub enum MasterClockDivider { |
| 394 | MasterClockDisabled, | 387 | MasterClockDisabled, |
| 395 | Div1, | 388 | Div1, |
| @@ -412,7 +405,7 @@ pub enum MasterClockDivider { | |||
| 412 | 405 | ||
| 413 | impl MasterClockDivider { | 406 | impl MasterClockDivider { |
| 414 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] | 407 | #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] |
| 415 | pub const fn mckdiv(&self) -> u8 { | 408 | const fn mckdiv(&self) -> u8 { |
| 416 | match self { | 409 | match self { |
| 417 | MasterClockDivider::MasterClockDisabled => 0, | 410 | MasterClockDivider::MasterClockDisabled => 0, |
| 418 | MasterClockDivider::Div1 => 0, | 411 | MasterClockDivider::Div1 => 0, |
| @@ -436,6 +429,7 @@ impl MasterClockDivider { | |||
| 436 | } | 429 | } |
| 437 | 430 | ||
| 438 | /// [`SAI`] configuration. | 431 | /// [`SAI`] configuration. |
| 432 | #[allow(missing_docs)] | ||
| 439 | #[non_exhaustive] | 433 | #[non_exhaustive] |
| 440 | #[derive(Copy, Clone)] | 434 | #[derive(Copy, Clone)] |
| 441 | pub struct Config { | 435 | pub struct Config { |
| @@ -459,7 +453,7 @@ pub struct Config { | |||
| 459 | pub clock_strobe: ClockStrobe, | 453 | pub clock_strobe: ClockStrobe, |
| 460 | pub output_drive: OutputDrive, | 454 | pub output_drive: OutputDrive, |
| 461 | pub master_clock_divider: MasterClockDivider, | 455 | pub master_clock_divider: MasterClockDivider, |
| 462 | pub is_high_impedenane_on_inactive_slot: bool, | 456 | pub is_high_impedance_on_inactive_slot: bool, |
| 463 | pub fifo_threshold: FifoThreshold, | 457 | pub fifo_threshold: FifoThreshold, |
| 464 | pub companding: Companding, | 458 | pub companding: Companding, |
| 465 | pub complement_format: ComplementFormat, | 459 | pub complement_format: ComplementFormat, |
| @@ -490,7 +484,7 @@ impl Default for Config { | |||
| 490 | master_clock_divider: MasterClockDivider::MasterClockDisabled, | 484 | master_clock_divider: MasterClockDivider::MasterClockDisabled, |
| 491 | clock_strobe: ClockStrobe::Rising, | 485 | clock_strobe: ClockStrobe::Rising, |
| 492 | output_drive: OutputDrive::Immediately, | 486 | output_drive: OutputDrive::Immediately, |
| 493 | is_high_impedenane_on_inactive_slot: false, | 487 | is_high_impedance_on_inactive_slot: false, |
| 494 | fifo_threshold: FifoThreshold::ThreeQuarters, | 488 | fifo_threshold: FifoThreshold::ThreeQuarters, |
| 495 | companding: Companding::None, | 489 | companding: Companding::None, |
| 496 | complement_format: ComplementFormat::TwosComplement, | 490 | complement_format: ComplementFormat::TwosComplement, |
| @@ -501,23 +495,10 @@ impl Default for Config { | |||
| 501 | } | 495 | } |
| 502 | 496 | ||
| 503 | impl Config { | 497 | impl Config { |
| 504 | pub fn new_i2s() -> Self { | 498 | /// Create a new config with all default values. |
| 499 | pub fn new() -> Self { | ||
| 505 | return Default::default(); | 500 | return Default::default(); |
| 506 | } | 501 | } |
| 507 | |||
| 508 | pub fn new_msb_first() -> Self { | ||
| 509 | Self { | ||
| 510 | bit_order: BitOrder::MsbFirst, | ||
| 511 | frame_sync_offset: FrameSyncOffset::OnFirstBit, | ||
| 512 | ..Default::default() | ||
| 513 | } | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | #[derive(Copy, Clone)] | ||
| 518 | enum WhichSubBlock { | ||
| 519 | A = 0, | ||
| 520 | B = 1, | ||
| 521 | } | 502 | } |
| 522 | 503 | ||
| 523 | enum RingBuffer<'d, C: Channel, W: word::Word> { | 504 | enum RingBuffer<'d, C: Channel, W: word::Word> { |
| @@ -531,28 +512,6 @@ fn dr<W: word::Word>(w: crate::pac::sai::Sai, sub_block: WhichSubBlock) -> *mut | |||
| 531 | ch.dr().as_ptr() as _ | 512 | ch.dr().as_ptr() as _ |
| 532 | } | 513 | } |
| 533 | 514 | ||
| 534 | pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> { | ||
| 535 | _peri: PeripheralRef<'d, T>, | ||
| 536 | sd: Option<PeripheralRef<'d, AnyPin>>, | ||
| 537 | fs: Option<PeripheralRef<'d, AnyPin>>, | ||
| 538 | sck: Option<PeripheralRef<'d, AnyPin>>, | ||
| 539 | mclk: Option<PeripheralRef<'d, AnyPin>>, | ||
| 540 | ring_buffer: RingBuffer<'d, C, W>, | ||
| 541 | sub_block: WhichSubBlock, | ||
| 542 | } | ||
| 543 | |||
| 544 | pub struct SubBlockA {} | ||
| 545 | pub struct SubBlockB {} | ||
| 546 | |||
| 547 | pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>); | ||
| 548 | pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>); | ||
| 549 | |||
| 550 | pub struct Sai<'d, T: Instance> { | ||
| 551 | _peri: PeripheralRef<'d, T>, | ||
| 552 | sub_block_a_peri: Option<SubBlockAPeripheral<'d, T>>, | ||
| 553 | sub_block_b_peri: Option<SubBlockBPeripheral<'d, T>>, | ||
| 554 | } | ||
| 555 | |||
| 556 | // return the type for (sd, sck) | 515 | // return the type for (sd, sck) |
| 557 | fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { | 516 | fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AFType, AFType) { |
| 558 | ( | 517 | ( |
| @@ -583,42 +542,14 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( | |||
| 583 | }; | 542 | }; |
| 584 | match tx_rx { | 543 | match tx_rx { |
| 585 | TxRx::Transmitter => RingBuffer::Writable(unsafe { | 544 | TxRx::Transmitter => RingBuffer::Writable(unsafe { |
| 586 | WritableRingBuffer::new_write(dma, request, dr(T::REGS, sub_block), dma_buf, opts) | 545 | WritableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts) |
| 587 | }), | 546 | }), |
| 588 | TxRx::Receiver => RingBuffer::Readable(unsafe { | 547 | TxRx::Receiver => RingBuffer::Readable(unsafe { |
| 589 | ReadableRingBuffer::new_read(dma, request, dr(T::REGS, sub_block), dma_buf, opts) | 548 | ReadableRingBuffer::new(dma, request, dr(T::REGS, sub_block), dma_buf, opts) |
| 590 | }), | 549 | }), |
| 591 | } | 550 | } |
| 592 | } | 551 | } |
| 593 | 552 | ||
| 594 | impl<'d, T: Instance> Sai<'d, T> { | ||
| 595 | pub fn new(peri: impl Peripheral<P = T> + 'd) -> Self { | ||
| 596 | T::enable_and_reset(); | ||
| 597 | |||
| 598 | Self { | ||
| 599 | _peri: unsafe { peri.clone_unchecked().into_ref() }, | ||
| 600 | sub_block_a_peri: Some(SubBlockAPeripheral(unsafe { peri.clone_unchecked().into_ref() })), | ||
| 601 | sub_block_b_peri: Some(SubBlockBPeripheral(peri.into_ref())), | ||
| 602 | } | ||
| 603 | } | ||
| 604 | |||
| 605 | pub fn take_sub_block_a(self: &mut Self) -> Option<SubBlockAPeripheral<'d, T>> { | ||
| 606 | if self.sub_block_a_peri.is_some() { | ||
| 607 | self.sub_block_a_peri.take() | ||
| 608 | } else { | ||
| 609 | None | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | pub fn take_sub_block_b(self: &mut Self) -> Option<SubBlockBPeripheral<'d, T>> { | ||
| 614 | if self.sub_block_b_peri.is_some() { | ||
| 615 | self.sub_block_b_peri.take() | ||
| 616 | } else { | ||
| 617 | None | ||
| 618 | } | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | fn update_synchronous_config(config: &mut Config) { | 553 | fn update_synchronous_config(config: &mut Config) { |
| 623 | config.mode = Mode::Slave; | 554 | config.mode = Mode::Slave; |
| 624 | config.sync_output = false; | 555 | config.sync_output = false; |
| @@ -636,122 +567,58 @@ fn update_synchronous_config(config: &mut Config) { | |||
| 636 | } | 567 | } |
| 637 | } | 568 | } |
| 638 | 569 | ||
| 639 | impl SubBlockA { | 570 | /// SAI subblock instance. |
| 640 | pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( | 571 | pub struct SubBlock<'d, T, S: SubBlockInstance> { |
| 641 | peri: SubBlockAPeripheral<'d, T>, | 572 | peri: PeripheralRef<'d, T>, |
| 642 | sck: impl Peripheral<P = impl SckAPin<T>> + 'd, | 573 | _phantom: PhantomData<S>, |
| 643 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | 574 | } |
| 644 | fs: impl Peripheral<P = impl FsAPin<T>> + 'd, | ||
| 645 | mclk: impl Peripheral<P = impl MclkAPin<T>> + 'd, | ||
| 646 | dma: impl Peripheral<P = C> + 'd, | ||
| 647 | dma_buf: &'d mut [W], | ||
| 648 | mut config: Config, | ||
| 649 | ) -> SubBlock<'d, T, C, W> | ||
| 650 | where | ||
| 651 | C: Channel + DmaA<T>, | ||
| 652 | { | ||
| 653 | into_ref!(mclk); | ||
| 654 | |||
| 655 | let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); | ||
| 656 | |||
| 657 | mclk.set_as_af(mclk.af_num(), ck_af_type); | ||
| 658 | mclk.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 659 | |||
| 660 | if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { | ||
| 661 | config.master_clock_divider = MasterClockDivider::Div1; | ||
| 662 | } | ||
| 663 | |||
| 664 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) | ||
| 665 | } | ||
| 666 | |||
| 667 | pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( | ||
| 668 | peri: SubBlockAPeripheral<'d, T>, | ||
| 669 | sck: impl Peripheral<P = impl SckAPin<T>> + 'd, | ||
| 670 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | ||
| 671 | fs: impl Peripheral<P = impl FsAPin<T>> + 'd, | ||
| 672 | dma: impl Peripheral<P = C> + 'd, | ||
| 673 | dma_buf: &'d mut [W], | ||
| 674 | config: Config, | ||
| 675 | ) -> SubBlock<'d, T, C, W> | ||
| 676 | where | ||
| 677 | C: Channel + DmaA<T>, | ||
| 678 | { | ||
| 679 | let peri = peri.0; | ||
| 680 | into_ref!(peri, dma, sck, sd, fs); | ||
| 681 | |||
| 682 | let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); | ||
| 683 | sd.set_as_af(sd.af_num(), sd_af_type); | ||
| 684 | sd.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 685 | |||
| 686 | sck.set_as_af(sck.af_num(), ck_af_type); | ||
| 687 | sck.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 688 | fs.set_as_af(fs.af_num(), ck_af_type); | ||
| 689 | fs.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 690 | 575 | ||
| 691 | let sub_block = WhichSubBlock::A; | 576 | /// Split the main SAIx peripheral into the two subblocks. |
| 692 | let request = dma.request(); | 577 | /// |
| 578 | /// You can then create a [`Sai`] driver for each each half. | ||
| 579 | pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { | ||
| 580 | into_ref!(peri); | ||
| 581 | T::enable_and_reset(); | ||
| 693 | 582 | ||
| 694 | SubBlock::new_inner( | 583 | ( |
| 584 | SubBlock { | ||
| 585 | peri: unsafe { peri.clone_unchecked() }, | ||
| 586 | _phantom: PhantomData, | ||
| 587 | }, | ||
| 588 | SubBlock { | ||
| 695 | peri, | 589 | peri, |
| 696 | sub_block, | 590 | _phantom: PhantomData, |
| 697 | Some(sck.map_into()), | 591 | }, |
| 698 | None, | 592 | ) |
| 699 | Some(sd.map_into()), | 593 | } |
| 700 | Some(fs.map_into()), | ||
| 701 | get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), | ||
| 702 | config, | ||
| 703 | ) | ||
| 704 | } | ||
| 705 | |||
| 706 | pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( | ||
| 707 | peri: SubBlockAPeripheral<'d, T>, | ||
| 708 | sd: impl Peripheral<P = impl SdAPin<T>> + 'd, | ||
| 709 | dma: impl Peripheral<P = C> + 'd, | ||
| 710 | dma_buf: &'d mut [W], | ||
| 711 | mut config: Config, | ||
| 712 | ) -> SubBlock<'d, T, C, W> | ||
| 713 | where | ||
| 714 | C: Channel + DmaA<T>, | ||
| 715 | { | ||
| 716 | update_synchronous_config(&mut config); | ||
| 717 | |||
| 718 | let peri = peri.0; | ||
| 719 | into_ref!(dma, peri, sd); | ||
| 720 | |||
| 721 | let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); | ||
| 722 | |||
| 723 | sd.set_as_af(sd.af_num(), sd_af_type); | ||
| 724 | sd.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 725 | |||
| 726 | let sub_block = WhichSubBlock::A; | ||
| 727 | let request = dma.request(); | ||
| 728 | 594 | ||
| 729 | SubBlock::new_inner( | 595 | /// SAI sub-block driver. |
| 730 | peri, | 596 | pub struct Sai<'d, T: Instance, C: Channel, W: word::Word> { |
| 731 | sub_block, | 597 | _peri: PeripheralRef<'d, T>, |
| 732 | None, | 598 | sd: Option<PeripheralRef<'d, AnyPin>>, |
| 733 | None, | 599 | fs: Option<PeripheralRef<'d, AnyPin>>, |
| 734 | Some(sd.map_into()), | 600 | sck: Option<PeripheralRef<'d, AnyPin>>, |
| 735 | None, | 601 | mclk: Option<PeripheralRef<'d, AnyPin>>, |
| 736 | get_ring_buffer::<T, C, W>(dma, dma_buf, request, sub_block, config.tx_rx), | 602 | ring_buffer: RingBuffer<'d, C, W>, |
| 737 | config, | 603 | sub_block: WhichSubBlock, |
| 738 | ) | ||
| 739 | } | ||
| 740 | } | 604 | } |
| 741 | 605 | ||
| 742 | impl SubBlockB { | 606 | impl<'d, T: Instance, C: Channel, W: word::Word> Sai<'d, T, C, W> { |
| 743 | pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( | 607 | /// Create a new SAI driver in asynchronous mode with MCLK. |
| 744 | peri: SubBlockBPeripheral<'d, T>, | 608 | /// |
| 745 | sck: impl Peripheral<P = impl SckBPin<T>> + 'd, | 609 | /// You can obtain the [`SubBlock`] with [`split_subblocks`]. |
| 746 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | 610 | pub fn new_asynchronous_with_mclk<S: SubBlockInstance>( |
| 747 | fs: impl Peripheral<P = impl FsBPin<T>> + 'd, | 611 | peri: SubBlock<'d, T, S>, |
| 748 | mclk: impl Peripheral<P = impl MclkBPin<T>> + 'd, | 612 | sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, |
| 613 | sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, | ||
| 614 | fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, | ||
| 615 | mclk: impl Peripheral<P = impl MclkPin<T, S>> + 'd, | ||
| 749 | dma: impl Peripheral<P = C> + 'd, | 616 | dma: impl Peripheral<P = C> + 'd, |
| 750 | dma_buf: &'d mut [W], | 617 | dma_buf: &'d mut [W], |
| 751 | mut config: Config, | 618 | mut config: Config, |
| 752 | ) -> SubBlock<'d, T, C, W> | 619 | ) -> Self |
| 753 | where | 620 | where |
| 754 | C: Channel + DmaB<T>, | 621 | C: Channel + Dma<T, S>, |
| 755 | { | 622 | { |
| 756 | into_ref!(mclk); | 623 | into_ref!(mclk); |
| 757 | 624 | ||
| @@ -767,23 +634,25 @@ impl SubBlockB { | |||
| 767 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) | 634 | Self::new_asynchronous(peri, sck, sd, fs, dma, dma_buf, config) |
| 768 | } | 635 | } |
| 769 | 636 | ||
| 770 | pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( | 637 | /// Create a new SAI driver in asynchronous mode without MCLK. |
| 771 | peri: SubBlockBPeripheral<'d, T>, | 638 | /// |
| 772 | sck: impl Peripheral<P = impl SckBPin<T>> + 'd, | 639 | /// You can obtain the [`SubBlock`] with [`split_subblocks`]. |
| 773 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | 640 | pub fn new_asynchronous<S: SubBlockInstance>( |
| 774 | fs: impl Peripheral<P = impl FsBPin<T>> + 'd, | 641 | peri: SubBlock<'d, T, S>, |
| 642 | sck: impl Peripheral<P = impl SckPin<T, S>> + 'd, | ||
| 643 | sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, | ||
| 644 | fs: impl Peripheral<P = impl FsPin<T, S>> + 'd, | ||
| 775 | dma: impl Peripheral<P = C> + 'd, | 645 | dma: impl Peripheral<P = C> + 'd, |
| 776 | dma_buf: &'d mut [W], | 646 | dma_buf: &'d mut [W], |
| 777 | config: Config, | 647 | config: Config, |
| 778 | ) -> SubBlock<'d, T, C, W> | 648 | ) -> Self |
| 779 | where | 649 | where |
| 780 | C: Channel + DmaB<T>, | 650 | C: Channel + Dma<T, S>, |
| 781 | { | 651 | { |
| 782 | let peri = peri.0; | 652 | let peri = peri.peri; |
| 783 | into_ref!(dma, peri, sck, sd, fs); | 653 | into_ref!(peri, dma, sck, sd, fs); |
| 784 | 654 | ||
| 785 | let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); | 655 | let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| 786 | |||
| 787 | sd.set_as_af(sd.af_num(), sd_af_type); | 656 | sd.set_as_af(sd.af_num(), sd_af_type); |
| 788 | sd.set_speed(crate::gpio::Speed::VeryHigh); | 657 | sd.set_speed(crate::gpio::Speed::VeryHigh); |
| 789 | 658 | ||
| @@ -792,10 +661,10 @@ impl SubBlockB { | |||
| 792 | fs.set_as_af(fs.af_num(), ck_af_type); | 661 | fs.set_as_af(fs.af_num(), ck_af_type); |
| 793 | fs.set_speed(crate::gpio::Speed::VeryHigh); | 662 | fs.set_speed(crate::gpio::Speed::VeryHigh); |
| 794 | 663 | ||
| 795 | let sub_block = WhichSubBlock::B; | 664 | let sub_block = S::WHICH; |
| 796 | let request = dma.request(); | 665 | let request = dma.request(); |
| 797 | 666 | ||
| 798 | SubBlock::new_inner( | 667 | Self::new_inner( |
| 799 | peri, | 668 | peri, |
| 800 | sub_block, | 669 | sub_block, |
| 801 | Some(sck.map_into()), | 670 | Some(sck.map_into()), |
| @@ -807,18 +676,22 @@ impl SubBlockB { | |||
| 807 | ) | 676 | ) |
| 808 | } | 677 | } |
| 809 | 678 | ||
| 810 | pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( | 679 | /// Create a new SAI driver in synchronous mode. |
| 811 | peri: SubBlockBPeripheral<'d, T>, | 680 | /// |
| 812 | sd: impl Peripheral<P = impl SdBPin<T>> + 'd, | 681 | /// You can obtain the [`SubBlock`] with [`split_subblocks`]. |
| 682 | pub fn new_synchronous<S: SubBlockInstance>( | ||
| 683 | peri: SubBlock<'d, T, S>, | ||
| 684 | sd: impl Peripheral<P = impl SdPin<T, S>> + 'd, | ||
| 813 | dma: impl Peripheral<P = C> + 'd, | 685 | dma: impl Peripheral<P = C> + 'd, |
| 814 | dma_buf: &'d mut [W], | 686 | dma_buf: &'d mut [W], |
| 815 | mut config: Config, | 687 | mut config: Config, |
| 816 | ) -> SubBlock<'d, T, C, W> | 688 | ) -> Self |
| 817 | where | 689 | where |
| 818 | C: Channel + DmaB<T>, | 690 | C: Channel + Dma<T, S>, |
| 819 | { | 691 | { |
| 820 | update_synchronous_config(&mut config); | 692 | update_synchronous_config(&mut config); |
| 821 | let peri = peri.0; | 693 | |
| 694 | let peri = peri.peri; | ||
| 822 | into_ref!(dma, peri, sd); | 695 | into_ref!(dma, peri, sd); |
| 823 | 696 | ||
| 824 | let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); | 697 | let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); |
| @@ -826,10 +699,10 @@ impl SubBlockB { | |||
| 826 | sd.set_as_af(sd.af_num(), sd_af_type); | 699 | sd.set_as_af(sd.af_num(), sd_af_type); |
| 827 | sd.set_speed(crate::gpio::Speed::VeryHigh); | 700 | sd.set_speed(crate::gpio::Speed::VeryHigh); |
| 828 | 701 | ||
| 829 | let sub_block = WhichSubBlock::B; | 702 | let sub_block = S::WHICH; |
| 830 | let request = dma.request(); | 703 | let request = dma.request(); |
| 831 | 704 | ||
| 832 | SubBlock::new_inner( | 705 | Self::new_inner( |
| 833 | peri, | 706 | peri, |
| 834 | sub_block, | 707 | sub_block, |
| 835 | None, | 708 | None, |
| @@ -840,26 +713,6 @@ impl SubBlockB { | |||
| 840 | config, | 713 | config, |
| 841 | ) | 714 | ) |
| 842 | } | 715 | } |
| 843 | } | ||
| 844 | |||
| 845 | impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | ||
| 846 | pub fn start(self: &mut Self) { | ||
| 847 | match self.ring_buffer { | ||
| 848 | RingBuffer::Writable(ref mut rb) => { | ||
| 849 | rb.start(); | ||
| 850 | } | ||
| 851 | RingBuffer::Readable(ref mut rb) => { | ||
| 852 | rb.start(); | ||
| 853 | } | ||
| 854 | } | ||
| 855 | } | ||
| 856 | |||
| 857 | fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool { | ||
| 858 | match ring_buffer { | ||
| 859 | RingBuffer::Writable(_) => true, | ||
| 860 | _ => false, | ||
| 861 | } | ||
| 862 | } | ||
| 863 | 716 | ||
| 864 | fn new_inner( | 717 | fn new_inner( |
| 865 | peri: impl Peripheral<P = T> + 'd, | 718 | peri: impl Peripheral<P = T> + 'd, |
| @@ -929,7 +782,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | |||
| 929 | w.set_cpl(config.complement_format.cpl()); | 782 | w.set_cpl(config.complement_format.cpl()); |
| 930 | w.set_muteval(config.mute_value.muteval()); | 783 | w.set_muteval(config.mute_value.muteval()); |
| 931 | w.set_mutecnt(config.mute_detection_counter.0 as u8); | 784 | w.set_mutecnt(config.mute_detection_counter.0 as u8); |
| 932 | w.set_tris(config.is_high_impedenane_on_inactive_slot); | 785 | w.set_tris(config.is_high_impedance_on_inactive_slot); |
| 933 | }); | 786 | }); |
| 934 | 787 | ||
| 935 | ch.frcr().modify(|w| { | 788 | ch.frcr().modify(|w| { |
| @@ -965,10 +818,31 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | |||
| 965 | } | 818 | } |
| 966 | } | 819 | } |
| 967 | 820 | ||
| 821 | /// Start the SAI driver. | ||
| 822 | pub fn start(&mut self) { | ||
| 823 | match self.ring_buffer { | ||
| 824 | RingBuffer::Writable(ref mut rb) => { | ||
| 825 | rb.start(); | ||
| 826 | } | ||
| 827 | RingBuffer::Readable(ref mut rb) => { | ||
| 828 | rb.start(); | ||
| 829 | } | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | fn is_transmitter(ring_buffer: &RingBuffer<C, W>) -> bool { | ||
| 834 | match ring_buffer { | ||
| 835 | RingBuffer::Writable(_) => true, | ||
| 836 | _ => false, | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | /// Reset SAI operation. | ||
| 968 | pub fn reset() { | 841 | pub fn reset() { |
| 969 | T::enable_and_reset(); | 842 | T::enable_and_reset(); |
| 970 | } | 843 | } |
| 971 | 844 | ||
| 845 | /// Flush. | ||
| 972 | pub fn flush(&mut self) { | 846 | pub fn flush(&mut self) { |
| 973 | let ch = T::REGS.ch(self.sub_block as usize); | 847 | let ch = T::REGS.ch(self.sub_block as usize); |
| 974 | ch.cr1().modify(|w| w.set_saien(false)); | 848 | ch.cr1().modify(|w| w.set_saien(false)); |
| @@ -983,19 +857,18 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | |||
| 983 | ch.cr1().modify(|w| w.set_saien(true)); | 857 | ch.cr1().modify(|w| w.set_saien(true)); |
| 984 | } | 858 | } |
| 985 | 859 | ||
| 860 | /// Enable or disable mute. | ||
| 986 | pub fn set_mute(&mut self, value: bool) { | 861 | pub fn set_mute(&mut self, value: bool) { |
| 987 | let ch = T::REGS.ch(self.sub_block as usize); | 862 | let ch = T::REGS.ch(self.sub_block as usize); |
| 988 | ch.cr2().modify(|w| w.set_mute(value)); | 863 | ch.cr2().modify(|w| w.set_mute(value)); |
| 989 | } | 864 | } |
| 990 | 865 | ||
| 991 | #[allow(dead_code)] | 866 | /// Write data to the SAI ringbuffer. |
| 992 | /// Reconfigures it with the supplied config. | 867 | /// |
| 993 | fn reconfigure(&mut self, _config: Config) {} | 868 | /// This appends the data to the buffer and returns immediately. The |
| 994 | 869 | /// data will be transmitted in the background. | |
| 995 | pub fn get_current_config(&self) -> Config { | 870 | /// |
| 996 | Config::default() | 871 | /// If there's no space in the buffer, this waits until there is. |
| 997 | } | ||
| 998 | |||
| 999 | pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { | 872 | pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { |
| 1000 | match &mut self.ring_buffer { | 873 | match &mut self.ring_buffer { |
| 1001 | RingBuffer::Writable(buffer) => { | 874 | RingBuffer::Writable(buffer) => { |
| @@ -1006,6 +879,12 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | |||
| 1006 | } | 879 | } |
| 1007 | } | 880 | } |
| 1008 | 881 | ||
| 882 | /// Read data from the SAI ringbuffer. | ||
| 883 | /// | ||
| 884 | /// SAI is always receiving data in the background. This function pops already-received | ||
| 885 | /// data from the buffer. | ||
| 886 | /// | ||
| 887 | /// If there's less than `data.len()` data in the buffer, this waits until there is. | ||
| 1009 | pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { | 888 | pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { |
| 1010 | match &mut self.ring_buffer { | 889 | match &mut self.ring_buffer { |
| 1011 | RingBuffer::Readable(buffer) => { | 890 | RingBuffer::Readable(buffer) => { |
| @@ -1017,7 +896,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { | |||
| 1017 | } | 896 | } |
| 1018 | } | 897 | } |
| 1019 | 898 | ||
| 1020 | impl<'d, T: Instance, C: Channel, W: word::Word> Drop for SubBlock<'d, T, C, W> { | 899 | impl<'d, T: Instance, C: Channel, W: word::Word> Drop for Sai<'d, T, C, W> { |
| 1021 | fn drop(&mut self) { | 900 | fn drop(&mut self) { |
| 1022 | let ch = T::REGS.ch(self.sub_block as usize); | 901 | let ch = T::REGS.ch(self.sub_block as usize); |
| 1023 | ch.cr1().modify(|w| w.set_saien(false)); | 902 | ch.cr1().modify(|w| w.set_saien(false)); |
| @@ -1034,22 +913,43 @@ pub(crate) mod sealed { | |||
| 1034 | pub trait Instance { | 913 | pub trait Instance { |
| 1035 | const REGS: Regs; | 914 | const REGS: Regs; |
| 1036 | } | 915 | } |
| 916 | |||
| 917 | #[derive(Copy, Clone)] | ||
| 918 | pub enum WhichSubBlock { | ||
| 919 | A = 0, | ||
| 920 | B = 1, | ||
| 921 | } | ||
| 922 | |||
| 923 | pub trait SubBlock { | ||
| 924 | const WHICH: WhichSubBlock; | ||
| 925 | } | ||
| 1037 | } | 926 | } |
| 1038 | 927 | ||
| 1039 | pub trait Word: word::Word {} | 928 | /// Sub-block instance trait. |
| 929 | pub trait SubBlockInstance: sealed::SubBlock {} | ||
| 1040 | 930 | ||
| 931 | /// Sub-block A. | ||
| 932 | pub enum A {} | ||
| 933 | impl sealed::SubBlock for A { | ||
| 934 | const WHICH: WhichSubBlock = WhichSubBlock::A; | ||
| 935 | } | ||
| 936 | impl SubBlockInstance for A {} | ||
| 937 | |||
| 938 | /// Sub-block B. | ||
| 939 | pub enum B {} | ||
| 940 | impl sealed::SubBlock for B { | ||
| 941 | const WHICH: WhichSubBlock = WhichSubBlock::B; | ||
| 942 | } | ||
| 943 | impl SubBlockInstance for B {} | ||
| 944 | |||
| 945 | /// SAI instance trait. | ||
| 1041 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 946 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} |
| 1042 | pin_trait!(SckAPin, Instance); | 947 | pin_trait!(SckPin, Instance, SubBlockInstance); |
| 1043 | pin_trait!(SckBPin, Instance); | 948 | pin_trait!(FsPin, Instance, SubBlockInstance); |
| 1044 | pin_trait!(FsAPin, Instance); | 949 | pin_trait!(SdPin, Instance, SubBlockInstance); |
| 1045 | pin_trait!(FsBPin, Instance); | 950 | pin_trait!(MclkPin, Instance, SubBlockInstance); |
| 1046 | pin_trait!(SdAPin, Instance); | 951 | |
| 1047 | pin_trait!(SdBPin, Instance); | 952 | dma_trait!(Dma, Instance, SubBlockInstance); |
| 1048 | pin_trait!(MclkAPin, Instance); | ||
| 1049 | pin_trait!(MclkBPin, Instance); | ||
| 1050 | |||
| 1051 | dma_trait!(DmaA, Instance); | ||
| 1052 | dma_trait!(DmaB, Instance); | ||
| 1053 | 953 | ||
| 1054 | foreach_peripheral!( | 954 | foreach_peripheral!( |
| 1055 | (sai, $inst:ident) => { | 955 | (sai, $inst:ident) => { |
| @@ -1060,13 +960,3 @@ foreach_peripheral!( | |||
| 1060 | impl Instance for peripherals::$inst {} | 960 | impl Instance for peripherals::$inst {} |
| 1061 | }; | 961 | }; |
| 1062 | ); | 962 | ); |
| 1063 | |||
| 1064 | impl<'d, T: Instance> SetConfig for Sai<'d, T> { | ||
| 1065 | type Config = Config; | ||
| 1066 | type ConfigError = (); | ||
| 1067 | fn set_config(&mut self, _config: &Self::Config) -> Result<(), ()> { | ||
| 1068 | // self.reconfigure(*config); | ||
| 1069 | |||
| 1070 | Ok(()) | ||
| 1071 | } | ||
| 1072 | } | ||
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 27a12062c..debe26c88 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Secure Digital / MultiMedia Card (SDMMC) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use core::default::Default; | 4 | use core::default::Default; |
| @@ -53,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000); | |||
| 53 | 54 | ||
| 54 | /// The signalling scheme used on the SDMMC bus | 55 | /// The signalling scheme used on the SDMMC bus |
| 55 | #[non_exhaustive] | 56 | #[non_exhaustive] |
| 57 | #[allow(missing_docs)] | ||
| 56 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 58 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 57 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 59 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 58 | pub enum Signalling { | 60 | pub enum Signalling { |
| @@ -69,6 +71,9 @@ impl Default for Signalling { | |||
| 69 | } | 71 | } |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 74 | /// Aligned data block for SDMMC transfers. | ||
| 75 | /// | ||
| 76 | /// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements. | ||
| 72 | #[repr(align(4))] | 77 | #[repr(align(4))] |
| 73 | #[derive(Debug, Clone, PartialEq, Eq)] | 78 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 74 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 79 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -93,17 +98,23 @@ impl DerefMut for DataBlock { | |||
| 93 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 98 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 94 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 99 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 95 | pub enum Error { | 100 | pub enum Error { |
| 101 | /// Timeout reported by the hardware | ||
| 96 | Timeout, | 102 | Timeout, |
| 103 | /// Timeout reported by the software driver. | ||
| 97 | SoftwareTimeout, | 104 | SoftwareTimeout, |
| 105 | /// Unsupported card version. | ||
| 98 | UnsupportedCardVersion, | 106 | UnsupportedCardVersion, |
| 107 | /// Unsupported card type. | ||
| 99 | UnsupportedCardType, | 108 | UnsupportedCardType, |
| 109 | /// CRC error. | ||
| 100 | Crc, | 110 | Crc, |
| 101 | DataCrcFail, | 111 | /// No card inserted. |
| 102 | RxOverFlow, | ||
| 103 | NoCard, | 112 | NoCard, |
| 113 | /// Bad clock supplied to the SDMMC peripheral. | ||
| 104 | BadClock, | 114 | BadClock, |
| 115 | /// Signaling switch failed. | ||
| 105 | SignalingSwitchFailed, | 116 | SignalingSwitchFailed, |
| 106 | PeripheralBusy, | 117 | /// ST bit error. |
| 107 | #[cfg(sdmmc_v1)] | 118 | #[cfg(sdmmc_v1)] |
| 108 | StBitErr, | 119 | StBitErr, |
| 109 | } | 120 | } |
| @@ -282,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> { | |||
| 282 | 293 | ||
| 283 | #[cfg(sdmmc_v1)] | 294 | #[cfg(sdmmc_v1)] |
| 284 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | 295 | impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { |
| 296 | /// Create a new SDMMC driver, with 1 data lane. | ||
| 285 | pub fn new_1bit( | 297 | pub fn new_1bit( |
| 286 | sdmmc: impl Peripheral<P = T> + 'd, | 298 | sdmmc: impl Peripheral<P = T> + 'd, |
| 287 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 299 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -316,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 316 | ) | 328 | ) |
| 317 | } | 329 | } |
| 318 | 330 | ||
| 331 | /// Create a new SDMMC driver, with 4 data lanes. | ||
| 319 | pub fn new_4bit( | 332 | pub fn new_4bit( |
| 320 | sdmmc: impl Peripheral<P = T> + 'd, | 333 | sdmmc: impl Peripheral<P = T> + 'd, |
| 321 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 334 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -362,6 +375,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { | |||
| 362 | 375 | ||
| 363 | #[cfg(sdmmc_v2)] | 376 | #[cfg(sdmmc_v2)] |
| 364 | impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | 377 | impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { |
| 378 | /// Create a new SDMMC driver, with 1 data lane. | ||
| 365 | pub fn new_1bit( | 379 | pub fn new_1bit( |
| 366 | sdmmc: impl Peripheral<P = T> + 'd, | 380 | sdmmc: impl Peripheral<P = T> + 'd, |
| 367 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 381 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -395,6 +409,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { | |||
| 395 | ) | 409 | ) |
| 396 | } | 410 | } |
| 397 | 411 | ||
| 412 | /// Create a new SDMMC driver, with 4 data lanes. | ||
| 398 | pub fn new_4bit( | 413 | pub fn new_4bit( |
| 399 | sdmmc: impl Peripheral<P = T> + 'd, | 414 | sdmmc: impl Peripheral<P = T> + 'd, |
| 400 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 415 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -496,7 +511,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 496 | } | 511 | } |
| 497 | 512 | ||
| 498 | /// Data transfer is in progress | 513 | /// Data transfer is in progress |
| 499 | #[inline(always)] | 514 | #[inline] |
| 500 | fn data_active() -> bool { | 515 | fn data_active() -> bool { |
| 501 | let regs = T::regs(); | 516 | let regs = T::regs(); |
| 502 | 517 | ||
| @@ -508,7 +523,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 508 | } | 523 | } |
| 509 | 524 | ||
| 510 | /// Coammand transfer is in progress | 525 | /// Coammand transfer is in progress |
| 511 | #[inline(always)] | 526 | #[inline] |
| 512 | fn cmd_active() -> bool { | 527 | fn cmd_active() -> bool { |
| 513 | let regs = T::regs(); | 528 | let regs = T::regs(); |
| 514 | 529 | ||
| @@ -520,7 +535,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 520 | } | 535 | } |
| 521 | 536 | ||
| 522 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) | 537 | /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) |
| 523 | #[inline(always)] | 538 | #[inline] |
| 524 | fn wait_idle() { | 539 | fn wait_idle() { |
| 525 | while Self::data_active() || Self::cmd_active() {} | 540 | while Self::data_active() || Self::cmd_active() {} |
| 526 | } | 541 | } |
| @@ -836,7 +851,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 836 | } | 851 | } |
| 837 | 852 | ||
| 838 | /// Clear flags in interrupt clear register | 853 | /// Clear flags in interrupt clear register |
| 839 | #[inline(always)] | 854 | #[inline] |
| 840 | fn clear_interrupt_flags() { | 855 | fn clear_interrupt_flags() { |
| 841 | let regs = T::regs(); | 856 | let regs = T::regs(); |
| 842 | regs.icr().write(|w| { | 857 | regs.icr().write(|w| { |
| @@ -1151,7 +1166,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1151 | Ok(()) | 1166 | Ok(()) |
| 1152 | } | 1167 | } |
| 1153 | 1168 | ||
| 1154 | #[inline(always)] | 1169 | /// Read a data block. |
| 1170 | #[inline] | ||
| 1155 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { | 1171 | pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { |
| 1156 | let card_capacity = self.card()?.card_type; | 1172 | let card_capacity = self.card()?.card_type; |
| 1157 | 1173 | ||
| @@ -1203,6 +1219,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1203 | res | 1219 | res |
| 1204 | } | 1220 | } |
| 1205 | 1221 | ||
| 1222 | /// Write a data block. | ||
| 1206 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { | 1223 | pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { |
| 1207 | let card = self.card.as_mut().ok_or(Error::NoCard)?; | 1224 | let card = self.card.as_mut().ok_or(Error::NoCard)?; |
| 1208 | 1225 | ||
| @@ -1282,7 +1299,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> { | |||
| 1282 | /// | 1299 | /// |
| 1283 | /// Returns Error::NoCard if [`init_card`](#method.init_card) | 1300 | /// Returns Error::NoCard if [`init_card`](#method.init_card) |
| 1284 | /// has not previously succeeded | 1301 | /// has not previously succeeded |
| 1285 | #[inline(always)] | 1302 | #[inline] |
| 1286 | pub fn card(&self) -> Result<&Card, Error> { | 1303 | pub fn card(&self) -> Result<&Card, Error> { |
| 1287 | self.card.as_ref().ok_or(Error::NoCard) | 1304 | self.card.as_ref().ok_or(Error::NoCard) |
| 1288 | } | 1305 | } |
| @@ -1418,7 +1435,9 @@ pub(crate) mod sealed { | |||
| 1418 | pub trait Pins<T: Instance> {} | 1435 | pub trait Pins<T: Instance> {} |
| 1419 | } | 1436 | } |
| 1420 | 1437 | ||
| 1438 | /// SDMMC instance trait. | ||
| 1421 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} | 1439 | pub trait Instance: sealed::Instance + RccPeripheral + 'static {} |
| 1440 | |||
| 1422 | pin_trait!(CkPin, Instance); | 1441 | pin_trait!(CkPin, Instance); |
| 1423 | pin_trait!(CmdPin, Instance); | 1442 | pin_trait!(CmdPin, Instance); |
| 1424 | pin_trait!(D0Pin, Instance); | 1443 | pin_trait!(D0Pin, Instance); |
| @@ -1433,7 +1452,10 @@ pin_trait!(D7Pin, Instance); | |||
| 1433 | #[cfg(sdmmc_v1)] | 1452 | #[cfg(sdmmc_v1)] |
| 1434 | dma_trait!(SdmmcDma, Instance); | 1453 | dma_trait!(SdmmcDma, Instance); |
| 1435 | 1454 | ||
| 1436 | // SDMMCv2 uses internal DMA | 1455 | /// DMA instance trait. |
| 1456 | /// | ||
| 1457 | /// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of | ||
| 1458 | /// using ST's system-wide DMA peripheral. | ||
| 1437 | #[cfg(sdmmc_v2)] | 1459 | #[cfg(sdmmc_v2)] |
| 1438 | pub trait SdmmcDma<T: Instance> {} | 1460 | pub trait SdmmcDma<T: Instance> {} |
| 1439 | #[cfg(sdmmc_v2)] | 1461 | #[cfg(sdmmc_v2)] |
| @@ -1516,53 +1538,3 @@ foreach_peripheral!( | |||
| 1516 | impl Instance for peripherals::$inst {} | 1538 | impl Instance for peripherals::$inst {} |
| 1517 | }; | 1539 | }; |
| 1518 | ); | 1540 | ); |
| 1519 | |||
| 1520 | #[cfg(feature = "embedded-sdmmc")] | ||
| 1521 | mod sdmmc_rs { | ||
| 1522 | use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx}; | ||
| 1523 | |||
| 1524 | use super::*; | ||
| 1525 | |||
| 1526 | impl<'d, T: Instance, Dma: SdmmcDma<T>> BlockDevice for Sdmmc<'d, T, Dma> { | ||
| 1527 | type Error = Error; | ||
| 1528 | |||
| 1529 | async fn read( | ||
| 1530 | &mut self, | ||
| 1531 | blocks: &mut [Block], | ||
| 1532 | start_block_idx: BlockIdx, | ||
| 1533 | _reason: &str, | ||
| 1534 | ) -> Result<(), Self::Error> { | ||
| 1535 | let mut address = start_block_idx.0; | ||
| 1536 | |||
| 1537 | for block in blocks.iter_mut() { | ||
| 1538 | let block: &mut [u8; 512] = &mut block.contents; | ||
| 1539 | |||
| 1540 | // NOTE(unsafe) Block uses align(4) | ||
| 1541 | let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) }; | ||
| 1542 | self.read_block(address, block).await?; | ||
| 1543 | address += 1; | ||
| 1544 | } | ||
| 1545 | Ok(()) | ||
| 1546 | } | ||
| 1547 | |||
| 1548 | async fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> { | ||
| 1549 | let mut address = start_block_idx.0; | ||
| 1550 | |||
| 1551 | for block in blocks.iter() { | ||
| 1552 | let block: &[u8; 512] = &block.contents; | ||
| 1553 | |||
| 1554 | // NOTE(unsafe) DataBlock uses align 4 | ||
| 1555 | let block = unsafe { &*(block as *const _ as *const DataBlock) }; | ||
| 1556 | self.write_block(address, block).await?; | ||
| 1557 | address += 1; | ||
| 1558 | } | ||
| 1559 | Ok(()) | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | fn num_blocks(&self) -> Result<BlockCount, Self::Error> { | ||
| 1563 | let card = self.card()?; | ||
| 1564 | let count = card.csd.block_count(); | ||
| 1565 | Ok(BlockCount(count)) | ||
| 1566 | } | ||
| 1567 | } | ||
| 1568 | } | ||
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 92599c75e..23f027e70 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Serial Peripheral Interface (SPI) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 2 | 3 | ||
| 3 | use core::ptr; | 4 | use core::ptr; |
| @@ -15,27 +16,38 @@ use crate::rcc::RccPeripheral; | |||
| 15 | use crate::time::Hertz; | 16 | use crate::time::Hertz; |
| 16 | use crate::{peripherals, Peripheral}; | 17 | use crate::{peripherals, Peripheral}; |
| 17 | 18 | ||
| 19 | /// SPI error. | ||
| 18 | #[derive(Debug, PartialEq, Eq)] | 20 | #[derive(Debug, PartialEq, Eq)] |
| 19 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 20 | pub enum Error { | 22 | pub enum Error { |
| 23 | /// Invalid framing. | ||
| 21 | Framing, | 24 | Framing, |
| 25 | /// CRC error (only if hardware CRC checking is enabled). | ||
| 22 | Crc, | 26 | Crc, |
| 27 | /// Mode fault | ||
| 23 | ModeFault, | 28 | ModeFault, |
| 29 | /// Overrun. | ||
| 24 | Overrun, | 30 | Overrun, |
| 25 | } | 31 | } |
| 26 | 32 | ||
| 27 | // TODO move upwards in the tree | 33 | /// SPI bit order |
| 28 | #[derive(Copy, Clone)] | 34 | #[derive(Copy, Clone)] |
| 29 | pub enum BitOrder { | 35 | pub enum BitOrder { |
| 36 | /// Least significant bit first. | ||
| 30 | LsbFirst, | 37 | LsbFirst, |
| 38 | /// Most significant bit first. | ||
| 31 | MsbFirst, | 39 | MsbFirst, |
| 32 | } | 40 | } |
| 33 | 41 | ||
| 42 | /// SPI configuration. | ||
| 34 | #[non_exhaustive] | 43 | #[non_exhaustive] |
| 35 | #[derive(Copy, Clone)] | 44 | #[derive(Copy, Clone)] |
| 36 | pub struct Config { | 45 | pub struct Config { |
| 46 | /// SPI mode. | ||
| 37 | pub mode: Mode, | 47 | pub mode: Mode, |
| 48 | /// Bit order. | ||
| 38 | pub bit_order: BitOrder, | 49 | pub bit_order: BitOrder, |
| 50 | /// Clock frequency. | ||
| 39 | pub frequency: Hertz, | 51 | pub frequency: Hertz, |
| 40 | } | 52 | } |
| 41 | 53 | ||
| @@ -72,6 +84,7 @@ impl Config { | |||
| 72 | } | 84 | } |
| 73 | } | 85 | } |
| 74 | 86 | ||
| 87 | /// SPI driver. | ||
| 75 | pub struct Spi<'d, T: Instance, Tx, Rx> { | 88 | pub struct Spi<'d, T: Instance, Tx, Rx> { |
| 76 | _peri: PeripheralRef<'d, T>, | 89 | _peri: PeripheralRef<'d, T>, |
| 77 | sck: Option<PeripheralRef<'d, AnyPin>>, | 90 | sck: Option<PeripheralRef<'d, AnyPin>>, |
| @@ -83,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> { | |||
| 83 | } | 96 | } |
| 84 | 97 | ||
| 85 | impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | 98 | impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { |
| 99 | /// Create a new SPI driver. | ||
| 86 | pub fn new( | 100 | pub fn new( |
| 87 | peri: impl Peripheral<P = T> + 'd, | 101 | peri: impl Peripheral<P = T> + 'd, |
| 88 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | 102 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, |
| @@ -117,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 117 | ) | 131 | ) |
| 118 | } | 132 | } |
| 119 | 133 | ||
| 134 | /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). | ||
| 120 | pub fn new_rxonly( | 135 | pub fn new_rxonly( |
| 121 | peri: impl Peripheral<P = T> + 'd, | 136 | peri: impl Peripheral<P = T> + 'd, |
| 122 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | 137 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, |
| @@ -142,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 142 | ) | 157 | ) |
| 143 | } | 158 | } |
| 144 | 159 | ||
| 160 | /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). | ||
| 145 | pub fn new_txonly( | 161 | pub fn new_txonly( |
| 146 | peri: impl Peripheral<P = T> + 'd, | 162 | peri: impl Peripheral<P = T> + 'd, |
| 147 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, | 163 | sck: impl Peripheral<P = impl SckPin<T>> + 'd, |
| @@ -167,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 167 | ) | 183 | ) |
| 168 | } | 184 | } |
| 169 | 185 | ||
| 186 | /// Create a new SPI driver, in TX-only mode, without SCK pin. | ||
| 187 | /// | ||
| 188 | /// This can be useful for bit-banging non-SPI protocols. | ||
| 170 | pub fn new_txonly_nosck( | 189 | pub fn new_txonly_nosck( |
| 171 | peri: impl Peripheral<P = T> + 'd, | 190 | peri: impl Peripheral<P = T> + 'd, |
| 172 | mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, | 191 | mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, |
| @@ -292,7 +311,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 292 | w.set_ssom(vals::Ssom::ASSERTED); | 311 | w.set_ssom(vals::Ssom::ASSERTED); |
| 293 | w.set_midi(0); | 312 | w.set_midi(0); |
| 294 | w.set_mssi(0); | 313 | w.set_mssi(0); |
| 295 | w.set_afcntr(vals::Afcntr::CONTROLLED); | 314 | w.set_afcntr(true); |
| 296 | w.set_ssiop(vals::Ssiop::ACTIVEHIGH); | 315 | w.set_ssiop(vals::Ssiop::ACTIVEHIGH); |
| 297 | }); | 316 | }); |
| 298 | T::REGS.cfg1().modify(|w| { | 317 | T::REGS.cfg1().modify(|w| { |
| @@ -354,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 354 | Ok(()) | 373 | Ok(()) |
| 355 | } | 374 | } |
| 356 | 375 | ||
| 376 | /// Get current SPI configuration. | ||
| 357 | pub fn get_current_config(&self) -> Config { | 377 | pub fn get_current_config(&self) -> Config { |
| 358 | #[cfg(any(spi_v1, spi_f1, spi_v2))] | 378 | #[cfg(any(spi_v1, spi_f1, spi_v2))] |
| 359 | let cfg = T::REGS.cr1().read(); | 379 | let cfg = T::REGS.cr1().read(); |
| @@ -443,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 443 | self.current_word_size = word_size; | 463 | self.current_word_size = word_size; |
| 444 | } | 464 | } |
| 445 | 465 | ||
| 466 | /// SPI write, using DMA. | ||
| 446 | pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> | 467 | pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> |
| 447 | where | 468 | where |
| 448 | Tx: TxDma<T>, | 469 | Tx: TxDma<T>, |
| @@ -476,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 476 | Ok(()) | 497 | Ok(()) |
| 477 | } | 498 | } |
| 478 | 499 | ||
| 500 | /// SPI read, using DMA. | ||
| 479 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> | 501 | pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> |
| 480 | where | 502 | where |
| 481 | Tx: TxDma<T>, | 503 | Tx: TxDma<T>, |
| @@ -579,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 579 | Ok(()) | 601 | Ok(()) |
| 580 | } | 602 | } |
| 581 | 603 | ||
| 604 | /// Bidirectional transfer, using DMA. | ||
| 605 | /// | ||
| 606 | /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`. | ||
| 607 | /// | ||
| 608 | /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. | ||
| 609 | /// If `write` is shorter it is padded with zero bytes. | ||
| 582 | pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> | 610 | pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> |
| 583 | where | 611 | where |
| 584 | Tx: TxDma<T>, | 612 | Tx: TxDma<T>, |
| @@ -587,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 587 | self.transfer_inner(read, write).await | 615 | self.transfer_inner(read, write).await |
| 588 | } | 616 | } |
| 589 | 617 | ||
| 618 | /// In-place bidirectional transfer, using DMA. | ||
| 619 | /// | ||
| 620 | /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. | ||
| 590 | pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> | 621 | pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> |
| 591 | where | 622 | where |
| 592 | Tx: TxDma<T>, | 623 | Tx: TxDma<T>, |
| @@ -595,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 595 | self.transfer_inner(data, data).await | 626 | self.transfer_inner(data, data).await |
| 596 | } | 627 | } |
| 597 | 628 | ||
| 629 | /// Blocking write. | ||
| 598 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { | 630 | pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { |
| 599 | T::REGS.cr1().modify(|w| w.set_spe(true)); | 631 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 600 | flush_rx_fifo(T::REGS); | 632 | flush_rx_fifo(T::REGS); |
| @@ -605,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 605 | Ok(()) | 637 | Ok(()) |
| 606 | } | 638 | } |
| 607 | 639 | ||
| 640 | /// Blocking read. | ||
| 608 | pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | 641 | pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { |
| 609 | T::REGS.cr1().modify(|w| w.set_spe(true)); | 642 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 610 | flush_rx_fifo(T::REGS); | 643 | flush_rx_fifo(T::REGS); |
| @@ -615,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 615 | Ok(()) | 648 | Ok(()) |
| 616 | } | 649 | } |
| 617 | 650 | ||
| 651 | /// Blocking in-place bidirectional transfer. | ||
| 652 | /// | ||
| 653 | /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. | ||
| 618 | pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { | 654 | pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { |
| 619 | T::REGS.cr1().modify(|w| w.set_spe(true)); | 655 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 620 | flush_rx_fifo(T::REGS); | 656 | flush_rx_fifo(T::REGS); |
| @@ -625,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
| 625 | Ok(()) | 661 | Ok(()) |
| 626 | } | 662 | } |
| 627 | 663 | ||
| 664 | /// Blocking bidirectional transfer. | ||
| 665 | /// | ||
| 666 | /// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`. | ||
| 667 | /// | ||
| 668 | /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. | ||
| 669 | /// If `write` is shorter it is padded with zero bytes. | ||
| 628 | pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { | 670 | pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { |
| 629 | T::REGS.cr1().modify(|w| w.set_spe(true)); | 671 | T::REGS.cr1().modify(|w| w.set_spe(true)); |
| 630 | flush_rx_fifo(T::REGS); | 672 | flush_rx_fifo(T::REGS); |
| @@ -945,6 +987,7 @@ pub(crate) mod sealed { | |||
| 945 | } | 987 | } |
| 946 | } | 988 | } |
| 947 | 989 | ||
| 990 | /// Word sizes usable for SPI. | ||
| 948 | pub trait Word: word::Word + sealed::Word {} | 991 | pub trait Word: word::Word + sealed::Word {} |
| 949 | 992 | ||
| 950 | macro_rules! impl_word { | 993 | macro_rules! impl_word { |
| @@ -1024,7 +1067,9 @@ mod word_impl { | |||
| 1024 | impl_word!(u32, 32 - 1); | 1067 | impl_word!(u32, 32 - 1); |
| 1025 | } | 1068 | } |
| 1026 | 1069 | ||
| 1070 | /// SPI instance trait. | ||
| 1027 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} | 1071 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} |
| 1072 | |||
| 1028 | pin_trait!(SckPin, Instance); | 1073 | pin_trait!(SckPin, Instance); |
| 1029 | pin_trait!(MosiPin, Instance); | 1074 | pin_trait!(MosiPin, Instance); |
| 1030 | pin_trait!(MisoPin, Instance); | 1075 | pin_trait!(MisoPin, Instance); |
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index a0bc33944..17690aefc 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs | |||
| @@ -8,14 +8,17 @@ use core::ops::{Div, Mul}; | |||
| 8 | pub struct Hertz(pub u32); | 8 | pub struct Hertz(pub u32); |
| 9 | 9 | ||
| 10 | impl Hertz { | 10 | impl Hertz { |
| 11 | /// Create a `Hertz` from the given hertz. | ||
| 11 | pub const fn hz(hertz: u32) -> Self { | 12 | pub const fn hz(hertz: u32) -> Self { |
| 12 | Self(hertz) | 13 | Self(hertz) |
| 13 | } | 14 | } |
| 14 | 15 | ||
| 16 | /// Create a `Hertz` from the given kilohertz. | ||
| 15 | pub const fn khz(kilohertz: u32) -> Self { | 17 | pub const fn khz(kilohertz: u32) -> Self { |
| 16 | Self(kilohertz * 1_000) | 18 | Self(kilohertz * 1_000) |
| 17 | } | 19 | } |
| 18 | 20 | ||
| 21 | /// Create a `Hertz` from the given megahertz. | ||
| 19 | pub const fn mhz(megahertz: u32) -> Self { | 22 | pub const fn mhz(megahertz: u32) -> Self { |
| 20 | Self(megahertz * 1_000_000) | 23 | Self(megahertz * 1_000_000) |
| 21 | } | 24 | } |
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index e2a4cc4da..9981800b2 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs | |||
| @@ -43,7 +43,10 @@ type T = peripherals::TIM3; | |||
| 43 | type T = peripherals::TIM4; | 43 | type T = peripherals::TIM4; |
| 44 | #[cfg(time_driver_tim5)] | 44 | #[cfg(time_driver_tim5)] |
| 45 | type T = peripherals::TIM5; | 45 | type T = peripherals::TIM5; |
| 46 | 46 | #[cfg(time_driver_tim9)] | |
| 47 | type T = peripherals::TIM9; | ||
| 48 | #[cfg(time_driver_tim11)] | ||
| 49 | type T = peripherals::TIM11; | ||
| 47 | #[cfg(time_driver_tim12)] | 50 | #[cfg(time_driver_tim12)] |
| 48 | type T = peripherals::TIM12; | 51 | type T = peripherals::TIM12; |
| 49 | #[cfg(time_driver_tim15)] | 52 | #[cfg(time_driver_tim15)] |
| @@ -82,6 +85,22 @@ foreach_interrupt! { | |||
| 82 | DRIVER.on_interrupt() | 85 | DRIVER.on_interrupt() |
| 83 | } | 86 | } |
| 84 | }; | 87 | }; |
| 88 | (TIM9, timer, $block:ident, UP, $irq:ident) => { | ||
| 89 | #[cfg(time_driver_tim9)] | ||
| 90 | #[cfg(feature = "rt")] | ||
| 91 | #[interrupt] | ||
| 92 | fn $irq() { | ||
| 93 | DRIVER.on_interrupt() | ||
| 94 | } | ||
| 95 | }; | ||
| 96 | (TIM11, timer, $block:ident, UP, $irq:ident) => { | ||
| 97 | #[cfg(time_driver_tim11)] | ||
| 98 | #[cfg(feature = "rt")] | ||
| 99 | #[interrupt] | ||
| 100 | fn $irq() { | ||
| 101 | DRIVER.on_interrupt() | ||
| 102 | } | ||
| 103 | }; | ||
| 85 | (TIM12, timer, $block:ident, UP, $irq:ident) => { | 104 | (TIM12, timer, $block:ident, UP, $irq:ident) => { |
| 86 | #[cfg(time_driver_tim12)] | 105 | #[cfg(time_driver_tim12)] |
| 87 | #[cfg(feature = "rt")] | 106 | #[cfg(feature = "rt")] |
| @@ -455,16 +474,29 @@ impl Driver for RtcDriver { | |||
| 455 | return false; | 474 | return false; |
| 456 | } | 475 | } |
| 457 | 476 | ||
| 458 | let safe_timestamp = timestamp.max(t + 3); | ||
| 459 | |||
| 460 | // Write the CCR value regardless of whether we're going to enable it now or not. | 477 | // Write the CCR value regardless of whether we're going to enable it now or not. |
| 461 | // This way, when we enable it later, the right value is already set. | 478 | // This way, when we enable it later, the right value is already set. |
| 462 | r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); | 479 | r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16)); |
| 463 | 480 | ||
| 464 | // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. | 481 | // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. |
| 465 | let diff = timestamp - t; | 482 | let diff = timestamp - t; |
| 466 | r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); | 483 | r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); |
| 467 | 484 | ||
| 485 | // Reevaluate if the alarm timestamp is still in the future | ||
| 486 | let t = self.now(); | ||
| 487 | if timestamp <= t { | ||
| 488 | // If alarm timestamp has passed since we set it, we have a race condition and | ||
| 489 | // the alarm may or may not have fired. | ||
| 490 | // Disarm the alarm and return `false` to indicate that. | ||
| 491 | // It is the caller's responsibility to handle this ambiguity. | ||
| 492 | r.dier().modify(|w| w.set_ccie(n + 1, false)); | ||
| 493 | |||
| 494 | alarm.timestamp.set(u64::MAX); | ||
| 495 | |||
| 496 | return false; | ||
| 497 | } | ||
| 498 | |||
| 499 | // We're confident the alarm will ring in the future. | ||
| 468 | true | 500 | true |
| 469 | }) | 501 | }) |
| 470 | } | 502 | } |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 6654366cd..71d7110b5 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! PWM driver with complementary output support. | ||
| 2 | |||
| 1 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 2 | 4 | ||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| @@ -11,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType}; | |||
| 11 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 12 | use crate::Peripheral; | 14 | use crate::Peripheral; |
| 13 | 15 | ||
| 14 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | 16 | /// Complementary PWM pin wrapper. |
| 17 | /// | ||
| 18 | /// This wraps a pin to make it usable with PWM. | ||
| 19 | pub struct ComplementaryPwmPin<'d, T, C> { | ||
| 15 | _pin: PeripheralRef<'d, AnyPin>, | 20 | _pin: PeripheralRef<'d, AnyPin>, |
| 16 | phantom: PhantomData<(Perip, Channel)>, | 21 | phantom: PhantomData<(T, C)>, |
| 17 | } | 22 | } |
| 18 | 23 | ||
| 19 | macro_rules! complementary_channel_impl { | 24 | macro_rules! complementary_channel_impl { |
| 20 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 25 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 21 | impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { | 26 | impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { |
| 22 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { | 27 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 28 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | ||
| 23 | into_ref!(pin); | 29 | into_ref!(pin); |
| 24 | critical_section::with(|_| { | 30 | critical_section::with(|_| { |
| 25 | pin.set_low(); | 31 | pin.set_low(); |
| @@ -41,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin); | |||
| 41 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); | 47 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); |
| 42 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); | 48 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); |
| 43 | 49 | ||
| 50 | /// PWM driver with support for standard and complementary outputs. | ||
| 44 | pub struct ComplementaryPwm<'d, T> { | 51 | pub struct ComplementaryPwm<'d, T> { |
| 45 | inner: PeripheralRef<'d, T>, | 52 | inner: PeripheralRef<'d, T>, |
| 46 | } | 53 | } |
| 47 | 54 | ||
| 48 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | 55 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { |
| 56 | /// Create a new complementary PWM driver. | ||
| 49 | pub fn new( | 57 | pub fn new( |
| 50 | tim: impl Peripheral<P = T> + 'd, | 58 | tim: impl Peripheral<P = T> + 'd, |
| 51 | _ch1: Option<PwmPin<'d, T, Ch1>>, | 59 | _ch1: Option<PwmPin<'d, T, Ch1>>, |
| @@ -70,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 70 | let mut this = Self { inner: tim }; | 78 | let mut this = Self { inner: tim }; |
| 71 | 79 | ||
| 72 | this.inner.set_counting_mode(counting_mode); | 80 | this.inner.set_counting_mode(counting_mode); |
| 73 | this.set_freq(freq); | 81 | this.set_frequency(freq); |
| 74 | this.inner.start(); | 82 | this.inner.start(); |
| 75 | 83 | ||
| 76 | this.inner.enable_outputs(); | 84 | this.inner.enable_outputs(); |
| @@ -86,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 86 | this | 94 | this |
| 87 | } | 95 | } |
| 88 | 96 | ||
| 97 | /// Enable the given channel. | ||
| 89 | pub fn enable(&mut self, channel: Channel) { | 98 | pub fn enable(&mut self, channel: Channel) { |
| 90 | self.inner.enable_channel(channel, true); | 99 | self.inner.enable_channel(channel, true); |
| 91 | self.inner.enable_complementary_channel(channel, true); | 100 | self.inner.enable_complementary_channel(channel, true); |
| 92 | } | 101 | } |
| 93 | 102 | ||
| 103 | /// Disable the given channel. | ||
| 94 | pub fn disable(&mut self, channel: Channel) { | 104 | pub fn disable(&mut self, channel: Channel) { |
| 95 | self.inner.enable_complementary_channel(channel, false); | 105 | self.inner.enable_complementary_channel(channel, false); |
| 96 | self.inner.enable_channel(channel, false); | 106 | self.inner.enable_channel(channel, false); |
| 97 | } | 107 | } |
| 98 | 108 | ||
| 99 | pub fn set_freq(&mut self, freq: Hertz) { | 109 | /// Set PWM frequency. |
| 110 | /// | ||
| 111 | /// Note: when you call this, the max duty value changes, so you will have to | ||
| 112 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | ||
| 113 | pub fn set_frequency(&mut self, freq: Hertz) { | ||
| 100 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 114 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 101 | 2u8 | 115 | 2u8 |
| 102 | } else { | 116 | } else { |
| @@ -105,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 105 | self.inner.set_frequency(freq * multiplier); | 119 | self.inner.set_frequency(freq * multiplier); |
| 106 | } | 120 | } |
| 107 | 121 | ||
| 122 | /// Get max duty value. | ||
| 123 | /// | ||
| 124 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 108 | pub fn get_max_duty(&self) -> u16 { | 125 | pub fn get_max_duty(&self) -> u16 { |
| 109 | self.inner.get_max_compare_value() + 1 | 126 | self.inner.get_max_compare_value() + 1 |
| 110 | } | 127 | } |
| 111 | 128 | ||
| 129 | /// Set the duty for a given channel. | ||
| 130 | /// | ||
| 131 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | ||
| 112 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 132 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 113 | assert!(duty <= self.get_max_duty()); | 133 | assert!(duty <= self.get_max_duty()); |
| 114 | self.inner.set_compare_value(channel, duty) | 134 | self.inner.set_compare_value(channel, duty) |
| 115 | } | 135 | } |
| 116 | 136 | ||
| 137 | /// Set the output polarity for a given channel. | ||
| 117 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 138 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 118 | self.inner.set_output_polarity(channel, polarity); | 139 | self.inner.set_output_polarity(channel, polarity); |
| 119 | self.inner.set_complementary_output_polarity(channel, polarity); | 140 | self.inner.set_complementary_output_polarity(channel, polarity); |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 2313a5b94..74120adad 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Timers, PWM, quadrature decoder. | ||
| 2 | |||
| 1 | pub mod complementary_pwm; | 3 | pub mod complementary_pwm; |
| 2 | pub mod qei; | 4 | pub mod qei; |
| 3 | pub mod simple_pwm; | 5 | pub mod simple_pwm; |
| @@ -8,23 +10,34 @@ use crate::interrupt; | |||
| 8 | use crate::rcc::RccPeripheral; | 10 | use crate::rcc::RccPeripheral; |
| 9 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 10 | 12 | ||
| 13 | /// Low-level timer access. | ||
| 11 | #[cfg(feature = "unstable-pac")] | 14 | #[cfg(feature = "unstable-pac")] |
| 12 | pub mod low_level { | 15 | pub mod low_level { |
| 13 | pub use super::sealed::*; | 16 | pub use super::sealed::*; |
| 14 | } | 17 | } |
| 15 | 18 | ||
| 16 | pub(crate) mod sealed { | 19 | pub(crate) mod sealed { |
| 17 | |||
| 18 | use super::*; | 20 | use super::*; |
| 21 | |||
| 22 | /// Basic 16-bit timer instance. | ||
| 19 | pub trait Basic16bitInstance: RccPeripheral { | 23 | pub trait Basic16bitInstance: RccPeripheral { |
| 24 | /// Interrupt for this timer. | ||
| 20 | type Interrupt: interrupt::typelevel::Interrupt; | 25 | type Interrupt: interrupt::typelevel::Interrupt; |
| 21 | 26 | ||
| 27 | /// Get access to the basic 16bit timer registers. | ||
| 28 | /// | ||
| 29 | /// Note: This works even if the timer is more capable, because registers | ||
| 30 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 31 | /// for a given set of capabilities, and having it transparently work with | ||
| 32 | /// more capable timers. | ||
| 22 | fn regs() -> crate::pac::timer::TimBasic; | 33 | fn regs() -> crate::pac::timer::TimBasic; |
| 23 | 34 | ||
| 35 | /// Start the timer. | ||
| 24 | fn start(&mut self) { | 36 | fn start(&mut self) { |
| 25 | Self::regs().cr1().modify(|r| r.set_cen(true)); | 37 | Self::regs().cr1().modify(|r| r.set_cen(true)); |
| 26 | } | 38 | } |
| 27 | 39 | ||
| 40 | /// Stop the timer. | ||
| 28 | fn stop(&mut self) { | 41 | fn stop(&mut self) { |
| 29 | Self::regs().cr1().modify(|r| r.set_cen(false)); | 42 | Self::regs().cr1().modify(|r| r.set_cen(false)); |
| 30 | } | 43 | } |
| @@ -60,6 +73,9 @@ pub(crate) mod sealed { | |||
| 60 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 73 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 61 | } | 74 | } |
| 62 | 75 | ||
| 76 | /// Clear update interrupt. | ||
| 77 | /// | ||
| 78 | /// Returns whether the update interrupt flag was set. | ||
| 63 | fn clear_update_interrupt(&mut self) -> bool { | 79 | fn clear_update_interrupt(&mut self) -> bool { |
| 64 | let regs = Self::regs(); | 80 | let regs = Self::regs(); |
| 65 | let sr = regs.sr().read(); | 81 | let sr = regs.sr().read(); |
| @@ -73,14 +89,17 @@ pub(crate) mod sealed { | |||
| 73 | } | 89 | } |
| 74 | } | 90 | } |
| 75 | 91 | ||
| 92 | /// Enable/disable the update interrupt. | ||
| 76 | fn enable_update_interrupt(&mut self, enable: bool) { | 93 | fn enable_update_interrupt(&mut self, enable: bool) { |
| 77 | Self::regs().dier().write(|r| r.set_uie(enable)); | 94 | Self::regs().dier().write(|r| r.set_uie(enable)); |
| 78 | } | 95 | } |
| 79 | 96 | ||
| 80 | fn set_autoreload_preload(&mut self, enable: vals::Arpe) { | 97 | /// Enable/disable autoreload preload. |
| 98 | fn set_autoreload_preload(&mut self, enable: bool) { | ||
| 81 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); | 99 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); |
| 82 | } | 100 | } |
| 83 | 101 | ||
| 102 | /// Get the timer frequency. | ||
| 84 | fn get_frequency(&self) -> Hertz { | 103 | fn get_frequency(&self) -> Hertz { |
| 85 | let timer_f = Self::frequency(); | 104 | let timer_f = Self::frequency(); |
| 86 | 105 | ||
| @@ -92,9 +111,17 @@ pub(crate) mod sealed { | |||
| 92 | } | 111 | } |
| 93 | } | 112 | } |
| 94 | 113 | ||
| 114 | /// Gneral-purpose 16-bit timer instance. | ||
| 95 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { | 115 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { |
| 116 | /// Get access to the general purpose 16bit timer registers. | ||
| 117 | /// | ||
| 118 | /// Note: This works even if the timer is more capable, because registers | ||
| 119 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 120 | /// for a given set of capabilities, and having it transparently work with | ||
| 121 | /// more capable timers. | ||
| 96 | fn regs_gp16() -> crate::pac::timer::TimGp16; | 122 | fn regs_gp16() -> crate::pac::timer::TimGp16; |
| 97 | 123 | ||
| 124 | /// Set counting mode. | ||
| 98 | fn set_counting_mode(&mut self, mode: CountingMode) { | 125 | fn set_counting_mode(&mut self, mode: CountingMode) { |
| 99 | let (cms, dir) = mode.into(); | 126 | let (cms, dir) = mode.into(); |
| 100 | 127 | ||
| @@ -107,19 +134,29 @@ pub(crate) mod sealed { | |||
| 107 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) | 134 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) |
| 108 | } | 135 | } |
| 109 | 136 | ||
| 137 | /// Get counting mode. | ||
| 110 | fn get_counting_mode(&self) -> CountingMode { | 138 | fn get_counting_mode(&self) -> CountingMode { |
| 111 | let cr1 = Self::regs_gp16().cr1().read(); | 139 | let cr1 = Self::regs_gp16().cr1().read(); |
| 112 | (cr1.cms(), cr1.dir()).into() | 140 | (cr1.cms(), cr1.dir()).into() |
| 113 | } | 141 | } |
| 114 | 142 | ||
| 143 | /// Set clock divider. | ||
| 115 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | 144 | fn set_clock_division(&mut self, ckd: vals::Ckd) { |
| 116 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); | 145 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); |
| 117 | } | 146 | } |
| 118 | } | 147 | } |
| 119 | 148 | ||
| 149 | /// Gneral-purpose 32-bit timer instance. | ||
| 120 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { | 150 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { |
| 151 | /// Get access to the general purpose 32bit timer registers. | ||
| 152 | /// | ||
| 153 | /// Note: This works even if the timer is more capable, because registers | ||
| 154 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 155 | /// for a given set of capabilities, and having it transparently work with | ||
| 156 | /// more capable timers. | ||
| 121 | fn regs_gp32() -> crate::pac::timer::TimGp32; | 157 | fn regs_gp32() -> crate::pac::timer::TimGp32; |
| 122 | 158 | ||
| 159 | /// Set timer frequency. | ||
| 123 | fn set_frequency(&mut self, frequency: Hertz) { | 160 | fn set_frequency(&mut self, frequency: Hertz) { |
| 124 | let f = frequency.0; | 161 | let f = frequency.0; |
| 125 | assert!(f > 0); | 162 | assert!(f > 0); |
| @@ -137,6 +174,7 @@ pub(crate) mod sealed { | |||
| 137 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 174 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 138 | } | 175 | } |
| 139 | 176 | ||
| 177 | /// Get timer frequency. | ||
| 140 | fn get_frequency(&self) -> Hertz { | 178 | fn get_frequency(&self) -> Hertz { |
| 141 | let timer_f = Self::frequency(); | 179 | let timer_f = Self::frequency(); |
| 142 | 180 | ||
| @@ -148,141 +186,177 @@ pub(crate) mod sealed { | |||
| 148 | } | 186 | } |
| 149 | } | 187 | } |
| 150 | 188 | ||
| 189 | /// Advanced control timer instance. | ||
| 151 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { | 190 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { |
| 191 | /// Get access to the advanced timer registers. | ||
| 152 | fn regs_advanced() -> crate::pac::timer::TimAdv; | 192 | fn regs_advanced() -> crate::pac::timer::TimAdv; |
| 153 | } | 193 | } |
| 154 | 194 | ||
| 195 | /// Capture/Compare 16-bit timer instance. | ||
| 155 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { | 196 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { |
| 197 | /// Set input capture filter. | ||
| 156 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { | 198 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { |
| 157 | let raw_channel = channel.raw(); | 199 | let raw_channel = channel.index(); |
| 158 | Self::regs_gp16() | 200 | Self::regs_gp16() |
| 159 | .ccmr_input(raw_channel / 2) | 201 | .ccmr_input(raw_channel / 2) |
| 160 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | 202 | .modify(|r| r.set_icf(raw_channel % 2, icf)); |
| 161 | } | 203 | } |
| 162 | 204 | ||
| 205 | /// Clear input interrupt. | ||
| 163 | fn clear_input_interrupt(&mut self, channel: Channel) { | 206 | fn clear_input_interrupt(&mut self, channel: Channel) { |
| 164 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); | 207 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); |
| 165 | } | 208 | } |
| 166 | 209 | ||
| 210 | /// Enable input interrupt. | ||
| 167 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | 211 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { |
| 168 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); | 212 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); |
| 169 | } | 213 | } |
| 214 | |||
| 215 | /// Set input capture prescaler. | ||
| 170 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | 216 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { |
| 171 | let raw_channel = channel.raw(); | 217 | let raw_channel = channel.index(); |
| 172 | Self::regs_gp16() | 218 | Self::regs_gp16() |
| 173 | .ccmr_input(raw_channel / 2) | 219 | .ccmr_input(raw_channel / 2) |
| 174 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | 220 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); |
| 175 | } | 221 | } |
| 176 | 222 | ||
| 223 | /// Set input TI selection. | ||
| 177 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | 224 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { |
| 178 | let raw_channel = channel.raw(); | 225 | let raw_channel = channel.index(); |
| 179 | Self::regs_gp16() | 226 | Self::regs_gp16() |
| 180 | .ccmr_input(raw_channel / 2) | 227 | .ccmr_input(raw_channel / 2) |
| 181 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | 228 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); |
| 182 | } | 229 | } |
| 230 | |||
| 231 | /// Set input capture mode. | ||
| 183 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | 232 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { |
| 184 | Self::regs_gp16().ccer().modify(|r| match mode { | 233 | Self::regs_gp16().ccer().modify(|r| match mode { |
| 185 | InputCaptureMode::Rising => { | 234 | InputCaptureMode::Rising => { |
| 186 | r.set_ccnp(channel.raw(), false); | 235 | r.set_ccnp(channel.index(), false); |
| 187 | r.set_ccp(channel.raw(), false); | 236 | r.set_ccp(channel.index(), false); |
| 188 | } | 237 | } |
| 189 | InputCaptureMode::Falling => { | 238 | InputCaptureMode::Falling => { |
| 190 | r.set_ccnp(channel.raw(), false); | 239 | r.set_ccnp(channel.index(), false); |
| 191 | r.set_ccp(channel.raw(), true); | 240 | r.set_ccp(channel.index(), true); |
| 192 | } | 241 | } |
| 193 | InputCaptureMode::BothEdges => { | 242 | InputCaptureMode::BothEdges => { |
| 194 | r.set_ccnp(channel.raw(), true); | 243 | r.set_ccnp(channel.index(), true); |
| 195 | r.set_ccp(channel.raw(), true); | 244 | r.set_ccp(channel.index(), true); |
| 196 | } | 245 | } |
| 197 | }); | 246 | }); |
| 198 | } | 247 | } |
| 248 | |||
| 249 | /// Enable timer outputs. | ||
| 199 | fn enable_outputs(&mut self); | 250 | fn enable_outputs(&mut self); |
| 200 | 251 | ||
| 252 | /// Set output compare mode. | ||
| 201 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { | 253 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { |
| 202 | let r = Self::regs_gp16(); | 254 | let r = Self::regs_gp16(); |
| 203 | let raw_channel: usize = channel.raw(); | 255 | let raw_channel: usize = channel.index(); |
| 204 | r.ccmr_output(raw_channel / 2) | 256 | r.ccmr_output(raw_channel / 2) |
| 205 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 257 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 206 | } | 258 | } |
| 207 | 259 | ||
| 260 | /// Set output polarity. | ||
| 208 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 261 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 209 | Self::regs_gp16() | 262 | Self::regs_gp16() |
| 210 | .ccer() | 263 | .ccer() |
| 211 | .modify(|w| w.set_ccp(channel.raw(), polarity.into())); | 264 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); |
| 212 | } | 265 | } |
| 213 | 266 | ||
| 267 | /// Enable/disable a channel. | ||
| 214 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 268 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 215 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | 269 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); |
| 216 | } | 270 | } |
| 217 | 271 | ||
| 272 | /// Set compare value for a channel. | ||
| 218 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | 273 | fn set_compare_value(&mut self, channel: Channel, value: u16) { |
| 219 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 274 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 220 | } | 275 | } |
| 221 | 276 | ||
| 277 | /// Get capture value for a channel. | ||
| 222 | fn get_capture_value(&mut self, channel: Channel) -> u16 { | 278 | fn get_capture_value(&mut self, channel: Channel) -> u16 { |
| 223 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | 279 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 224 | } | 280 | } |
| 225 | 281 | ||
| 282 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 226 | fn get_max_compare_value(&self) -> u16 { | 283 | fn get_max_compare_value(&self) -> u16 { |
| 227 | Self::regs_gp16().arr().read().arr() | 284 | Self::regs_gp16().arr().read().arr() |
| 228 | } | 285 | } |
| 229 | 286 | ||
| 287 | /// Get compare value for a channel. | ||
| 230 | fn get_compare_value(&self, channel: Channel) -> u16 { | 288 | fn get_compare_value(&self, channel: Channel) -> u16 { |
| 231 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | 289 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 232 | } | 290 | } |
| 233 | } | 291 | } |
| 234 | 292 | ||
| 293 | /// Capture/Compare 16-bit timer instance with complementary pin support. | ||
| 235 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { | 294 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { |
| 295 | /// Set complementary output polarity. | ||
| 236 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 296 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 237 | Self::regs_advanced() | 297 | Self::regs_advanced() |
| 238 | .ccer() | 298 | .ccer() |
| 239 | .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); | 299 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); |
| 240 | } | 300 | } |
| 241 | 301 | ||
| 302 | /// Set clock divider for the dead time. | ||
| 242 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { | 303 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { |
| 243 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | 304 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); |
| 244 | } | 305 | } |
| 245 | 306 | ||
| 307 | /// Set dead time, as a fraction of the max duty value. | ||
| 246 | fn set_dead_time_value(&mut self, value: u8) { | 308 | fn set_dead_time_value(&mut self, value: u8) { |
| 247 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); | 309 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); |
| 248 | } | 310 | } |
| 249 | 311 | ||
| 312 | /// Enable/disable a complementary channel. | ||
| 250 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | 313 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { |
| 251 | Self::regs_advanced() | 314 | Self::regs_advanced() |
| 252 | .ccer() | 315 | .ccer() |
| 253 | .modify(|w| w.set_ccne(channel.raw(), enable)); | 316 | .modify(|w| w.set_ccne(channel.index(), enable)); |
| 254 | } | 317 | } |
| 255 | } | 318 | } |
| 256 | 319 | ||
| 320 | /// Capture/Compare 32-bit timer instance. | ||
| 257 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { | 321 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { |
| 322 | /// Set comapre value for a channel. | ||
| 258 | fn set_compare_value(&mut self, channel: Channel, value: u32) { | 323 | fn set_compare_value(&mut self, channel: Channel, value: u32) { |
| 259 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 324 | Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 260 | } | 325 | } |
| 261 | 326 | ||
| 327 | /// Get capture value for a channel. | ||
| 262 | fn get_capture_value(&mut self, channel: Channel) -> u32 { | 328 | fn get_capture_value(&mut self, channel: Channel) -> u32 { |
| 263 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | 329 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 264 | } | 330 | } |
| 265 | 331 | ||
| 332 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 266 | fn get_max_compare_value(&self) -> u32 { | 333 | fn get_max_compare_value(&self) -> u32 { |
| 267 | Self::regs_gp32().arr().read().arr() | 334 | Self::regs_gp32().arr().read().arr() |
| 268 | } | 335 | } |
| 269 | 336 | ||
| 337 | /// Get compare value for a channel. | ||
| 270 | fn get_compare_value(&self, channel: Channel) -> u32 { | 338 | fn get_compare_value(&self, channel: Channel) -> u32 { |
| 271 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | 339 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 272 | } | 340 | } |
| 273 | } | 341 | } |
| 274 | } | 342 | } |
| 275 | 343 | ||
| 344 | /// Timer channel. | ||
| 276 | #[derive(Clone, Copy)] | 345 | #[derive(Clone, Copy)] |
| 277 | pub enum Channel { | 346 | pub enum Channel { |
| 347 | /// Channel 1. | ||
| 278 | Ch1, | 348 | Ch1, |
| 349 | /// Channel 2. | ||
| 279 | Ch2, | 350 | Ch2, |
| 351 | /// Channel 3. | ||
| 280 | Ch3, | 352 | Ch3, |
| 353 | /// Channel 4. | ||
| 281 | Ch4, | 354 | Ch4, |
| 282 | } | 355 | } |
| 283 | 356 | ||
| 284 | impl Channel { | 357 | impl Channel { |
| 285 | pub fn raw(&self) -> usize { | 358 | /// Get the channel index (0..3) |
| 359 | pub fn index(&self) -> usize { | ||
| 286 | match self { | 360 | match self { |
| 287 | Channel::Ch1 => 0, | 361 | Channel::Ch1 => 0, |
| 288 | Channel::Ch2 => 1, | 362 | Channel::Ch2 => 1, |
| @@ -292,17 +366,25 @@ impl Channel { | |||
| 292 | } | 366 | } |
| 293 | } | 367 | } |
| 294 | 368 | ||
| 369 | /// Input capture mode. | ||
| 295 | #[derive(Clone, Copy)] | 370 | #[derive(Clone, Copy)] |
| 296 | pub enum InputCaptureMode { | 371 | pub enum InputCaptureMode { |
| 372 | /// Rising edge only. | ||
| 297 | Rising, | 373 | Rising, |
| 374 | /// Falling edge only. | ||
| 298 | Falling, | 375 | Falling, |
| 376 | /// Both rising or falling edges. | ||
| 299 | BothEdges, | 377 | BothEdges, |
| 300 | } | 378 | } |
| 301 | 379 | ||
| 380 | /// Input TI selection. | ||
| 302 | #[derive(Clone, Copy)] | 381 | #[derive(Clone, Copy)] |
| 303 | pub enum InputTISelection { | 382 | pub enum InputTISelection { |
| 383 | /// Normal | ||
| 304 | Normal, | 384 | Normal, |
| 385 | /// Alternate | ||
| 305 | Alternate, | 386 | Alternate, |
| 387 | /// TRC | ||
| 306 | TRC, | 388 | TRC, |
| 307 | } | 389 | } |
| 308 | 390 | ||
| @@ -316,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | |||
| 316 | } | 398 | } |
| 317 | } | 399 | } |
| 318 | 400 | ||
| 401 | /// Timer counting mode. | ||
| 319 | #[repr(u8)] | 402 | #[repr(u8)] |
| 320 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | 403 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] |
| 321 | pub enum CountingMode { | 404 | pub enum CountingMode { |
| @@ -342,6 +425,7 @@ pub enum CountingMode { | |||
| 342 | } | 425 | } |
| 343 | 426 | ||
| 344 | impl CountingMode { | 427 | impl CountingMode { |
| 428 | /// Return whether this mode is edge-aligned (up or down). | ||
| 345 | pub fn is_edge_aligned(&self) -> bool { | 429 | pub fn is_edge_aligned(&self) -> bool { |
| 346 | match self { | 430 | match self { |
| 347 | CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, | 431 | CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, |
| @@ -349,6 +433,7 @@ impl CountingMode { | |||
| 349 | } | 433 | } |
| 350 | } | 434 | } |
| 351 | 435 | ||
| 436 | /// Return whether this mode is center-aligned. | ||
| 352 | pub fn is_center_aligned(&self) -> bool { | 437 | pub fn is_center_aligned(&self) -> bool { |
| 353 | match self { | 438 | match self { |
| 354 | CountingMode::CenterAlignedDownInterrupts | 439 | CountingMode::CenterAlignedDownInterrupts |
| @@ -383,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode { | |||
| 383 | } | 468 | } |
| 384 | } | 469 | } |
| 385 | 470 | ||
| 471 | /// Output compare mode. | ||
| 386 | #[derive(Clone, Copy)] | 472 | #[derive(Clone, Copy)] |
| 387 | pub enum OutputCompareMode { | 473 | pub enum OutputCompareMode { |
| 474 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 475 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 476 | /// (this mode is used to generate a timing base). | ||
| 388 | Frozen, | 477 | Frozen, |
| 478 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 479 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 389 | ActiveOnMatch, | 480 | ActiveOnMatch, |
| 481 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 482 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 390 | InactiveOnMatch, | 483 | InactiveOnMatch, |
| 484 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 391 | Toggle, | 485 | Toggle, |
| 486 | /// Force inactive level - OCxREF is forced low. | ||
| 392 | ForceInactive, | 487 | ForceInactive, |
| 488 | /// Force active level - OCxREF is forced high. | ||
| 393 | ForceActive, | 489 | ForceActive, |
| 490 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 491 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 492 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 394 | PwmMode1, | 493 | PwmMode1, |
| 494 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 495 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 496 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 395 | PwmMode2, | 497 | PwmMode2, |
| 498 | // TODO: there's more modes here depending on the chip family. | ||
| 396 | } | 499 | } |
| 397 | 500 | ||
| 398 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | 501 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { |
| @@ -410,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | |||
| 410 | } | 513 | } |
| 411 | } | 514 | } |
| 412 | 515 | ||
| 516 | /// Timer output pin polarity. | ||
| 413 | #[derive(Clone, Copy)] | 517 | #[derive(Clone, Copy)] |
| 414 | pub enum OutputPolarity { | 518 | pub enum OutputPolarity { |
| 519 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 415 | ActiveHigh, | 520 | ActiveHigh, |
| 521 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 416 | ActiveLow, | 522 | ActiveLow, |
| 417 | } | 523 | } |
| 418 | 524 | ||
| @@ -425,24 +531,31 @@ impl From<OutputPolarity> for bool { | |||
| 425 | } | 531 | } |
| 426 | } | 532 | } |
| 427 | 533 | ||
| 534 | /// Basic 16-bit timer instance. | ||
| 428 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | 535 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} |
| 429 | 536 | ||
| 537 | /// Gneral-purpose 16-bit timer instance. | ||
| 430 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} | 538 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} |
| 431 | 539 | ||
| 540 | /// Gneral-purpose 32-bit timer instance. | ||
| 432 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} | 541 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} |
| 433 | 542 | ||
| 543 | /// Advanced control timer instance. | ||
| 434 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} | 544 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} |
| 435 | 545 | ||
| 546 | /// Capture/Compare 16-bit timer instance. | ||
| 436 | pub trait CaptureCompare16bitInstance: | 547 | pub trait CaptureCompare16bitInstance: |
| 437 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static | 548 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static |
| 438 | { | 549 | { |
| 439 | } | 550 | } |
| 440 | 551 | ||
| 552 | /// Capture/Compare 16-bit timer instance with complementary pin support. | ||
| 441 | pub trait ComplementaryCaptureCompare16bitInstance: | 553 | pub trait ComplementaryCaptureCompare16bitInstance: |
| 442 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static | 554 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static |
| 443 | { | 555 | { |
| 444 | } | 556 | } |
| 445 | 557 | ||
| 558 | /// Capture/Compare 32-bit timer instance. | ||
| 446 | pub trait CaptureCompare32bitInstance: | 559 | pub trait CaptureCompare32bitInstance: |
| 447 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static | 560 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static |
| 448 | { | 561 | { |
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 01d028bf9..59efb72ba 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Quadrature decoder using a timer. | ||
| 2 | |||
| 1 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 2 | 4 | ||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| @@ -7,23 +9,30 @@ use crate::gpio::sealed::AFType; | |||
| 7 | use crate::gpio::AnyPin; | 9 | use crate::gpio::AnyPin; |
| 8 | use crate::Peripheral; | 10 | use crate::Peripheral; |
| 9 | 11 | ||
| 12 | /// Counting direction | ||
| 10 | pub enum Direction { | 13 | pub enum Direction { |
| 14 | /// Counting up. | ||
| 11 | Upcounting, | 15 | Upcounting, |
| 16 | /// Counting down. | ||
| 12 | Downcounting, | 17 | Downcounting, |
| 13 | } | 18 | } |
| 14 | 19 | ||
| 15 | pub struct Ch1; | 20 | /// Channel 1 marker type. |
| 16 | pub struct Ch2; | 21 | pub enum Ch1 {} |
| 22 | /// Channel 2 marker type. | ||
| 23 | pub enum Ch2 {} | ||
| 17 | 24 | ||
| 18 | pub struct QeiPin<'d, Perip, Channel> { | 25 | /// Wrapper for using a pin with QEI. |
| 26 | pub struct QeiPin<'d, T, Channel> { | ||
| 19 | _pin: PeripheralRef<'d, AnyPin>, | 27 | _pin: PeripheralRef<'d, AnyPin>, |
| 20 | phantom: PhantomData<(Perip, Channel)>, | 28 | phantom: PhantomData<(T, Channel)>, |
| 21 | } | 29 | } |
| 22 | 30 | ||
| 23 | macro_rules! channel_impl { | 31 | macro_rules! channel_impl { |
| 24 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 25 | impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { | 33 | impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { |
| 26 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | 34 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { | ||
| 27 | into_ref!(pin); | 36 | into_ref!(pin); |
| 28 | critical_section::with(|_| { | 37 | critical_section::with(|_| { |
| 29 | pin.set_low(); | 38 | pin.set_low(); |
| @@ -43,11 +52,13 @@ macro_rules! channel_impl { | |||
| 43 | channel_impl!(new_ch1, Ch1, Channel1Pin); | 52 | channel_impl!(new_ch1, Ch1, Channel1Pin); |
| 44 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 53 | channel_impl!(new_ch2, Ch2, Channel2Pin); |
| 45 | 54 | ||
| 55 | /// Quadrature decoder driver. | ||
| 46 | pub struct Qei<'d, T> { | 56 | pub struct Qei<'d, T> { |
| 47 | _inner: PeripheralRef<'d, T>, | 57 | _inner: PeripheralRef<'d, T>, |
| 48 | } | 58 | } |
| 49 | 59 | ||
| 50 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | 60 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { |
| 61 | /// Create a new quadrature decoder driver. | ||
| 51 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { | 62 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { |
| 52 | Self::new_inner(tim) | 63 | Self::new_inner(tim) |
| 53 | } | 64 | } |
| @@ -82,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 82 | Self { _inner: tim } | 93 | Self { _inner: tim } |
| 83 | } | 94 | } |
| 84 | 95 | ||
| 96 | /// Get direction. | ||
| 85 | pub fn read_direction(&self) -> Direction { | 97 | pub fn read_direction(&self) -> Direction { |
| 86 | match T::regs_gp16().cr1().read().dir() { | 98 | match T::regs_gp16().cr1().read().dir() { |
| 87 | vals::Dir::DOWN => Direction::Downcounting, | 99 | vals::Dir::DOWN => Direction::Downcounting, |
| @@ -89,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 89 | } | 101 | } |
| 90 | } | 102 | } |
| 91 | 103 | ||
| 104 | /// Get count. | ||
| 92 | pub fn count(&self) -> u16 { | 105 | pub fn count(&self) -> u16 { |
| 93 | T::regs_gp16().cnt().read().cnt() | 106 | T::regs_gp16().cnt().read().cnt() |
| 94 | } | 107 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1cf0ad728..e6072aa15 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Simple PWM driver. | ||
| 2 | |||
| 1 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 2 | 4 | ||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| @@ -9,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType}; | |||
| 9 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 10 | use crate::Peripheral; | 12 | use crate::Peripheral; |
| 11 | 13 | ||
| 12 | pub struct Ch1; | 14 | /// Channel 1 marker type. |
| 13 | pub struct Ch2; | 15 | pub enum Ch1 {} |
| 14 | pub struct Ch3; | 16 | /// Channel 2 marker type. |
| 15 | pub struct Ch4; | 17 | pub enum Ch2 {} |
| 16 | 18 | /// Channel 3 marker type. | |
| 17 | pub struct PwmPin<'d, Perip, Channel> { | 19 | pub enum Ch3 {} |
| 20 | /// Channel 4 marker type. | ||
| 21 | pub enum Ch4 {} | ||
| 22 | |||
| 23 | /// PWM pin wrapper. | ||
| 24 | /// | ||
| 25 | /// This wraps a pin to make it usable with PWM. | ||
| 26 | pub struct PwmPin<'d, T, C> { | ||
| 18 | _pin: PeripheralRef<'d, AnyPin>, | 27 | _pin: PeripheralRef<'d, AnyPin>, |
| 19 | phantom: PhantomData<(Perip, Channel)>, | 28 | phantom: PhantomData<(T, C)>, |
| 20 | } | 29 | } |
| 21 | 30 | ||
| 22 | macro_rules! channel_impl { | 31 | macro_rules! channel_impl { |
| 23 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 24 | impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { | 33 | impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { |
| 25 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { | 34 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | ||
| 26 | into_ref!(pin); | 36 | into_ref!(pin); |
| 27 | critical_section::with(|_| { | 37 | critical_section::with(|_| { |
| 28 | pin.set_low(); | 38 | pin.set_low(); |
| @@ -44,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin); | |||
| 44 | channel_impl!(new_ch3, Ch3, Channel3Pin); | 54 | channel_impl!(new_ch3, Ch3, Channel3Pin); |
| 45 | channel_impl!(new_ch4, Ch4, Channel4Pin); | 55 | channel_impl!(new_ch4, Ch4, Channel4Pin); |
| 46 | 56 | ||
| 57 | /// Simple PWM driver. | ||
| 47 | pub struct SimplePwm<'d, T> { | 58 | pub struct SimplePwm<'d, T> { |
| 48 | inner: PeripheralRef<'d, T>, | 59 | inner: PeripheralRef<'d, T>, |
| 49 | } | 60 | } |
| 50 | 61 | ||
| 51 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 62 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { |
| 63 | /// Create a new simple PWM driver. | ||
| 52 | pub fn new( | 64 | pub fn new( |
| 53 | tim: impl Peripheral<P = T> + 'd, | 65 | tim: impl Peripheral<P = T> + 'd, |
| 54 | _ch1: Option<PwmPin<'d, T, Ch1>>, | 66 | _ch1: Option<PwmPin<'d, T, Ch1>>, |
| @@ -69,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 69 | let mut this = Self { inner: tim }; | 81 | let mut this = Self { inner: tim }; |
| 70 | 82 | ||
| 71 | this.inner.set_counting_mode(counting_mode); | 83 | this.inner.set_counting_mode(counting_mode); |
| 72 | this.set_freq(freq); | 84 | this.set_frequency(freq); |
| 73 | this.inner.start(); | 85 | this.inner.start(); |
| 74 | 86 | ||
| 75 | this.inner.enable_outputs(); | 87 | this.inner.enable_outputs(); |
| @@ -85,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 85 | this | 97 | this |
| 86 | } | 98 | } |
| 87 | 99 | ||
| 100 | /// Enable the given channel. | ||
| 88 | pub fn enable(&mut self, channel: Channel) { | 101 | pub fn enable(&mut self, channel: Channel) { |
| 89 | self.inner.enable_channel(channel, true); | 102 | self.inner.enable_channel(channel, true); |
| 90 | } | 103 | } |
| 91 | 104 | ||
| 105 | /// Disable the given channel. | ||
| 92 | pub fn disable(&mut self, channel: Channel) { | 106 | pub fn disable(&mut self, channel: Channel) { |
| 93 | self.inner.enable_channel(channel, false); | 107 | self.inner.enable_channel(channel, false); |
| 94 | } | 108 | } |
| 95 | 109 | ||
| 96 | pub fn set_freq(&mut self, freq: Hertz) { | 110 | /// Set PWM frequency. |
| 111 | /// | ||
| 112 | /// Note: when you call this, the max duty value changes, so you will have to | ||
| 113 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | ||
| 114 | pub fn set_frequency(&mut self, freq: Hertz) { | ||
| 97 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 115 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 98 | 2u8 | 116 | 2u8 |
| 99 | } else { | 117 | } else { |
| @@ -102,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 102 | self.inner.set_frequency(freq * multiplier); | 120 | self.inner.set_frequency(freq * multiplier); |
| 103 | } | 121 | } |
| 104 | 122 | ||
| 123 | /// Get max duty value. | ||
| 124 | /// | ||
| 125 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 105 | pub fn get_max_duty(&self) -> u16 { | 126 | pub fn get_max_duty(&self) -> u16 { |
| 106 | self.inner.get_max_compare_value() + 1 | 127 | self.inner.get_max_compare_value() + 1 |
| 107 | } | 128 | } |
| 108 | 129 | ||
| 130 | /// Set the duty for a given channel. | ||
| 131 | /// | ||
| 132 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | ||
| 109 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 133 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 110 | assert!(duty <= self.get_max_duty()); | 134 | assert!(duty <= self.get_max_duty()); |
| 111 | self.inner.set_compare_value(channel, duty) | 135 | self.inner.set_compare_value(channel, duty) |
| 112 | } | 136 | } |
| 113 | 137 | ||
| 138 | /// Set the output polarity for a given channel. | ||
| 114 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 139 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 115 | self.inner.set_output_polarity(channel, polarity); | 140 | self.inner.set_output_polarity(channel, polarity); |
| 116 | } | 141 | } |
diff --git a/embassy-stm32/src/traits.rs b/embassy-stm32/src/traits.rs index ffce7bd42..13f695821 100644 --- a/embassy-stm32/src/traits.rs +++ b/embassy-stm32/src/traits.rs | |||
| @@ -1,16 +1,18 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | macro_rules! pin_trait { | 3 | macro_rules! pin_trait { |
| 4 | ($signal:ident, $instance:path) => { | 4 | ($signal:ident, $instance:path $(, $mode:path)?) => { |
| 5 | pub trait $signal<T: $instance>: crate::gpio::Pin { | 5 | #[doc = concat!(stringify!($signal), " pin trait")] |
| 6 | pub trait $signal<T: $instance $(, M: $mode)?>: crate::gpio::Pin { | ||
| 7 | #[doc = concat!("Get the AF number needed to use this pin as ", stringify!($signal))] | ||
| 6 | fn af_num(&self) -> u8; | 8 | fn af_num(&self) -> u8; |
| 7 | } | 9 | } |
| 8 | }; | 10 | }; |
| 9 | } | 11 | } |
| 10 | 12 | ||
| 11 | macro_rules! pin_trait_impl { | 13 | macro_rules! pin_trait_impl { |
| 12 | (crate::$mod:ident::$trait:ident, $instance:ident, $pin:ident, $af:expr) => { | 14 | (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $af:expr) => { |
| 13 | impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$pin { | 15 | impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$pin { |
| 14 | fn af_num(&self) -> u8 { | 16 | fn af_num(&self) -> u8 { |
| 15 | $af | 17 | $af |
| 16 | } | 18 | } |
| @@ -21,8 +23,12 @@ macro_rules! pin_trait_impl { | |||
| 21 | // ==================== | 23 | // ==================== |
| 22 | 24 | ||
| 23 | macro_rules! dma_trait { | 25 | macro_rules! dma_trait { |
| 24 | ($signal:ident, $instance:path) => { | 26 | ($signal:ident, $instance:path$(, $mode:path)?) => { |
| 25 | pub trait $signal<T: $instance>: crate::dma::Channel { | 27 | #[doc = concat!(stringify!($signal), " DMA request trait")] |
| 28 | pub trait $signal<T: $instance $(, M: $mode)?>: crate::dma::Channel { | ||
| 29 | #[doc = concat!("Get the DMA request number needed to use this channel as", stringify!($signal))] | ||
| 30 | /// Note: in some chips, ST calls this the "channel", and calls channels "streams". | ||
| 31 | /// `embassy-stm32` always uses the "channel" and "request number" names. | ||
| 26 | fn request(&self) -> crate::dma::Request; | 32 | fn request(&self) -> crate::dma::Request; |
| 27 | } | 33 | } |
| 28 | }; | 34 | }; |
| @@ -31,8 +37,8 @@ macro_rules! dma_trait { | |||
| 31 | #[allow(unused)] | 37 | #[allow(unused)] |
| 32 | macro_rules! dma_trait_impl { | 38 | macro_rules! dma_trait_impl { |
| 33 | // DMAMUX | 39 | // DMAMUX |
| 34 | (crate::$mod:ident::$trait:ident, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { | 40 | (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dmamux: $dmamux:ident}, $request:expr) => { |
| 35 | impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T | 41 | impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T |
| 36 | where | 42 | where |
| 37 | T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, | 43 | T: crate::dma::Channel + crate::dma::MuxChannel<Mux = crate::dma::$dmamux>, |
| 38 | { | 44 | { |
| @@ -43,8 +49,8 @@ macro_rules! dma_trait_impl { | |||
| 43 | }; | 49 | }; |
| 44 | 50 | ||
| 45 | // DMAMUX | 51 | // DMAMUX |
| 46 | (crate::$mod:ident::$trait:ident, $instance:ident, {dma: $dma:ident}, $request:expr) => { | 52 | (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {dma: $dma:ident}, $request:expr) => { |
| 47 | impl<T> crate::$mod::$trait<crate::peripherals::$instance> for T | 53 | impl<T> crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for T |
| 48 | where | 54 | where |
| 49 | T: crate::dma::Channel, | 55 | T: crate::dma::Channel, |
| 50 | { | 56 | { |
| @@ -55,8 +61,8 @@ macro_rules! dma_trait_impl { | |||
| 55 | }; | 61 | }; |
| 56 | 62 | ||
| 57 | // DMA/GPDMA, without DMAMUX | 63 | // DMA/GPDMA, without DMAMUX |
| 58 | (crate::$mod:ident::$trait:ident, $instance:ident, {channel: $channel:ident}, $request:expr) => { | 64 | (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, {channel: $channel:ident}, $request:expr) => { |
| 59 | impl crate::$mod::$trait<crate::peripherals::$instance> for crate::peripherals::$channel { | 65 | impl crate::$mod::$trait<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel { |
| 60 | fn request(&self) -> crate::dma::Request { | 66 | fn request(&self) -> crate::dma::Request { |
| 61 | $request | 67 | $request |
| 62 | } | 68 | } |
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs index 6dcfcb96e..aa13586f8 100644 --- a/embassy-stm32/src/uid.rs +++ b/embassy-stm32/src/uid.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Unique ID (UID) | ||
| 2 | |||
| 1 | /// Get this device's unique 96-bit ID. | 3 | /// Get this device's unique 96-bit ID. |
| 2 | pub fn uid() -> &'static [u8; 12] { | 4 | pub fn uid() -> &'static [u8; 12] { |
| 3 | unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } | 5 | unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } |
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index a2e4ceaae..962547bd7 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -82,6 +82,7 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 82 | } | 82 | } |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | /// Buffered UART State | ||
| 85 | pub struct State { | 86 | pub struct State { |
| 86 | rx_waker: AtomicWaker, | 87 | rx_waker: AtomicWaker, |
| 87 | rx_buf: RingBuffer, | 88 | rx_buf: RingBuffer, |
| @@ -91,6 +92,7 @@ pub struct State { | |||
| 91 | } | 92 | } |
| 92 | 93 | ||
| 93 | impl State { | 94 | impl State { |
| 95 | /// Create new state | ||
| 94 | pub const fn new() -> Self { | 96 | pub const fn new() -> Self { |
| 95 | Self { | 97 | Self { |
| 96 | rx_buf: RingBuffer::new(), | 98 | rx_buf: RingBuffer::new(), |
| @@ -101,15 +103,18 @@ impl State { | |||
| 101 | } | 103 | } |
| 102 | } | 104 | } |
| 103 | 105 | ||
| 106 | /// Bidirectional buffered UART | ||
| 104 | pub struct BufferedUart<'d, T: BasicInstance> { | 107 | pub struct BufferedUart<'d, T: BasicInstance> { |
| 105 | rx: BufferedUartRx<'d, T>, | 108 | rx: BufferedUartRx<'d, T>, |
| 106 | tx: BufferedUartTx<'d, T>, | 109 | tx: BufferedUartTx<'d, T>, |
| 107 | } | 110 | } |
| 108 | 111 | ||
| 112 | /// Tx-only buffered UART | ||
| 109 | pub struct BufferedUartTx<'d, T: BasicInstance> { | 113 | pub struct BufferedUartTx<'d, T: BasicInstance> { |
| 110 | phantom: PhantomData<&'d mut T>, | 114 | phantom: PhantomData<&'d mut T>, |
| 111 | } | 115 | } |
| 112 | 116 | ||
| 117 | /// Rx-only buffered UART | ||
| 113 | pub struct BufferedUartRx<'d, T: BasicInstance> { | 118 | pub struct BufferedUartRx<'d, T: BasicInstance> { |
| 114 | phantom: PhantomData<&'d mut T>, | 119 | phantom: PhantomData<&'d mut T>, |
| 115 | } | 120 | } |
| @@ -142,6 +147,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { | |||
| 142 | } | 147 | } |
| 143 | 148 | ||
| 144 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { | 149 | impl<'d, T: BasicInstance> BufferedUart<'d, T> { |
| 150 | /// Create a new bidirectional buffered UART driver | ||
| 145 | pub fn new( | 151 | pub fn new( |
| 146 | peri: impl Peripheral<P = T> + 'd, | 152 | peri: impl Peripheral<P = T> + 'd, |
| 147 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 153 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 158 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) | 164 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) |
| 159 | } | 165 | } |
| 160 | 166 | ||
| 167 | /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins | ||
| 161 | pub fn new_with_rtscts( | 168 | pub fn new_with_rtscts( |
| 162 | peri: impl Peripheral<P = T> + 'd, | 169 | peri: impl Peripheral<P = T> + 'd, |
| 163 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 170 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 185 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) | 192 | Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) |
| 186 | } | 193 | } |
| 187 | 194 | ||
| 195 | /// Create a new bidirectional buffered UART driver with a driver-enable pin | ||
| 188 | #[cfg(not(any(usart_v1, usart_v2)))] | 196 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 189 | pub fn new_with_de( | 197 | pub fn new_with_de( |
| 190 | peri: impl Peripheral<P = T> + 'd, | 198 | peri: impl Peripheral<P = T> + 'd, |
| @@ -246,10 +254,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { | |||
| 246 | }) | 254 | }) |
| 247 | } | 255 | } |
| 248 | 256 | ||
| 257 | /// Split the driver into a Tx and Rx part (useful for sending to separate tasks) | ||
| 249 | pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { | 258 | pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { |
| 250 | (self.tx, self.rx) | 259 | (self.tx, self.rx) |
| 251 | } | 260 | } |
| 252 | 261 | ||
| 262 | /// Reconfigure the driver | ||
| 253 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 263 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 254 | reconfigure::<T>(config)?; | 264 | reconfigure::<T>(config)?; |
| 255 | 265 | ||
| @@ -337,6 +347,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { | |||
| 337 | } | 347 | } |
| 338 | } | 348 | } |
| 339 | 349 | ||
| 350 | /// Reconfigure the driver | ||
| 340 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 351 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 341 | reconfigure::<T>(config)?; | 352 | reconfigure::<T>(config)?; |
| 342 | 353 | ||
| @@ -418,6 +429,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { | |||
| 418 | } | 429 | } |
| 419 | } | 430 | } |
| 420 | 431 | ||
| 432 | /// Reconfigure the driver | ||
| 421 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 433 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 422 | reconfigure::<T>(config)?; | 434 | reconfigure::<T>(config)?; |
| 423 | 435 | ||
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index d5828a492..8a0c85d2c 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | //! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) | ||
| 1 | #![macro_use] | 2 | #![macro_use] |
| 3 | #![warn(missing_docs)] | ||
| 2 | 4 | ||
| 3 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 4 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| @@ -76,21 +78,29 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt | |||
| 76 | 78 | ||
| 77 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 79 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 78 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 80 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 81 | /// Number of data bits | ||
| 79 | pub enum DataBits { | 82 | pub enum DataBits { |
| 83 | /// 8 Data Bits | ||
| 80 | DataBits8, | 84 | DataBits8, |
| 85 | /// 9 Data Bits | ||
| 81 | DataBits9, | 86 | DataBits9, |
| 82 | } | 87 | } |
| 83 | 88 | ||
| 84 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 89 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 85 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 90 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 91 | /// Parity | ||
| 86 | pub enum Parity { | 92 | pub enum Parity { |
| 93 | /// No parity | ||
| 87 | ParityNone, | 94 | ParityNone, |
| 95 | /// Even Parity | ||
| 88 | ParityEven, | 96 | ParityEven, |
| 97 | /// Odd Parity | ||
| 89 | ParityOdd, | 98 | ParityOdd, |
| 90 | } | 99 | } |
| 91 | 100 | ||
| 92 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 101 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 93 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 102 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 103 | /// Number of stop bits | ||
| 94 | pub enum StopBits { | 104 | pub enum StopBits { |
| 95 | #[doc = "1 stop bit"] | 105 | #[doc = "1 stop bit"] |
| 96 | STOP1, | 106 | STOP1, |
| @@ -105,26 +115,37 @@ pub enum StopBits { | |||
| 105 | #[non_exhaustive] | 115 | #[non_exhaustive] |
| 106 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 116 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 107 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 117 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 118 | /// Config Error | ||
| 108 | pub enum ConfigError { | 119 | pub enum ConfigError { |
| 120 | /// Baudrate too low | ||
| 109 | BaudrateTooLow, | 121 | BaudrateTooLow, |
| 122 | /// Baudrate too high | ||
| 110 | BaudrateTooHigh, | 123 | BaudrateTooHigh, |
| 124 | /// Rx or Tx not enabled | ||
| 111 | RxOrTxNotEnabled, | 125 | RxOrTxNotEnabled, |
| 112 | } | 126 | } |
| 113 | 127 | ||
| 114 | #[non_exhaustive] | 128 | #[non_exhaustive] |
| 115 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 129 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 130 | /// Config | ||
| 116 | pub struct Config { | 131 | pub struct Config { |
| 132 | /// Baud rate | ||
| 117 | pub baudrate: u32, | 133 | pub baudrate: u32, |
| 134 | /// Number of data bits | ||
| 118 | pub data_bits: DataBits, | 135 | pub data_bits: DataBits, |
| 136 | /// Number of stop bits | ||
| 119 | pub stop_bits: StopBits, | 137 | pub stop_bits: StopBits, |
| 138 | /// Parity type | ||
| 120 | pub parity: Parity, | 139 | pub parity: Parity, |
| 121 | /// if true, on read-like method, if there is a latent error pending, | 140 | |
| 122 | /// read will abort, the error reported and cleared | 141 | /// If true: on a read-like method, if there is a latent error pending, |
| 123 | /// if false, the error is ignored and cleared | 142 | /// the read will abort and the error will be reported and cleared |
| 143 | /// | ||
| 144 | /// If false: the error is ignored and cleared | ||
| 124 | pub detect_previous_overrun: bool, | 145 | pub detect_previous_overrun: bool, |
| 125 | 146 | ||
| 126 | /// Set this to true if the line is considered noise free. | 147 | /// Set this to true if the line is considered noise free. |
| 127 | /// This will increase the receivers tolerance to clock deviations, | 148 | /// This will increase the receiver’s tolerance to clock deviations, |
| 128 | /// but will effectively disable noise detection. | 149 | /// but will effectively disable noise detection. |
| 129 | #[cfg(not(usart_v1))] | 150 | #[cfg(not(usart_v1))] |
| 130 | pub assume_noise_free: bool, | 151 | pub assume_noise_free: bool, |
| @@ -132,6 +153,14 @@ pub struct Config { | |||
| 132 | /// Set this to true to swap the RX and TX pins. | 153 | /// Set this to true to swap the RX and TX pins. |
| 133 | #[cfg(any(usart_v3, usart_v4))] | 154 | #[cfg(any(usart_v3, usart_v4))] |
| 134 | pub swap_rx_tx: bool, | 155 | pub swap_rx_tx: bool, |
| 156 | |||
| 157 | /// Set this to true to invert TX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle). | ||
| 158 | #[cfg(any(usart_v3, usart_v4))] | ||
| 159 | pub invert_tx: bool, | ||
| 160 | |||
| 161 | /// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle). | ||
| 162 | #[cfg(any(usart_v3, usart_v4))] | ||
| 163 | pub invert_rx: bool, | ||
| 135 | } | 164 | } |
| 136 | 165 | ||
| 137 | impl Default for Config { | 166 | impl Default for Config { |
| @@ -147,6 +176,10 @@ impl Default for Config { | |||
| 147 | assume_noise_free: false, | 176 | assume_noise_free: false, |
| 148 | #[cfg(any(usart_v3, usart_v4))] | 177 | #[cfg(any(usart_v3, usart_v4))] |
| 149 | swap_rx_tx: false, | 178 | swap_rx_tx: false, |
| 179 | #[cfg(any(usart_v3, usart_v4))] | ||
| 180 | invert_tx: false, | ||
| 181 | #[cfg(any(usart_v3, usart_v4))] | ||
| 182 | invert_rx: false, | ||
| 150 | } | 183 | } |
| 151 | } | 184 | } |
| 152 | } | 185 | } |
| @@ -175,6 +208,7 @@ enum ReadCompletionEvent { | |||
| 175 | Idle(usize), | 208 | Idle(usize), |
| 176 | } | 209 | } |
| 177 | 210 | ||
| 211 | /// Bidirectional UART Driver | ||
| 178 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { | 212 | pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { |
| 179 | tx: UartTx<'d, T, TxDma>, | 213 | tx: UartTx<'d, T, TxDma>, |
| 180 | rx: UartRx<'d, T, RxDma>, | 214 | rx: UartRx<'d, T, RxDma>, |
| @@ -190,6 +224,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> | |||
| 190 | } | 224 | } |
| 191 | } | 225 | } |
| 192 | 226 | ||
| 227 | /// Tx-only UART Driver | ||
| 193 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { | 228 | pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { |
| 194 | phantom: PhantomData<&'d mut T>, | 229 | phantom: PhantomData<&'d mut T>, |
| 195 | tx_dma: PeripheralRef<'d, TxDma>, | 230 | tx_dma: PeripheralRef<'d, TxDma>, |
| @@ -204,6 +239,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { | |||
| 204 | } | 239 | } |
| 205 | } | 240 | } |
| 206 | 241 | ||
| 242 | /// Rx-only UART Driver | ||
| 207 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { | 243 | pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { |
| 208 | _peri: PeripheralRef<'d, T>, | 244 | _peri: PeripheralRef<'d, T>, |
| 209 | rx_dma: PeripheralRef<'d, RxDma>, | 245 | rx_dma: PeripheralRef<'d, RxDma>, |
| @@ -234,6 +270,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 234 | Self::new_inner(peri, tx, tx_dma, config) | 270 | Self::new_inner(peri, tx, tx_dma, config) |
| 235 | } | 271 | } |
| 236 | 272 | ||
| 273 | /// Create a new tx-only UART with a clear-to-send pin | ||
| 237 | pub fn new_with_cts( | 274 | pub fn new_with_cts( |
| 238 | peri: impl Peripheral<P = T> + 'd, | 275 | peri: impl Peripheral<P = T> + 'd, |
| 239 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, | 276 | tx: impl Peripheral<P = impl TxPin<T>> + 'd, |
| @@ -275,10 +312,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 275 | }) | 312 | }) |
| 276 | } | 313 | } |
| 277 | 314 | ||
| 315 | /// Reconfigure the driver | ||
| 278 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 316 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 279 | reconfigure::<T>(config) | 317 | reconfigure::<T>(config) |
| 280 | } | 318 | } |
| 281 | 319 | ||
| 320 | /// Initiate an asynchronous UART write | ||
| 282 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> | 321 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> |
| 283 | where | 322 | where |
| 284 | TxDma: crate::usart::TxDma<T>, | 323 | TxDma: crate::usart::TxDma<T>, |
| @@ -295,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 295 | Ok(()) | 334 | Ok(()) |
| 296 | } | 335 | } |
| 297 | 336 | ||
| 337 | /// Perform a blocking UART write | ||
| 298 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 338 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 299 | let r = T::regs(); | 339 | let r = T::regs(); |
| 300 | for &b in buffer { | 340 | for &b in buffer { |
| @@ -304,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { | |||
| 304 | Ok(()) | 344 | Ok(()) |
| 305 | } | 345 | } |
| 306 | 346 | ||
| 347 | /// Block until transmission complete | ||
| 307 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 348 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 308 | let r = T::regs(); | 349 | let r = T::regs(); |
| 309 | while !sr(r).read().tc() {} | 350 | while !sr(r).read().tc() {} |
| @@ -325,6 +366,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 325 | Self::new_inner(peri, rx, rx_dma, config) | 366 | Self::new_inner(peri, rx, rx_dma, config) |
| 326 | } | 367 | } |
| 327 | 368 | ||
| 369 | /// Create a new rx-only UART with a request-to-send pin | ||
| 328 | pub fn new_with_rts( | 370 | pub fn new_with_rts( |
| 329 | peri: impl Peripheral<P = T> + 'd, | 371 | peri: impl Peripheral<P = T> + 'd, |
| 330 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 372 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -374,6 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 374 | }) | 416 | }) |
| 375 | } | 417 | } |
| 376 | 418 | ||
| 419 | /// Reconfigure the driver | ||
| 377 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 420 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 378 | reconfigure::<T>(config) | 421 | reconfigure::<T>(config) |
| 379 | } | 422 | } |
| @@ -431,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 431 | Ok(sr.rxne()) | 474 | Ok(sr.rxne()) |
| 432 | } | 475 | } |
| 433 | 476 | ||
| 477 | /// Initiate an asynchronous UART read | ||
| 434 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> | 478 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> |
| 435 | where | 479 | where |
| 436 | RxDma: crate::usart::RxDma<T>, | 480 | RxDma: crate::usart::RxDma<T>, |
| @@ -440,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 440 | Ok(()) | 484 | Ok(()) |
| 441 | } | 485 | } |
| 442 | 486 | ||
| 487 | /// Read a single u8 if there is one available, otherwise return WouldBlock | ||
| 443 | pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { | 488 | pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { |
| 444 | let r = T::regs(); | 489 | let r = T::regs(); |
| 445 | if self.check_rx_flags()? { | 490 | if self.check_rx_flags()? { |
| @@ -449,6 +494,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 449 | } | 494 | } |
| 450 | } | 495 | } |
| 451 | 496 | ||
| 497 | /// Perform a blocking read into `buffer` | ||
| 452 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 498 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 453 | let r = T::regs(); | 499 | let r = T::regs(); |
| 454 | for b in buffer { | 500 | for b in buffer { |
| @@ -458,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { | |||
| 458 | Ok(()) | 504 | Ok(()) |
| 459 | } | 505 | } |
| 460 | 506 | ||
| 507 | /// Initiate an asynchronous read with idle line detection enabled | ||
| 461 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | 508 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> |
| 462 | where | 509 | where |
| 463 | RxDma: crate::usart::RxDma<T>, | 510 | RxDma: crate::usart::RxDma<T>, |
| @@ -682,6 +729,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { | |||
| 682 | } | 729 | } |
| 683 | 730 | ||
| 684 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | 731 | impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { |
| 732 | /// Create a new bidirectional UART | ||
| 685 | pub fn new( | 733 | pub fn new( |
| 686 | peri: impl Peripheral<P = T> + 'd, | 734 | peri: impl Peripheral<P = T> + 'd, |
| 687 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 735 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| @@ -698,6 +746,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 698 | Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) | 746 | Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) |
| 699 | } | 747 | } |
| 700 | 748 | ||
| 749 | /// Create a new bidirectional UART with request-to-send and clear-to-send pins | ||
| 701 | pub fn new_with_rtscts( | 750 | pub fn new_with_rtscts( |
| 702 | peri: impl Peripheral<P = T> + 'd, | 751 | peri: impl Peripheral<P = T> + 'd, |
| 703 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 752 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| @@ -725,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 725 | } | 774 | } |
| 726 | 775 | ||
| 727 | #[cfg(not(any(usart_v1, usart_v2)))] | 776 | #[cfg(not(any(usart_v1, usart_v2)))] |
| 777 | /// Create a new bidirectional UART with a driver-enable pin | ||
| 728 | pub fn new_with_de( | 778 | pub fn new_with_de( |
| 729 | peri: impl Peripheral<P = T> + 'd, | 779 | peri: impl Peripheral<P = T> + 'd, |
| 730 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, | 780 | rx: impl Peripheral<P = impl RxPin<T>> + 'd, |
| @@ -800,6 +850,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 800 | }) | 850 | }) |
| 801 | } | 851 | } |
| 802 | 852 | ||
| 853 | /// Initiate an asynchronous write | ||
| 803 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> | 854 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> |
| 804 | where | 855 | where |
| 805 | TxDma: crate::usart::TxDma<T>, | 856 | TxDma: crate::usart::TxDma<T>, |
| @@ -807,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 807 | self.tx.write(buffer).await | 858 | self.tx.write(buffer).await |
| 808 | } | 859 | } |
| 809 | 860 | ||
| 861 | /// Perform a blocking write | ||
| 810 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 862 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 811 | self.tx.blocking_write(buffer) | 863 | self.tx.blocking_write(buffer) |
| 812 | } | 864 | } |
| 813 | 865 | ||
| 866 | /// Block until transmission complete | ||
| 814 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 867 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 815 | self.tx.blocking_flush() | 868 | self.tx.blocking_flush() |
| 816 | } | 869 | } |
| 817 | 870 | ||
| 871 | /// Initiate an asynchronous read into `buffer` | ||
| 818 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> | 872 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> |
| 819 | where | 873 | where |
| 820 | RxDma: crate::usart::RxDma<T>, | 874 | RxDma: crate::usart::RxDma<T>, |
| @@ -822,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { | |||
| 822 | self.rx.read(buffer).await | 876 | self.rx.read(buffer).await |
| 823 | } | 877 | } |
| 824 | 878 | ||
| 879 | /// Read a single `u8` or return `WouldBlock` | ||
| 825 | pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { | 880 | pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { |
| 826 | self.rx.nb_read() | 881 | self.rx.nb_read() |
| 827 | } | 882 | } |
| 828 | 883 | ||
| 884 | /// Perform a blocking read into `buffer` | ||
| 829 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 885 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 830 | self.rx.blocking_read(buffer) | 886 | self.rx.blocking_read(buffer) |
| 831 | } | 887 | } |
| 832 | 888 | ||
| 889 | /// Initiate an an asynchronous read with idle line detection enabled | ||
| 833 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> | 890 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> |
| 834 | where | 891 | where |
| 835 | RxDma: crate::usart::RxDma<T>, | 892 | RxDma: crate::usart::RxDma<T>, |
| @@ -972,7 +1029,11 @@ fn configure( | |||
| 972 | }); | 1029 | }); |
| 973 | 1030 | ||
| 974 | #[cfg(any(usart_v3, usart_v4))] | 1031 | #[cfg(any(usart_v3, usart_v4))] |
| 975 | w.set_swap(config.swap_rx_tx); | 1032 | { |
| 1033 | w.set_txinv(config.invert_tx); | ||
| 1034 | w.set_rxinv(config.invert_rx); | ||
| 1035 | w.set_swap(config.swap_rx_tx); | ||
| 1036 | } | ||
| 976 | }); | 1037 | }); |
| 977 | 1038 | ||
| 978 | #[cfg(not(usart_v1))] | 1039 | #[cfg(not(usart_v1))] |
| @@ -1275,8 +1336,10 @@ pub(crate) mod sealed { | |||
| 1275 | } | 1336 | } |
| 1276 | } | 1337 | } |
| 1277 | 1338 | ||
| 1339 | /// Basic UART driver instance | ||
| 1278 | pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} | 1340 | pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} |
| 1279 | 1341 | ||
| 1342 | /// Full UART driver instance | ||
| 1280 | pub trait FullInstance: sealed::FullInstance {} | 1343 | pub trait FullInstance: sealed::FullInstance {} |
| 1281 | 1344 | ||
| 1282 | pin_trait!(RxPin, BasicInstance); | 1345 | pin_trait!(RxPin, BasicInstance); |
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b8d17e4e4..4391bfef7 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs | |||
| @@ -11,6 +11,7 @@ use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, | |||
| 11 | use crate::dma::ReadableRingBuffer; | 11 | use crate::dma::ReadableRingBuffer; |
| 12 | use crate::usart::{Regs, Sr}; | 12 | use crate::usart::{Regs, Sr}; |
| 13 | 13 | ||
| 14 | /// Rx-only Ring-buffered UART Driver | ||
| 14 | pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { | 15 | pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { |
| 15 | _peri: PeripheralRef<'d, T>, | 16 | _peri: PeripheralRef<'d, T>, |
| 16 | ring_buf: ReadableRingBuffer<'d, RxDma, u8>, | 17 | ring_buf: ReadableRingBuffer<'d, RxDma, u8>, |
| @@ -27,8 +28,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUar | |||
| 27 | 28 | ||
| 28 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { | 29 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { |
| 29 | /// Turn the `UartRx` into a buffered uart which can continously receive in the background | 30 | /// Turn the `UartRx` into a buffered uart which can continously receive in the background |
| 30 | /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the | 31 | /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the |
| 31 | /// DMA controller, and must be sufficiently large, such that it will not overflow. | 32 | /// DMA controller, and must be large enough to prevent overflows. |
| 32 | pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { | 33 | pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { |
| 33 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | 34 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); |
| 34 | 35 | ||
| @@ -39,7 +40,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { | |||
| 39 | let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; | 40 | let rx_dma = unsafe { self.rx_dma.clone_unchecked() }; |
| 40 | let _peri = unsafe { self._peri.clone_unchecked() }; | 41 | let _peri = unsafe { self._peri.clone_unchecked() }; |
| 41 | 42 | ||
| 42 | let ring_buf = unsafe { ReadableRingBuffer::new_read(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; | 43 | let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) }; |
| 43 | 44 | ||
| 44 | // Don't disable the clock | 45 | // Don't disable the clock |
| 45 | mem::forget(self); | 46 | mem::forget(self); |
| @@ -49,6 +50,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { | |||
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> { | 52 | impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> { |
| 53 | /// Clear the ring buffer and start receiving in the background | ||
| 52 | pub fn start(&mut self) -> Result<(), Error> { | 54 | pub fn start(&mut self) -> Result<(), Error> { |
| 53 | // Clear the ring buffer so that it is ready to receive data | 55 | // Clear the ring buffer so that it is ready to receive data |
| 54 | self.ring_buf.clear(); | 56 | self.ring_buf.clear(); |
| @@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD | |||
| 64 | Err(err) | 66 | Err(err) |
| 65 | } | 67 | } |
| 66 | 68 | ||
| 69 | /// Cleanly stop and reconfigure the driver | ||
| 67 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { | 70 | pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { |
| 68 | self.teardown_uart(); | 71 | self.teardown_uart(); |
| 69 | reconfigure::<T>(config) | 72 | reconfigure::<T>(config) |
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index d0b289462..4debd4e54 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Universal Serial Bus (USB) | ||
| 2 | |||
| 1 | use crate::interrupt; | 3 | use crate::interrupt; |
| 2 | use crate::rcc::RccPeripheral; | 4 | use crate::rcc::RccPeripheral; |
| 3 | 5 | ||
| @@ -10,7 +12,9 @@ pub(crate) mod sealed { | |||
| 10 | } | 12 | } |
| 11 | } | 13 | } |
| 12 | 14 | ||
| 15 | /// USB instance trait. | ||
| 13 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 16 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { |
| 17 | /// Interrupt for this USB instance. | ||
| 14 | type Interrupt: interrupt::typelevel::Interrupt; | 18 | type Interrupt: interrupt::typelevel::Interrupt; |
| 15 | } | 19 | } |
| 16 | 20 | ||
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 295dc9198..04b1b35e8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs | |||
| @@ -244,6 +244,7 @@ struct EndpointData { | |||
| 244 | used_out: bool, | 244 | used_out: bool, |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | /// USB driver. | ||
| 247 | pub struct Driver<'d, T: Instance> { | 248 | pub struct Driver<'d, T: Instance> { |
| 248 | phantom: PhantomData<&'d mut T>, | 249 | phantom: PhantomData<&'d mut T>, |
| 249 | alloc: [EndpointData; EP_COUNT], | 250 | alloc: [EndpointData; EP_COUNT], |
| @@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> { | |||
| 251 | } | 252 | } |
| 252 | 253 | ||
| 253 | impl<'d, T: Instance> Driver<'d, T> { | 254 | impl<'d, T: Instance> Driver<'d, T> { |
| 255 | /// Create a new USB driver. | ||
| 254 | pub fn new( | 256 | pub fn new( |
| 255 | _usb: impl Peripheral<P = T> + 'd, | 257 | _usb: impl Peripheral<P = T> + 'd, |
| 256 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 258 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| @@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> { | |||
| 465 | } | 467 | } |
| 466 | } | 468 | } |
| 467 | 469 | ||
| 470 | /// USB bus. | ||
| 468 | pub struct Bus<'d, T: Instance> { | 471 | pub struct Bus<'d, T: Instance> { |
| 469 | phantom: PhantomData<&'d mut T>, | 472 | phantom: PhantomData<&'d mut T>, |
| 470 | ep_types: [EpType; EP_COUNT - 1], | 473 | ep_types: [EpType; EP_COUNT - 1], |
| @@ -640,6 +643,7 @@ trait Dir { | |||
| 640 | fn waker(i: usize) -> &'static AtomicWaker; | 643 | fn waker(i: usize) -> &'static AtomicWaker; |
| 641 | } | 644 | } |
| 642 | 645 | ||
| 646 | /// Marker type for the "IN" direction. | ||
| 643 | pub enum In {} | 647 | pub enum In {} |
| 644 | impl Dir for In { | 648 | impl Dir for In { |
| 645 | fn dir() -> Direction { | 649 | fn dir() -> Direction { |
| @@ -652,6 +656,7 @@ impl Dir for In { | |||
| 652 | } | 656 | } |
| 653 | } | 657 | } |
| 654 | 658 | ||
| 659 | /// Marker type for the "OUT" direction. | ||
| 655 | pub enum Out {} | 660 | pub enum Out {} |
| 656 | impl Dir for Out { | 661 | impl Dir for Out { |
| 657 | fn dir() -> Direction { | 662 | fn dir() -> Direction { |
| @@ -664,6 +669,7 @@ impl Dir for Out { | |||
| 664 | } | 669 | } |
| 665 | } | 670 | } |
| 666 | 671 | ||
| 672 | /// USB endpoint. | ||
| 667 | pub struct Endpoint<'d, T: Instance, D> { | 673 | pub struct Endpoint<'d, T: Instance, D> { |
| 668 | _phantom: PhantomData<(&'d mut T, D)>, | 674 | _phantom: PhantomData<(&'d mut T, D)>, |
| 669 | info: EndpointInfo, | 675 | info: EndpointInfo, |
| @@ -695,10 +701,10 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | |||
| 695 | } | 701 | } |
| 696 | 702 | ||
| 697 | async fn wait_enabled(&mut self) { | 703 | async fn wait_enabled(&mut self) { |
| 698 | trace!("wait_enabled OUT WAITING"); | 704 | trace!("wait_enabled IN WAITING"); |
| 699 | let index = self.info.addr.index(); | 705 | let index = self.info.addr.index(); |
| 700 | poll_fn(|cx| { | 706 | poll_fn(|cx| { |
| 701 | EP_OUT_WAKERS[index].register(cx.waker()); | 707 | EP_IN_WAKERS[index].register(cx.waker()); |
| 702 | let regs = T::regs(); | 708 | let regs = T::regs(); |
| 703 | if regs.epr(index).read().stat_tx() == Stat::DISABLED { | 709 | if regs.epr(index).read().stat_tx() == Stat::DISABLED { |
| 704 | Poll::Pending | 710 | Poll::Pending |
| @@ -707,7 +713,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { | |||
| 707 | } | 713 | } |
| 708 | }) | 714 | }) |
| 709 | .await; | 715 | .await; |
| 710 | trace!("wait_enabled OUT OK"); | 716 | trace!("wait_enabled IN OK"); |
| 711 | } | 717 | } |
| 712 | } | 718 | } |
| 713 | 719 | ||
| @@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 813 | } | 819 | } |
| 814 | } | 820 | } |
| 815 | 821 | ||
| 822 | /// USB control pipe. | ||
| 816 | pub struct ControlPipe<'d, T: Instance> { | 823 | pub struct ControlPipe<'d, T: Instance> { |
| 817 | _phantom: PhantomData<&'d mut T>, | 824 | _phantom: PhantomData<&'d mut T>, |
| 818 | max_packet_size: u16, | 825 | max_packet_size: u16, |
diff --git a/embassy-stm32/src/usb_otg/mod.rs b/embassy-stm32/src/usb_otg/mod.rs index be54a3d10..0649e684b 100644 --- a/embassy-stm32/src/usb_otg/mod.rs +++ b/embassy-stm32/src/usb_otg/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! USB On The Go (OTG) | ||
| 2 | |||
| 1 | use crate::rcc::RccPeripheral; | 3 | use crate::rcc::RccPeripheral; |
| 2 | use crate::{interrupt, peripherals}; | 4 | use crate::{interrupt, peripherals}; |
| 3 | 5 | ||
| @@ -18,7 +20,9 @@ pub(crate) mod sealed { | |||
| 18 | } | 20 | } |
| 19 | } | 21 | } |
| 20 | 22 | ||
| 23 | /// USB OTG instance. | ||
| 21 | pub trait Instance: sealed::Instance + RccPeripheral { | 24 | pub trait Instance: sealed::Instance + RccPeripheral { |
| 25 | /// Interrupt for this USB OTG instance. | ||
| 22 | type Interrupt: interrupt::typelevel::Interrupt; | 26 | type Interrupt: interrupt::typelevel::Interrupt; |
| 23 | } | 27 | } |
| 24 | 28 | ||
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index ba77bfb16..190fb274f 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs | |||
| @@ -204,6 +204,7 @@ pub enum PhyType { | |||
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | impl PhyType { | 206 | impl PhyType { |
| 207 | /// Get whether this PHY is any of the internal types. | ||
| 207 | pub fn internal(&self) -> bool { | 208 | pub fn internal(&self) -> bool { |
| 208 | match self { | 209 | match self { |
| 209 | PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, | 210 | PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, |
| @@ -211,6 +212,7 @@ impl PhyType { | |||
| 211 | } | 212 | } |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 215 | /// Get whether this PHY is any of the high-speed types. | ||
| 214 | pub fn high_speed(&self) -> bool { | 216 | pub fn high_speed(&self) -> bool { |
| 215 | match self { | 217 | match self { |
| 216 | PhyType::InternalFullSpeed => false, | 218 | PhyType::InternalFullSpeed => false, |
| @@ -218,7 +220,7 @@ impl PhyType { | |||
| 218 | } | 220 | } |
| 219 | } | 221 | } |
| 220 | 222 | ||
| 221 | pub fn to_dspd(&self) -> vals::Dspd { | 223 | fn to_dspd(&self) -> vals::Dspd { |
| 222 | match self { | 224 | match self { |
| 223 | PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, | 225 | PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, |
| 224 | PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, | 226 | PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, |
| @@ -230,6 +232,7 @@ impl PhyType { | |||
| 230 | /// Indicates that [State::ep_out_buffers] is empty. | 232 | /// Indicates that [State::ep_out_buffers] is empty. |
| 231 | const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; | 233 | const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; |
| 232 | 234 | ||
| 235 | /// USB OTG driver state. | ||
| 233 | pub struct State<const EP_COUNT: usize> { | 236 | pub struct State<const EP_COUNT: usize> { |
| 234 | /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. | 237 | /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. |
| 235 | ep0_setup_data: UnsafeCell<[u8; 8]>, | 238 | ep0_setup_data: UnsafeCell<[u8; 8]>, |
| @@ -247,6 +250,7 @@ unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {} | |||
| 247 | unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} | 250 | unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} |
| 248 | 251 | ||
| 249 | impl<const EP_COUNT: usize> State<EP_COUNT> { | 252 | impl<const EP_COUNT: usize> State<EP_COUNT> { |
| 253 | /// Create a new State. | ||
| 250 | pub const fn new() -> Self { | 254 | pub const fn new() -> Self { |
| 251 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 255 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 252 | const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); | 256 | const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); |
| @@ -271,6 +275,7 @@ struct EndpointData { | |||
| 271 | fifo_size_words: u16, | 275 | fifo_size_words: u16, |
| 272 | } | 276 | } |
| 273 | 277 | ||
| 278 | /// USB driver config. | ||
| 274 | #[non_exhaustive] | 279 | #[non_exhaustive] |
| 275 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 280 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 276 | pub struct Config { | 281 | pub struct Config { |
| @@ -297,6 +302,7 @@ impl Default for Config { | |||
| 297 | } | 302 | } |
| 298 | } | 303 | } |
| 299 | 304 | ||
| 305 | /// USB driver. | ||
| 300 | pub struct Driver<'d, T: Instance> { | 306 | pub struct Driver<'d, T: Instance> { |
| 301 | config: Config, | 307 | config: Config, |
| 302 | phantom: PhantomData<&'d mut T>, | 308 | phantom: PhantomData<&'d mut T>, |
| @@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { | |||
| 527 | } | 533 | } |
| 528 | } | 534 | } |
| 529 | 535 | ||
| 536 | /// USB bus. | ||
| 530 | pub struct Bus<'d, T: Instance> { | 537 | pub struct Bus<'d, T: Instance> { |
| 531 | config: Config, | 538 | config: Config, |
| 532 | phantom: PhantomData<&'d mut T>, | 539 | phantom: PhantomData<&'d mut T>, |
| @@ -1092,6 +1099,7 @@ trait Dir { | |||
| 1092 | fn dir() -> Direction; | 1099 | fn dir() -> Direction; |
| 1093 | } | 1100 | } |
| 1094 | 1101 | ||
| 1102 | /// Marker type for the "IN" direction. | ||
| 1095 | pub enum In {} | 1103 | pub enum In {} |
| 1096 | impl Dir for In { | 1104 | impl Dir for In { |
| 1097 | fn dir() -> Direction { | 1105 | fn dir() -> Direction { |
| @@ -1099,6 +1107,7 @@ impl Dir for In { | |||
| 1099 | } | 1107 | } |
| 1100 | } | 1108 | } |
| 1101 | 1109 | ||
| 1110 | /// Marker type for the "OUT" direction. | ||
| 1102 | pub enum Out {} | 1111 | pub enum Out {} |
| 1103 | impl Dir for Out { | 1112 | impl Dir for Out { |
| 1104 | fn dir() -> Direction { | 1113 | fn dir() -> Direction { |
| @@ -1106,6 +1115,7 @@ impl Dir for Out { | |||
| 1106 | } | 1115 | } |
| 1107 | } | 1116 | } |
| 1108 | 1117 | ||
| 1118 | /// USB endpoint. | ||
| 1109 | pub struct Endpoint<'d, T: Instance, D> { | 1119 | pub struct Endpoint<'d, T: Instance, D> { |
| 1110 | _phantom: PhantomData<(&'d mut T, D)>, | 1120 | _phantom: PhantomData<(&'d mut T, D)>, |
| 1111 | info: EndpointInfo, | 1121 | info: EndpointInfo, |
| @@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1299 | } | 1309 | } |
| 1300 | } | 1310 | } |
| 1301 | 1311 | ||
| 1312 | /// USB control pipe. | ||
| 1302 | pub struct ControlPipe<'d, T: Instance> { | 1313 | pub struct ControlPipe<'d, T: Instance> { |
| 1303 | _phantom: PhantomData<&'d mut T>, | 1314 | _phantom: PhantomData<&'d mut T>, |
| 1304 | max_packet_size: u16, | 1315 | max_packet_size: u16, |
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index c7c2694e0..dc701ef64 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | //! Watchdog Timer (IWDG, WWDG) | ||
| 1 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 2 | 3 | ||
| 3 | use embassy_hal_internal::{into_ref, Peripheral}; | 4 | use embassy_hal_internal::{into_ref, Peripheral}; |
| @@ -5,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr}; | |||
| 5 | 6 | ||
| 6 | use crate::rcc::LSI_FREQ; | 7 | use crate::rcc::LSI_FREQ; |
| 7 | 8 | ||
| 9 | /// Independent watchdog (IWDG) driver. | ||
| 8 | pub struct IndependentWatchdog<'d, T: Instance> { | 10 | pub struct IndependentWatchdog<'d, T: Instance> { |
| 9 | wdg: PhantomData<&'d mut T>, | 11 | wdg: PhantomData<&'d mut T>, |
| 10 | } | 12 | } |
| @@ -63,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { | |||
| 63 | IndependentWatchdog { wdg: PhantomData } | 65 | IndependentWatchdog { wdg: PhantomData } |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 68 | /// Unleash (start) the watchdog. | ||
| 66 | pub fn unleash(&mut self) { | 69 | pub fn unleash(&mut self) { |
| 67 | T::regs().kr().write(|w| w.set_key(Key::START)); | 70 | T::regs().kr().write(|w| w.set_key(Key::START)); |
| 68 | } | 71 | } |
| 69 | 72 | ||
| 73 | /// Pet (reload, refresh) the watchdog. | ||
| 70 | pub fn pet(&mut self) { | 74 | pub fn pet(&mut self) { |
| 71 | T::regs().kr().write(|w| w.set_key(Key::RESET)); | 75 | T::regs().kr().write(|w| w.set_key(Key::RESET)); |
| 72 | } | 76 | } |
| @@ -78,6 +82,7 @@ mod sealed { | |||
| 78 | } | 82 | } |
| 79 | } | 83 | } |
| 80 | 84 | ||
| 85 | /// IWDG instance trait. | ||
| 81 | pub trait Instance: sealed::Instance {} | 86 | pub trait Instance: sealed::Instance {} |
| 82 | 87 | ||
| 83 | foreach_peripheral!( | 88 | foreach_peripheral!( |
