diff options
| author | xoviat <[email protected]> | 2025-11-13 17:41:44 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-13 17:41:44 -0600 |
| commit | cc1aad2cc4d2f87a177495e8352dd312c1ac331c (patch) | |
| tree | 8bca5d0816882f151a87b88121e15c9e4f11f36a /embassy-stm32/src | |
| parent | 4fb60b5991c4c98427ef23e6c011210341ba09e1 (diff) | |
| parent | 578679771eafe93ccc0e8de8fc3f97a5b991b02c (diff) | |
Merge branch 'main' of https://github.com/embassy-rs/embassy into adc
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/adc/adc4.rs | 83 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/c0.rs | 507 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f1.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/f3.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 82 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 101 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 51 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v4.rs | 102 | ||||
| -rw-r--r-- | embassy-stm32/src/dsihost.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/generic_phy.rs | 14 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/c.rs | 131 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/common.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/g.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/flash/mod.rs | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 704 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 14 | ||||
| -rw-r--r-- | embassy-stm32/src/opamp.rs | 13 |
18 files changed, 1107 insertions, 752 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 52678d1b6..babdebfdb 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs | |||
| @@ -76,71 +76,17 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { | |||
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 79 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 80 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 80 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 81 | #[allow(unused)] | 81 | match raw_prescaler { |
| 82 | enum Prescaler { | 82 | 0 => Presc::DIV1, |
| 83 | NotDivided, | 83 | 1 => Presc::DIV2, |
| 84 | DividedBy2, | 84 | 2..=3 => Presc::DIV4, |
| 85 | DividedBy4, | 85 | 4..=5 => Presc::DIV6, |
| 86 | DividedBy6, | 86 | 6..=7 => Presc::DIV8, |
| 87 | DividedBy8, | 87 | 8..=9 => Presc::DIV10, |
| 88 | DividedBy10, | 88 | 10..=11 => Presc::DIV12, |
| 89 | DividedBy12, | 89 | _ => unimplemented!(), |
| 90 | DividedBy16, | ||
| 91 | DividedBy32, | ||
| 92 | DividedBy64, | ||
| 93 | DividedBy128, | ||
| 94 | DividedBy256, | ||
| 95 | } | ||
| 96 | |||
| 97 | impl Prescaler { | ||
| 98 | fn from_ker_ck(frequency: Hertz) -> Self { | ||
| 99 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | ||
| 100 | match raw_prescaler { | ||
| 101 | 0 => Self::NotDivided, | ||
| 102 | 1 => Self::DividedBy2, | ||
| 103 | 2..=3 => Self::DividedBy4, | ||
| 104 | 4..=5 => Self::DividedBy6, | ||
| 105 | 6..=7 => Self::DividedBy8, | ||
| 106 | 8..=9 => Self::DividedBy10, | ||
| 107 | 10..=11 => Self::DividedBy12, | ||
| 108 | _ => unimplemented!(), | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | fn divisor(&self) -> u32 { | ||
| 113 | match self { | ||
| 114 | Prescaler::NotDivided => 1, | ||
| 115 | Prescaler::DividedBy2 => 2, | ||
| 116 | Prescaler::DividedBy4 => 4, | ||
| 117 | Prescaler::DividedBy6 => 6, | ||
| 118 | Prescaler::DividedBy8 => 8, | ||
| 119 | Prescaler::DividedBy10 => 10, | ||
| 120 | Prescaler::DividedBy12 => 12, | ||
| 121 | Prescaler::DividedBy16 => 16, | ||
| 122 | Prescaler::DividedBy32 => 32, | ||
| 123 | Prescaler::DividedBy64 => 64, | ||
| 124 | Prescaler::DividedBy128 => 128, | ||
| 125 | Prescaler::DividedBy256 => 256, | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | fn presc(&self) -> Presc { | ||
| 130 | match self { | ||
| 131 | Prescaler::NotDivided => Presc::DIV1, | ||
| 132 | Prescaler::DividedBy2 => Presc::DIV2, | ||
| 133 | Prescaler::DividedBy4 => Presc::DIV4, | ||
| 134 | Prescaler::DividedBy6 => Presc::DIV6, | ||
| 135 | Prescaler::DividedBy8 => Presc::DIV8, | ||
| 136 | Prescaler::DividedBy10 => Presc::DIV10, | ||
| 137 | Prescaler::DividedBy12 => Presc::DIV12, | ||
| 138 | Prescaler::DividedBy16 => Presc::DIV16, | ||
| 139 | Prescaler::DividedBy32 => Presc::DIV32, | ||
| 140 | Prescaler::DividedBy64 => Presc::DIV64, | ||
| 141 | Prescaler::DividedBy128 => Presc::DIV128, | ||
| 142 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 143 | } | ||
| 144 | } | 90 | } |
| 145 | } | 91 | } |
| 146 | 92 | ||
| @@ -212,6 +158,7 @@ foreach_adc!( | |||
| 212 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | 158 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) |
| 213 | }); | 159 | }); |
| 214 | } | 160 | } |
| 161 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 215 | _ => unreachable!(), | 162 | _ => unreachable!(), |
| 216 | } | 163 | } |
| 217 | } | 164 | } |
| @@ -283,11 +230,11 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { | |||
| 283 | /// Create a new ADC driver. | 230 | /// Create a new ADC driver. |
| 284 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { | 231 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { |
| 285 | rcc::enable_and_reset::<T>(); | 232 | rcc::enable_and_reset::<T>(); |
| 286 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 233 | let prescaler = from_ker_ck(T::frequency()); |
| 287 | 234 | ||
| 288 | T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 235 | T::regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 289 | 236 | ||
| 290 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 237 | let frequency = T::frequency() / prescaler; |
| 291 | info!("ADC4 frequency set to {}", frequency); | 238 | info!("ADC4 frequency set to {}", frequency); |
| 292 | 239 | ||
| 293 | if frequency > MAX_ADC_CLK_FREQ { | 240 | if frequency > MAX_ADC_CLK_FREQ { |
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index bc97a7c4b..3bdca7edb 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs | |||
| @@ -1,12 +1,10 @@ | |||
| 1 | use pac::adc::vals::Scandir; | ||
| 2 | #[allow(unused)] | 1 | #[allow(unused)] |
| 3 | use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; | 2 | use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; |
| 4 | use pac::adccommon::vals::Presc; | 3 | use pac::adccommon::vals::Presc; |
| 4 | use stm32_metapac::adc::vals::Scandir; | ||
| 5 | 5 | ||
| 6 | use super::{ | 6 | use super::{Adc, Instance, Resolution, blocking_delay_us}; |
| 7 | Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, | 7 | use crate::adc::{AnyInstance, ConversionMode}; |
| 8 | }; | ||
| 9 | use crate::dma::Transfer; | ||
| 10 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 11 | use crate::{Peri, pac, rcc}; | 9 | use crate::{Peri, pac, rcc}; |
| 12 | 10 | ||
| @@ -32,123 +30,184 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { | |||
| 32 | const CHANNEL: u8 = 9; | 30 | const CHANNEL: u8 = 9; |
| 33 | } | 31 | } |
| 34 | 32 | ||
| 35 | #[derive(Copy, Clone, Debug)] | 33 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 36 | pub enum Prescaler { | 34 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 37 | NotDivided, | 35 | match raw_prescaler { |
| 38 | DividedBy2, | 36 | 0 => Presc::DIV1, |
| 39 | DividedBy4, | 37 | 1 => Presc::DIV2, |
| 40 | DividedBy6, | 38 | 2..=3 => Presc::DIV4, |
| 41 | DividedBy8, | 39 | 4..=5 => Presc::DIV6, |
| 42 | DividedBy10, | 40 | 6..=7 => Presc::DIV8, |
| 43 | DividedBy12, | 41 | 8..=9 => Presc::DIV10, |
| 44 | DividedBy16, | 42 | 10..=11 => Presc::DIV12, |
| 45 | DividedBy32, | 43 | _ => unimplemented!(), |
| 46 | DividedBy64, | 44 | } |
| 47 | DividedBy128, | ||
| 48 | DividedBy256, | ||
| 49 | } | 45 | } |
| 50 | 46 | ||
| 51 | impl Prescaler { | 47 | impl<T: Instance> super::SealedAnyInstance for T { |
| 52 | fn from_ker_ck(frequency: Hertz) -> Self { | 48 | fn dr() -> *mut u16 { |
| 53 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 49 | T::regs().dr().as_ptr() as *mut u16 |
| 54 | match raw_prescaler { | ||
| 55 | 0 => Self::NotDivided, | ||
| 56 | 1 => Self::DividedBy2, | ||
| 57 | 2..=3 => Self::DividedBy4, | ||
| 58 | 4..=5 => Self::DividedBy6, | ||
| 59 | 6..=7 => Self::DividedBy8, | ||
| 60 | 8..=9 => Self::DividedBy10, | ||
| 61 | 10..=11 => Self::DividedBy12, | ||
| 62 | _ => unimplemented!(), | ||
| 63 | } | ||
| 64 | } | 50 | } |
| 65 | 51 | ||
| 66 | #[allow(unused)] | 52 | fn enable() { |
| 67 | fn divisor(&self) -> u32 { | 53 | T::regs().isr().modify(|w| w.set_adrdy(true)); |
| 68 | match self { | 54 | T::regs().cr().modify(|w| w.set_aden(true)); |
| 69 | Prescaler::NotDivided => 1, | 55 | // ADRDY is "ADC ready". Wait until it will be True. |
| 70 | Prescaler::DividedBy2 => 2, | 56 | while !T::regs().isr().read().adrdy() {} |
| 71 | Prescaler::DividedBy4 => 4, | 57 | } |
| 72 | Prescaler::DividedBy6 => 6, | 58 | |
| 73 | Prescaler::DividedBy8 => 8, | 59 | fn start() { |
| 74 | Prescaler::DividedBy10 => 10, | 60 | // Start conversion |
| 75 | Prescaler::DividedBy12 => 12, | 61 | T::regs().cr().modify(|reg| { |
| 76 | Prescaler::DividedBy16 => 16, | 62 | reg.set_adstart(true); |
| 77 | Prescaler::DividedBy32 => 32, | 63 | }); |
| 78 | Prescaler::DividedBy64 => 64, | 64 | } |
| 79 | Prescaler::DividedBy128 => 128, | 65 | |
| 80 | Prescaler::DividedBy256 => 256, | 66 | fn stop() { |
| 67 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | ||
| 68 | T::regs().cr().modify(|reg| { | ||
| 69 | reg.set_adstp(Adstp::STOP); | ||
| 70 | }); | ||
| 71 | while T::regs().cr().read().adstart() {} | ||
| 81 | } | 72 | } |
| 73 | |||
| 74 | // Reset configuration. | ||
| 75 | T::regs().cfgr1().modify(|reg| { | ||
| 76 | reg.set_cont(false); | ||
| 77 | reg.set_dmacfg(Dmacfg::from_bits(0)); | ||
| 78 | reg.set_dmaen(false); | ||
| 79 | }); | ||
| 82 | } | 80 | } |
| 83 | 81 | ||
| 84 | fn presc(&self) -> Presc { | 82 | fn configure_dma(conversion_mode: super::ConversionMode) { |
| 85 | match self { | 83 | match conversion_mode { |
| 86 | Prescaler::NotDivided => Presc::DIV1, | 84 | ConversionMode::Singular => { |
| 87 | Prescaler::DividedBy2 => Presc::DIV2, | 85 | // Enable overrun control, so no new DMA requests will be generated until |
| 88 | Prescaler::DividedBy4 => Presc::DIV4, | 86 | // previous DR values is read. |
| 89 | Prescaler::DividedBy6 => Presc::DIV6, | 87 | T::regs().isr().modify(|reg| { |
| 90 | Prescaler::DividedBy8 => Presc::DIV8, | 88 | reg.set_ovr(true); |
| 91 | Prescaler::DividedBy10 => Presc::DIV10, | 89 | }); |
| 92 | Prescaler::DividedBy12 => Presc::DIV12, | 90 | |
| 93 | Prescaler::DividedBy16 => Presc::DIV16, | 91 | // Set continuous mode with oneshot dma. |
| 94 | Prescaler::DividedBy32 => Presc::DIV32, | 92 | T::regs().cfgr1().modify(|reg| { |
| 95 | Prescaler::DividedBy64 => Presc::DIV64, | 93 | reg.set_discen(false); |
| 96 | Prescaler::DividedBy128 => Presc::DIV128, | 94 | reg.set_cont(true); |
| 97 | Prescaler::DividedBy256 => Presc::DIV256, | 95 | reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); |
| 96 | reg.set_dmaen(true); | ||
| 97 | reg.set_ovrmod(Ovrmod::PRESERVE); | ||
| 98 | }); | ||
| 99 | } | ||
| 98 | } | 100 | } |
| 99 | } | 101 | } |
| 100 | } | ||
| 101 | 102 | ||
| 102 | #[cfg(feature = "defmt")] | 103 | fn configure_sequence(mut sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool) { |
| 103 | impl<'a> defmt::Format for Prescaler { | 104 | T::regs().cfgr1().modify(|reg| { |
| 104 | fn format(&self, fmt: defmt::Formatter) { | 105 | reg.set_chselrmod(!blocking); |
| 105 | match self { | 106 | reg.set_align(Align::RIGHT); |
| 106 | Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), | 107 | }); |
| 107 | Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), | 108 | |
| 108 | Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), | 109 | assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking."); |
| 109 | Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), | 110 | if blocking { |
| 110 | Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), | 111 | let ((ch, _), sample_time) = sequence.next().unwrap(); |
| 111 | Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), | 112 | // Set all channels to use SMP1 field as source. |
| 112 | Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), | 113 | T::regs().smpr().modify(|w| { |
| 113 | Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), | 114 | w.smpsel(0); |
| 114 | Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), | 115 | w.set_smp1(sample_time); |
| 115 | Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), | 116 | }); |
| 116 | Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), | 117 | |
| 117 | Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), | 118 | // write() because we want all other bits to be set to 0. |
| 119 | T::regs().chselr().write(|w| w.set_chsel(ch.into(), true)); | ||
| 120 | } else { | ||
| 121 | let mut hw_channel_selection: u32 = 0; | ||
| 122 | let mut is_ordered_up = true; | ||
| 123 | let mut is_ordered_down = true; | ||
| 124 | let mut needs_hw = false; | ||
| 125 | |||
| 126 | assert!( | ||
| 127 | sequence.len() <= CHSELR_SQ_SIZE, | ||
| 128 | "Sequence read set cannot be more than {} in size.", | ||
| 129 | CHSELR_SQ_SIZE | ||
| 130 | ); | ||
| 131 | let mut last_sq_set: usize = 0; | ||
| 132 | let mut last_channel: u8 = 0; | ||
| 133 | T::regs().chselr_sq().write(|w| { | ||
| 134 | for (i, ((channel, _), _sample_time)) in sequence.enumerate() { | ||
| 135 | needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; | ||
| 136 | last_sq_set = i; | ||
| 137 | is_ordered_up = is_ordered_up && channel > last_channel; | ||
| 138 | is_ordered_down = is_ordered_down && channel < last_channel; | ||
| 139 | hw_channel_selection += 1 << channel; | ||
| 140 | last_channel = channel; | ||
| 141 | |||
| 142 | if !needs_hw { | ||
| 143 | w.set_sq(i, channel); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | assert!( | ||
| 148 | !needs_hw || is_ordered_up || is_ordered_down, | ||
| 149 | "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", | ||
| 150 | CHSELR_SQ_MAX_CHANNEL | ||
| 151 | ); | ||
| 152 | |||
| 153 | if needs_hw { | ||
| 154 | assert!( | ||
| 155 | hw_channel_selection != 0, | ||
| 156 | "Some bits in `hw_channel_selection` shall be set." | ||
| 157 | ); | ||
| 158 | assert!( | ||
| 159 | (hw_channel_selection >> NUM_HW_CHANNELS) == 0, | ||
| 160 | "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", | ||
| 161 | NUM_HW_CHANNELS | ||
| 162 | ); | ||
| 163 | |||
| 164 | T::regs().cfgr1().modify(|reg| { | ||
| 165 | reg.set_chselrmod(false); | ||
| 166 | reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK }); | ||
| 167 | }); | ||
| 168 | |||
| 169 | // Set required channels for multi-convert. | ||
| 170 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } | ||
| 171 | } else { | ||
| 172 | for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { | ||
| 173 | w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | }); | ||
| 118 | } | 177 | } |
| 178 | |||
| 179 | // Trigger and wait for the channel selection procedure to complete. | ||
| 180 | T::regs().isr().modify(|w| w.set_ccrdy(false)); | ||
| 181 | while !T::regs().isr().read().ccrdy() {} | ||
| 119 | } | 182 | } |
| 120 | } | ||
| 121 | 183 | ||
| 122 | /// Number of samples used for averaging. | 184 | fn convert() -> u16 { |
| 123 | /// TODO: Implement hardware averaging setting. | 185 | // Set single conversion mode. |
| 124 | #[allow(unused)] | 186 | T::regs().cfgr1().modify(|w| w.set_cont(false)); |
| 125 | #[derive(Copy, Clone, Debug)] | 187 | |
| 126 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 188 | // Start conversion |
| 127 | pub enum Averaging { | 189 | T::regs().cr().modify(|reg| { |
| 128 | Disabled, | 190 | reg.set_adstart(true); |
| 129 | Samples2, | 191 | }); |
| 130 | Samples4, | 192 | |
| 131 | Samples8, | 193 | // Waiting for End Of Conversion (EOC). |
| 132 | Samples16, | 194 | while !T::regs().isr().read().eoc() {} |
| 133 | Samples32, | 195 | |
| 134 | Samples64, | 196 | T::regs().dr().read().data() as u16 |
| 135 | Samples128, | 197 | } |
| 136 | Samples256, | ||
| 137 | Samples512, | ||
| 138 | Samples1024, | ||
| 139 | } | 198 | } |
| 140 | 199 | ||
| 141 | impl<'d, T: Instance> Adc<'d, T> { | 200 | impl<'d, T: AnyInstance> Adc<'d, T> { |
| 142 | /// Create a new ADC driver. | 201 | /// Create a new ADC driver. |
| 143 | pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { | 202 | pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { |
| 144 | rcc::enable_and_reset::<T>(); | 203 | rcc::enable_and_reset::<T>(); |
| 145 | 204 | ||
| 146 | T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); | 205 | T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); |
| 147 | 206 | ||
| 148 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 207 | let prescaler = from_ker_ck(T::frequency()); |
| 149 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 208 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 150 | 209 | ||
| 151 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 210 | let frequency = T::frequency() / prescaler; |
| 152 | debug!("ADC frequency set to {}", frequency); | 211 | debug!("ADC frequency set to {}", frequency); |
| 153 | 212 | ||
| 154 | if frequency > MAX_ADC_CLK_FREQ { | 213 | if frequency > MAX_ADC_CLK_FREQ { |
| @@ -158,32 +217,16 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 158 | ); | 217 | ); |
| 159 | } | 218 | } |
| 160 | 219 | ||
| 161 | let mut s = Self { adc }; | ||
| 162 | |||
| 163 | s.power_up(); | ||
| 164 | |||
| 165 | s.set_resolution(resolution); | ||
| 166 | |||
| 167 | s.calibrate(); | ||
| 168 | |||
| 169 | s.enable(); | ||
| 170 | |||
| 171 | s.configure_default(); | ||
| 172 | |||
| 173 | s | ||
| 174 | } | ||
| 175 | |||
| 176 | fn power_up(&mut self) { | ||
| 177 | T::regs().cr().modify(|reg| { | 220 | T::regs().cr().modify(|reg| { |
| 178 | reg.set_advregen(true); | 221 | reg.set_advregen(true); |
| 179 | }); | 222 | }); |
| 180 | 223 | ||
| 181 | // "The software must wait for the ADC voltage regulator startup time." | 224 | // "The software must wait for the ADC voltage regulator startup time." |
| 182 | // See datasheet for the value. | 225 | // See datasheet for the value. |
| 183 | blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); | 226 | blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1); |
| 184 | } | 227 | |
| 228 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); | ||
| 185 | 229 | ||
| 186 | fn calibrate(&mut self) { | ||
| 187 | // We have to make sure AUTOFF is OFF, but keep its value after calibration. | 230 | // We have to make sure AUTOFF is OFF, but keep its value after calibration. |
| 188 | let autoff_value = T::regs().cfgr1().read().autoff(); | 231 | let autoff_value = T::regs().cfgr1().read().autoff(); |
| 189 | T::regs().cfgr1().modify(|w| w.set_autoff(false)); | 232 | T::regs().cfgr1().modify(|w| w.set_autoff(false)); |
| @@ -197,22 +240,17 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 197 | debug!("ADC calibration value: {}.", T::regs().dr().read().data()); | 240 | debug!("ADC calibration value: {}.", T::regs().dr().read().data()); |
| 198 | 241 | ||
| 199 | T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); | 242 | T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); |
| 200 | } | ||
| 201 | 243 | ||
| 202 | fn enable(&mut self) { | 244 | T::enable(); |
| 203 | T::regs().isr().modify(|w| w.set_adrdy(true)); | ||
| 204 | T::regs().cr().modify(|w| w.set_aden(true)); | ||
| 205 | // ADRDY is "ADC ready". Wait until it will be True. | ||
| 206 | while !T::regs().isr().read().adrdy() {} | ||
| 207 | } | ||
| 208 | 245 | ||
| 209 | fn configure_default(&mut self) { | ||
| 210 | // single conversion mode, software trigger | 246 | // single conversion mode, software trigger |
| 211 | T::regs().cfgr1().modify(|w| { | 247 | T::regs().cfgr1().modify(|w| { |
| 212 | w.set_cont(false); | 248 | w.set_cont(false); |
| 213 | w.set_exten(Exten::DISABLED); | 249 | w.set_exten(Exten::DISABLED); |
| 214 | w.set_align(Align::RIGHT); | 250 | w.set_align(Align::RIGHT); |
| 215 | }); | 251 | }); |
| 252 | |||
| 253 | Self { adc } | ||
| 216 | } | 254 | } |
| 217 | 255 | ||
| 218 | /// Enable reading the voltage reference internal channel. | 256 | /// Enable reading the voltage reference internal channel. |
| @@ -233,219 +271,4 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 233 | 271 | ||
| 234 | super::Temperature {} | 272 | super::Temperature {} |
| 235 | } | 273 | } |
| 236 | |||
| 237 | /// Set the ADC sample time. | ||
| 238 | /// Shall only be called when ADC is not converting. | ||
| 239 | pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) { | ||
| 240 | // Set all channels to use SMP1 field as source. | ||
| 241 | T::regs().smpr().modify(|w| { | ||
| 242 | w.smpsel(0); | ||
| 243 | w.set_smp1(sample_time); | ||
| 244 | }); | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Set the ADC resolution. | ||
| 248 | pub fn set_resolution(&mut self, resolution: Resolution) { | ||
| 249 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Perform a single conversion. | ||
| 253 | fn convert(&mut self) -> u16 { | ||
| 254 | // Set single conversion mode. | ||
| 255 | T::regs().cfgr1().modify(|w| w.set_cont(false)); | ||
| 256 | |||
| 257 | // Start conversion | ||
| 258 | T::regs().cr().modify(|reg| { | ||
| 259 | reg.set_adstart(true); | ||
| 260 | }); | ||
| 261 | |||
| 262 | // Waiting for End Of Conversion (EOC). | ||
| 263 | while !T::regs().isr().read().eoc() {} | ||
| 264 | |||
| 265 | T::regs().dr().read().data() as u16 | ||
| 266 | } | ||
| 267 | |||
| 268 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { | ||
| 269 | self.set_sample_time_all_channels(sample_time); | ||
| 270 | |||
| 271 | Self::configure_channel(channel); | ||
| 272 | T::regs().cfgr1().write(|reg| { | ||
| 273 | reg.set_chselrmod(false); | ||
| 274 | reg.set_align(Align::RIGHT); | ||
| 275 | }); | ||
| 276 | self.convert() | ||
| 277 | } | ||
| 278 | |||
| 279 | fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) { | ||
| 280 | assert!( | ||
| 281 | channel_sequence.len() <= CHSELR_SQ_SIZE, | ||
| 282 | "Seqenced read set cannot be more than {} in size.", | ||
| 283 | CHSELR_SQ_SIZE | ||
| 284 | ); | ||
| 285 | let mut last_sq_set: usize = 0; | ||
| 286 | T::regs().chselr_sq().write(|w| { | ||
| 287 | for (i, channel) in channel_sequence.enumerate() { | ||
| 288 | assert!( | ||
| 289 | channel.channel() <= CHSELR_SQ_MAX_CHANNEL, | ||
| 290 | "Sequencer only support HW channels smaller than {}.", | ||
| 291 | CHSELR_SQ_MAX_CHANNEL | ||
| 292 | ); | ||
| 293 | w.set_sq(i, channel.channel()); | ||
| 294 | last_sq_set = i; | ||
| 295 | } | ||
| 296 | |||
| 297 | for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { | ||
| 298 | w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); | ||
| 299 | } | ||
| 300 | }); | ||
| 301 | |||
| 302 | Self::apply_channel_conf() | ||
| 303 | } | ||
| 304 | |||
| 305 | async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) { | ||
| 306 | // Enable overrun control, so no new DMA requests will be generated until | ||
| 307 | // previous DR values is read. | ||
| 308 | T::regs().isr().modify(|reg| { | ||
| 309 | reg.set_ovr(true); | ||
| 310 | }); | ||
| 311 | |||
| 312 | // Set continuous mode with oneshot dma. | ||
| 313 | T::regs().cfgr1().modify(|reg| { | ||
| 314 | reg.set_discen(false); | ||
| 315 | reg.set_cont(true); | ||
| 316 | reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); | ||
| 317 | reg.set_dmaen(true); | ||
| 318 | reg.set_ovrmod(Ovrmod::PRESERVE); | ||
| 319 | }); | ||
| 320 | |||
| 321 | let request = rx_dma.request(); | ||
| 322 | let transfer = unsafe { | ||
| 323 | Transfer::new_read( | ||
| 324 | rx_dma, | ||
| 325 | request, | ||
| 326 | T::regs().dr().as_ptr() as *mut u16, | ||
| 327 | readings, | ||
| 328 | Default::default(), | ||
| 329 | ) | ||
| 330 | }; | ||
| 331 | |||
| 332 | // Start conversion. | ||
| 333 | T::regs().cr().modify(|reg| { | ||
| 334 | reg.set_adstart(true); | ||
| 335 | }); | ||
| 336 | |||
| 337 | // Wait for conversion sequence to finish. | ||
| 338 | transfer.await; | ||
| 339 | |||
| 340 | // Ensure conversions are finished. | ||
| 341 | Self::cancel_conversions(); | ||
| 342 | |||
| 343 | // Reset configuration. | ||
| 344 | T::regs().cfgr1().modify(|reg| { | ||
| 345 | reg.set_cont(false); | ||
| 346 | reg.set_dmacfg(Dmacfg::from_bits(0)); | ||
| 347 | reg.set_dmaen(false); | ||
| 348 | }); | ||
| 349 | } | ||
| 350 | |||
| 351 | /// Read one or multiple ADC channels using DMA in hardware order. | ||
| 352 | /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting. | ||
| 353 | /// Readings won't be in the same order as in the `set`! | ||
| 354 | /// | ||
| 355 | /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use | ||
| 356 | /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). | ||
| 357 | /// TODO(chudsaviet): externalize generic code and merge with read(). | ||
| 358 | pub async fn read_in_hw_order( | ||
| 359 | &mut self, | ||
| 360 | rx_dma: Peri<'_, impl RxDma<T>>, | ||
| 361 | hw_channel_selection: u32, | ||
| 362 | scandir: Scandir, | ||
| 363 | readings: &mut [u16], | ||
| 364 | ) { | ||
| 365 | assert!( | ||
| 366 | hw_channel_selection != 0, | ||
| 367 | "Some bits in `hw_channel_selection` shall be set." | ||
| 368 | ); | ||
| 369 | assert!( | ||
| 370 | (hw_channel_selection >> NUM_HW_CHANNELS) == 0, | ||
| 371 | "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", | ||
| 372 | NUM_HW_CHANNELS | ||
| 373 | ); | ||
| 374 | // To check for correct readings slice size, we shall solve Hamming weight problem, | ||
| 375 | // which is either slow or memory consuming. | ||
| 376 | // Since we have limited resources, we don't do it here. | ||
| 377 | // Not doing this have a great potential for a bug through. | ||
| 378 | |||
| 379 | // Ensure no conversions are ongoing. | ||
| 380 | Self::cancel_conversions(); | ||
| 381 | |||
| 382 | T::regs().cfgr1().modify(|reg| { | ||
| 383 | reg.set_chselrmod(false); | ||
| 384 | reg.set_scandir(scandir); | ||
| 385 | reg.set_align(Align::RIGHT); | ||
| 386 | }); | ||
| 387 | |||
| 388 | // Set required channels for multi-convert. | ||
| 389 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } | ||
| 390 | |||
| 391 | Self::apply_channel_conf(); | ||
| 392 | |||
| 393 | self.dma_convert(rx_dma, readings).await | ||
| 394 | } | ||
| 395 | |||
| 396 | // Read ADC channels in specified order using DMA (CHSELRMOD = 1). | ||
| 397 | // In STM32C0, only lower 14 ADC channels can be read this way. | ||
| 398 | // For other channels, use `read_in_hw_order()` or blocking read. | ||
| 399 | pub async fn read( | ||
| 400 | &mut self, | ||
| 401 | rx_dma: Peri<'_, impl RxDma<T>>, | ||
| 402 | channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>, | ||
| 403 | readings: &mut [u16], | ||
| 404 | ) { | ||
| 405 | assert!( | ||
| 406 | channel_sequence.len() != 0, | ||
| 407 | "Asynchronous read channel sequence cannot be empty." | ||
| 408 | ); | ||
| 409 | assert!( | ||
| 410 | channel_sequence.len() == readings.len(), | ||
| 411 | "Channel sequence length must be equal to readings length." | ||
| 412 | ); | ||
| 413 | |||
| 414 | // Ensure no conversions are ongoing. | ||
| 415 | Self::cancel_conversions(); | ||
| 416 | |||
| 417 | T::regs().cfgr1().modify(|reg| { | ||
| 418 | reg.set_chselrmod(true); | ||
| 419 | reg.set_align(Align::RIGHT); | ||
| 420 | }); | ||
| 421 | |||
| 422 | Self::setup_channel_sequencer(channel_sequence); | ||
| 423 | |||
| 424 | self.dma_convert(rx_dma, readings).await | ||
| 425 | } | ||
| 426 | |||
| 427 | fn configure_channel(channel: &mut impl AdcChannel<T>) { | ||
| 428 | channel.setup(); | ||
| 429 | // write() because we want all other bits to be set to 0. | ||
| 430 | T::regs() | ||
| 431 | .chselr() | ||
| 432 | .write(|w| w.set_chsel(channel.channel().into(), true)); | ||
| 433 | |||
| 434 | Self::apply_channel_conf(); | ||
| 435 | } | ||
| 436 | |||
| 437 | fn apply_channel_conf() { | ||
| 438 | // Trigger and wait for the channel selection procedure to complete. | ||
| 439 | T::regs().isr().modify(|w| w.set_ccrdy(false)); | ||
| 440 | while !T::regs().isr().read().ccrdy() {} | ||
| 441 | } | ||
| 442 | |||
| 443 | fn cancel_conversions() { | ||
| 444 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | ||
| 445 | T::regs().cr().modify(|reg| { | ||
| 446 | reg.set_adstp(Adstp::STOP); | ||
| 447 | }); | ||
| 448 | while T::regs().cr().read().adstart() {} | ||
| 449 | } | ||
| 450 | } | ||
| 451 | } | 274 | } |
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index f6220de78..d6c6f480b 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs | |||
| @@ -43,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 43 | 43 | ||
| 44 | // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) | 44 | // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) |
| 45 | // for at least two ADC clock cycles. | 45 | // for at least two ADC clock cycles. |
| 46 | blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1); | 46 | blocking_delay_us((1_000_000 * 2) / Self::freq().0 as u64 + 1); |
| 47 | 47 | ||
| 48 | // Reset calibration | 48 | // Reset calibration |
| 49 | T::regs().cr2().modify(|reg| reg.set_rstcal(true)); | 49 | T::regs().cr2().modify(|reg| reg.set_rstcal(true)); |
| @@ -58,7 +58,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | // One cycle after calibration | 60 | // One cycle after calibration |
| 61 | blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); | 61 | blocking_delay_us((1_000_000 * 1) / Self::freq().0 as u64 + 1); |
| 62 | 62 | ||
| 63 | T::Interrupt::unpend(); | 63 | T::Interrupt::unpend(); |
| 64 | unsafe { T::Interrupt::enable() }; | 64 | unsafe { T::Interrupt::enable() }; |
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 4a77f3c5b..29bfdac97 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs | |||
| @@ -62,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 62 | while T::regs().cr().read().adcal() {} | 62 | while T::regs().cr().read().adcal() {} |
| 63 | 63 | ||
| 64 | // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). | 64 | // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). |
| 65 | blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1); | 65 | blocking_delay_us((1_000_000 * 4) / Self::freq().0 as u64 + 1); |
| 66 | 66 | ||
| 67 | // Enable the adc | 67 | // Enable the adc |
| 68 | T::regs().cr().modify(|w| w.set_aden(true)); | 68 | T::regs().cr().modify(|w| w.set_aden(true)); |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 71dc8acc0..514734017 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -32,71 +32,17 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); | |||
| 32 | #[cfg(stm32h7)] | 32 | #[cfg(stm32h7)] |
| 33 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); | 33 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
| 34 | 34 | ||
| 35 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 35 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 36 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 36 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 37 | #[allow(unused)] | 37 | match raw_prescaler { |
| 38 | enum Prescaler { | 38 | 0 => Presc::DIV1, |
| 39 | NotDivided, | 39 | 1 => Presc::DIV2, |
| 40 | DividedBy2, | 40 | 2..=3 => Presc::DIV4, |
| 41 | DividedBy4, | 41 | 4..=5 => Presc::DIV6, |
| 42 | DividedBy6, | 42 | 6..=7 => Presc::DIV8, |
| 43 | DividedBy8, | 43 | 8..=9 => Presc::DIV10, |
| 44 | DividedBy10, | 44 | 10..=11 => Presc::DIV12, |
| 45 | DividedBy12, | 45 | _ => unimplemented!(), |
| 46 | DividedBy16, | ||
| 47 | DividedBy32, | ||
| 48 | DividedBy64, | ||
| 49 | DividedBy128, | ||
| 50 | DividedBy256, | ||
| 51 | } | ||
| 52 | |||
| 53 | impl Prescaler { | ||
| 54 | fn from_ker_ck(frequency: Hertz) -> Self { | ||
| 55 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | ||
| 56 | match raw_prescaler { | ||
| 57 | 0 => Self::NotDivided, | ||
| 58 | 1 => Self::DividedBy2, | ||
| 59 | 2..=3 => Self::DividedBy4, | ||
| 60 | 4..=5 => Self::DividedBy6, | ||
| 61 | 6..=7 => Self::DividedBy8, | ||
| 62 | 8..=9 => Self::DividedBy10, | ||
| 63 | 10..=11 => Self::DividedBy12, | ||
| 64 | _ => unimplemented!(), | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | fn divisor(&self) -> u32 { | ||
| 69 | match self { | ||
| 70 | Prescaler::NotDivided => 1, | ||
| 71 | Prescaler::DividedBy2 => 2, | ||
| 72 | Prescaler::DividedBy4 => 4, | ||
| 73 | Prescaler::DividedBy6 => 6, | ||
| 74 | Prescaler::DividedBy8 => 8, | ||
| 75 | Prescaler::DividedBy10 => 10, | ||
| 76 | Prescaler::DividedBy12 => 12, | ||
| 77 | Prescaler::DividedBy16 => 16, | ||
| 78 | Prescaler::DividedBy32 => 32, | ||
| 79 | Prescaler::DividedBy64 => 64, | ||
| 80 | Prescaler::DividedBy128 => 128, | ||
| 81 | Prescaler::DividedBy256 => 256, | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | fn presc(&self) -> Presc { | ||
| 86 | match self { | ||
| 87 | Prescaler::NotDivided => Presc::DIV1, | ||
| 88 | Prescaler::DividedBy2 => Presc::DIV2, | ||
| 89 | Prescaler::DividedBy4 => Presc::DIV4, | ||
| 90 | Prescaler::DividedBy6 => Presc::DIV6, | ||
| 91 | Prescaler::DividedBy8 => Presc::DIV8, | ||
| 92 | Prescaler::DividedBy10 => Presc::DIV10, | ||
| 93 | Prescaler::DividedBy12 => Presc::DIV12, | ||
| 94 | Prescaler::DividedBy16 => Presc::DIV16, | ||
| 95 | Prescaler::DividedBy32 => Presc::DIV32, | ||
| 96 | Prescaler::DividedBy64 => Presc::DIV64, | ||
| 97 | Prescaler::DividedBy128 => Presc::DIV128, | ||
| 98 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 99 | } | ||
| 100 | } | 46 | } |
| 101 | } | 47 | } |
| 102 | 48 | ||
| @@ -292,11 +238,11 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 292 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 238 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 293 | rcc::enable_and_reset::<T>(); | 239 | rcc::enable_and_reset::<T>(); |
| 294 | 240 | ||
| 295 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 241 | let prescaler = from_ker_ck(T::frequency()); |
| 296 | 242 | ||
| 297 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 243 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 298 | 244 | ||
| 299 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 245 | let frequency = T::frequency() / prescaler; |
| 300 | trace!("ADC frequency set to {}", frequency); | 246 | trace!("ADC frequency set to {}", frequency); |
| 301 | 247 | ||
| 302 | if frequency > MAX_ADC_CLK_FREQ { | 248 | if frequency > MAX_ADC_CLK_FREQ { |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 856c2e61e..5ec08a22d 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -35,6 +35,8 @@ pub use ringbuffered::RingBufferedAdc; | |||
| 35 | #[path = "adc4.rs"] | 35 | #[path = "adc4.rs"] |
| 36 | pub mod adc4; | 36 | pub mod adc4; |
| 37 | 37 | ||
| 38 | #[allow(unused)] | ||
| 39 | pub(self) use crate::block_for_us as blocking_delay_us; | ||
| 38 | pub use crate::pac::adc::vals; | 40 | pub use crate::pac::adc::vals; |
| 39 | #[cfg(not(any(adc_f1, adc_f3v3)))] | 41 | #[cfg(not(any(adc_f1, adc_f3v3)))] |
| 40 | pub use crate::pac::adc::vals::Res as Resolution; | 42 | pub use crate::pac::adc::vals::Res as Resolution; |
| @@ -88,31 +90,37 @@ pub(crate) trait SealedAdcChannel<T> { | |||
| 88 | } | 90 | } |
| 89 | 91 | ||
| 90 | // Temporary patch for ADCs that have not implemented the standard iface yet | 92 | // Temporary patch for ADCs that have not implemented the standard iface yet |
| 91 | #[cfg(not(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4)))] | 93 | #[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))] |
| 92 | trait_set::trait_set! { | 94 | trait_set::trait_set! { |
| 93 | pub trait AnyInstance = Instance; | 95 | pub trait AnyInstance = Instance; |
| 94 | } | 96 | } |
| 95 | 97 | ||
| 96 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 98 | #[cfg(any( |
| 97 | #[allow(dead_code)] | 99 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 100 | ))] | ||
| 98 | pub trait BasicAnyInstance { | 101 | pub trait BasicAnyInstance { |
| 99 | type SampleTime; | 102 | type SampleTime; |
| 100 | } | 103 | } |
| 101 | 104 | ||
| 102 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 105 | #[cfg(any( |
| 103 | #[allow(dead_code)] | 106 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 107 | ))] | ||
| 104 | pub(self) trait SealedAnyInstance: BasicAnyInstance { | 108 | pub(self) trait SealedAnyInstance: BasicAnyInstance { |
| 105 | fn enable(); | 109 | fn enable(); |
| 106 | fn start(); | 110 | fn start(); |
| 107 | fn stop(); | 111 | fn stop(); |
| 108 | fn convert() -> u16; | 112 | fn convert() -> u16; |
| 109 | fn configure_dma(conversion_mode: ConversionMode); | 113 | fn configure_dma(conversion_mode: ConversionMode); |
| 114 | #[cfg(not(adc_c0))] | ||
| 110 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); | 115 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); |
| 116 | #[cfg(adc_c0)] | ||
| 117 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool); | ||
| 118 | #[allow(dead_code)] | ||
| 111 | fn dr() -> *mut u16; | 119 | fn dr() -> *mut u16; |
| 112 | } | 120 | } |
| 113 | 121 | ||
| 114 | // On chips without ADC4, AnyInstance is an Instance | 122 | // On chips without ADC4, AnyInstance is an Instance |
| 115 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] | 123 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))] |
| 116 | #[allow(private_bounds)] | 124 | #[allow(private_bounds)] |
| 117 | pub trait AnyInstance: SealedAnyInstance + Instance {} | 125 | pub trait AnyInstance: SealedAnyInstance + Instance {} |
| 118 | 126 | ||
| @@ -122,44 +130,53 @@ pub trait AnyInstance: SealedAnyInstance + Instance {} | |||
| 122 | pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} | 130 | pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} |
| 123 | 131 | ||
| 124 | // Implement AnyInstance automatically for SealedAnyInstance | 132 | // Implement AnyInstance automatically for SealedAnyInstance |
| 125 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 133 | #[cfg(any( |
| 134 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 135 | ))] | ||
| 126 | impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { | 136 | impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { |
| 127 | type SampleTime = SampleTime; | 137 | type SampleTime = SampleTime; |
| 128 | } | 138 | } |
| 129 | 139 | ||
| 130 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 140 | #[cfg(any( |
| 141 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 142 | ))] | ||
| 131 | impl<T: SealedAnyInstance + Instance> AnyInstance for T {} | 143 | impl<T: SealedAnyInstance + Instance> AnyInstance for T {} |
| 132 | 144 | ||
| 133 | /// Performs a busy-wait delay for a specified number of microseconds. | 145 | #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] |
| 134 | #[allow(unused)] | 146 | /// Number of samples used for averaging. |
| 135 | pub(crate) fn blocking_delay_us(us: u32) { | 147 | #[derive(Copy, Clone, Debug)] |
| 136 | cfg_if::cfg_if! { | 148 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 137 | // this does strange things on stm32wlx in low power mode depending on exactly when it's called | 149 | pub enum Averaging { |
| 138 | // as in sometimes 15 us (1 tick) would take > 20 seconds. | 150 | Disabled, |
| 139 | if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { | 151 | Samples2, |
| 140 | let duration = embassy_time::Duration::from_micros(us as u64); | 152 | Samples4, |
| 141 | embassy_time::block_for(duration); | 153 | Samples8, |
| 142 | } else { | 154 | Samples16, |
| 143 | let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; | 155 | Samples32, |
| 144 | let us = us as u64; | 156 | Samples64, |
| 145 | let cycles = freq * us / 1_000_000; | 157 | Samples128, |
| 146 | cortex_m::asm::delay(cycles as u32); | 158 | Samples256, |
| 147 | } | 159 | #[cfg(any(adc_c0, adc_v4, adc_u5))] |
| 148 | } | 160 | Samples512, |
| 161 | #[cfg(any(adc_c0, adc_v4, adc_u5))] | ||
| 162 | Samples1024, | ||
| 149 | } | 163 | } |
| 150 | 164 | ||
| 151 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 165 | #[cfg(any( |
| 152 | #[allow(dead_code)] | 166 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0 |
| 167 | ))] | ||
| 153 | pub(crate) enum ConversionMode { | 168 | pub(crate) enum ConversionMode { |
| 154 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 169 | // Should match the cfg on "read" below |
| 170 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 155 | Singular, | 171 | Singular, |
| 156 | #[allow(dead_code)] | 172 | // Should match the cfg on "into_ring_buffered" below |
| 173 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 157 | Repeated(RegularConversionMode), | 174 | Repeated(RegularConversionMode), |
| 158 | } | 175 | } |
| 159 | 176 | ||
| 160 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 177 | // Should match the cfg on "into_ring_buffered" below |
| 178 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 161 | // Conversion mode for regular ADC channels | 179 | // Conversion mode for regular ADC channels |
| 162 | #[allow(dead_code)] | ||
| 163 | #[derive(Copy, Clone)] | 180 | #[derive(Copy, Clone)] |
| 164 | pub enum RegularConversionMode { | 181 | pub enum RegularConversionMode { |
| 165 | // Samples as fast as possible | 182 | // Samples as fast as possible |
| @@ -170,7 +187,9 @@ pub enum RegularConversionMode { | |||
| 170 | } | 187 | } |
| 171 | 188 | ||
| 172 | impl<'d, T: AnyInstance> Adc<'d, T> { | 189 | impl<'d, T: AnyInstance> Adc<'d, T> { |
| 173 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] | 190 | #[cfg(any( |
| 191 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0 | ||
| 192 | ))] | ||
| 174 | /// Read an ADC pin. | 193 | /// Read an ADC pin. |
| 175 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { | 194 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { |
| 176 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 195 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| @@ -178,12 +197,18 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 178 | 197 | ||
| 179 | #[cfg(not(adc_v4))] | 198 | #[cfg(not(adc_v4))] |
| 180 | T::enable(); | 199 | T::enable(); |
| 200 | #[cfg(not(adc_c0))] | ||
| 181 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); | 201 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); |
| 202 | #[cfg(adc_c0)] | ||
| 203 | T::configure_sequence( | ||
| 204 | [((channel.channel(), channel.is_differential()), sample_time)].into_iter(), | ||
| 205 | true, | ||
| 206 | ); | ||
| 182 | 207 | ||
| 183 | T::convert() | 208 | T::convert() |
| 184 | } | 209 | } |
| 185 | 210 | ||
| 186 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 211 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] |
| 187 | /// Read one or multiple ADC regular channels using DMA. | 212 | /// Read one or multiple ADC regular channels using DMA. |
| 188 | /// | 213 | /// |
| 189 | /// `sequence` iterator and `readings` must have the same length. | 214 | /// `sequence` iterator and `readings` must have the same length. |
| @@ -212,6 +237,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 212 | /// | 237 | /// |
| 213 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use | 238 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use |
| 214 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` | 239 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` |
| 240 | /// | ||
| 241 | /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use | ||
| 242 | /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). | ||
| 243 | /// | ||
| 244 | /// In addtion, on STM320, this method will panic if the channels are not passed in order | ||
| 215 | pub async fn read( | 245 | pub async fn read( |
| 216 | &mut self, | 246 | &mut self, |
| 217 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, | 247 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, |
| @@ -232,8 +262,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 232 | T::stop(); | 262 | T::stop(); |
| 233 | T::enable(); | 263 | T::enable(); |
| 234 | 264 | ||
| 265 | #[cfg(not(adc_c0))] | ||
| 266 | T::configure_sequence( | ||
| 267 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | ||
| 268 | ); | ||
| 269 | |||
| 270 | #[cfg(adc_c0)] | ||
| 235 | T::configure_sequence( | 271 | T::configure_sequence( |
| 236 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 272 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 273 | false, | ||
| 237 | ); | 274 | ); |
| 238 | 275 | ||
| 239 | T::configure_dma(ConversionMode::Singular); | 276 | T::configure_dma(ConversionMode::Singular); |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4065f89a7..07eaebf7c 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -3,6 +3,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 3 | use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; | 3 | use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 4 | use crate::adc::{Adc, Instance, Resolution, SampleTime}; | 4 | use crate::adc::{Adc, Instance, Resolution, SampleTime}; |
| 5 | use crate::pac::adc::vals; | 5 | use crate::pac::adc::vals; |
| 6 | pub use crate::pac::adccommon::vals::Adcpre; | ||
| 6 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| 7 | use crate::{Peri, rcc}; | 8 | use crate::{Peri, rcc}; |
| 8 | 9 | ||
| @@ -50,38 +51,20 @@ impl Temperature { | |||
| 50 | } | 51 | } |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | enum Prescaler { | 54 | fn from_pclk2(freq: Hertz) -> Adcpre { |
| 54 | Div2, | 55 | // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). |
| 55 | Div4, | 56 | #[cfg(stm32f2)] |
| 56 | Div6, | 57 | const MAX_FREQUENCY: Hertz = Hertz(30_000_000); |
| 57 | Div8, | 58 | // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. |
| 58 | } | 59 | #[cfg(not(stm32f2))] |
| 59 | 60 | const MAX_FREQUENCY: Hertz = Hertz(36_000_000); | |
| 60 | impl Prescaler { | 61 | let raw_div = freq.0 / MAX_FREQUENCY.0; |
| 61 | fn from_pclk2(freq: Hertz) -> Self { | 62 | match raw_div { |
| 62 | // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). | 63 | 0..=1 => Adcpre::DIV2, |
| 63 | #[cfg(stm32f2)] | 64 | 2..=3 => Adcpre::DIV4, |
| 64 | const MAX_FREQUENCY: Hertz = Hertz(30_000_000); | 65 | 4..=5 => Adcpre::DIV6, |
| 65 | // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. | 66 | 6..=7 => Adcpre::DIV8, |
| 66 | #[cfg(not(stm32f2))] | 67 | _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), |
| 67 | const MAX_FREQUENCY: Hertz = Hertz(36_000_000); | ||
| 68 | let raw_div = freq.0 / MAX_FREQUENCY.0; | ||
| 69 | match raw_div { | ||
| 70 | 0..=1 => Self::Div2, | ||
| 71 | 2..=3 => Self::Div4, | ||
| 72 | 4..=5 => Self::Div6, | ||
| 73 | 6..=7 => Self::Div8, | ||
| 74 | _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre { | ||
| 79 | match self { | ||
| 80 | Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2, | ||
| 81 | Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4, | ||
| 82 | Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6, | ||
| 83 | Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8, | ||
| 84 | } | ||
| 85 | } | 68 | } |
| 86 | } | 69 | } |
| 87 | 70 | ||
| @@ -224,8 +207,8 @@ where | |||
| 224 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 207 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 225 | rcc::enable_and_reset::<T>(); | 208 | rcc::enable_and_reset::<T>(); |
| 226 | 209 | ||
| 227 | let presc = Prescaler::from_pclk2(T::frequency()); | 210 | let presc = from_pclk2(T::frequency()); |
| 228 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | 211 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); |
| 229 | T::regs().cr2().modify(|reg| { | 212 | T::regs().cr2().modify(|reg| { |
| 230 | reg.set_adon(true); | 213 | reg.set_adon(true); |
| 231 | }); | 214 | }); |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index ba1afbe05..288bd77ce 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -11,7 +11,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; | |||
| 11 | 11 | ||
| 12 | #[allow(unused_imports)] | 12 | #[allow(unused_imports)] |
| 13 | use super::SealedAdcChannel; | 13 | use super::SealedAdcChannel; |
| 14 | use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; | 14 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 15 | use crate::adc::ConversionMode; | 15 | use crate::adc::ConversionMode; |
| 16 | use crate::{Peri, pac, rcc}; | 16 | use crate::{Peri, pac, rcc}; |
| 17 | 17 | ||
| @@ -100,21 +100,6 @@ cfg_if! { | |||
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /// Number of samples used for averaging. | ||
| 104 | #[derive(Copy, Clone, Debug)] | ||
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 106 | pub enum Averaging { | ||
| 107 | Disabled, | ||
| 108 | Samples2, | ||
| 109 | Samples4, | ||
| 110 | Samples8, | ||
| 111 | Samples16, | ||
| 112 | Samples32, | ||
| 113 | Samples64, | ||
| 114 | Samples128, | ||
| 115 | Samples256, | ||
| 116 | } | ||
| 117 | |||
| 118 | cfg_if! { if #[cfg(adc_g0)] { | 103 | cfg_if! { if #[cfg(adc_g0)] { |
| 119 | 104 | ||
| 120 | /// Synchronous PCLK prescaler | 105 | /// Synchronous PCLK prescaler |
| @@ -267,6 +252,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 267 | reg.set_cont(true); | 252 | reg.set_cont(true); |
| 268 | reg.set_dmacfg(match conversion_mode { | 253 | reg.set_dmacfg(match conversion_mode { |
| 269 | ConversionMode::Singular => Dmacfg::ONE_SHOT, | 254 | ConversionMode::Singular => Dmacfg::ONE_SHOT, |
| 255 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 270 | ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, | 256 | ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, |
| 271 | }); | 257 | }); |
| 272 | reg.set_dmaen(true); | 258 | reg.set_dmaen(true); |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 43eb16fd5..804e63db6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -4,7 +4,7 @@ use pac::adc::vals::{Adcaldif, Boost}; | |||
| 4 | use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; | 4 | use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; |
| 5 | use pac::adccommon::vals::Presc; | 5 | use pac::adccommon::vals::Presc; |
| 6 | 6 | ||
| 7 | use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; | 7 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 8 | use crate::adc::ConversionMode; | 8 | use crate::adc::ConversionMode; |
| 9 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 10 | use crate::{Peri, pac, rcc}; | 10 | use crate::{Peri, pac, rcc}; |
| @@ -59,91 +59,20 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | |||
| 59 | const CHANNEL: u8 = 18; | 59 | const CHANNEL: u8 = 18; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 62 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 63 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 63 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 64 | #[allow(unused)] | 64 | match raw_prescaler { |
| 65 | enum Prescaler { | 65 | 0 => Presc::DIV1, |
| 66 | NotDivided, | 66 | 1 => Presc::DIV2, |
| 67 | DividedBy2, | 67 | 2..=3 => Presc::DIV4, |
| 68 | DividedBy4, | 68 | 4..=5 => Presc::DIV6, |
| 69 | DividedBy6, | 69 | 6..=7 => Presc::DIV8, |
| 70 | DividedBy8, | 70 | 8..=9 => Presc::DIV10, |
| 71 | DividedBy10, | 71 | 10..=11 => Presc::DIV12, |
| 72 | DividedBy12, | 72 | _ => unimplemented!(), |
| 73 | DividedBy16, | ||
| 74 | DividedBy32, | ||
| 75 | DividedBy64, | ||
| 76 | DividedBy128, | ||
| 77 | DividedBy256, | ||
| 78 | } | ||
| 79 | |||
| 80 | impl Prescaler { | ||
| 81 | fn from_ker_ck(frequency: Hertz) -> Self { | ||
| 82 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | ||
| 83 | match raw_prescaler { | ||
| 84 | 0 => Self::NotDivided, | ||
| 85 | 1 => Self::DividedBy2, | ||
| 86 | 2..=3 => Self::DividedBy4, | ||
| 87 | 4..=5 => Self::DividedBy6, | ||
| 88 | 6..=7 => Self::DividedBy8, | ||
| 89 | 8..=9 => Self::DividedBy10, | ||
| 90 | 10..=11 => Self::DividedBy12, | ||
| 91 | _ => unimplemented!(), | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | fn divisor(&self) -> u32 { | ||
| 96 | match self { | ||
| 97 | Prescaler::NotDivided => 1, | ||
| 98 | Prescaler::DividedBy2 => 2, | ||
| 99 | Prescaler::DividedBy4 => 4, | ||
| 100 | Prescaler::DividedBy6 => 6, | ||
| 101 | Prescaler::DividedBy8 => 8, | ||
| 102 | Prescaler::DividedBy10 => 10, | ||
| 103 | Prescaler::DividedBy12 => 12, | ||
| 104 | Prescaler::DividedBy16 => 16, | ||
| 105 | Prescaler::DividedBy32 => 32, | ||
| 106 | Prescaler::DividedBy64 => 64, | ||
| 107 | Prescaler::DividedBy128 => 128, | ||
| 108 | Prescaler::DividedBy256 => 256, | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | fn presc(&self) -> Presc { | ||
| 113 | match self { | ||
| 114 | Prescaler::NotDivided => Presc::DIV1, | ||
| 115 | Prescaler::DividedBy2 => Presc::DIV2, | ||
| 116 | Prescaler::DividedBy4 => Presc::DIV4, | ||
| 117 | Prescaler::DividedBy6 => Presc::DIV6, | ||
| 118 | Prescaler::DividedBy8 => Presc::DIV8, | ||
| 119 | Prescaler::DividedBy10 => Presc::DIV10, | ||
| 120 | Prescaler::DividedBy12 => Presc::DIV12, | ||
| 121 | Prescaler::DividedBy16 => Presc::DIV16, | ||
| 122 | Prescaler::DividedBy32 => Presc::DIV32, | ||
| 123 | Prescaler::DividedBy64 => Presc::DIV64, | ||
| 124 | Prescaler::DividedBy128 => Presc::DIV128, | ||
| 125 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 126 | } | ||
| 127 | } | 73 | } |
| 128 | } | 74 | } |
| 129 | 75 | ||
| 130 | /// Number of samples used for averaging. | ||
| 131 | #[derive(Copy, Clone, Debug)] | ||
| 132 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 133 | pub enum Averaging { | ||
| 134 | Disabled, | ||
| 135 | Samples2, | ||
| 136 | Samples4, | ||
| 137 | Samples8, | ||
| 138 | Samples16, | ||
| 139 | Samples32, | ||
| 140 | Samples64, | ||
| 141 | Samples128, | ||
| 142 | Samples256, | ||
| 143 | Samples512, | ||
| 144 | Samples1024, | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Adc configuration | 76 | /// Adc configuration |
| 148 | #[derive(Default)] | 77 | #[derive(Default)] |
| 149 | pub struct AdcConfig { | 78 | pub struct AdcConfig { |
| @@ -214,6 +143,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 214 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); | 143 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); |
| 215 | }); | 144 | }); |
| 216 | } | 145 | } |
| 146 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 217 | _ => unreachable!(), | 147 | _ => unreachable!(), |
| 218 | } | 148 | } |
| 219 | } | 149 | } |
| @@ -309,11 +239,11 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { | |||
| 309 | pub fn new(adc: Peri<'d, T>) -> Self { | 239 | pub fn new(adc: Peri<'d, T>) -> Self { |
| 310 | rcc::enable_and_reset::<T>(); | 240 | rcc::enable_and_reset::<T>(); |
| 311 | 241 | ||
| 312 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 242 | let prescaler = from_ker_ck(T::frequency()); |
| 313 | 243 | ||
| 314 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 244 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 315 | 245 | ||
| 316 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 246 | let frequency = T::frequency() / prescaler; |
| 317 | info!("ADC frequency set to {}", frequency); | 247 | info!("ADC frequency set to {}", frequency); |
| 318 | 248 | ||
| 319 | if frequency > MAX_ADC_CLK_FREQ { | 249 | if frequency > MAX_ADC_CLK_FREQ { |
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index 59a2cbcdb..b8945820c 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs | |||
| @@ -5,18 +5,11 @@ use core::marker::PhantomData; | |||
| 5 | use embassy_hal_internal::PeripheralType; | 5 | use embassy_hal_internal::PeripheralType; |
| 6 | 6 | ||
| 7 | //use crate::gpio::{AnyPin, SealedPin}; | 7 | //use crate::gpio::{AnyPin, SealedPin}; |
| 8 | use crate::block_for_us; | ||
| 8 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; | 9 | use crate::gpio::{AfType, AnyPin, OutputType, Speed}; |
| 9 | use crate::rcc::{self, RccPeripheral}; | 10 | use crate::rcc::{self, RccPeripheral}; |
| 10 | use crate::{Peri, peripherals}; | 11 | use crate::{Peri, peripherals}; |
| 11 | 12 | ||
| 12 | /// Performs a busy-wait delay for a specified number of microseconds. | ||
| 13 | pub fn blocking_delay_ms(ms: u32) { | ||
| 14 | #[cfg(feature = "time")] | ||
| 15 | embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); | ||
| 16 | #[cfg(not(feature = "time"))] | ||
| 17 | cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms); | ||
| 18 | } | ||
| 19 | |||
| 20 | /// PacketTypes extracted from CubeMX | 13 | /// PacketTypes extracted from CubeMX |
| 21 | #[repr(u8)] | 14 | #[repr(u8)] |
| 22 | #[allow(dead_code)] | 15 | #[allow(dead_code)] |
| @@ -334,7 +327,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { | |||
| 334 | if T::regs().gpsr().read().cmdfe() { | 327 | if T::regs().gpsr().read().cmdfe() { |
| 335 | return Ok(()); | 328 | return Ok(()); |
| 336 | } | 329 | } |
| 337 | blocking_delay_ms(1); | 330 | block_for_us(1_000); |
| 338 | } | 331 | } |
| 339 | Err(Error::FifoTimeout) | 332 | Err(Error::FifoTimeout) |
| 340 | } | 333 | } |
| @@ -345,7 +338,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { | |||
| 345 | if !T::regs().gpsr().read().cmdff() { | 338 | if !T::regs().gpsr().read().cmdff() { |
| 346 | return Ok(()); | 339 | return Ok(()); |
| 347 | } | 340 | } |
| 348 | blocking_delay_ms(1); | 341 | block_for_us(1_000); |
| 349 | } | 342 | } |
| 350 | Err(Error::FifoTimeout) | 343 | Err(Error::FifoTimeout) |
| 351 | } | 344 | } |
| @@ -356,7 +349,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { | |||
| 356 | if !self.read_busy() { | 349 | if !self.read_busy() { |
| 357 | return Ok(()); | 350 | return Ok(()); |
| 358 | } | 351 | } |
| 359 | blocking_delay_ms(1); | 352 | block_for_us(1_000); |
| 360 | } | 353 | } |
| 361 | Err(Error::ReadTimeout) | 354 | Err(Error::ReadTimeout) |
| 362 | } | 355 | } |
| @@ -367,7 +360,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { | |||
| 367 | if !T::regs().gpsr().read().prdfe() { | 360 | if !T::regs().gpsr().read().prdfe() { |
| 368 | return Ok(()); | 361 | return Ok(()); |
| 369 | } | 362 | } |
| 370 | blocking_delay_ms(1); | 363 | block_for_us(1_000); |
| 371 | } | 364 | } |
| 372 | Err(Error::FifoTimeout) | 365 | Err(Error::FifoTimeout) |
| 373 | } | 366 | } |
diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs index 774beef80..947874d7f 100644 --- a/embassy-stm32/src/eth/generic_phy.rs +++ b/embassy-stm32/src/eth/generic_phy.rs | |||
| @@ -8,6 +8,7 @@ use embassy_time::{Duration, Timer}; | |||
| 8 | use futures_util::FutureExt; | 8 | use futures_util::FutureExt; |
| 9 | 9 | ||
| 10 | use super::{Phy, StationManagement}; | 10 | use super::{Phy, StationManagement}; |
| 11 | use crate::block_for_us as blocking_delay_us; | ||
| 11 | 12 | ||
| 12 | #[allow(dead_code)] | 13 | #[allow(dead_code)] |
| 13 | mod phy_consts { | 14 | mod phy_consts { |
| @@ -76,19 +77,6 @@ impl GenericPhy { | |||
| 76 | } | 77 | } |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 79 | // TODO: Factor out to shared functionality | ||
| 80 | fn blocking_delay_us(us: u32) { | ||
| 81 | #[cfg(feature = "time")] | ||
| 82 | embassy_time::block_for(Duration::from_micros(us as u64)); | ||
| 83 | #[cfg(not(feature = "time"))] | ||
| 84 | { | ||
| 85 | let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; | ||
| 86 | let us = us as u64; | ||
| 87 | let cycles = freq * us / 1_000_000; | ||
| 88 | cortex_m::asm::delay(cycles as u32); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | impl Phy for GenericPhy { | 80 | impl Phy for GenericPhy { |
| 93 | fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) { | 81 | fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) { |
| 94 | // Detect SMI address | 82 | // Detect SMI address |
diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs new file mode 100644 index 000000000..0ad1002b0 --- /dev/null +++ b/embassy-stm32/src/flash/c.rs | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | use core::ptr::write_volatile; | ||
| 2 | use core::sync::atomic::{Ordering, fence}; | ||
| 3 | |||
| 4 | use cortex_m::interrupt; | ||
| 5 | |||
| 6 | use super::{FlashSector, WRITE_SIZE}; | ||
| 7 | use crate::flash::Error; | ||
| 8 | use crate::pac; | ||
| 9 | |||
| 10 | pub(crate) unsafe fn lock() { | ||
| 11 | pac::FLASH.cr().modify(|w| w.set_lock(true)); | ||
| 12 | } | ||
| 13 | pub(crate) unsafe fn unlock() { | ||
| 14 | // Wait, while the memory interface is busy. | ||
| 15 | wait_busy(); | ||
| 16 | |||
| 17 | // Unlock flash | ||
| 18 | if pac::FLASH.cr().read().lock() { | ||
| 19 | pac::FLASH.keyr().write_value(0x4567_0123); | ||
| 20 | pac::FLASH.keyr().write_value(0xCDEF_89AB); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | pub(crate) unsafe fn enable_blocking_write() { | ||
| 25 | assert_eq!(0, WRITE_SIZE % 4); | ||
| 26 | pac::FLASH.cr().write(|w| w.set_pg(true)); | ||
| 27 | } | ||
| 28 | |||
| 29 | pub(crate) unsafe fn disable_blocking_write() { | ||
| 30 | pac::FLASH.cr().write(|w| w.set_pg(false)); | ||
| 31 | } | ||
| 32 | |||
| 33 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { | ||
| 34 | let mut address = start_address; | ||
| 35 | for val in buf.chunks(4) { | ||
| 36 | write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into()))); | ||
| 37 | address += val.len() as u32; | ||
| 38 | |||
| 39 | // prevents parallelism errors | ||
| 40 | fence(Ordering::SeqCst); | ||
| 41 | } | ||
| 42 | |||
| 43 | wait_ready_blocking() | ||
| 44 | } | ||
| 45 | |||
| 46 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | ||
| 47 | let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; | ||
| 48 | |||
| 49 | #[cfg(feature = "defmt")] | ||
| 50 | defmt::trace!( | ||
| 51 | "STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}", | ||
| 52 | sector.start, | ||
| 53 | idx, | ||
| 54 | super::BANK1_REGION.erase_size | ||
| 55 | ); | ||
| 56 | |||
| 57 | wait_busy(); | ||
| 58 | clear_all_err(); | ||
| 59 | |||
| 60 | // Explicitly unlock before erase | ||
| 61 | unlock(); | ||
| 62 | |||
| 63 | interrupt::free(|_| { | ||
| 64 | #[cfg(feature = "defmt")] | ||
| 65 | { | ||
| 66 | let cr_before = pac::FLASH.cr().read(); | ||
| 67 | defmt::trace!("FLASH_CR before: 0x{:08x}", cr_before.0); | ||
| 68 | } | ||
| 69 | |||
| 70 | pac::FLASH.cr().modify(|w| { | ||
| 71 | w.set_per(true); | ||
| 72 | w.set_pnb(idx as u8); | ||
| 73 | w.set_strt(true); | ||
| 74 | }); | ||
| 75 | |||
| 76 | #[cfg(feature = "defmt")] | ||
| 77 | { | ||
| 78 | let cr_after = pac::FLASH.cr().read(); | ||
| 79 | defmt::trace!( | ||
| 80 | "FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}", | ||
| 81 | cr_after.0, | ||
| 82 | cr_after.per(), | ||
| 83 | cr_after.pnb(), | ||
| 84 | cr_after.strt() | ||
| 85 | ); | ||
| 86 | } | ||
| 87 | }); | ||
| 88 | |||
| 89 | let ret: Result<(), Error> = wait_ready_blocking(); | ||
| 90 | |||
| 91 | // Clear erase bit | ||
| 92 | pac::FLASH.cr().modify(|w| w.set_per(false)); | ||
| 93 | |||
| 94 | // Explicitly lock after erase | ||
| 95 | lock(); | ||
| 96 | |||
| 97 | // Extra wait to ensure operation completes | ||
| 98 | wait_busy(); | ||
| 99 | |||
| 100 | ret | ||
| 101 | } | ||
| 102 | |||
| 103 | pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { | ||
| 104 | while pac::FLASH.sr().read().bsy() {} | ||
| 105 | |||
| 106 | let sr = pac::FLASH.sr().read(); | ||
| 107 | |||
| 108 | if sr.progerr() { | ||
| 109 | return Err(Error::Prog); | ||
| 110 | } | ||
| 111 | |||
| 112 | if sr.wrperr() { | ||
| 113 | return Err(Error::Protected); | ||
| 114 | } | ||
| 115 | |||
| 116 | if sr.pgaerr() { | ||
| 117 | return Err(Error::Unaligned); | ||
| 118 | } | ||
| 119 | |||
| 120 | Ok(()) | ||
| 121 | } | ||
| 122 | |||
| 123 | pub(crate) unsafe fn clear_all_err() { | ||
| 124 | // read and write back the same value. | ||
| 125 | // This clears all "write 1 to clear" bits. | ||
| 126 | pac::FLASH.sr().modify(|_| {}); | ||
| 127 | } | ||
| 128 | |||
| 129 | fn wait_busy() { | ||
| 130 | while pac::FLASH.sr().read().bsy() {} | ||
| 131 | } | ||
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index b595938a6..60d00e766 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs | |||
| @@ -102,7 +102,13 @@ pub(super) unsafe fn blocking_write( | |||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | let mut address = base + offset; | 104 | let mut address = base + offset; |
| 105 | trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); | 105 | trace!( |
| 106 | "Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})", | ||
| 107 | bytes.len(), | ||
| 108 | address, | ||
| 109 | base, | ||
| 110 | offset | ||
| 111 | ); | ||
| 106 | 112 | ||
| 107 | for chunk in bytes.chunks(WRITE_SIZE) { | 113 | for chunk in bytes.chunks(WRITE_SIZE) { |
| 108 | write_chunk(address, chunk)?; | 114 | write_chunk(address, chunk)?; |
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index d026541a4..d7ba2f571 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs | |||
| @@ -44,7 +44,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { | 46 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { |
| 47 | let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; | ||
| 48 | wait_busy(); | 47 | wait_busy(); |
| 49 | clear_all_err(); | 48 | clear_all_err(); |
| 50 | 49 | ||
| @@ -54,9 +53,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 54 | #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] | 53 | #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] |
| 55 | w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); | 54 | w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); |
| 56 | #[cfg(flash_g0x0)] | 55 | #[cfg(flash_g0x0)] |
| 57 | w.set_pnb(idx as u16); | 56 | w.set_pnb(sector.index_in_bank as u16); |
| 58 | #[cfg(not(flash_g0x0))] | 57 | #[cfg(not(flash_g0x0))] |
| 59 | w.set_pnb(idx as u8); | 58 | w.set_pnb(sector.index_in_bank as u8); |
| 60 | w.set_strt(true); | 59 | w.set_strt(true); |
| 61 | }); | 60 | }); |
| 62 | }); | 61 | }); |
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 3e74d857a..39cd9b3a9 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs | |||
| @@ -99,6 +99,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is | |||
| 99 | #[cfg_attr(flash_f4, path = "f4.rs")] | 99 | #[cfg_attr(flash_f4, path = "f4.rs")] |
| 100 | #[cfg_attr(flash_f7, path = "f7.rs")] | 100 | #[cfg_attr(flash_f7, path = "f7.rs")] |
| 101 | #[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] | 101 | #[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] |
| 102 | #[cfg_attr(flash_c0, path = "c.rs")] | ||
| 102 | #[cfg_attr(flash_h7, path = "h7.rs")] | 103 | #[cfg_attr(flash_h7, path = "h7.rs")] |
| 103 | #[cfg_attr(flash_h7ab, path = "h7.rs")] | 104 | #[cfg_attr(flash_h7ab, path = "h7.rs")] |
| 104 | #[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")] | 105 | #[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")] |
| @@ -108,7 +109,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is | |||
| 108 | #[cfg_attr( | 109 | #[cfg_attr( |
| 109 | not(any( | 110 | not(any( |
| 110 | flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, | 111 | flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, |
| 111 | flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, | 112 | flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_c0, flash_h7, flash_h7ab, flash_u5, |
| 112 | flash_wba, flash_h50, flash_u0, flash_h5, | 113 | flash_wba, flash_h50, flash_u0, flash_h5, |
| 113 | )), | 114 | )), |
| 114 | path = "other.rs" | 115 | path = "other.rs" |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 4527e55b9..61e550ad4 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -98,6 +98,27 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | 100 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { |
| 101 | #[inline] | ||
| 102 | fn to_reload(reload: bool) -> i2c::vals::Reload { | ||
| 103 | if reload { | ||
| 104 | i2c::vals::Reload::NOT_COMPLETED | ||
| 105 | } else { | ||
| 106 | i2c::vals::Reload::COMPLETED | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Calculate total bytes in a group of operations | ||
| 111 | #[inline] | ||
| 112 | fn total_operation_bytes(operations: &[Operation<'_>]) -> usize { | ||
| 113 | operations | ||
| 114 | .iter() | ||
| 115 | .map(|op| match op { | ||
| 116 | Operation::Write(buf) => buf.len(), | ||
| 117 | Operation::Read(buf) => buf.len(), | ||
| 118 | }) | ||
| 119 | .sum() | ||
| 120 | } | ||
| 121 | |||
| 101 | pub(crate) fn init(&mut self, config: Config) { | 122 | pub(crate) fn init(&mut self, config: Config) { |
| 102 | self.info.regs.cr1().modify(|reg| { | 123 | self.info.regs.cr1().modify(|reg| { |
| 103 | reg.set_pe(false); | 124 | reg.set_pe(false); |
| @@ -147,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 147 | // `buffer`. The START bit can be set even if the bus | 168 | // `buffer`. The START bit can be set even if the bus |
| 148 | // is BUSY or I2C is in slave mode. | 169 | // is BUSY or I2C is in slave mode. |
| 149 | 170 | ||
| 150 | let reload = if reload { | ||
| 151 | i2c::vals::Reload::NOT_COMPLETED | ||
| 152 | } else { | ||
| 153 | i2c::vals::Reload::COMPLETED | ||
| 154 | }; | ||
| 155 | |||
| 156 | info.regs.cr2().modify(|w| { | 171 | info.regs.cr2().modify(|w| { |
| 157 | w.set_sadd(address.addr() << 1); | 172 | w.set_sadd(address.addr() << 1); |
| 158 | w.set_add10(address.add_mode()); | 173 | w.set_add10(address.add_mode()); |
| @@ -160,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 160 | w.set_nbytes(length as u8); | 175 | w.set_nbytes(length as u8); |
| 161 | w.set_start(true); | 176 | w.set_start(true); |
| 162 | w.set_autoend(stop.autoend()); | 177 | w.set_autoend(stop.autoend()); |
| 163 | w.set_reload(reload); | 178 | w.set_reload(Self::to_reload(reload)); |
| 164 | }); | 179 | }); |
| 165 | 180 | ||
| 166 | Ok(()) | 181 | Ok(()) |
| @@ -172,28 +187,25 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 172 | length: usize, | 187 | length: usize, |
| 173 | stop: Stop, | 188 | stop: Stop, |
| 174 | reload: bool, | 189 | reload: bool, |
| 190 | restart: bool, | ||
| 175 | timeout: Timeout, | 191 | timeout: Timeout, |
| 176 | ) -> Result<(), Error> { | 192 | ) -> Result<(), Error> { |
| 177 | assert!(length < 256); | 193 | assert!(length < 256); |
| 178 | 194 | ||
| 179 | // Wait for any previous address sequence to end | 195 | if !restart { |
| 180 | // automatically. This could be up to 50% of a bus | 196 | // Wait for any previous address sequence to end |
| 181 | // cycle (ie. up to 0.5/freq) | 197 | // automatically. This could be up to 50% of a bus |
| 182 | while info.regs.cr2().read().start() { | 198 | // cycle (ie. up to 0.5/freq) |
| 183 | timeout.check()?; | 199 | while info.regs.cr2().read().start() { |
| 184 | } | 200 | timeout.check()?; |
| 201 | } | ||
| 185 | 202 | ||
| 186 | // Wait for the bus to be free | 203 | // Wait for the bus to be free |
| 187 | while info.regs.isr().read().busy() { | 204 | while info.regs.isr().read().busy() { |
| 188 | timeout.check()?; | 205 | timeout.check()?; |
| 206 | } | ||
| 189 | } | 207 | } |
| 190 | 208 | ||
| 191 | let reload = if reload { | ||
| 192 | i2c::vals::Reload::NOT_COMPLETED | ||
| 193 | } else { | ||
| 194 | i2c::vals::Reload::COMPLETED | ||
| 195 | }; | ||
| 196 | |||
| 197 | // Set START and prepare to send `bytes`. The | 209 | // Set START and prepare to send `bytes`. The |
| 198 | // START bit can be set even if the bus is BUSY or | 210 | // START bit can be set even if the bus is BUSY or |
| 199 | // I2C is in slave mode. | 211 | // I2C is in slave mode. |
| @@ -204,28 +216,36 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 204 | w.set_nbytes(length as u8); | 216 | w.set_nbytes(length as u8); |
| 205 | w.set_start(true); | 217 | w.set_start(true); |
| 206 | w.set_autoend(stop.autoend()); | 218 | w.set_autoend(stop.autoend()); |
| 207 | w.set_reload(reload); | 219 | w.set_reload(Self::to_reload(reload)); |
| 208 | }); | 220 | }); |
| 209 | 221 | ||
| 210 | Ok(()) | 222 | Ok(()) |
| 211 | } | 223 | } |
| 212 | 224 | ||
| 213 | fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { | 225 | fn reload( |
| 226 | info: &'static Info, | ||
| 227 | length: usize, | ||
| 228 | will_reload: bool, | ||
| 229 | stop: Stop, | ||
| 230 | timeout: Timeout, | ||
| 231 | ) -> Result<(), Error> { | ||
| 214 | assert!(length < 256 && length > 0); | 232 | assert!(length < 256 && length > 0); |
| 215 | 233 | ||
| 216 | while !info.regs.isr().read().tcr() { | 234 | // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete) |
| 235 | // TCR occurs when RELOAD=1, TC occurs when RELOAD=0 | ||
| 236 | // Both indicate the peripheral is ready for the next transfer | ||
| 237 | loop { | ||
| 238 | let isr = info.regs.isr().read(); | ||
| 239 | if isr.tcr() || isr.tc() { | ||
| 240 | break; | ||
| 241 | } | ||
| 217 | timeout.check()?; | 242 | timeout.check()?; |
| 218 | } | 243 | } |
| 219 | 244 | ||
| 220 | let will_reload = if will_reload { | ||
| 221 | i2c::vals::Reload::NOT_COMPLETED | ||
| 222 | } else { | ||
| 223 | i2c::vals::Reload::COMPLETED | ||
| 224 | }; | ||
| 225 | |||
| 226 | info.regs.cr2().modify(|w| { | 245 | info.regs.cr2().modify(|w| { |
| 227 | w.set_nbytes(length as u8); | 246 | w.set_nbytes(length as u8); |
| 228 | w.set_reload(will_reload); | 247 | w.set_reload(Self::to_reload(will_reload)); |
| 248 | w.set_autoend(stop.autoend()); | ||
| 229 | }); | 249 | }); |
| 230 | 250 | ||
| 231 | Ok(()) | 251 | Ok(()) |
| @@ -369,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 369 | loop { | 389 | loop { |
| 370 | let isr = self.info.regs.isr().read(); | 390 | let isr = self.info.regs.isr().read(); |
| 371 | self.error_occurred(&isr, timeout)?; | 391 | self.error_occurred(&isr, timeout)?; |
| 372 | if isr.tc() { | 392 | // Wait for either TC or TCR - both indicate transfer completion |
| 393 | // TCR occurs when RELOAD=1, TC occurs when RELOAD=0 | ||
| 394 | if isr.tc() || isr.tcr() { | ||
| 373 | return Ok(()); | 395 | return Ok(()); |
| 374 | } | 396 | } |
| 375 | timeout.check()?; | 397 | timeout.check()?; |
| @@ -396,14 +418,20 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 396 | address, | 418 | address, |
| 397 | read.len().min(255), | 419 | read.len().min(255), |
| 398 | Stop::Automatic, | 420 | Stop::Automatic, |
| 399 | last_chunk_idx != 0, | 421 | last_chunk_idx != 0, // reload |
| 400 | restart, | 422 | restart, |
| 401 | timeout, | 423 | timeout, |
| 402 | )?; | 424 | )?; |
| 403 | 425 | ||
| 404 | for (number, chunk) in read.chunks_mut(255).enumerate() { | 426 | for (number, chunk) in read.chunks_mut(255).enumerate() { |
| 405 | if number != 0 { | 427 | if number != 0 { |
| 406 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 428 | Self::reload( |
| 429 | self.info, | ||
| 430 | chunk.len(), | ||
| 431 | number != last_chunk_idx, | ||
| 432 | Stop::Automatic, | ||
| 433 | timeout, | ||
| 434 | )?; | ||
| 407 | } | 435 | } |
| 408 | 436 | ||
| 409 | for byte in chunk { | 437 | for byte in chunk { |
| @@ -441,6 +469,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 441 | write.len().min(255), | 469 | write.len().min(255), |
| 442 | Stop::Software, | 470 | Stop::Software, |
| 443 | last_chunk_idx != 0, | 471 | last_chunk_idx != 0, |
| 472 | false, // restart | ||
| 444 | timeout, | 473 | timeout, |
| 445 | ) { | 474 | ) { |
| 446 | if send_stop { | 475 | if send_stop { |
| @@ -451,7 +480,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 451 | 480 | ||
| 452 | for (number, chunk) in write.chunks(255).enumerate() { | 481 | for (number, chunk) in write.chunks(255).enumerate() { |
| 453 | if number != 0 { | 482 | if number != 0 { |
| 454 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 483 | Self::reload( |
| 484 | self.info, | ||
| 485 | chunk.len(), | ||
| 486 | number != last_chunk_idx, | ||
| 487 | Stop::Software, | ||
| 488 | timeout, | ||
| 489 | )?; | ||
| 455 | } | 490 | } |
| 456 | 491 | ||
| 457 | for byte in chunk { | 492 | for byte in chunk { |
| @@ -507,9 +542,215 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 507 | /// | 542 | /// |
| 508 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction | 543 | /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction |
| 509 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 544 | pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 510 | let _ = addr; | 545 | if operations.is_empty() { |
| 511 | let _ = operations; | 546 | return Err(Error::ZeroLengthTransfer); |
| 512 | todo!() | 547 | } |
| 548 | |||
| 549 | let address = addr.into(); | ||
| 550 | let timeout = self.timeout(); | ||
| 551 | |||
| 552 | // Group consecutive operations of the same type | ||
| 553 | let mut op_idx = 0; | ||
| 554 | let mut is_first_group = true; | ||
| 555 | |||
| 556 | while op_idx < operations.len() { | ||
| 557 | // Determine the type of current group and find all consecutive operations of same type | ||
| 558 | let is_read = matches!(operations[op_idx], Operation::Read(_)); | ||
| 559 | let group_start = op_idx; | ||
| 560 | |||
| 561 | // Find end of this group (consecutive operations of same type) | ||
| 562 | while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read { | ||
| 563 | op_idx += 1; | ||
| 564 | } | ||
| 565 | let group_end = op_idx; | ||
| 566 | let is_last_group = op_idx >= operations.len(); | ||
| 567 | |||
| 568 | // Execute this group of operations | ||
| 569 | if is_read { | ||
| 570 | self.execute_read_group( | ||
| 571 | address, | ||
| 572 | &mut operations[group_start..group_end], | ||
| 573 | is_first_group, | ||
| 574 | is_last_group, | ||
| 575 | timeout, | ||
| 576 | )?; | ||
| 577 | } else { | ||
| 578 | self.execute_write_group( | ||
| 579 | address, | ||
| 580 | &operations[group_start..group_end], | ||
| 581 | is_first_group, | ||
| 582 | is_last_group, | ||
| 583 | timeout, | ||
| 584 | )?; | ||
| 585 | } | ||
| 586 | |||
| 587 | is_first_group = false; | ||
| 588 | } | ||
| 589 | |||
| 590 | Ok(()) | ||
| 591 | } | ||
| 592 | |||
| 593 | fn execute_write_group( | ||
| 594 | &mut self, | ||
| 595 | address: Address, | ||
| 596 | operations: &[Operation<'_>], | ||
| 597 | is_first_group: bool, | ||
| 598 | is_last_group: bool, | ||
| 599 | timeout: Timeout, | ||
| 600 | ) -> Result<(), Error> { | ||
| 601 | // Calculate total bytes across all operations in this group | ||
| 602 | let total_bytes = Self::total_operation_bytes(operations); | ||
| 603 | |||
| 604 | if total_bytes == 0 { | ||
| 605 | // Handle empty write group - just send address | ||
| 606 | if is_first_group { | ||
| 607 | Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; | ||
| 608 | } | ||
| 609 | if is_last_group { | ||
| 610 | self.master_stop(); | ||
| 611 | } | ||
| 612 | return Ok(()); | ||
| 613 | } | ||
| 614 | |||
| 615 | let mut total_remaining = total_bytes; | ||
| 616 | let mut first_chunk = true; | ||
| 617 | |||
| 618 | for operation in operations { | ||
| 619 | if let Operation::Write(buffer) = operation { | ||
| 620 | for chunk in buffer.chunks(255) { | ||
| 621 | let chunk_len = chunk.len(); | ||
| 622 | total_remaining -= chunk_len; | ||
| 623 | let is_last_chunk = total_remaining == 0; | ||
| 624 | let will_reload = !is_last_chunk; | ||
| 625 | |||
| 626 | if first_chunk { | ||
| 627 | // First chunk: initiate transfer | ||
| 628 | // If not first group, use RESTART instead of START | ||
| 629 | Self::master_write( | ||
| 630 | self.info, | ||
| 631 | address, | ||
| 632 | chunk_len, | ||
| 633 | Stop::Software, | ||
| 634 | will_reload, | ||
| 635 | !is_first_group, | ||
| 636 | timeout, | ||
| 637 | )?; | ||
| 638 | first_chunk = false; | ||
| 639 | } else { | ||
| 640 | // Subsequent chunks: use reload | ||
| 641 | // Always use Software stop for writes | ||
| 642 | Self::reload(self.info, chunk_len, will_reload, Stop::Software, timeout)?; | ||
| 643 | } | ||
| 644 | |||
| 645 | // Send data bytes | ||
| 646 | for byte in chunk { | ||
| 647 | self.wait_txis(timeout)?; | ||
| 648 | self.info.regs.txdr().write(|w| w.set_txdata(*byte)); | ||
| 649 | } | ||
| 650 | } | ||
| 651 | } | ||
| 652 | } | ||
| 653 | |||
| 654 | // Wait for transfer to complete | ||
| 655 | if is_last_group { | ||
| 656 | self.wait_tc(timeout)?; | ||
| 657 | self.master_stop(); | ||
| 658 | self.wait_stop(timeout)?; | ||
| 659 | } else { | ||
| 660 | // Wait for TC before next group (enables RESTART) | ||
| 661 | self.wait_tc(timeout)?; | ||
| 662 | } | ||
| 663 | |||
| 664 | Ok(()) | ||
| 665 | } | ||
| 666 | |||
| 667 | fn execute_read_group( | ||
| 668 | &mut self, | ||
| 669 | address: Address, | ||
| 670 | operations: &mut [Operation<'_>], | ||
| 671 | is_first_group: bool, | ||
| 672 | is_last_group: bool, | ||
| 673 | timeout: Timeout, | ||
| 674 | ) -> Result<(), Error> { | ||
| 675 | // Calculate total bytes across all operations in this group | ||
| 676 | let total_bytes = Self::total_operation_bytes(operations); | ||
| 677 | |||
| 678 | if total_bytes == 0 { | ||
| 679 | // Handle empty read group | ||
| 680 | if is_first_group { | ||
| 681 | Self::master_read( | ||
| 682 | self.info, | ||
| 683 | address, | ||
| 684 | 0, | ||
| 685 | if is_last_group { Stop::Automatic } else { Stop::Software }, | ||
| 686 | false, // reload | ||
| 687 | !is_first_group, | ||
| 688 | timeout, | ||
| 689 | )?; | ||
| 690 | } | ||
| 691 | if is_last_group { | ||
| 692 | self.wait_stop(timeout)?; | ||
| 693 | } | ||
| 694 | return Ok(()); | ||
| 695 | } | ||
| 696 | |||
| 697 | let mut total_remaining = total_bytes; | ||
| 698 | let mut first_chunk = true; | ||
| 699 | |||
| 700 | for operation in operations { | ||
| 701 | if let Operation::Read(buffer) = operation { | ||
| 702 | for chunk in buffer.chunks_mut(255) { | ||
| 703 | let chunk_len = chunk.len(); | ||
| 704 | total_remaining -= chunk_len; | ||
| 705 | let is_last_chunk = total_remaining == 0; | ||
| 706 | let will_reload = !is_last_chunk; | ||
| 707 | |||
| 708 | if first_chunk { | ||
| 709 | // First chunk: initiate transfer | ||
| 710 | let stop = if is_last_group && is_last_chunk { | ||
| 711 | Stop::Automatic | ||
| 712 | } else { | ||
| 713 | Stop::Software | ||
| 714 | }; | ||
| 715 | |||
| 716 | Self::master_read( | ||
| 717 | self.info, | ||
| 718 | address, | ||
| 719 | chunk_len, | ||
| 720 | stop, | ||
| 721 | will_reload, | ||
| 722 | !is_first_group, // restart if not first group | ||
| 723 | timeout, | ||
| 724 | )?; | ||
| 725 | first_chunk = false; | ||
| 726 | } else { | ||
| 727 | // Subsequent chunks: use reload | ||
| 728 | let stop = if is_last_group && is_last_chunk { | ||
| 729 | Stop::Automatic | ||
| 730 | } else { | ||
| 731 | Stop::Software | ||
| 732 | }; | ||
| 733 | Self::reload(self.info, chunk_len, will_reload, stop, timeout)?; | ||
| 734 | } | ||
| 735 | |||
| 736 | // Receive data bytes | ||
| 737 | for byte in chunk { | ||
| 738 | self.wait_rxne(timeout)?; | ||
| 739 | *byte = self.info.regs.rxdr().read().rxdata(); | ||
| 740 | } | ||
| 741 | } | ||
| 742 | } | ||
| 743 | } | ||
| 744 | |||
| 745 | // Wait for transfer to complete | ||
| 746 | if is_last_group { | ||
| 747 | self.wait_stop(timeout)?; | ||
| 748 | } | ||
| 749 | // For non-last read groups, don't wait for TC - the peripheral may hold SCL low | ||
| 750 | // in Software AUTOEND mode until the next START is issued. Just proceed directly | ||
| 751 | // to the next group which will issue RESTART and release the clock. | ||
| 752 | |||
| 753 | Ok(()) | ||
| 513 | } | 754 | } |
| 514 | 755 | ||
| 515 | /// Blocking write multiple buffers. | 756 | /// Blocking write multiple buffers. |
| @@ -531,6 +772,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 531 | first_length.min(255), | 772 | first_length.min(255), |
| 532 | Stop::Software, | 773 | Stop::Software, |
| 533 | (first_length > 255) || (last_slice_index != 0), | 774 | (first_length > 255) || (last_slice_index != 0), |
| 775 | false, // restart | ||
| 534 | timeout, | 776 | timeout, |
| 535 | ) { | 777 | ) { |
| 536 | self.master_stop(); | 778 | self.master_stop(); |
| @@ -552,6 +794,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 552 | self.info, | 794 | self.info, |
| 553 | slice_len.min(255), | 795 | slice_len.min(255), |
| 554 | (idx != last_slice_index) || (slice_len > 255), | 796 | (idx != last_slice_index) || (slice_len > 255), |
| 797 | Stop::Software, | ||
| 555 | timeout, | 798 | timeout, |
| 556 | ) { | 799 | ) { |
| 557 | if err != Error::Nack { | 800 | if err != Error::Nack { |
| @@ -567,6 +810,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 567 | self.info, | 810 | self.info, |
| 568 | chunk.len(), | 811 | chunk.len(), |
| 569 | (number != last_chunk_idx) || (idx != last_slice_index), | 812 | (number != last_chunk_idx) || (idx != last_slice_index), |
| 813 | Stop::Software, | ||
| 570 | timeout, | 814 | timeout, |
| 571 | ) { | 815 | ) { |
| 572 | if err != Error::Nack { | 816 | if err != Error::Nack { |
| @@ -610,6 +854,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 610 | first_slice: bool, | 854 | first_slice: bool, |
| 611 | last_slice: bool, | 855 | last_slice: bool, |
| 612 | send_stop: bool, | 856 | send_stop: bool, |
| 857 | restart: bool, | ||
| 613 | timeout: Timeout, | 858 | timeout: Timeout, |
| 614 | ) -> Result<(), Error> { | 859 | ) -> Result<(), Error> { |
| 615 | let total_len = write.len(); | 860 | let total_len = write.len(); |
| @@ -676,10 +921,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 676 | total_len.min(255), | 921 | total_len.min(255), |
| 677 | Stop::Software, | 922 | Stop::Software, |
| 678 | (total_len > 255) || !last_slice, | 923 | (total_len > 255) || !last_slice, |
| 924 | restart, | ||
| 679 | timeout, | 925 | timeout, |
| 680 | )?; | 926 | )?; |
| 681 | } else { | 927 | } else { |
| 682 | Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; | 928 | Self::reload( |
| 929 | self.info, | ||
| 930 | total_len.min(255), | ||
| 931 | (total_len > 255) || !last_slice, | ||
| 932 | Stop::Software, | ||
| 933 | timeout, | ||
| 934 | )?; | ||
| 683 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 935 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| 684 | } | 936 | } |
| 685 | } else if !(isr.tcr() || isr.tc()) { | 937 | } else if !(isr.tcr() || isr.tc()) { |
| @@ -688,9 +940,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 688 | } else if remaining_len == 0 { | 940 | } else if remaining_len == 0 { |
| 689 | return Poll::Ready(Ok(())); | 941 | return Poll::Ready(Ok(())); |
| 690 | } else { | 942 | } else { |
| 691 | let last_piece = (remaining_len <= 255) && last_slice; | 943 | if let Err(e) = Self::reload( |
| 692 | 944 | self.info, | |
| 693 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { | 945 | remaining_len.min(255), |
| 946 | (remaining_len > 255) || !last_slice, | ||
| 947 | Stop::Software, | ||
| 948 | timeout, | ||
| 949 | ) { | ||
| 694 | return Poll::Ready(Err(e)); | 950 | return Poll::Ready(Err(e)); |
| 695 | } | 951 | } |
| 696 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 952 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| @@ -702,10 +958,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 702 | .await?; | 958 | .await?; |
| 703 | 959 | ||
| 704 | dma_transfer.await; | 960 | dma_transfer.await; |
| 705 | if last_slice { | 961 | |
| 706 | // This should be done already | 962 | // Always wait for TC after DMA completes - needed for consecutive buffers |
| 707 | self.wait_tc(timeout)?; | 963 | self.wait_tc(timeout)?; |
| 708 | } | ||
| 709 | 964 | ||
| 710 | if last_slice & send_stop { | 965 | if last_slice & send_stop { |
| 711 | self.master_stop(); | 966 | self.master_stop(); |
| @@ -780,7 +1035,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 780 | address, | 1035 | address, |
| 781 | total_len.min(255), | 1036 | total_len.min(255), |
| 782 | Stop::Automatic, | 1037 | Stop::Automatic, |
| 783 | total_len > 255, | 1038 | total_len > 255, // reload |
| 784 | restart, | 1039 | restart, |
| 785 | timeout, | 1040 | timeout, |
| 786 | )?; | 1041 | )?; |
| @@ -788,12 +1043,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 788 | return Poll::Ready(Ok(())); | 1043 | return Poll::Ready(Ok(())); |
| 789 | } | 1044 | } |
| 790 | } else if isr.tcr() { | 1045 | } else if isr.tcr() { |
| 791 | // poll_fn was woken without an interrupt present | 1046 | // Transfer Complete Reload - need to set up next chunk |
| 792 | return Poll::Pending; | ||
| 793 | } else { | ||
| 794 | let last_piece = remaining_len <= 255; | 1047 | let last_piece = remaining_len <= 255; |
| 795 | 1048 | ||
| 796 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { | 1049 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) { |
| 797 | return Poll::Ready(Err(e)); | 1050 | return Poll::Ready(Err(e)); |
| 798 | } | 1051 | } |
| 799 | // Return here if we are on last chunk, | 1052 | // Return here if we are on last chunk, |
| @@ -802,6 +1055,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 802 | return Poll::Ready(Ok(())); | 1055 | return Poll::Ready(Ok(())); |
| 803 | } | 1056 | } |
| 804 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | 1057 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); |
| 1058 | } else { | ||
| 1059 | // poll_fn was woken without TCR interrupt | ||
| 1060 | return Poll::Pending; | ||
| 805 | } | 1061 | } |
| 806 | 1062 | ||
| 807 | remaining_len = remaining_len.saturating_sub(255); | 1063 | remaining_len = remaining_len.saturating_sub(255); |
| @@ -826,7 +1082,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 826 | self.write_internal(address.into(), write, true, timeout) | 1082 | self.write_internal(address.into(), write, true, timeout) |
| 827 | } else { | 1083 | } else { |
| 828 | timeout | 1084 | timeout |
| 829 | .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) | 1085 | .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout)) |
| 830 | .await | 1086 | .await |
| 831 | } | 1087 | } |
| 832 | } | 1088 | } |
| @@ -842,16 +1098,24 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 842 | if write.is_empty() { | 1098 | if write.is_empty() { |
| 843 | return Err(Error::ZeroLengthTransfer); | 1099 | return Err(Error::ZeroLengthTransfer); |
| 844 | } | 1100 | } |
| 845 | let mut iter = write.iter(); | ||
| 846 | 1101 | ||
| 1102 | let mut iter = write.iter(); | ||
| 847 | let mut first = true; | 1103 | let mut first = true; |
| 848 | let mut current = iter.next(); | 1104 | let mut current = iter.next(); |
| 1105 | |||
| 849 | while let Some(c) = current { | 1106 | while let Some(c) = current { |
| 850 | let next = iter.next(); | 1107 | let next = iter.next(); |
| 851 | let is_last = next.is_none(); | 1108 | let is_last = next.is_none(); |
| 852 | 1109 | ||
| 853 | let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); | 1110 | let fut = self.write_dma_internal( |
| 1111 | address, c, first, // first_slice | ||
| 1112 | is_last, // last_slice | ||
| 1113 | is_last, // send_stop (only on last buffer) | ||
| 1114 | false, // restart (false for all - they're one continuous write) | ||
| 1115 | timeout, | ||
| 1116 | ); | ||
| 854 | timeout.with(fut).await?; | 1117 | timeout.with(fut).await?; |
| 1118 | |||
| 855 | first = false; | 1119 | first = false; |
| 856 | current = next; | 1120 | current = next; |
| 857 | } | 1121 | } |
| @@ -881,7 +1145,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 881 | if write.is_empty() { | 1145 | if write.is_empty() { |
| 882 | self.write_internal(address.into(), write, false, timeout)?; | 1146 | self.write_internal(address.into(), write, false, timeout)?; |
| 883 | } else { | 1147 | } else { |
| 884 | let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); | 1148 | let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout); |
| 885 | timeout.with(fut).await?; | 1149 | timeout.with(fut).await?; |
| 886 | } | 1150 | } |
| 887 | 1151 | ||
| @@ -903,9 +1167,299 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 903 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { | 1167 | pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 904 | #[cfg(all(feature = "low-power", stm32wlex))] | 1168 | #[cfg(all(feature = "low-power", stm32wlex))] |
| 905 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); | 1169 | let _device_busy = crate::low_power::DeviceBusy::new_stop1(); |
| 906 | let _ = addr; | 1170 | |
| 907 | let _ = operations; | 1171 | if operations.is_empty() { |
| 908 | todo!() | 1172 | return Err(Error::ZeroLengthTransfer); |
| 1173 | } | ||
| 1174 | |||
| 1175 | let address = addr.into(); | ||
| 1176 | let timeout = self.timeout(); | ||
| 1177 | |||
| 1178 | // Group consecutive operations of the same type | ||
| 1179 | let mut op_idx = 0; | ||
| 1180 | let mut is_first_group = true; | ||
| 1181 | |||
| 1182 | while op_idx < operations.len() { | ||
| 1183 | // Determine the type of current group and find all consecutive operations of same type | ||
| 1184 | let is_read = matches!(operations[op_idx], Operation::Read(_)); | ||
| 1185 | let group_start = op_idx; | ||
| 1186 | |||
| 1187 | // Find end of this group (consecutive operations of same type) | ||
| 1188 | while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read { | ||
| 1189 | op_idx += 1; | ||
| 1190 | } | ||
| 1191 | let group_end = op_idx; | ||
| 1192 | let is_last_group = op_idx >= operations.len(); | ||
| 1193 | |||
| 1194 | // Execute this group of operations | ||
| 1195 | if is_read { | ||
| 1196 | self.execute_read_group_async( | ||
| 1197 | address, | ||
| 1198 | &mut operations[group_start..group_end], | ||
| 1199 | is_first_group, | ||
| 1200 | is_last_group, | ||
| 1201 | timeout, | ||
| 1202 | ) | ||
| 1203 | .await?; | ||
| 1204 | } else { | ||
| 1205 | self.execute_write_group_async( | ||
| 1206 | address, | ||
| 1207 | &operations[group_start..group_end], | ||
| 1208 | is_first_group, | ||
| 1209 | is_last_group, | ||
| 1210 | timeout, | ||
| 1211 | ) | ||
| 1212 | .await?; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | is_first_group = false; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | Ok(()) | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | async fn execute_write_group_async( | ||
| 1222 | &mut self, | ||
| 1223 | address: Address, | ||
| 1224 | operations: &[Operation<'_>], | ||
| 1225 | is_first_group: bool, | ||
| 1226 | is_last_group: bool, | ||
| 1227 | timeout: Timeout, | ||
| 1228 | ) -> Result<(), Error> { | ||
| 1229 | // Calculate total bytes across all operations in this group | ||
| 1230 | let total_bytes = Self::total_operation_bytes(operations); | ||
| 1231 | |||
| 1232 | if total_bytes == 0 { | ||
| 1233 | // Handle empty write group using blocking call | ||
| 1234 | if is_first_group { | ||
| 1235 | Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; | ||
| 1236 | } | ||
| 1237 | if is_last_group { | ||
| 1238 | self.master_stop(); | ||
| 1239 | } | ||
| 1240 | return Ok(()); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | // Collect all write buffers | ||
| 1244 | let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new(); | ||
| 1245 | for operation in operations { | ||
| 1246 | if let Operation::Write(buffer) = operation { | ||
| 1247 | if !buffer.is_empty() { | ||
| 1248 | let _ = write_buffers.push(buffer); | ||
| 1249 | } | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | if write_buffers.is_empty() { | ||
| 1254 | return Ok(()); | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | // Send each buffer using DMA | ||
| 1258 | let num_buffers = write_buffers.len(); | ||
| 1259 | for (idx, buffer) in write_buffers.iter().enumerate() { | ||
| 1260 | let is_first_buffer = idx == 0; | ||
| 1261 | let is_last_buffer = idx == num_buffers - 1; | ||
| 1262 | |||
| 1263 | let fut = self.write_dma_internal( | ||
| 1264 | address, | ||
| 1265 | buffer, | ||
| 1266 | is_first_buffer, // first_slice | ||
| 1267 | is_last_buffer, // last_slice | ||
| 1268 | is_last_buffer && is_last_group, // send_stop | ||
| 1269 | is_first_buffer && !is_first_group, // restart (only for first buffer if not first group) | ||
| 1270 | timeout, | ||
| 1271 | ); | ||
| 1272 | timeout.with(fut).await?; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | Ok(()) | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | async fn execute_read_group_async( | ||
| 1279 | &mut self, | ||
| 1280 | address: Address, | ||
| 1281 | operations: &mut [Operation<'_>], | ||
| 1282 | is_first_group: bool, | ||
| 1283 | is_last_group: bool, | ||
| 1284 | timeout: Timeout, | ||
| 1285 | ) -> Result<(), Error> { | ||
| 1286 | // Calculate total bytes across all operations in this group | ||
| 1287 | let total_bytes = Self::total_operation_bytes(operations); | ||
| 1288 | |||
| 1289 | if total_bytes == 0 { | ||
| 1290 | // Handle empty read group using blocking call | ||
| 1291 | if is_first_group { | ||
| 1292 | Self::master_read( | ||
| 1293 | self.info, | ||
| 1294 | address, | ||
| 1295 | 0, | ||
| 1296 | if is_last_group { Stop::Automatic } else { Stop::Software }, | ||
| 1297 | false, // reload | ||
| 1298 | !is_first_group, | ||
| 1299 | timeout, | ||
| 1300 | )?; | ||
| 1301 | } | ||
| 1302 | if is_last_group { | ||
| 1303 | self.wait_stop(timeout)?; | ||
| 1304 | } | ||
| 1305 | return Ok(()); | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | // Use DMA for read operations - need to handle multiple buffers | ||
| 1309 | let restart = !is_first_group; | ||
| 1310 | let mut total_remaining = total_bytes; | ||
| 1311 | let mut is_first_in_group = true; | ||
| 1312 | |||
| 1313 | for operation in operations { | ||
| 1314 | if let Operation::Read(buffer) = operation { | ||
| 1315 | if buffer.is_empty() { | ||
| 1316 | // Skip empty buffers | ||
| 1317 | continue; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | let buf_len = buffer.len(); | ||
| 1321 | total_remaining -= buf_len; | ||
| 1322 | let is_last_in_group = total_remaining == 0; | ||
| 1323 | |||
| 1324 | // Perform DMA read | ||
| 1325 | if is_first_in_group { | ||
| 1326 | // First buffer: use read_dma_internal which handles restart properly | ||
| 1327 | // Only use Automatic stop if this is the last buffer in the last group | ||
| 1328 | let stop_mode = if is_last_group && is_last_in_group { | ||
| 1329 | Stop::Automatic | ||
| 1330 | } else { | ||
| 1331 | Stop::Software | ||
| 1332 | }; | ||
| 1333 | |||
| 1334 | // We need a custom DMA read that respects our stop mode | ||
| 1335 | self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout) | ||
| 1336 | .await?; | ||
| 1337 | is_first_in_group = false; | ||
| 1338 | } else { | ||
| 1339 | // Subsequent buffers: need to reload and continue | ||
| 1340 | let stop_mode = if is_last_group && is_last_in_group { | ||
| 1341 | Stop::Automatic | ||
| 1342 | } else { | ||
| 1343 | Stop::Software | ||
| 1344 | }; | ||
| 1345 | |||
| 1346 | self.read_dma_group_internal( | ||
| 1347 | address, buffer, false, // no restart for subsequent buffers in same group | ||
| 1348 | stop_mode, timeout, | ||
| 1349 | ) | ||
| 1350 | .await?; | ||
| 1351 | } | ||
| 1352 | } | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | // Wait for transfer to complete | ||
| 1356 | if is_last_group { | ||
| 1357 | self.wait_stop(timeout)?; | ||
| 1358 | } | ||
| 1359 | |||
| 1360 | Ok(()) | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | /// Internal DMA read helper for transaction groups | ||
| 1364 | async fn read_dma_group_internal( | ||
| 1365 | &mut self, | ||
| 1366 | address: Address, | ||
| 1367 | buffer: &mut [u8], | ||
| 1368 | restart: bool, | ||
| 1369 | stop_mode: Stop, | ||
| 1370 | timeout: Timeout, | ||
| 1371 | ) -> Result<(), Error> { | ||
| 1372 | let total_len = buffer.len(); | ||
| 1373 | |||
| 1374 | let dma_transfer = unsafe { | ||
| 1375 | let regs = self.info.regs; | ||
| 1376 | regs.cr1().modify(|w| { | ||
| 1377 | w.set_rxdmaen(true); | ||
| 1378 | w.set_tcie(true); | ||
| 1379 | w.set_nackie(true); | ||
| 1380 | w.set_errie(true); | ||
| 1381 | }); | ||
| 1382 | let src = regs.rxdr().as_ptr() as *mut u8; | ||
| 1383 | |||
| 1384 | self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) | ||
| 1385 | }; | ||
| 1386 | |||
| 1387 | let mut remaining_len = total_len; | ||
| 1388 | |||
| 1389 | let on_drop = OnDrop::new(|| { | ||
| 1390 | let regs = self.info.regs; | ||
| 1391 | regs.cr1().modify(|w| { | ||
| 1392 | w.set_rxdmaen(false); | ||
| 1393 | w.set_tcie(false); | ||
| 1394 | w.set_nackie(false); | ||
| 1395 | w.set_errie(false); | ||
| 1396 | }); | ||
| 1397 | regs.icr().write(|w| { | ||
| 1398 | w.set_nackcf(true); | ||
| 1399 | w.set_berrcf(true); | ||
| 1400 | w.set_arlocf(true); | ||
| 1401 | w.set_ovrcf(true); | ||
| 1402 | }); | ||
| 1403 | }); | ||
| 1404 | |||
| 1405 | poll_fn(|cx| { | ||
| 1406 | self.state.waker.register(cx.waker()); | ||
| 1407 | |||
| 1408 | let isr = self.info.regs.isr().read(); | ||
| 1409 | |||
| 1410 | if isr.nackf() { | ||
| 1411 | return Poll::Ready(Err(Error::Nack)); | ||
| 1412 | } | ||
| 1413 | if isr.arlo() { | ||
| 1414 | return Poll::Ready(Err(Error::Arbitration)); | ||
| 1415 | } | ||
| 1416 | if isr.berr() { | ||
| 1417 | return Poll::Ready(Err(Error::Bus)); | ||
| 1418 | } | ||
| 1419 | if isr.ovr() { | ||
| 1420 | return Poll::Ready(Err(Error::Overrun)); | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | if remaining_len == total_len { | ||
| 1424 | Self::master_read( | ||
| 1425 | self.info, | ||
| 1426 | address, | ||
| 1427 | total_len.min(255), | ||
| 1428 | stop_mode, | ||
| 1429 | total_len > 255, // reload | ||
| 1430 | restart, | ||
| 1431 | timeout, | ||
| 1432 | )?; | ||
| 1433 | if total_len <= 255 { | ||
| 1434 | return Poll::Ready(Ok(())); | ||
| 1435 | } | ||
| 1436 | } else if isr.tcr() { | ||
| 1437 | // Transfer Complete Reload - need to set up next chunk | ||
| 1438 | let last_piece = remaining_len <= 255; | ||
| 1439 | |||
| 1440 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) { | ||
| 1441 | return Poll::Ready(Err(e)); | ||
| 1442 | } | ||
| 1443 | // Return here if we are on last chunk, | ||
| 1444 | // end of transfer will be awaited with the DMA below | ||
| 1445 | if last_piece { | ||
| 1446 | return Poll::Ready(Ok(())); | ||
| 1447 | } | ||
| 1448 | self.info.regs.cr1().modify(|w| w.set_tcie(true)); | ||
| 1449 | } else { | ||
| 1450 | // poll_fn was woken without TCR interrupt | ||
| 1451 | return Poll::Pending; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | remaining_len = remaining_len.saturating_sub(255); | ||
| 1455 | Poll::Pending | ||
| 1456 | }) | ||
| 1457 | .await?; | ||
| 1458 | |||
| 1459 | dma_transfer.await; | ||
| 1460 | drop(on_drop); | ||
| 1461 | |||
| 1462 | Ok(()) | ||
| 909 | } | 1463 | } |
| 910 | } | 1464 | } |
| 911 | 1465 | ||
| @@ -1043,7 +1597,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1043 | if number == 0 { | 1597 | if number == 0 { |
| 1044 | Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); | 1598 | Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); |
| 1045 | } else { | 1599 | } else { |
| 1046 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 1600 | Self::reload( |
| 1601 | self.info, | ||
| 1602 | chunk.len(), | ||
| 1603 | number != last_chunk_idx, | ||
| 1604 | Stop::Software, | ||
| 1605 | timeout, | ||
| 1606 | )?; | ||
| 1047 | } | 1607 | } |
| 1048 | 1608 | ||
| 1049 | let mut index = 0; | 1609 | let mut index = 0; |
| @@ -1092,7 +1652,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1092 | if number == 0 { | 1652 | if number == 0 { |
| 1093 | Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); | 1653 | Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); |
| 1094 | } else { | 1654 | } else { |
| 1095 | Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; | 1655 | Self::reload( |
| 1656 | self.info, | ||
| 1657 | chunk.len(), | ||
| 1658 | number != last_chunk_idx, | ||
| 1659 | Stop::Software, | ||
| 1660 | timeout, | ||
| 1661 | )?; | ||
| 1096 | } | 1662 | } |
| 1097 | 1663 | ||
| 1098 | let mut index = 0; | 1664 | let mut index = 0; |
| @@ -1228,7 +1794,13 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1228 | Poll::Pending | 1794 | Poll::Pending |
| 1229 | } else if isr.tcr() { | 1795 | } else if isr.tcr() { |
| 1230 | let is_last_slice = remaining_len <= 255; | 1796 | let is_last_slice = remaining_len <= 255; |
| 1231 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { | 1797 | if let Err(e) = Self::reload( |
| 1798 | self.info, | ||
| 1799 | remaining_len.min(255), | ||
| 1800 | !is_last_slice, | ||
| 1801 | Stop::Software, | ||
| 1802 | timeout, | ||
| 1803 | ) { | ||
| 1232 | return Poll::Ready(Err(e)); | 1804 | return Poll::Ready(Err(e)); |
| 1233 | } | 1805 | } |
| 1234 | remaining_len = remaining_len.saturating_sub(255); | 1806 | remaining_len = remaining_len.saturating_sub(255); |
| @@ -1292,7 +1864,13 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1292 | Poll::Pending | 1864 | Poll::Pending |
| 1293 | } else if isr.tcr() { | 1865 | } else if isr.tcr() { |
| 1294 | let is_last_slice = remaining_len <= 255; | 1866 | let is_last_slice = remaining_len <= 255; |
| 1295 | if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { | 1867 | if let Err(e) = Self::reload( |
| 1868 | self.info, | ||
| 1869 | remaining_len.min(255), | ||
| 1870 | !is_last_slice, | ||
| 1871 | Stop::Software, | ||
| 1872 | timeout, | ||
| 1873 | ) { | ||
| 1296 | return Poll::Ready(Err(e)); | 1874 | return Poll::Ready(Err(e)); |
| 1297 | } | 1875 | } |
| 1298 | remaining_len = remaining_len.saturating_sub(255); | 1876 | remaining_len = remaining_len.saturating_sub(255); |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 680edf433..6e492946a 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -658,3 +658,17 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 658 | p | 658 | p |
| 659 | }) | 659 | }) |
| 660 | } | 660 | } |
| 661 | |||
| 662 | /// Performs a busy-wait delay for a specified number of microseconds. | ||
| 663 | #[allow(unused)] | ||
| 664 | pub(crate) fn block_for_us(us: u64) { | ||
| 665 | cfg_if::cfg_if! { | ||
| 666 | // this does strange things on stm32wlx in low power mode depending on exactly when it's called | ||
| 667 | // as in sometimes 15 us (1 tick) would take > 20 seconds. | ||
| 668 | if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { | ||
| 669 | embassy_time::block_for(embassy_time::Duration::from_micros(us)); | ||
| 670 | } else { | ||
| 671 | cortex_m::asm::delay(unsafe { rcc::get_freqs().sys.to_hertz().unwrap().0 as u64 * us / 1_000_000 } as u32); | ||
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index ac8d5de21..4a55f5bd3 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -4,19 +4,12 @@ | |||
| 4 | use embassy_hal_internal::PeripheralType; | 4 | use embassy_hal_internal::PeripheralType; |
| 5 | 5 | ||
| 6 | use crate::Peri; | 6 | use crate::Peri; |
| 7 | #[cfg(opamp_v5)] | ||
| 8 | use crate::block_for_us; | ||
| 7 | use crate::pac::opamp::vals::*; | 9 | use crate::pac::opamp::vals::*; |
| 8 | #[cfg(not(any(stm32g4, stm32f3)))] | 10 | #[cfg(not(any(stm32g4, stm32f3)))] |
| 9 | use crate::rcc::RccInfo; | 11 | use crate::rcc::RccInfo; |
| 10 | 12 | ||
| 11 | /// Performs a busy-wait delay for a specified number of microseconds. | ||
| 12 | #[cfg(opamp_v5)] | ||
| 13 | fn blocking_delay_ms(ms: u32) { | ||
| 14 | #[cfg(feature = "time")] | ||
| 15 | embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); | ||
| 16 | #[cfg(not(feature = "time"))] | ||
| 17 | cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms); | ||
| 18 | } | ||
| 19 | |||
| 20 | /// Gain | 13 | /// Gain |
| 21 | #[allow(missing_docs)] | 14 | #[allow(missing_docs)] |
| 22 | #[derive(Clone, Copy)] | 15 | #[derive(Clone, Copy)] |
| @@ -439,7 +432,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 439 | 432 | ||
| 440 | // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize | 433 | // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize |
| 441 | // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 | 434 | // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 |
| 442 | blocking_delay_ms(2); | 435 | block_for_us(2_000); |
| 443 | 436 | ||
| 444 | if !T::regs().csr().read().calout() { | 437 | if !T::regs().csr().read().calout() { |
| 445 | if mid == 0 { | 438 | if mid == 0 { |
