aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-24 21:28:58 -0600
committerxoviat <[email protected]>2025-11-24 21:28:58 -0600
commitee14305d152273254571d2a5a8192fad26f3ab73 (patch)
tree80ee08b08ddb82fe712da50b0a0859d4ded6b9b9 /embassy-stm32/src
parent461681028681930e50f41ee00154ac3e1886ebca (diff)
parent5ffb3698541674d57fddb22044ac0f06397c6113 (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into xspi
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/adc/adc4.rs497
-rw-r--r--embassy-stm32/src/adc/c0.rs537
-rw-r--r--embassy-stm32/src/adc/f1.rs45
-rw-r--r--embassy-stm32/src/adc/f3.rs50
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs7
-rw-r--r--embassy-stm32/src/adc/g4.rs789
-rw-r--r--embassy-stm32/src/adc/injected.rs44
-rw-r--r--embassy-stm32/src/adc/mod.rs383
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs180
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs432
-rw-r--r--embassy-stm32/src/adc/v1.rs59
-rw-r--r--embassy-stm32/src/adc/v2.rs299
-rw-r--r--embassy-stm32/src/adc/v3.rs849
-rw-r--r--embassy-stm32/src/adc/v4.rs562
-rw-r--r--embassy-stm32/src/adc/watchdog_v1.rs6
-rw-r--r--embassy-stm32/src/backup_sram.rs28
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs12
-rw-r--r--embassy-stm32/src/can/fd/config.rs15
-rw-r--r--embassy-stm32/src/can/fdcan.rs27
-rw-r--r--embassy-stm32/src/can/util.rs2
-rw-r--r--embassy-stm32/src/crc/v1.rs2
-rw-r--r--embassy-stm32/src/crc/v2v3.rs4
-rw-r--r--embassy-stm32/src/cryp/mod.rs10
-rw-r--r--embassy-stm32/src/dac/mod.rs2
-rw-r--r--embassy-stm32/src/dcmi.rs2
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs20
-rw-r--r--embassy-stm32/src/dma/gpdma/mod.rs16
-rw-r--r--embassy-stm32/src/dma/gpdma/ringbuffered.rs14
-rw-r--r--embassy-stm32/src/dma/mod.rs72
-rw-r--r--embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs2
-rw-r--r--embassy-stm32/src/dsihost.rs31
-rw-r--r--embassy-stm32/src/dts/mod.rs2
-rw-r--r--embassy-stm32/src/dts/tsel.rs17
-rw-r--r--embassy-stm32/src/eth/generic_phy.rs64
-rw-r--r--embassy-stm32/src/eth/mod.rs29
-rw-r--r--embassy-stm32/src/eth/sma/mod.rs42
-rw-r--r--embassy-stm32/src/eth/sma/v1.rs102
-rw-r--r--embassy-stm32/src/eth/sma/v2.rs94
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs265
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs2
-rw-r--r--embassy-stm32/src/eth/v1/tx_desc.rs2
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs201
-rw-r--r--embassy-stm32/src/exti.rs165
-rw-r--r--embassy-stm32/src/flash/asynch.rs8
-rw-r--r--embassy-stm32/src/flash/c.rs131
-rw-r--r--embassy-stm32/src/flash/common.rs16
-rw-r--r--embassy-stm32/src/flash/eeprom.rs2
-rw-r--r--embassy-stm32/src/flash/f0.rs2
-rw-r--r--embassy-stm32/src/flash/f1f3.rs2
-rw-r--r--embassy-stm32/src/flash/f2.rs4
-rw-r--r--embassy-stm32/src/flash/f4.rs24
-rw-r--r--embassy-stm32/src/flash/f7.rs12
-rw-r--r--embassy-stm32/src/flash/g.rs23
-rw-r--r--embassy-stm32/src/flash/h5.rs2
-rw-r--r--embassy-stm32/src/flash/h50.rs2
-rw-r--r--embassy-stm32/src/flash/h7.rs194
-rw-r--r--embassy-stm32/src/flash/l.rs30
-rw-r--r--embassy-stm32/src/flash/mod.rs7
-rw-r--r--embassy-stm32/src/flash/u0.rs2
-rw-r--r--embassy-stm32/src/flash/u5.rs2
-rw-r--r--embassy-stm32/src/fmc.rs38
-rw-r--r--embassy-stm32/src/gpio.rs67
-rw-r--r--embassy-stm32/src/hash/mod.rs8
-rw-r--r--embassy-stm32/src/hrtim/mod.rs87
-rw-r--r--embassy-stm32/src/hsem/mod.rs287
-rw-r--r--embassy-stm32/src/hspi/mod.rs2
-rw-r--r--embassy-stm32/src/i2c/config.rs8
-rw-r--r--embassy-stm32/src/i2c/mod.rs106
-rw-r--r--embassy-stm32/src/i2c/v1.rs1088
-rw-r--r--embassy-stm32/src/i2c/v2.rs734
-rw-r--r--embassy-stm32/src/i2s.rs7
-rw-r--r--embassy-stm32/src/ipcc.rs252
-rw-r--r--embassy-stm32/src/lcd.rs510
-rw-r--r--embassy-stm32/src/lib.rs65
-rw-r--r--embassy-stm32/src/low_power.rs316
-rw-r--r--embassy-stm32/src/lptim/pwm.rs6
-rw-r--r--embassy-stm32/src/ltdc.rs2
-rw-r--r--embassy-stm32/src/opamp.rs15
-rw-r--r--embassy-stm32/src/ospi/mod.rs6
-rw-r--r--embassy-stm32/src/qspi/mod.rs2
-rw-r--r--embassy-stm32/src/rcc/bd.rs140
-rw-r--r--embassy-stm32/src/rcc/f247.rs4
-rw-r--r--embassy-stm32/src/rcc/h.rs5
-rw-r--r--embassy-stm32/src/rcc/l.rs8
-rw-r--r--embassy-stm32/src/rcc/mco.rs14
-rw-r--r--embassy-stm32/src/rcc/mod.rs101
-rw-r--r--embassy-stm32/src/rcc/n6.rs1046
-rw-r--r--embassy-stm32/src/rcc/u5.rs9
-rw-r--r--embassy-stm32/src/rcc/wba.rs9
-rw-r--r--embassy-stm32/src/rng.rs2
-rw-r--r--embassy-stm32/src/rtc/low_power.rs82
-rw-r--r--embassy-stm32/src/rtc/mod.rs121
-rw-r--r--embassy-stm32/src/rtc/v2.rs2
-rw-r--r--embassy-stm32/src/rtc/v3.rs8
-rw-r--r--embassy-stm32/src/sai/mod.rs10
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs16
-rw-r--r--embassy-stm32/src/spdifrx/mod.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs155
-rw-r--r--embassy-stm32/src/time_driver.rs155
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs127
-rw-r--r--embassy-stm32/src/timer/input_capture.rs3
-rw-r--r--embassy-stm32/src/timer/low_level.rs320
-rw-r--r--embassy-stm32/src/timer/mod.rs4
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs2
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs3
-rw-r--r--embassy-stm32/src/timer/qei.rs2
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs224
-rw-r--r--embassy-stm32/src/tsc/acquisition_banks.rs4
-rw-r--r--embassy-stm32/src/tsc/pin_groups.rs4
-rw-r--r--embassy-stm32/src/ucpd.rs7
-rw-r--r--embassy-stm32/src/uid.rs4
-rw-r--r--embassy-stm32/src/usart/buffered.rs8
-rw-r--r--embassy-stm32/src/usart/mod.rs8
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs40
-rw-r--r--embassy-stm32/src/usb/otg.rs10
-rw-r--r--embassy-stm32/src/usb/usb.rs4
-rw-r--r--embassy-stm32/src/vrefbuf/mod.rs11
-rw-r--r--embassy-stm32/src/wdg/mod.rs2
-rw-r--r--embassy-stm32/src/xspi/mod.rs6
120 files changed, 8490 insertions, 4246 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 255dc7956..453513309 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -4,8 +4,8 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR
4#[cfg(stm32wba)] 4#[cfg(stm32wba)]
5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; 5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel};
6 6
7use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; 7use super::blocking_delay_us;
8use crate::dma::Transfer; 8use crate::adc::ConversionMode;
9#[cfg(stm32u5)] 9#[cfg(stm32u5)]
10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; 10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
11#[cfg(stm32wba)] 11#[cfg(stm32wba)]
@@ -15,7 +15,7 @@ pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4S
15#[cfg(stm32wba)] 15#[cfg(stm32wba)]
16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; 16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime};
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{pac, rcc, Peri}; 18use crate::{Peri, pac, rcc};
19 19
20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
21 21
@@ -24,56 +24,24 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
24/// VREF voltage used for factory calibration of VREFINTCAL register. 24/// VREF voltage used for factory calibration of VREFINTCAL register.
25pub const VREF_CALIB_MV: u32 = 3300; 25pub const VREF_CALIB_MV: u32 = 3300;
26 26
27const VREF_CHANNEL: u8 = 0; 27impl<'d, T: Instance> super::SealedSpecialConverter<super::VrefInt> for Adc4<'d, T> {
28const VCORE_CHANNEL: u8 = 12; 28 const CHANNEL: u8 = 0;
29const TEMP_CHANNEL: u8 = 13;
30const VBAT_CHANNEL: u8 = 14;
31const DAC_CHANNEL: u8 = 21;
32
33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
34/// Internal voltage reference channel.
35pub struct VrefInt;
36impl<T: Instance> AdcChannel<T> for VrefInt {}
37impl<T: Instance> SealedAdcChannel<T> for VrefInt {
38 fn channel(&self) -> u8 {
39 VREF_CHANNEL
40 }
41} 29}
42 30
43/// Internal temperature channel. 31impl<'d, T: Instance> super::SealedSpecialConverter<super::Temperature> for Adc4<'d, T> {
44pub struct Temperature; 32 const CHANNEL: u8 = 13;
45impl<T: Instance> AdcChannel<T> for Temperature {}
46impl<T: Instance> SealedAdcChannel<T> for Temperature {
47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL
49 }
50} 33}
51 34
52/// Internal battery voltage channel. 35impl<'d, T: Instance> super::SealedSpecialConverter<super::Vcore> for Adc4<'d, T> {
53pub struct Vbat; 36 const CHANNEL: u8 = 12;
54impl<T: Instance> AdcChannel<T> for Vbat {}
55impl<T: Instance> SealedAdcChannel<T> for Vbat {
56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL
58 }
59} 37}
60 38
61/// Internal DAC channel. 39impl<'d, T: Instance> super::SealedSpecialConverter<super::Vbat> for Adc4<'d, T> {
62pub struct Dac; 40 const CHANNEL: u8 = 14;
63impl<T: Instance> AdcChannel<T> for Dac {}
64impl<T: Instance> SealedAdcChannel<T> for Dac {
65 fn channel(&self) -> u8 {
66 DAC_CHANNEL
67 }
68} 41}
69 42
70/// Internal Vcore channel. 43impl<'d, T: Instance> super::SealedSpecialConverter<super::Dac> for Adc4<'d, T> {
71pub struct Vcore; 44 const CHANNEL: u8 = 21;
72impl<T: Instance> AdcChannel<T> for Vcore {}
73impl<T: Instance> SealedAdcChannel<T> for Vcore {
74 fn channel(&self) -> u8 {
75 VCORE_CHANNEL
76 }
77} 45}
78 46
79#[derive(Copy, Clone)] 47#[derive(Copy, Clone)]
@@ -108,71 +76,17 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
108 } 76 }
109} 77}
110 78
111// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 79fn from_ker_ck(frequency: Hertz) -> Presc {
112// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 80 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
113#[allow(unused)] 81 match raw_prescaler {
114enum Prescaler { 82 0 => Presc::DIV1,
115 NotDivided, 83 1 => Presc::DIV2,
116 DividedBy2, 84 2..=3 => Presc::DIV4,
117 DividedBy4, 85 4..=5 => Presc::DIV6,
118 DividedBy6, 86 6..=7 => Presc::DIV8,
119 DividedBy8, 87 8..=9 => Presc::DIV10,
120 DividedBy10, 88 10..=11 => Presc::DIV12,
121 DividedBy12, 89 _ => unimplemented!(),
122 DividedBy16,
123 DividedBy32,
124 DividedBy64,
125 DividedBy128,
126 DividedBy256,
127}
128
129impl Prescaler {
130 fn from_ker_ck(frequency: Hertz) -> Self {
131 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
132 match raw_prescaler {
133 0 => Self::NotDivided,
134 1 => Self::DividedBy2,
135 2..=3 => Self::DividedBy4,
136 4..=5 => Self::DividedBy6,
137 6..=7 => Self::DividedBy8,
138 8..=9 => Self::DividedBy10,
139 10..=11 => Self::DividedBy12,
140 _ => unimplemented!(),
141 }
142 }
143
144 fn divisor(&self) -> u32 {
145 match self {
146 Prescaler::NotDivided => 1,
147 Prescaler::DividedBy2 => 2,
148 Prescaler::DividedBy4 => 4,
149 Prescaler::DividedBy6 => 6,
150 Prescaler::DividedBy8 => 8,
151 Prescaler::DividedBy10 => 10,
152 Prescaler::DividedBy12 => 12,
153 Prescaler::DividedBy16 => 16,
154 Prescaler::DividedBy32 => 32,
155 Prescaler::DividedBy64 => 64,
156 Prescaler::DividedBy128 => 128,
157 Prescaler::DividedBy256 => 256,
158 }
159 }
160
161 fn presc(&self) -> Presc {
162 match self {
163 Prescaler::NotDivided => Presc::DIV1,
164 Prescaler::DividedBy2 => Presc::DIV2,
165 Prescaler::DividedBy4 => Presc::DIV4,
166 Prescaler::DividedBy6 => Presc::DIV6,
167 Prescaler::DividedBy8 => Presc::DIV8,
168 Prescaler::DividedBy10 => Presc::DIV10,
169 Prescaler::DividedBy12 => Presc::DIV12,
170 Prescaler::DividedBy16 => Presc::DIV16,
171 Prescaler::DividedBy32 => Presc::DIV32,
172 Prescaler::DividedBy64 => Presc::DIV64,
173 Prescaler::DividedBy128 => Presc::DIV128,
174 Prescaler::DividedBy256 => Presc::DIV256,
175 }
176 } 90 }
177} 91}
178 92
@@ -185,6 +99,127 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri
185 type Interrupt: crate::interrupt::typelevel::Interrupt; 99 type Interrupt: crate::interrupt::typelevel::Interrupt;
186} 100}
187 101
102foreach_adc!(
103 (ADC4, $common_inst:ident, $clock:ident) => {
104 use crate::peripherals::ADC4;
105
106 impl super::BasicAnyInstance for ADC4 {
107 type SampleTime = SampleTime;
108 }
109
110 impl super::SealedAnyInstance for ADC4 {
111 fn dr() -> *mut u16 {
112 ADC4::regs().dr().as_ptr() as *mut u16
113 }
114
115 fn enable() {
116 if !ADC4::regs().cr().read().aden() || !ADC4::regs().isr().read().adrdy() {
117 ADC4::regs().isr().write(|w| w.set_adrdy(true));
118 ADC4::regs().cr().modify(|w| w.set_aden(true));
119 while !ADC4::regs().isr().read().adrdy() {}
120 }
121 }
122
123 fn start() {
124 // Start conversion
125 ADC4::regs().cr().modify(|reg| {
126 reg.set_adstart(true);
127 });
128 }
129
130 fn stop() {
131 let cr = ADC4::regs().cr().read();
132 if cr.adstart() {
133 ADC4::regs().cr().modify(|w| w.set_adstp(true));
134 while ADC4::regs().cr().read().adstart() {}
135 }
136
137 if cr.aden() || cr.adstart() {
138 ADC4::regs().cr().modify(|w| w.set_addis(true));
139 while ADC4::regs().cr().read().aden() {}
140 }
141
142 // Reset configuration.
143 ADC4::regs().cfgr1().modify(|reg| {
144 reg.set_dmaen(false);
145 });
146 }
147
148 fn configure_dma(conversion_mode: ConversionMode) {
149 match conversion_mode {
150 ConversionMode::Singular => {
151 ADC4::regs().isr().modify(|reg| {
152 reg.set_ovr(true);
153 reg.set_eos(true);
154 reg.set_eoc(true);
155 });
156
157 ADC4::regs().cfgr1().modify(|reg| {
158 reg.set_dmaen(true);
159 reg.set_dmacfg(Dmacfg::ONE_SHOT);
160 #[cfg(stm32u5)]
161 reg.set_chselrmod(false);
162 #[cfg(stm32wba)]
163 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
164 });
165 }
166 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
167 _ => unreachable!(),
168 }
169 }
170
171 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
172 let mut prev_channel: i16 = -1;
173 #[cfg(stm32wba)]
174 ADC4::regs().chselr().write_value(Chselr(0_u32));
175 #[cfg(stm32u5)]
176 ADC4::regs().chselrmod0().write_value(Chselr(0_u32));
177 for (_i, ((channel, _), sample_time)) in sequence.enumerate() {
178 ADC4::regs().smpr().modify(|w| {
179 w.set_smp(_i, sample_time);
180 });
181
182 let channel_num = channel;
183 if channel_num as i16 <= prev_channel {
184 return;
185 };
186 prev_channel = channel_num as i16;
187
188 #[cfg(stm32wba)]
189 ADC4::regs().chselr().modify(|w| {
190 w.set_chsel0(channel as usize, true);
191 });
192 #[cfg(stm32u5)]
193 ADC4::regs().chselrmod0().modify(|w| {
194 w.set_chsel(channel as usize, true);
195 });
196 }
197 }
198
199 fn convert() -> u16 {
200 // Reset interrupts
201 ADC4::regs().isr().modify(|reg| {
202 reg.set_eos(true);
203 reg.set_eoc(true);
204 });
205
206 // Start conversion
207 ADC4::regs().cr().modify(|reg| {
208 reg.set_adstart(true);
209 });
210
211 while !ADC4::regs().isr().read().eos() {
212 // spin
213 }
214
215 ADC4::regs().dr().read().0 as u16
216 }
217 }
218
219 impl super::AnyInstance for ADC4 {}
220 };
221);
222
188pub struct Adc4<'d, T: Instance> { 223pub struct Adc4<'d, T: Instance> {
189 #[allow(unused)] 224 #[allow(unused)]
190 adc: crate::Peri<'d, T>, 225 adc: crate::Peri<'d, T>,
@@ -196,35 +231,24 @@ pub enum Adc4Error {
196 DMAError, 231 DMAError,
197} 232}
198 233
199impl<'d, T: Instance> Adc4<'d, T> { 234impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> {
200 /// Create a new ADC driver. 235 /// Create a new ADC driver.
201 pub fn new(adc: Peri<'d, T>) -> Self { 236 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
202 rcc::enable_and_reset::<T>(); 237 rcc::enable_and_reset::<T>();
203 let prescaler = Prescaler::from_ker_ck(T::frequency()); 238 let prescaler = from_ker_ck(T::frequency());
204 239
205 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 240 T::regs().ccr().modify(|w| w.set_presc(prescaler));
206 241
207 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 242 let frequency = T::frequency() / prescaler;
208 info!("ADC4 frequency set to {}", frequency); 243 info!("ADC4 frequency set to {}", frequency);
209 244
210 if frequency > MAX_ADC_CLK_FREQ { 245 if frequency > MAX_ADC_CLK_FREQ {
211 panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 246 panic!(
247 "Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.",
248 MAX_ADC_CLK_FREQ.0 / 1_000_000
249 );
212 } 250 }
213 251
214 let mut s = Self { adc };
215
216 s.power_up();
217
218 s.calibrate();
219 blocking_delay_us(1);
220
221 s.enable();
222 s.configure();
223
224 s
225 }
226
227 fn power_up(&mut self) {
228 T::regs().isr().modify(|w| { 252 T::regs().isr().modify(|w| {
229 w.set_ldordy(true); 253 w.set_ldordy(true);
230 }); 254 });
@@ -236,22 +260,15 @@ impl<'d, T: Instance> Adc4<'d, T> {
236 T::regs().isr().modify(|w| { 260 T::regs().isr().modify(|w| {
237 w.set_ldordy(true); 261 w.set_ldordy(true);
238 }); 262 });
239 }
240 263
241 fn calibrate(&mut self) {
242 T::regs().cr().modify(|w| w.set_adcal(true)); 264 T::regs().cr().modify(|w| w.set_adcal(true));
243 while T::regs().cr().read().adcal() {} 265 while T::regs().cr().read().adcal() {}
244 T::regs().isr().modify(|w| w.set_eocal(true)); 266 T::regs().isr().modify(|w| w.set_eocal(true));
245 }
246 267
247 fn enable(&mut self) { 268 blocking_delay_us(1);
248 T::regs().isr().write(|w| w.set_adrdy(true)); 269
249 T::regs().cr().modify(|w| w.set_aden(true)); 270 T::enable();
250 while !T::regs().isr().read().adrdy() {}
251 T::regs().isr().write(|w| w.set_adrdy(true));
252 }
253 271
254 fn configure(&mut self) {
255 // single conversion mode, software trigger 272 // single conversion mode, software trigger
256 T::regs().cfgr1().modify(|w| { 273 T::regs().cfgr1().modify(|w| {
257 #[cfg(stm32u5)] 274 #[cfg(stm32u5)]
@@ -277,73 +294,63 @@ impl<'d, T: Instance> Adc4<'d, T> {
277 w.set_smpsel(i, Smpsel::SMP1); 294 w.set_smpsel(i, Smpsel::SMP1);
278 } 295 }
279 }); 296 });
297
298 Self { adc }
280 } 299 }
281 300
282 /// Enable reading the voltage reference internal channel. 301 /// Enable reading the voltage reference internal channel.
283 pub fn enable_vrefint(&self) -> VrefInt { 302 pub fn enable_vrefint_adc4(&self) -> super::VrefInt {
284 T::regs().ccr().modify(|w| { 303 T::regs().ccr().modify(|w| {
285 w.set_vrefen(true); 304 w.set_vrefen(true);
286 }); 305 });
287 306
288 VrefInt {} 307 super::VrefInt {}
289 } 308 }
290 309
291 /// Enable reading the temperature internal channel. 310 /// Enable reading the temperature internal channel.
292 pub fn enable_temperature(&self) -> Temperature { 311 pub fn enable_temperature_adc4(&self) -> super::Temperature {
293 T::regs().ccr().modify(|w| { 312 T::regs().ccr().modify(|w| {
294 w.set_vsensesel(true); 313 w.set_vsensesel(true);
295 }); 314 });
296 315
297 Temperature {} 316 super::Temperature {}
298 } 317 }
299 318
300 /// Enable reading the vbat internal channel. 319 /// Enable reading the vbat internal channel.
301 #[cfg(stm32u5)] 320 #[cfg(stm32u5)]
302 pub fn enable_vbat(&self) -> Vbat { 321 pub fn enable_vbat_adc4(&self) -> super::Vbat {
303 T::regs().ccr().modify(|w| { 322 T::regs().ccr().modify(|w| {
304 w.set_vbaten(true); 323 w.set_vbaten(true);
305 }); 324 });
306 325
307 Vbat {} 326 super::Vbat {}
308 } 327 }
309 328
310 /// Enable reading the vbat internal channel. 329 /// Enable reading the vbat internal channel.
311 pub fn enable_vcore(&self) -> Vcore { 330 pub fn enable_vcore_adc4(&self) -> super::Vcore {
312 Vcore {} 331 super::Vcore {}
313 } 332 }
314 333
315 /// Enable reading the vbat internal channel. 334 /// Enable reading the vbat internal channel.
316 #[cfg(stm32u5)] 335 #[cfg(stm32u5)]
317 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { 336 pub fn enable_dac_channel_adc4(&self, dac: DacChannel) -> super::Dac {
318 let mux; 337 let mux;
319 match dac { 338 match dac {
320 DacChannel::OUT1 => mux = false, 339 DacChannel::OUT1 => mux = false,
321 DacChannel::OUT2 => mux = true, 340 DacChannel::OUT2 => mux = true,
322 } 341 }
323 T::regs().or().modify(|w| w.set_chn21sel(mux)); 342 T::regs().or().modify(|w| w.set_chn21sel(mux));
324 Dac {} 343 super::Dac {}
325 }
326
327 /// Set the ADC sample time.
328 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
329 T::regs().smpr().modify(|w| {
330 w.set_smp(0, sample_time);
331 });
332 }
333
334 /// Get the ADC sample time.
335 pub fn sample_time(&self) -> SampleTime {
336 T::regs().smpr().read().smp(0)
337 } 344 }
338 345
339 /// Set the ADC resolution. 346 /// Set the ADC resolution.
340 pub fn set_resolution(&mut self, resolution: Resolution) { 347 pub fn set_resolution_adc4(&mut self, resolution: Resolution) {
341 T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); 348 T::regs().cfgr1().modify(|w| w.set_res(resolution.into()));
342 } 349 }
343 350
344 /// Set hardware averaging. 351 /// Set hardware averaging.
345 #[cfg(stm32u5)] 352 #[cfg(stm32u5)]
346 pub fn set_averaging(&mut self, averaging: Averaging) { 353 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
347 let (enable, samples, right_shift) = match averaging { 354 let (enable, samples, right_shift) = match averaging {
348 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), 355 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0),
349 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), 356 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1),
@@ -363,7 +370,7 @@ impl<'d, T: Instance> Adc4<'d, T> {
363 }) 370 })
364 } 371 }
365 #[cfg(stm32wba)] 372 #[cfg(stm32wba)]
366 pub fn set_averaging(&mut self, averaging: Averaging) { 373 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
367 let (enable, samples, right_shift) = match averaging { 374 let (enable, samples, right_shift) = match averaging {
368 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), 375 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0),
369 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), 376 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1),
@@ -382,164 +389,4 @@ impl<'d, T: Instance> Adc4<'d, T> {
382 w.set_ovse(enable) 389 w.set_ovse(enable)
383 }) 390 })
384 } 391 }
385
386 /// Read an ADC channel.
387 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
388 channel.setup();
389
390 // Select channel
391 #[cfg(stm32wba)]
392 {
393 T::regs().chselr().write_value(Chselr(0_u32));
394 T::regs().chselr().modify(|w| {
395 w.set_chsel0(channel.channel() as usize, true);
396 });
397 }
398 #[cfg(stm32u5)]
399 {
400 T::regs().chselrmod0().write_value(Chselr(0_u32));
401 T::regs().chselrmod0().modify(|w| {
402 w.set_chsel(channel.channel() as usize, true);
403 });
404 }
405
406 // Reset interrupts
407 T::regs().isr().modify(|reg| {
408 reg.set_eos(true);
409 reg.set_eoc(true);
410 });
411
412 // Start conversion
413 T::regs().cr().modify(|reg| {
414 reg.set_adstart(true);
415 });
416
417 while !T::regs().isr().read().eos() {
418 // spin
419 }
420
421 T::regs().dr().read().0 as u16
422 }
423
424 /// Read one or multiple ADC channels using DMA.
425 ///
426 /// `sequence` iterator and `readings` must have the same length.
427 /// The channels in `sequence` must be in ascending order.
428 ///
429 /// Example
430 /// ```rust,ignore
431 /// use embassy_stm32::adc::adc4;
432 /// use embassy_stm32::adc::AdcChannel;
433 ///
434 /// let mut adc4 = adc4::Adc4::new(p.ADC4);
435 /// let mut adc4_pin1 = p.PC1;
436 /// let mut adc4_pin2 = p.PC0;
437 /// let mut.into()d41 = adc4_pin1.into();
438 /// let mut.into()d42 = adc4_pin2.into();
439 /// let mut measurements = [0u16; 2];
440 /// // not that the channels must be in ascending order
441 /// adc4.read(
442 /// &mut p.GPDMA1_CH1,
443 /// [
444 /// &mut.into()d42,
445 /// &mut.into()d41,
446 /// ]
447 /// .into_iter(),
448 /// &mut measurements,
449 /// ).await.unwrap();
450 /// ```
451 pub async fn read(
452 &mut self,
453 rx_dma: Peri<'_, impl RxDma4<T>>,
454 sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
455 readings: &mut [u16],
456 ) -> Result<(), Adc4Error> {
457 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
458 assert!(
459 sequence.len() == readings.len(),
460 "Sequence length must be equal to readings length"
461 );
462
463 // Ensure no conversions are ongoing
464 Self::cancel_conversions();
465
466 T::regs().isr().modify(|reg| {
467 reg.set_ovr(true);
468 reg.set_eos(true);
469 reg.set_eoc(true);
470 });
471
472 T::regs().cfgr1().modify(|reg| {
473 reg.set_dmaen(true);
474 reg.set_dmacfg(Dmacfg::ONE_SHOT);
475 #[cfg(stm32u5)]
476 reg.set_chselrmod(false);
477 #[cfg(stm32wba)]
478 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
479 });
480
481 // Verify and activate sequence
482 let mut prev_channel: i16 = -1;
483 #[cfg(stm32wba)]
484 T::regs().chselr().write_value(Chselr(0_u32));
485 #[cfg(stm32u5)]
486 T::regs().chselrmod0().write_value(Chselr(0_u32));
487 for channel in sequence {
488 let channel_num = channel.channel;
489 if channel_num as i16 <= prev_channel {
490 return Err(Adc4Error::InvalidSequence);
491 };
492 prev_channel = channel_num as i16;
493
494 #[cfg(stm32wba)]
495 T::regs().chselr().modify(|w| {
496 w.set_chsel0(channel.channel as usize, true);
497 });
498 #[cfg(stm32u5)]
499 T::regs().chselrmod0().modify(|w| {
500 w.set_chsel(channel.channel as usize, true);
501 });
502 }
503
504 let request = rx_dma.request();
505 let transfer = unsafe {
506 Transfer::new_read(
507 rx_dma,
508 request,
509 T::regs().dr().as_ptr() as *mut u16,
510 readings,
511 Default::default(),
512 )
513 };
514
515 // Start conversion
516 T::regs().cr().modify(|reg| {
517 reg.set_adstart(true);
518 });
519
520 transfer.await;
521
522 // Ensure conversions are finished.
523 Self::cancel_conversions();
524
525 // Reset configuration.
526 T::regs().cfgr1().modify(|reg| {
527 reg.set_dmaen(false);
528 });
529
530 if T::regs().isr().read().ovr() {
531 Err(Adc4Error::DMAError)
532 } else {
533 Ok(())
534 }
535 }
536
537 fn cancel_conversions() {
538 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
539 T::regs().cr().modify(|reg| {
540 reg.set_adstp(true);
541 });
542 while T::regs().cr().read().adstart() {}
543 }
544 }
545} 392}
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index f2837a8f1..3e109e429 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,14 +1,12 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)] 1#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; 2use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4use stm32_metapac::adc::vals::{SampleTime, Scandir};
5 5
6use super::{ 6use super::{Adc, Instance, Resolution, blocking_delay_us};
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 7use crate::adc::{AnyInstance, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{pac, rcc, Peri}; 9use crate::{Peri, pac, rcc};
12 10
13/// Default VREF voltage used for sample conversion to millivolts. 11/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300; 12pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -19,189 +17,200 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25);
19 17
20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; 18const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20;
21 19
22const TEMP_CHANNEL: u8 = 9;
23const VREF_CHANNEL: u8 = 10;
24
25const NUM_HW_CHANNELS: u8 = 22;
26const CHSELR_SQ_SIZE: usize = 8; 20const CHSELR_SQ_SIZE: usize = 8;
27const CHSELR_SQ_MAX_CHANNEL: u8 = 14; 21const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
28const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; 22const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
29 23
30// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, 24impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
31// this currently cannot be modeled with stm32-data, 25 const CHANNEL: u8 = 10;
32// so these are available from the software on all ADCs.
33/// Internal voltage reference channel.
34pub struct VrefInt;
35impl<T: Instance> AdcChannel<T> for VrefInt {}
36impl<T: Instance> SealedAdcChannel<T> for VrefInt {
37 fn channel(&self) -> u8 {
38 VREF_CHANNEL
39 }
40} 26}
41 27
42/// Internal temperature channel. 28impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
43pub struct Temperature; 29 const CHANNEL: u8 = 9;
44impl<T: Instance> AdcChannel<T> for Temperature {}
45impl<T: Instance> SealedAdcChannel<T> for Temperature {
46 fn channel(&self) -> u8 {
47 TEMP_CHANNEL
48 }
49} 30}
50 31
51#[derive(Copy, Clone, Debug)] 32fn from_ker_ck(frequency: Hertz) -> Presc {
52pub enum Prescaler { 33 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
53 NotDivided, 34 match raw_prescaler {
54 DividedBy2, 35 0 => Presc::DIV1,
55 DividedBy4, 36 1 => Presc::DIV2,
56 DividedBy6, 37 2..=3 => Presc::DIV4,
57 DividedBy8, 38 4..=5 => Presc::DIV6,
58 DividedBy10, 39 6..=7 => Presc::DIV8,
59 DividedBy12, 40 8..=9 => Presc::DIV10,
60 DividedBy16, 41 10..=11 => Presc::DIV12,
61 DividedBy32, 42 _ => unimplemented!(),
62 DividedBy64, 43 }
63 DividedBy128,
64 DividedBy256,
65} 44}
66 45
67impl Prescaler { 46impl<T: Instance> super::SealedAnyInstance for T {
68 fn from_ker_ck(frequency: Hertz) -> Self { 47 fn dr() -> *mut u16 {
69 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 48 T::regs().dr().as_ptr() as *mut u16
70 match raw_prescaler {
71 0 => Self::NotDivided,
72 1 => Self::DividedBy2,
73 2..=3 => Self::DividedBy4,
74 4..=5 => Self::DividedBy6,
75 6..=7 => Self::DividedBy8,
76 8..=9 => Self::DividedBy10,
77 10..=11 => Self::DividedBy12,
78 _ => unimplemented!(),
79 }
80 } 49 }
81 50
82 #[allow(unused)] 51 fn enable() {
83 fn divisor(&self) -> u32 { 52 T::regs().isr().modify(|w| w.set_adrdy(true));
84 match self { 53 T::regs().cr().modify(|w| w.set_aden(true));
85 Prescaler::NotDivided => 1, 54 // ADRDY is "ADC ready". Wait until it will be True.
86 Prescaler::DividedBy2 => 2, 55 while !T::regs().isr().read().adrdy() {}
87 Prescaler::DividedBy4 => 4,
88 Prescaler::DividedBy6 => 6,
89 Prescaler::DividedBy8 => 8,
90 Prescaler::DividedBy10 => 10,
91 Prescaler::DividedBy12 => 12,
92 Prescaler::DividedBy16 => 16,
93 Prescaler::DividedBy32 => 32,
94 Prescaler::DividedBy64 => 64,
95 Prescaler::DividedBy128 => 128,
96 Prescaler::DividedBy256 => 256,
97 }
98 } 56 }
99 57
100 fn presc(&self) -> Presc { 58 fn start() {
101 match self { 59 // Start conversion
102 Prescaler::NotDivided => Presc::DIV1, 60 T::regs().cr().modify(|reg| {
103 Prescaler::DividedBy2 => Presc::DIV2, 61 reg.set_adstart(true);
104 Prescaler::DividedBy4 => Presc::DIV4, 62 });
105 Prescaler::DividedBy6 => Presc::DIV6, 63 }
106 Prescaler::DividedBy8 => Presc::DIV8, 64
107 Prescaler::DividedBy10 => Presc::DIV10, 65 fn stop() {
108 Prescaler::DividedBy12 => Presc::DIV12, 66 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
109 Prescaler::DividedBy16 => Presc::DIV16, 67 T::regs().cr().modify(|reg| {
110 Prescaler::DividedBy32 => Presc::DIV32, 68 reg.set_adstp(Adstp::STOP);
111 Prescaler::DividedBy64 => Presc::DIV64, 69 });
112 Prescaler::DividedBy128 => Presc::DIV128, 70 while T::regs().cr().read().adstart() {}
113 Prescaler::DividedBy256 => Presc::DIV256,
114 } 71 }
72
73 // Reset configuration.
74 T::regs().cfgr1().modify(|reg| {
75 reg.set_cont(false);
76 reg.set_dmacfg(Dmacfg::from_bits(0));
77 reg.set_dmaen(false);
78 });
115 } 79 }
116}
117 80
118#[cfg(feature = "defmt")] 81 fn configure_dma(conversion_mode: super::ConversionMode) {
119impl<'a> defmt::Format for Prescaler { 82 match conversion_mode {
120 fn format(&self, fmt: defmt::Formatter) { 83 ConversionMode::Singular => {
121 match self { 84 // Enable overrun control, so no new DMA requests will be generated until
122 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), 85 // previous DR values is read.
123 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), 86 T::regs().isr().modify(|reg| {
124 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), 87 reg.set_ovr(true);
125 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), 88 });
126 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), 89
127 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), 90 // Set continuous mode with oneshot dma.
128 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), 91 T::regs().cfgr1().modify(|reg| {
129 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), 92 reg.set_discen(false);
130 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), 93 reg.set_cont(true);
131 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), 94 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
132 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), 95 reg.set_dmaen(true);
133 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), 96 reg.set_ovrmod(Ovrmod::PRESERVE);
97 });
98 }
134 } 99 }
135 } 100 }
136}
137 101
138/// Number of samples used for averaging. 102 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) {
139/// TODO: Implement hardware averaging setting. 103 let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE;
140#[allow(unused)] 104 let mut is_ordered_up = true;
141#[derive(Copy, Clone, Debug)] 105 let mut is_ordered_down = true;
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
143pub enum Averaging {
144 Disabled,
145 Samples2,
146 Samples4,
147 Samples8,
148 Samples16,
149 Samples32,
150 Samples64,
151 Samples128,
152 Samples256,
153 Samples512,
154 Samples1024,
155}
156 106
157impl<'d, T: Instance> Adc<'d, T> { 107 let sequence_len = sequence.len();
158 /// Create a new ADC driver. 108 let mut hw_channel_selection: u32 = 0;
159 pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self { 109 let mut last_channel: u8 = 0;
160 rcc::enable_and_reset::<T>(); 110 let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5;
161 111
162 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 112 T::regs().chselr_sq().write(|w| {
113 for (i, ((channel, _), _sample_time)) in sequence.enumerate() {
114 assert!(
115 sample_time == _sample_time || i == 0,
116 "C0 only supports one sample time for the sequence."
117 );
163 118
164 let prescaler = Prescaler::from_ker_ck(T::frequency()); 119 sample_time = _sample_time;
165 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 120 needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL;
121 is_ordered_up = is_ordered_up && (channel > last_channel || i == 0);
122 is_ordered_down = is_ordered_down && (channel < last_channel || i == 0);
123 hw_channel_selection += 1 << channel;
124 last_channel = channel;
166 125
167 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 126 if !needs_hw {
168 debug!("ADC frequency set to {}", frequency); 127 w.set_sq(i, channel);
128 }
129 }
169 130
170 if frequency > MAX_ADC_CLK_FREQ { 131 for i in sequence_len..CHSELR_SQ_SIZE {
171 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 132 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
172 } 133 }
134 });
173 135
174 let mut s = Self { 136 if needs_hw {
175 adc, 137 assert!(
176 sample_time: SampleTime::from_bits(0), 138 sequence_len <= CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down,
177 }; 139 "Sequencer is required because of unordered channels, but read set cannot be more than {} in size.",
140 CHSELR_SQ_SIZE
141 );
142 assert!(
143 sequence_len > CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down,
144 "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.",
145 CHSELR_SQ_MAX_CHANNEL
146 );
147
148 // Set required channels for multi-convert.
149 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
150 }
178 151
179 s.power_up(); 152 T::regs().smpr().modify(|w| {
153 w.smpsel(0);
154 w.set_smp1(sample_time);
155 });
180 156
181 s.set_resolution(resolution); 157 T::regs().cfgr1().modify(|reg| {
158 reg.set_chselrmod(!needs_hw);
159 reg.set_align(Align::RIGHT);
160 reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK });
161 });
182 162
183 s.calibrate(); 163 // Trigger and wait for the channel selection procedure to complete.
164 T::regs().isr().modify(|w| w.set_ccrdy(false));
165 while !T::regs().isr().read().ccrdy() {}
166 }
184 167
185 s.enable(); 168 fn convert() -> u16 {
169 // Set single conversion mode.
170 T::regs().cfgr1().modify(|w| w.set_cont(false));
186 171
187 s.configure_default(); 172 // Start conversion
173 T::regs().cr().modify(|reg| {
174 reg.set_adstart(true);
175 });
188 176
189 s.set_sample_time_all_channels(sample_time); 177 // Waiting for End Of Conversion (EOC).
178 while !T::regs().isr().read().eoc() {}
190 179
191 s 180 T::regs().dr().read().data() as u16
192 } 181 }
182}
183
184impl<'d, T: AnyInstance> Adc<'d, T> {
185 /// Create a new ADC driver.
186 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
187 rcc::enable_and_reset::<T>();
188
189 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
190
191 let prescaler = from_ker_ck(T::frequency());
192 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
193
194 let frequency = T::frequency() / prescaler;
195 debug!("ADC frequency set to {}", frequency);
196
197 if frequency > MAX_ADC_CLK_FREQ {
198 panic!(
199 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
200 MAX_ADC_CLK_FREQ.0 / 1_000_000
201 );
202 }
193 203
194 fn power_up(&mut self) {
195 T::regs().cr().modify(|reg| { 204 T::regs().cr().modify(|reg| {
196 reg.set_advregen(true); 205 reg.set_advregen(true);
197 }); 206 });
198 207
199 // "The software must wait for the ADC voltage regulator startup time." 208 // "The software must wait for the ADC voltage regulator startup time."
200 // See datasheet for the value. 209 // See datasheet for the value.
201 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); 210 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1);
202 } 211
212 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
203 213
204 fn calibrate(&mut self) {
205 // We have to make sure AUTOFF is OFF, but keep its value after calibration. 214 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
206 let autoff_value = T::regs().cfgr1().read().autoff(); 215 let autoff_value = T::regs().cfgr1().read().autoff();
207 T::regs().cfgr1().modify(|w| w.set_autoff(false)); 216 T::regs().cfgr1().modify(|w| w.set_autoff(false));
@@ -215,255 +224,35 @@ impl<'d, T: Instance> Adc<'d, T> {
215 debug!("ADC calibration value: {}.", T::regs().dr().read().data()); 224 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
216 225
217 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); 226 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
218 }
219 227
220 fn enable(&mut self) { 228 T::enable();
221 T::regs().isr().modify(|w| w.set_adrdy(true));
222 T::regs().cr().modify(|w| w.set_aden(true));
223 // ADRDY is "ADC ready". Wait until it will be True.
224 while !T::regs().isr().read().adrdy() {}
225 }
226 229
227 fn configure_default(&mut self) {
228 // single conversion mode, software trigger 230 // single conversion mode, software trigger
229 T::regs().cfgr1().modify(|w| { 231 T::regs().cfgr1().modify(|w| {
230 w.set_cont(false); 232 w.set_cont(false);
231 w.set_exten(Exten::DISABLED); 233 w.set_exten(Exten::DISABLED);
232 w.set_align(Align::RIGHT); 234 w.set_align(Align::RIGHT);
233 }); 235 });
236
237 Self { adc }
234 } 238 }
235 239
236 /// Enable reading the voltage reference internal channel. 240 /// Enable reading the voltage reference internal channel.
237 pub fn enable_vrefint(&self) -> VrefInt { 241 pub fn enable_vrefint(&self) -> super::VrefInt {
238 T::common_regs().ccr().modify(|reg| { 242 T::common_regs().ccr().modify(|reg| {
239 reg.set_vrefen(true); 243 reg.set_vrefen(true);
240 }); 244 });
241 245
242 VrefInt {} 246 super::VrefInt {}
243 } 247 }
244 248
245 /// Enable reading the temperature internal channel. 249 /// Enable reading the temperature internal channel.
246 pub fn enable_temperature(&self) -> Temperature { 250 pub fn enable_temperature(&self) -> super::Temperature {
247 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!"); 251 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!");
248 T::common_regs().ccr().modify(|reg| { 252 T::common_regs().ccr().modify(|reg| {
249 reg.set_tsen(true); 253 reg.set_tsen(true);
250 }); 254 });
251 255
252 Temperature {} 256 super::Temperature {}
253 }
254
255 /// Set the ADC sample time.
256 /// Shall only be called when ADC is not converting.
257 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
258 self.sample_time = sample_time;
259
260 // Set all channels to use SMP1 field as source.
261 T::regs().smpr().modify(|w| {
262 w.smpsel(0);
263 w.set_smp1(sample_time);
264 });
265 }
266
267 /// Set the ADC resolution.
268 pub fn set_resolution(&mut self, resolution: Resolution) {
269 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
270 }
271
272 /// Perform a single conversion.
273 fn convert(&mut self) -> u16 {
274 // Set single conversion mode.
275 T::regs().cfgr1().modify(|w| w.set_cont(false));
276
277 // Start conversion
278 T::regs().cr().modify(|reg| {
279 reg.set_adstart(true);
280 });
281
282 // Waiting for End Of Conversion (EOC).
283 while !T::regs().isr().read().eoc() {}
284
285 T::regs().dr().read().data() as u16
286 }
287
288 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
289 Self::configure_channel(channel);
290 T::regs().cfgr1().write(|reg| {
291 reg.set_chselrmod(false);
292 reg.set_align(Align::RIGHT);
293 });
294 self.convert()
295 }
296
297 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
298 assert!(
299 channel_sequence.len() <= CHSELR_SQ_SIZE,
300 "Seqenced read set cannot be more than {} in size.",
301 CHSELR_SQ_SIZE
302 );
303 let mut last_sq_set: usize = 0;
304 T::regs().chselr_sq().write(|w| {
305 for (i, channel) in channel_sequence.enumerate() {
306 assert!(
307 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
308 "Sequencer only support HW channels smaller than {}.",
309 CHSELR_SQ_MAX_CHANNEL
310 );
311 w.set_sq(i, channel.channel());
312 last_sq_set = i;
313 }
314
315 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
316 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
317 }
318 });
319
320 Self::apply_channel_conf()
321 }
322
323 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
324 // Enable overrun control, so no new DMA requests will be generated until
325 // previous DR values is read.
326 T::regs().isr().modify(|reg| {
327 reg.set_ovr(true);
328 });
329
330 // Set continuous mode with oneshot dma.
331 T::regs().cfgr1().modify(|reg| {
332 reg.set_discen(false);
333 reg.set_cont(true);
334 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
335 reg.set_dmaen(true);
336 reg.set_ovrmod(Ovrmod::PRESERVE);
337 });
338
339 let request = rx_dma.request();
340 let transfer = unsafe {
341 Transfer::new_read(
342 rx_dma,
343 request,
344 T::regs().dr().as_ptr() as *mut u16,
345 readings,
346 Default::default(),
347 )
348 };
349
350 // Start conversion.
351 T::regs().cr().modify(|reg| {
352 reg.set_adstart(true);
353 });
354
355 // Wait for conversion sequence to finish.
356 transfer.await;
357
358 // Ensure conversions are finished.
359 Self::cancel_conversions();
360
361 // Reset configuration.
362 T::regs().cfgr1().modify(|reg| {
363 reg.set_cont(false);
364 reg.set_dmacfg(Dmacfg::from_bits(0));
365 reg.set_dmaen(false);
366 });
367 }
368
369 /// Read one or multiple ADC channels using DMA in hardware order.
370 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
371 /// Readings won't be in the same order as in the `set`!
372 ///
373 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
374 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
375 /// TODO(chudsaviet): externalize generic code and merge with read().
376 pub async fn read_in_hw_order(
377 &mut self,
378 rx_dma: Peri<'_, impl RxDma<T>>,
379 hw_channel_selection: u32,
380 scandir: Scandir,
381 readings: &mut [u16],
382 ) {
383 assert!(
384 hw_channel_selection != 0,
385 "Some bits in `hw_channel_selection` shall be set."
386 );
387 assert!(
388 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
389 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
390 NUM_HW_CHANNELS
391 );
392 // To check for correct readings slice size, we shall solve Hamming weight problem,
393 // which is either slow or memory consuming.
394 // Since we have limited resources, we don't do it here.
395 // Not doing this have a great potential for a bug through.
396
397 // Ensure no conversions are ongoing.
398 Self::cancel_conversions();
399
400 T::regs().cfgr1().modify(|reg| {
401 reg.set_chselrmod(false);
402 reg.set_scandir(scandir);
403 reg.set_align(Align::RIGHT);
404 });
405
406 // Set required channels for multi-convert.
407 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
408
409 Self::apply_channel_conf();
410
411 self.dma_convert(rx_dma, readings).await
412 }
413
414 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
415 // In STM32C0, only lower 14 ADC channels can be read this way.
416 // For other channels, use `read_in_hw_order()` or blocking read.
417 pub async fn read(
418 &mut self,
419 rx_dma: Peri<'_, impl RxDma<T>>,
420 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
421 readings: &mut [u16],
422 ) {
423 assert!(
424 channel_sequence.len() != 0,
425 "Asynchronous read channel sequence cannot be empty."
426 );
427 assert!(
428 channel_sequence.len() == readings.len(),
429 "Channel sequence length must be equal to readings length."
430 );
431
432 // Ensure no conversions are ongoing.
433 Self::cancel_conversions();
434
435 T::regs().cfgr1().modify(|reg| {
436 reg.set_chselrmod(true);
437 reg.set_align(Align::RIGHT);
438 });
439
440 Self::setup_channel_sequencer(channel_sequence);
441
442 self.dma_convert(rx_dma, readings).await
443 }
444
445 fn configure_channel(channel: &mut impl AdcChannel<T>) {
446 channel.setup();
447 // write() because we want all other bits to be set to 0.
448 T::regs()
449 .chselr()
450 .write(|w| w.set_chsel(channel.channel().into(), true));
451
452 Self::apply_channel_conf();
453 }
454
455 fn apply_channel_conf() {
456 // Trigger and wait for the channel selection procedure to complete.
457 T::regs().isr().modify(|w| w.set_ccrdy(false));
458 while !T::regs().isr().read().ccrdy() {}
459 }
460
461 fn cancel_conversions() {
462 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
463 T::regs().cr().modify(|reg| {
464 reg.set_adstp(Adstp::STOP);
465 });
466 while T::regs().cr().read().adstart() {}
467 }
468 } 257 }
469} 258}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 3cdc9d8fb..d6c6f480b 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -3,11 +3,11 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use super::blocking_delay_us; 5use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::interrupt::{self}; 8use crate::interrupt::{self};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{rcc, Peri}; 10use crate::{Peri, rcc};
11 11
12pub const VDDA_CALIB_MV: u32 = 3300; 12pub const VDDA_CALIB_MV: u32 = 3300;
13pub const ADC_MAX: u32 = (1 << 12) - 1; 13pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -28,20 +28,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
28 } 28 }
29} 29}
30 30
31pub struct Vref; 31impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T {
32impl<T: Instance> AdcChannel<T> for Vref {} 32 const CHANNEL: u8 = 17;
33impl<T: Instance> super::SealedAdcChannel<T> for Vref {
34 fn channel(&self) -> u8 {
35 17
36 }
37} 33}
38 34
39pub struct Temperature; 35impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
40impl<T: Instance> AdcChannel<T> for Temperature {} 36 const CHANNEL: u8 = 16;
41impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
42 fn channel(&self) -> u8 {
43 16
44 }
45} 37}
46 38
47impl<'d, T: Instance> Adc<'d, T> { 39impl<'d, T: Instance> Adc<'d, T> {
@@ -51,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> {
51 43
52 // 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’)
53 // for at least two ADC clock cycles. 45 // for at least two ADC clock cycles.
54 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);
55 47
56 // Reset calibration 48 // Reset calibration
57 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 49 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -66,15 +58,12 @@ impl<'d, T: Instance> Adc<'d, T> {
66 } 58 }
67 59
68 // One cycle after calibration 60 // One cycle after calibration
69 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);
70 62
71 T::Interrupt::unpend(); 63 T::Interrupt::unpend();
72 unsafe { T::Interrupt::enable() }; 64 unsafe { T::Interrupt::enable() };
73 65
74 Self { 66 Self { adc }
75 adc,
76 sample_time: SampleTime::from_bits(0),
77 }
78 } 67 }
79 68
80 fn freq() -> Hertz { 69 fn freq() -> Hertz {
@@ -94,22 +83,18 @@ impl<'d, T: Instance> Adc<'d, T> {
94 } 83 }
95 } 84 }
96 85
97 pub fn enable_vref(&self) -> Vref { 86 pub fn enable_vref(&self) -> super::VrefInt {
98 T::regs().cr2().modify(|reg| { 87 T::regs().cr2().modify(|reg| {
99 reg.set_tsvrefe(true); 88 reg.set_tsvrefe(true);
100 }); 89 });
101 Vref {} 90 super::VrefInt {}
102 } 91 }
103 92
104 pub fn enable_temperature(&self) -> Temperature { 93 pub fn enable_temperature(&self) -> super::Temperature {
105 T::regs().cr2().modify(|reg| { 94 T::regs().cr2().modify(|reg| {
106 reg.set_tsvrefe(true); 95 reg.set_tsvrefe(true);
107 }); 96 });
108 Temperature {} 97 super::Temperature {}
109 }
110
111 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
112 self.sample_time = sample_time;
113 } 98 }
114 99
115 /// Perform a single conversion. 100 /// Perform a single conversion.
@@ -134,8 +119,8 @@ impl<'d, T: Instance> Adc<'d, T> {
134 T::regs().dr().read().0 as u16 119 T::regs().dr().read().0 as u16
135 } 120 }
136 121
137 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 122 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
138 Self::set_channel_sample_time(channel.channel(), self.sample_time); 123 Self::set_channel_sample_time(channel.channel(), sample_time);
139 T::regs().cr1().modify(|reg| { 124 T::regs().cr1().modify(|reg| {
140 reg.set_scan(false); 125 reg.set_scan(false);
141 reg.set_discen(false); 126 reg.set_discen(false);
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 3aeb6f2c7..29bfdac97 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -3,10 +3,10 @@ use core::marker::PhantomData;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use super::blocking_delay_us; 5use super::blocking_delay_us;
6use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 6use crate::adc::{Adc, AdcChannel, Instance, SampleTime, VrefInt};
7use crate::interrupt::typelevel::Interrupt; 7use crate::interrupt::typelevel::Interrupt;
8use crate::time::Hertz; 8use crate::time::Hertz;
9use crate::{interrupt, rcc, Peri}; 9use crate::{Peri, interrupt, rcc};
10 10
11pub const VDDA_CALIB_MV: u32 = 3300; 11pub const VDDA_CALIB_MV: u32 = 3300;
12pub const ADC_MAX: u32 = (1 << 12) - 1; 12pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -29,27 +29,12 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
29 } 29 }
30} 30}
31 31
32pub struct Vref; 32impl<T: Instance> super::SealedSpecialConverter<VrefInt> for T {
33impl<T: Instance> AdcChannel<T> for Vref {} 33 const CHANNEL: u8 = 18;
34impl<T: Instance> super::SealedAdcChannel<T> for Vref {
35 fn channel(&self) -> u8 {
36 18
37 }
38}
39
40impl Vref {
41 /// The value that vref would be if vdda was at 3300mv
42 pub fn value(&self) -> u16 {
43 crate::pac::VREFINTCAL.data().read()
44 }
45} 34}
46 35
47pub struct Temperature; 36impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
48impl<T: Instance> AdcChannel<T> for Temperature {} 37 const CHANNEL: u8 = 16;
49impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
50 fn channel(&self) -> u8 {
51 16
52 }
53} 38}
54 39
55impl<'d, T: Instance> Adc<'d, T> { 40impl<'d, T: Instance> Adc<'d, T> {
@@ -77,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> {
77 while T::regs().cr().read().adcal() {} 62 while T::regs().cr().read().adcal() {}
78 63
79 // 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).
80 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);
81 66
82 // Enable the adc 67 // Enable the adc
83 T::regs().cr().modify(|w| w.set_aden(true)); 68 T::regs().cr().modify(|w| w.set_aden(true));
@@ -90,10 +75,7 @@ impl<'d, T: Instance> Adc<'d, T> {
90 T::Interrupt::enable(); 75 T::Interrupt::enable();
91 } 76 }
92 77
93 Self { 78 Self { adc }
94 adc,
95 sample_time: SampleTime::from_bits(0),
96 }
97 } 79 }
98 80
99 fn freq() -> Hertz { 81 fn freq() -> Hertz {
@@ -112,20 +94,16 @@ impl<'d, T: Instance> Adc<'d, T> {
112 } 94 }
113 } 95 }
114 96
115 pub fn enable_vref(&self) -> Vref { 97 pub fn enable_vref(&self) -> super::VrefInt {
116 T::common_regs().ccr().modify(|w| w.set_vrefen(true)); 98 T::common_regs().ccr().modify(|w| w.set_vrefen(true));
117 99
118 Vref {} 100 super::VrefInt {}
119 } 101 }
120 102
121 pub fn enable_temperature(&self) -> Temperature { 103 pub fn enable_temperature(&self) -> super::Temperature {
122 T::common_regs().ccr().modify(|w| w.set_tsen(true)); 104 T::common_regs().ccr().modify(|w| w.set_tsen(true));
123 105
124 Temperature {} 106 super::Temperature {}
125 }
126
127 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
128 self.sample_time = sample_time;
129 } 107 }
130 108
131 /// Perform a single conversion. 109 /// Perform a single conversion.
@@ -150,8 +128,8 @@ impl<'d, T: Instance> Adc<'d, T> {
150 T::regs().dr().read().rdata() 128 T::regs().dr().read().rdata()
151 } 129 }
152 130
153 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 131 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
154 Self::set_channel_sample_time(channel.channel(), self.sample_time); 132 Self::set_channel_sample_time(channel.channel(), sample_time);
155 133
156 // Configure the channel to sample 134 // Configure the channel to sample
157 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel())); 135 T::regs().sqr1().write(|w| w.set_sq(0, channel.channel()));
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 84613078c..919ac3cc0 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -9,7 +9,7 @@ use super::Resolution;
9use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 9use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
10use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::{interrupt, rcc, Peri}; 12use crate::{Peri, interrupt, rcc};
13 13
14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; 14const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
15 15
@@ -79,7 +79,7 @@ impl<T: Instance> Vref<T> {
79 } 79 }
80 80
81 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { 81 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
82 let vref_val = adc.read(self).await; 82 let vref_val = adc.read(self, SampleTime::from(0)).await;
83 Calibration { 83 Calibration {
84 vref_cal: self.calibrated_value(), 84 vref_cal: self.calibrated_value(),
85 vref_val, 85 vref_val,
@@ -270,7 +270,8 @@ impl<'d, T: Instance> Adc<'d, T> {
270 } 270 }
271 } 271 }
272 272
273 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 273 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
274 self.set_sample_time(channel, sample_time).await;
274 self.set_sample_sequence(&[channel.channel()]).await; 275 self.set_sample_sequence(&[channel.channel()]).await;
275 self.convert().await 276 self.convert().await
276 } 277 }
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 43498966f..1767a3bb3 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,175 +1,278 @@
1#[cfg(stm32g4)]
2use pac::adc::regs::Difsel as DifselReg;
3#[allow(unused)]
4#[cfg(stm32g4)]
5pub use pac::adc::vals::{Adcaldif, Adstp, Difsel, Dmacfg, Dmaen, Exten, Rovsm, Trovs};
1#[allow(unused)] 6#[allow(unused)]
2#[cfg(stm32h7)] 7#[cfg(stm32h7)]
3use pac::adc::vals::{Adcaldif, Difsel, Exten}; 8use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)] 9pub use pac::adccommon::vals::{Dual, Presc};
5#[cfg(stm32g4)]
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
7use pac::adccommon::vals::Presc;
8use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen};
9 10
10use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; 11use super::{
11use crate::adc::SealedAdcChannel; 12 Adc, AnyAdcChannel, ConversionMode, Instance, RegularConversionMode, Resolution, RxDma, SampleTime,
12use crate::dma::Transfer; 13 blocking_delay_us,
14};
15use crate::adc::{AnyInstance, SealedAdcChannel};
13use crate::time::Hertz; 16use crate::time::Hertz;
14use crate::{pac, rcc, Peri}; 17use crate::{Peri, pac, rcc};
18
19mod injected;
20pub use injected::InjectedAdc;
15 21
16/// Default VREF voltage used for sample conversion to millivolts. 22/// Default VREF voltage used for sample conversion to millivolts.
17pub const VREF_DEFAULT_MV: u32 = 3300; 23pub const VREF_DEFAULT_MV: u32 = 3300;
18/// VREF voltage used for factory calibration of VREFINTCAL register. 24/// VREF voltage used for factory calibration of VREFINTCAL register.
19pub const VREF_CALIB_MV: u32 = 3300; 25pub const VREF_CALIB_MV: u32 = 3300;
20 26
27const NR_INJECTED_RANKS: usize = 4;
28
21/// Max single ADC operation clock frequency 29/// Max single ADC operation clock frequency
22#[cfg(stm32g4)] 30#[cfg(stm32g4)]
23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); 31const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
24#[cfg(stm32h7)] 32#[cfg(stm32h7)]
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 33const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
26 34
27// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs 35fn from_ker_ck(frequency: Hertz) -> Presc {
28/// Internal voltage reference channel. 36 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
29pub struct VrefInt; 37 match raw_prescaler {
30impl<T: Instance + VrefChannel> AdcChannel<T> for VrefInt {} 38 0 => Presc::DIV1,
31impl<T: Instance + VrefChannel> super::SealedAdcChannel<T> for VrefInt { 39 1 => Presc::DIV2,
32 fn channel(&self) -> u8 { 40 2..=3 => Presc::DIV4,
33 T::CHANNEL 41 4..=5 => Presc::DIV6,
42 6..=7 => Presc::DIV8,
43 8..=9 => Presc::DIV10,
44 10..=11 => Presc::DIV12,
45 _ => unimplemented!(),
34 } 46 }
35} 47}
36 48
37/// Internal temperature channel. 49/// ADC configuration
38pub struct Temperature; 50#[derive(Default)]
39impl<T: Instance + TemperatureChannel> AdcChannel<T> for Temperature {} 51pub struct AdcConfig {
40impl<T: Instance + TemperatureChannel> super::SealedAdcChannel<T> for Temperature { 52 pub dual_mode: Option<Dual>,
41 fn channel(&self) -> u8 { 53 pub resolution: Option<Resolution>,
42 T::CHANNEL 54 #[cfg(stm32g4)]
43 } 55 pub oversampling_shift: Option<u8>,
56 #[cfg(stm32g4)]
57 pub oversampling_ratio: Option<u8>,
58 #[cfg(stm32g4)]
59 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
44} 60}
45 61
46/// Internal battery voltage channel. 62// Trigger source for ADC conversions¨
47pub struct Vbat; 63#[derive(Copy, Clone)]
48impl<T: Instance + VBatChannel> AdcChannel<T> for Vbat {} 64pub struct ConversionTrigger {
49impl<T: Instance + VBatChannel> super::SealedAdcChannel<T> for Vbat { 65 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
50 fn channel(&self) -> u8 { 66 // Note that Injected and Regular channels uses different mappings
51 T::CHANNEL 67 pub channel: u8,
52 } 68 pub edge: Exten,
53} 69}
54 70
55// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 71impl<T: Instance> super::SealedAnyInstance for T {
56// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 72 fn dr() -> *mut u16 {
57#[allow(unused)] 73 T::regs().dr().as_ptr() as *mut u16
58enum Prescaler { 74 }
59 NotDivided, 75
60 DividedBy2, 76 fn enable() {
61 DividedBy4, 77 // Make sure bits are off
62 DividedBy6, 78 while T::regs().cr().read().addis() {
63 DividedBy8, 79 // spin
64 DividedBy10, 80 }
65 DividedBy12, 81
66 DividedBy16, 82 if !T::regs().cr().read().aden() {
67 DividedBy32, 83 // Enable ADC
68 DividedBy64, 84 T::regs().isr().modify(|reg| {
69 DividedBy128, 85 reg.set_adrdy(true);
70 DividedBy256, 86 });
71} 87 T::regs().cr().modify(|reg| {
88 reg.set_aden(true);
89 });
72 90
73impl Prescaler { 91 while !T::regs().isr().read().adrdy() {
74 fn from_ker_ck(frequency: Hertz) -> Self { 92 // spin
75 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 93 }
76 match raw_prescaler {
77 0 => Self::NotDivided,
78 1 => Self::DividedBy2,
79 2..=3 => Self::DividedBy4,
80 4..=5 => Self::DividedBy6,
81 6..=7 => Self::DividedBy8,
82 8..=9 => Self::DividedBy10,
83 10..=11 => Self::DividedBy12,
84 _ => unimplemented!(),
85 } 94 }
86 } 95 }
87 96
88 fn divisor(&self) -> u32 { 97 fn start() {
89 match self { 98 T::regs().cr().modify(|reg| {
90 Prescaler::NotDivided => 1, 99 reg.set_adstart(true);
91 Prescaler::DividedBy2 => 2, 100 });
92 Prescaler::DividedBy4 => 4, 101 }
93 Prescaler::DividedBy6 => 6, 102
94 Prescaler::DividedBy8 => 8, 103 fn stop() {
95 Prescaler::DividedBy10 => 10, 104 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
96 Prescaler::DividedBy12 => 12, 105 T::regs().cr().modify(|reg| {
97 Prescaler::DividedBy16 => 16, 106 reg.set_adstp(Adstp::STOP);
98 Prescaler::DividedBy32 => 32, 107 });
99 Prescaler::DividedBy64 => 64, 108 // The software must poll ADSTART until the bit is reset before assuming the
100 Prescaler::DividedBy128 => 128, 109 // ADC is completely stopped
101 Prescaler::DividedBy256 => 256, 110 while T::regs().cr().read().adstart() {}
102 } 111 }
112
113 // Disable dma control and continuous conversion, if enabled
114 T::regs().cfgr().modify(|reg| {
115 reg.set_cont(false);
116 reg.set_dmaen(Dmaen::DISABLE);
117 });
103 } 118 }
104 119
105 fn presc(&self) -> Presc { 120 fn convert() -> u16 {
106 match self { 121 T::regs().isr().modify(|reg| {
107 Prescaler::NotDivided => Presc::DIV1, 122 reg.set_eos(true);
108 Prescaler::DividedBy2 => Presc::DIV2, 123 reg.set_eoc(true);
109 Prescaler::DividedBy4 => Presc::DIV4, 124 });
110 Prescaler::DividedBy6 => Presc::DIV6, 125
111 Prescaler::DividedBy8 => Presc::DIV8, 126 // Start conversion
112 Prescaler::DividedBy10 => Presc::DIV10, 127 T::regs().cr().modify(|reg| {
113 Prescaler::DividedBy12 => Presc::DIV12, 128 reg.set_adstart(true);
114 Prescaler::DividedBy16 => Presc::DIV16, 129 });
115 Prescaler::DividedBy32 => Presc::DIV32, 130
116 Prescaler::DividedBy64 => Presc::DIV64, 131 while !T::regs().isr().read().eos() {
117 Prescaler::DividedBy128 => Presc::DIV128, 132 // spin
118 Prescaler::DividedBy256 => Presc::DIV256,
119 } 133 }
134
135 T::regs().dr().read().0 as u16
120 } 136 }
121}
122 137
123impl<'d, T: Instance> Adc<'d, T> { 138 fn configure_dma(conversion_mode: ConversionMode) {
124 /// Create a new ADC driver. 139 T::regs().isr().modify(|reg| {
125 pub fn new(adc: Peri<'d, T>) -> Self { 140 reg.set_ovr(true);
126 rcc::enable_and_reset::<T>(); 141 });
127 142
128 let prescaler = Prescaler::from_ker_ck(T::frequency()); 143 T::regs().cfgr().modify(|reg| {
144 reg.set_discen(false); // Convert all channels for each trigger
145 reg.set_dmacfg(match conversion_mode {
146 ConversionMode::Singular => Dmacfg::ONE_SHOT,
147 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
148 });
149 reg.set_dmaen(Dmaen::ENABLE);
150 });
129 151
130 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 152 if let ConversionMode::Repeated(mode) = conversion_mode {
153 match mode {
154 RegularConversionMode::Continuous => {
155 T::regs().cfgr().modify(|reg| {
156 reg.set_cont(true);
157 });
158 }
159 RegularConversionMode::Triggered(trigger) => {
160 T::regs().cfgr().modify(|r| {
161 r.set_cont(false); // New trigger is neede for each sample to be read
162 });
131 163
132 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 164 T::regs().cfgr().modify(|r| {
133 trace!("ADC frequency set to {}", frequency); 165 r.set_extsel(trigger.channel);
166 r.set_exten(trigger.edge);
167 });
134 168
135 if frequency > MAX_ADC_CLK_FREQ { 169 // Regular conversions uses DMA so no need to generate interrupt
136 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 170 T::regs().ier().modify(|r| r.set_eosie(false));
171 }
172 }
137 } 173 }
174 }
175
176 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
177 T::regs().cr().modify(|w| w.set_aden(false));
138 178
139 let mut s = Self { 179 // Set sequence length
140 adc, 180 T::regs().sqr1().modify(|w| {
141 sample_time: SampleTime::from_bits(0), 181 w.set_l(sequence.len() as u8 - 1);
142 }; 182 });
143 s.power_up();
144 s.configure_differential_inputs();
145 183
146 s.calibrate(); 184 #[cfg(stm32g4)]
147 blocking_delay_us(1); 185 let mut difsel = DifselReg::default();
186 let mut smpr = T::regs().smpr().read();
187 let mut smpr2 = T::regs().smpr2().read();
188 let mut sqr1 = T::regs().sqr1().read();
189 let mut sqr2 = T::regs().sqr2().read();
190 let mut sqr3 = T::regs().sqr3().read();
191 let mut sqr4 = T::regs().sqr4().read();
148 192
149 s.enable(); 193 // Configure channels and ranks
150 s.configure(); 194 for (_i, ((ch, is_differential), sample_time)) in sequence.enumerate() {
195 let sample_time = sample_time.into();
196 if ch <= 9 {
197 smpr.set_smp(ch as _, sample_time);
198 } else {
199 smpr2.set_smp((ch - 10) as _, sample_time);
200 }
151 201
152 s 202 match _i {
203 0..=3 => {
204 sqr1.set_sq(_i, ch);
205 }
206 4..=8 => {
207 sqr2.set_sq(_i - 4, ch);
208 }
209 9..=13 => {
210 sqr3.set_sq(_i - 9, ch);
211 }
212 14..=15 => {
213 sqr4.set_sq(_i - 14, ch);
214 }
215 _ => unreachable!(),
216 }
217
218 #[cfg(stm32g4)]
219 {
220 if ch < 18 {
221 difsel.set_difsel(
222 ch.into(),
223 if is_differential {
224 Difsel::DIFFERENTIAL
225 } else {
226 Difsel::SINGLE_ENDED
227 },
228 );
229 }
230 }
231 }
232
233 T::regs().smpr().write_value(smpr);
234 T::regs().smpr2().write_value(smpr2);
235 T::regs().sqr1().write_value(sqr1);
236 T::regs().sqr2().write_value(sqr2);
237 T::regs().sqr3().write_value(sqr3);
238 T::regs().sqr4().write_value(sqr4);
239 #[cfg(stm32g4)]
240 T::regs().difsel().write_value(difsel);
153 } 241 }
242}
243
244impl<'d, T: Instance + AnyInstance> Adc<'d, T> {
245 /// Create a new ADC driver.
246 pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self {
247 rcc::enable_and_reset::<T>();
248
249 let prescaler = from_ker_ck(T::frequency());
250
251 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
252
253 let frequency = T::frequency() / prescaler;
254 trace!("ADC frequency set to {}", frequency);
255
256 if frequency > MAX_ADC_CLK_FREQ {
257 panic!(
258 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
259 MAX_ADC_CLK_FREQ.0 / 1_000_000
260 );
261 }
154 262
155 fn power_up(&mut self) {
156 T::regs().cr().modify(|reg| { 263 T::regs().cr().modify(|reg| {
157 reg.set_deeppwd(false); 264 reg.set_deeppwd(false);
158 reg.set_advregen(true); 265 reg.set_advregen(true);
159 }); 266 });
160 267
161 blocking_delay_us(20); 268 blocking_delay_us(20);
162 }
163 269
164 fn configure_differential_inputs(&mut self) {
165 T::regs().difsel().modify(|w| { 270 T::regs().difsel().modify(|w| {
166 for n in 0..18 { 271 for n in 0..18 {
167 w.set_difsel(n, Difsel::SINGLE_ENDED); 272 w.set_difsel(n, Difsel::SINGLE_ENDED);
168 } 273 }
169 }); 274 });
170 }
171 275
172 fn calibrate(&mut self) {
173 T::regs().cr().modify(|w| { 276 T::regs().cr().modify(|w| {
174 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 277 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
175 }); 278 });
@@ -189,120 +292,79 @@ impl<'d, T: Instance> Adc<'d, T> {
189 while T::regs().cr().read().adcal() {} 292 while T::regs().cr().read().adcal() {}
190 293
191 blocking_delay_us(20); 294 blocking_delay_us(20);
192 }
193
194 fn enable(&mut self) {
195 // Make sure bits are off
196 while T::regs().cr().read().addis() {
197 // spin
198 }
199
200 if !T::regs().cr().read().aden() {
201 // Enable ADC
202 T::regs().isr().modify(|reg| {
203 reg.set_adrdy(true);
204 });
205 T::regs().cr().modify(|reg| {
206 reg.set_aden(true);
207 });
208 295
209 while !T::regs().isr().read().adrdy() { 296 T::enable();
210 // spin
211 }
212 }
213 }
214 297
215 fn configure(&mut self) {
216 // single conversion mode, software trigger 298 // single conversion mode, software trigger
217 T::regs().cfgr().modify(|w| { 299 T::regs().cfgr().modify(|w| {
218 w.set_cont(false); 300 w.set_cont(false);
219 w.set_exten(Exten::DISABLED); 301 w.set_exten(Exten::DISABLED);
220 }); 302 });
303
304 if let Some(dual) = config.dual_mode {
305 T::common_regs().ccr().modify(|reg| {
306 reg.set_dual(dual);
307 })
308 }
309
310 if let Some(resolution) = config.resolution {
311 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
312 }
313
314 #[cfg(stm32g4)]
315 if let Some(shift) = config.oversampling_shift {
316 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
317 }
318
319 #[cfg(stm32g4)]
320 if let Some(ratio) = config.oversampling_ratio {
321 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
322 }
323
324 #[cfg(stm32g4)]
325 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
326 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
327 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
328 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
329 }
330
331 Self { adc }
221 } 332 }
222 333
223 /// Enable reading the voltage reference internal channel. 334 /// Enable reading the voltage reference internal channel.
224 pub fn enable_vrefint(&self) -> VrefInt 335 pub fn enable_vrefint(&self) -> super::VrefInt
225 where 336 where
226 T: VrefChannel, 337 T: super::SpecialConverter<super::VrefInt>,
227 { 338 {
228 T::common_regs().ccr().modify(|reg| { 339 T::common_regs().ccr().modify(|reg| {
229 reg.set_vrefen(true); 340 reg.set_vrefen(true);
230 }); 341 });
231 342
232 VrefInt {} 343 super::VrefInt {}
233 } 344 }
234 345
235 /// Enable reading the temperature internal channel. 346 /// Enable reading the temperature internal channel.
236 pub fn enable_temperature(&self) -> Temperature 347 pub fn enable_temperature(&self) -> super::Temperature
237 where 348 where
238 T: TemperatureChannel, 349 T: super::SpecialConverter<super::Temperature>,
239 { 350 {
240 T::common_regs().ccr().modify(|reg| { 351 T::common_regs().ccr().modify(|reg| {
241 reg.set_vsenseen(true); 352 reg.set_vsenseen(true);
242 }); 353 });
243 354
244 Temperature {} 355 super::Temperature {}
245 } 356 }
246 357
247 /// Enable reading the vbat internal channel. 358 /// Enable reading the vbat internal channel.
248 pub fn enable_vbat(&self) -> Vbat 359 pub fn enable_vbat(&self) -> super::Vbat
249 where 360 where
250 T: VBatChannel, 361 T: super::SpecialConverter<super::Vbat>,
251 { 362 {
252 T::common_regs().ccr().modify(|reg| { 363 T::common_regs().ccr().modify(|reg| {
253 reg.set_vbaten(true); 364 reg.set_vbaten(true);
254 }); 365 });
255 366
256 Vbat {} 367 super::Vbat {}
257 }
258
259 /// Enable differential channel.
260 /// Caution:
261 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i]
262 /// is connected to another channel. As a consequence, this channel is no longer usable in
263 /// single-ended mode or in differential mode and must never be configured to be converted.
264 /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the
265 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
266 /// operate in interleaved mode.
267 #[cfg(stm32g4)]
268 pub fn set_differential_channel(&mut self, ch: usize, enable: bool) {
269 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
270 T::regs().difsel().modify(|w| {
271 w.set_difsel(
272 ch,
273 if enable {
274 Difsel::DIFFERENTIAL
275 } else {
276 Difsel::SINGLE_ENDED
277 },
278 );
279 });
280 T::regs().cr().modify(|w| w.set_aden(true));
281 }
282
283 #[cfg(stm32g4)]
284 pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) {
285 self.set_differential_channel(channel.channel() as usize, enable);
286 }
287
288 /// Set oversampling shift.
289 #[cfg(stm32g4)]
290 pub fn set_oversampling_shift(&mut self, shift: u8) {
291 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
292 }
293
294 /// Set oversampling ratio.
295 #[cfg(stm32g4)]
296 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
297 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
298 }
299
300 /// Enable oversampling in regular mode.
301 #[cfg(stm32g4)]
302 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
303 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
304 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
305 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
306 } 368 }
307 369
308 // Reads that are not implemented as INJECTED in "blocking_read" 370 // Reads that are not implemented as INJECTED in "blocking_read"
@@ -318,260 +380,215 @@ impl<'d, T: Instance> Adc<'d, T> {
318 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); 380 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
319 // } 381 // }
320 382
321 /// Set the ADC sample time. 383 /// Configures the ADC for injected conversions.
322 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
323 self.sample_time = sample_time;
324 }
325
326 /// Set the ADC resolution.
327 pub fn set_resolution(&mut self, resolution: Resolution) {
328 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
329 }
330
331 /// Perform a single conversion.
332 fn convert(&mut self) -> u16 {
333 T::regs().isr().modify(|reg| {
334 reg.set_eos(true);
335 reg.set_eoc(true);
336 });
337
338 // Start conversion
339 T::regs().cr().modify(|reg| {
340 reg.set_adstart(true);
341 });
342
343 while !T::regs().isr().read().eos() {
344 // spin
345 }
346
347 T::regs().dr().read().0 as u16
348 }
349
350 /// Read an ADC pin.
351 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
352 channel.setup();
353
354 self.read_channel(channel)
355 }
356
357 /// Read one or multiple ADC channels using DMA.
358 /// 384 ///
359 /// `sequence` iterator and `readings` must have the same length. 385 /// Injected conversions are separate from the regular conversion sequence and are typically
386 /// triggered by software or an external event. This method sets up a fixed-length sequence of
387 /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence
388 /// interrupt should be enabled.
360 /// 389 ///
361 /// Example 390 /// # Parameters
362 /// ```rust,ignore 391 /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length
363 /// use embassy_stm32::adc::{Adc, AdcChannel} 392 /// `N` determines the number of injected ranks to configure (maximum 4 for STM32).
393 /// - `trigger`: The trigger source that starts the injected conversion sequence.
394 /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions.
364 /// 395 ///
365 /// let mut adc = Adc::new(p.ADC1); 396 /// # Returns
366 /// let mut adc_pin0 = p.PA0.into(); 397 /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned
367 /// let mut adc_pin1 = p.PA1.into(); 398 /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples.
368 /// let mut measurements = [0u16; 2];
369 /// 399 ///
370 /// adc.read( 400 /// # Panics
371 /// p.DMA1_CH2.reborrow(), 401 /// This function will panic if:
372 /// [ 402 /// - `sequence` is empty.
373 /// (&mut *adc_pin0, SampleTime::CYCLES160_5), 403 /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`).
374 /// (&mut *adc_pin1, SampleTime::CYCLES160_5), 404 ///
375 /// ] 405 /// # Notes
376 /// .into_iter(), 406 /// - Injected conversions can run independently of regular ADC conversions.
377 /// &mut measurements, 407 /// - The order of channels in `sequence` determines the rank order in the injected sequence.
378 /// ) 408 /// - Accessing samples beyond `N` will result in a panic; use the returned type
379 /// .await; 409 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
380 /// defmt::info!("measurements: {}", measurements); 410 pub fn setup_injected_conversions<'a, const N: usize>(
381 /// ``` 411 self,
382 pub async fn read( 412 sequence: [(AnyAdcChannel<T>, SampleTime); N],
383 &mut self, 413 trigger: ConversionTrigger,
384 rx_dma: Peri<'_, impl RxDma<T>>, 414 interrupt: bool,
385 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, 415 ) -> InjectedAdc<T, N> {
386 readings: &mut [u16], 416 assert!(N != 0, "Read sequence cannot be empty");
387 ) {
388 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
389 assert!(
390 sequence.len() == readings.len(),
391 "Sequence length must be equal to readings length"
392 );
393 assert!( 417 assert!(
394 sequence.len() <= 16, 418 N <= NR_INJECTED_RANKS,
395 "Asynchronous read sequence cannot be more than 16 in length" 419 "Read sequence cannot be more than {} in length",
420 NR_INJECTED_RANKS
396 ); 421 );
397 422
398 // Ensure no conversions are ongoing and ADC is enabled. 423 T::enable();
399 Self::cancel_conversions();
400 self.enable();
401
402 // Set sequence length
403 T::regs().sqr1().modify(|w| {
404 w.set_l(sequence.len() as u8 - 1);
405 });
406 424
407 // Configure channels and ranks 425 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
408 for (_i, (channel, sample_time)) in sequence.enumerate() {
409 Self::configure_channel(channel, sample_time);
410 426
411 match _i { 427 for (n, (channel, sample_time)) in sequence.into_iter().enumerate() {
412 0..=3 => { 428 let sample_time = sample_time.into();
413 T::regs().sqr1().modify(|w| { 429 if channel.channel() <= 9 {
414 w.set_sq(_i, channel.channel()); 430 T::regs()
415 }); 431 .smpr()
416 } 432 .modify(|reg| reg.set_smp(channel.channel() as _, sample_time));
417 4..=8 => { 433 } else {
418 T::regs().sqr2().modify(|w| { 434 T::regs()
419 w.set_sq(_i - 4, channel.channel()); 435 .smpr2()
420 }); 436 .modify(|reg| reg.set_smp((channel.channel() - 10) as _, sample_time));
421 }
422 9..=13 => {
423 T::regs().sqr3().modify(|w| {
424 w.set_sq(_i - 9, channel.channel());
425 });
426 }
427 14..=15 => {
428 T::regs().sqr4().modify(|w| {
429 w.set_sq(_i - 14, channel.channel());
430 });
431 }
432 _ => unreachable!(),
433 } 437 }
434 }
435
436 // Set continuous mode with oneshot dma.
437 // Clear overrun flag before starting transfer.
438 T::regs().isr().modify(|reg| {
439 reg.set_ovr(true);
440 });
441
442 T::regs().cfgr().modify(|reg| {
443 reg.set_discen(false);
444 reg.set_cont(true);
445 reg.set_dmacfg(Dmacfg::ONE_SHOT);
446 reg.set_dmaen(Dmaen::ENABLE);
447 });
448
449 let request = rx_dma.request();
450 let transfer = unsafe {
451 Transfer::new_read(
452 rx_dma,
453 request,
454 T::regs().dr().as_ptr() as *mut u16,
455 readings,
456 Default::default(),
457 )
458 };
459 438
460 // Start conversion 439 let idx = match n {
461 T::regs().cr().modify(|reg| { 440 0..=3 => n,
462 reg.set_adstart(true); 441 4..=8 => n - 4,
463 }); 442 9..=13 => n - 9,
443 14..=15 => n - 14,
444 _ => unreachable!(),
445 };
464 446
465 // Wait for conversion sequence to finish. 447 T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel()));
466 transfer.await; 448 }
467 449
468 // Ensure conversions are finished. 450 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
469 Self::cancel_conversions();
470 451
471 // Reset configuration. 452 // Set external trigger for injected conversion sequence
472 T::regs().cfgr().modify(|reg| { 453 // Possible trigger values are seen in Table 167 in RM0440 Rev 9
473 reg.set_cont(false); 454 T::regs().jsqr().modify(|r| {
455 r.set_jextsel(trigger.channel);
456 r.set_jexten(trigger.edge);
474 }); 457 });
475 }
476
477 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
478 // Configure channel
479 Self::set_channel_sample_time(channel.channel(), sample_time);
480 }
481 458
482 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 459 // Enable end of injected sequence interrupt
483 Self::configure_channel(channel, self.sample_time); 460 T::regs().ier().modify(|r| r.set_jeosie(interrupt));
484 #[cfg(stm32h7)]
485 {
486 T::regs().cfgr2().modify(|w| w.set_lshift(0));
487 T::regs()
488 .pcsel()
489 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
490 }
491 461
492 T::regs().sqr1().write(|reg| { 462 Self::start_injected_conversions();
493 reg.set_sq(0, channel.channel());
494 reg.set_l(0);
495 });
496 463
497 self.convert() 464 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
498 } 465 }
499 466
500 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 467 /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions.
501 let sample_time = sample_time.into(); 468 ///
502 if ch <= 9 { 469 /// # Parameters
503 T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); 470 /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers.
504 } else { 471 /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions.
505 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); 472 /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions.
473 /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered).
474 /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`).
475 /// - `injected_trigger`: The trigger source for injected conversions.
476 /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions.
477 ///
478 /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode,
479 /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete.
480 ///
481 /// # Returns
482 /// A tuple containing:
483 /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA.
484 /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions.
485 ///
486 /// # Safety
487 /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the
488 /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently.
489 /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way.
490 pub fn into_ring_buffered_and_injected<'a, const N: usize>(
491 self,
492 dma: Peri<'a, impl RxDma<T>>,
493 dma_buf: &'a mut [u16],
494 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>,
495 regular_conversion_mode: RegularConversionMode,
496 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
497 injected_trigger: ConversionTrigger,
498 injected_interrupt: bool,
499 ) -> (super::RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
500 unsafe {
501 (
502 Self {
503 adc: self.adc.clone_unchecked(),
504 }
505 .into_ring_buffered(dma, dma_buf, regular_sequence, regular_conversion_mode),
506 Self {
507 adc: self.adc.clone_unchecked(),
508 }
509 .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt),
510 )
506 } 511 }
507 } 512 }
508 513
509 fn cancel_conversions() { 514 /// Stop injected conversions
515 pub(super) fn stop_injected_conversions() {
510 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 516 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
511 T::regs().cr().modify(|reg| { 517 T::regs().cr().modify(|reg| {
512 reg.set_adstp(Adstp::STOP); 518 reg.set_jadstp(Adstp::STOP);
513 }); 519 });
514 while T::regs().cr().read().adstart() {} 520 // The software must poll JADSTART until the bit is reset before assuming the
521 // ADC is completely stopped
522 while T::regs().cr().read().jadstart() {}
515 } 523 }
516 } 524 }
517}
518 525
519/// Implemented for ADCs that have a Temperature channel 526 /// Start injected ADC conversion
520pub trait TemperatureChannel { 527 pub(super) fn start_injected_conversions() {
521 const CHANNEL: u8; 528 T::regs().cr().modify(|reg| {
522} 529 reg.set_jadstart(true);
523/// Implemented for ADCs that have a Vref channel 530 });
524pub trait VrefChannel { 531 }
525 const CHANNEL: u8;
526} 532}
527/// Implemented for ADCs that have a VBat channel 533
528pub trait VBatChannel { 534impl<T: Instance, const N: usize> InjectedAdc<T, N> {
529 const CHANNEL: u8; 535 /// Read sampled data from all injected ADC injected ranks
536 /// Clear the JEOS flag to allow a new injected sequence
537 pub(super) fn read_injected_data() -> [u16; N] {
538 let mut data = [0u16; N];
539 for i in 0..N {
540 data[i] = T::regs().jdr(i).read().jdata();
541 }
542
543 // Clear JEOS by writing 1
544 T::regs().isr().modify(|r| r.set_jeos(true));
545 data
546 }
530} 547}
531 548
532#[cfg(stm32g4)] 549#[cfg(stm32g4)]
533mod g4 { 550mod g4 {
534 pub use super::*; 551 use crate::adc::{SealedSpecialConverter, Temperature, Vbat, VrefInt};
535 552
536 impl TemperatureChannel for crate::peripherals::ADC1 { 553 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC1 {
537 const CHANNEL: u8 = 16; 554 const CHANNEL: u8 = 16;
538 } 555 }
539 556
540 impl VrefChannel for crate::peripherals::ADC1 { 557 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC1 {
541 const CHANNEL: u8 = 18; 558 const CHANNEL: u8 = 18;
542 } 559 }
543 560
544 impl VBatChannel for crate::peripherals::ADC1 { 561 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC1 {
545 const CHANNEL: u8 = 17; 562 const CHANNEL: u8 = 17;
546 } 563 }
547 564
548 #[cfg(peri_adc3_common)] 565 #[cfg(peri_adc3_common)]
549 impl VrefChannel for crate::peripherals::ADC3 { 566 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC3 {
550 const CHANNEL: u8 = 18; 567 const CHANNEL: u8 = 18;
551 } 568 }
552 569
553 #[cfg(peri_adc3_common)] 570 #[cfg(peri_adc3_common)]
554 impl VBatChannel for crate::peripherals::ADC3 { 571 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC3 {
555 const CHANNEL: u8 = 17; 572 const CHANNEL: u8 = 17;
556 } 573 }
557 574
558 #[cfg(not(stm32g4x1))] 575 #[cfg(not(stm32g4x1))]
559 impl VrefChannel for crate::peripherals::ADC4 { 576 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC4 {
560 const CHANNEL: u8 = 18; 577 const CHANNEL: u8 = 18;
561 } 578 }
562 579
563 #[cfg(not(stm32g4x1))] 580 #[cfg(not(stm32g4x1))]
564 impl TemperatureChannel for crate::peripherals::ADC5 { 581 impl SealedSpecialConverter<Temperature> for crate::peripherals::ADC5 {
565 const CHANNEL: u8 = 4; 582 const CHANNEL: u8 = 4;
566 } 583 }
567 584
568 #[cfg(not(stm32g4x1))] 585 #[cfg(not(stm32g4x1))]
569 impl VrefChannel for crate::peripherals::ADC5 { 586 impl SealedSpecialConverter<VrefInt> for crate::peripherals::ADC5 {
570 const CHANNEL: u8 = 18; 587 const CHANNEL: u8 = 18;
571 } 588 }
572 589
573 #[cfg(not(stm32g4x1))] 590 #[cfg(not(stm32g4x1))]
574 impl VBatChannel for crate::peripherals::ADC5 { 591 impl SealedSpecialConverter<Vbat> for crate::peripherals::ADC5 {
575 const CHANNEL: u8 = 17; 592 const CHANNEL: u8 = 17;
576 } 593 }
577} 594}
@@ -579,13 +596,13 @@ mod g4 {
579// TODO this should look at each ADC individually and impl the correct channels 596// TODO this should look at each ADC individually and impl the correct channels
580#[cfg(stm32h7)] 597#[cfg(stm32h7)]
581mod h7 { 598mod h7 {
582 impl<T: Instance> TemperatureChannel for T { 599 impl<T: Instance> SealedSpecialConverter<Temperature> for T {
583 const CHANNEL: u8 = 18; 600 const CHANNEL: u8 = 18;
584 } 601 }
585 impl<T: Instance> VrefChannel for T { 602 impl<T: Instance> SealedSpecialConverter<VrefInt> for T {
586 const CHANNEL: u8 = 19; 603 const CHANNEL: u8 = 19;
587 } 604 }
588 impl<T: Instance> VBatChannel for T { 605 impl<T: Instance> SealedSpecialConverter<Vbat> for T {
589 // TODO this should be 14 for H7a/b/35 606 // TODO this should be 14 for H7a/b/35
590 const CHANNEL: u8 = 17; 607 const CHANNEL: u8 = 17;
591 } 608 }
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
new file mode 100644
index 000000000..ccaa5d1b2
--- /dev/null
+++ b/embassy-stm32/src/adc/injected.rs
@@ -0,0 +1,44 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use super::{AnyAdcChannel, SampleTime};
8#[allow(unused_imports)]
9use crate::adc::Instance;
10use crate::adc::{Adc, AnyInstance};
11
12/// Injected ADC sequence with owned channels.
13pub struct InjectedAdc<T: Instance, const N: usize> {
14 _channels: [(AnyAdcChannel<T>, SampleTime); N],
15 _phantom: PhantomData<T>,
16}
17
18impl<T: Instance, const N: usize> InjectedAdc<T, N> {
19 pub(crate) fn new(channels: [(AnyAdcChannel<T>, SampleTime); N]) -> Self {
20 Self {
21 _channels: channels,
22 _phantom: PhantomData,
23 }
24 }
25
26 pub fn stop_injected_conversions(&mut self) {
27 Adc::<T>::stop_injected_conversions()
28 }
29
30 pub fn start_injected_conversions(&mut self) {
31 Adc::<T>::start_injected_conversions()
32 }
33
34 pub fn read_injected_samples(&mut self) -> [u16; N] {
35 InjectedAdc::<T, N>::read_injected_data()
36 }
37}
38
39impl<T: Instance + AnyInstance, const N: usize> Drop for InjectedAdc<T, N> {
40 fn drop(&mut self) {
41 T::stop();
42 compiler_fence(Ordering::SeqCst);
43 }
44}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index ea986f4cf..6d53d9b91 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -17,38 +17,38 @@
17#[cfg_attr(adc_c0, path = "c0.rs")] 17#[cfg_attr(adc_c0, path = "c0.rs")]
18mod _version; 18mod _version;
19 19
20#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
21mod ringbuffered;
22
20use core::marker::PhantomData; 23use core::marker::PhantomData;
21 24
22#[allow(unused)] 25#[allow(unused)]
23#[cfg(not(any(adc_f3v3, adc_wba)))] 26#[cfg(not(any(adc_f3v3, adc_wba)))]
24pub use _version::*; 27pub use _version::*;
25use embassy_hal_internal::{impl_peripheral, PeripheralType}; 28use embassy_hal_internal::{PeripheralType, impl_peripheral};
26#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 29#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
27use embassy_sync::waitqueue::AtomicWaker; 30use embassy_sync::waitqueue::AtomicWaker;
31#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
32pub use ringbuffered::RingBufferedAdc;
28 33
29#[cfg(any(adc_u5, adc_wba))] 34#[cfg(any(adc_u5, adc_wba))]
30#[path = "adc4.rs"] 35#[path = "adc4.rs"]
31pub mod adc4; 36pub mod adc4;
32 37
38#[allow(unused)]
39pub(self) use crate::block_for_us as blocking_delay_us;
33pub use crate::pac::adc::vals; 40pub use crate::pac::adc::vals;
34#[cfg(not(any(adc_f1, adc_f3v3)))] 41#[cfg(not(any(adc_f1, adc_f3v3)))]
35pub use crate::pac::adc::vals::Res as Resolution; 42pub use crate::pac::adc::vals::Res as Resolution;
36pub use crate::pac::adc::vals::SampleTime; 43pub use crate::pac::adc::vals::SampleTime;
37use crate::peripherals; 44use crate::peripherals;
38 45
39#[cfg(not(adc_wba))] 46dma_trait!(RxDma, AnyInstance);
40dma_trait!(RxDma, Instance);
41#[cfg(adc_u5)]
42dma_trait!(RxDma4, adc4::Instance);
43#[cfg(adc_wba)]
44dma_trait!(RxDma4, adc4::Instance);
45 47
46/// Analog to Digital driver. 48/// Analog to Digital driver.
47pub struct Adc<'d, T: Instance> { 49pub struct Adc<'d, T: AnyInstance> {
48 #[allow(unused)] 50 #[allow(unused)]
49 adc: crate::Peri<'d, T>, 51 adc: crate::Peri<'d, T>,
50 #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))]
51 sample_time: SampleTime,
52} 52}
53 53
54#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] 54#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))]
@@ -82,22 +82,318 @@ pub(crate) trait SealedAdcChannel<T> {
82 82
83 #[allow(unused)] 83 #[allow(unused)]
84 fn channel(&self) -> u8; 84 fn channel(&self) -> u8;
85
86 #[allow(unused)]
87 fn is_differential(&self) -> bool {
88 false
89 }
85} 90}
86 91
87/// Performs a busy-wait delay for a specified number of microseconds. 92// Temporary patch for ADCs that have not implemented the standard iface yet
88#[allow(unused)] 93#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))]
89pub(crate) fn blocking_delay_us(us: u32) { 94trait_set::trait_set! {
90 #[cfg(feature = "time")] 95 pub trait AnyInstance = Instance;
91 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); 96}
92 #[cfg(not(feature = "time"))] 97
93 { 98#[cfg(any(
94 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 99 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
95 let us = us as u64; 100))]
96 let cycles = freq * us / 1_000_000; 101pub trait BasicAnyInstance {
97 cortex_m::asm::delay(cycles as u32); 102 type SampleTime;
103}
104
105#[cfg(any(
106 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
107))]
108pub(self) trait SealedAnyInstance: BasicAnyInstance {
109 fn enable();
110 fn start();
111 fn stop();
112 fn convert() -> u16;
113 fn configure_dma(conversion_mode: ConversionMode);
114 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>);
115 #[allow(dead_code)]
116 fn dr() -> *mut u16;
117}
118
119// On chips without ADC4, AnyInstance is an Instance
120#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))]
121#[allow(private_bounds)]
122pub trait AnyInstance: SealedAnyInstance + Instance {}
123
124// On chips with ADC4, AnyInstance is an Instance or adc4::Instance
125#[cfg(any(adc_v4, adc_u5, adc_wba))]
126#[allow(private_bounds)]
127pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {}
128
129// Implement AnyInstance automatically for SealedAnyInstance
130#[cfg(any(
131 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
132))]
133impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T {
134 type SampleTime = SampleTime;
135}
136
137#[cfg(any(
138 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
139))]
140impl<T: SealedAnyInstance + Instance> AnyInstance for T {}
141
142#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
143/// Number of samples used for averaging.
144#[derive(Copy, Clone, Debug)]
145#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum Averaging {
147 Disabled,
148 Samples2,
149 Samples4,
150 Samples8,
151 Samples16,
152 Samples32,
153 Samples64,
154 Samples128,
155 Samples256,
156 #[cfg(any(adc_c0, adc_v4, adc_u5))]
157 Samples512,
158 #[cfg(any(adc_c0, adc_v4, adc_u5))]
159 Samples1024,
160}
161
162#[cfg(any(
163 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
164))]
165pub(crate) enum ConversionMode {
166 // Should match the cfg on "read" below
167 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
168 Singular,
169 // Should match the cfg on "into_ring_buffered" below
170 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
171 Repeated(RegularConversionMode),
172}
173
174// Should match the cfg on "into_ring_buffered" below
175#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
176// Conversion mode for regular ADC channels
177#[derive(Copy, Clone)]
178pub enum RegularConversionMode {
179 // Samples as fast as possible
180 Continuous,
181 #[cfg(adc_g4)]
182 // Sample at rate determined by external trigger
183 Triggered(ConversionTrigger),
184}
185
186impl<'d, T: AnyInstance> Adc<'d, T> {
187 #[cfg(any(
188 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0
189 ))]
190 /// Read an ADC pin.
191 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 {
192 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
193 channel.setup();
194
195 // Ensure no conversions are ongoing
196 T::stop();
197 #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))]
198 T::enable();
199 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
200
201 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
202 //
203 // TODO: If hardware allows, enable after configure_sequence on all chips
204 #[cfg(any(adc_g4, adc_h5))]
205 T::enable();
206
207 T::convert()
208 }
209
210 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
211 /// Read one or multiple ADC regular channels using DMA.
212 ///
213 /// `sequence` iterator and `readings` must have the same length.
214 ///
215 /// Example
216 /// ```rust,ignore
217 /// use embassy_stm32::adc::{Adc, AdcChannel}
218 ///
219 /// let mut adc = Adc::new(p.ADC1);
220 /// let mut adc_pin0 = p.PA0.into();
221 /// let mut adc_pin1 = p.PA1.into();
222 /// let mut measurements = [0u16; 2];
223 ///
224 /// adc.read(
225 /// p.DMA1_CH2.reborrow(),
226 /// [
227 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
228 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
229 /// ]
230 /// .into_iter(),
231 /// &mut measurements,
232 /// )
233 /// .await;
234 /// defmt::info!("measurements: {}", measurements);
235 /// ```
236 ///
237 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
238 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
239 ///
240 /// Note: Depending on hardware limitations, this method may require channels to be passed
241 /// in order or require the sequence to have the same sample time for all channnels, depending
242 /// on the number and properties of the channels in the sequence. This method will panic if
243 /// the hardware cannot deliver the requested configuration.
244 pub async fn read(
245 &mut self,
246 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
247 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, T::SampleTime)>,
248 readings: &mut [u16],
249 ) {
250 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
251 assert!(
252 sequence.len() == readings.len(),
253 "Sequence length must be equal to readings length"
254 );
255 assert!(
256 sequence.len() <= 16,
257 "Asynchronous read sequence cannot be more than 16 in length"
258 );
259
260 // Ensure no conversions are ongoing
261 T::stop();
262 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
263 T::enable();
264
265 T::configure_sequence(
266 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
267 );
268
269 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
270 //
271 // TODO: If hardware allows, enable after configure_sequence on all chips
272 #[cfg(any(adc_g4, adc_h5))]
273 T::enable();
274 T::configure_dma(ConversionMode::Singular);
275
276 let request = rx_dma.request();
277 let transfer =
278 unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::dr(), readings, Default::default()) };
279
280 T::start();
281
282 // Wait for conversion sequence to finish.
283 transfer.await;
284
285 // Ensure conversions are finished.
286 T::stop();
287 }
288
289 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
290 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
291 ///
292 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
293 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
294 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
295 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
296 /// defines the period at which the buffer should be read.
297 ///
298 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
299 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
300 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
301 /// the buffer length should be `3 * 40 = 120`.
302 ///
303 /// # Parameters
304 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
305 /// - `dma_buf`: The buffer where DMA stores ADC samples.
306 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
307 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
308 ///
309 /// # Returns
310 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
311 ///
312 /// Note: Depending on hardware limitations, this method may require channels to be passed
313 /// in order or require the sequence to have the same sample time for all channnels, depending
314 /// on the number and properties of the channels in the sequence. This method will panic if
315 /// the hardware cannot deliver the requested configuration.
316 pub fn into_ring_buffered<'a>(
317 self,
318 dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>,
319 dma_buf: &'a mut [u16],
320 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, T::SampleTime)>,
321 mode: RegularConversionMode,
322 ) -> RingBufferedAdc<'a, T> {
323 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
324 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
325 assert!(
326 sequence.len() <= 16,
327 "Asynchronous read sequence cannot be more than 16 in length"
328 );
329 // Ensure no conversions are ongoing
330 T::stop();
331 #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
332 T::enable();
333
334 T::configure_sequence(
335 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
336 );
337
338 // On chips with differential channels, enable after configure_sequence to allow setting differential channels
339 //
340 // TODO: If hardware allows, enable after configure_sequence on all chips
341 #[cfg(any(adc_g4, adc_h5))]
342 T::enable();
343 T::configure_dma(ConversionMode::Repeated(mode));
344
345 core::mem::forget(self);
346
347 RingBufferedAdc::new(dma, dma_buf)
98 } 348 }
99} 349}
100 350
351pub(self) trait SpecialChannel {}
352
353/// Implemented for ADCs that have a special channel
354trait SealedSpecialConverter<T: SpecialChannel + Sized> {
355 const CHANNEL: u8;
356}
357
358#[allow(private_bounds)]
359pub trait SpecialConverter<T: SpecialChannel + Sized>: SealedSpecialConverter<T> {}
360
361impl<C: SpecialChannel + Sized, T: SealedSpecialConverter<C>> SpecialConverter<C> for T {}
362
363impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> AdcChannel<T> for C {}
364impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> SealedAdcChannel<T> for C {
365 fn channel(&self) -> u8 {
366 T::CHANNEL
367 }
368}
369
370pub struct VrefInt;
371impl SpecialChannel for VrefInt {}
372
373impl VrefInt {
374 #[cfg(any(adc_f3v1, adc_f3v2))]
375 /// The value that vref would be if vdda was at 3300mv
376 pub fn calibrated_value(&self) -> u16 {
377 crate::pac::VREFINTCAL.data().read()
378 }
379}
380
381/// Internal temperature channel.
382pub struct Temperature;
383impl SpecialChannel for Temperature {}
384
385/// Internal battery voltage channel.
386pub struct Vbat;
387impl SpecialChannel for Vbat {}
388
389/// Vcore channel.
390pub struct Vcore;
391impl SpecialChannel for Vcore {}
392
393/// Internal dac channel.
394pub struct Dac;
395impl SpecialChannel for Dac {}
396
101/// ADC instance. 397/// ADC instance.
102#[cfg(not(any( 398#[cfg(not(any(
103 adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, 399 adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs,
@@ -127,6 +423,7 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
127 423
128 AnyAdcChannel { 424 AnyAdcChannel {
129 channel: self.channel(), 425 channel: self.channel(),
426 is_differential: self.is_differential(),
130 _phantom: PhantomData, 427 _phantom: PhantomData,
131 } 428 }
132 } 429 }
@@ -138,14 +435,19 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
138/// storing them in an array. 435/// storing them in an array.
139pub struct AnyAdcChannel<T> { 436pub struct AnyAdcChannel<T> {
140 channel: u8, 437 channel: u8,
438 is_differential: bool,
141 _phantom: PhantomData<T>, 439 _phantom: PhantomData<T>,
142} 440}
143impl_peripheral!(AnyAdcChannel<T: Instance>); 441impl_peripheral!(AnyAdcChannel<T: AnyInstance>);
144impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {} 442impl<T: AnyInstance> AdcChannel<T> for AnyAdcChannel<T> {}
145impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> { 443impl<T: AnyInstance> SealedAdcChannel<T> for AnyAdcChannel<T> {
146 fn channel(&self) -> u8 { 444 fn channel(&self) -> u8 {
147 self.channel 445 self.channel
148 } 446 }
447
448 fn is_differential(&self) -> bool {
449 self.is_differential
450 }
149} 451}
150 452
151impl<T> AnyAdcChannel<T> { 453impl<T> AnyAdcChannel<T> {
@@ -264,6 +566,39 @@ macro_rules! impl_adc_pin {
264 }; 566 };
265} 567}
266 568
569#[allow(unused_macros)]
570macro_rules! impl_adc_pair {
571 ($inst:ident, $pin:ident, $npin:ident, $ch:expr) => {
572 impl crate::adc::AdcChannel<peripherals::$inst>
573 for (
574 crate::Peri<'_, crate::peripherals::$pin>,
575 crate::Peri<'_, crate::peripherals::$npin>,
576 )
577 {
578 }
579 impl crate::adc::SealedAdcChannel<peripherals::$inst>
580 for (
581 crate::Peri<'_, crate::peripherals::$pin>,
582 crate::Peri<'_, crate::peripherals::$npin>,
583 )
584 {
585 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
586 fn setup(&mut self) {
587 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0);
588 <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1);
589 }
590
591 fn channel(&self) -> u8 {
592 $ch
593 }
594
595 fn is_differential(&self) -> bool {
596 true
597 }
598 }
599 };
600}
601
267/// Get the maximum reading value for this resolution. 602/// Get the maximum reading value for this resolution.
268/// 603///
269/// This is `2**n - 1`. 604/// This is `2**n - 1`.
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
new file mode 100644
index 000000000..5437866d3
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -0,0 +1,180 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use crate::adc::AnyInstance;
8#[allow(unused_imports)]
9use crate::adc::{Instance, RxDma};
10#[allow(unused_imports)]
11use crate::dma::{ReadableRingBuffer, TransferOptions};
12use crate::rcc;
13
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct OverrunError;
16
17pub struct RingBufferedAdc<'d, T: Instance> {
18 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u16>,
20}
21
22impl<'d, T: Instance + AnyInstance> RingBufferedAdc<'d, T> {
23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
24 //dma side setup
25 let opts = TransferOptions {
26 half_transfer_ir: true,
27 circular: true,
28 ..Default::default()
29 };
30
31 // Safety: we forget the struct before this function returns.
32 let request = dma.request();
33
34 let ring_buf =
35 unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) };
36
37 Self {
38 _phantom: PhantomData,
39 ring_buf,
40 }
41 }
42
43 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
44 pub fn start(&mut self) {
45 compiler_fence(Ordering::SeqCst);
46 self.ring_buf.start();
47
48 T::start();
49 }
50
51 pub fn stop(&mut self) {
52 self.ring_buf.request_pause();
53
54 compiler_fence(Ordering::SeqCst);
55 }
56
57 pub fn clear(&mut self) {
58 self.ring_buf.clear();
59 }
60
61 /// Reads measurements from the DMA ring buffer.
62 ///
63 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
64 /// The length of the `measurements` array should be exactly half of the DMA buffer length.
65 /// Because interrupts are only generated if half or full DMA transfer completes.
66 ///
67 /// Each call to `read` will populate the `measurements` array in the same order as the channels
68 /// defined with `sequence`. There will be many sequences worth of measurements in this array
69 /// because it only returns if at least half of the DMA buffer is filled. For example if 2
70 /// channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
71 ///
72 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly
73 /// running tasks. Otherwise, you'll see constant Overrun errors occurring, this means that
74 /// you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
75 /// Example:
76 /// ```rust,ignore
77 /// const DMA_BUF_LEN: usize = 120;
78 /// use embassy_stm32::adc::{Adc, AdcChannel}
79 ///
80 /// let mut adc = Adc::new(p.ADC1);
81 /// let mut adc_pin0 = p.PA0.degrade_adc();
82 /// let mut adc_pin1 = p.PA1.degrade_adc();
83 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
84 ///
85 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
86 /// p.DMA2_CH0,
87 /// adc_dma_buf, [
88 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
89 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
90 /// ].into_iter());
91 ///
92 ///
93 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
94 /// loop {
95 /// match ring_buffered_adc.read(&mut measurements).await {
96 /// Ok(_) => {
97 /// defmt::info!("adc1: {}", measurements);
98 /// }
99 /// Err(e) => {
100 /// defmt::warn!("Error: {:?}", e);
101 /// }
102 /// }
103 /// }
104 /// ```
105 ///
106 ///
107 /// [`teardown_adc`]: #method.teardown_adc
108 /// [`start_continuous_sampling`]: #method.start_continuous_sampling
109 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
110 assert_eq!(
111 self.ring_buf.capacity() / 2,
112 measurements.len(),
113 "Buffer size must be half the size of the ring buffer"
114 );
115
116 if !self.ring_buf.is_running() {
117 self.start();
118 }
119
120 #[cfg(adc_v2)]
121 {
122 // Clear overrun flag if set.
123 if T::regs().sr().read().ovr() {
124 self.stop();
125
126 return Err(OverrunError);
127 }
128 }
129
130 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
131 }
132
133 /// Read bytes that are readily available in the ring buffer.
134 /// If no bytes are currently available in the buffer the call waits until the some
135 /// bytes are available (at least one byte and at most half the buffer size)
136 ///
137 /// Background receive is started if `start_continuous_sampling()` has not been previously called.
138 ///
139 /// Receive in the background is terminated if an error is returned.
140 /// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`.
141 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
142 if !self.ring_buf.is_running() {
143 self.start();
144 }
145
146 #[cfg(adc_v2)]
147 {
148 // Clear overrun flag if set.
149 if T::regs().sr().read().ovr() {
150 self.stop();
151
152 return Err(OverrunError);
153 }
154 }
155 loop {
156 match self.ring_buf.read(buf) {
157 Ok((0, _)) => {}
158 Ok((len, _)) => {
159 return Ok(len);
160 }
161 Err(_) => {
162 self.ring_buf.request_pause();
163
164 return Err(OverrunError);
165 }
166 }
167 }
168 }
169}
170
171impl<T: Instance + AnyInstance> Drop for RingBufferedAdc<'_, T> {
172 fn drop(&mut self) {
173 T::stop();
174
175 compiler_fence(Ordering::SeqCst);
176
177 self.ring_buf.request_pause();
178 rcc::disable::<T>();
179 }
180}
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
deleted file mode 100644
index 6f69e8486..000000000
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ /dev/null
@@ -1,432 +0,0 @@
1use core::marker::PhantomData;
2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering};
4
5use stm32_metapac::adc::vals::SampleTime;
6
7use crate::adc::{Adc, AdcChannel, Instance, RxDma};
8use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
9use crate::pac::adc::vals;
10use crate::{rcc, Peri};
11
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OverrunError;
14
15fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
16 r.sr().modify(|regs| {
17 regs.set_eoc(false);
18 regs.set_ovr(false);
19 });
20}
21
22#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
23pub enum Sequence {
24 One,
25 Two,
26 Three,
27 Four,
28 Five,
29 Six,
30 Seven,
31 Eight,
32 Nine,
33 Ten,
34 Eleven,
35 Twelve,
36 Thirteen,
37 Fourteen,
38 Fifteen,
39 Sixteen,
40}
41
42impl From<Sequence> for u8 {
43 fn from(s: Sequence) -> u8 {
44 match s {
45 Sequence::One => 0,
46 Sequence::Two => 1,
47 Sequence::Three => 2,
48 Sequence::Four => 3,
49 Sequence::Five => 4,
50 Sequence::Six => 5,
51 Sequence::Seven => 6,
52 Sequence::Eight => 7,
53 Sequence::Nine => 8,
54 Sequence::Ten => 9,
55 Sequence::Eleven => 10,
56 Sequence::Twelve => 11,
57 Sequence::Thirteen => 12,
58 Sequence::Fourteen => 13,
59 Sequence::Fifteen => 14,
60 Sequence::Sixteen => 15,
61 }
62 }
63}
64
65impl From<u8> for Sequence {
66 fn from(val: u8) -> Self {
67 match val {
68 0 => Sequence::One,
69 1 => Sequence::Two,
70 2 => Sequence::Three,
71 3 => Sequence::Four,
72 4 => Sequence::Five,
73 5 => Sequence::Six,
74 6 => Sequence::Seven,
75 7 => Sequence::Eight,
76 8 => Sequence::Nine,
77 9 => Sequence::Ten,
78 10 => Sequence::Eleven,
79 11 => Sequence::Twelve,
80 12 => Sequence::Thirteen,
81 13 => Sequence::Fourteen,
82 14 => Sequence::Fifteen,
83 15 => Sequence::Sixteen,
84 _ => panic!("Invalid sequence number"),
85 }
86 }
87}
88
89pub struct RingBufferedAdc<'d, T: Instance> {
90 _phantom: PhantomData<T>,
91 ring_buf: ReadableRingBuffer<'d, u16>,
92}
93
94impl<'d, T: Instance> Adc<'d, T> {
95 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
96 ///
97 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
98 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
99 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
100 ///
101 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
102 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
103 ///
104 /// [`read`]: #method.read
105 pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> {
106 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
107
108 let opts: crate::dma::TransferOptions = TransferOptions {
109 half_transfer_ir: true,
110 priority: Priority::VeryHigh,
111 ..Default::default()
112 };
113
114 // Safety: we forget the struct before this function returns.
115 let rx_src = T::regs().dr().as_ptr() as *mut u16;
116 let request = dma.request();
117
118 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
119
120 // Don't disable the clock
121 mem::forget(self);
122
123 RingBufferedAdc {
124 _phantom: PhantomData,
125 ring_buf,
126 }
127 }
128}
129
130impl<'d, T: Instance> RingBufferedAdc<'d, T> {
131 fn is_on() -> bool {
132 T::regs().cr2().read().adon()
133 }
134
135 fn stop_adc() {
136 T::regs().cr2().modify(|reg| {
137 reg.set_adon(false);
138 });
139 }
140
141 fn start_adc() {
142 T::regs().cr2().modify(|reg| {
143 reg.set_adon(true);
144 });
145 }
146
147 /// Sets the channel sample time
148 ///
149 /// ## SAFETY:
150 /// - ADON == 0 i.e ADC must not be enabled when this is called.
151 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
152 if ch <= 9 {
153 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
154 } else {
155 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
156 }
157 }
158
159 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
160 let ch_iter = ch.iter();
161 for idx in ch_iter {
162 unsafe {
163 Self::set_channel_sample_time(*idx, sample_time);
164 }
165 }
166 }
167
168 pub fn set_sample_sequence(
169 &mut self,
170 sequence: Sequence,
171 channel: &mut impl AdcChannel<T>,
172 sample_time: SampleTime,
173 ) {
174 let was_on = Self::is_on();
175 if !was_on {
176 Self::start_adc();
177 }
178
179 // Check the sequence is long enough
180 T::regs().sqr1().modify(|r| {
181 let prev: Sequence = r.l().into();
182 if prev < sequence {
183 let new_l: Sequence = sequence;
184 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
185 r.set_l(sequence.into())
186 } else {
187 r.set_l(prev.into())
188 }
189 });
190
191 // Set this GPIO as an analog input.
192 channel.setup();
193
194 // Set the channel in the right sequence field.
195 match sequence {
196 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
197 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
198 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
199 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
200 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
201 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
202 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
203 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
204 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
205 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
206 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
207 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
208 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
209 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
210 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
211 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
212 };
213
214 if !was_on {
215 Self::stop_adc();
216 }
217
218 self.set_channels_sample_time(&[channel.channel()], sample_time);
219
220 Self::start_adc();
221 }
222
223 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
224 pub fn start(&mut self) -> Result<(), OverrunError> {
225 self.setup_adc();
226 self.ring_buf.clear();
227
228 Ok(())
229 }
230
231 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
232 self.teardown_adc();
233 Err(err)
234 }
235
236 /// Stops DMA transfer.
237 /// It does not turn off ADC.
238 /// Calling `start` restarts continuous DMA transfer.
239 ///
240 /// [`start`]: #method.start
241 pub fn teardown_adc(&mut self) {
242 // Stop the DMA transfer
243 self.ring_buf.request_pause();
244
245 let r = T::regs();
246
247 // Stop ADC
248 r.cr2().modify(|reg| {
249 // Stop ADC
250 reg.set_swstart(false);
251 // Stop DMA
252 reg.set_dma(false);
253 });
254
255 r.cr1().modify(|w| {
256 // Disable interrupt for end of conversion
257 w.set_eocie(false);
258 // Disable interrupt for overrun
259 w.set_ovrie(false);
260 });
261
262 clear_interrupt_flags(r);
263
264 compiler_fence(Ordering::SeqCst);
265 }
266
267 fn setup_adc(&mut self) {
268 compiler_fence(Ordering::SeqCst);
269
270 self.ring_buf.start();
271
272 let r = T::regs();
273
274 // Enable ADC
275 let was_on = Self::is_on();
276 if !was_on {
277 r.cr2().modify(|reg| {
278 reg.set_adon(false);
279 reg.set_swstart(false);
280 });
281 }
282
283 // Clear all interrupts
284 r.sr().modify(|regs| {
285 regs.set_eoc(false);
286 regs.set_ovr(false);
287 regs.set_strt(false);
288 });
289
290 r.cr1().modify(|w| {
291 // Enable interrupt for end of conversion
292 w.set_eocie(true);
293 // Enable interrupt for overrun
294 w.set_ovrie(true);
295 // Scanning converisons of multiple channels
296 w.set_scan(true);
297 // Continuous conversion mode
298 w.set_discen(false);
299 });
300
301 r.cr2().modify(|w| {
302 // Enable DMA mode
303 w.set_dma(true);
304 // Enable continuous conversions
305 w.set_cont(true);
306 // DMA requests are issues as long as DMA=1 and data are converted.
307 w.set_dds(vals::Dds::CONTINUOUS);
308 // EOC flag is set at the end of each conversion.
309 w.set_eocs(vals::Eocs::EACH_CONVERSION);
310 });
311
312 // Begin ADC conversions
313 T::regs().cr2().modify(|reg| {
314 reg.set_adon(true);
315 reg.set_swstart(true);
316 });
317
318 super::blocking_delay_us(3);
319 }
320
321 /// Read bytes that are readily available in the ring buffer.
322 /// If no bytes are currently available in the buffer the call waits until the some
323 /// bytes are available (at least one byte and at most half the buffer size)
324 ///
325 /// Background receive is started if `start()` has not been previously called.
326 ///
327 /// Receive in the background is terminated if an error is returned.
328 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
329 pub fn blocking_read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
330 let r = T::regs();
331
332 // Start background receive if it was not already started
333 if !r.cr2().read().dma() {
334 self.start()?;
335 }
336
337 // Clear overrun flag if set.
338 if r.sr().read().ovr() {
339 return self.stop(OverrunError);
340 }
341
342 loop {
343 match self.ring_buf.read(buf) {
344 Ok((0, _)) => {}
345 Ok((len, _)) => {
346 return Ok(len);
347 }
348 Err(_) => {
349 return self.stop(OverrunError);
350 }
351 }
352 }
353 }
354
355 /// Reads measurements from the DMA ring buffer.
356 ///
357 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
358 /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
359 ///
360 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
361 /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
362 /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
363 ///
364 /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` or `read` again.
365 ///
366 /// By default, the ADC fills the DMA buffer as quickly as possible. To control the sample rate, call `teardown_adc` after each readout, and then start the DMA again at the desired interval.
367 /// Note that even if using `teardown_adc` to control the sample rate, with each call to `read`, measurements equivalent to half the size of the DMA buffer are still collected.
368 ///
369 /// Example:
370 /// ```rust,ignore
371 /// const DMA_BUF_LEN: usize = 120;
372 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
373 /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
374 ///
375 /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
376 /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
377 /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
378 ///
379 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
380 /// loop {
381 /// match adc.read(&mut measurements).await {
382 /// Ok(_) => {
383 /// defmt::info!("adc1: {}", measurements);
384 /// // Only needed to manually control sample rate.
385 /// adc.teardown_adc();
386 /// }
387 /// Err(e) => {
388 /// defmt::warn!("Error: {:?}", e);
389 /// // DMA overrun, next call to `read` restarts ADC.
390 /// }
391 /// }
392 ///
393 /// // Manually control sample rate.
394 /// Timer::after_millis(100).await;
395 /// }
396 /// ```
397 ///
398 ///
399 /// [`set_sample_sequence`]: #method.set_sample_sequence
400 /// [`teardown_adc`]: #method.teardown_adc
401 /// [`start`]: #method.start
402 pub async fn read<const N: usize>(&mut self, measurements: &mut [u16; N]) -> Result<usize, OverrunError> {
403 assert_eq!(
404 self.ring_buf.capacity() / 2,
405 N,
406 "Buffer size must be half the size of the ring buffer"
407 );
408
409 let r = T::regs();
410
411 // Start background receive if it was not already started
412 if !r.cr2().read().dma() {
413 self.start()?;
414 }
415
416 // Clear overrun flag if set.
417 if r.sr().read().ovr() {
418 return self.stop(OverrunError);
419 }
420 match self.ring_buf.read_exact(measurements).await {
421 Ok(len) => Ok(len),
422 Err(_) => self.stop(OverrunError),
423 }
424 }
425}
426
427impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
428 fn drop(&mut self) {
429 self.teardown_adc();
430 rcc::disable::<T>();
431 }
432}
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index d09374876..58c30935f 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -5,11 +5,12 @@ use core::task::Poll;
5#[cfg(adc_l0)] 5#[cfg(adc_l0)]
6use stm32_metapac::adc::vals::Ckmode; 6use stm32_metapac::adc::vals::Ckmode;
7 7
8use super::blocking_delay_us; 8#[cfg(not(adc_l0))]
9use super::Vbat;
10use super::{Temperature, VrefInt, blocking_delay_us};
9use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 11use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
10use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
11use crate::peripherals::ADC1; 13use crate::{Peri, interrupt, rcc};
12use crate::{interrupt, rcc, Peri};
13 14
14mod watchdog_v1; 15mod watchdog_v1;
15pub use watchdog_v1::WatchdogChannels; 16pub use watchdog_v1::WatchdogChannels;
@@ -42,36 +43,23 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
42} 43}
43 44
44#[cfg(not(adc_l0))] 45#[cfg(not(adc_l0))]
45pub struct Vbat; 46impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
46 47 const CHANNEL: u8 = 18;
47#[cfg(not(adc_l0))] 48}
48impl AdcChannel<ADC1> for Vbat {}
49 49
50#[cfg(not(adc_l0))] 50#[cfg(not(adc_l0))]
51impl super::SealedAdcChannel<ADC1> for Vbat { 51impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
52 fn channel(&self) -> u8 { 52 const CHANNEL: u8 = 17;
53 18
54 }
55} 53}
56 54
57pub struct Vref; 55#[cfg(adc_l0)]
58impl AdcChannel<ADC1> for Vref {} 56impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
59impl super::SealedAdcChannel<ADC1> for Vref { 57 const CHANNEL: u8 = 18;
60 fn channel(&self) -> u8 {
61 17
62 }
63} 58}
64 59
65pub struct Temperature; 60#[cfg(not(adc_l0))]
66impl AdcChannel<ADC1> for Temperature {} 61impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
67impl super::SealedAdcChannel<ADC1> for Temperature { 62 const CHANNEL: u8 = 16;
68 fn channel(&self) -> u8 {
69 if cfg!(adc_l0) {
70 18
71 } else {
72 16
73 }
74 }
75} 63}
76 64
77impl<'d, T: Instance> Adc<'d, T> { 65impl<'d, T: Instance> Adc<'d, T> {
@@ -118,10 +106,7 @@ impl<'d, T: Instance> Adc<'d, T> {
118 T::Interrupt::enable(); 106 T::Interrupt::enable();
119 } 107 }
120 108
121 Self { 109 Self { adc }
122 adc,
123 sample_time: SampleTime::from_bits(0),
124 }
125 } 110 }
126 111
127 #[cfg(not(adc_l0))] 112 #[cfg(not(adc_l0))]
@@ -134,12 +119,12 @@ impl<'d, T: Instance> Adc<'d, T> {
134 Vbat 119 Vbat
135 } 120 }
136 121
137 pub fn enable_vref(&self) -> Vref { 122 pub fn enable_vref(&self) -> VrefInt {
138 // Table 28. Embedded internal reference voltage 123 // Table 28. Embedded internal reference voltage
139 // tstart = 10μs 124 // tstart = 10μs
140 T::regs().ccr().modify(|reg| reg.set_vrefen(true)); 125 T::regs().ccr().modify(|reg| reg.set_vrefen(true));
141 blocking_delay_us(10); 126 blocking_delay_us(10);
142 Vref 127 VrefInt
143 } 128 }
144 129
145 pub fn enable_temperature(&self) -> Temperature { 130 pub fn enable_temperature(&self) -> Temperature {
@@ -153,10 +138,6 @@ impl<'d, T: Instance> Adc<'d, T> {
153 Temperature 138 Temperature
154 } 139 }
155 140
156 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
157 self.sample_time = sample_time;
158 }
159
160 pub fn set_resolution(&mut self, resolution: Resolution) { 141 pub fn set_resolution(&mut self, resolution: Resolution) {
161 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 142 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
162 } 143 }
@@ -167,12 +148,13 @@ impl<'d, T: Instance> Adc<'d, T> {
167 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode)); 148 T::regs().cfgr2().modify(|reg| reg.set_ckmode(ckmode));
168 } 149 }
169 150
170 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 151 pub async fn read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
171 let ch_num = channel.channel(); 152 let ch_num = channel.channel();
172 channel.setup(); 153 channel.setup();
173 154
174 // A.7.5 Single conversion sequence code example - Software trigger 155 // A.7.5 Single conversion sequence code example - Software trigger
175 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true)); 156 T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true));
157 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into()));
176 158
177 self.convert().await 159 self.convert().await
178 } 160 }
@@ -183,7 +165,6 @@ impl<'d, T: Instance> Adc<'d, T> {
183 reg.set_eosmp(true); 165 reg.set_eosmp(true);
184 }); 166 });
185 167
186 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
187 T::regs().ier().modify(|w| w.set_eocie(true)); 168 T::regs().ier().modify(|w| w.set_eocie(true));
188 T::regs().cr().modify(|reg| reg.set_adstart(true)); 169 T::regs().cr().modify(|reg| reg.set_adstart(true));
189 170
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index e94a25b24..3c4431ae0 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,23 +1,40 @@
1use super::blocking_delay_us; 1use core::sync::atomic::{Ordering, compiler_fence};
2use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 2
3use crate::peripherals::ADC1; 3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us};
4use crate::adc::{Adc, Instance, Resolution, SampleTime};
5use crate::pac::adc::vals;
6pub use crate::pac::adccommon::vals::Adcpre;
4use crate::time::Hertz; 7use crate::time::Hertz;
5use crate::{rcc, Peri}; 8use crate::{Peri, rcc};
6 9
7mod ringbuffered_v2; 10fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
8pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; 11 r.sr().modify(|regs| {
12 regs.set_eoc(false);
13 regs.set_ovr(false);
14 });
15}
9 16
10/// Default VREF voltage used for sample conversion to millivolts. 17/// Default VREF voltage used for sample conversion to millivolts.
11pub const VREF_DEFAULT_MV: u32 = 3300; 18pub const VREF_DEFAULT_MV: u32 = 3300;
12/// VREF voltage used for factory calibration of VREFINTCAL register. 19/// VREF voltage used for factory calibration of VREFINTCAL register.
13pub const VREF_CALIB_MV: u32 = 3300; 20pub const VREF_CALIB_MV: u32 = 3300;
14 21
15pub struct VrefInt; 22impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC1 {
16impl AdcChannel<ADC1> for VrefInt {} 23 const CHANNEL: u8 = 17;
17impl super::SealedAdcChannel<ADC1> for VrefInt { 24}
18 fn channel(&self) -> u8 { 25
19 17 26#[cfg(any(stm32f2, stm32f40x, stm32f41x))]
20 } 27impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
28 const CHANNEL: u8 = 16;
29}
30
31#[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))]
32impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC1 {
33 const CHANNEL: u8 = 18;
34}
35
36impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC1 {
37 const CHANNEL: u8 = 18;
21} 38}
22 39
23impl VrefInt { 40impl VrefInt {
@@ -27,20 +44,6 @@ impl VrefInt {
27 } 44 }
28} 45}
29 46
30pub struct Temperature;
31impl AdcChannel<ADC1> for Temperature {}
32impl super::SealedAdcChannel<ADC1> for Temperature {
33 fn channel(&self) -> u8 {
34 cfg_if::cfg_if! {
35 if #[cfg(any(stm32f2, stm32f40x, stm32f41x))] {
36 16
37 } else {
38 18
39 }
40 }
41 }
42}
43
44impl Temperature { 47impl Temperature {
45 /// Time needed for temperature sensor readings to stabilize 48 /// Time needed for temperature sensor readings to stabilize
46 pub fn start_time_us() -> u32 { 49 pub fn start_time_us() -> u32 {
@@ -48,76 +51,176 @@ impl Temperature {
48 } 51 }
49} 52}
50 53
51pub struct Vbat; 54fn from_pclk2(freq: Hertz) -> Adcpre {
52impl AdcChannel<ADC1> for Vbat {} 55 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
53impl super::SealedAdcChannel<ADC1> for Vbat { 56 #[cfg(stm32f2)]
54 fn channel(&self) -> u8 { 57 const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
55 18 58 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
59 #[cfg(not(stm32f2))]
60 const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
61 let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0);
62 match raw_div {
63 0..=1 => Adcpre::DIV2,
64 2..=3 => Adcpre::DIV4,
65 4..=5 => Adcpre::DIV6,
66 6..=7 => Adcpre::DIV8,
67 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."),
56 } 68 }
57} 69}
58 70
59enum Prescaler { 71/// ADC configuration
60 Div2, 72#[derive(Default)]
61 Div4, 73pub struct AdcConfig {
62 Div6, 74 resolution: Option<Resolution>,
63 Div8,
64} 75}
65 76
66impl Prescaler { 77impl<T: Instance> super::SealedAnyInstance for T {
67 fn from_pclk2(freq: Hertz) -> Self { 78 fn dr() -> *mut u16 {
68 // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). 79 T::regs().dr().as_ptr() as *mut u16
69 #[cfg(stm32f2)] 80 }
70 const MAX_FREQUENCY: Hertz = Hertz(30_000_000); 81
71 // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. 82 fn enable() {
72 #[cfg(not(stm32f2))] 83 T::regs().cr2().modify(|reg| {
73 const MAX_FREQUENCY: Hertz = Hertz(36_000_000); 84 reg.set_adon(true);
74 let raw_div = freq.0 / MAX_FREQUENCY.0; 85 });
75 match raw_div { 86
76 0..=1 => Self::Div2, 87 blocking_delay_us(3);
77 2..=3 => Self::Div4, 88 }
78 4..=5 => Self::Div6, 89
79 6..=7 => Self::Div8, 90 fn start() {
80 _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), 91 // Begin ADC conversions
81 } 92 T::regs().cr2().modify(|reg| {
93 reg.set_swstart(true);
94 });
95 }
96
97 fn stop() {
98 let r = T::regs();
99
100 // Stop ADC
101 r.cr2().modify(|reg| {
102 // Stop ADC
103 reg.set_swstart(false);
104 // Stop ADC
105 reg.set_adon(false);
106 // Stop DMA
107 reg.set_dma(false);
108 });
109
110 r.cr1().modify(|w| {
111 // Disable interrupt for end of conversion
112 w.set_eocie(false);
113 // Disable interrupt for overrun
114 w.set_ovrie(false);
115 });
116
117 clear_interrupt_flags(r);
118
119 compiler_fence(Ordering::SeqCst);
82 } 120 }
83 121
84 fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre { 122 fn convert() -> u16 {
85 match self { 123 // clear end of conversion flag
86 Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2, 124 T::regs().sr().modify(|reg| {
87 Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4, 125 reg.set_eoc(false);
88 Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6, 126 });
89 Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8, 127
128 // Start conversion
129 T::regs().cr2().modify(|reg| {
130 reg.set_swstart(true);
131 });
132
133 while T::regs().sr().read().strt() == false {
134 // spin //wait for actual start
135 }
136 while T::regs().sr().read().eoc() == false {
137 // spin //wait for finish
90 } 138 }
139
140 T::regs().dr().read().0 as u16
91 } 141 }
92}
93 142
94impl<'d, T> Adc<'d, T> 143 fn configure_dma(conversion_mode: ConversionMode) {
95where 144 match conversion_mode {
96 T: Instance, 145 ConversionMode::Repeated(_) => {
97{ 146 let r = T::regs();
98 pub fn new(adc: Peri<'d, T>) -> Self { 147
99 rcc::enable_and_reset::<T>(); 148 // Clear all interrupts
149 r.sr().modify(|regs| {
150 regs.set_eoc(false);
151 regs.set_ovr(false);
152 regs.set_strt(false);
153 });
154
155 r.cr1().modify(|w| {
156 // Enable interrupt for end of conversion
157 w.set_eocie(true);
158 // Enable interrupt for overrun
159 w.set_ovrie(true);
160 // Scanning converisons of multiple channels
161 w.set_scan(true);
162 // Continuous conversion mode
163 w.set_discen(false);
164 });
165
166 r.cr2().modify(|w| {
167 // Enable DMA mode
168 w.set_dma(true);
169 // Enable continuous conversions
170 w.set_cont(true);
171 // DMA requests are issues as long as DMA=1 and data are converted.
172 w.set_dds(vals::Dds::CONTINUOUS);
173 // EOC flag is set at the end of each conversion.
174 w.set_eocs(vals::Eocs::EACH_CONVERSION);
175 });
176 }
177 }
178 }
100 179
101 let presc = Prescaler::from_pclk2(T::frequency()); 180 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
102 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
103 T::regs().cr2().modify(|reg| { 181 T::regs().cr2().modify(|reg| {
104 reg.set_adon(true); 182 reg.set_adon(true);
105 }); 183 });
106 184
107 blocking_delay_us(3); 185 // Check the sequence is long enough
186 T::regs().sqr1().modify(|r| {
187 r.set_l((sequence.len() - 1).try_into().unwrap());
188 });
108 189
109 Self { 190 for (i, ((ch, _), sample_time)) in sequence.enumerate() {
110 adc, 191 // Set the channel in the right sequence field.
111 sample_time: SampleTime::from_bits(0), 192 T::regs().sqr3().modify(|w| w.set_sq(i, ch));
193
194 let sample_time = sample_time.into();
195 if ch <= 9 {
196 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
197 } else {
198 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
199 }
112 } 200 }
113 } 201 }
202}
114 203
115 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 204impl<'d, T> Adc<'d, T>
116 self.sample_time = sample_time; 205where
206 T: Instance + super::AnyInstance,
207{
208 pub fn new(adc: Peri<'d, T>) -> Self {
209 Self::new_with_config(adc, Default::default())
117 } 210 }
118 211
119 pub fn set_resolution(&mut self, resolution: Resolution) { 212 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
120 T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); 213 rcc::enable_and_reset::<T>();
214
215 let presc = from_pclk2(T::frequency());
216 T::common_regs().ccr().modify(|w| w.set_adcpre(presc));
217 T::enable();
218
219 if let Some(resolution) = config.resolution {
220 T::regs().cr1().modify(|reg| reg.set_res(resolution.into()));
221 }
222
223 Self { adc }
121 } 224 }
122 225
123 /// Enables internal voltage reference and returns [VrefInt], which can be used in 226 /// Enables internal voltage reference and returns [VrefInt], which can be used in
@@ -152,52 +255,6 @@ where
152 255
153 Vbat {} 256 Vbat {}
154 } 257 }
155
156 /// Perform a single conversion.
157 fn convert(&mut self) -> u16 {
158 // clear end of conversion flag
159 T::regs().sr().modify(|reg| {
160 reg.set_eoc(false);
161 });
162
163 // Start conversion
164 T::regs().cr2().modify(|reg| {
165 reg.set_swstart(true);
166 });
167
168 while T::regs().sr().read().strt() == false {
169 // spin //wait for actual start
170 }
171 while T::regs().sr().read().eoc() == false {
172 // spin //wait for finish
173 }
174
175 T::regs().dr().read().0 as u16
176 }
177
178 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
179 channel.setup();
180
181 // Configure ADC
182 let channel = channel.channel();
183
184 // Select channel
185 T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
186
187 // Configure channel
188 Self::set_channel_sample_time(channel, self.sample_time);
189
190 self.convert()
191 }
192
193 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
194 let sample_time = sample_time.into();
195 if ch <= 9 {
196 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
197 } else {
198 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
199 }
200 }
201} 258}
202 259
203impl<'d, T: Instance> Drop for Adc<'d, T> { 260impl<'d, T: Instance> Drop for Adc<'d, T> {
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 16063ce4d..b270588c4 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,19 +1,19 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2#[cfg(adc_g0)] 2#[cfg(adc_g0)]
3use heapless::Vec; 3use heapless::Vec;
4use pac::adc::vals::Dmacfg;
5#[cfg(adc_g0)] 4#[cfg(adc_g0)]
6use pac::adc::vals::{Ckmode, Smpsel}; 5use pac::adc::vals::Ckmode;
6use pac::adc::vals::Dmacfg;
7#[cfg(adc_v3)] 7#[cfg(adc_v3)]
8use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs}; 8use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
9#[cfg(adc_g0)] 9#[cfg(adc_g0)]
10pub use pac::adc::vals::{Ovsr, Ovss, Presc}; 10pub use pac::adc::vals::{Ovsr, Ovss, Presc};
11 11
12use super::{ 12#[allow(unused_imports)]
13 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 13use super::SealedAdcChannel;
14}; 14use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
15use crate::dma::Transfer; 15use crate::adc::ConversionMode;
16use crate::{pac, rcc, Peri}; 16use crate::{Peri, pac, rcc};
17 17
18/// Default VREF voltage used for sample conversion to millivolts. 18/// Default VREF voltage used for sample conversion to millivolts.
19pub const VREF_DEFAULT_MV: u32 = 3300; 19pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -25,70 +25,64 @@ pub const VREF_CALIB_MV: u32 = 3000;
25// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable 25// TODO: Use [#![feature(variant_count)]](https://github.com/rust-lang/rust/issues/73662) when stable
26const SAMPLE_TIMES_CAPACITY: usize = 2; 26const SAMPLE_TIMES_CAPACITY: usize = 2;
27 27
28pub struct VrefInt; 28#[cfg(adc_g0)]
29impl<T: Instance> AdcChannel<T> for VrefInt {} 29impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
30impl<T: Instance> SealedAdcChannel<T> for VrefInt { 30 const CHANNEL: u8 = 13;
31 fn channel(&self) -> u8 { 31}
32 cfg_if! { 32#[cfg(any(adc_h5, adc_h7rs))]
33 if #[cfg(adc_g0)] { 33impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
34 let val = 13; 34 const CHANNEL: u8 = 17;
35 } else if #[cfg(any(adc_h5, adc_h7rs))] { 35}
36 let val = 17; 36#[cfg(adc_u0)]
37 } else if #[cfg(adc_u0)] { 37impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
38 let val = 12; 38 const CHANNEL: u8 = 12;
39 } else { 39}
40 let val = 0; 40#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
41 } 41impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
42 } 42 const CHANNEL: u8 = 0;
43 val
44 }
45} 43}
46 44
47pub struct Temperature; 45#[cfg(adc_g0)]
48impl<T: Instance> AdcChannel<T> for Temperature {} 46impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
49impl<T: Instance> SealedAdcChannel<T> for Temperature { 47 const CHANNEL: u8 = 12;
50 fn channel(&self) -> u8 { 48}
51 cfg_if! { 49#[cfg(any(adc_h5, adc_h7rs))]
52 if #[cfg(adc_g0)] { 50impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
53 let val = 12; 51 const CHANNEL: u8 = 16;
54 } else if #[cfg(any(adc_h5, adc_h7rs))] { 52}
55 let val = 16; 53#[cfg(adc_u0)]
56 } else if #[cfg(adc_u0)] { 54impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
57 let val = 11; 55 const CHANNEL: u8 = 11;
58 } else { 56}
59 let val = 17; 57#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
60 } 58impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
61 } 59 const CHANNEL: u8 = 17;
62 val
63 }
64} 60}
65 61
66pub struct Vbat; 62#[cfg(adc_g0)]
67impl<T: Instance> AdcChannel<T> for Vbat {} 63impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
68impl<T: Instance> SealedAdcChannel<T> for Vbat { 64 const CHANNEL: u8 = 14;
69 fn channel(&self) -> u8 { 65}
70 cfg_if! { 66#[cfg(any(adc_h5, adc_h7rs))]
71 if #[cfg(adc_g0)] { 67impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
72 let val = 14; 68 const CHANNEL: u8 = 16;
73 } else if #[cfg(any(adc_h5, adc_h7rs))] { 69}
74 let val = 2; 70#[cfg(adc_u0)]
75 } else if #[cfg(any(adc_h5, adc_h7rs))] { 71impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
76 let val = 13; 72 const CHANNEL: u8 = 13;
77 } else { 73}
78 let val = 18; 74#[cfg(not(any(adc_g0, adc_h5, adc_h7rs, adc_u0)))]
79 } 75impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
80 } 76 const CHANNEL: u8 = 18;
81 val
82 }
83} 77}
84 78
85cfg_if! { 79cfg_if! {
86 if #[cfg(any(adc_h5, adc_h7rs))] { 80 if #[cfg(any(adc_h5, adc_h7rs))] {
87 pub struct VddCore; 81 pub struct VddCore;
88 impl<T: Instance> AdcChannel<T> for VddCore {} 82 impl<T: Instance> super::AdcChannel<T> for VddCore {}
89 impl<T: Instance> super::SealedAdcChannel<T> for VddCore { 83 impl<T: Instance> super::SealedAdcChannel<T> for VddCore {
90 fn channel(&self) -> u8 { 84 fn channel(&self) -> u8 {
91 6 85 17
92 } 86 }
93 } 87 }
94 } 88 }
@@ -97,7 +91,7 @@ cfg_if! {
97cfg_if! { 91cfg_if! {
98 if #[cfg(adc_u0)] { 92 if #[cfg(adc_u0)] {
99 pub struct DacOut; 93 pub struct DacOut;
100 impl<T: Instance> AdcChannel<T> for DacOut {} 94 impl<T: Instance> super::AdcChannel<T> for DacOut {}
101 impl<T: Instance> super::SealedAdcChannel<T> for DacOut { 95 impl<T: Instance> super::SealedAdcChannel<T> for DacOut {
102 fn channel(&self) -> u8 { 96 fn channel(&self) -> u8 {
103 19 97 19
@@ -106,21 +100,6 @@ cfg_if! {
106 } 100 }
107} 101}
108 102
109/// Number of samples used for averaging.
110#[derive(Copy, Clone, Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum Averaging {
113 Disabled,
114 Samples2,
115 Samples4,
116 Samples8,
117 Samples16,
118 Samples32,
119 Samples64,
120 Samples128,
121 Samples256,
122}
123
124cfg_if! { if #[cfg(adc_g0)] { 103cfg_if! { if #[cfg(adc_g0)] {
125 104
126/// Synchronous PCLK prescaler 105/// Synchronous PCLK prescaler
@@ -141,91 +120,39 @@ pub enum Clock {
141 120
142}} 121}}
143 122
144impl<'d, T: Instance> Adc<'d, T> { 123#[cfg(adc_u0)]
145 /// Enable the voltage regulator 124type Ovss = u8;
146 fn init_regulator() { 125#[cfg(adc_u0)]
147 rcc::enable_and_reset::<T>(); 126type Ovsr = u8;
148 T::regs().cr().modify(|reg| { 127#[cfg(adc_v3)]
149 #[cfg(not(any(adc_g0, adc_u0)))] 128type Ovss = OversamplingShift;
150 reg.set_deeppwd(false); 129#[cfg(adc_v3)]
151 reg.set_advregen(true); 130type Ovsr = OversamplingRatio;
152 }); 131
153 132/// Adc configuration
154 // If this is false then each ADC_CHSELR bit enables an input channel. 133#[derive(Default)]
155 // This is the reset value, so has no effect. 134pub struct AdcConfig {
156 #[cfg(any(adc_g0, adc_u0))] 135 #[cfg(any(adc_u0, adc_g0, adc_v3))]
157 T::regs().cfgr1().modify(|reg| { 136 pub oversampling_shift: Option<Ovss>,
158 reg.set_chselrmod(false); 137 #[cfg(any(adc_u0, adc_g0, adc_v3))]
159 }); 138 pub oversampling_ratio: Option<Ovsr>,
160 139 #[cfg(any(adc_u0, adc_g0))]
161 blocking_delay_us(20); 140 pub oversampling_enable: Option<bool>,
162 } 141 #[cfg(adc_v3)]
163 142 pub oversampling_mode: Option<(Rovsm, Trovs, bool)>,
164 /// Calibrate to remove conversion offset
165 fn init_calibrate() {
166 T::regs().cr().modify(|reg| {
167 reg.set_adcal(true);
168 });
169
170 while T::regs().cr().read().adcal() {
171 // spin
172 }
173
174 blocking_delay_us(1);
175 }
176
177 /// Initialize the ADC leaving any analog clock at reset value.
178 /// For G0 and WL, this is the async clock without prescaler.
179 pub fn new(adc: Peri<'d, T>) -> Self {
180 Self::init_regulator();
181 Self::init_calibrate();
182 Self {
183 adc,
184 sample_time: SampleTime::from_bits(0),
185 }
186 }
187
188 #[cfg(adc_g0)] 143 #[cfg(adc_g0)]
189 /// Initialize ADC with explicit clock for the analog ADC 144 pub clock: Option<Clock>,
190 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self { 145 pub resolution: Option<Resolution>,
191 Self::init_regulator(); 146 pub averaging: Option<Averaging>,
192 147}
193 #[cfg(any(stm32wl5x))]
194 {
195 // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual
196 let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0;
197 match clock {
198 Clock::Async { div: _ } => {
199 assert!(async_clock_available);
200 }
201 Clock::Sync { div: _ } => {
202 if async_clock_available {
203 warn!("Not using configured ADC clock");
204 }
205 }
206 }
207 }
208 match clock {
209 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
210 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
211 reg.set_ckmode(match div {
212 CkModePclk::DIV1 => Ckmode::PCLK,
213 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
214 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
215 })
216 }),
217 }
218
219 Self::init_calibrate();
220 148
221 Self { 149impl<T: Instance> super::SealedAnyInstance for T {
222 adc, 150 fn dr() -> *mut u16 {
223 sample_time: SampleTime::from_bits(0), 151 T::regs().dr().as_ptr() as *mut u16
224 }
225 } 152 }
226 153
227 // Enable ADC only when it is not already running. 154 // Enable ADC only when it is not already running.
228 fn enable(&mut self) { 155 fn enable() {
229 // Make sure bits are off 156 // Make sure bits are off
230 while T::regs().cr().read().addis() { 157 while T::regs().cr().read().addis() {
231 // spin 158 // spin
@@ -246,186 +173,95 @@ impl<'d, T: Instance> Adc<'d, T> {
246 } 173 }
247 } 174 }
248 175
249 pub fn enable_vrefint(&self) -> VrefInt { 176 fn start() {
250 #[cfg(not(any(adc_g0, adc_u0)))] 177 T::regs().cr().modify(|reg| {
251 T::common_regs().ccr().modify(|reg| { 178 reg.set_adstart(true);
252 reg.set_vrefen(true);
253 });
254 #[cfg(any(adc_g0, adc_u0))]
255 T::regs().ccr().modify(|reg| {
256 reg.set_vrefen(true);
257 }); 179 });
258
259 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
260 // to stabilize the internal voltage reference.
261 blocking_delay_us(15);
262
263 VrefInt {}
264 } 180 }
265 181
266 pub fn enable_temperature(&self) -> Temperature { 182 fn stop() {
267 cfg_if! { 183 // Ensure conversions are finished.
268 if #[cfg(any(adc_g0, adc_u0))] { 184 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
269 T::regs().ccr().modify(|reg| { 185 T::regs().cr().modify(|reg| {
270 reg.set_tsen(true); 186 reg.set_adstp(true);
271 }); 187 });
272 } else if #[cfg(any(adc_h5, adc_h7rs))] { 188 while T::regs().cr().read().adstart() {}
273 T::common_regs().ccr().modify(|reg| {
274 reg.set_tsen(true);
275 });
276 } else {
277 T::common_regs().ccr().modify(|reg| {
278 reg.set_ch17sel(true);
279 });
280 }
281 } 189 }
282 190
283 Temperature {} 191 // Reset configuration.
192 #[cfg(not(any(adc_g0, adc_u0)))]
193 T::regs().cfgr().modify(|reg| {
194 reg.set_cont(false);
195 reg.set_dmaen(false);
196 });
197 #[cfg(any(adc_g0, adc_u0))]
198 T::regs().cfgr1().modify(|reg| {
199 reg.set_cont(false);
200 reg.set_dmaen(false);
201 });
284 } 202 }
285 203
286 pub fn enable_vbat(&self) -> Vbat { 204 /// Perform a single conversion.
287 cfg_if! { 205 fn convert() -> u16 {
288 if #[cfg(any(adc_g0, adc_u0))] { 206 // Some models are affected by an erratum:
289 T::regs().ccr().modify(|reg| { 207 // If we perform conversions slower than 1 kHz, the first read ADC value can be
290 reg.set_vbaten(true); 208 // corrupted, so we discard it and measure again.
291 }); 209 //
292 } else if #[cfg(any(adc_h5, adc_h7rs))] { 210 // STM32L471xx: Section 2.7.3
293 T::common_regs().ccr().modify(|reg| { 211 // STM32G4: Section 2.7.3
294 reg.set_vbaten(true); 212 #[cfg(any(rcc_l4, rcc_g4))]
295 }); 213 let len = 2;
296 } else {
297 T::common_regs().ccr().modify(|reg| {
298 reg.set_ch18sel(true);
299 });
300 }
301 }
302 214
303 Vbat {} 215 #[cfg(not(any(rcc_l4, rcc_g4)))]
304 } 216 let len = 1;
305 217
306 /// Set the ADC sample time. 218 for _ in 0..len {
307 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 219 T::regs().isr().modify(|reg| {
308 self.sample_time = sample_time; 220 reg.set_eos(true);
309 } 221 reg.set_eoc(true);
222 });
310 223
311 /// Get the ADC sample time. 224 // Start conversion
312 pub fn sample_time(&self) -> SampleTime { 225 T::regs().cr().modify(|reg| {
313 self.sample_time 226 reg.set_adstart(true);
314 } 227 });
315 228
316 /// Set the ADC resolution. 229 while !T::regs().isr().read().eos() {
317 pub fn set_resolution(&mut self, resolution: Resolution) { 230 // spin
318 #[cfg(not(any(adc_g0, adc_u0)))] 231 }
319 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 232 }
320 #[cfg(any(adc_g0, adc_u0))]
321 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
322 }
323 233
324 pub fn set_averaging(&mut self, averaging: Averaging) { 234 T::regs().dr().read().0 as u16
325 let (enable, samples, right_shift) = match averaging {
326 Averaging::Disabled => (false, 0, 0),
327 Averaging::Samples2 => (true, 0, 1),
328 Averaging::Samples4 => (true, 1, 2),
329 Averaging::Samples8 => (true, 2, 3),
330 Averaging::Samples16 => (true, 3, 4),
331 Averaging::Samples32 => (true, 4, 5),
332 Averaging::Samples64 => (true, 5, 6),
333 Averaging::Samples128 => (true, 6, 7),
334 Averaging::Samples256 => (true, 7, 8),
335 };
336 T::regs().cfgr2().modify(|reg| {
337 #[cfg(not(any(adc_g0, adc_u0)))]
338 reg.set_rovse(enable);
339 #[cfg(any(adc_g0, adc_u0))]
340 reg.set_ovse(enable);
341 #[cfg(any(adc_h5, adc_h7rs))]
342 reg.set_ovsr(samples.into());
343 #[cfg(not(any(adc_h5, adc_h7rs)))]
344 reg.set_ovsr(samples.into());
345 reg.set_ovss(right_shift.into());
346 })
347 }
348 /*
349 /// Convert a raw sample from the `Temperature` to deg C
350 pub fn to_degrees_centigrade(sample: u16) -> f32 {
351 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
352 * (sample as f32 - VtempCal30::get().read() as f32)
353 + 30.0
354 } 235 }
355 */
356 236
357 /// Perform a single conversion. 237 fn configure_dma(conversion_mode: ConversionMode) {
358 fn convert(&mut self) -> u16 { 238 // Set continuous mode with oneshot dma.
239 // Clear overrun flag before starting transfer.
359 T::regs().isr().modify(|reg| { 240 T::regs().isr().modify(|reg| {
360 reg.set_eos(true); 241 reg.set_ovr(true);
361 reg.set_eoc(true);
362 });
363
364 // Start conversion
365 T::regs().cr().modify(|reg| {
366 reg.set_adstart(true);
367 }); 242 });
368 243
369 while !T::regs().isr().read().eos() { 244 #[cfg(not(any(adc_g0, adc_u0)))]
370 // spin 245 let regs = T::regs().cfgr();
371 }
372 246
373 T::regs().dr().read().0 as u16 247 #[cfg(any(adc_g0, adc_u0))]
374 } 248 let regs = T::regs().cfgr1();
375 249
376 /// Read an ADC channel. 250 regs.modify(|reg| {
377 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 251 reg.set_discen(false);
378 self.read_channel(channel) 252 reg.set_cont(true);
253 reg.set_dmacfg(match conversion_mode {
254 ConversionMode::Singular => Dmacfg::ONE_SHOT,
255 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
256 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
257 });
258 reg.set_dmaen(true);
259 });
379 } 260 }
380 261
381 /// Read one or multiple ADC channels using DMA. 262 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
382 /// 263 #[cfg(adc_h5)]
383 /// `readings` must have a length that is a multiple of the length of the 264 T::regs().cr().modify(|w| w.set_aden(false));
384 /// `sequence` iterator.
385 ///
386 /// Note: The order of values in `readings` is defined by the pin ADC
387 /// channel number and not the pin order in `sequence`.
388 ///
389 /// Example
390 /// ```rust,ignore
391 /// use embassy_stm32::adc::{Adc, AdcChannel}
392 ///
393 /// let mut adc = Adc::new(p.ADC1);
394 /// let mut adc_pin0 = p.PA0.degrade_adc();
395 /// let mut adc_pin1 = p.PA1.degrade_adc();
396 /// let mut measurements = [0u16; 2];
397 ///
398 /// adc.read(
399 /// p.DMA1_CH2.reborrow(),
400 /// [
401 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
402 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
403 /// ]
404 /// .into_iter(),
405 /// &mut measurements,
406 /// )
407 /// .await;
408 /// defmt::info!("measurements: {}", measurements);
409 /// ```
410 pub async fn read(
411 &mut self,
412 rx_dma: Peri<'_, impl RxDma<T>>,
413 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
414 readings: &mut [u16],
415 ) {
416 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
417 assert!(
418 readings.len() % sequence.len() == 0,
419 "Readings length must be a multiple of sequence length"
420 );
421 assert!(
422 sequence.len() <= 16,
423 "Asynchronous read sequence cannot be more than 16 in length"
424 );
425
426 // Ensure no conversions are ongoing and ADC is enabled.
427 Self::cancel_conversions();
428 self.enable();
429 265
430 // Set sequence length 266 // Set sequence length
431 #[cfg(not(any(adc_g0, adc_u0)))] 267 #[cfg(not(any(adc_g0, adc_u0)))]
@@ -439,10 +275,10 @@ impl<'d, T: Instance> Adc<'d, T> {
439 275
440 T::regs().chselr().write(|chselr| { 276 T::regs().chselr().write(|chselr| {
441 T::regs().smpr().write(|smpr| { 277 T::regs().smpr().write(|smpr| {
442 for (channel, sample_time) in sequence { 278 for ((channel, _), sample_time) in sequence {
443 chselr.set_chsel(channel.channel.into(), true); 279 chselr.set_chsel(channel.into(), true);
444 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) { 280 if let Some(i) = sample_times.iter().position(|&t| t == sample_time) {
445 smpr.set_smpsel(channel.channel.into(), (i as u8).into()); 281 smpr.set_smpsel(channel.into(), (i as u8).into());
446 } else { 282 } else {
447 smpr.set_sample_time(sample_times.len(), sample_time); 283 smpr.set_sample_time(sample_times.len(), sample_time);
448 if let Err(_) = sample_times.push(sample_time) { 284 if let Err(_) = sample_times.push(sample_time) {
@@ -461,42 +297,86 @@ impl<'d, T: Instance> Adc<'d, T> {
461 #[cfg(adc_u0)] 297 #[cfg(adc_u0)]
462 let mut channel_mask = 0; 298 let mut channel_mask = 0;
463 299
300 #[cfg(adc_h5)]
301 let mut difsel = 0u32;
302
464 // Configure channels and ranks 303 // Configure channels and ranks
465 for (_i, (channel, sample_time)) in sequence.enumerate() { 304 for (_i, ((channel, _is_differential), sample_time)) in sequence.enumerate() {
466 Self::configure_channel(channel, sample_time); 305 // RM0492, RM0481, etc.
306 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
307 #[cfg(any(adc_h5, adc_h7rs))]
308 if channel == 0 {
309 T::regs().or().modify(|reg| reg.set_op0(true));
310 }
311
312 // Configure channel
313 cfg_if! {
314 if #[cfg(adc_u0)] {
315 // On G0 and U6 all channels use the same sampling time.
316 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into()));
317 } else if #[cfg(any(adc_h5, adc_h7rs))] {
318 match channel {
319 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
320 _ => T::regs().smpr2().modify(|w| w.set_smp(channel as usize % 10, sample_time.into())),
321 }
322 } else {
323 let sample_time = sample_time.into();
324 T::regs()
325 .smpr(channel as usize / 10)
326 .modify(|reg| reg.set_smp(channel as usize % 10, sample_time));
327 }
328 }
329
330 #[cfg(stm32h7)]
331 {
332 use crate::pac::adc::vals::Pcsel;
333
334 T::regs().cfgr2().modify(|w| w.set_lshift(0));
335 T::regs()
336 .pcsel()
337 .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED));
338 }
467 339
468 // Each channel is sampled according to sequence 340 // Each channel is sampled according to sequence
469 #[cfg(not(any(adc_g0, adc_u0)))] 341 #[cfg(not(any(adc_g0, adc_u0)))]
470 match _i { 342 match _i {
471 0..=3 => { 343 0..=3 => {
472 T::regs().sqr1().modify(|w| { 344 T::regs().sqr1().modify(|w| {
473 w.set_sq(_i, channel.channel()); 345 w.set_sq(_i, channel);
474 }); 346 });
475 } 347 }
476 4..=8 => { 348 4..=8 => {
477 T::regs().sqr2().modify(|w| { 349 T::regs().sqr2().modify(|w| {
478 w.set_sq(_i - 4, channel.channel()); 350 w.set_sq(_i - 4, channel);
479 }); 351 });
480 } 352 }
481 9..=13 => { 353 9..=13 => {
482 T::regs().sqr3().modify(|w| { 354 T::regs().sqr3().modify(|w| {
483 w.set_sq(_i - 9, channel.channel()); 355 w.set_sq(_i - 9, channel);
484 }); 356 });
485 } 357 }
486 14..=15 => { 358 14..=15 => {
487 T::regs().sqr4().modify(|w| { 359 T::regs().sqr4().modify(|w| {
488 w.set_sq(_i - 14, channel.channel()); 360 w.set_sq(_i - 14, channel);
489 }); 361 });
490 } 362 }
491 _ => unreachable!(), 363 _ => unreachable!(),
492 } 364 }
493 365
366 #[cfg(adc_h5)]
367 {
368 difsel |= (_is_differential as u32) << channel;
369 }
370
494 #[cfg(adc_u0)] 371 #[cfg(adc_u0)]
495 { 372 {
496 channel_mask |= 1 << channel.channel(); 373 channel_mask |= 1 << channel;
497 } 374 }
498 } 375 }
499 376
377 #[cfg(adc_h5)]
378 T::regs().difsel().write(|w| w.set_difsel(difsel));
379
500 // On G0 and U0 enabled channels are sampled from 0 to last channel. 380 // On G0 and U0 enabled channels are sampled from 0 to last channel.
501 // It is possible to add up to 8 sequences if CHSELRMOD = 1. 381 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
502 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. 382 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
@@ -505,181 +385,234 @@ impl<'d, T: Instance> Adc<'d, T> {
505 reg.set_chsel(channel_mask); 385 reg.set_chsel(channel_mask);
506 }); 386 });
507 } 387 }
508 // Set continuous mode with oneshot dma. 388 }
509 // Clear overrun flag before starting transfer. 389}
510 T::regs().isr().modify(|reg| {
511 reg.set_ovr(true);
512 });
513 390
514 #[cfg(not(any(adc_g0, adc_u0)))] 391impl<'d, T: Instance> Adc<'d, T> {
515 T::regs().cfgr().modify(|reg| { 392 /// Enable the voltage regulator
516 reg.set_discen(false); 393 fn init_regulator() {
517 reg.set_cont(true); 394 rcc::enable_and_reset::<T>();
518 reg.set_dmacfg(Dmacfg::ONE_SHOT); 395 T::regs().cr().modify(|reg| {
519 reg.set_dmaen(true); 396 #[cfg(not(any(adc_g0, adc_u0)))]
397 reg.set_deeppwd(false);
398 reg.set_advregen(true);
520 }); 399 });
400
401 // If this is false then each ADC_CHSELR bit enables an input channel.
402 // This is the reset value, so has no effect.
521 #[cfg(any(adc_g0, adc_u0))] 403 #[cfg(any(adc_g0, adc_u0))]
522 T::regs().cfgr1().modify(|reg| { 404 T::regs().cfgr1().modify(|reg| {
523 reg.set_discen(false); 405 reg.set_chselrmod(false);
524 reg.set_cont(true);
525 reg.set_dmacfg(Dmacfg::ONE_SHOT);
526 reg.set_dmaen(true);
527 }); 406 });
528 407
529 let request = rx_dma.request(); 408 blocking_delay_us(20);
530 let transfer = unsafe { 409 }
531 Transfer::new_read(
532 rx_dma,
533 request,
534 T::regs().dr().as_ptr() as *mut u16,
535 readings,
536 Default::default(),
537 )
538 };
539 410
540 // Start conversion 411 /// Calibrate to remove conversion offset
412 fn init_calibrate() {
541 T::regs().cr().modify(|reg| { 413 T::regs().cr().modify(|reg| {
542 reg.set_adstart(true); 414 reg.set_adcal(true);
543 }); 415 });
544 416
545 // Wait for conversion sequence to finish. 417 while T::regs().cr().read().adcal() {
546 transfer.await; 418 // spin
547 419 }
548 // Ensure conversions are finished.
549 Self::cancel_conversions();
550 420
551 // Reset configuration. 421 blocking_delay_us(1);
552 #[cfg(not(any(adc_g0, adc_u0)))]
553 T::regs().cfgr().modify(|reg| {
554 reg.set_cont(false);
555 });
556 #[cfg(any(adc_g0, adc_u0))]
557 T::regs().cfgr1().modify(|reg| {
558 reg.set_cont(false);
559 });
560 } 422 }
561 423
562 #[cfg(not(adc_g0))] 424 /// Initialize the ADC leaving any analog clock at reset value.
563 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 425 /// For G0 and WL, this is the async clock without prescaler.
564 // RM0492, RM0481, etc. 426 pub fn new(adc: Peri<'d, T>) -> Self {
565 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 427 Self::init_regulator();
566 #[cfg(any(adc_h5, adc_h7rs))] 428 Self::init_calibrate();
567 if channel.channel() == 0 { 429 Self { adc }
568 T::regs().or().modify(|reg| reg.set_op0(true));
569 }
570
571 // Configure channel
572 Self::set_channel_sample_time(channel.channel(), sample_time);
573 } 430 }
574 431
575 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 432 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
576 self.enable();
577 #[cfg(not(adc_g0))] 433 #[cfg(not(adc_g0))]
578 Self::configure_channel(channel, self.sample_time); 434 let s = Self::new(adc);
435
579 #[cfg(adc_g0)] 436 #[cfg(adc_g0)]
580 T::regs().smpr().write(|reg| { 437 let s = match config.clock {
581 reg.set_sample_time(0, self.sample_time); 438 Some(clock) => Self::new_with_clock(adc, clock),
582 reg.set_smpsel(channel.channel().into(), Smpsel::SMP1); 439 None => Self::new(adc),
583 }); 440 };
584 // Select channel 441
585 #[cfg(not(any(adc_g0, adc_u0)))] 442 #[cfg(any(adc_g0, adc_u0, adc_v3))]
586 T::regs().sqr1().write(|reg| reg.set_sq(0, channel.channel())); 443 if let Some(shift) = config.oversampling_shift {
444 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
445 }
446
447 #[cfg(any(adc_g0, adc_u0, adc_v3))]
448 if let Some(ratio) = config.oversampling_ratio {
449 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
450 }
451
587 #[cfg(any(adc_g0, adc_u0))] 452 #[cfg(any(adc_g0, adc_u0))]
588 T::regs().chselr().write(|reg| { 453 if let Some(enable) = config.oversampling_enable {
589 #[cfg(adc_g0)] 454 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
590 reg.set_chsel(channel.channel().into(), true); 455 }
591 #[cfg(adc_u0)]
592 reg.set_chsel(1 << channel.channel());
593 });
594 456
595 // Some models are affected by an erratum: 457 #[cfg(adc_v3)]
596 // If we perform conversions slower than 1 kHz, the first read ADC value can be 458 if let Some((mode, trig_mode, enable)) = config.oversampling_mode {
597 // corrupted, so we discard it and measure again. 459 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
598 // 460 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
599 // STM32L471xx: Section 2.7.3 461 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
600 // STM32G4: Section 2.7.3 462 }
601 #[cfg(any(rcc_l4, rcc_g4))]
602 let _ = self.convert();
603 let val = self.convert();
604 463
605 T::regs().cr().modify(|reg| reg.set_addis(true)); 464 if let Some(resolution) = config.resolution {
465 #[cfg(not(any(adc_g0, adc_u0)))]
466 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
467 #[cfg(any(adc_g0, adc_u0))]
468 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
469 }
606 470
607 // RM0492, RM0481, etc. 471 if let Some(averaging) = config.averaging {
608 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 472 let (enable, samples, right_shift) = match averaging {
609 #[cfg(any(adc_h5, adc_h7rs))] 473 Averaging::Disabled => (false, 0, 0),
610 if channel.channel() == 0 { 474 Averaging::Samples2 => (true, 0, 1),
611 T::regs().or().modify(|reg| reg.set_op0(false)); 475 Averaging::Samples4 => (true, 1, 2),
476 Averaging::Samples8 => (true, 2, 3),
477 Averaging::Samples16 => (true, 3, 4),
478 Averaging::Samples32 => (true, 4, 5),
479 Averaging::Samples64 => (true, 5, 6),
480 Averaging::Samples128 => (true, 6, 7),
481 Averaging::Samples256 => (true, 7, 8),
482 };
483 T::regs().cfgr2().modify(|reg| {
484 #[cfg(not(any(adc_g0, adc_u0)))]
485 reg.set_rovse(enable);
486 #[cfg(any(adc_g0, adc_u0))]
487 reg.set_ovse(enable);
488 #[cfg(any(adc_h5, adc_h7rs))]
489 reg.set_ovsr(samples.into());
490 #[cfg(not(any(adc_h5, adc_h7rs)))]
491 reg.set_ovsr(samples.into());
492 reg.set_ovss(right_shift.into());
493 })
612 } 494 }
613 495
614 val 496 s
615 } 497 }
616 498
617 #[cfg(adc_g0)] 499 #[cfg(adc_g0)]
618 pub fn set_oversampling_shift(&mut self, shift: Ovss) { 500 /// Initialize ADC with explicit clock for the analog ADC
619 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); 501 pub fn new_with_clock(adc: Peri<'d, T>, clock: Clock) -> Self {
620 } 502 Self::init_regulator();
621 #[cfg(adc_u0)]
622 pub fn set_oversampling_shift(&mut self, shift: u8) {
623 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
624 }
625 503
626 #[cfg(adc_g0)] 504 #[cfg(any(stm32wl5x))]
627 pub fn set_oversampling_ratio(&mut self, ratio: Ovsr) { 505 {
628 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 506 // Reset value 0 is actually _No clock selected_ in the STM32WL5x reference manual
629 } 507 let async_clock_available = pac::RCC.ccipr().read().adcsel() != pac::rcc::vals::Adcsel::_RESERVED_0;
630 #[cfg(adc_u0)] 508 match clock {
631 pub fn set_oversampling_ratio(&mut self, ratio: u8) { 509 Clock::Async { div: _ } => {
632 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 510 assert!(async_clock_available);
633 } 511 }
512 Clock::Sync { div: _ } => {
513 if async_clock_available {
514 warn!("Not using configured ADC clock");
515 }
516 }
517 }
518 }
519 match clock {
520 Clock::Async { div } => T::regs().ccr().modify(|reg| reg.set_presc(div)),
521 Clock::Sync { div } => T::regs().cfgr2().modify(|reg| {
522 reg.set_ckmode(match div {
523 CkModePclk::DIV1 => Ckmode::PCLK,
524 CkModePclk::DIV2 => Ckmode::PCLK_DIV2,
525 CkModePclk::DIV4 => Ckmode::PCLK_DIV4,
526 })
527 }),
528 }
634 529
635 #[cfg(any(adc_g0, adc_u0))] 530 Self::init_calibrate();
636 pub fn oversampling_enable(&mut self, enable: bool) {
637 T::regs().cfgr2().modify(|reg| reg.set_ovse(enable));
638 }
639 531
640 #[cfg(adc_v3)] 532 Self { adc }
641 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
642 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
643 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
644 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
645 } 533 }
646 534
647 #[cfg(adc_v3)] 535 pub fn enable_vrefint(&self) -> VrefInt {
648 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) { 536 #[cfg(not(any(adc_g0, adc_u0)))]
649 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); 537 T::common_regs().ccr().modify(|reg| {
538 reg.set_vrefen(true);
539 });
540 #[cfg(any(adc_g0, adc_u0))]
541 T::regs().ccr().modify(|reg| {
542 reg.set_vrefen(true);
543 });
544
545 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
546 // to stabilize the internal voltage reference.
547 blocking_delay_us(15);
548
549 VrefInt {}
650 } 550 }
651 551
652 #[cfg(adc_v3)] 552 pub fn enable_temperature(&self) -> Temperature {
653 pub fn set_oversampling_shift(&mut self, shift: OversamplingShift) { 553 cfg_if! {
654 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); 554 if #[cfg(any(adc_g0, adc_u0))] {
555 T::regs().ccr().modify(|reg| {
556 reg.set_tsen(true);
557 });
558 } else if #[cfg(any(adc_h5, adc_h7rs))] {
559 T::common_regs().ccr().modify(|reg| {
560 reg.set_tsen(true);
561 });
562 } else {
563 T::common_regs().ccr().modify(|reg| {
564 reg.set_ch17sel(true);
565 });
566 }
567 }
568
569 Temperature {}
655 } 570 }
656 571
657 #[cfg(not(adc_g0))] 572 pub fn enable_vbat(&self) -> Vbat {
658 fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) {
659 cfg_if! { 573 cfg_if! {
660 if #[cfg(adc_u0)] { 574 if #[cfg(any(adc_g0, adc_u0))] {
661 // On G0 and U6 all channels use the same sampling time. 575 T::regs().ccr().modify(|reg| {
662 T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); 576 reg.set_vbaten(true);
577 });
663 } else if #[cfg(any(adc_h5, adc_h7rs))] { 578 } else if #[cfg(any(adc_h5, adc_h7rs))] {
664 match _ch { 579 T::common_regs().ccr().modify(|reg| {
665 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 580 reg.set_vbaten(true);
666 _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), 581 });
667 }
668 } else { 582 } else {
669 let sample_time = sample_time.into(); 583 T::common_regs().ccr().modify(|reg| {
670 T::regs() 584 reg.set_ch18sel(true);
671 .smpr(_ch as usize / 10) 585 });
672 .modify(|reg| reg.set_smp(_ch as usize % 10, sample_time));
673 } 586 }
674 } 587 }
588
589 Vbat {}
675 } 590 }
676 591
677 fn cancel_conversions() { 592 pub fn disable_vbat(&self) {
678 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 593 cfg_if! {
679 T::regs().cr().modify(|reg| { 594 if #[cfg(any(adc_g0, adc_u0))] {
680 reg.set_adstp(true); 595 T::regs().ccr().modify(|reg| {
681 }); 596 reg.set_vbaten(false);
682 while T::regs().cr().read().adstart() {} 597 });
598 } else if #[cfg(any(adc_h5, adc_h7rs))] {
599 T::common_regs().ccr().modify(|reg| {
600 reg.set_vbaten(false);
601 });
602 } else {
603 T::common_regs().ccr().modify(|reg| {
604 reg.set_ch18sel(false);
605 });
606 }
683 } 607 }
684 } 608 }
609
610 /*
611 /// Convert a raw sample from the `Temperature` to deg C
612 pub fn to_degrees_centigrade(sample: u16) -> f32 {
613 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
614 * (sample as f32 - VtempCal30::get().read() as f32)
615 + 30.0
616 }
617 */
685} 618}
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index b66437e6e..a3d9e6176 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,12 +4,10 @@ use pac::adc::vals::{Adcaldif, Boost};
4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; 4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{ 7use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
8 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 8use crate::adc::ConversionMode;
9};
10use crate::dma::Transfer;
11use crate::time::Hertz; 9use crate::time::Hertz;
12use crate::{pac, rcc, Peri}; 10use crate::{Peri, pac, rcc};
13 11
14/// Default VREF voltage used for sample conversion to millivolts. 12/// Default VREF voltage used for sample conversion to millivolts.
15pub const VREF_DEFAULT_MV: u32 = 3300; 13pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -25,153 +23,234 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
25const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 23const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
26 24
27#[cfg(stm32g4)] 25#[cfg(stm32g4)]
28const VREF_CHANNEL: u8 = 18; 26impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
27 const CHANNEL: u8 = 18;
28}
29#[cfg(stm32g4)] 29#[cfg(stm32g4)]
30const TEMP_CHANNEL: u8 = 16; 30impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
31 const CHANNEL: u8 = 16;
32}
31 33
32#[cfg(stm32h7)] 34#[cfg(stm32h7)]
33const VREF_CHANNEL: u8 = 19; 35impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
36 const CHANNEL: u8 = 19;
37}
34#[cfg(stm32h7)] 38#[cfg(stm32h7)]
35const TEMP_CHANNEL: u8 = 18; 39impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
40 const CHANNEL: u8 = 18;
41}
36 42
37// TODO this should be 14 for H7a/b/35 43// TODO this should be 14 for H7a/b/35
38#[cfg(not(stm32u5))] 44#[cfg(not(stm32u5))]
39const VBAT_CHANNEL: u8 = 17; 45impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
46 const CHANNEL: u8 = 17;
47}
40 48
41#[cfg(stm32u5)] 49#[cfg(stm32u5)]
42const VREF_CHANNEL: u8 = 0; 50impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
51 const CHANNEL: u8 = 0;
52}
43#[cfg(stm32u5)] 53#[cfg(stm32u5)]
44const TEMP_CHANNEL: u8 = 19; 54impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
55 const CHANNEL: u8 = 19;
56}
45#[cfg(stm32u5)] 57#[cfg(stm32u5)]
46const VBAT_CHANNEL: u8 = 18; 58impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
47 59 const CHANNEL: u8 = 18;
48// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
49/// Internal voltage reference channel.
50pub struct VrefInt;
51impl<T: Instance> AdcChannel<T> for VrefInt {}
52impl<T: Instance> SealedAdcChannel<T> for VrefInt {
53 fn channel(&self) -> u8 {
54 VREF_CHANNEL
55 }
56} 60}
57 61
58/// Internal temperature channel. 62fn from_ker_ck(frequency: Hertz) -> Presc {
59pub struct Temperature; 63 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
60impl<T: Instance> AdcChannel<T> for Temperature {} 64 match raw_prescaler {
61impl<T: Instance> SealedAdcChannel<T> for Temperature { 65 0 => Presc::DIV1,
62 fn channel(&self) -> u8 { 66 1 => Presc::DIV2,
63 TEMP_CHANNEL 67 2..=3 => Presc::DIV4,
68 4..=5 => Presc::DIV6,
69 6..=7 => Presc::DIV8,
70 8..=9 => Presc::DIV10,
71 10..=11 => Presc::DIV12,
72 _ => unimplemented!(),
64 } 73 }
65} 74}
66 75
67/// Internal battery voltage channel. 76/// Adc configuration
68pub struct Vbat; 77#[derive(Default)]
69impl<T: Instance> AdcChannel<T> for Vbat {} 78pub struct AdcConfig {
70impl<T: Instance> SealedAdcChannel<T> for Vbat { 79 pub resolution: Option<Resolution>,
71 fn channel(&self) -> u8 { 80 pub averaging: Option<Averaging>,
72 VBAT_CHANNEL
73 }
74} 81}
75 82
76// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 83impl<T: Instance> super::SealedAnyInstance for T {
77// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 84 fn dr() -> *mut u16 {
78#[allow(unused)] 85 T::regs().dr().as_ptr() as *mut u16
79enum Prescaler { 86 }
80 NotDivided, 87
81 DividedBy2, 88 fn enable() {
82 DividedBy4, 89 T::regs().isr().write(|w| w.set_adrdy(true));
83 DividedBy6, 90 T::regs().cr().modify(|w| w.set_aden(true));
84 DividedBy8, 91 while !T::regs().isr().read().adrdy() {}
85 DividedBy10, 92 T::regs().isr().write(|w| w.set_adrdy(true));
86 DividedBy12, 93 }
87 DividedBy16,
88 DividedBy32,
89 DividedBy64,
90 DividedBy128,
91 DividedBy256,
92}
93 94
94impl Prescaler { 95 fn start() {
95 fn from_ker_ck(frequency: Hertz) -> Self { 96 // Start conversion
96 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 97 T::regs().cr().modify(|reg| {
97 match raw_prescaler { 98 reg.set_adstart(true);
98 0 => Self::NotDivided, 99 });
99 1 => Self::DividedBy2, 100 }
100 2..=3 => Self::DividedBy4, 101
101 4..=5 => Self::DividedBy6, 102 fn stop() {
102 6..=7 => Self::DividedBy8, 103 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
103 8..=9 => Self::DividedBy10, 104 T::regs().cr().modify(|reg| {
104 10..=11 => Self::DividedBy12, 105 reg.set_adstp(Adstp::STOP);
105 _ => unimplemented!(), 106 });
107 while T::regs().cr().read().adstart() {}
106 } 108 }
109
110 // Reset configuration.
111 T::regs().cfgr().modify(|reg| {
112 reg.set_cont(false);
113 reg.set_dmngt(Dmngt::from_bits(0));
114 });
107 } 115 }
108 116
109 fn divisor(&self) -> u32 { 117 fn convert() -> u16 {
110 match self { 118 T::regs().isr().modify(|reg| {
111 Prescaler::NotDivided => 1, 119 reg.set_eos(true);
112 Prescaler::DividedBy2 => 2, 120 reg.set_eoc(true);
113 Prescaler::DividedBy4 => 4, 121 });
114 Prescaler::DividedBy6 => 6, 122
115 Prescaler::DividedBy8 => 8, 123 // Start conversion
116 Prescaler::DividedBy10 => 10, 124 T::regs().cr().modify(|reg| {
117 Prescaler::DividedBy12 => 12, 125 reg.set_adstart(true);
118 Prescaler::DividedBy16 => 16, 126 });
119 Prescaler::DividedBy32 => 32, 127
120 Prescaler::DividedBy64 => 64, 128 while !T::regs().isr().read().eos() {
121 Prescaler::DividedBy128 => 128, 129 // spin
122 Prescaler::DividedBy256 => 256,
123 } 130 }
131
132 T::regs().dr().read().0 as u16
124 } 133 }
125 134
126 fn presc(&self) -> Presc { 135 fn configure_dma(conversion_mode: ConversionMode) {
127 match self { 136 match conversion_mode {
128 Prescaler::NotDivided => Presc::DIV1, 137 ConversionMode::Singular => {
129 Prescaler::DividedBy2 => Presc::DIV2, 138 T::regs().isr().modify(|reg| {
130 Prescaler::DividedBy4 => Presc::DIV4, 139 reg.set_ovr(true);
131 Prescaler::DividedBy6 => Presc::DIV6, 140 });
132 Prescaler::DividedBy8 => Presc::DIV8, 141 T::regs().cfgr().modify(|reg| {
133 Prescaler::DividedBy10 => Presc::DIV10, 142 reg.set_cont(true);
134 Prescaler::DividedBy12 => Presc::DIV12, 143 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
135 Prescaler::DividedBy16 => Presc::DIV16, 144 });
136 Prescaler::DividedBy32 => Presc::DIV32, 145 }
137 Prescaler::DividedBy64 => Presc::DIV64, 146 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
138 Prescaler::DividedBy128 => Presc::DIV128, 147 _ => unreachable!(),
139 Prescaler::DividedBy256 => Presc::DIV256,
140 } 148 }
141 } 149 }
142}
143 150
144/// Number of samples used for averaging. 151 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
145#[derive(Copy, Clone, Debug)] 152 // Set sequence length
146#[cfg_attr(feature = "defmt", derive(defmt::Format))] 153 T::regs().sqr1().modify(|w| {
147pub enum Averaging { 154 w.set_l(sequence.len() as u8 - 1);
148 Disabled, 155 });
149 Samples2, 156
150 Samples4, 157 // Configure channels and ranks
151 Samples8, 158 for (i, ((channel, _), sample_time)) in sequence.enumerate() {
152 Samples16, 159 let sample_time = sample_time.into();
153 Samples32, 160 if channel <= 9 {
154 Samples64, 161 T::regs().smpr(0).modify(|reg| reg.set_smp(channel as _, sample_time));
155 Samples128, 162 } else {
156 Samples256, 163 T::regs()
157 Samples512, 164 .smpr(1)
158 Samples1024, 165 .modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
166 }
167
168 #[cfg(any(stm32h7, stm32u5))]
169 {
170 T::regs().cfgr2().modify(|w| w.set_lshift(0));
171 T::regs()
172 .pcsel()
173 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
174 }
175
176 match i {
177 0..=3 => {
178 T::regs().sqr1().modify(|w| {
179 w.set_sq(i, channel);
180 });
181 }
182 4..=8 => {
183 T::regs().sqr2().modify(|w| {
184 w.set_sq(i - 4, channel);
185 });
186 }
187 9..=13 => {
188 T::regs().sqr3().modify(|w| {
189 w.set_sq(i - 9, channel);
190 });
191 }
192 14..=15 => {
193 T::regs().sqr4().modify(|w| {
194 w.set_sq(i - 14, channel);
195 });
196 }
197 _ => unreachable!(),
198 }
199 }
200 }
159} 201}
160 202
161impl<'d, T: Instance> Adc<'d, T> { 203impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> {
204 pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self {
205 let s = Self::new(adc);
206
207 // Set the ADC resolution.
208 if let Some(resolution) = config.resolution {
209 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
210 }
211
212 // Set hardware averaging.
213 if let Some(averaging) = config.averaging {
214 let (enable, samples, right_shift) = match averaging {
215 Averaging::Disabled => (false, 0, 0),
216 Averaging::Samples2 => (true, 1, 1),
217 Averaging::Samples4 => (true, 3, 2),
218 Averaging::Samples8 => (true, 7, 3),
219 Averaging::Samples16 => (true, 15, 4),
220 Averaging::Samples32 => (true, 31, 5),
221 Averaging::Samples64 => (true, 63, 6),
222 Averaging::Samples128 => (true, 127, 7),
223 Averaging::Samples256 => (true, 255, 8),
224 Averaging::Samples512 => (true, 511, 9),
225 Averaging::Samples1024 => (true, 1023, 10),
226 };
227
228 T::regs().cfgr2().modify(|reg| {
229 reg.set_rovse(enable);
230 reg.set_ovsr(samples);
231 reg.set_ovss(right_shift);
232 })
233 }
234
235 s
236 }
237
162 /// Create a new ADC driver. 238 /// Create a new ADC driver.
163 pub fn new(adc: Peri<'d, T>) -> Self { 239 pub fn new(adc: Peri<'d, T>) -> Self {
164 rcc::enable_and_reset::<T>(); 240 rcc::enable_and_reset::<T>();
165 241
166 let prescaler = Prescaler::from_ker_ck(T::frequency()); 242 let prescaler = from_ker_ck(T::frequency());
167 243
168 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 244 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
169 245
170 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 246 let frequency = T::frequency() / prescaler;
171 info!("ADC frequency set to {}", frequency); 247 info!("ADC frequency set to {}", frequency);
172 248
173 if frequency > MAX_ADC_CLK_FREQ { 249 if frequency > MAX_ADC_CLK_FREQ {
174 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 250 panic!(
251 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
252 MAX_ADC_CLK_FREQ.0 / 1_000_000
253 );
175 } 254 }
176 255
177 #[cfg(stm32h7)] 256 #[cfg(stm32h7)]
@@ -187,40 +266,20 @@ impl<'d, T: Instance> Adc<'d, T> {
187 }; 266 };
188 T::regs().cr().modify(|w| w.set_boost(boost)); 267 T::regs().cr().modify(|w| w.set_boost(boost));
189 } 268 }
190 let mut s = Self {
191 adc,
192 sample_time: SampleTime::from_bits(0),
193 };
194 s.power_up();
195 s.configure_differential_inputs();
196
197 s.calibrate();
198 blocking_delay_us(1);
199
200 s.enable();
201 s.configure();
202
203 s
204 }
205 269
206 fn power_up(&mut self) {
207 T::regs().cr().modify(|reg| { 270 T::regs().cr().modify(|reg| {
208 reg.set_deeppwd(false); 271 reg.set_deeppwd(false);
209 reg.set_advregen(true); 272 reg.set_advregen(true);
210 }); 273 });
211 274
212 blocking_delay_us(10); 275 blocking_delay_us(10);
213 }
214 276
215 fn configure_differential_inputs(&mut self) {
216 T::regs().difsel().modify(|w| { 277 T::regs().difsel().modify(|w| {
217 for n in 0..20 { 278 for n in 0..20 {
218 w.set_difsel(n, Difsel::SINGLE_ENDED); 279 w.set_difsel(n, Difsel::SINGLE_ENDED);
219 } 280 }
220 }); 281 });
221 }
222 282
223 fn calibrate(&mut self) {
224 T::regs().cr().modify(|w| { 283 T::regs().cr().modify(|w| {
225 #[cfg(not(adc_u5))] 284 #[cfg(not(adc_u5))]
226 w.set_adcaldif(Adcaldif::SINGLE_ENDED); 285 w.set_adcaldif(Adcaldif::SINGLE_ENDED);
@@ -230,21 +289,18 @@ impl<'d, T: Instance> Adc<'d, T> {
230 T::regs().cr().modify(|w| w.set_adcal(true)); 289 T::regs().cr().modify(|w| w.set_adcal(true));
231 290
232 while T::regs().cr().read().adcal() {} 291 while T::regs().cr().read().adcal() {}
233 }
234 292
235 fn enable(&mut self) { 293 blocking_delay_us(1);
236 T::regs().isr().write(|w| w.set_adrdy(true)); 294
237 T::regs().cr().modify(|w| w.set_aden(true)); 295 T::enable();
238 while !T::regs().isr().read().adrdy() {}
239 T::regs().isr().write(|w| w.set_adrdy(true));
240 }
241 296
242 fn configure(&mut self) {
243 // single conversion mode, software trigger 297 // single conversion mode, software trigger
244 T::regs().cfgr().modify(|w| { 298 T::regs().cfgr().modify(|w| {
245 w.set_cont(false); 299 w.set_cont(false);
246 w.set_exten(Exten::DISABLED); 300 w.set_exten(Exten::DISABLED);
247 }); 301 });
302
303 Self { adc }
248 } 304 }
249 305
250 /// Enable reading the voltage reference internal channel. 306 /// Enable reading the voltage reference internal channel.
@@ -273,228 +329,4 @@ impl<'d, T: Instance> Adc<'d, T> {
273 329
274 Vbat {} 330 Vbat {}
275 } 331 }
276
277 /// Set the ADC sample time.
278 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
279 self.sample_time = sample_time;
280 }
281
282 /// Get the ADC sample time.
283 pub fn sample_time(&self) -> SampleTime {
284 self.sample_time
285 }
286
287 /// Set the ADC resolution.
288 pub fn set_resolution(&mut self, resolution: Resolution) {
289 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
290 }
291
292 /// Set hardware averaging.
293 pub fn set_averaging(&mut self, averaging: Averaging) {
294 let (enable, samples, right_shift) = match averaging {
295 Averaging::Disabled => (false, 0, 0),
296 Averaging::Samples2 => (true, 1, 1),
297 Averaging::Samples4 => (true, 3, 2),
298 Averaging::Samples8 => (true, 7, 3),
299 Averaging::Samples16 => (true, 15, 4),
300 Averaging::Samples32 => (true, 31, 5),
301 Averaging::Samples64 => (true, 63, 6),
302 Averaging::Samples128 => (true, 127, 7),
303 Averaging::Samples256 => (true, 255, 8),
304 Averaging::Samples512 => (true, 511, 9),
305 Averaging::Samples1024 => (true, 1023, 10),
306 };
307
308 T::regs().cfgr2().modify(|reg| {
309 reg.set_rovse(enable);
310 reg.set_ovsr(samples);
311 reg.set_ovss(right_shift);
312 })
313 }
314
315 /// Perform a single conversion.
316 fn convert(&mut self) -> u16 {
317 T::regs().isr().modify(|reg| {
318 reg.set_eos(true);
319 reg.set_eoc(true);
320 });
321
322 // Start conversion
323 T::regs().cr().modify(|reg| {
324 reg.set_adstart(true);
325 });
326
327 while !T::regs().isr().read().eos() {
328 // spin
329 }
330
331 T::regs().dr().read().0 as u16
332 }
333
334 /// Read an ADC channel.
335 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
336 self.read_channel(channel)
337 }
338
339 /// Read one or multiple ADC channels using DMA.
340 ///
341 /// `sequence` iterator and `readings` must have the same length.
342 ///
343 /// Example
344 /// ```rust,ignore
345 /// use embassy_stm32::adc::{Adc, AdcChannel}
346 ///
347 /// let mut adc = Adc::new(p.ADC1);
348 /// let mut adc_pin0 = p.PA0.into();
349 /// let mut adc_pin2 = p.PA2.into();
350 /// let mut measurements = [0u16; 2];
351 ///
352 /// adc.read(
353 /// p.DMA2_CH0.reborrow(),
354 /// [
355 /// (&mut *adc_pin0, SampleTime::CYCLES112),
356 /// (&mut *adc_pin2, SampleTime::CYCLES112),
357 /// ]
358 /// .into_iter(),
359 /// &mut measurements,
360 /// )
361 /// .await;
362 /// defmt::info!("measurements: {}", measurements);
363 /// ```
364 pub async fn read(
365 &mut self,
366 rx_dma: Peri<'_, impl RxDma<T>>,
367 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
368 readings: &mut [u16],
369 ) {
370 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
371 assert!(
372 sequence.len() == readings.len(),
373 "Sequence length must be equal to readings length"
374 );
375 assert!(
376 sequence.len() <= 16,
377 "Asynchronous read sequence cannot be more than 16 in length"
378 );
379
380 // Ensure no conversions are ongoing
381 Self::cancel_conversions();
382
383 // Set sequence length
384 T::regs().sqr1().modify(|w| {
385 w.set_l(sequence.len() as u8 - 1);
386 });
387
388 // Configure channels and ranks
389 for (i, (channel, sample_time)) in sequence.enumerate() {
390 Self::configure_channel(channel, sample_time);
391 match i {
392 0..=3 => {
393 T::regs().sqr1().modify(|w| {
394 w.set_sq(i, channel.channel());
395 });
396 }
397 4..=8 => {
398 T::regs().sqr2().modify(|w| {
399 w.set_sq(i - 4, channel.channel());
400 });
401 }
402 9..=13 => {
403 T::regs().sqr3().modify(|w| {
404 w.set_sq(i - 9, channel.channel());
405 });
406 }
407 14..=15 => {
408 T::regs().sqr4().modify(|w| {
409 w.set_sq(i - 14, channel.channel());
410 });
411 }
412 _ => unreachable!(),
413 }
414 }
415
416 // Set continuous mode with oneshot dma.
417 // Clear overrun flag before starting transfer.
418
419 T::regs().isr().modify(|reg| {
420 reg.set_ovr(true);
421 });
422 T::regs().cfgr().modify(|reg| {
423 reg.set_cont(true);
424 reg.set_dmngt(Dmngt::DMA_ONE_SHOT);
425 });
426
427 let request = rx_dma.request();
428 let transfer = unsafe {
429 Transfer::new_read(
430 rx_dma,
431 request,
432 T::regs().dr().as_ptr() as *mut u16,
433 readings,
434 Default::default(),
435 )
436 };
437
438 // Start conversion
439 T::regs().cr().modify(|reg| {
440 reg.set_adstart(true);
441 });
442
443 // Wait for conversion sequence to finish.
444 transfer.await;
445
446 // Ensure conversions are finished.
447 Self::cancel_conversions();
448
449 // Reset configuration.
450 T::regs().cfgr().modify(|reg| {
451 reg.set_cont(false);
452 reg.set_dmngt(Dmngt::from_bits(0));
453 });
454 }
455
456 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
457 channel.setup();
458
459 let channel = channel.channel();
460
461 Self::set_channel_sample_time(channel, sample_time);
462
463 #[cfg(any(stm32h7, stm32u5))]
464 {
465 T::regs().cfgr2().modify(|w| w.set_lshift(0));
466 T::regs()
467 .pcsel()
468 .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
469 }
470 }
471
472 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
473 Self::configure_channel(channel, self.sample_time);
474
475 T::regs().sqr1().modify(|reg| {
476 reg.set_sq(0, channel.channel());
477 reg.set_l(0);
478 });
479
480 self.convert()
481 }
482
483 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
484 let sample_time = sample_time.into();
485 if ch <= 9 {
486 T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time));
487 } else {
488 T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
489 }
490 }
491
492 fn cancel_conversions() {
493 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
494 T::regs().cr().modify(|reg| {
495 reg.set_adstp(Adstp::STOP);
496 });
497 while T::regs().cr().read().adstart() {}
498 }
499 }
500} 332}
diff --git a/embassy-stm32/src/adc/watchdog_v1.rs b/embassy-stm32/src/adc/watchdog_v1.rs
index bbe8e1971..b12e0d333 100644
--- a/embassy-stm32/src/adc/watchdog_v1.rs
+++ b/embassy-stm32/src/adc/watchdog_v1.rs
@@ -1,7 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::task::Poll; 2use core::task::Poll;
3 3
4use stm32_metapac::adc::vals::{Align, Awdsgl, Res}; 4use stm32_metapac::adc::vals::{Align, Awdsgl, Res, SampleTime};
5 5
6use crate::adc::{Adc, AdcChannel, Instance}; 6use crate::adc::{Adc, AdcChannel, Instance};
7 7
@@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> {
67 /// let v_high = adc.monitor_watchdog().await; 67 /// let v_high = adc.monitor_watchdog().await;
68 /// info!("ADC sample is high {}", v_high); 68 /// info!("ADC sample is high {}", v_high);
69 /// ``` 69 /// ```
70 pub async fn monitor_watchdog(&mut self) -> u16 { 70 pub async fn monitor_watchdog(&mut self, sample_time: SampleTime) -> u16 {
71 assert!( 71 assert!(
72 match T::regs().cfgr1().read().awdsgl() { 72 match T::regs().cfgr1().read().awdsgl() {
73 Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0, 73 Awdsgl::SINGLE_CHANNEL => T::regs().cfgr1().read().awdch() != 0,
@@ -76,7 +76,7 @@ impl<'d, T: Instance> Adc<'d, T> {
76 "`set_channel` should be called before `monitor`", 76 "`set_channel` should be called before `monitor`",
77 ); 77 );
78 assert!(T::regs().chselr().read().0 != 0); 78 assert!(T::regs().chselr().read().0 != 0);
79 T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); 79 T::regs().smpr().modify(|reg| reg.set_smp(sample_time.into()));
80 Self::start_awd(); 80 Self::start_awd();
81 81
82 let sample = poll_fn(|cx| { 82 let sample = poll_fn(|cx| {
diff --git a/embassy-stm32/src/backup_sram.rs b/embassy-stm32/src/backup_sram.rs
new file mode 100644
index 000000000..31b373c6c
--- /dev/null
+++ b/embassy-stm32/src/backup_sram.rs
@@ -0,0 +1,28 @@
1//! Battary backed SRAM
2
3use core::slice;
4
5use embassy_hal_internal::Peri;
6
7use crate::_generated::{BKPSRAM_BASE, BKPSRAM_SIZE};
8use crate::peripherals::BKPSRAM;
9
10/// Struct used to initilize backup sram
11pub struct BackupMemory {}
12
13impl BackupMemory {
14 /// Setup battery backed sram
15 ///
16 /// Returns slice to sram and whether the sram was retained
17 pub fn new(_backup_sram: Peri<'static, BKPSRAM>) -> (&'static mut [u8], bool) {
18 // Assert bksram has been enabled in rcc
19 assert!(crate::pac::PWR.bdcr().read().bren() == crate::pac::pwr::vals::Retention::PRESERVED);
20
21 unsafe {
22 (
23 slice::from_raw_parts_mut(BKPSRAM_BASE as *mut u8, BKPSRAM_SIZE),
24 critical_section::with(|_| crate::rcc::BKSRAM_RETAINED),
25 )
26 }
27 }
28}
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 8eb188560..507350c42 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -5,8 +5,8 @@ use core::future::poll_fn;
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::interrupt::InterruptExt;
9use embassy_hal_internal::PeripheralType; 8use embassy_hal_internal::PeripheralType;
9use embassy_hal_internal::interrupt::InterruptExt;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
11use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
@@ -22,7 +22,7 @@ use crate::can::enums::{BusError, RefCountOp, TryReadError};
22use crate::gpio::{AfType, OutputType, Pull, Speed}; 22use crate::gpio::{AfType, OutputType, Pull, Speed};
23use crate::interrupt::typelevel::Interrupt; 23use crate::interrupt::typelevel::Interrupt;
24use crate::rcc::{self, RccPeripheral}; 24use crate::rcc::{self, RccPeripheral};
25use crate::{interrupt, peripherals, Peri}; 25use crate::{Peri, interrupt, peripherals};
26 26
27/// Interrupt handler. 27/// Interrupt handler.
28pub struct TxInterruptHandler<T: Instance> { 28pub struct TxInterruptHandler<T: Instance> {
@@ -186,10 +186,10 @@ impl<'d> Can<'d> {
186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>, 186 rx: Peri<'d, if_afio!(impl RxPin<T, A>)>,
187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>, 187 tx: Peri<'d, if_afio!(impl TxPin<T, A>)>,
188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>> 190 + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
191 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> 191 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
192 + 'd, 192 + 'd,
193 ) -> Self { 193 ) -> Self {
194 let info = T::info(); 194 let info = T::info();
195 let regs = &T::info().regs; 195 let regs = &T::info().regs;
diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs
index c6a66b469..4fe634ce4 100644
--- a/embassy-stm32/src/can/fd/config.rs
+++ b/embassy-stm32/src/can/fd/config.rs
@@ -1,7 +1,7 @@
1//! Configuration for FDCAN Module 1//! Configuration for FDCAN Module
2// Note: This file is copied and modified from fdcan crate by Richard Meadows 2// Note: This file is copied and modified from fdcan crate by Richard Meadows
3 3
4use core::num::{NonZeroU16, NonZeroU8}; 4use core::num::{NonZeroU8, NonZeroU16};
5 5
6/// Configures the bit timings. 6/// Configures the bit timings.
7/// 7///
@@ -360,6 +360,8 @@ pub struct FdCanConfig {
360 pub global_filter: GlobalFilter, 360 pub global_filter: GlobalFilter,
361 /// TX buffer mode (FIFO or priority queue) 361 /// TX buffer mode (FIFO or priority queue)
362 pub tx_buffer_mode: TxBufferMode, 362 pub tx_buffer_mode: TxBufferMode,
363 /// Automatic recovery from bus off state
364 pub automatic_bus_off_recovery: bool,
363} 365}
364 366
365impl FdCanConfig { 367impl FdCanConfig {
@@ -456,6 +458,16 @@ impl FdCanConfig {
456 self.tx_buffer_mode = txbm; 458 self.tx_buffer_mode = txbm;
457 self 459 self
458 } 460 }
461
462 /// Enables or disables automatic recovery from bus off state
463 ///
464 /// Automatic recovery is performed by clearing the INIT bit in the CCCR register if
465 /// the BO bit is active in the IR register in the IT0 interrupt.
466 #[inline]
467 pub const fn set_automatic_bus_off_recovery(mut self, enabled: bool) -> Self {
468 self.automatic_bus_off_recovery = enabled;
469 self
470 }
459} 471}
460 472
461impl Default for FdCanConfig { 473impl Default for FdCanConfig {
@@ -474,6 +486,7 @@ impl Default for FdCanConfig {
474 timestamp_source: TimestampSource::None, 486 timestamp_source: TimestampSource::None,
475 global_filter: GlobalFilter::default(), 487 global_filter: GlobalFilter::default(),
476 tx_buffer_mode: TxBufferMode::Priority, 488 tx_buffer_mode: TxBufferMode::Priority,
489 automatic_bus_off_recovery: true,
477 } 490 }
478 } 491 }
479} 492}
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index d8f71e03e..9883aff57 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -3,8 +3,8 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::interrupt::InterruptExt;
7use embassy_hal_internal::PeripheralType; 6use embassy_hal_internal::PeripheralType;
7use embassy_hal_internal::interrupt::InterruptExt;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::channel::Channel; 9use embassy_sync::channel::Channel;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
@@ -13,7 +13,7 @@ use crate::can::fd::peripheral::Registers;
13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, peripherals, Peri}; 16use crate::{Peri, interrupt, peripherals};
17 17
18pub(crate) mod fd; 18pub(crate) mod fd;
19 19
@@ -53,7 +53,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
53 regs.ir().write(|w| w.set_tefn(true)); 53 regs.ir().write(|w| w.set_tefn(true));
54 } 54 }
55 55
56 T::info().state.lock(|s| { 56 let recover_from_bo = T::info().state.lock(|s| {
57 let state = s.borrow_mut(); 57 let state = s.borrow_mut();
58 match &state.tx_mode { 58 match &state.tx_mode {
59 TxMode::NonBuffered(waker) => waker.wake(), 59 TxMode::NonBuffered(waker) => waker.wake(),
@@ -85,11 +85,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
85 if ir.rfn(1) { 85 if ir.rfn(1) {
86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick); 86 state.rx_mode.on_interrupt::<T>(1, state.ns_per_timer_tick);
87 } 87 }
88
89 state.automatic_bus_off_recovery
88 }); 90 });
89 91
90 if ir.bo() { 92 if ir.bo() {
91 regs.ir().write(|w| w.set_bo(true)); 93 regs.ir().write(|w| w.set_bo(true));
92 if regs.psr().read().bo() { 94 if let Some(true) = recover_from_bo
95 && regs.psr().read().bo()
96 {
93 // Initiate bus-off recovery sequence by resetting CCCR.INIT 97 // Initiate bus-off recovery sequence by resetting CCCR.INIT
94 regs.cccr().modify(|w| w.set_init(false)); 98 regs.cccr().modify(|w| w.set_init(false));
95 } 99 }
@@ -182,8 +186,8 @@ impl<'d> CanConfigurator<'d> {
182 rx: Peri<'d, impl RxPin<T>>, 186 rx: Peri<'d, impl RxPin<T>>,
183 tx: Peri<'d, impl TxPin<T>>, 187 tx: Peri<'d, impl TxPin<T>>,
184 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> 188 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
185 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 189 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
186 + 'd, 190 + 'd,
187 ) -> CanConfigurator<'d> { 191 ) -> CanConfigurator<'d> {
188 set_as_af!(rx, AfType::input(Pull::None)); 192 set_as_af!(rx, AfType::input(Pull::None));
189 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 193 set_as_af!(tx, AfType::output(OutputType::PushPull, Speed::VeryHigh));
@@ -263,7 +267,9 @@ impl<'d> CanConfigurator<'d> {
263 pub fn start(self, mode: OperatingMode) -> Can<'d> { 267 pub fn start(self, mode: OperatingMode) -> Can<'d> {
264 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit); 268 let ns_per_timer_tick = calc_ns_per_timer_tick(&self.info, self.periph_clock, self.config.frame_transmit);
265 self.info.state.lock(|s| { 269 self.info.state.lock(|s| {
266 s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; 270 let mut state = s.borrow_mut();
271 state.ns_per_timer_tick = ns_per_timer_tick;
272 state.automatic_bus_off_recovery = Some(self.config.automatic_bus_off_recovery);
267 }); 273 });
268 self.info.regs.into_mode(self.config, mode); 274 self.info.regs.into_mode(self.config, mode);
269 Can { 275 Can {
@@ -459,7 +465,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d,
459 pub async fn write(&mut self, frame: Frame) { 465 pub async fn write(&mut self, frame: Frame) {
460 self.tx_buf.send(frame).await; 466 self.tx_buf.send(frame).await;
461 self.info.interrupt0.pend(); // Wake for Tx 467 self.info.interrupt0.pend(); // Wake for Tx
462 //T::IT0Interrupt::pend(); // Wake for Tx 468 //T::IT0Interrupt::pend(); // Wake for Tx
463 } 469 }
464 470
465 /// Async read frame from RX buffer. 471 /// Async read frame from RX buffer.
@@ -548,7 +554,7 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'
548 pub async fn write(&mut self, frame: FdFrame) { 554 pub async fn write(&mut self, frame: FdFrame) {
549 self.tx_buf.send(frame).await; 555 self.tx_buf.send(frame).await;
550 self.info.interrupt0.pend(); // Wake for Tx 556 self.info.interrupt0.pend(); // Wake for Tx
551 //T::IT0Interrupt::pend(); // Wake for Tx 557 //T::IT0Interrupt::pend(); // Wake for Tx
552 } 558 }
553 559
554 /// Async read frame from RX buffer. 560 /// Async read frame from RX buffer.
@@ -861,7 +867,7 @@ struct State {
861 sender_instance_count: usize, 867 sender_instance_count: usize,
862 tx_pin_port: Option<u8>, 868 tx_pin_port: Option<u8>,
863 rx_pin_port: Option<u8>, 869 rx_pin_port: Option<u8>,
864 870 automatic_bus_off_recovery: Option<bool>, // controlled by CanConfigurator::start()
865 pub err_waker: AtomicWaker, 871 pub err_waker: AtomicWaker,
866} 872}
867 873
@@ -876,6 +882,7 @@ impl State {
876 sender_instance_count: 0, 882 sender_instance_count: 0,
877 tx_pin_port: None, 883 tx_pin_port: None,
878 rx_pin_port: None, 884 rx_pin_port: None,
885 automatic_bus_off_recovery: None,
879 } 886 }
880 } 887 }
881} 888}
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs
index fcdbbad62..6d7f0c16a 100644
--- a/embassy-stm32/src/can/util.rs
+++ b/embassy-stm32/src/can/util.rs
@@ -1,6 +1,6 @@
1//! Utility functions shared between CAN controller types. 1//! Utility functions shared between CAN controller types.
2 2
3use core::num::{NonZeroU16, NonZeroU8}; 3use core::num::{NonZeroU8, NonZeroU16};
4 4
5/// Shared struct to represent bit timings used by calc_can_timings. 5/// Shared struct to represent bit timings used by calc_can_timings.
6#[derive(Clone, Copy, Debug)] 6#[derive(Clone, Copy, Debug)]
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index 13e5263de..836228599 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -1,6 +1,6 @@
1use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
2use crate::peripherals::CRC; 2use crate::peripherals::CRC;
3use crate::{rcc, Peri}; 3use crate::{Peri, rcc};
4 4
5/// CRC driver. 5/// CRC driver.
6pub struct Crc<'d> { 6pub struct Crc<'d> {
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index d834d0971..a566a2e04 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -1,7 +1,7 @@
1use crate::pac::crc::vals;
2use crate::pac::CRC as PAC_CRC; 1use crate::pac::CRC as PAC_CRC;
2use crate::pac::crc::vals;
3use crate::peripherals::CRC; 3use crate::peripherals::CRC;
4use crate::{rcc, Peri}; 4use crate::{Peri, rcc};
5 5
6/// CRC driver. 6/// CRC driver.
7pub struct Crc<'d> { 7pub struct Crc<'d> {
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index 0173b2b5d..4f1115fb7 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -1236,7 +1236,10 @@ impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> {
1236 } 1236 }
1237 if C::REQUIRES_PADDING { 1237 if C::REQUIRES_PADDING {
1238 if last_block_remainder != 0 { 1238 if last_block_remainder != 0 {
1239 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); 1239 panic!(
1240 "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
1241 C::BLOCK_SIZE
1242 );
1240 } 1243 }
1241 } 1244 }
1242 if last_block { 1245 if last_block {
@@ -1703,7 +1706,10 @@ impl<'d, T: Instance> Cryp<'d, T, Async> {
1703 } 1706 }
1704 if C::REQUIRES_PADDING { 1707 if C::REQUIRES_PADDING {
1705 if last_block_remainder != 0 { 1708 if last_block_remainder != 0 {
1706 panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); 1709 panic!(
1710 "Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
1711 C::BLOCK_SIZE
1712 );
1707 } 1713 }
1708 } 1714 }
1709 if last_block { 1715 if last_block {
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 08e001337..d74d4a4be 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -8,7 +8,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode};
8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] 8#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
9use crate::pac::dac; 9use crate::pac::dac;
10use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
11use crate::{peripherals, Peri}; 11use crate::{Peri, peripherals};
12 12
13mod tsel; 13mod tsel;
14use embassy_hal_internal::PeripheralType; 14use embassy_hal_internal::PeripheralType;
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index bd03f1e00..dcae9f298 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::gpio::{AfType, Pull}; 10use crate::gpio::{AfType, Pull};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, rcc, Peri}; 12use crate::{Peri, interrupt, rcc};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
15pub struct InterruptHandler<T: Instance> { 15pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 73ecab070..b46ae2813 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -1,6 +1,6 @@
1use core::future::{poll_fn, Future}; 1use core::future::{Future, poll_fn};
2use core::pin::Pin; 2use core::pin::Pin;
3use core::sync::atomic::{fence, AtomicUsize, Ordering}; 3use core::sync::atomic::{AtomicUsize, Ordering, fence};
4use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
5 5
6use embassy_hal_internal::Peri; 6use embassy_hal_internal::Peri;
@@ -8,7 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 9use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
10use super::word::{Word, WordSize}; 10use super::word::{Word, WordSize};
11use super::{AnyChannel, Channel, Dir, Request, STATE}; 11use super::{AnyChannel, BusyChannel, Channel, Dir, Request, STATE};
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac}; 13use crate::{interrupt, pac};
14 14
@@ -602,7 +602,7 @@ impl AnyChannel {
602/// DMA transfer. 602/// DMA transfer.
603#[must_use = "futures do nothing unless you `.await` or poll them"] 603#[must_use = "futures do nothing unless you `.await` or poll them"]
604pub struct Transfer<'a> { 604pub struct Transfer<'a> {
605 channel: Peri<'a, AnyChannel>, 605 channel: BusyChannel<'a>,
606} 606}
607 607
608impl<'a> Transfer<'a> { 608impl<'a> Transfer<'a> {
@@ -713,7 +713,9 @@ impl<'a> Transfer<'a> {
713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options, 713 _request, dir, peri_addr, mem_addr, mem_len, incr_mem, mem_size, peri_size, options,
714 ); 714 );
715 channel.start(); 715 channel.start();
716 Self { channel } 716 Self {
717 channel: BusyChannel::new(channel),
718 }
717 } 719 }
718 720
719 /// Request the transfer to pause, keeping the existing configuration for this channel. 721 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -816,7 +818,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
816 818
817/// Ringbuffer for receiving data using DMA circular mode. 819/// Ringbuffer for receiving data using DMA circular mode.
818pub struct ReadableRingBuffer<'a, W: Word> { 820pub struct ReadableRingBuffer<'a, W: Word> {
819 channel: Peri<'a, AnyChannel>, 821 channel: BusyChannel<'a>,
820 ringbuf: ReadableDmaRingBuffer<'a, W>, 822 ringbuf: ReadableDmaRingBuffer<'a, W>,
821} 823}
822 824
@@ -853,7 +855,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
853 ); 855 );
854 856
855 Self { 857 Self {
856 channel, 858 channel: BusyChannel::new(channel),
857 ringbuf: ReadableDmaRingBuffer::new(buffer), 859 ringbuf: ReadableDmaRingBuffer::new(buffer),
858 } 860 }
859 } 861 }
@@ -972,7 +974,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
972 974
973/// Ringbuffer for writing data using DMA circular mode. 975/// Ringbuffer for writing data using DMA circular mode.
974pub struct WritableRingBuffer<'a, W: Word> { 976pub struct WritableRingBuffer<'a, W: Word> {
975 channel: Peri<'a, AnyChannel>, 977 channel: BusyChannel<'a>,
976 ringbuf: WritableDmaRingBuffer<'a, W>, 978 ringbuf: WritableDmaRingBuffer<'a, W>,
977} 979}
978 980
@@ -1009,7 +1011,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
1009 ); 1011 );
1010 1012
1011 Self { 1013 Self {
1012 channel, 1014 channel: BusyChannel::new(channel),
1013 ringbuf: WritableDmaRingBuffer::new(buffer), 1015 ringbuf: WritableDmaRingBuffer::new(buffer),
1014 } 1016 }
1015 } 1017 }
diff --git a/embassy-stm32/src/dma/gpdma/mod.rs b/embassy-stm32/src/dma/gpdma/mod.rs
index 4a14c2a8e..383c74a78 100644
--- a/embassy-stm32/src/dma/gpdma/mod.rs
+++ b/embassy-stm32/src/dma/gpdma/mod.rs
@@ -2,7 +2,7 @@
2 2
3use core::future::Future; 3use core::future::Future;
4use core::pin::Pin; 4use core::pin::Pin;
5use core::sync::atomic::{fence, AtomicUsize, Ordering}; 5use core::sync::atomic::{AtomicUsize, Ordering, fence};
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
@@ -11,6 +11,7 @@ use linked_list::Table;
11 11
12use super::word::{Word, WordSize}; 12use super::word::{Word, WordSize};
13use super::{AnyChannel, Channel, Dir, Request, STATE}; 13use super::{AnyChannel, Channel, Dir, Request, STATE};
14use crate::dma::BusyChannel;
14use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
15use crate::pac; 16use crate::pac;
16use crate::pac::gpdma::vals; 17use crate::pac::gpdma::vals;
@@ -136,6 +137,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: c
136 137
137impl AnyChannel { 138impl AnyChannel {
138 /// Safety: Must be called with a matching set of parameters for a valid dma channel 139 /// Safety: Must be called with a matching set of parameters for a valid dma channel
140 #[cfg(not(stm32n6))]
139 pub(crate) unsafe fn on_irq(&self) { 141 pub(crate) unsafe fn on_irq(&self) {
140 let info = self.info(); 142 let info = self.info();
141 #[cfg(feature = "_dual-core")] 143 #[cfg(feature = "_dual-core")]
@@ -407,7 +409,7 @@ impl AnyChannel {
407/// Linked-list DMA transfer. 409/// Linked-list DMA transfer.
408#[must_use = "futures do nothing unless you `.await` or poll them"] 410#[must_use = "futures do nothing unless you `.await` or poll them"]
409pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> { 411pub struct LinkedListTransfer<'a, const ITEM_COUNT: usize> {
410 channel: Peri<'a, AnyChannel>, 412 channel: BusyChannel<'a>,
411} 413}
412 414
413impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> { 415impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
@@ -428,7 +430,9 @@ impl<'a, const ITEM_COUNT: usize> LinkedListTransfer<'a, ITEM_COUNT> {
428 channel.configure_linked_list(&table, options); 430 channel.configure_linked_list(&table, options);
429 channel.start(); 431 channel.start();
430 432
431 Self { channel } 433 Self {
434 channel: BusyChannel::new(channel),
435 }
432 } 436 }
433 437
434 /// Request the transfer to pause, keeping the existing configuration for this channel. 438 /// Request the transfer to pause, keeping the existing configuration for this channel.
@@ -504,7 +508,7 @@ impl<'a, const ITEM_COUNT: usize> Future for LinkedListTransfer<'a, ITEM_COUNT>
504/// DMA transfer. 508/// DMA transfer.
505#[must_use = "futures do nothing unless you `.await` or poll them"] 509#[must_use = "futures do nothing unless you `.await` or poll them"]
506pub struct Transfer<'a> { 510pub struct Transfer<'a> {
507 channel: Peri<'a, AnyChannel>, 511 channel: BusyChannel<'a>,
508} 512}
509 513
510impl<'a> Transfer<'a> { 514impl<'a> Transfer<'a> {
@@ -624,7 +628,9 @@ impl<'a> Transfer<'a> {
624 ); 628 );
625 channel.start(); 629 channel.start();
626 630
627 Self { channel } 631 Self {
632 channel: BusyChannel::new(channel),
633 }
628 } 634 }
629 635
630 /// Request the transfer to pause, keeping the existing configuration for this channel. 636 /// Request the transfer to pause, keeping the existing configuration for this channel.
diff --git a/embassy-stm32/src/dma/gpdma/ringbuffered.rs b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
index 9ee52193b..54e4d5f71 100644
--- a/embassy-stm32/src/dma/gpdma/ringbuffered.rs
+++ b/embassy-stm32/src/dma/gpdma/ringbuffered.rs
@@ -3,16 +3,16 @@
3//! FIXME: Add request_pause functionality? 3//! FIXME: Add request_pause functionality?
4//! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically). 4//! FIXME: Stop the DMA, if a user does not queue new transfers (chain of linked-list items ends automatically).
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::sync::atomic::{fence, Ordering}; 6use core::sync::atomic::{Ordering, fence};
7use core::task::Waker; 7use core::task::Waker;
8 8
9use embassy_hal_internal::Peri; 9use embassy_hal_internal::Peri;
10 10
11use super::{AnyChannel, TransferOptions, STATE}; 11use super::{AnyChannel, STATE, TransferOptions};
12use crate::dma::gpdma::linked_list::{RunMode, Table}; 12use crate::dma::gpdma::linked_list::{RunMode, Table};
13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; 13use crate::dma::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer};
14use crate::dma::word::Word; 14use crate::dma::word::Word;
15use crate::dma::{Channel, Dir, Request}; 15use crate::dma::{BusyChannel, Channel, Dir, Request};
16 16
17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); 17struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>);
18 18
@@ -49,7 +49,7 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
49 49
50/// Ringbuffer for receiving data using GPDMA linked-list mode. 50/// Ringbuffer for receiving data using GPDMA linked-list mode.
51pub struct ReadableRingBuffer<'a, W: Word> { 51pub struct ReadableRingBuffer<'a, W: Word> {
52 channel: Peri<'a, AnyChannel>, 52 channel: BusyChannel<'a>,
53 ringbuf: ReadableDmaRingBuffer<'a, W>, 53 ringbuf: ReadableDmaRingBuffer<'a, W>,
54 table: Table<2>, 54 table: Table<2>,
55 options: TransferOptions, 55 options: TransferOptions,
@@ -70,7 +70,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory); 70 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::PeripheralToMemory);
71 71
72 Self { 72 Self {
73 channel, 73 channel: BusyChannel::new(channel),
74 ringbuf: ReadableDmaRingBuffer::new(buffer), 74 ringbuf: ReadableDmaRingBuffer::new(buffer),
75 table, 75 table,
76 options, 76 options,
@@ -189,7 +189,7 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> {
189 189
190/// Ringbuffer for writing data using GPDMA linked-list mode. 190/// Ringbuffer for writing data using GPDMA linked-list mode.
191pub struct WritableRingBuffer<'a, W: Word> { 191pub struct WritableRingBuffer<'a, W: Word> {
192 channel: Peri<'a, AnyChannel>, 192 channel: BusyChannel<'a>,
193 ringbuf: WritableDmaRingBuffer<'a, W>, 193 ringbuf: WritableDmaRingBuffer<'a, W>,
194 table: Table<2>, 194 table: Table<2>,
195 options: TransferOptions, 195 options: TransferOptions,
@@ -210,7 +210,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral); 210 let table = Table::<2>::new_ping_pong::<W>(request, peri_addr, buffer, Dir::MemoryToPeripheral);
211 211
212 Self { 212 Self {
213 channel, 213 channel: BusyChannel::new(channel),
214 ringbuf: WritableDmaRingBuffer::new(buffer), 214 ringbuf: WritableDmaRingBuffer::new(buffer),
215 table, 215 table,
216 options, 216 options,
diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs
index 5989bfd7c..4becc2d87 100644
--- a/embassy-stm32/src/dma/mod.rs
+++ b/embassy-stm32/src/dma/mod.rs
@@ -3,11 +3,14 @@
3 3
4#[cfg(any(bdma, dma))] 4#[cfg(any(bdma, dma))]
5mod dma_bdma; 5mod dma_bdma;
6use core::ops;
7
6#[cfg(any(bdma, dma))] 8#[cfg(any(bdma, dma))]
7pub use dma_bdma::*; 9pub use dma_bdma::*;
8 10
9#[cfg(gpdma)] 11#[cfg(gpdma)]
10pub(crate) mod gpdma; 12pub(crate) mod gpdma;
13use embassy_hal_internal::Peri;
11#[cfg(gpdma)] 14#[cfg(gpdma)]
12pub use gpdma::ringbuffered::*; 15pub use gpdma::ringbuffered::*;
13#[cfg(gpdma)] 16#[cfg(gpdma)]
@@ -24,7 +27,7 @@ pub(crate) use util::*;
24pub(crate) mod ringbuffer; 27pub(crate) mod ringbuffer;
25pub mod word; 28pub mod word;
26 29
27use embassy_hal_internal::{impl_peripheral, PeripheralType}; 30use embassy_hal_internal::{PeripheralType, impl_peripheral};
28 31
29use crate::interrupt; 32use crate::interrupt;
30 33
@@ -46,9 +49,13 @@ pub type Request = u8;
46pub type Request = (); 49pub type Request = ();
47 50
48pub(crate) trait SealedChannel { 51pub(crate) trait SealedChannel {
52 #[cfg(not(stm32n6))]
49 fn id(&self) -> u8; 53 fn id(&self) -> u8;
54 #[cfg(feature = "low-power")]
55 fn stop_mode(&self) -> crate::rcc::StopMode;
50} 56}
51 57
58#[cfg(not(stm32n6))]
52pub(crate) trait ChannelInterrupt { 59pub(crate) trait ChannelInterrupt {
53 #[cfg_attr(not(feature = "rt"), allow(unused))] 60 #[cfg_attr(not(feature = "rt"), allow(unused))]
54 unsafe fn on_irq(); 61 unsafe fn on_irq();
@@ -58,16 +65,27 @@ pub(crate) trait ChannelInterrupt {
58#[allow(private_bounds)] 65#[allow(private_bounds)]
59pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {} 66pub trait Channel: SealedChannel + PeripheralType + Into<AnyChannel> + 'static {}
60 67
68#[cfg(not(stm32n6))]
61macro_rules! dma_channel_impl { 69macro_rules! dma_channel_impl {
62 ($channel_peri:ident, $index:expr) => { 70 ($channel_peri:ident, $index:expr, $stop_mode:ident) => {
63 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri { 71 impl crate::dma::SealedChannel for crate::peripherals::$channel_peri {
64 fn id(&self) -> u8 { 72 fn id(&self) -> u8 {
65 $index 73 $index
66 } 74 }
75
76 #[cfg(feature = "low-power")]
77 fn stop_mode(&self) -> crate::rcc::StopMode {
78 crate::rcc::StopMode::$stop_mode
79 }
67 } 80 }
68 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri { 81 impl crate::dma::ChannelInterrupt for crate::peripherals::$channel_peri {
69 unsafe fn on_irq() { 82 unsafe fn on_irq() {
70 crate::dma::AnyChannel { id: $index }.on_irq(); 83 crate::dma::AnyChannel {
84 id: $index,
85 #[cfg(feature = "low-power")]
86 stop_mode: crate::rcc::StopMode::$stop_mode,
87 }
88 .on_irq();
71 } 89 }
72 } 90 }
73 91
@@ -77,15 +95,57 @@ macro_rules! dma_channel_impl {
77 fn from(val: crate::peripherals::$channel_peri) -> Self { 95 fn from(val: crate::peripherals::$channel_peri) -> Self {
78 Self { 96 Self {
79 id: crate::dma::SealedChannel::id(&val), 97 id: crate::dma::SealedChannel::id(&val),
98 #[cfg(feature = "low-power")]
99 stop_mode: crate::dma::SealedChannel::stop_mode(&val),
80 } 100 }
81 } 101 }
82 } 102 }
83 }; 103 };
84} 104}
85 105
106pub(crate) struct BusyChannel<'a> {
107 channel: Peri<'a, AnyChannel>,
108}
109
110impl<'a> BusyChannel<'a> {
111 pub fn new(channel: Peri<'a, AnyChannel>) -> Self {
112 #[cfg(feature = "low-power")]
113 critical_section::with(|cs| {
114 crate::rcc::increment_stop_refcount(cs, channel.stop_mode);
115 });
116
117 Self { channel }
118 }
119}
120
121impl<'a> Drop for BusyChannel<'a> {
122 fn drop(&mut self) {
123 #[cfg(feature = "low-power")]
124 critical_section::with(|cs| {
125 crate::rcc::decrement_stop_refcount(cs, self.stop_mode);
126 });
127 }
128}
129
130impl<'a> ops::Deref for BusyChannel<'a> {
131 type Target = Peri<'a, AnyChannel>;
132
133 fn deref(&self) -> &Self::Target {
134 &self.channel
135 }
136}
137
138impl<'a> ops::DerefMut for BusyChannel<'a> {
139 fn deref_mut(&mut self) -> &mut Self::Target {
140 &mut self.channel
141 }
142}
143
86/// Type-erased DMA channel. 144/// Type-erased DMA channel.
87pub struct AnyChannel { 145pub struct AnyChannel {
88 pub(crate) id: u8, 146 pub(crate) id: u8,
147 #[cfg(feature = "low-power")]
148 pub(crate) stop_mode: crate::rcc::StopMode,
89} 149}
90impl_peripheral!(AnyChannel); 150impl_peripheral!(AnyChannel);
91 151
@@ -96,9 +156,15 @@ impl AnyChannel {
96} 156}
97 157
98impl SealedChannel for AnyChannel { 158impl SealedChannel for AnyChannel {
159 #[cfg(not(stm32n6))]
99 fn id(&self) -> u8 { 160 fn id(&self) -> u8 {
100 self.id 161 self.id
101 } 162 }
163
164 #[cfg(feature = "low-power")]
165 fn stop_mode(&self) -> crate::rcc::StopMode {
166 self.stop_mode
167 }
102} 168}
103impl Channel for AnyChannel {} 169impl Channel for AnyChannel {}
104 170
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
index 661fb1728..eff5b4058 100644
--- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
+++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs
@@ -2,7 +2,7 @@ use std::task::Waker;
2 2
3use proptest::prop_oneof; 3use proptest::prop_oneof;
4use proptest::strategy::{self, BoxedStrategy, Strategy as _}; 4use proptest::strategy::{self, BoxedStrategy, Strategy as _};
5use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest}; 5use proptest_state_machine::{ReferenceStateMachine, StateMachineTest, prop_state_machine};
6 6
7use super::*; 7use super::*;
8 8
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index deda956af..b8945820c 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -5,17 +5,10 @@ use core::marker::PhantomData;
5use embassy_hal_internal::PeripheralType; 5use embassy_hal_internal::PeripheralType;
6 6
7//use crate::gpio::{AnyPin, SealedPin}; 7//use crate::gpio::{AnyPin, SealedPin};
8use crate::block_for_us;
8use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 9use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
10use crate::{peripherals, Peri}; 11use crate::{Peri, peripherals};
11
12/// Performs a busy-wait delay for a specified number of microseconds.
13pub 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 12
20/// PacketTypes extracted from CubeMX 13/// PacketTypes extracted from CubeMX
21#[repr(u8)] 14#[repr(u8)]
@@ -121,17 +114,15 @@ impl<'d, T: Instance> DsiHost<'d, T> {
121 114
122 /// DCS or Generic short/long write command 115 /// DCS or Generic short/long write command
123 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> { 116 pub fn write_cmd(&mut self, channel_id: u8, address: u8, data: &[u8]) -> Result<(), Error> {
124 assert!(data.len() > 0); 117 match data.len() {
125 118 0 => self.short_write(channel_id, PacketType::DcsShortPktWriteP0, address, 0),
126 if data.len() == 1 { 119 1 => self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]),
127 self.short_write(channel_id, PacketType::DcsShortPktWriteP1, address, data[0]) 120 _ => self.long_write(
128 } else {
129 self.long_write(
130 channel_id, 121 channel_id,
131 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well... 122 PacketType::DcsLongPktWrite, // FIXME: This might be a generic long packet, as well...
132 address, 123 address,
133 data, 124 data,
134 ) 125 ),
135 } 126 }
136 } 127 }
137 128
@@ -336,7 +327,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
336 if T::regs().gpsr().read().cmdfe() { 327 if T::regs().gpsr().read().cmdfe() {
337 return Ok(()); 328 return Ok(());
338 } 329 }
339 blocking_delay_ms(1); 330 block_for_us(1_000);
340 } 331 }
341 Err(Error::FifoTimeout) 332 Err(Error::FifoTimeout)
342 } 333 }
@@ -347,7 +338,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
347 if !T::regs().gpsr().read().cmdff() { 338 if !T::regs().gpsr().read().cmdff() {
348 return Ok(()); 339 return Ok(());
349 } 340 }
350 blocking_delay_ms(1); 341 block_for_us(1_000);
351 } 342 }
352 Err(Error::FifoTimeout) 343 Err(Error::FifoTimeout)
353 } 344 }
@@ -358,7 +349,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
358 if !self.read_busy() { 349 if !self.read_busy() {
359 return Ok(()); 350 return Ok(());
360 } 351 }
361 blocking_delay_ms(1); 352 block_for_us(1_000);
362 } 353 }
363 Err(Error::ReadTimeout) 354 Err(Error::ReadTimeout)
364 } 355 }
@@ -369,7 +360,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
369 if !T::regs().gpsr().read().prdfe() { 360 if !T::regs().gpsr().read().prdfe() {
370 return Ok(()); 361 return Ok(());
371 } 362 }
372 blocking_delay_ms(1); 363 block_for_us(1_000);
373 } 364 }
374 Err(Error::FifoTimeout) 365 Err(Error::FifoTimeout)
375 } 366 }
diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs
index 1f39c8db5..a75ae0560 100644
--- a/embassy-stm32/src/dts/mod.rs
+++ b/embassy-stm32/src/dts/mod.rs
@@ -1,7 +1,7 @@
1//! Digital Temperature Sensor (DTS) 1//! Digital Temperature Sensor (DTS)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_hal_internal::Peri; 7use embassy_hal_internal::Peri;
diff --git a/embassy-stm32/src/dts/tsel.rs b/embassy-stm32/src/dts/tsel.rs
index 99eab6dd8..79c697c8d 100644
--- a/embassy-stm32/src/dts/tsel.rs
+++ b/embassy-stm32/src/dts/tsel.rs
@@ -49,3 +49,20 @@ pub enum TriggerSel {
49 /// EXTI13 49 /// EXTI13
50 Exti13 = 4, 50 Exti13 = 4,
51} 51}
52
53/// Trigger selection for N6
54#[cfg(stm32n6)]
55#[derive(Debug, Copy, Clone, Eq, PartialEq)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))]
57pub enum TriggerSel {
58 /// Software triggering. Performs continuous measurements.
59 Software = 0,
60 /// LPTIM4 OUT
61 Lptim4 = 1,
62 /// LPTIM2 CH1
63 Lptim2 = 2,
64 /// LPTIM3 CH1
65 Lptim3 = 3,
66 /// EXTI13
67 Exti13 = 4,
68}
diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs
index 774beef80..0a5f41de0 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};
8use futures_util::FutureExt; 8use futures_util::FutureExt;
9 9
10use super::{Phy, StationManagement}; 10use super::{Phy, StationManagement};
11use crate::block_for_us as blocking_delay_us;
11 12
12#[allow(dead_code)] 13#[allow(dead_code)]
13mod phy_consts { 14mod phy_consts {
@@ -43,21 +44,23 @@ mod phy_consts {
43use self::phy_consts::*; 44use self::phy_consts::*;
44 45
45/// Generic SMI Ethernet PHY implementation 46/// Generic SMI Ethernet PHY implementation
46pub struct GenericPhy { 47pub struct GenericPhy<SM: StationManagement> {
47 phy_addr: u8, 48 phy_addr: u8,
49 sm: SM,
48 #[cfg(feature = "time")] 50 #[cfg(feature = "time")]
49 poll_interval: Duration, 51 poll_interval: Duration,
50} 52}
51 53
52impl GenericPhy { 54impl<SM: StationManagement> GenericPhy<SM> {
53 /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication 55 /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication
54 /// 56 ///
55 /// # Panics 57 /// # Panics
56 /// `phy_addr` must be in range `0..32` 58 /// `phy_addr` must be in range `0..32`
57 pub fn new(phy_addr: u8) -> Self { 59 pub fn new(sm: SM, phy_addr: u8) -> Self {
58 assert!(phy_addr < 32); 60 assert!(phy_addr < 32);
59 Self { 61 Self {
60 phy_addr, 62 phy_addr,
63 sm,
61 #[cfg(feature = "time")] 64 #[cfg(feature = "time")]
62 poll_interval: Duration::from_millis(500), 65 poll_interval: Duration::from_millis(500),
63 } 66 }
@@ -67,8 +70,9 @@ impl GenericPhy {
67 /// 70 ///
68 /// # Panics 71 /// # Panics
69 /// Initialization panics if PHY didn't respond on any address 72 /// Initialization panics if PHY didn't respond on any address
70 pub fn new_auto() -> Self { 73 pub fn new_auto(sm: SM) -> Self {
71 Self { 74 Self {
75 sm,
72 phy_addr: 0xFF, 76 phy_addr: 0xFF,
73 #[cfg(feature = "time")] 77 #[cfg(feature = "time")]
74 poll_interval: Duration::from_millis(500), 78 poll_interval: Duration::from_millis(500),
@@ -76,27 +80,14 @@ impl GenericPhy {
76 } 80 }
77} 81}
78 82
79// TODO: Factor out to shared functionality 83impl<SM: StationManagement> Phy for GenericPhy<SM> {
80fn blocking_delay_us(us: u32) { 84 fn phy_reset(&mut self) {
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
92impl Phy for GenericPhy {
93 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
94 // Detect SMI address 85 // Detect SMI address
95 if self.phy_addr == 0xFF { 86 if self.phy_addr == 0xFF {
96 for addr in 0..32 { 87 for addr in 0..32 {
97 sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); 88 self.sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
98 for _ in 0..10 { 89 for _ in 0..10 {
99 if sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET { 90 if self.sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET {
100 trace!("Found ETH PHY on address {}", addr); 91 trace!("Found ETH PHY on address {}", addr);
101 self.phy_addr = addr; 92 self.phy_addr = addr;
102 return; 93 return;
@@ -108,30 +99,30 @@ impl Phy for GenericPhy {
108 panic!("PHY did not respond"); 99 panic!("PHY did not respond");
109 } 100 }
110 101
111 sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); 102 self.sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
112 while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} 103 while self.sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
113 } 104 }
114 105
115 fn phy_init<S: StationManagement>(&mut self, sm: &mut S) { 106 fn phy_init(&mut self) {
116 // Clear WU CSR 107 // Clear WU CSR
117 self.smi_write_ext(sm, PHY_REG_WUCSR, 0); 108 self.smi_write_ext(PHY_REG_WUCSR, 0);
118 109
119 // Enable auto-negotiation 110 // Enable auto-negotiation
120 sm.smi_write( 111 self.sm.smi_write(
121 self.phy_addr, 112 self.phy_addr,
122 PHY_REG_BCR, 113 PHY_REG_BCR,
123 PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M, 114 PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M,
124 ); 115 );
125 } 116 }
126 117
127 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool { 118 fn poll_link(&mut self, cx: &mut Context) -> bool {
128 #[cfg(not(feature = "time"))] 119 #[cfg(not(feature = "time"))]
129 cx.waker().wake_by_ref(); 120 cx.waker().wake_by_ref();
130 121
131 #[cfg(feature = "time")] 122 #[cfg(feature = "time")]
132 let _ = Timer::after(self.poll_interval).poll_unpin(cx); 123 let _ = Timer::after(self.poll_interval).poll_unpin(cx);
133 124
134 let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR); 125 let bsr = self.sm.smi_read(self.phy_addr, PHY_REG_BSR);
135 126
136 // No link without autonegotiate 127 // No link without autonegotiate
137 if bsr & PHY_REG_BSR_ANDONE == 0 { 128 if bsr & PHY_REG_BSR_ANDONE == 0 {
@@ -148,7 +139,7 @@ impl Phy for GenericPhy {
148} 139}
149 140
150/// Public functions for the PHY 141/// Public functions for the PHY
151impl GenericPhy { 142impl<SM: StationManagement> GenericPhy<SM> {
152 /// Set the SMI polling interval. 143 /// Set the SMI polling interval.
153 #[cfg(feature = "time")] 144 #[cfg(feature = "time")]
154 pub fn set_poll_interval(&mut self, poll_interval: Duration) { 145 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
@@ -156,10 +147,15 @@ impl GenericPhy {
156 } 147 }
157 148
158 // Writes a value to an extended PHY register in MMD address space 149 // Writes a value to an extended PHY register in MMD address space
159 fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) { 150 fn smi_write_ext(&mut self, reg_addr: u16, reg_data: u16) {
160 sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address 151 self.sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
161 sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr); 152 self.sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
162 sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data 153 self.sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
163 sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data); 154 self.sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
155 }
156
157 /// Access the underlying station management.
158 pub fn station_management(&mut self) -> &mut SM {
159 &mut self.sm
164 } 160 }
165} 161}
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 10b3a0517..c8bce0e8a 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -5,6 +5,7 @@
5#[cfg_attr(eth_v2, path = "v2/mod.rs")] 5#[cfg_attr(eth_v2, path = "v2/mod.rs")]
6mod _version; 6mod _version;
7mod generic_phy; 7mod generic_phy;
8mod sma;
8 9
9use core::mem::MaybeUninit; 10use core::mem::MaybeUninit;
10use core::task::Context; 11use core::task::Context;
@@ -15,6 +16,7 @@ use embassy_sync::waitqueue::AtomicWaker;
15 16
16pub use self::_version::{InterruptHandler, *}; 17pub use self::_version::{InterruptHandler, *};
17pub use self::generic_phy::*; 18pub use self::generic_phy::*;
19pub use self::sma::{Sma, StationManagement};
18use crate::rcc::RccPeripheral; 20use crate::rcc::RccPeripheral;
19 21
20#[allow(unused)] 22#[allow(unused)]
@@ -109,7 +111,7 @@ impl<'d, T: Instance, P: Phy> embassy_net_driver::Driver for Ethernet<'d, T, P>
109 } 111 }
110 112
111 fn link_state(&mut self, cx: &mut Context) -> LinkState { 113 fn link_state(&mut self, cx: &mut Context) -> LinkState {
112 if self.phy.poll_link(&mut self.station_management, cx) { 114 if self.phy.poll_link(cx) {
113 LinkState::Up 115 LinkState::Up
114 } else { 116 } else {
115 LinkState::Down 117 LinkState::Down
@@ -157,32 +159,17 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
157 } 159 }
158} 160}
159 161
160/// Station Management Interface (SMI) on an ethernet PHY
161pub trait StationManagement {
162 /// Read a register over SMI.
163 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
164 /// Write a register over SMI.
165 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
166}
167
168/// Trait for an Ethernet PHY 162/// Trait for an Ethernet PHY
169pub trait Phy { 163pub trait Phy {
170 /// Reset PHY and wait for it to come out of reset. 164 /// Reset PHY and wait for it to come out of reset.
171 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S); 165 fn phy_reset(&mut self);
172 /// PHY initialisation. 166 /// PHY initialisation.
173 fn phy_init<S: StationManagement>(&mut self, sm: &mut S); 167 fn phy_init(&mut self);
174 /// Poll link to see if it is up and FD with 100Mbps 168 /// Poll link to see if it is up and FD with 100Mbps
175 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool; 169 fn poll_link(&mut self, cx: &mut Context) -> bool;
176} 170}
177 171
178impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 172impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
179 /// Directly expose the SMI interface used by the Ethernet driver.
180 ///
181 /// This can be used to for example configure special PHY registers for compliance testing.
182 pub fn station_management(&mut self) -> &mut impl StationManagement {
183 &mut self.station_management
184 }
185
186 /// Access the user-supplied `Phy`. 173 /// Access the user-supplied `Phy`.
187 pub fn phy(&self) -> &P { 174 pub fn phy(&self) -> &P {
188 &self.phy 175 &self.phy
@@ -212,8 +199,8 @@ impl Instance for crate::peripherals::ETH {}
212pin_trait!(RXClkPin, Instance, @A); 199pin_trait!(RXClkPin, Instance, @A);
213pin_trait!(TXClkPin, Instance, @A); 200pin_trait!(TXClkPin, Instance, @A);
214pin_trait!(RefClkPin, Instance, @A); 201pin_trait!(RefClkPin, Instance, @A);
215pin_trait!(MDIOPin, Instance, @A); 202pin_trait!(MDIOPin, sma::Instance, @A);
216pin_trait!(MDCPin, Instance, @A); 203pin_trait!(MDCPin, sma::Instance, @A);
217pin_trait!(RXDVPin, Instance, @A); 204pin_trait!(RXDVPin, Instance, @A);
218pin_trait!(CRSPin, Instance, @A); 205pin_trait!(CRSPin, Instance, @A);
219pin_trait!(RXD0Pin, Instance, @A); 206pin_trait!(RXD0Pin, Instance, @A);
diff --git a/embassy-stm32/src/eth/sma/mod.rs b/embassy-stm32/src/eth/sma/mod.rs
new file mode 100644
index 000000000..6c851911d
--- /dev/null
+++ b/embassy-stm32/src/eth/sma/mod.rs
@@ -0,0 +1,42 @@
1//! Station Management Agent (also known as MDIO or SMI).
2
3#![macro_use]
4
5#[cfg_attr(eth_v2, path = "v2.rs")]
6#[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1.rs")]
7mod _version;
8
9use embassy_hal_internal::PeripheralType;
10use stm32_metapac::common::{RW, Reg};
11
12pub use self::_version::*;
13
14/// Station Management Interface (SMI).
15pub trait StationManagement {
16 /// Read a register over SMI.
17 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
18 /// Write a register over SMI.
19 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
20}
21
22trait SealedInstance {
23 fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>);
24}
25
26/// MDIO instance.
27#[allow(private_bounds)]
28pub trait Instance: SealedInstance + PeripheralType + Send + 'static {}
29
30impl SealedInstance for crate::peripherals::ETH_SMA {
31 fn regs() -> (Reg<AddressRegister, RW>, Reg<DataRegister, RW>) {
32 let mac = crate::pac::ETH.ethernet_mac();
33
34 #[cfg(any(eth_v1a, eth_v1b, eth_v1c))]
35 return (mac.macmiiar(), mac.macmiidr());
36
37 #[cfg(eth_v2)]
38 return (mac.macmdioar(), mac.macmdiodr());
39 }
40}
41
42impl Instance for crate::peripherals::ETH_SMA {}
diff --git a/embassy-stm32/src/eth/sma/v1.rs b/embassy-stm32/src/eth/sma/v1.rs
new file mode 100644
index 000000000..db64a6c78
--- /dev/null
+++ b/embassy-stm32/src/eth/sma/v1.rs
@@ -0,0 +1,102 @@
1use embassy_hal_internal::Peri;
2pub(crate) use regs::{Macmiiar as AddressRegister, Macmiidr as DataRegister};
3use stm32_metapac::eth::regs;
4use stm32_metapac::eth::vals::{Cr, MbProgress, Mw};
5
6use super::{Instance, StationManagement};
7use crate::eth::{MDCPin, MDIOPin};
8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
9
10/// Station Management Agent.
11///
12/// This peripheral is used for SMI reads and writes to the connected
13/// ethernet PHY/device(s).
14pub struct Sma<'d, T: Instance> {
15 _peri: Peri<'d, T>,
16 clock_range: Cr,
17 pins: [Peri<'d, AnyPin>; 2],
18}
19
20impl<'d, T: Instance> Sma<'d, T> {
21 /// Create a new instance of this peripheral.
22 pub fn new<#[cfg(afio)] A>(
23 peri: Peri<'d, T>,
24 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
25 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
26 ) -> Self {
27 set_as_af!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh));
28 set_as_af!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh));
29
30 // Enable necessary clocks.
31 critical_section::with(|_| {
32 #[cfg(eth_v1a)]
33 let reg = crate::pac::RCC.ahbenr();
34
35 #[cfg(any(eth_v1b, eth_v1c))]
36 let reg = crate::pac::RCC.ahb1enr();
37
38 reg.modify(|w| {
39 w.set_ethen(true);
40 })
41 });
42
43 let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() };
44 let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not.");
45 let hclk_mhz = hclk.0 / 1_000_000;
46
47 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
48 let clock_range = match hclk_mhz {
49 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
50 25..=34 => Cr::CR_20_35, // Divide by 16
51 35..=59 => Cr::CR_35_60, // Divide by 26
52 60..=99 => Cr::CR_60_100, // Divide by 42
53 100..=149 => Cr::CR_100_150, // Divide by 62
54 150..=216 => Cr::CR_150_168, // Divide by 102
55 _ => {
56 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
57 }
58 };
59
60 Self {
61 _peri: peri,
62 clock_range,
63 pins: [mdio.into(), mdc.into()],
64 }
65 }
66}
67
68impl<T: Instance> StationManagement for Sma<'_, T> {
69 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
70 let (macmiiar, macmiidr) = T::regs();
71
72 macmiiar.modify(|w| {
73 w.set_pa(phy_addr);
74 w.set_mr(reg);
75 w.set_mw(Mw::READ); // read operation
76 w.set_cr(self.clock_range);
77 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
78 });
79 while macmiiar.read().mb() == MbProgress::BUSY {}
80 macmiidr.read().md()
81 }
82
83 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
84 let (macmiiar, macmiidr) = T::regs();
85
86 macmiidr.write(|w| w.set_md(val));
87 macmiiar.modify(|w| {
88 w.set_pa(phy_addr);
89 w.set_mr(reg);
90 w.set_mw(Mw::WRITE); // write
91 w.set_cr(self.clock_range);
92 w.set_mb(MbProgress::BUSY);
93 });
94 while macmiiar.read().mb() == MbProgress::BUSY {}
95 }
96}
97
98impl<T: Instance> Drop for Sma<'_, T> {
99 fn drop(&mut self) {
100 self.pins.iter_mut().for_each(|p| p.set_as_disconnected());
101 }
102}
diff --git a/embassy-stm32/src/eth/sma/v2.rs b/embassy-stm32/src/eth/sma/v2.rs
new file mode 100644
index 000000000..6bc5230b5
--- /dev/null
+++ b/embassy-stm32/src/eth/sma/v2.rs
@@ -0,0 +1,94 @@
1use embassy_hal_internal::Peri;
2pub(crate) use regs::{Macmdioar as AddressRegister, Macmdiodr as DataRegister};
3use stm32_metapac::eth::regs;
4
5use super::{Instance, StationManagement};
6use crate::eth::{MDCPin, MDIOPin};
7use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
8
9/// Station Management Agent.
10///
11/// This peripheral is used for SMI reads and writes to the connected
12/// ethernet PHY/device(s).
13pub struct Sma<'d, T: Instance> {
14 _peri: Peri<'d, T>,
15 pins: [Peri<'d, AnyPin>; 2],
16 clock_range: u8,
17}
18
19impl<'d, T: Instance> Sma<'d, T> {
20 /// Create a new instance of this peripheral.
21 pub fn new(peri: Peri<'d, T>, mdio: Peri<'d, impl MDIOPin<T>>, mdc: Peri<'d, impl MDCPin<T>>) -> Self {
22 set_as_af!(mdio, AfType::output(OutputType::PushPull, Speed::VeryHigh));
23 set_as_af!(mdc, AfType::output(OutputType::PushPull, Speed::VeryHigh));
24
25 // Enable necessary clocks.
26 critical_section::with(|_| {
27 crate::pac::RCC.ahb1enr().modify(|w| {
28 w.set_ethen(true);
29 })
30 });
31
32 let hclk = unsafe { crate::rcc::get_freqs().hclk1.to_hertz() };
33 let hclk = unwrap!(hclk, "SMA requires HCLK to be enabled, but it was not.");
34 let hclk_mhz = hclk.0 / 1_000_000;
35
36 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
37 let clock_range = match hclk_mhz {
38 0..=34 => 2, // Divide by 16
39 35..=59 => 3, // Divide by 26
40 60..=99 => 0, // Divide by 42
41 100..=149 => 1, // Divide by 62
42 150..=249 => 4, // Divide by 102
43 250..=310 => 5, // Divide by 124
44 _ => {
45 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
46 }
47 };
48
49 Self {
50 _peri: peri,
51 clock_range,
52 pins: [mdio.into(), mdc.into()],
53 }
54 }
55}
56
57impl<T: Instance> StationManagement for Sma<'_, T> {
58 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
59 let (macmdioar, macmdiodr) = T::regs();
60
61 macmdioar.modify(|w| {
62 w.set_pa(phy_addr);
63 w.set_rda(reg);
64 w.set_goc(0b11); // read
65 w.set_cr(self.clock_range);
66 w.set_mb(true);
67 });
68
69 while macmdioar.read().mb() {}
70
71 macmdiodr.read().md()
72 }
73
74 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
75 let (macmdioar, macmdiodr) = T::regs();
76
77 macmdiodr.write(|w| w.set_md(val));
78 macmdioar.modify(|w| {
79 w.set_pa(phy_addr);
80 w.set_rda(reg);
81 w.set_goc(0b01); // write
82 w.set_cr(self.clock_range);
83 w.set_mb(true);
84 });
85
86 while macmdioar.read().mb() {}
87 }
88}
89
90impl<T: Instance> Drop for Sma<'_, T> {
91 fn drop(&mut self) {
92 self.pins.iter_mut().for_each(|p| p.set_as_disconnected());
93 }
94}
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 5be1c9739..8de26ce9d 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -3,11 +3,10 @@
3mod rx_desc; 3mod rx_desc;
4mod tx_desc; 4mod tx_desc;
5 5
6use core::marker::PhantomData; 6use core::sync::atomic::{Ordering, fence};
7use core::sync::atomic::{fence, Ordering};
8 7
9use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
10use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; 9use stm32_metapac::eth::vals::{Apcs, Dm, DmaomrSr, Fes, Ftf, Ifg, Pbl, Rsf, St, Tsf};
11 10
12pub(crate) use self::rx_desc::{RDes, RDesRing}; 11pub(crate) use self::rx_desc::{RDes, RDesRing};
13pub(crate) use self::tx_desc::{TDes, TDesRing}; 12pub(crate) use self::tx_desc::{TDes, TDesRing};
@@ -22,7 +21,6 @@ use crate::pac::AFIO;
22#[cfg(any(eth_v1b, eth_v1c))] 21#[cfg(any(eth_v1b, eth_v1c))]
23use crate::pac::SYSCFG; 22use crate::pac::SYSCFG;
24use crate::pac::{ETH, RCC}; 23use crate::pac::{ETH, RCC};
25use crate::rcc::SealedRccPeripheral;
26 24
27/// Interrupt handler. 25/// Interrupt handler.
28pub struct InterruptHandler {} 26pub struct InterruptHandler {}
@@ -53,14 +51,13 @@ pub struct Ethernet<'d, T: Instance, P: Phy> {
53 51
54 pins: Pins<'d>, 52 pins: Pins<'d>,
55 pub(crate) phy: P, 53 pub(crate) phy: P,
56 pub(crate) station_management: EthernetStationManagement<T>,
57 pub(crate) mac_addr: [u8; 6], 54 pub(crate) mac_addr: [u8; 6],
58} 55}
59 56
60/// Pins of ethernet driver. 57/// Pins of ethernet driver.
61enum Pins<'d> { 58enum Pins<'d> {
62 Rmii([Peri<'d, AnyPin>; 9]), 59 Rmii([Peri<'d, AnyPin>; 7]),
63 Mii([Peri<'d, AnyPin>; 14]), 60 Mii([Peri<'d, AnyPin>; 12]),
64} 61}
65 62
66#[cfg(eth_v1a)] 63#[cfg(eth_v1a)]
@@ -97,68 +94,105 @@ macro_rules! config_pins {
97 }; 94 };
98} 95}
99 96
100impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 97impl<'d, T: Instance, SMA: sma::Instance> Ethernet<'d, T, GenericPhy<Sma<'d, SMA>>> {
98 /// Create a new RMII ethernet driver using 7 pins.
99 ///
100 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
101 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
102 ///
103 /// See [`Ethernet::new_with_phy`] for creating an RMII ethernet
104 /// river with a non-standard PHY.
105 ///
101 /// safety: the returned instance is not leak-safe 106 /// safety: the returned instance is not leak-safe
102 pub fn new<const TX: usize, const RX: usize, #[cfg(afio)] A>( 107 pub fn new<const TX: usize, const RX: usize, #[cfg(afio)] A>(
103 queue: &'d mut PacketQueue<TX, RX>, 108 queue: &'d mut PacketQueue<TX, RX>,
104 peri: Peri<'d, T>, 109 peri: Peri<'d, T>,
105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 110 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
106 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>, 111 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>,
107 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
108 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
109 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>, 112 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>,
110 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>, 113 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
111 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>, 114 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
112 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>, 115 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
113 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>, 116 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
114 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>, 117 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
115 phy: P,
116 mac_addr: [u8; 6], 118 mac_addr: [u8; 6],
119 sma: Peri<'d, SMA>,
120 mdio: Peri<'d, if_afio!(impl MDIOPin<SMA, A>)>,
121 mdc: Peri<'d, if_afio!(impl MDCPin<SMA, A>)>,
117 ) -> Self { 122 ) -> Self {
118 // Enable the necessary Clocks 123 let sma = Sma::new(sma, mdio, mdc);
119 #[cfg(eth_v1a)] 124 let phy = GenericPhy::new_auto(sma);
120 critical_section::with(|_| {
121 RCC.apb2enr().modify(|w| w.set_afioen(true));
122
123 // Select RMII (Reduced Media Independent Interface)
124 // Must be done prior to enabling peripheral clock
125 AFIO.mapr().modify(|w| {
126 w.set_mii_rmii_sel(true);
127 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
128 });
129 125
130 RCC.ahbenr().modify(|w| { 126 Self::new_with_phy(
131 w.set_ethen(true); 127 queue, peri, irq, ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en, mac_addr, phy,
132 w.set_ethtxen(true); 128 )
133 w.set_ethrxen(true); 129 }
134 });
135 });
136 130
137 #[cfg(any(eth_v1b, eth_v1c))] 131 /// Create a new MII ethernet driver using 14 pins.
138 critical_section::with(|_| { 132 ///
139 RCC.ahb1enr().modify(|w| { 133 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
140 w.set_ethen(true); 134 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
141 w.set_ethtxen(true); 135 ///
142 w.set_ethrxen(true); 136 /// See [`Ethernet::new_mii_with_phy`] for creating an RMII ethernet
143 }); 137 /// river with a non-standard PHY.
138 pub fn new_mii<const TX: usize, const RX: usize, #[cfg(afio)] A>(
139 queue: &'d mut PacketQueue<TX, RX>,
140 peri: Peri<'d, T>,
141 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
142 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>,
143 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>,
144 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>,
145 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
146 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
147 rx_d2: Peri<'d, if_afio!(impl RXD2Pin<T, A>)>,
148 rx_d3: Peri<'d, if_afio!(impl RXD3Pin<T, A>)>,
149 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
150 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
151 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>,
152 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>,
153 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
154 mac_addr: [u8; 6],
155 sma: Peri<'d, SMA>,
156 mdio: Peri<'d, if_afio!(impl MDIOPin<SMA, A>)>,
157 mdc: Peri<'d, if_afio!(impl MDCPin<SMA, A>)>,
158 ) -> Self {
159 let sma = Sma::new(sma, mdio, mdc);
160 let phy = GenericPhy::new_auto(sma);
144 161
145 // RMII (Reduced Media Independent Interface) 162 Self::new_mii_with_phy(
146 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); 163 queue, peri, irq, rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en,
147 }); 164 mac_addr, phy,
165 )
166 }
167}
148 168
169impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
170 /// safety: the returned instance is not leak-safe
171 pub fn new_with_phy<const TX: usize, const RX: usize, #[cfg(afio)] A>(
172 queue: &'d mut PacketQueue<TX, RX>,
173 peri: Peri<'d, T>,
174 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
175 ref_clk: Peri<'d, if_afio!(impl RefClkPin<T, A>)>,
176 crs: Peri<'d, if_afio!(impl CRSPin<T, A>)>,
177 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
178 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
179 tx_d0: Peri<'d, if_afio!(impl TXD0Pin<T, A>)>,
180 tx_d1: Peri<'d, if_afio!(impl TXD1Pin<T, A>)>,
181 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
182 mac_addr: [u8; 6],
183 phy: P,
184 ) -> Self {
149 #[cfg(eth_v1a)] 185 #[cfg(eth_v1a)]
150 { 186 {
151 config_in_pins!(ref_clk, rx_d0, rx_d1); 187 config_in_pins!(ref_clk, rx_d0, rx_d1);
152 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); 188 config_af_pins!(tx_d0, tx_d1, tx_en);
153 } 189 }
154 190
155 #[cfg(any(eth_v1b, eth_v1c))] 191 #[cfg(any(eth_v1b, eth_v1c))]
156 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 192 config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
157 193
158 let pins = Pins::Rmii([ 194 let pins = Pins::Rmii([
159 ref_clk.into(), 195 ref_clk.into(),
160 mdio.into(),
161 mdc.into(),
162 crs.into(), 196 crs.into(),
163 rx_d0.into(), 197 rx_d0.into(),
164 rx_d1.into(), 198 rx_d1.into(),
@@ -167,7 +201,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
167 tx_en.into(), 201 tx_en.into(),
168 ]); 202 ]);
169 203
170 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 204 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, true)
171 } 205 }
172 206
173 fn new_inner<const TX: usize, const RX: usize>( 207 fn new_inner<const TX: usize, const RX: usize>(
@@ -177,7 +211,39 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
177 pins: Pins<'d>, 211 pins: Pins<'d>,
178 phy: P, 212 phy: P,
179 mac_addr: [u8; 6], 213 mac_addr: [u8; 6],
214 rmii_mii_sel: bool,
180 ) -> Self { 215 ) -> Self {
216 // Enable the necessary Clocks
217 #[cfg(eth_v1a)]
218 critical_section::with(|_| {
219 RCC.apb2enr().modify(|w| w.set_afioen(true));
220
221 // Select (R)MII (Reduced Media Independent Interface)
222 // Must be done prior to enabling peripheral clock
223 AFIO.mapr().modify(|w| {
224 w.set_mii_rmii_sel(rmii_mii_sel);
225 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
226 });
227
228 RCC.ahbenr().modify(|w| {
229 w.set_ethen(true);
230 w.set_ethtxen(true);
231 w.set_ethrxen(true);
232 });
233 });
234
235 #[cfg(any(eth_v1b, eth_v1c))]
236 critical_section::with(|_| {
237 RCC.ahb1enr().modify(|w| {
238 w.set_ethen(true);
239 w.set_ethtxen(true);
240 w.set_ethrxen(true);
241 });
242
243 // (R)MII ((Reduced) Media Independent Interface)
244 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(rmii_mii_sel));
245 });
246
181 let dma = T::regs().ethernet_dma(); 247 let dma = T::regs().ethernet_dma();
182 let mac = T::regs().ethernet_mac(); 248 let mac = T::regs().ethernet_mac();
183 249
@@ -190,7 +256,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
190 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping 256 w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping
191 w.set_fes(Fes::FES100); // fast ethernet speed 257 w.set_fes(Fes::FES100); // fast ethernet speed
192 w.set_dm(Dm::FULL_DUPLEX); // full duplex 258 w.set_dm(Dm::FULL_DUPLEX); // full duplex
193 // TODO: Carrier sense ? ECRSFD 259 // TODO: Carrier sense ? ECRSFD
194 }); 260 });
195 261
196 // Set the mac to pass all multicast packets 262 // Set the mac to pass all multicast packets
@@ -226,30 +292,10 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
226 292
227 // TODO MTU size setting not found for v1 ethernet, check if correct 293 // TODO MTU size setting not found for v1 ethernet, check if correct
228 294
229 let hclk = <T as SealedRccPeripheral>::frequency();
230 let hclk_mhz = hclk.0 / 1_000_000;
231
232 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
233 let clock_range = match hclk_mhz {
234 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."),
235 25..=34 => Cr::CR_20_35, // Divide by 16
236 35..=59 => Cr::CR_35_60, // Divide by 26
237 60..=99 => Cr::CR_60_100, // Divide by 42
238 100..=149 => Cr::CR_100_150, // Divide by 62
239 150..=216 => Cr::CR_150_168, // Divide by 102
240 _ => {
241 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
242 }
243 };
244
245 let mut this = Self { 295 let mut this = Self {
246 _peri: peri, 296 _peri: peri,
247 pins, 297 pins,
248 phy: phy, 298 phy: phy,
249 station_management: EthernetStationManagement {
250 peri: PhantomData,
251 clock_range: clock_range,
252 },
253 mac_addr, 299 mac_addr,
254 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 300 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
255 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 301 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
@@ -279,8 +325,8 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
279 w.set_tie(true); 325 w.set_tie(true);
280 }); 326 });
281 327
282 this.phy.phy_reset(&mut this.station_management); 328 this.phy.phy_reset();
283 this.phy.phy_init(&mut this.station_management); 329 this.phy.phy_init();
284 330
285 interrupt::ETH.unpend(); 331 interrupt::ETH.unpend();
286 unsafe { interrupt::ETH.enable() }; 332 unsafe { interrupt::ETH.enable() };
@@ -288,15 +334,13 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
288 this 334 this
289 } 335 }
290 336
291 /// Create a new MII ethernet driver using 14 pins. 337 /// Create a new MII ethernet driver using 12 pins.
292 pub fn new_mii<const TX: usize, const RX: usize, #[cfg(afio)] A>( 338 pub fn new_mii_with_phy<const TX: usize, const RX: usize, #[cfg(afio)] A>(
293 queue: &'d mut PacketQueue<TX, RX>, 339 queue: &'d mut PacketQueue<TX, RX>,
294 peri: Peri<'d, T>, 340 peri: Peri<'d, T>,
295 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 341 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
296 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>, 342 rx_clk: Peri<'d, if_afio!(impl RXClkPin<T, A>)>,
297 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>, 343 tx_clk: Peri<'d, if_afio!(impl TXClkPin<T, A>)>,
298 mdio: Peri<'d, if_afio!(impl MDIOPin<T, A>)>,
299 mdc: Peri<'d, if_afio!(impl MDCPin<T, A>)>,
300 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>, 344 rxdv: Peri<'d, if_afio!(impl RXDVPin<T, A>)>,
301 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>, 345 rx_d0: Peri<'d, if_afio!(impl RXD0Pin<T, A>)>,
302 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>, 346 rx_d1: Peri<'d, if_afio!(impl RXD1Pin<T, A>)>,
@@ -307,56 +351,23 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
307 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>, 351 tx_d2: Peri<'d, if_afio!(impl TXD2Pin<T, A>)>,
308 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>, 352 tx_d3: Peri<'d, if_afio!(impl TXD3Pin<T, A>)>,
309 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>, 353 tx_en: Peri<'d, if_afio!(impl TXEnPin<T, A>)>,
310 phy: P,
311 mac_addr: [u8; 6], 354 mac_addr: [u8; 6],
355 phy: P,
312 ) -> Self { 356 ) -> Self {
313 // TODO: Handle optional signals like CRS, MII_COL, RX_ER?
314
315 // Enable the necessary Clocks
316 #[cfg(eth_v1a)]
317 critical_section::with(|_| {
318 RCC.apb2enr().modify(|w| w.set_afioen(true));
319
320 // Select MII (Media Independent Interface)
321 // Must be done prior to enabling peripheral clock
322 AFIO.mapr().modify(|w| {
323 w.set_mii_rmii_sel(false);
324 w.set_swj_cfg(crate::pac::afio::vals::SwjCfg::NO_OP);
325 });
326
327 RCC.ahbenr().modify(|w| {
328 w.set_ethen(true);
329 w.set_ethtxen(true);
330 w.set_ethrxen(true);
331 });
332 });
333
334 #[cfg(any(eth_v1b, eth_v1c))]
335 critical_section::with(|_| {
336 RCC.ahb1enr().modify(|w| {
337 w.set_ethen(true);
338 w.set_ethtxen(true);
339 w.set_ethrxen(true);
340 });
341
342 // MII (Media Independent Interface)
343 SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(false));
344 });
345
346 #[cfg(eth_v1a)] 357 #[cfg(eth_v1a)]
347 { 358 {
348 config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv); 359 config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv);
349 config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); 360 config_af_pins!(tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
350 } 361 }
351 362
352 #[cfg(any(eth_v1b, eth_v1c))] 363 #[cfg(any(eth_v1b, eth_v1c))]
353 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); 364 config_pins!(
365 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
366 );
354 367
355 let pins = Pins::Mii([ 368 let pins = Pins::Mii([
356 rx_clk.into(), 369 rx_clk.into(),
357 tx_clk.into(), 370 tx_clk.into(),
358 mdio.into(),
359 mdc.into(),
360 rxdv.into(), 371 rxdv.into(),
361 rx_d0.into(), 372 rx_d0.into(),
362 rx_d1.into(), 373 rx_d1.into(),
@@ -369,43 +380,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
369 tx_en.into(), 380 tx_en.into(),
370 ]); 381 ]);
371 382
372 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 383 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, false)
373 }
374}
375
376/// Ethernet station management interface.
377pub(crate) struct EthernetStationManagement<T: Instance> {
378 peri: PhantomData<T>,
379 clock_range: Cr,
380}
381
382impl<T: Instance> StationManagement for EthernetStationManagement<T> {
383 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
384 let mac = T::regs().ethernet_mac();
385
386 mac.macmiiar().modify(|w| {
387 w.set_pa(phy_addr);
388 w.set_mr(reg);
389 w.set_mw(Mw::READ); // read operation
390 w.set_cr(self.clock_range);
391 w.set_mb(MbProgress::BUSY); // indicate that operation is in progress
392 });
393 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
394 mac.macmiidr().read().md()
395 }
396
397 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
398 let mac = T::regs().ethernet_mac();
399
400 mac.macmiidr().write(|w| w.set_md(val));
401 mac.macmiiar().modify(|w| {
402 w.set_pa(phy_addr);
403 w.set_mr(reg);
404 w.set_mw(Mw::WRITE); // write
405 w.set_cr(self.clock_range);
406 w.set_mb(MbProgress::BUSY);
407 });
408 while mac.macmiiar().read().mb() == MbProgress::BUSY {}
409 } 384 }
410} 385}
411 386
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 2a46c1895..6ade1f29c 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{compiler_fence, fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence, fence};
2 2
3use stm32_metapac::eth::vals::{Rpd, Rps}; 3use stm32_metapac::eth::vals::{Rpd, Rps};
4use vcell::VolatileCell; 4use vcell::VolatileCell;
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs
index 1317d20f4..ba99b66cb 100644
--- a/embassy-stm32/src/eth/v1/tx_desc.rs
+++ b/embassy-stm32/src/eth/v1/tx_desc.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{compiler_fence, fence, Ordering}; 1use core::sync::atomic::{Ordering, compiler_fence, fence};
2 2
3use vcell::VolatileCell; 3use vcell::VolatileCell;
4 4
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index 645bfdb14..e335ed8f3 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -1,4 +1,4 @@
1use core::sync::atomic::{fence, Ordering}; 1use core::sync::atomic::{Ordering, fence};
2 2
3use vcell::VolatileCell; 3use vcell::VolatileCell;
4 4
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index cf7a9901b..7f92e351c 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,7 +1,6 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData; 3use core::sync::atomic::{Ordering, fence};
4use core::sync::atomic::{fence, Ordering};
5 4
6use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
7use stm32_metapac::syscfg::vals::EthSelPhy; 6use stm32_metapac::syscfg::vals::EthSelPhy;
@@ -12,7 +11,6 @@ use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed};
12use crate::interrupt; 11use crate::interrupt;
13use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
14use crate::pac::ETH; 13use crate::pac::ETH;
15use crate::rcc::SealedRccPeripheral;
16 14
17/// Interrupt handler. 15/// Interrupt handler.
18pub struct InterruptHandler {} 16pub struct InterruptHandler {}
@@ -42,14 +40,13 @@ pub struct Ethernet<'d, T: Instance, P: Phy> {
42 pub(crate) rx: RDesRing<'d>, 40 pub(crate) rx: RDesRing<'d>,
43 pins: Pins<'d>, 41 pins: Pins<'d>,
44 pub(crate) phy: P, 42 pub(crate) phy: P,
45 pub(crate) station_management: EthernetStationManagement<T>,
46 pub(crate) mac_addr: [u8; 6], 43 pub(crate) mac_addr: [u8; 6],
47} 44}
48 45
49/// Pins of ethernet driver. 46/// Pins of ethernet driver.
50enum Pins<'d> { 47enum Pins<'d> {
51 Rmii([Peri<'d, AnyPin>; 9]), 48 Rmii([Peri<'d, AnyPin>; 7]),
52 Mii([Peri<'d, AnyPin>; 14]), 49 Mii([Peri<'d, AnyPin>; 12]),
53} 50}
54 51
55macro_rules! config_pins { 52macro_rules! config_pins {
@@ -63,41 +60,96 @@ macro_rules! config_pins {
63 }; 60 };
64} 61}
65 62
66impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { 63impl<'d, T: Instance, SMA: sma::Instance> Ethernet<'d, T, GenericPhy<Sma<'d, SMA>>> {
67 /// Create a new RMII ethernet driver using 9 pins. 64 /// Create a new RMII ethernet driver using 7 pins.
65 ///
66 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
67 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
68 ///
69 /// See [`Ethernet::new_with_phy`] for creating an RMII ethernet
70 /// river with a non-standard PHY.
68 pub fn new<const TX: usize, const RX: usize>( 71 pub fn new<const TX: usize, const RX: usize>(
69 queue: &'d mut PacketQueue<TX, RX>, 72 queue: &'d mut PacketQueue<TX, RX>,
70 peri: Peri<'d, T>, 73 peri: Peri<'d, T>,
71 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 74 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
72 ref_clk: Peri<'d, impl RefClkPin<T>>, 75 ref_clk: Peri<'d, impl RefClkPin<T>>,
73 mdio: Peri<'d, impl MDIOPin<T>>,
74 mdc: Peri<'d, impl MDCPin<T>>,
75 crs: Peri<'d, impl CRSPin<T>>, 76 crs: Peri<'d, impl CRSPin<T>>,
76 rx_d0: Peri<'d, impl RXD0Pin<T>>, 77 rx_d0: Peri<'d, impl RXD0Pin<T>>,
77 rx_d1: Peri<'d, impl RXD1Pin<T>>, 78 rx_d1: Peri<'d, impl RXD1Pin<T>>,
78 tx_d0: Peri<'d, impl TXD0Pin<T>>, 79 tx_d0: Peri<'d, impl TXD0Pin<T>>,
79 tx_d1: Peri<'d, impl TXD1Pin<T>>, 80 tx_d1: Peri<'d, impl TXD1Pin<T>>,
80 tx_en: Peri<'d, impl TXEnPin<T>>, 81 tx_en: Peri<'d, impl TXEnPin<T>>,
81 phy: P,
82 mac_addr: [u8; 6], 82 mac_addr: [u8; 6],
83 sma: Peri<'d, SMA>,
84 mdio: Peri<'d, impl MDIOPin<SMA>>,
85 mdc: Peri<'d, impl MDCPin<SMA>>,
83 ) -> Self { 86 ) -> Self {
84 // Enable the necessary clocks 87 let sma = Sma::new(sma, mdio, mdc);
85 critical_section::with(|_| { 88 let phy = GenericPhy::new_auto(sma);
86 crate::pac::RCC.ahb1enr().modify(|w| {
87 w.set_ethen(true);
88 w.set_ethtxen(true);
89 w.set_ethrxen(true);
90 });
91 89
92 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); 90 Self::new_with_phy(
93 }); 91 queue, peri, irq, ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en, mac_addr, phy,
92 )
93 }
94
95 /// Create a new MII ethernet driver using 14 pins.
96 ///
97 /// This function uses a [`GenericPhy::new_auto`] as PHY, created using the
98 /// provided [`SMA`](sma::Instance), and MDIO and MDC pins.
99 ///
100 /// See [`Ethernet::new_mii_with_phy`] for creating an RMII ethernet
101 /// river with a non-standard PHY.
102 pub fn new_mii<const TX: usize, const RX: usize>(
103 queue: &'d mut PacketQueue<TX, RX>,
104 peri: Peri<'d, T>,
105 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
106 rx_clk: Peri<'d, impl RXClkPin<T>>,
107 tx_clk: Peri<'d, impl TXClkPin<T>>,
108 rxdv: Peri<'d, impl RXDVPin<T>>,
109 rx_d0: Peri<'d, impl RXD0Pin<T>>,
110 rx_d1: Peri<'d, impl RXD1Pin<T>>,
111 rx_d2: Peri<'d, impl RXD2Pin<T>>,
112 rx_d3: Peri<'d, impl RXD3Pin<T>>,
113 tx_d0: Peri<'d, impl TXD0Pin<T>>,
114 tx_d1: Peri<'d, impl TXD1Pin<T>>,
115 tx_d2: Peri<'d, impl TXD2Pin<T>>,
116 tx_d3: Peri<'d, impl TXD3Pin<T>>,
117 tx_en: Peri<'d, impl TXEnPin<T>>,
118 mac_addr: [u8; 6],
119 sma: Peri<'d, SMA>,
120 mdio: Peri<'d, impl MDIOPin<SMA>>,
121 mdc: Peri<'d, impl MDCPin<SMA>>,
122 ) -> Self {
123 let sma = Sma::new(sma, mdio, mdc);
124 let phy = GenericPhy::new_auto(sma);
125
126 Self::new_mii_with_phy(
127 queue, peri, irq, rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en,
128 mac_addr, phy,
129 )
130 }
131}
94 132
95 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 133impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
134 /// Create a new RMII ethernet driver using 7 pins.
135 pub fn new_with_phy<const TX: usize, const RX: usize>(
136 queue: &'d mut PacketQueue<TX, RX>,
137 peri: Peri<'d, T>,
138 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
139 ref_clk: Peri<'d, impl RefClkPin<T>>,
140 crs: Peri<'d, impl CRSPin<T>>,
141 rx_d0: Peri<'d, impl RXD0Pin<T>>,
142 rx_d1: Peri<'d, impl RXD1Pin<T>>,
143 tx_d0: Peri<'d, impl TXD0Pin<T>>,
144 tx_d1: Peri<'d, impl TXD1Pin<T>>,
145 tx_en: Peri<'d, impl TXEnPin<T>>,
146 mac_addr: [u8; 6],
147 phy: P,
148 ) -> Self {
149 config_pins!(ref_clk, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
96 150
97 let pins = Pins::Rmii([ 151 let pins = Pins::Rmii([
98 ref_clk.into(), 152 ref_clk.into(),
99 mdio.into(),
100 mdc.into(),
101 crs.into(), 153 crs.into(),
102 rx_d0.into(), 154 rx_d0.into(),
103 rx_d1.into(), 155 rx_d1.into(),
@@ -106,18 +158,16 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
106 tx_en.into(), 158 tx_en.into(),
107 ]); 159 ]);
108 160
109 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 161 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::RMII)
110 } 162 }
111 163
112 /// Create a new MII ethernet driver using 14 pins. 164 /// Create a new MII ethernet driver using 12 pins.
113 pub fn new_mii<const TX: usize, const RX: usize>( 165 pub fn new_mii_with_phy<const TX: usize, const RX: usize>(
114 queue: &'d mut PacketQueue<TX, RX>, 166 queue: &'d mut PacketQueue<TX, RX>,
115 peri: Peri<'d, T>, 167 peri: Peri<'d, T>,
116 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd, 168 irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
117 rx_clk: Peri<'d, impl RXClkPin<T>>, 169 rx_clk: Peri<'d, impl RXClkPin<T>>,
118 tx_clk: Peri<'d, impl TXClkPin<T>>, 170 tx_clk: Peri<'d, impl TXClkPin<T>>,
119 mdio: Peri<'d, impl MDIOPin<T>>,
120 mdc: Peri<'d, impl MDCPin<T>>,
121 rxdv: Peri<'d, impl RXDVPin<T>>, 171 rxdv: Peri<'d, impl RXDVPin<T>>,
122 rx_d0: Peri<'d, impl RXD0Pin<T>>, 172 rx_d0: Peri<'d, impl RXD0Pin<T>>,
123 rx_d1: Peri<'d, impl RXD1Pin<T>>, 173 rx_d1: Peri<'d, impl RXD1Pin<T>>,
@@ -128,29 +178,16 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
128 tx_d2: Peri<'d, impl TXD2Pin<T>>, 178 tx_d2: Peri<'d, impl TXD2Pin<T>>,
129 tx_d3: Peri<'d, impl TXD3Pin<T>>, 179 tx_d3: Peri<'d, impl TXD3Pin<T>>,
130 tx_en: Peri<'d, impl TXEnPin<T>>, 180 tx_en: Peri<'d, impl TXEnPin<T>>,
131 phy: P,
132 mac_addr: [u8; 6], 181 mac_addr: [u8; 6],
182 phy: P,
133 ) -> Self { 183 ) -> Self {
134 // Enable the necessary clocks 184 config_pins!(
135 critical_section::with(|_| { 185 rx_clk, tx_clk, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en
136 crate::pac::RCC.ahb1enr().modify(|w| { 186 );
137 w.set_ethen(true);
138 w.set_ethtxen(true);
139 w.set_ethrxen(true);
140 });
141
142 crate::pac::SYSCFG
143 .pmcr()
144 .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII));
145 });
146
147 config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
148 187
149 let pins = Pins::Mii([ 188 let pins = Pins::Mii([
150 rx_clk.into(), 189 rx_clk.into(),
151 tx_clk.into(), 190 tx_clk.into(),
152 mdio.into(),
153 mdc.into(),
154 rxdv.into(), 191 rxdv.into(),
155 rx_d0.into(), 192 rx_d0.into(),
156 rx_d1.into(), 193 rx_d1.into(),
@@ -163,7 +200,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
163 tx_en.into(), 200 tx_en.into(),
164 ]); 201 ]);
165 202
166 Self::new_inner(queue, peri, irq, pins, phy, mac_addr) 203 Self::new_inner(queue, peri, irq, pins, phy, mac_addr, EthSelPhy::MII_GMII)
167 } 204 }
168 205
169 fn new_inner<const TX: usize, const RX: usize>( 206 fn new_inner<const TX: usize, const RX: usize>(
@@ -173,7 +210,19 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
173 pins: Pins<'d>, 210 pins: Pins<'d>,
174 phy: P, 211 phy: P,
175 mac_addr: [u8; 6], 212 mac_addr: [u8; 6],
213 eth_sel_phy: EthSelPhy,
176 ) -> Self { 214 ) -> Self {
215 // Enable the necessary clocks
216 critical_section::with(|_| {
217 crate::pac::RCC.ahb1enr().modify(|w| {
218 w.set_ethen(true);
219 w.set_ethtxen(true);
220 w.set_ethrxen(true);
221 });
222
223 crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(eth_sel_phy));
224 });
225
177 let dma = T::regs().ethernet_dma(); 226 let dma = T::regs().ethernet_dma();
178 let mac = T::regs().ethernet_mac(); 227 let mac = T::regs().ethernet_mac();
179 let mtl = T::regs().ethernet_mtl(); 228 let mtl = T::regs().ethernet_mtl();
@@ -235,32 +284,12 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
235 w.set_rbsz(RX_BUFFER_SIZE as u16); 284 w.set_rbsz(RX_BUFFER_SIZE as u16);
236 }); 285 });
237 286
238 let hclk = <T as SealedRccPeripheral>::frequency();
239 let hclk_mhz = hclk.0 / 1_000_000;
240
241 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
242 let clock_range = match hclk_mhz {
243 0..=34 => 2, // Divide by 16
244 35..=59 => 3, // Divide by 26
245 60..=99 => 0, // Divide by 42
246 100..=149 => 1, // Divide by 62
247 150..=249 => 4, // Divide by 102
248 250..=310 => 5, // Divide by 124
249 _ => {
250 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
251 }
252 };
253
254 let mut this = Self { 287 let mut this = Self {
255 _peri: peri, 288 _peri: peri,
256 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 289 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
257 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 290 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
258 pins, 291 pins,
259 phy, 292 phy,
260 station_management: EthernetStationManagement {
261 peri: PhantomData,
262 clock_range: clock_range,
263 },
264 mac_addr, 293 mac_addr,
265 }; 294 };
266 295
@@ -286,8 +315,8 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
286 w.set_tie(true); 315 w.set_tie(true);
287 }); 316 });
288 317
289 this.phy.phy_reset(&mut this.station_management); 318 this.phy.phy_reset();
290 this.phy.phy_init(&mut this.station_management); 319 this.phy.phy_init();
291 320
292 interrupt::ETH.unpend(); 321 interrupt::ETH.unpend();
293 unsafe { interrupt::ETH.enable() }; 322 unsafe { interrupt::ETH.enable() };
@@ -296,42 +325,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> {
296 } 325 }
297} 326}
298 327
299/// Ethernet SMI driver.
300pub struct EthernetStationManagement<T: Instance> {
301 peri: PhantomData<T>,
302 clock_range: u8,
303}
304
305impl<T: Instance> StationManagement for EthernetStationManagement<T> {
306 fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
307 let mac = T::regs().ethernet_mac();
308
309 mac.macmdioar().modify(|w| {
310 w.set_pa(phy_addr);
311 w.set_rda(reg);
312 w.set_goc(0b11); // read
313 w.set_cr(self.clock_range);
314 w.set_mb(true);
315 });
316 while mac.macmdioar().read().mb() {}
317 mac.macmdiodr().read().md()
318 }
319
320 fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
321 let mac = T::regs().ethernet_mac();
322
323 mac.macmdiodr().write(|w| w.set_md(val));
324 mac.macmdioar().modify(|w| {
325 w.set_pa(phy_addr);
326 w.set_rda(reg);
327 w.set_goc(0b01); // write
328 w.set_cr(self.clock_range);
329 w.set_mb(true);
330 });
331 while mac.macmdioar().read().mb() {}
332 }
333}
334
335impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { 328impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {
336 fn drop(&mut self) { 329 fn drop(&mut self) {
337 let dma = T::regs().ethernet_dma(); 330 let dma = T::regs().ethernet_dma();
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 9fce78f95..7b7896d46 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -5,13 +5,16 @@ use core::marker::PhantomData;
5use core::pin::Pin; 5use core::pin::Pin;
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{impl_peripheral, PeripheralType}; 8use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use futures_util::FutureExt;
10 11
11use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; 12use crate::gpio::{AnyPin, ExtiPin, Input, Level, Pin as GpioPin, PinNumber, Pull};
12use crate::pac::exti::regs::Lines; 13use crate::interrupt::Interrupt as InterruptEnum;
14use crate::interrupt::typelevel::{Binding, Handler, Interrupt as InterruptType};
13use crate::pac::EXTI; 15use crate::pac::EXTI;
14use crate::{interrupt, pac, peripherals, Peri}; 16use crate::pac::exti::regs::Lines;
17use crate::{Peri, pac};
15 18
16const EXTI_COUNT: usize = 16; 19const EXTI_COUNT: usize = 16;
17static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; 20static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT];
@@ -31,11 +34,11 @@ fn cpu_regs() -> pac::exti::Exti {
31 EXTI 34 EXTI
32} 35}
33 36
34#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] 37#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50, exti_n6)))]
35fn exticr_regs() -> pac::syscfg::Syscfg { 38fn exticr_regs() -> pac::syscfg::Syscfg {
36 pac::SYSCFG 39 pac::SYSCFG
37} 40}
38#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 41#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
39fn exticr_regs() -> pac::exti::Exti { 42fn exticr_regs() -> pac::exti::Exti {
40 EXTI 43 EXTI
41} 44}
@@ -45,9 +48,9 @@ fn exticr_regs() -> pac::afio::Afio {
45} 48}
46 49
47unsafe fn on_irq() { 50unsafe fn on_irq() {
48 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 51 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
49 let bits = EXTI.pr(0).read().0; 52 let bits = EXTI.pr(0).read().0;
50 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 53 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
51 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; 54 let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
52 55
53 // We don't handle or change any EXTI lines above 16. 56 // We don't handle or change any EXTI lines above 16.
@@ -62,16 +65,16 @@ unsafe fn on_irq() {
62 } 65 }
63 66
64 // Clear pending 67 // Clear pending
65 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 68 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
66 EXTI.pr(0).write_value(Lines(bits)); 69 EXTI.pr(0).write_value(Lines(bits));
67 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 70 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
68 { 71 {
69 EXTI.rpr(0).write_value(Lines(bits)); 72 EXTI.rpr(0).write_value(Lines(bits));
70 EXTI.fpr(0).write_value(Lines(bits)); 73 EXTI.fpr(0).write_value(Lines(bits));
71 } 74 }
72 75
73 #[cfg(feature = "low-power")] 76 #[cfg(feature = "low-power")]
74 crate::low_power::on_wakeup_irq(); 77 crate::low_power::Executor::on_wakeup_irq();
75} 78}
76 79
77struct BitIter(u32); 80struct BitIter(u32);
@@ -105,10 +108,17 @@ impl<'d> Unpin for ExtiInput<'d> {}
105 108
106impl<'d> ExtiInput<'d> { 109impl<'d> ExtiInput<'d> {
107 /// Create an EXTI input. 110 /// Create an EXTI input.
108 pub fn new<T: GpioPin>(pin: Peri<'d, T>, ch: Peri<'d, T::ExtiChannel>, pull: Pull) -> Self { 111 ///
109 // Needed if using AnyPin+AnyChannel. 112 /// The Binding must bind the Channel's IRQ to [InterruptHandler].
110 assert_eq!(pin.pin(), ch.number()); 113 pub fn new<T: ExtiPin + GpioPin>(
111 114 pin: Peri<'d, T>,
115 _ch: Peri<'d, T::ExtiChannel>,
116 pull: Pull,
117 _irq: impl Binding<
118 <<T as ExtiPin>::ExtiChannel as Channel>::IRQ,
119 InterruptHandler<<<T as ExtiPin>::ExtiChannel as Channel>::IRQ>,
120 >,
121 ) -> Self {
112 Self { 122 Self {
113 pin: Input::new(pin, pull), 123 pin: Input::new(pin, pull),
114 } 124 }
@@ -133,7 +143,7 @@ impl<'d> ExtiInput<'d> {
133 /// 143 ///
134 /// This returns immediately if the pin is already high. 144 /// This returns immediately if the pin is already high.
135 pub async fn wait_for_high(&mut self) { 145 pub async fn wait_for_high(&mut self) {
136 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false); 146 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, true);
137 if self.is_high() { 147 if self.is_high() {
138 return; 148 return;
139 } 149 }
@@ -144,7 +154,7 @@ impl<'d> ExtiInput<'d> {
144 /// 154 ///
145 /// This returns immediately if the pin is already low. 155 /// This returns immediately if the pin is already low.
146 pub async fn wait_for_low(&mut self) { 156 pub async fn wait_for_low(&mut self) {
147 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true); 157 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, true);
148 if self.is_low() { 158 if self.is_low() {
149 return; 159 return;
150 } 160 }
@@ -155,19 +165,40 @@ impl<'d> ExtiInput<'d> {
155 /// 165 ///
156 /// If the pin is already high, it will wait for it to go low then back high. 166 /// If the pin is already high, it will wait for it to go low then back high.
157 pub async fn wait_for_rising_edge(&mut self) { 167 pub async fn wait_for_rising_edge(&mut self) {
158 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await 168 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, true).await
169 }
170
171 /// Asynchronously wait until the pin sees a rising edge.
172 ///
173 /// If the pin is already high, it will wait for it to go low then back high.
174 pub fn poll_for_rising_edge<'a>(&mut self, cx: &mut Context<'a>) {
175 let _ =
176 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false, false).poll_unpin(cx);
159 } 177 }
160 178
161 /// Asynchronously wait until the pin sees a falling edge. 179 /// Asynchronously wait until the pin sees a falling edge.
162 /// 180 ///
163 /// If the pin is already low, it will wait for it to go high then back low. 181 /// If the pin is already low, it will wait for it to go high then back low.
164 pub async fn wait_for_falling_edge(&mut self) { 182 pub async fn wait_for_falling_edge(&mut self) {
165 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await 183 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, true).await
184 }
185
186 /// Asynchronously wait until the pin sees a falling edge.
187 ///
188 /// If the pin is already low, it will wait for it to go high then back low.
189 pub fn poll_for_falling_edge<'a>(&mut self, cx: &mut Context<'a>) {
190 let _ =
191 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true, false).poll_unpin(cx);
166 } 192 }
167 193
168 /// Asynchronously wait until the pin sees any edge (either rising or falling). 194 /// Asynchronously wait until the pin sees any edge (either rising or falling).
169 pub async fn wait_for_any_edge(&mut self) { 195 pub async fn wait_for_any_edge(&mut self) {
170 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await 196 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true, true).await
197 }
198
199 /// Asynchronously wait until the pin sees any edge (either rising or falling).
200 pub fn poll_for_any_edge<'a>(&mut self, cx: &mut Context<'a>) {
201 let _ = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true, false).poll_unpin(cx);
171 } 202 }
172} 203}
173 204
@@ -226,12 +257,13 @@ impl<'d> embedded_hal_async::digital::Wait for ExtiInput<'d> {
226 257
227#[must_use = "futures do nothing unless you `.await` or poll them"] 258#[must_use = "futures do nothing unless you `.await` or poll them"]
228struct ExtiInputFuture<'a> { 259struct ExtiInputFuture<'a> {
229 pin: u8, 260 pin: PinNumber,
261 drop: bool,
230 phantom: PhantomData<&'a mut AnyPin>, 262 phantom: PhantomData<&'a mut AnyPin>,
231} 263}
232 264
233impl<'a> ExtiInputFuture<'a> { 265impl<'a> ExtiInputFuture<'a> {
234 fn new(pin: u8, port: u8, rising: bool, falling: bool) -> Self { 266 fn new(pin: PinNumber, port: PinNumber, rising: bool, falling: bool, drop: bool) -> Self {
235 critical_section::with(|_| { 267 critical_section::with(|_| {
236 let pin = pin as usize; 268 let pin = pin as usize;
237 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port)); 269 exticr_regs().exticr(pin / 4).modify(|w| w.set_exti(pin % 4, port));
@@ -239,9 +271,9 @@ impl<'a> ExtiInputFuture<'a> {
239 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); 271 EXTI.ftsr(0).modify(|w| w.set_line(pin, falling));
240 272
241 // clear pending bit 273 // clear pending bit
242 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] 274 #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
243 EXTI.pr(0).write(|w| w.set_line(pin, true)); 275 EXTI.pr(0).write(|w| w.set_line(pin, true));
244 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] 276 #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
245 { 277 {
246 EXTI.rpr(0).write(|w| w.set_line(pin, true)); 278 EXTI.rpr(0).write(|w| w.set_line(pin, true));
247 EXTI.fpr(0).write(|w| w.set_line(pin, true)); 279 EXTI.fpr(0).write(|w| w.set_line(pin, true));
@@ -252,6 +284,7 @@ impl<'a> ExtiInputFuture<'a> {
252 284
253 Self { 285 Self {
254 pin, 286 pin,
287 drop,
255 phantom: PhantomData, 288 phantom: PhantomData,
256 } 289 }
257 } 290 }
@@ -259,10 +292,12 @@ impl<'a> ExtiInputFuture<'a> {
259 292
260impl<'a> Drop for ExtiInputFuture<'a> { 293impl<'a> Drop for ExtiInputFuture<'a> {
261 fn drop(&mut self) { 294 fn drop(&mut self) {
262 critical_section::with(|_| { 295 if self.drop {
263 let pin = self.pin as _; 296 critical_section::with(|_| {
264 cpu_regs().imr(0).modify(|w| w.set_line(pin, false)); 297 let pin = self.pin as _;
265 }); 298 cpu_regs().imr(0).modify(|w| w.set_line(pin, false));
299 });
300 }
266 } 301 }
267} 302}
268 303
@@ -302,7 +337,7 @@ macro_rules! foreach_exti_irq {
302 (EXTI15) => { $action!(EXTI15); }; 337 (EXTI15) => { $action!(EXTI15); };
303 338
304 // plus the weird ones 339 // plus the weird ones
305 (EXTI0_1) => { $action!( EXTI0_1 ); }; 340 (EXTI0_1) => { $action!(EXTI0_1); };
306 (EXTI15_10) => { $action!(EXTI15_10); }; 341 (EXTI15_10) => { $action!(EXTI15_10); };
307 (EXTI15_4) => { $action!(EXTI15_4); }; 342 (EXTI15_4) => { $action!(EXTI15_4); };
308 (EXTI1_0) => { $action!(EXTI1_0); }; 343 (EXTI1_0) => { $action!(EXTI1_0); };
@@ -315,57 +350,67 @@ macro_rules! foreach_exti_irq {
315 }; 350 };
316} 351}
317 352
318macro_rules! impl_irq { 353///EXTI interrupt handler. All EXTI interrupt vectors should be bound to this handler.
319 ($e:ident) => { 354///
320 #[allow(non_snake_case)] 355/// It is generic over the [Interrupt](InterruptType) rather
321 #[cfg(feature = "rt")] 356/// than the [Channel] because it should not be bound multiple
322 #[interrupt] 357/// times to the same vector on chips which multiplex multiple EXTI interrupts into one vector.
323 unsafe fn $e() { 358//
324 on_irq() 359// It technically doesn't need to be generic at all, except to satisfy the generic argument
325 } 360// of [Handler]. All EXTI interrupts eventually land in the same on_irq() function.
326 }; 361pub struct InterruptHandler<T: crate::interrupt::typelevel::Interrupt> {
362 _phantom: PhantomData<T>,
327} 363}
328 364
329foreach_exti_irq!(impl_irq); 365impl<T: InterruptType> Handler<T> for InterruptHandler<T> {
366 unsafe fn on_interrupt() {
367 on_irq()
368 }
369}
330 370
331trait SealedChannel {} 371trait SealedChannel {}
332 372
333/// EXTI channel trait. 373/// EXTI channel trait.
334#[allow(private_bounds)] 374#[allow(private_bounds)]
335pub trait Channel: PeripheralType + SealedChannel + Sized { 375pub trait Channel: PeripheralType + SealedChannel + Sized {
336 /// Get the EXTI channel number. 376 /// EXTI channel number.
337 fn number(&self) -> u8; 377 fn number(&self) -> PinNumber;
378 /// [Enum-level Interrupt](InterruptEnum), which may be the same for multiple channels.
379 fn irq(&self) -> InterruptEnum;
380 /// [Type-level Interrupt](InterruptType), which may be the same for multiple channels.
381 type IRQ: InterruptType;
338} 382}
339 383
340/// Type-erased EXTI channel. 384//Doc isn't hidden in order to surface the explanation to users, even though it's completely inoperable, not just deprecated.
385//Entire type along with doc can probably be removed after deprecation has appeared in a release once.
386/// Deprecated type-erased EXTI channel.
341/// 387///
342/// This represents ownership over any EXTI channel, known at runtime. 388/// Support for AnyChannel was removed in order to support manually bindable EXTI interrupts via bind_interrupts; [ExtiInput::new()]
389/// must know the required IRQ at compile time, and therefore cannot support type-erased channels.
390#[deprecated = "type-erased EXTI channels are no longer supported, in order to support manually bindable EXTI interrupts (more info: https://github.com/embassy-rs/embassy/pull/4922)"]
343pub struct AnyChannel { 391pub struct AnyChannel {
344 number: u8, 392 #[allow(unused)]
345} 393 number: PinNumber,
346
347impl_peripheral!(AnyChannel);
348impl SealedChannel for AnyChannel {}
349impl Channel for AnyChannel {
350 fn number(&self) -> u8 {
351 self.number
352 }
353} 394}
354 395
355macro_rules! impl_exti { 396macro_rules! impl_exti {
356 ($type:ident, $number:expr) => { 397 ($type:ident, $number:expr) => {
357 impl SealedChannel for peripherals::$type {} 398 impl SealedChannel for crate::peripherals::$type {}
358 impl Channel for peripherals::$type { 399 impl Channel for crate::peripherals::$type {
359 fn number(&self) -> u8 { 400 fn number(&self) -> PinNumber {
360 $number 401 $number
361 } 402 }
403 fn irq(&self) -> InterruptEnum {
404 crate::_generated::peripheral_interrupts::EXTI::$type::IRQ
405 }
406 type IRQ = crate::_generated::peripheral_interrupts::EXTI::$type;
362 } 407 }
363 408
364 impl From<peripherals::$type> for AnyChannel { 409 //Still here to surface deprecation messages to the user - remove when removing AnyChannel
365 fn from(val: peripherals::$type) -> Self { 410 #[allow(deprecated)]
366 Self { 411 impl From<crate::peripherals::$type> for AnyChannel {
367 number: val.number() as u8, 412 fn from(_val: crate::peripherals::$type) -> Self {
368 } 413 Self { number: $number }
369 } 414 }
370 } 415 }
371 }; 416 };
diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs
index 006dcddeb..a131217b7 100644
--- a/embassy-stm32/src/flash/asynch.rs
+++ b/embassy-stm32/src/flash/asynch.rs
@@ -1,17 +1,17 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::mutex::Mutex; 6use embassy_sync::mutex::Mutex;
7 7
8use super::{ 8use super::{
9 blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout, 9 Async, Error, FLASH_BASE, FLASH_SIZE, Flash, FlashLayout, WRITE_SIZE, blocking_read, ensure_sector_aligned, family,
10 FLASH_BASE, FLASH_SIZE, WRITE_SIZE, 10 get_flash_regions, get_sector,
11}; 11};
12use crate::interrupt::InterruptExt; 12use crate::interrupt::InterruptExt;
13use crate::peripherals::FLASH; 13use crate::peripherals::FLASH;
14use crate::{interrupt, Peri}; 14use crate::{Peri, interrupt};
15 15
16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(()); 16pub(super) static REGION_ACCESS: Mutex<CriticalSectionRawMutex, ()> = Mutex::new(());
17 17
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 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{Ordering, fence};
3
4use cortex_m::interrupt;
5
6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10pub(crate) unsafe fn lock() {
11 pac::FLASH.cr().modify(|w| w.set_lock(true));
12}
13pub(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
24pub(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
29pub(crate) unsafe fn disable_blocking_write() {
30 pac::FLASH.cr().write(|w| w.set_pg(false));
31}
32
33pub(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
46pub(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
103pub(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
123pub(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
129fn 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 10023e637..60d00e766 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -1,14 +1,14 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use embassy_hal_internal::drop::OnDrop; 4use embassy_hal_internal::drop::OnDrop;
5 5
6use super::{ 6use super::{
7 family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, 7 Async, Blocking, Error, FLASH_SIZE, FlashBank, FlashLayout, FlashRegion, FlashSector, MAX_ERASE_SIZE, READ_SIZE,
8 MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, 8 WRITE_SIZE, family, get_flash_regions,
9}; 9};
10use crate::Peri;
11use crate::_generated::FLASH_BASE; 10use crate::_generated::FLASH_BASE;
11use crate::Peri;
12use crate::peripherals::FLASH; 12use crate::peripherals::FLASH;
13 13
14/// Internal flash memory driver. 14/// Internal flash memory driver.
@@ -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/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs
index cc3529eb9..39c497e3f 100644
--- a/embassy-stm32/src/flash/eeprom.rs
+++ b/embassy-stm32/src/flash/eeprom.rs
@@ -1,6 +1,6 @@
1use embassy_hal_internal::drop::OnDrop; 1use embassy_hal_internal::drop::OnDrop;
2 2
3use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; 3use super::{Blocking, EEPROM_BASE, EEPROM_SIZE, Error, Flash, family};
4 4
5#[cfg(eeprom)] 5#[cfg(eeprom)]
6impl<'d> Flash<'d, Blocking> { 6impl<'d> Flash<'d, Blocking> {
diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs
index 3f9dbe945..5c01fce9c 100644
--- a/embassy-stm32/src/flash/f0.rs
+++ b/embassy-stm32/src/flash/f0.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs
index bf9ad2893..9e469ffbc 100644
--- a/embassy-stm32/src/flash/f1f3.rs
+++ b/embassy-stm32/src/flash/f1f3.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs
index 67e380619..b48ab3b76 100644
--- a/embassy-stm32/src/flash/f2.rs
+++ b/embassy-stm32/src/flash/f2.rs
@@ -1,9 +1,9 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering, fence};
3 3
4use pac::flash::regs::Sr; 4use pac::flash::regs::Sr;
5 5
6use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; 6use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions};
7use crate::flash::Error; 7use crate::flash::Error;
8use crate::pac; 8use crate::pac;
9 9
diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs
index 62e0492b5..9c5051492 100644
--- a/embassy-stm32/src/flash/f4.rs
+++ b/embassy-stm32/src/flash/f4.rs
@@ -1,10 +1,10 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering}; 2use core::sync::atomic::{AtomicBool, Ordering, fence};
3 3
4use embassy_sync::waitqueue::AtomicWaker; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr; 5use pac::flash::regs::Sr;
6 6
7use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; 7use super::{FlashBank, FlashSector, WRITE_SIZE, get_flash_regions};
8use crate::_generated::FLASH_SIZE; 8use crate::_generated::FLASH_SIZE;
9use crate::flash::Error; 9use crate::flash::Error;
10use crate::pac; 10use crate::pac;
@@ -246,7 +246,9 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
246 feature = "stm32f439zi", 246 feature = "stm32f439zi",
247 ))] 247 ))]
248 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { 248 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
249 panic!("Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"); 249 panic!(
250 "Read corruption for stm32f42xxI and stm32f43xxI when PA12 is in use for chips below revision 3, see errata 2.2.11"
251 );
250 } 252 }
251 253
252 #[cfg(any( 254 #[cfg(any(
@@ -270,14 +272,16 @@ pub(crate) fn assert_not_corrupted_read(end_address: u32) {
270 feature = "stm32f439zg", 272 feature = "stm32f439zg",
271 ))] 273 ))]
272 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() { 274 if second_bank_read && pac::DBGMCU.idcode().read().rev_id() < REVISION_3 && !pa12_is_output_pull_low() {
273 panic!("Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"); 275 panic!(
276 "Read corruption for stm32f42xxG and stm32f43xxG in dual bank mode when PA12 is in use for chips below revision 3, see errata 2.2.11"
277 );
274 } 278 }
275} 279}
276 280
277#[allow(unused)] 281#[allow(unused)]
278fn pa12_is_output_pull_low() -> bool { 282fn pa12_is_output_pull_low() -> bool {
279 use pac::gpio::vals;
280 use pac::GPIOA; 283 use pac::GPIOA;
284 use pac::gpio::vals;
281 const PIN: usize = 12; 285 const PIN: usize = 12;
282 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT 286 GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT
283 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN 287 && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN
@@ -287,7 +291,7 @@ fn pa12_is_output_pull_low() -> bool {
287#[cfg(test)] 291#[cfg(test)]
288mod tests { 292mod tests {
289 use super::*; 293 use super::*;
290 use crate::flash::{get_sector, FlashBank}; 294 use crate::flash::{FlashBank, get_sector};
291 295
292 #[test] 296 #[test]
293 #[cfg(stm32f429)] 297 #[cfg(stm32f429)]
@@ -370,9 +374,13 @@ mod tests {
370#[cfg(all(bank_setup_configurable))] 374#[cfg(all(bank_setup_configurable))]
371pub(crate) fn check_bank_setup() { 375pub(crate) fn check_bank_setup() {
372 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() { 376 if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() {
373 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"); 377 panic!(
378 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"
379 );
374 } 380 }
375 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() { 381 if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() {
376 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"); 382 panic!(
383 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"
384 );
377 } 385 }
378} 386}
diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs
index 0547c747a..09389c417 100644
--- a/embassy-stm32/src/flash/f7.rs
+++ b/embassy-stm32/src/flash/f7.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
@@ -99,7 +99,7 @@ unsafe fn blocking_wait_ready() -> Result<(), Error> {
99#[cfg(test)] 99#[cfg(test)]
100mod tests { 100mod tests {
101 use super::*; 101 use super::*;
102 use crate::flash::{get_sector, FlashBank}; 102 use crate::flash::{FlashBank, get_sector};
103 103
104 #[test] 104 #[test]
105 #[cfg(stm32f732)] 105 #[cfg(stm32f732)]
@@ -218,9 +218,13 @@ mod tests {
218#[cfg(all(bank_setup_configurable))] 218#[cfg(all(bank_setup_configurable))]
219pub(crate) fn check_bank_setup() { 219pub(crate) fn check_bank_setup() {
220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() { 220 if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() {
221 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"); 221 panic!(
222 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"
223 );
222 } 224 }
223 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() { 225 if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() {
224 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"); 226 panic!(
227 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"
228 );
225 } 229 }
226} 230}
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index bc1fd360c..d7ba2f571 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
@@ -44,7 +44,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
44} 44}
45 45
46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 46pub(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 });
@@ -105,19 +104,27 @@ fn wait_busy() {
105#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))] 104#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))]
106pub(crate) fn check_bank_setup() { 105pub(crate) fn check_bank_setup() {
107 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { 106 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
108 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); 107 panic!(
108 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"
109 );
109 } 110 }
110 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { 111 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
111 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); 112 panic!(
113 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"
114 );
112 } 115 }
113} 116}
114 117
115#[cfg(all(bank_setup_configurable, flash_g0x1))] 118#[cfg(all(bank_setup_configurable, flash_g0x1))]
116pub(crate) fn check_bank_setup() { 119pub(crate) fn check_bank_setup() {
117 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() { 120 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() {
118 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"); 121 panic!(
122 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"
123 );
119 } 124 }
120 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() { 125 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() {
121 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"); 126 panic!(
127 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"
128 );
122 } 129 }
123} 130}
diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs
index fd9bfcc75..88f247879 100644
--- a/embassy-stm32/src/flash/h5.rs
+++ b/embassy-stm32/src/flash/h5.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs
index f8e210556..91d5da4d6 100644
--- a/embassy-stm32/src/flash/h50.rs
+++ b/embassy-stm32/src/flash/h50.rs
@@ -1,7 +1,7 @@
1/// STM32H50 series flash impl. See RM0492 1/// STM32H50 series flash impl. See RM0492
2use core::{ 2use core::{
3 ptr::write_volatile, 3 ptr::write_volatile,
4 sync::atomic::{fence, Ordering}, 4 sync::atomic::{Ordering, fence},
5}; 5};
6 6
7use cortex_m::interrupt; 7use cortex_m::interrupt;
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs
index f1d84101c..b342f4a83 100644
--- a/embassy-stm32/src/flash/h7.rs
+++ b/embassy-stm32/src/flash/h7.rs
@@ -1,10 +1,31 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; 4use embassy_sync::waitqueue::AtomicWaker;
5use pac::flash::regs::Sr;
6
7use super::{BANK1_REGION, FLASH_REGIONS, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 8use crate::flash::Error;
6use crate::pac; 9use crate::pac;
7 10
11static WAKER: AtomicWaker = AtomicWaker::new();
12
13pub(crate) unsafe fn on_interrupt() {
14 // Clear IRQ flags
15 pac::FLASH.bank(0).ccr().write(|w| {
16 w.set_clr_eop(true);
17 w.set_clr_operr(true);
18 });
19 if is_dual_bank() {
20 pac::FLASH.bank(1).ccr().write(|w| {
21 w.set_clr_eop(true);
22 w.set_clr_operr(true);
23 });
24 }
25
26 WAKER.wake();
27}
28
8const fn is_dual_bank() -> bool { 29const fn is_dual_bank() -> bool {
9 FLASH_REGIONS.len() >= 2 30 FLASH_REGIONS.len() >= 2
10} 31}
@@ -29,12 +50,68 @@ pub(crate) unsafe fn unlock() {
29 } 50 }
30} 51}
31 52
53pub(crate) unsafe fn enable_write() {
54 enable_blocking_write();
55}
56
57pub(crate) unsafe fn disable_write() {
58 disable_blocking_write();
59}
60
32pub(crate) unsafe fn enable_blocking_write() { 61pub(crate) unsafe fn enable_blocking_write() {
33 assert_eq!(0, WRITE_SIZE % 4); 62 assert_eq!(0, WRITE_SIZE % 4);
34} 63}
35 64
36pub(crate) unsafe fn disable_blocking_write() {} 65pub(crate) unsafe fn disable_blocking_write() {}
37 66
67pub(crate) async unsafe fn write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
68 // We cannot have the write setup sequence in begin_write as it depends on the address
69 let bank = if start_address < BANK1_REGION.end() {
70 pac::FLASH.bank(0)
71 } else {
72 pac::FLASH.bank(1)
73 };
74 bank.cr().write(|w| {
75 w.set_pg(true);
76 #[cfg(flash_h7)]
77 w.set_psize(2); // 32 bits at once
78 w.set_eopie(true);
79 w.set_operrie(true);
80 });
81 cortex_m::asm::isb();
82 cortex_m::asm::dsb();
83 fence(Ordering::SeqCst);
84
85 let mut res = None;
86 let mut address = start_address;
87 for val in buf.chunks(4) {
88 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
89 address += val.len() as u32;
90
91 res = Some(wait_ready(bank).await);
92 bank.sr().modify(|w| {
93 if w.eop() {
94 w.set_eop(true);
95 }
96 });
97 if unwrap!(res).is_err() {
98 break;
99 }
100 }
101
102 cortex_m::asm::isb();
103 cortex_m::asm::dsb();
104 fence(Ordering::SeqCst);
105
106 bank.cr().write(|w| {
107 w.set_pg(false);
108 w.set_eopie(false);
109 w.set_operrie(false);
110 });
111
112 unwrap!(res)
113}
114
38pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { 115pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
39 // We cannot have the write setup sequence in begin_write as it depends on the address 116 // We cannot have the write setup sequence in begin_write as it depends on the address
40 let bank = if start_address < BANK1_REGION.end() { 117 let bank = if start_address < BANK1_REGION.end() {
@@ -77,6 +154,36 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
77 unwrap!(res) 154 unwrap!(res)
78} 155}
79 156
157pub(crate) async unsafe fn erase_sector(sector: &FlashSector) -> Result<(), Error> {
158 let bank = pac::FLASH.bank(sector.bank as usize);
159 bank.cr().modify(|w| {
160 w.set_ser(true);
161 #[cfg(flash_h7)]
162 w.set_snb(sector.index_in_bank);
163 #[cfg(flash_h7ab)]
164 w.set_ssn(sector.index_in_bank);
165 w.set_eopie(true);
166 w.set_operrie(true);
167 });
168
169 bank.cr().modify(|w| {
170 w.set_start(true);
171 });
172
173 cortex_m::asm::isb();
174 cortex_m::asm::dsb();
175 fence(Ordering::SeqCst);
176
177 let ret: Result<(), Error> = wait_ready(bank).await;
178 bank.cr().modify(|w| {
179 w.set_ser(false);
180 w.set_eopie(false);
181 w.set_operrie(false);
182 });
183 bank_clear_all_err(bank);
184 ret
185}
186
80pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 187pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
81 let bank = pac::FLASH.bank(sector.bank as usize); 188 let bank = pac::FLASH.bank(sector.bank as usize);
82 bank.cr().modify(|w| { 189 bank.cr().modify(|w| {
@@ -112,46 +219,59 @@ unsafe fn bank_clear_all_err(bank: pac::flash::Bank) {
112 bank.sr().modify(|_| {}); 219 bank.sr().modify(|_| {});
113} 220}
114 221
222async fn wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
223 use core::future::poll_fn;
224 use core::task::Poll;
225
226 poll_fn(|cx| {
227 WAKER.register(cx.waker());
228
229 let sr = bank.sr().read();
230 if !sr.bsy() && !sr.qw() {
231 Poll::Ready(get_result(sr))
232 } else {
233 return Poll::Pending;
234 }
235 })
236 .await
237}
238
115unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { 239unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> {
116 loop { 240 loop {
117 let sr = bank.sr().read(); 241 let sr = bank.sr().read();
118 242
119 if !sr.bsy() && !sr.qw() { 243 if !sr.bsy() && !sr.qw() {
120 if sr.wrperr() { 244 return get_result(sr);
121 return Err(Error::Protected);
122 }
123 if sr.pgserr() {
124 error!("pgserr");
125 return Err(Error::Seq);
126 }
127 if sr.incerr() {
128 // writing to a different address when programming 256 bit word was not finished
129 error!("incerr");
130 return Err(Error::Seq);
131 }
132 if sr.crcrderr() {
133 error!("crcrderr");
134 return Err(Error::Seq);
135 }
136 if sr.operr() {
137 return Err(Error::Prog);
138 }
139 if sr.sneccerr1() {
140 // single ECC error
141 return Err(Error::Prog);
142 }
143 if sr.dbeccerr() {
144 // double ECC error
145 return Err(Error::Prog);
146 }
147 if sr.rdperr() {
148 return Err(Error::Protected);
149 }
150 if sr.rdserr() {
151 return Err(Error::Protected);
152 }
153
154 return Ok(());
155 } 245 }
156 } 246 }
157} 247}
248
249fn get_result(sr: Sr) -> Result<(), Error> {
250 if sr.wrperr() {
251 Err(Error::Protected)
252 } else if sr.pgserr() {
253 error!("pgserr");
254 Err(Error::Seq)
255 } else if sr.incerr() {
256 // writing to a different address when programming 256 bit word was not finished
257 error!("incerr");
258 Err(Error::Seq)
259 } else if sr.crcrderr() {
260 error!("crcrderr");
261 Err(Error::Seq)
262 } else if sr.operr() {
263 Err(Error::Prog)
264 } else if sr.sneccerr1() {
265 // single ECC error
266 Err(Error::Prog)
267 } else if sr.dbeccerr() {
268 // double ECC error
269 Err(Error::Prog)
270 } else if sr.rdperr() {
271 Err(Error::Protected)
272 } else if sr.rdserr() {
273 Err(Error::Protected)
274 } else {
275 Ok(())
276 }
277}
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs
index 1b82704ec..b3281f2d5 100644
--- a/embassy-stm32/src/flash/l.rs
+++ b/embassy-stm32/src/flash/l.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashSector, WRITE_SIZE}; 4use super::{FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
@@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] 96 #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))]
97 { 97 {
98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; 98 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
99 #[cfg(any(flash_l4, flash_l5))]
100 let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32;
99 101
100 #[cfg(flash_l4)] 102 #[cfg(flash_l4)]
101 let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; 103 let (idx, bank) = if idx > (pgn - 1) {
104 (idx - pgn, true)
105 } else {
106 (idx, false)
107 };
102 108
103 #[cfg(flash_l5)] 109 #[cfg(flash_l5)]
104 let (idx, bank) = if pac::FLASH.optr().read().dbank() { 110 let (idx, bank) = if pac::FLASH.optr().read().dbank() {
105 if idx > 255 { 111 if idx > (pgn - 1) {
106 (idx - 256, Some(true)) 112 (idx - pgn, Some(true))
107 } else { 113 } else {
108 (idx, Some(false)) 114 (idx, Some(false))
109 } 115 }
@@ -234,19 +240,27 @@ pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
234#[cfg(all(bank_setup_configurable, flash_l5))] 240#[cfg(all(bank_setup_configurable, flash_l5))]
235pub(crate) fn check_bank_setup() { 241pub(crate) fn check_bank_setup() {
236 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { 242 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() {
237 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); 243 panic!(
244 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"
245 );
238 } 246 }
239 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { 247 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() {
240 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); 248 panic!(
249 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"
250 );
241 } 251 }
242} 252}
243 253
244#[cfg(all(bank_setup_configurable, flash_l4))] 254#[cfg(all(bank_setup_configurable, flash_l4))]
245pub(crate) fn check_bank_setup() { 255pub(crate) fn check_bank_setup() {
246 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() { 256 if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() {
247 panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"); 257 panic!(
258 "Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"
259 );
248 } 260 }
249 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() { 261 if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() {
250 panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"); 262 panic!(
263 "Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"
264 );
251 } 265 }
252} 266}
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 3e74d857a..6211a37b7 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -1,14 +1,14 @@
1//! Flash memory (FLASH) 1//! Flash memory (FLASH)
2use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; 2use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind};
3 3
4#[cfg(flash_f4)] 4#[cfg(any(flash_f4, flash_h7, flash_h7ab))]
5mod asynch; 5mod asynch;
6#[cfg(flash)] 6#[cfg(flash)]
7mod common; 7mod common;
8#[cfg(eeprom)] 8#[cfg(eeprom)]
9mod eeprom; 9mod eeprom;
10 10
11#[cfg(flash_f4)] 11#[cfg(any(flash_f4, flash_h7, flash_h7ab))]
12pub use asynch::InterruptHandler; 12pub use asynch::InterruptHandler;
13#[cfg(flash)] 13#[cfg(flash)]
14pub use common::*; 14pub use common::*;
@@ -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/flash/u0.rs b/embassy-stm32/src/flash/u0.rs
index 68d847eca..a64f6c492 100644
--- a/embassy-stm32/src/flash/u0.rs
+++ b/embassy-stm32/src/flash/u0.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use cortex_m::interrupt; 4use cortex_m::interrupt;
5 5
diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs
index 6c3d4b422..5f1f562c0 100644
--- a/embassy-stm32/src/flash/u5.rs
+++ b/embassy-stm32/src/flash/u5.rs
@@ -1,5 +1,5 @@
1use core::ptr::write_volatile; 1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{Ordering, fence};
3 3
4use super::{FlashBank, FlashSector, WRITE_SIZE}; 4use super::{FlashBank, FlashSector, WRITE_SIZE};
5use crate::flash::Error; 5use crate::flash::Error;
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index ff18a8bee..a7c6c90bb 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::gpio::{AfType, OutputType, Pull, Speed}; 6use crate::gpio::{AfType, OutputType, Pull, Speed};
7use crate::{rcc, Peri}; 7use crate::{Peri, rcc};
8 8
9/// FMC driver 9/// FMC driver
10pub struct Fmc<'d, T: Instance> { 10pub struct Fmc<'d, T: Instance> {
@@ -236,6 +236,42 @@ impl<'d, T: Instance> Fmc<'d, T> {
236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) 236 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
237 ] 237 ]
238 )); 238 ));
239
240 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank1: (
241 bank: stm32_fmc::SdramTargetBank::Bank1,
242 addr: [
243 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
244 ],
245 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
246 d: [
247 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
248 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
249 ],
250 nbl: [
251 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
252 ],
253 ctrl: [
254 (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
255 ]
256 ));
257
258 fmc_sdram_constructor!(sdram_a13bits_d16bits_4banks_bank2: (
259 bank: stm32_fmc::SdramTargetBank::Bank2,
260 addr: [
261 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
262 ],
263 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
264 d: [
265 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
266 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin)
267 ],
268 nbl: [
269 (nbl0: NBL0Pin), (nbl1: NBL1Pin)
270 ],
271 ctrl: [
272 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
273 ]
274 ));
239} 275}
240 276
241trait SealedInstance: crate::rcc::RccPeripheral { 277trait SealedInstance: crate::rcc::RccPeripheral {
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 5a8d23183..e7d4e9ad3 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -4,7 +4,7 @@
4use core::convert::Infallible; 4use core::convert::Infallible;
5 5
6use critical_section::CriticalSection; 6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; 7use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral};
8 8
9use crate::pac::gpio::{self, vals}; 9use crate::pac::gpio::{self, vals};
10use crate::peripherals; 10use crate::peripherals;
@@ -592,7 +592,7 @@ impl AfType {
592 592
593#[inline(never)] 593#[inline(never)]
594#[cfg(gpio_v1)] 594#[cfg(gpio_v1)]
595fn set_as_af(pin_port: u8, af_type: AfType) { 595fn set_as_af(pin_port: PinNumber, af_type: AfType) {
596 let pin = unsafe { AnyPin::steal(pin_port) }; 596 let pin = unsafe { AnyPin::steal(pin_port) };
597 let r = pin.block(); 597 let r = pin.block();
598 let n = pin._pin() as usize; 598 let n = pin._pin() as usize;
@@ -649,7 +649,7 @@ impl AfType {
649 649
650#[inline(never)] 650#[inline(never)]
651#[cfg(gpio_v2)] 651#[cfg(gpio_v2)]
652fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { 652fn set_as_af(pin_port: PinNumber, af_num: u8, af_type: AfType) {
653 let pin = unsafe { AnyPin::steal(pin_port) }; 653 let pin = unsafe { AnyPin::steal(pin_port) };
654 let r = pin.block(); 654 let r = pin.block();
655 let n = pin._pin() as usize; 655 let n = pin._pin() as usize;
@@ -663,7 +663,7 @@ fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) {
663 663
664#[inline(never)] 664#[inline(never)]
665#[cfg(gpio_v2)] 665#[cfg(gpio_v2)]
666fn set_speed(pin_port: u8, speed: Speed) { 666fn set_speed(pin_port: PinNumber, speed: Speed) {
667 let pin = unsafe { AnyPin::steal(pin_port) }; 667 let pin = unsafe { AnyPin::steal(pin_port) };
668 let r = pin.block(); 668 let r = pin.block();
669 let n = pin._pin() as usize; 669 let n = pin._pin() as usize;
@@ -672,7 +672,7 @@ fn set_speed(pin_port: u8, speed: Speed) {
672} 672}
673 673
674#[inline(never)] 674#[inline(never)]
675fn set_as_analog(pin_port: u8) { 675fn set_as_analog(pin_port: PinNumber) {
676 let pin = unsafe { AnyPin::steal(pin_port) }; 676 let pin = unsafe { AnyPin::steal(pin_port) };
677 let r = pin.block(); 677 let r = pin.block();
678 let n = pin._pin() as usize; 678 let n = pin._pin() as usize;
@@ -688,7 +688,7 @@ fn set_as_analog(pin_port: u8) {
688} 688}
689 689
690#[inline(never)] 690#[inline(never)]
691fn get_pull(pin_port: u8) -> Pull { 691fn get_pull(pin_port: PinNumber) -> Pull {
692 let pin = unsafe { AnyPin::steal(pin_port) }; 692 let pin = unsafe { AnyPin::steal(pin_port) };
693 let r = pin.block(); 693 let r = pin.block();
694 let n = pin._pin() as usize; 694 let n = pin._pin() as usize;
@@ -727,15 +727,15 @@ pub struct AfioRemapBool<const V: bool>;
727pub struct AfioRemapNotApplicable; 727pub struct AfioRemapNotApplicable;
728 728
729pub(crate) trait SealedPin { 729pub(crate) trait SealedPin {
730 fn pin_port(&self) -> u8; 730 fn pin_port(&self) -> PinNumber;
731 731
732 #[inline] 732 #[inline]
733 fn _pin(&self) -> u8 { 733 fn _pin(&self) -> PinNumber {
734 self.pin_port() % 16 734 self.pin_port() % 16
735 } 735 }
736 736
737 #[inline] 737 #[inline]
738 fn _port(&self) -> u8 { 738 fn _port(&self) -> PinNumber {
739 self.pin_port() / 16 739 self.pin_port() / 16
740 } 740 }
741 741
@@ -798,31 +798,49 @@ pub(crate) trait SealedPin {
798 } 798 }
799} 799}
800 800
801/// GPIO pin trait. 801/// GPIO pin number type.
802///
803/// Some chips have a total number of ports that exceeds 8, a larger integer
804/// is needed to hold the total pin number `(ports * number)`.
805#[cfg(not(stm32n6))]
806pub type PinNumber = u8;
807
808/// GPIO pin number type.
809///
810/// Some chips have a total number of ports that exceeds 8, a larger integer
811/// is needed to hold the total pin number `(ports * number)`.
812#[cfg(stm32n6)]
813pub type PinNumber = u16;
814
815/// Pin that can be used to configure an [ExtiInput](crate::exti::ExtiInput). This trait is lost when converting to [AnyPin].
816#[cfg(feature = "exti")]
802#[allow(private_bounds)] 817#[allow(private_bounds)]
803pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static { 818pub trait ExtiPin: PeripheralType + SealedPin {
804 /// EXTI channel assigned to this pin. 819 /// EXTI channel assigned to this pin.
805 /// 820 ///
806 /// For example, PC4 uses EXTI4. 821 /// For example, PC4 uses EXTI4.
807 #[cfg(feature = "exti")]
808 type ExtiChannel: crate::exti::Channel; 822 type ExtiChannel: crate::exti::Channel;
823}
809 824
825/// GPIO pin trait.
826#[allow(private_bounds)]
827pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
810 /// Number of the pin within the port (0..31) 828 /// Number of the pin within the port (0..31)
811 #[inline] 829 #[inline]
812 fn pin(&self) -> u8 { 830 fn pin(&self) -> PinNumber {
813 self._pin() 831 self._pin()
814 } 832 }
815 833
816 /// Port of the pin 834 /// Port of the pin
817 #[inline] 835 #[inline]
818 fn port(&self) -> u8 { 836 fn port(&self) -> PinNumber {
819 self._port() 837 self._port()
820 } 838 }
821} 839}
822 840
823/// Type-erased GPIO pin 841/// Type-erased GPIO pin.
824pub struct AnyPin { 842pub struct AnyPin {
825 pin_port: u8, 843 pin_port: PinNumber,
826} 844}
827 845
828impl AnyPin { 846impl AnyPin {
@@ -830,12 +848,12 @@ impl AnyPin {
830 /// 848 ///
831 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... 849 /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
832 #[inline] 850 #[inline]
833 pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { 851 pub unsafe fn steal(pin_port: PinNumber) -> Peri<'static, Self> {
834 Peri::new_unchecked(Self { pin_port }) 852 Peri::new_unchecked(Self { pin_port })
835 } 853 }
836 854
837 #[inline] 855 #[inline]
838 fn _port(&self) -> u8 { 856 fn _port(&self) -> PinNumber {
839 self.pin_port / 16 857 self.pin_port / 16
840 } 858 }
841 859
@@ -848,13 +866,10 @@ impl AnyPin {
848} 866}
849 867
850impl_peripheral!(AnyPin); 868impl_peripheral!(AnyPin);
851impl Pin for AnyPin { 869impl Pin for AnyPin {}
852 #[cfg(feature = "exti")]
853 type ExtiChannel = crate::exti::AnyChannel;
854}
855impl SealedPin for AnyPin { 870impl SealedPin for AnyPin {
856 #[inline] 871 #[inline]
857 fn pin_port(&self) -> u8 { 872 fn pin_port(&self) -> PinNumber {
858 self.pin_port 873 self.pin_port
859 } 874 }
860} 875}
@@ -864,12 +879,14 @@ impl SealedPin for AnyPin {
864foreach_pin!( 879foreach_pin!(
865 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { 880 ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => {
866 impl Pin for peripherals::$pin_name { 881 impl Pin for peripherals::$pin_name {
867 #[cfg(feature = "exti")] 882 }
883 #[cfg(feature = "exti")]
884 impl ExtiPin for peripherals::$pin_name {
868 type ExtiChannel = peripherals::$exti_ch; 885 type ExtiChannel = peripherals::$exti_ch;
869 } 886 }
870 impl SealedPin for peripherals::$pin_name { 887 impl SealedPin for peripherals::$pin_name {
871 #[inline] 888 #[inline]
872 fn pin_port(&self) -> u8 { 889 fn pin_port(&self) -> PinNumber {
873 $port_num * 16 + $pin_num 890 $port_num * 16 + $pin_num
874 } 891 }
875 } 892 }
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index 90c06c0d8..ba573267c 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt;
19use crate::mode::Async; 19use crate::mode::Async;
20use crate::mode::{Blocking, Mode}; 20use crate::mode::{Blocking, Mode};
21use crate::peripherals::HASH; 21use crate::peripherals::HASH;
22use crate::{interrupt, pac, peripherals, rcc, Peri}; 22use crate::{Peri, interrupt, pac, peripherals, rcc};
23 23
24#[cfg(hash_v1)] 24#[cfg(hash_v1)]
25const NUM_CONTEXT_REGS: usize = 51; 25const NUM_CONTEXT_REGS: usize = 51;
@@ -514,11 +514,7 @@ impl<'d, T: Instance> Hash<'d, T, Async> {
514 T::regs().imr().modify(|reg| reg.set_dcie(true)); 514 T::regs().imr().modify(|reg| reg.set_dcie(true));
515 // Check for completion. 515 // Check for completion.
516 let bits = T::regs().sr().read(); 516 let bits = T::regs().sr().read();
517 if bits.dcis() { 517 if bits.dcis() { Poll::Ready(()) } else { Poll::Pending }
518 Poll::Ready(())
519 } else {
520 Poll::Pending
521 }
522 }) 518 })
523 .await; 519 .await;
524 520
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 6fece5eb2..6c6807479 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -10,6 +10,7 @@ pub use traits::Instance;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::rcc; 11use crate::rcc;
12use crate::time::Hertz; 12use crate::time::Hertz;
13pub use crate::timer::simple_pwm::PwmPinConfig;
13 14
14/// HRTIM burst controller instance. 15/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 16pub struct BurstController<T: Instance> {
@@ -73,7 +74,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
73} 74}
74 75
75macro_rules! advanced_channel_impl { 76macro_rules! advanced_channel_impl {
76 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 77 ($new_chx:ident, $new_chx_with_config:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
77 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> { 78 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
78 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 79 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
79 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 80 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self {
@@ -86,6 +87,21 @@ macro_rules! advanced_channel_impl {
86 phantom: PhantomData, 87 phantom: PhantomData,
87 } 88 }
88 } 89 }
90
91 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with a specific configuration.")]
92 pub fn $new_chx_with_config(
93 pin: Peri<'d, impl $pin_trait<T>>,
94 pin_config: PwmPinConfig,
95 ) -> Self {
96 critical_section::with(|_| {
97 pin.set_low();
98 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
99 });
100 PwmPin {
101 _pin: pin.into(),
102 phantom: PhantomData,
103 }
104 }
89 } 105 }
90 106
91 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> { 107 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
@@ -100,6 +116,21 @@ macro_rules! advanced_channel_impl {
100 phantom: PhantomData, 116 phantom: PhantomData,
101 } 117 }
102 } 118 }
119
120 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance with a specific configuration.")]
121 pub fn $new_chx_with_config(
122 pin: Peri<'d, impl $complementary_pin_trait<T>>,
123 pin_config: PwmPinConfig,
124 ) -> Self {
125 critical_section::with(|_| {
126 pin.set_low();
127 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
128 });
129 ComplementaryPwmPin {
130 _pin: pin.into(),
131 phantom: PhantomData,
132 }
133 }
103 } 134 }
104 135
105 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> { 136 impl<T: Instance> SealedAdvancedChannel<T> for $channel<T> {
@@ -111,13 +142,55 @@ macro_rules! advanced_channel_impl {
111 }; 142 };
112} 143}
113 144
114advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); 145advanced_channel_impl!(
115advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); 146 new_cha,
116advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); 147 new_cha_with_config,
117advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); 148 ChA,
118advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); 149 0,
150 ChannelAPin,
151 ChannelAComplementaryPin
152);
153advanced_channel_impl!(
154 new_chb,
155 new_chb_with_config,
156 ChB,
157 1,
158 ChannelBPin,
159 ChannelBComplementaryPin
160);
161advanced_channel_impl!(
162 new_chc,
163 new_chc_with_config,
164 ChC,
165 2,
166 ChannelCPin,
167 ChannelCComplementaryPin
168);
169advanced_channel_impl!(
170 new_chd,
171 new_chd_with_config,
172 ChD,
173 3,
174 ChannelDPin,
175 ChannelDComplementaryPin
176);
177advanced_channel_impl!(
178 new_che,
179 new_che_with_config,
180 ChE,
181 4,
182 ChannelEPin,
183 ChannelEComplementaryPin
184);
119#[cfg(hrtim_v2)] 185#[cfg(hrtim_v2)]
120advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); 186advanced_channel_impl!(
187 new_chf,
188 new_chf_with_config,
189 ChF,
190 5,
191 ChannelFPin,
192 ChannelFComplementaryPin
193);
121 194
122/// Struct used to divide a high resolution timer into multiple channels 195/// Struct used to divide a high resolution timer into multiple channels
123pub struct AdvancedPwm<'d, T: Instance> { 196pub struct AdvancedPwm<'d, T: Instance> {
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index 573a1851d..e62de0454 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -1,14 +1,22 @@
1//! Hardware Semaphore (HSEM) 1//! Hardware Semaphore (HSEM)
2 2
3use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::sync::atomic::{Ordering, compiler_fence};
6use core::task::Poll;
7
8#[cfg(all(stm32wb, feature = "low-power"))]
9use critical_section::CriticalSection;
3use embassy_hal_internal::PeripheralType; 10use embassy_hal_internal::PeripheralType;
11use embassy_sync::waitqueue::AtomicWaker;
4 12
5use crate::pac;
6use crate::rcc::{self, RccPeripheral};
7// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. 13// TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs.
8// Those MCUs have a different HSEM implementation (Secure semaphore lock support, 14// Those MCUs have a different HSEM implementation (Secure semaphore lock support,
9// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), 15// Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute),
10// which is not yet supported by this code. 16// which is not yet supported by this code.
11use crate::Peri; 17use crate::Peri;
18use crate::rcc::{self, RccPeripheral};
19use crate::{interrupt, pac};
12 20
13/// HSEM error. 21/// HSEM error.
14#[derive(Debug)] 22#[derive(Debug)]
@@ -41,63 +49,152 @@ pub enum CoreId {
41 Core1 = 0x8, 49 Core1 = 0x8,
42} 50}
43 51
44/// Get the current core id 52impl CoreId {
45/// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core. 53 /// Get the current core id
46#[inline(always)] 54 /// This code assume that it is only executed on a Cortex-M M0+, M4 or M7 core.
47pub fn get_current_coreid() -> CoreId { 55 pub fn current() -> Self {
48 let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() }; 56 let cpuid = unsafe { cortex_m::peripheral::CPUID::PTR.read_volatile().base.read() };
49 match (cpuid & 0x000000F0) >> 4 { 57 match (cpuid & 0x000000F0) >> 4 {
50 #[cfg(any(stm32wb, stm32wl))] 58 #[cfg(any(stm32wb, stm32wl))]
51 0x0 => CoreId::Core1, 59 0x0 => CoreId::Core1,
52 60
53 #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))] 61 #[cfg(not(any(stm32h745, stm32h747, stm32h755, stm32h757)))]
54 0x4 => CoreId::Core0, 62 0x4 => CoreId::Core0,
55 63
56 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] 64 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
57 0x4 => CoreId::Core1, 65 0x4 => CoreId::Core1,
58 66
59 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))] 67 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757))]
60 0x7 => CoreId::Core0, 68 0x7 => CoreId::Core0,
61 _ => panic!("Unknown Cortex-M core"), 69 _ => panic!("Unknown Cortex-M core"),
70 }
71 }
72
73 /// Translates the core ID to an index into the interrupt registers.
74 pub fn to_index(&self) -> usize {
75 match &self {
76 CoreId::Core0 => 0,
77 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))]
78 CoreId::Core1 => 1,
79 }
62 } 80 }
63} 81}
64 82
65/// Translates the core ID to an index into the interrupt registers. 83#[cfg(not(all(stm32wb, feature = "low-power")))]
66#[inline(always)] 84const PUB_CHANNELS: usize = 6;
67fn core_id_to_index(core: CoreId) -> usize { 85
68 match core { 86#[cfg(all(stm32wb, feature = "low-power"))]
69 CoreId::Core0 => 0, 87const PUB_CHANNELS: usize = 4;
70 #[cfg(any(stm32h745, stm32h747, stm32h755, stm32h757, stm32wb, stm32wl))] 88
71 CoreId::Core1 => 1, 89/// TX interrupt handler.
90pub struct HardwareSemaphoreInterruptHandler<T: Instance> {
91 _phantom: PhantomData<T>,
92}
93
94impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for HardwareSemaphoreInterruptHandler<T> {
95 unsafe fn on_interrupt() {
96 let core_id = CoreId::current();
97
98 for number in 0..5 {
99 if T::regs().isr(core_id.to_index()).read().isf(number as usize) {
100 T::regs()
101 .icr(core_id.to_index())
102 .write(|w| w.set_isc(number as usize, true));
103
104 T::regs()
105 .ier(core_id.to_index())
106 .modify(|w| w.set_ise(number as usize, false));
107
108 T::state().waker_for(number).wake();
109 }
110 }
72 } 111 }
73} 112}
74 113
75/// HSEM driver 114/// Hardware semaphore mutex
76pub struct HardwareSemaphore<'d, T: Instance> { 115pub struct HardwareSemaphoreMutex<'a, T: Instance> {
77 _peri: Peri<'d, T>, 116 index: u8,
117 process_id: u8,
118 _lifetime: PhantomData<&'a mut T>,
78} 119}
79 120
80impl<'d, T: Instance> HardwareSemaphore<'d, T> { 121impl<'a, T: Instance> Drop for HardwareSemaphoreMutex<'a, T> {
81 /// Creates a new HardwareSemaphore instance. 122 fn drop(&mut self) {
82 pub fn new(peripheral: Peri<'d, T>) -> Self { 123 HardwareSemaphoreChannel::<'a, T> {
83 rcc::enable_and_reset::<T>(); 124 index: self.index,
125 _lifetime: PhantomData,
126 }
127 .unlock(self.process_id);
128 }
129}
130
131/// Hardware semaphore channel
132pub struct HardwareSemaphoreChannel<'a, T: Instance> {
133 index: u8,
134 _lifetime: PhantomData<&'a mut T>,
135}
136
137impl<'a, T: Instance> HardwareSemaphoreChannel<'a, T> {
138 pub(crate) const fn new(number: u8) -> Self {
139 core::assert!(number > 0 && number <= 6);
140
141 Self {
142 index: number - 1,
143 _lifetime: PhantomData,
144 }
145 }
146
147 /// Locks the semaphore.
148 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
149 /// check if the lock has been successful, carried out from the HSEM_Rx register.
150 pub async fn lock(&mut self, process_id: u8) -> HardwareSemaphoreMutex<'a, T> {
151 let core_id = CoreId::current();
152
153 poll_fn(|cx| {
154 T::state().waker_for(self.index).register(cx.waker());
155
156 compiler_fence(Ordering::SeqCst);
157
158 T::regs()
159 .ier(core_id.to_index())
160 .modify(|w| w.set_ise(self.index as usize, true));
84 161
85 HardwareSemaphore { _peri: peripheral } 162 match self.try_lock(process_id) {
163 Some(mutex) => Poll::Ready(mutex),
164 None => Poll::Pending,
165 }
166 })
167 .await
168 }
169
170 /// Try to lock the semaphor
171 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
172 /// check if the lock has been successful, carried out from the HSEM_Rx register.
173 pub fn try_lock(&mut self, process_id: u8) -> Option<HardwareSemaphoreMutex<'a, T>> {
174 if self.two_step_lock(process_id).is_ok() {
175 Some(HardwareSemaphoreMutex {
176 index: self.index,
177 process_id: process_id,
178 _lifetime: PhantomData,
179 })
180 } else {
181 None
182 }
86 } 183 }
87 184
88 /// Locks the semaphore. 185 /// Locks the semaphore.
89 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to 186 /// The 2-step lock procedure consists in a write to lock the semaphore, followed by a read to
90 /// check if the lock has been successful, carried out from the HSEM_Rx register. 187 /// check if the lock has been successful, carried out from the HSEM_Rx register.
91 pub fn two_step_lock(&mut self, sem_id: u8, process_id: u8) -> Result<(), HsemError> { 188 pub fn two_step_lock(&mut self, process_id: u8) -> Result<(), HsemError> {
92 T::regs().r(sem_id as usize).write(|w| { 189 T::regs().r(self.index as usize).write(|w| {
93 w.set_procid(process_id); 190 w.set_procid(process_id);
94 w.set_coreid(get_current_coreid() as u8); 191 w.set_coreid(CoreId::current() as u8);
95 w.set_lock(true); 192 w.set_lock(true);
96 }); 193 });
97 let reg = T::regs().r(sem_id as usize).read(); 194 let reg = T::regs().r(self.index as usize).read();
98 match ( 195 match (
99 reg.lock(), 196 reg.lock(),
100 reg.coreid() == get_current_coreid() as u8, 197 reg.coreid() == CoreId::current() as u8,
101 reg.procid() == process_id, 198 reg.procid() == process_id,
102 ) { 199 ) {
103 (true, true, true) => Ok(()), 200 (true, true, true) => Ok(()),
@@ -108,9 +205,9 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
108 /// Locks the semaphore. 205 /// Locks the semaphore.
109 /// The 1-step procedure consists in a read to lock and check the semaphore in a single step, 206 /// The 1-step procedure consists in a read to lock and check the semaphore in a single step,
110 /// carried out from the HSEM_RLRx register. 207 /// carried out from the HSEM_RLRx register.
111 pub fn one_step_lock(&mut self, sem_id: u8) -> Result<(), HsemError> { 208 pub fn one_step_lock(&mut self) -> Result<(), HsemError> {
112 let reg = T::regs().rlr(sem_id as usize).read(); 209 let reg = T::regs().rlr(self.index as usize).read();
113 match (reg.lock(), reg.coreid() == get_current_coreid() as u8, reg.procid()) { 210 match (reg.lock(), reg.coreid() == CoreId::current() as u8, reg.procid()) {
114 (false, true, 0) => Ok(()), 211 (false, true, 0) => Ok(()),
115 _ => Err(HsemError::LockFailed), 212 _ => Err(HsemError::LockFailed),
116 } 213 }
@@ -119,14 +216,60 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
119 /// Unlocks the semaphore. 216 /// Unlocks the semaphore.
120 /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus 217 /// Unlocking a semaphore is a protected process, to prevent accidental clearing by a AHB bus
121 /// core ID or by a process not having the semaphore lock right. 218 /// core ID or by a process not having the semaphore lock right.
122 pub fn unlock(&mut self, sem_id: u8, process_id: u8) { 219 pub fn unlock(&mut self, process_id: u8) {
123 T::regs().r(sem_id as usize).write(|w| { 220 T::regs().r(self.index as usize).write(|w| {
124 w.set_procid(process_id); 221 w.set_procid(process_id);
125 w.set_coreid(get_current_coreid() as u8); 222 w.set_coreid(CoreId::current() as u8);
126 w.set_lock(false); 223 w.set_lock(false);
127 }); 224 });
128 } 225 }
129 226
227 /// Return the channel number
228 pub const fn channel(&self) -> u8 {
229 self.index + 1
230 }
231}
232
233/// HSEM driver
234pub struct HardwareSemaphore<T: Instance> {
235 _type: PhantomData<T>,
236}
237
238impl<T: Instance> HardwareSemaphore<T> {
239 /// Creates a new HardwareSemaphore instance.
240 pub fn new<'d>(
241 _peripheral: Peri<'d, T>,
242 _irq: impl interrupt::typelevel::Binding<T::Interrupt, HardwareSemaphoreInterruptHandler<T>> + 'd,
243 ) -> Self {
244 rcc::enable_and_reset::<T>();
245
246 HardwareSemaphore { _type: PhantomData }
247 }
248
249 /// Get a single channel, and keep the global struct
250 pub const fn channel_for<'a>(&'a mut self, number: u8) -> HardwareSemaphoreChannel<'a, T> {
251 #[cfg(all(stm32wb, feature = "low-power"))]
252 core::assert!(number != 3 && number != 4);
253
254 HardwareSemaphoreChannel::new(number)
255 }
256
257 /// Split the global struct into channels
258 ///
259 /// If using low-power mode, channels 3 and 4 will not be returned
260 pub const fn split<'a>(self) -> [HardwareSemaphoreChannel<'a, T>; PUB_CHANNELS] {
261 [
262 HardwareSemaphoreChannel::new(1),
263 HardwareSemaphoreChannel::new(2),
264 #[cfg(not(all(stm32wb, feature = "low-power")))]
265 HardwareSemaphoreChannel::new(3),
266 #[cfg(not(all(stm32wb, feature = "low-power")))]
267 HardwareSemaphoreChannel::new(4),
268 HardwareSemaphoreChannel::new(5),
269 HardwareSemaphoreChannel::new(6),
270 ]
271 }
272
130 /// Unlocks all semaphores. 273 /// Unlocks all semaphores.
131 /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR 274 /// All semaphores locked by a COREID can be unlocked at once by using the HSEM_CR
132 /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a 275 /// register. Write COREID and correct KEY value in HSEM_CR. All locked semaphores with a
@@ -138,11 +281,6 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
138 }); 281 });
139 } 282 }
140 283
141 /// Checks if the semaphore is locked.
142 pub fn is_semaphore_locked(&self, sem_id: u8) -> bool {
143 T::regs().r(sem_id as usize).read().lock()
144 }
145
146 /// Sets the clear (unlock) key 284 /// Sets the clear (unlock) key
147 pub fn set_clear_key(&mut self, key: u16) { 285 pub fn set_clear_key(&mut self, key: u16) {
148 T::regs().keyr().modify(|w| w.set_key(key)); 286 T::regs().keyr().modify(|w| w.set_key(key));
@@ -152,38 +290,61 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
152 pub fn get_clear_key(&mut self) -> u16 { 290 pub fn get_clear_key(&mut self) -> u16 {
153 T::regs().keyr().read().key() 291 T::regs().keyr().read().key()
154 } 292 }
293}
155 294
156 /// Sets the interrupt enable bit for the semaphore. 295#[cfg(all(stm32wb, feature = "low-power"))]
157 pub fn enable_interrupt(&mut self, core_id: CoreId, sem_x: usize, enable: bool) { 296pub(crate) fn init_hsem(cs: CriticalSection) {
158 T::regs() 297 rcc::enable_and_reset_with_cs::<crate::peripherals::HSEM>(cs);
159 .ier(core_id_to_index(core_id)) 298
160 .modify(|w| w.set_ise(sem_x, enable)); 299 unsafe {
300 crate::rcc::REFCOUNT_STOP1 = 0;
301 crate::rcc::REFCOUNT_STOP2 = 0;
161 } 302 }
303}
162 304
163 /// Gets the interrupt flag for the semaphore. 305struct State {
164 pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool { 306 wakers: [AtomicWaker; 6],
165 T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x) 307}
308
309impl State {
310 const fn new() -> Self {
311 Self {
312 wakers: [const { AtomicWaker::new() }; 6],
313 }
166 } 314 }
167 315
168 /// Clears the interrupt flag for the semaphore. 316 const fn waker_for(&self, index: u8) -> &AtomicWaker {
169 pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { 317 &self.wakers[index as usize]
170 T::regs()
171 .icr(core_id_to_index(core_id))
172 .write(|w| w.set_isc(sem_x, false));
173 } 318 }
174} 319}
175 320
176trait SealedInstance { 321trait SealedInstance {
177 fn regs() -> pac::hsem::Hsem; 322 fn regs() -> pac::hsem::Hsem;
323 fn state() -> &'static State;
178} 324}
179 325
180/// HSEM instance trait. 326/// HSEM instance trait.
181#[allow(private_bounds)] 327#[allow(private_bounds)]
182pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {} 328pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {
329 /// Interrupt for this peripheral.
330 type Interrupt: interrupt::typelevel::Interrupt;
331}
183 332
184impl SealedInstance for crate::peripherals::HSEM { 333impl SealedInstance for crate::peripherals::HSEM {
185 fn regs() -> crate::pac::hsem::Hsem { 334 fn regs() -> crate::pac::hsem::Hsem {
186 crate::pac::HSEM 335 crate::pac::HSEM
187 } 336 }
337
338 fn state() -> &'static State {
339 static STATE: State = State::new();
340 &STATE
341 }
188} 342}
189impl Instance for crate::peripherals::HSEM {} 343
344foreach_interrupt!(
345 ($inst:ident, hsem, $block:ident, $signal_name:ident, $irq:ident) => {
346 impl Instance for crate::peripherals::$inst {
347 type Interrupt = crate::interrupt::typelevel::$irq;
348 }
349 };
350);
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
index 59dd7ca16..1d3560678 100644
--- a/embassy-stm32/src/hspi/mod.rs
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -16,7 +16,7 @@ use embassy_embedded_hal::{GetConfig, SetConfig};
16use embassy_hal_internal::{Peri, PeripheralType}; 16use embassy_hal_internal::{Peri, PeripheralType};
17pub use enums::*; 17pub use enums::*;
18 18
19use crate::dma::{word, ChannelAndRequest}; 19use crate::dma::{ChannelAndRequest, word};
20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 20use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
21use crate::mode::{Async, Blocking, Mode as PeriMode}; 21use crate::mode::{Async, Blocking, Mode as PeriMode};
22use crate::pac::hspi::Hspi as Regs; 22use crate::pac::hspi::Hspi as Regs;
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs
index 4e3b736c7..74fac14b2 100644
--- a/embassy-stm32/src/i2c/config.rs
+++ b/embassy-stm32/src/i2c/config.rs
@@ -4,7 +4,7 @@ use crate::gpio::{AfType, OutputType, Speed};
4use crate::time::Hertz; 4use crate::time::Hertz;
5 5
6#[repr(u8)] 6#[repr(u8)]
7#[derive(Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Bits of the I2C OA2 register to mask out. 9/// Bits of the I2C OA2 register to mask out.
10pub enum AddrMask { 10pub enum AddrMask {
@@ -60,7 +60,7 @@ impl Address {
60 } 60 }
61} 61}
62 62
63#[derive(Copy, Clone)] 63#[derive(Debug, Copy, Clone)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65/// The second Own Address register. 65/// The second Own Address register.
66pub struct OA2 { 66pub struct OA2 {
@@ -70,7 +70,7 @@ pub struct OA2 {
70 pub mask: AddrMask, 70 pub mask: AddrMask,
71} 71}
72 72
73#[derive(Copy, Clone)] 73#[derive(Debug, Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// The Own Address(es) of the I2C peripheral. 75/// The Own Address(es) of the I2C peripheral.
76pub enum OwnAddresses { 76pub enum OwnAddresses {
@@ -88,7 +88,7 @@ pub enum OwnAddresses {
88} 88}
89 89
90/// Slave Configuration 90/// Slave Configuration
91#[derive(Copy, Clone)] 91#[derive(Debug, Copy, Clone)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))] 92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct SlaveAddrConfig { 93pub struct SlaveAddrConfig {
94 /// Target Address(es) 94 /// Target Address(es)
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 249bac41c..ee60c3f44 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -154,8 +154,8 @@ impl<'d> I2c<'d, Async, Master> {
154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>, 154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>, 155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
158 + 'd, 158 + 'd,
159 tx_dma: Peri<'d, impl TxDma<T>>, 159 tx_dma: Peri<'d, impl TxDma<T>>,
160 rx_dma: Peri<'d, impl RxDma<T>>, 160 rx_dma: Peri<'d, impl RxDma<T>>,
161 config: Config, 161 config: Config,
@@ -219,6 +219,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
219 sda, 219 sda,
220 }, 220 },
221 }; 221 };
222
222 this.enable_and_init(config); 223 this.enable_and_init(config);
223 224
224 this 225 this
@@ -437,15 +438,15 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
437 438
438/// Frame type in I2C transaction. 439/// Frame type in I2C transaction.
439/// 440///
440/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST 441/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST
441/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an 442/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
442/// ACK or NACK after the last byte received. 443/// ACK or NACK after the last byte received.
443/// 444///
444/// For write operations, the following options are identical because they differ only in the (N)ACK 445/// For write operations, the following options are identical because they differ only in the (N)ACK
445/// treatment relevant for read operations: 446/// treatment relevant for read operations:
446/// 447///
447/// - `FirstFrame` and `FirstAndNextFrame` 448/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes
448/// - `NextFrame` and `LastFrameNoStop` 449/// - `NextFrame` and `LastFrameNoStop` behave identically for writes
449/// 450///
450/// Abbreviations used below: 451/// Abbreviations used below:
451/// 452///
@@ -474,7 +475,7 @@ enum FrameOptions {
474 475
475#[allow(dead_code)] 476#[allow(dead_code)]
476impl FrameOptions { 477impl FrameOptions {
477 /// Sends start or repeated start condition before transfer. 478 /// Returns true if a start or repeated start condition should be generated before this operation.
478 fn send_start(self) -> bool { 479 fn send_start(self) -> bool {
479 match self { 480 match self {
480 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, 481 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
@@ -482,7 +483,7 @@ impl FrameOptions {
482 } 483 }
483 } 484 }
484 485
485 /// Sends stop condition after transfer. 486 /// Returns true if a stop condition should be generated after this operation.
486 fn send_stop(self) -> bool { 487 fn send_stop(self) -> bool {
487 match self { 488 match self {
488 Self::FirstAndLastFrame | Self::LastFrame => true, 489 Self::FirstAndLastFrame | Self::LastFrame => true,
@@ -490,7 +491,10 @@ impl FrameOptions {
490 } 491 }
491 } 492 }
492 493
493 /// Sends NACK after last byte received, indicating end of read operation. 494 /// Returns true if NACK should be sent after the last byte received in a read operation.
495 ///
496 /// This signals the end of a read sequence and releases the bus for the master's
497 /// next transmission (or stop condition).
494 fn send_nack(self) -> bool { 498 fn send_nack(self) -> bool {
495 match self { 499 match self {
496 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, 500 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
@@ -499,24 +503,44 @@ impl FrameOptions {
499 } 503 }
500} 504}
501 505
502/// Iterates over operations in transaction. 506/// Analyzes I2C transaction operations and assigns appropriate frame to each.
507///
508/// This function processes a sequence of I2C operations and determines the correct
509/// frame configuration for each operation to ensure proper I2C protocol compliance.
510/// It handles the complex logic of:
511///
512/// - Generating start conditions for the first operation of each type (read/write)
513/// - Generating stop conditions for the final operation in the entire transaction
514/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads
515/// - Ensuring proper bus handoff between different operation types
516///
517/// **Transaction Contract Compliance:**
518/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract,
519/// where consecutive operations of the same type are logically merged while maintaining
520/// proper protocol boundaries.
503/// 521///
504/// Returns necessary frame options for each operation to uphold the [transaction contract] and have 522/// **Error Handling:**
505/// the right start/stop/(N)ACK conditions on the wire. 523/// Returns an error if any read operation has an empty buffer, as this would create
524/// an invalid I2C transaction that could halt mid-execution.
525///
526/// # Arguments
527/// * `operations` - Mutable slice of I2C operations from embedded-hal
528///
529/// # Returns
530/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid
506/// 531///
507/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
508#[allow(dead_code)] 532#[allow(dead_code)]
509fn operation_frames<'a, 'b: 'a>( 533fn operation_frames<'a, 'b: 'a>(
510 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 534 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
511) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { 535) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
512 use embedded_hal_1::i2c::Operation::{Read, Write}; 536 use embedded_hal_1::i2c::Operation::{Read, Write};
513 537
514 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an 538 // Validate that no read operations have empty buffers before starting the transaction.
515 // error in the middle of the transaction. 539 // Empty read operations would risk halting with an error mid-transaction.
516 // 540 //
517 // In principle, we could allow empty read frames within consecutive read operations, as long as 541 // Note: We could theoretically allow empty read operations within consecutive read
518 // at least one byte remains in the final (merged) read operation, but that makes the logic more 542 // sequences as long as the final merged read has at least one byte, but this would
519 // complicated and error-prone. 543 // complicate the logic significantly and create error-prone edge cases.
520 if operations.iter().any(|op| match op { 544 if operations.iter().any(|op| match op {
521 Read(read) => read.is_empty(), 545 Read(read) => read.is_empty(),
522 Write(_) => false, 546 Write(_) => false,
@@ -525,46 +549,52 @@ fn operation_frames<'a, 'b: 'a>(
525 } 549 }
526 550
527 let mut operations = operations.iter_mut().peekable(); 551 let mut operations = operations.iter_mut().peekable();
528 552 let mut next_first_operation = true;
529 let mut next_first_frame = true;
530 553
531 Ok(iter::from_fn(move || { 554 Ok(iter::from_fn(move || {
532 let op = operations.next()?; 555 let current_op = operations.next()?;
533 556
534 // Is `op` first frame of its type? 557 // Determine if this is the first operation of its type (read or write)
535 let first_frame = next_first_frame; 558 let is_first_of_type = next_first_operation;
536 let next_op = operations.peek(); 559 let next_op = operations.peek();
537 560
538 // Get appropriate frame options as combination of the following properties: 561 // Compute the appropriate frame based on three key properties:
539 // 562 //
540 // - For each first operation of its type, generate a (repeated) start condition. 563 // 1. **Start Condition**: Generate (repeated) start for first operation of each type
541 // - For the last operation overall in the entire transaction, generate a stop condition. 564 // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction
542 // - For read operations, check the next operation: if it is also a read operation, we merge 565 // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the
543 // these and send ACK for all bytes in the current operation; send NACK only for the final 566 // sequence, or NACK for the final read in a sequence (before write or transaction end)
544 // read operation's last byte (before write or end of entire transaction) to indicate last
545 // byte read and release the bus for transmission of the bus master's next byte (or stop).
546 // 567 //
547 // We check the third property unconditionally, i.e. even for write opeartions. This is okay 568 // The third property is checked for all operations since the resulting frame
548 // because the resulting frame options are identical for write operations. 569 // configurations are identical for write operations regardless of ACK/NACK treatment.
549 let frame = match (first_frame, next_op) { 570 let frame = match (is_first_of_type, next_op) {
571 // First operation of type, and it's also the final operation overall
550 (true, None) => FrameOptions::FirstAndLastFrame, 572 (true, None) => FrameOptions::FirstAndLastFrame,
573 // First operation of type, next operation is also a read (continue read sequence)
551 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, 574 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
575 // First operation of type, next operation is write (end current sequence)
552 (true, Some(Write(_))) => FrameOptions::FirstFrame, 576 (true, Some(Write(_))) => FrameOptions::FirstFrame,
553 // 577
578 // Continuation operation, and it's the final operation overall
554 (false, None) => FrameOptions::LastFrame, 579 (false, None) => FrameOptions::LastFrame,
580 // Continuation operation, next operation is also a read (continue read sequence)
555 (false, Some(Read(_))) => FrameOptions::NextFrame, 581 (false, Some(Read(_))) => FrameOptions::NextFrame,
582 // Continuation operation, next operation is write (end current sequence, no stop)
556 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, 583 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
557 }; 584 };
558 585
559 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at 586 // Pre-calculate whether the next operation will be the first of its type.
560 // the beginning of the loop because we hand out `op` as iterator value and cannot access it 587 // This is done here because we consume `current_op` as the iterator value
561 // anymore in the next iteration. 588 // and cannot access it in the next iteration.
562 next_first_frame = match (&op, next_op) { 589 next_first_operation = match (&current_op, next_op) {
590 // No next operation
563 (_, None) => false, 591 (_, None) => false,
592 // Operation type changes: next will be first of its type
564 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, 593 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
594 // Operation type continues: next will not be first of its type
565 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, 595 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
566 }; 596 };
567 597
568 Some((op, frame)) 598 Some((current_op, frame))
569 })) 599 }))
570} 600}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 081eb1191..128a58db7 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -8,7 +8,7 @@ use core::future::poll_fn;
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{Either, select};
12use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
13use embedded_hal_1::i2c::Operation; 13use embedded_hal_1::i2c::Operation;
14use mode::Master; 14use mode::Master;
@@ -30,6 +30,7 @@ use crate::pac::i2c;
30// hit a case like this! 30// hit a case like this!
31pub unsafe fn on_interrupt<T: Instance>() { 31pub unsafe fn on_interrupt<T: Instance>() {
32 let regs = T::info().regs; 32 let regs = T::info().regs;
33 trace!("I2C interrupt triggered");
33 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 34 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
34 // other stuff, so we wake the task on every interrupt. 35 // other stuff, so we wake the task on every interrupt.
35 T::state().waker.wake(); 36 T::state().waker.wake();
@@ -92,6 +93,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
92 self.info.regs.cr1().modify(|reg| { 93 self.info.regs.cr1().modify(|reg| {
93 reg.set_pe(true); 94 reg.set_pe(true);
94 }); 95 });
96 trace!("i2c v1 init complete");
95 } 97 }
96 98
97 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> { 99 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
@@ -151,7 +153,13 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
151 Ok(sr1) 153 Ok(sr1)
152 } 154 }
153 155
154 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { 156 fn write_bytes(
157 &mut self,
158 address: u8,
159 write_buffer: &[u8],
160 timeout: Timeout,
161 frame: FrameOptions,
162 ) -> Result<(), Error> {
155 if frame.send_start() { 163 if frame.send_start() {
156 // Send a START condition 164 // Send a START condition
157 165
@@ -170,7 +178,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
170 } 178 }
171 179
172 // Set up current address we're trying to talk to 180 // Set up current address we're trying to talk to
173 self.info.regs.dr().write(|reg| reg.set_dr(addr << 1)); 181 self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
174 182
175 // Wait until address was sent 183 // Wait until address was sent
176 // Wait for the address to be acknowledged 184 // Wait for the address to be acknowledged
@@ -184,7 +192,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
184 } 192 }
185 193
186 // Send bytes 194 // Send bytes
187 for c in bytes { 195 for c in write_buffer {
188 self.send_byte(*c, timeout)?; 196 self.send_byte(*c, timeout)?;
189 } 197 }
190 198
@@ -236,12 +244,12 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
236 244
237 fn blocking_read_timeout( 245 fn blocking_read_timeout(
238 &mut self, 246 &mut self,
239 addr: u8, 247 address: u8,
240 buffer: &mut [u8], 248 read_buffer: &mut [u8],
241 timeout: Timeout, 249 timeout: Timeout,
242 frame: FrameOptions, 250 frame: FrameOptions,
243 ) -> Result<(), Error> { 251 ) -> Result<(), Error> {
244 let Some((last, buffer)) = buffer.split_last_mut() else { 252 let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else {
245 return Err(Error::Overrun); 253 return Err(Error::Overrun);
246 }; 254 };
247 255
@@ -263,7 +271,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
263 } 271 }
264 272
265 // Set up current address we're trying to talk to 273 // Set up current address we're trying to talk to
266 self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1)); 274 self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1));
267 275
268 // Wait until address was sent 276 // Wait until address was sent
269 // Wait for the address to be acknowledged 277 // Wait for the address to be acknowledged
@@ -276,7 +284,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
276 } 284 }
277 285
278 // Receive bytes into buffer 286 // Receive bytes into buffer
279 for c in buffer { 287 for c in read_buffer {
280 *c = self.recv_byte(timeout)?; 288 *c = self.recv_byte(timeout)?;
281 } 289 }
282 290
@@ -291,37 +299,42 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
291 }); 299 });
292 300
293 // Receive last byte 301 // Receive last byte
294 *last = self.recv_byte(timeout)?; 302 *last_byte = self.recv_byte(timeout)?;
295 303
296 // Fallthrough is success 304 // Fallthrough is success
297 Ok(()) 305 Ok(())
298 } 306 }
299 307
300 /// Blocking read. 308 /// Blocking read.
301 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 309 pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
302 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) 310 self.blocking_read_timeout(address, read_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)
303 } 311 }
304 312
305 /// Blocking write. 313 /// Blocking write.
306 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 314 pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
307 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; 315 self.write_bytes(address, write_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)?;
308 316
309 // Fallthrough is success 317 // Fallthrough is success
310 Ok(()) 318 Ok(())
311 } 319 }
312 320
313 /// Blocking write, restart, read. 321 /// Blocking write, restart, read.
314 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 322 pub fn blocking_write_read(
323 &mut self,
324 address: u8,
325 write_buffer: &[u8],
326 read_buffer: &mut [u8],
327 ) -> Result<(), Error> {
315 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 328 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
316 // stop condition below. 329 // stop condition below.
317 if read.is_empty() { 330 if read_buffer.is_empty() {
318 return Err(Error::Overrun); 331 return Err(Error::Overrun);
319 } 332 }
320 333
321 let timeout = self.timeout(); 334 let timeout = self.timeout();
322 335
323 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; 336 self.write_bytes(address, write_buffer, timeout, FrameOptions::FirstFrame)?;
324 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; 337 self.blocking_read_timeout(address, read_buffer, timeout, FrameOptions::FirstAndLastFrame)?;
325 338
326 Ok(()) 339 Ok(())
327 } 340 }
@@ -331,32 +344,43 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
331 /// Consecutive operations of same type are merged. See [transaction contract] for details. 344 /// Consecutive operations of same type are merged. See [transaction contract] for details.
332 /// 345 ///
333 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 346 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
334 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 347 pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
335 let timeout = self.timeout(); 348 let timeout = self.timeout();
336 349
337 for (op, frame) in operation_frames(operations)? { 350 for (op, frame) in operation_frames(operations)? {
338 match op { 351 match op {
339 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, 352 Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, frame)?,
340 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, 353 Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, frame)?,
341 } 354 }
342 } 355 }
343 356
344 Ok(()) 357 Ok(())
345 } 358 }
346 359
347 // Async 360 /// Can be used by both blocking and async implementations
348
349 #[inline] // pretty sure this should always be inlined 361 #[inline] // pretty sure this should always be inlined
350 fn enable_interrupts(info: &'static Info) -> () { 362 fn enable_interrupts(info: &'static Info) {
351 info.regs.cr2().modify(|w| { 363 // The interrupt handler disables interrupts globally, so we need to re-enable them
352 w.set_iterren(true); 364 // This must be done in a critical section to avoid races
353 w.set_itevten(true); 365 critical_section::with(|_| {
366 info.regs.cr2().modify(|w| {
367 w.set_iterren(true);
368 w.set_itevten(true);
369 });
354 }); 370 });
355 } 371 }
372
373 /// Can be used by both blocking and async implementations
374 fn clear_stop_flag(info: &'static Info) {
375 trace!("I2C slave: clearing STOPF flag (v1 sequence)");
376 // v1 requires: READ SR1 then WRITE CR1 to clear STOPF
377 let _ = info.regs.sr1().read();
378 info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF
379 }
356} 380}
357 381
358impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 382impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
359 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { 383 async fn write_frame(&mut self, address: u8, write_buffer: &[u8], frame: FrameOptions) -> Result<(), Error> {
360 self.info.regs.cr2().modify(|w| { 384 self.info.regs.cr2().modify(|w| {
361 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 385 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
362 // reception. 386 // reception.
@@ -439,7 +463,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
439 // this address from the memory after each TxE event. 463 // this address from the memory after each TxE event.
440 let dst = self.info.regs.dr().as_ptr() as *mut u8; 464 let dst = self.info.regs.dr().as_ptr() as *mut u8;
441 465
442 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 466 self.tx_dma
467 .as_mut()
468 .unwrap()
469 .write(write_buffer, dst, Default::default())
443 }; 470 };
444 471
445 // Wait for bytes to be sent, or an error to occur. 472 // Wait for bytes to be sent, or an error to occur.
@@ -501,28 +528,28 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
501 } 528 }
502 529
503 /// Write. 530 /// Write.
504 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 531 pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
505 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 532 self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame)
506 .await?; 533 .await?;
507 534
508 Ok(()) 535 Ok(())
509 } 536 }
510 537
511 /// Read. 538 /// Read.
512 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 539 pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
513 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 540 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
514 .await?; 541 .await?;
515 542
516 Ok(()) 543 Ok(())
517 } 544 }
518 545
519 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { 546 async fn read_frame(&mut self, address: u8, read_buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
520 if buffer.is_empty() { 547 if read_buffer.is_empty() {
521 return Err(Error::Overrun); 548 return Err(Error::Overrun);
522 } 549 }
523 550
524 // Some branches below depend on whether the buffer contains only a single byte. 551 // Some branches below depend on whether the buffer contains only a single byte.
525 let single_byte = buffer.len() == 1; 552 let single_byte = read_buffer.len() == 1;
526 553
527 self.info.regs.cr2().modify(|w| { 554 self.info.regs.cr2().modify(|w| {
528 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 555 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
@@ -612,7 +639,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
612 self.info.regs.sr2().read(); 639 self.info.regs.sr2().read();
613 } else { 640 } else {
614 // Before starting reception of single byte (but without START condition, i.e. in case 641 // Before starting reception of single byte (but without START condition, i.e. in case
615 // of continued frame), program NACK to emit at end of this byte. 642 // of merged operations), program NACK to emit at end of this byte.
616 if frame.send_nack() && single_byte { 643 if frame.send_nack() && single_byte {
617 self.info.regs.cr1().modify(|w| { 644 self.info.regs.cr1().modify(|w| {
618 w.set_ack(false); 645 w.set_ack(false);
@@ -634,7 +661,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
634 // from this address from the memory after each RxE event. 661 // from this address from the memory after each RxE event.
635 let src = self.info.regs.dr().as_ptr() as *mut u8; 662 let src = self.info.regs.dr().as_ptr() as *mut u8;
636 663
637 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 664 self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default())
638 }; 665 };
639 666
640 // Wait for bytes to be received, or an error to occur. 667 // Wait for bytes to be received, or an error to occur.
@@ -673,15 +700,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
673 } 700 }
674 701
675 /// Write, restart, read. 702 /// Write, restart, read.
676 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 703 pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> {
677 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 704 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
678 // stop condition below. 705 // stop condition below.
679 if read.is_empty() { 706 if read_buffer.is_empty() {
680 return Err(Error::Overrun); 707 return Err(Error::Overrun);
681 } 708 }
682 709
683 self.write_frame(address, write, FrameOptions::FirstFrame).await?; 710 self.write_frame(address, write_buffer, FrameOptions::FirstFrame)
684 self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await 711 .await?;
712 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
713 .await
685 } 714 }
686 715
687 /// Transaction with operations. 716 /// Transaction with operations.
@@ -689,11 +718,11 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
689 /// Consecutive operations of same type are merged. See [transaction contract] for details. 718 /// Consecutive operations of same type are merged. See [transaction contract] for details.
690 /// 719 ///
691 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 720 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
692 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 721 pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
693 for (op, frame) in operation_frames(operations)? { 722 for (op, frame) in operation_frames(operations)? {
694 match op { 723 match op {
695 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 724 Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?,
696 Operation::Write(write) => self.write_frame(addr, write, frame).await?, 725 Operation::Write(write_buffer) => self.write_frame(address, write_buffer, frame).await?,
697 } 726 }
698 } 727 }
699 728
@@ -729,12 +758,956 @@ impl Duty {
729 } 758 }
730} 759}
731 760
761/// Result of attempting to send a byte in slave transmitter mode
762#[derive(Debug, PartialEq)]
763enum TransmitResult {
764 /// Byte sent and ACKed by master - continue transmission
765 Acknowledged,
766 /// Byte sent but NACKed by master - normal end of read transaction
767 NotAcknowledged,
768 /// STOP condition detected - master terminated transaction
769 Stopped,
770 /// RESTART condition detected - master starting new transaction
771 Restarted,
772}
773
774/// Result of attempting to receive a byte in slave receiver mode
775#[derive(Debug, PartialEq)]
776enum ReceiveResult {
777 /// Data byte successfully received
778 Data(u8),
779 /// STOP condition detected - end of write transaction
780 Stopped,
781 /// RESTART condition detected - master starting new transaction
782 Restarted,
783}
784
785/// Enumeration of slave transaction termination conditions
786#[derive(Debug, Clone, Copy, PartialEq)]
787#[cfg_attr(feature = "defmt", derive(defmt::Format))]
788enum SlaveTermination {
789 /// STOP condition received - normal end of transaction
790 Stop,
791 /// RESTART condition received - master starting new transaction
792 Restart,
793 /// NACK received - normal end of read transaction
794 Nack,
795}
796
797impl<'d, M: PeriMode> I2c<'d, M, Master> {
798 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
799 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
800 let mut slave = I2c {
801 info: self.info,
802 state: self.state,
803 kernel_clock: self.kernel_clock,
804 tx_dma: self.tx_dma.take(), // Use take() to move ownership
805 rx_dma: self.rx_dma.take(), // Use take() to move ownership
806 #[cfg(feature = "time")]
807 timeout: self.timeout,
808 _phantom: PhantomData,
809 _phantom2: PhantomData,
810 _drop_guard: self._drop_guard, // Move the drop guard
811 };
812 slave.init_slave(slave_addr_config);
813 slave
814 }
815}
816
817// Address configuration methods
818impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
819 /// Initialize slave mode with address configuration
820 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
821 trace!("I2C slave: initializing with config={:?}", config);
822
823 // Disable peripheral for configuration
824 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
825
826 // Configure slave addresses
827 self.apply_address_configuration(config);
828
829 // Enable peripheral with slave settings
830 self.info.regs.cr1().modify(|reg| {
831 reg.set_pe(true);
832 reg.set_ack(true); // Enable acknowledgment for slave mode
833 reg.set_nostretch(false); // Allow clock stretching for processing time
834 });
835
836 trace!("I2C slave: initialization complete");
837 }
838
839 /// Apply the complete address configuration for slave mode
840 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
841 match config.addr {
842 OwnAddresses::OA1(addr) => {
843 self.configure_primary_address(addr);
844 self.disable_secondary_address();
845 }
846 OwnAddresses::OA2(oa2) => {
847 self.configure_default_primary_address();
848 self.configure_secondary_address(oa2.addr); // v1 ignores mask
849 }
850 OwnAddresses::Both { oa1, oa2 } => {
851 self.configure_primary_address(oa1);
852 self.configure_secondary_address(oa2.addr); // v1 ignores mask
853 }
854 }
855
856 // Configure general call detection
857 if config.general_call {
858 self.info.regs.cr1().modify(|w| w.set_engc(true));
859 }
860 }
861
862 /// Configure the primary address (OA1) register
863 fn configure_primary_address(&mut self, addr: Address) {
864 match addr {
865 Address::SevenBit(addr) => {
866 self.info.regs.oar1().write(|reg| {
867 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
868 reg.set_add(hw_addr);
869 reg.set_addmode(i2c::vals::Addmode::BIT7);
870 });
871 }
872 Address::TenBit(addr) => {
873 self.info.regs.oar1().write(|reg| {
874 reg.set_add(addr);
875 reg.set_addmode(i2c::vals::Addmode::BIT10);
876 });
877 }
878 }
879
880 // Set required bit 14 as per reference manual
881 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
882 }
883
884 /// Configure the secondary address (OA2) register
885 fn configure_secondary_address(&mut self, addr: u8) {
886 self.info.regs.oar2().write(|reg| {
887 reg.set_add2(addr);
888 reg.set_endual(i2c::vals::Endual::DUAL);
889 });
890 }
891
892 /// Set a default primary address when using OA2-only mode
893 fn configure_default_primary_address(&mut self) {
894 self.info.regs.oar1().write(|reg| {
895 reg.set_add(0); // Reserved address, safe to use
896 reg.set_addmode(i2c::vals::Addmode::BIT7);
897 });
898 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
899 }
900
901 /// Disable secondary address when not needed
902 fn disable_secondary_address(&mut self) {
903 self.info.regs.oar2().write(|reg| {
904 reg.set_endual(i2c::vals::Endual::SINGLE);
905 });
906 }
907}
908
909impl<'d, M: PeriMode> I2c<'d, M, MultiMaster> {
910 /// Listen for incoming I2C address match and return the command type
911 ///
912 /// This method blocks until the slave address is matched by a master.
913 /// Returns the command type (Read/Write) and the matched address.
914 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
915 trace!("I2C slave: starting blocking listen for address match");
916 let result = self.blocking_listen_with_timeout(self.timeout());
917 trace!("I2C slave: blocking listen complete, result={:?}", result);
918 result
919 }
920
921 /// Respond to a master read request by transmitting data
922 ///
923 /// Sends the provided data to the master. If the master requests more bytes
924 /// than available, padding bytes (0x00) are sent until the master terminates
925 /// the transaction with NACK.
926 ///
927 /// Returns the total number of bytes transmitted (including padding).
928 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
929 trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len());
930
931 if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? {
932 trace!("I2C slave: zero-length read detected");
933 return Ok(zero_length_result);
934 }
935
936 let result = self.transmit_to_master(data, self.timeout());
937 trace!("I2C slave: blocking respond_to_read complete, result={:?}", result);
938 result
939 }
940
941 /// Respond to a master write request by receiving data
942 ///
943 /// Receives data from the master into the provided buffer. If the master
944 /// sends more bytes than the buffer can hold, excess bytes are acknowledged
945 /// but discarded.
946 ///
947 /// Returns the number of bytes stored in the buffer (not total received).
948 pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
949 trace!(
950 "I2C slave: starting blocking respond_to_write, buffer_len={}",
951 buffer.len()
952 );
953 let result = self.receive_from_master(buffer, self.timeout());
954 trace!("I2C slave: blocking respond_to_write complete, result={:?}", result);
955 result
956 }
957
958 // Private implementation methods
959
960 /// Wait for address match and determine transaction type
961 fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result<SlaveCommand, Error> {
962 // Ensure interrupts are disabled for blocking operation
963 self.disable_i2c_interrupts();
964
965 // Wait for address match (ADDR flag)
966 loop {
967 let sr1 = Self::read_status_and_handle_errors(self.info)?;
968
969 if sr1.addr() {
970 // Address matched - read SR2 to get direction and clear ADDR flag
971 let sr2 = self.info.regs.sr2().read();
972 let direction = if sr2.tra() {
973 SlaveCommandKind::Read
974 } else {
975 SlaveCommandKind::Write
976 };
977
978 // Use the static method instead of the instance method
979 let matched_address = Self::decode_matched_address(sr2, self.info)?;
980 trace!(
981 "I2C slave: address matched, direction={:?}, addr={:?}",
982 direction, matched_address
983 );
984
985 return Ok(SlaveCommand {
986 kind: direction,
987 address: matched_address,
988 });
989 }
990
991 timeout.check()?;
992 }
993 }
994
995 /// Transmit data to master in response to read request
996 fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> {
997 let mut bytes_transmitted = 0;
998 let mut padding_count = 0;
999
1000 loop {
1001 let byte_to_send = if bytes_transmitted < data.len() {
1002 data[bytes_transmitted]
1003 } else {
1004 padding_count += 1;
1005 0x00 // Send padding bytes when data is exhausted
1006 };
1007
1008 match self.transmit_byte(byte_to_send, timeout)? {
1009 TransmitResult::Acknowledged => {
1010 bytes_transmitted += 1;
1011 }
1012 TransmitResult::NotAcknowledged => {
1013 bytes_transmitted += 1; // Count the NACKed byte
1014 break;
1015 }
1016 TransmitResult::Stopped | TransmitResult::Restarted => {
1017 break;
1018 }
1019 }
1020 }
1021
1022 if padding_count > 0 {
1023 trace!(
1024 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1025 data.len(),
1026 padding_count,
1027 bytes_transmitted
1028 );
1029 }
1030
1031 Ok(bytes_transmitted)
1032 }
1033
1034 /// Receive data from master during write request
1035 fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
1036 let mut bytes_stored = 0;
1037
1038 // Receive bytes that fit in buffer
1039 while bytes_stored < buffer.len() {
1040 match self.receive_byte(timeout)? {
1041 ReceiveResult::Data(byte) => {
1042 buffer[bytes_stored] = byte;
1043 bytes_stored += 1;
1044 }
1045 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1046 return Ok(bytes_stored);
1047 }
1048 }
1049 }
1050
1051 // Handle buffer overflow by discarding excess bytes
1052 if bytes_stored == buffer.len() {
1053 trace!("I2C slave: buffer full, discarding excess bytes");
1054 self.discard_excess_bytes(timeout)?;
1055 }
1056
1057 Ok(bytes_stored)
1058 }
1059
1060 /// Detect zero-length read pattern early
1061 ///
1062 /// Zero-length reads occur when a master sends START+ADDR+R followed immediately
1063 /// by NACK+STOP without wanting any data. This must be detected before attempting
1064 /// to transmit any bytes to avoid SDA line issues.
1065 fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result<Option<usize>, Error> {
1066 // Quick check for immediate termination signals
1067 let sr1 = self.info.regs.sr1().read();
1068
1069 // Check for immediate NACK (fastest zero-length pattern)
1070 if sr1.af() {
1071 self.clear_acknowledge_failure();
1072 return Ok(Some(0));
1073 }
1074
1075 // Check for immediate STOP (alternative zero-length pattern)
1076 if sr1.stopf() {
1077 Self::clear_stop_flag(self.info);
1078 return Ok(Some(0));
1079 }
1080
1081 // Give a brief window for master to send termination signals
1082 // This handles masters that have slight delays between address ACK and NACK
1083 const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window
1084
1085 for _ in 0..ZERO_LENGTH_DETECTION_CYCLES {
1086 let sr1 = self.info.regs.sr1().read();
1087
1088 // Immediate NACK indicates zero-length read
1089 if sr1.af() {
1090 self.clear_acknowledge_failure();
1091 return Ok(Some(0));
1092 }
1093
1094 // Immediate STOP indicates zero-length read
1095 if sr1.stopf() {
1096 Self::clear_stop_flag(self.info);
1097 return Ok(Some(0));
1098 }
1099
1100 // If TXE becomes ready, master is waiting for data - not zero-length
1101 if sr1.txe() {
1102 return Ok(None); // Proceed with normal transmission
1103 }
1104
1105 // If RESTART detected, handle as zero-length
1106 if sr1.addr() {
1107 return Ok(Some(0));
1108 }
1109 }
1110
1111 // No zero-length pattern detected within the window
1112 Ok(None)
1113 }
1114
1115 /// Discard excess bytes when buffer is full
1116 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> {
1117 let mut discarded_count = 0;
1118
1119 loop {
1120 match self.receive_byte(timeout)? {
1121 ReceiveResult::Data(_) => {
1122 discarded_count += 1;
1123 continue;
1124 }
1125 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1126 if discarded_count > 0 {
1127 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1128 }
1129 break;
1130 }
1131 }
1132 }
1133 Ok(())
1134 }
1135
1136 /// Send a single byte and wait for master's response
1137 fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result<TransmitResult, Error> {
1138 // Wait for transmit buffer ready
1139 self.wait_for_transmit_ready(timeout)?;
1140
1141 // Send the byte
1142 self.info.regs.dr().write(|w| w.set_dr(byte));
1143
1144 // Wait for transmission completion or master response
1145 self.wait_for_transmit_completion(timeout)
1146 }
1147
1148 /// Wait until transmit buffer is ready (TXE flag set)
1149 fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> {
1150 loop {
1151 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1152
1153 // Check for early termination conditions
1154 if let Some(result) = Self::check_early_termination(sr1) {
1155 return Err(self.handle_early_termination(result));
1156 }
1157
1158 if sr1.txe() {
1159 return Ok(()); // Ready to transmit
1160 }
1161
1162 timeout.check()?;
1163 }
1164 }
1165
1166 /// Wait for byte transmission completion or master response
1167 fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result<TransmitResult, Error> {
1168 loop {
1169 let sr1 = self.info.regs.sr1().read();
1170
1171 // Check flags in priority order
1172 if sr1.af() {
1173 self.clear_acknowledge_failure();
1174 return Ok(TransmitResult::NotAcknowledged);
1175 }
1176
1177 if sr1.btf() {
1178 return Ok(TransmitResult::Acknowledged);
1179 }
1180
1181 if sr1.stopf() {
1182 Self::clear_stop_flag(self.info);
1183 return Ok(TransmitResult::Stopped);
1184 }
1185
1186 if sr1.addr() {
1187 return Ok(TransmitResult::Restarted);
1188 }
1189
1190 // Check for other error conditions
1191 self.check_for_hardware_errors(sr1)?;
1192
1193 timeout.check()?;
1194 }
1195 }
1196
1197 /// Receive a single byte or detect transaction termination
1198 fn receive_byte(&mut self, timeout: Timeout) -> Result<ReceiveResult, Error> {
1199 loop {
1200 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1201
1202 // Check for received data first (prioritize data over control signals)
1203 if sr1.rxne() {
1204 let byte = self.info.regs.dr().read().dr();
1205 return Ok(ReceiveResult::Data(byte));
1206 }
1207
1208 // Check for transaction termination
1209 if sr1.addr() {
1210 return Ok(ReceiveResult::Restarted);
1211 }
1212
1213 if sr1.stopf() {
1214 Self::clear_stop_flag(self.info);
1215 return Ok(ReceiveResult::Stopped);
1216 }
1217
1218 timeout.check()?;
1219 }
1220 }
1221
1222 /// Determine which slave address was matched based on SR2 flags
1223 fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result<Address, Error> {
1224 if sr2.gencall() {
1225 Ok(Address::SevenBit(0x00)) // General call address
1226 } else if sr2.dualf() {
1227 // OA2 (secondary address) was matched
1228 let oar2 = info.regs.oar2().read();
1229 if oar2.endual() != i2c::vals::Endual::DUAL {
1230 return Err(Error::Bus); // Hardware inconsistency
1231 }
1232 Ok(Address::SevenBit(oar2.add2()))
1233 } else {
1234 // OA1 (primary address) was matched
1235 let oar1 = info.regs.oar1().read();
1236 match oar1.addmode() {
1237 i2c::vals::Addmode::BIT7 => {
1238 let addr = (oar1.add() >> 1) as u8;
1239 Ok(Address::SevenBit(addr))
1240 }
1241 i2c::vals::Addmode::BIT10 => Ok(Address::TenBit(oar1.add())),
1242 }
1243 }
1244 }
1245
1246 // Helper methods for hardware interaction
1247
1248 /// Read status register and handle I2C errors (except NACK in slave mode)
1249 fn read_status_and_handle_errors(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
1250 match Self::check_and_clear_error_flags(info) {
1251 Ok(sr1) => Ok(sr1),
1252 Err(Error::Nack) => {
1253 // In slave mode, NACK is normal protocol behavior, not an error
1254 Ok(info.regs.sr1().read())
1255 }
1256 Err(other_error) => Err(other_error),
1257 }
1258 }
1259
1260 /// Check for conditions that cause early termination of operations
1261 fn check_early_termination(sr1: i2c::regs::Sr1) -> Option<TransmitResult> {
1262 if sr1.stopf() {
1263 Some(TransmitResult::Stopped)
1264 } else if sr1.addr() {
1265 Some(TransmitResult::Restarted)
1266 } else if sr1.af() {
1267 Some(TransmitResult::NotAcknowledged)
1268 } else {
1269 None
1270 }
1271 }
1272
1273 /// Convert early termination to appropriate error
1274 fn handle_early_termination(&mut self, result: TransmitResult) -> Error {
1275 match result {
1276 TransmitResult::Stopped => {
1277 Self::clear_stop_flag(self.info);
1278 Error::Bus // Unexpected STOP during setup
1279 }
1280 TransmitResult::Restarted => {
1281 Error::Bus // Unexpected RESTART during setup
1282 }
1283 TransmitResult::NotAcknowledged => {
1284 self.clear_acknowledge_failure();
1285 Error::Bus // Unexpected NACK during setup
1286 }
1287 TransmitResult::Acknowledged => {
1288 unreachable!() // This should never be passed to this function
1289 }
1290 }
1291 }
1292
1293 /// Check for hardware-level I2C errors during transmission
1294 fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> {
1295 if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() {
1296 // Delegate to existing error handling
1297 Self::check_and_clear_error_flags(self.info)?;
1298 }
1299 Ok(())
1300 }
1301
1302 /// Disable I2C event and error interrupts for blocking operations
1303 fn disable_i2c_interrupts(&mut self) {
1304 self.info.regs.cr2().modify(|w| {
1305 w.set_itevten(false);
1306 w.set_iterren(false);
1307 });
1308 }
1309
1310 /// Clear the acknowledge failure flag
1311 fn clear_acknowledge_failure(&mut self) {
1312 self.info.regs.sr1().write(|reg| {
1313 reg.0 = !0;
1314 reg.set_af(false);
1315 });
1316 }
1317
1318 /// Configure DMA settings for slave operations (shared between read/write)
1319 fn setup_slave_dma_base(&mut self) {
1320 self.info.regs.cr2().modify(|w| {
1321 w.set_itbufen(false); // Always disable buffer interrupts when using DMA
1322 w.set_dmaen(true); // Enable DMA requests
1323 w.set_last(false); // LAST bit not used in slave mode for v1 hardware
1324 });
1325 }
1326
1327 /// Disable DMA and interrupts in a critical section
1328 fn disable_dma_and_interrupts(info: &'static Info) {
1329 critical_section::with(|_| {
1330 info.regs.cr2().modify(|w| {
1331 w.set_dmaen(false);
1332 w.set_iterren(false);
1333 w.set_itevten(false);
1334 });
1335 });
1336 }
1337
1338 /// Check for early termination conditions during slave operations
1339 /// Returns Some(result) if termination detected, None to continue
1340 fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option<SlaveTermination> {
1341 if sr1.stopf() {
1342 Some(SlaveTermination::Stop)
1343 } else if sr1.addr() {
1344 Some(SlaveTermination::Restart)
1345 } else if sr1.af() {
1346 Some(SlaveTermination::Nack)
1347 } else {
1348 None
1349 }
1350 }
1351}
1352
1353impl<'d> I2c<'d, Async, MultiMaster> {
1354 /// Async listen for incoming I2C messages using interrupts
1355 ///
1356 /// Waits for a master to address this slave and returns the command type
1357 /// (Read/Write) and the matched address. This method will suspend until
1358 /// an address match occurs.
1359 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1360 trace!("I2C slave: starting async listen for address match");
1361 let state = self.state;
1362 let info = self.info;
1363
1364 Self::enable_interrupts(info);
1365
1366 let on_drop = OnDrop::new(|| {
1367 Self::disable_dma_and_interrupts(info);
1368 });
1369
1370 let result = poll_fn(|cx| {
1371 state.waker.register(cx.waker());
1372
1373 match Self::check_and_clear_error_flags(info) {
1374 Err(e) => {
1375 error!("I2C slave: error during listen: {:?}", e);
1376 Poll::Ready(Err(e))
1377 }
1378 Ok(sr1) => {
1379 if sr1.addr() {
1380 let sr2 = info.regs.sr2().read();
1381 let direction = if sr2.tra() {
1382 SlaveCommandKind::Read
1383 } else {
1384 SlaveCommandKind::Write
1385 };
1386
1387 let matched_address = match Self::decode_matched_address(sr2, info) {
1388 Ok(addr) => {
1389 trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr);
1390 addr
1391 }
1392 Err(e) => {
1393 error!("I2C slave: failed to decode matched address: {:?}", e);
1394 return Poll::Ready(Err(e));
1395 }
1396 };
1397
1398 Poll::Ready(Ok(SlaveCommand {
1399 kind: direction,
1400 address: matched_address,
1401 }))
1402 } else {
1403 Self::enable_interrupts(info);
1404 Poll::Pending
1405 }
1406 }
1407 }
1408 })
1409 .await;
1410
1411 drop(on_drop);
1412 trace!("I2C slave: listen complete, result={:?}", result);
1413 result
1414 }
1415
1416 /// Async respond to write command using RX DMA
1417 ///
1418 /// Receives data from the master into the provided buffer using DMA.
1419 /// If the master sends more bytes than the buffer can hold, excess bytes
1420 /// are acknowledged but discarded to prevent interrupt flooding.
1421 ///
1422 /// Returns the number of bytes stored in the buffer (not total received).
1423 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1424 trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len());
1425
1426 if buffer.is_empty() {
1427 warn!("I2C slave: respond_to_write called with empty buffer");
1428 return Err(Error::Overrun);
1429 }
1430
1431 let state = self.state;
1432 let info = self.info;
1433
1434 self.setup_slave_dma_base();
1435
1436 let on_drop = OnDrop::new(|| {
1437 Self::disable_dma_and_interrupts(info);
1438 });
1439
1440 info.regs.sr2().read();
1441
1442 let result = self.execute_slave_receive_transfer(buffer, state, info).await;
1443
1444 drop(on_drop);
1445 trace!("I2C slave: respond_to_write complete, result={:?}", result);
1446 result
1447 }
1448
1449 /// Async respond to read command using TX DMA
1450 ///
1451 /// Transmits data to the master using DMA. If the master requests more bytes
1452 /// than available in the data buffer, padding bytes (0x00) are sent until
1453 /// the master terminates the transaction with NACK, STOP, or RESTART.
1454 ///
1455 /// Returns the total number of bytes transmitted (data + padding).
1456 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
1457 trace!("I2C slave: starting respond_to_read, data_len={}", data.len());
1458
1459 if data.is_empty() {
1460 warn!("I2C slave: respond_to_read called with empty data");
1461 return Err(Error::Overrun);
1462 }
1463
1464 let state = self.state;
1465 let info = self.info;
1466
1467 self.setup_slave_dma_base();
1468
1469 let on_drop = OnDrop::new(|| {
1470 Self::disable_dma_and_interrupts(info);
1471 });
1472
1473 info.regs.sr2().read();
1474
1475 let result = self.execute_slave_transmit_transfer(data, state, info).await;
1476
1477 drop(on_drop);
1478 trace!("I2C slave: respond_to_read complete, result={:?}", result);
1479 result
1480 }
1481
1482 // === Private Transfer Execution Methods ===
1483
1484 /// Execute complete slave receive transfer with excess byte handling
1485 async fn execute_slave_receive_transfer(
1486 &mut self,
1487 buffer: &mut [u8],
1488 state: &'static State,
1489 info: &'static Info,
1490 ) -> Result<usize, Error> {
1491 let dma_transfer = unsafe {
1492 let src = info.regs.dr().as_ptr() as *mut u8;
1493 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1494 };
1495
1496 let i2c_monitor =
1497 Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]);
1498
1499 match select(dma_transfer, i2c_monitor).await {
1500 Either::Second(Err(e)) => {
1501 error!("I2C slave: error during receive transfer: {:?}", e);
1502 Self::disable_dma_and_interrupts(info);
1503 Err(e)
1504 }
1505 Either::First(_) => {
1506 trace!("I2C slave: DMA receive completed, handling excess bytes");
1507 Self::disable_dma_and_interrupts(info);
1508 self.handle_excess_bytes(state, info).await?;
1509 Ok(buffer.len())
1510 }
1511 Either::Second(Ok(termination)) => {
1512 trace!("I2C slave: receive terminated by I2C event: {:?}", termination);
1513 Self::disable_dma_and_interrupts(info);
1514 Ok(buffer.len())
1515 }
1516 }
1517 }
1518
1519 /// Execute complete slave transmit transfer with padding byte handling
1520 async fn execute_slave_transmit_transfer(
1521 &mut self,
1522 data: &[u8],
1523 state: &'static State,
1524 info: &'static Info,
1525 ) -> Result<usize, Error> {
1526 let dma_transfer = unsafe {
1527 let dst = info.regs.dr().as_ptr() as *mut u8;
1528 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default())
1529 };
1530
1531 let i2c_monitor = Self::create_termination_monitor(
1532 state,
1533 info,
1534 &[
1535 SlaveTermination::Stop,
1536 SlaveTermination::Restart,
1537 SlaveTermination::Nack,
1538 ],
1539 );
1540
1541 match select(dma_transfer, i2c_monitor).await {
1542 Either::Second(Err(e)) => {
1543 error!("I2C slave: error during transmit transfer: {:?}", e);
1544 Self::disable_dma_and_interrupts(info);
1545 Err(e)
1546 }
1547 Either::First(_) => {
1548 trace!("I2C slave: DMA transmit completed, handling padding bytes");
1549 Self::disable_dma_and_interrupts(info);
1550 let padding_count = self.handle_padding_bytes(state, info).await?;
1551 let total_bytes = data.len() + padding_count;
1552 trace!(
1553 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1554 data.len(),
1555 padding_count,
1556 total_bytes
1557 );
1558 Ok(total_bytes)
1559 }
1560 Either::Second(Ok(termination)) => {
1561 trace!("I2C slave: transmit terminated by I2C event: {:?}", termination);
1562 Self::disable_dma_and_interrupts(info);
1563 Ok(data.len())
1564 }
1565 }
1566 }
1567
1568 /// Create a future that monitors for specific slave termination conditions
1569 fn create_termination_monitor(
1570 state: &'static State,
1571 info: &'static Info,
1572 allowed_terminations: &'static [SlaveTermination],
1573 ) -> impl Future<Output = Result<SlaveTermination, Error>> {
1574 poll_fn(move |cx| {
1575 state.waker.register(cx.waker());
1576
1577 match Self::check_and_clear_error_flags(info) {
1578 Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => {
1579 Poll::Ready(Ok(SlaveTermination::Nack))
1580 }
1581 Err(e) => Poll::Ready(Err(e)),
1582 Ok(sr1) => {
1583 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1584 if allowed_terminations.contains(&termination) {
1585 // Handle the specific termination condition
1586 match termination {
1587 SlaveTermination::Stop => Self::clear_stop_flag(info),
1588 SlaveTermination::Nack => {
1589 info.regs.sr1().write(|reg| {
1590 reg.0 = !0;
1591 reg.set_af(false);
1592 });
1593 }
1594 SlaveTermination::Restart => {
1595 // ADDR flag will be handled by next listen() call
1596 }
1597 }
1598 Poll::Ready(Ok(termination))
1599 } else {
1600 // Unexpected termination condition
1601 Poll::Ready(Err(Error::Bus))
1602 }
1603 } else {
1604 Self::enable_interrupts(info);
1605 Poll::Pending
1606 }
1607 }
1608 }
1609 })
1610 }
1611
1612 /// Handle excess bytes after DMA buffer is full
1613 ///
1614 /// Reads and discards bytes until transaction termination to prevent interrupt flooding
1615 async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> {
1616 let mut discarded_count = 0;
1617
1618 poll_fn(|cx| {
1619 state.waker.register(cx.waker());
1620
1621 match Self::check_and_clear_error_flags(info) {
1622 Err(e) => {
1623 error!("I2C slave: error while discarding excess bytes: {:?}", e);
1624 Poll::Ready(Err(e))
1625 }
1626 Ok(sr1) => {
1627 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1628 match termination {
1629 SlaveTermination::Stop => Self::clear_stop_flag(info),
1630 SlaveTermination::Restart => {}
1631 SlaveTermination::Nack => unreachable!("NACK not expected during receive"),
1632 }
1633 if discarded_count > 0 {
1634 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1635 }
1636 return Poll::Ready(Ok(()));
1637 }
1638
1639 if sr1.rxne() {
1640 let _discarded_byte = info.regs.dr().read().dr();
1641 discarded_count += 1;
1642 Self::enable_interrupts(info);
1643 return Poll::Pending;
1644 }
1645
1646 Self::enable_interrupts(info);
1647 Poll::Pending
1648 }
1649 }
1650 })
1651 .await
1652 }
1653
1654 /// Handle padding bytes after DMA data is exhausted
1655 ///
1656 /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding
1657 async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<usize, Error> {
1658 let mut padding_count = 0;
1659
1660 poll_fn(|cx| {
1661 state.waker.register(cx.waker());
1662
1663 match Self::check_and_clear_error_flags(info) {
1664 Err(Error::Nack) => Poll::Ready(Ok(padding_count)),
1665 Err(e) => {
1666 error!("I2C slave: error while sending padding bytes: {:?}", e);
1667 Poll::Ready(Err(e))
1668 }
1669 Ok(sr1) => {
1670 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1671 match termination {
1672 SlaveTermination::Stop => Self::clear_stop_flag(info),
1673 SlaveTermination::Restart => {}
1674 SlaveTermination::Nack => {
1675 info.regs.sr1().write(|reg| {
1676 reg.0 = !0;
1677 reg.set_af(false);
1678 });
1679 }
1680 }
1681 return Poll::Ready(Ok(padding_count));
1682 }
1683
1684 if sr1.txe() {
1685 info.regs.dr().write(|w| w.set_dr(0x00));
1686 padding_count += 1;
1687 Self::enable_interrupts(info);
1688 return Poll::Pending;
1689 }
1690
1691 Self::enable_interrupts(info);
1692 Poll::Pending
1693 }
1694 }
1695 })
1696 .await
1697 }
1698}
1699
1700/// Timing configuration for I2C v1 hardware
1701///
1702/// This struct encapsulates the complex timing calculations required for STM32 I2C v1
1703/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of
1704/// the unified TIMINGR register found in v2 hardware.
732struct Timings { 1705struct Timings {
733 freq: u8, 1706 freq: u8, // APB frequency in MHz for CR2.FREQ register
734 mode: Mode, 1707 mode: Mode, // Standard or Fast mode selection
735 trise: u8, 1708 trise: u8, // Rise time compensation value
736 ccr: u16, 1709 ccr: u16, // Clock control register value
737 duty: Duty, 1710 duty: Duty, // Fast mode duty cycle selection
738} 1711}
739 1712
740impl Timings { 1713impl Timings {
@@ -762,11 +1735,7 @@ impl Timings {
762 mode = Mode::Standard; 1735 mode = Mode::Standard;
763 ccr = { 1736 ccr = {
764 let ccr = clock / (frequency * 2); 1737 let ccr = clock / (frequency * 2);
765 if ccr < 4 { 1738 if ccr < 4 { 4 } else { ccr }
766 4
767 } else {
768 ccr
769 }
770 }; 1739 };
771 } else { 1740 } else {
772 const DUTYCYCLE: u8 = 0; 1741 const DUTYCYCLE: u8 = 0;
@@ -775,14 +1744,10 @@ impl Timings {
775 duty = Duty::Duty2_1; 1744 duty = Duty::Duty2_1;
776 ccr = clock / (frequency * 3); 1745 ccr = clock / (frequency * 3);
777 ccr = if ccr < 1 { 1 } else { ccr }; 1746 ccr = if ccr < 1 { 1 } else { ccr };
778
779 // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
780 } else { 1747 } else {
781 duty = Duty::Duty16_9; 1748 duty = Duty::Duty16_9;
782 ccr = clock / (frequency * 25); 1749 ccr = clock / (frequency * 25);
783 ccr = if ccr < 1 { 1 } else { ccr }; 1750 ccr = if ccr < 1 { 1 } else { ccr };
784
785 // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
786 } 1751 }
787 } 1752 }
788 1753
@@ -792,11 +1757,6 @@ impl Timings {
792 ccr: ccr as u16, 1757 ccr: ccr as u16,
793 duty, 1758 duty,
794 mode, 1759 mode,
795 //prescale: presc_reg,
796 //scll,
797 //sclh,
798 //sdadel,
799 //scldel,
800 } 1760 }
801 } 1761 }
802} 1762}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 0bfc795ac..61e550ad4 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -2,7 +2,7 @@ use core::cmp;
2use core::future::poll_fn; 2use core::future::poll_fn;
3use core::task::Poll; 3use core::task::Poll;
4 4
5use config::{Address, OwnAddresses, OA2}; 5use config::{Address, OA2, OwnAddresses};
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::drop::OnDrop; 7use embassy_hal_internal::drop::OnDrop;
8use embedded_hal_1::i2c::Operation; 8use embedded_hal_1::i2c::Operation;
@@ -70,6 +70,11 @@ fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) {
70} 70}
71 71
72pub(crate) unsafe fn on_interrupt<T: Instance>() { 72pub(crate) unsafe fn on_interrupt<T: Instance>() {
73 // restore the clocks to their last configured state as
74 // much is lost in STOP modes
75 #[cfg(all(feature = "low-power", stm32wlex))]
76 crate::low_power::Executor::on_wakeup_irq();
77
73 let regs = T::info().regs; 78 let regs = T::info().regs;
74 let isr = regs.isr().read(); 79 let isr = regs.isr().read();
75 80
@@ -93,6 +98,27 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
93} 98}
94 99
95impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { 100impl<'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
96 pub(crate) fn init(&mut self, config: Config) { 122 pub(crate) fn init(&mut self, config: Config) {
97 self.info.regs.cr1().modify(|reg| { 123 self.info.regs.cr1().modify(|reg| {
98 reg.set_pe(false); 124 reg.set_pe(false);
@@ -142,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
142 // `buffer`. The START bit can be set even if the bus 168 // `buffer`. The START bit can be set even if the bus
143 // is BUSY or I2C is in slave mode. 169 // is BUSY or I2C is in slave mode.
144 170
145 let reload = if reload {
146 i2c::vals::Reload::NOT_COMPLETED
147 } else {
148 i2c::vals::Reload::COMPLETED
149 };
150
151 info.regs.cr2().modify(|w| { 171 info.regs.cr2().modify(|w| {
152 w.set_sadd(address.addr() << 1); 172 w.set_sadd(address.addr() << 1);
153 w.set_add10(address.add_mode()); 173 w.set_add10(address.add_mode());
@@ -155,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
155 w.set_nbytes(length as u8); 175 w.set_nbytes(length as u8);
156 w.set_start(true); 176 w.set_start(true);
157 w.set_autoend(stop.autoend()); 177 w.set_autoend(stop.autoend());
158 w.set_reload(reload); 178 w.set_reload(Self::to_reload(reload));
159 }); 179 });
160 180
161 Ok(()) 181 Ok(())
@@ -167,28 +187,25 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
167 length: usize, 187 length: usize,
168 stop: Stop, 188 stop: Stop,
169 reload: bool, 189 reload: bool,
190 restart: bool,
170 timeout: Timeout, 191 timeout: Timeout,
171 ) -> Result<(), Error> { 192 ) -> Result<(), Error> {
172 assert!(length < 256); 193 assert!(length < 256);
173 194
174 // Wait for any previous address sequence to end 195 if !restart {
175 // automatically. This could be up to 50% of a bus 196 // Wait for any previous address sequence to end
176 // cycle (ie. up to 0.5/freq) 197 // automatically. This could be up to 50% of a bus
177 while info.regs.cr2().read().start() { 198 // cycle (ie. up to 0.5/freq)
178 timeout.check()?; 199 while info.regs.cr2().read().start() {
179 } 200 timeout.check()?;
201 }
180 202
181 // Wait for the bus to be free 203 // Wait for the bus to be free
182 while info.regs.isr().read().busy() { 204 while info.regs.isr().read().busy() {
183 timeout.check()?; 205 timeout.check()?;
206 }
184 } 207 }
185 208
186 let reload = if reload {
187 i2c::vals::Reload::NOT_COMPLETED
188 } else {
189 i2c::vals::Reload::COMPLETED
190 };
191
192 // Set START and prepare to send `bytes`. The 209 // Set START and prepare to send `bytes`. The
193 // 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
194 // I2C is in slave mode. 211 // I2C is in slave mode.
@@ -199,28 +216,36 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
199 w.set_nbytes(length as u8); 216 w.set_nbytes(length as u8);
200 w.set_start(true); 217 w.set_start(true);
201 w.set_autoend(stop.autoend()); 218 w.set_autoend(stop.autoend());
202 w.set_reload(reload); 219 w.set_reload(Self::to_reload(reload));
203 }); 220 });
204 221
205 Ok(()) 222 Ok(())
206 } 223 }
207 224
208 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> {
209 assert!(length < 256 && length > 0); 232 assert!(length < 256 && length > 0);
210 233
211 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 }
212 timeout.check()?; 242 timeout.check()?;
213 } 243 }
214 244
215 let will_reload = if will_reload {
216 i2c::vals::Reload::NOT_COMPLETED
217 } else {
218 i2c::vals::Reload::COMPLETED
219 };
220
221 info.regs.cr2().modify(|w| { 245 info.regs.cr2().modify(|w| {
222 w.set_nbytes(length as u8); 246 w.set_nbytes(length as u8);
223 w.set_reload(will_reload); 247 w.set_reload(Self::to_reload(will_reload));
248 w.set_autoend(stop.autoend());
224 }); 249 });
225 250
226 Ok(()) 251 Ok(())
@@ -364,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
364 loop { 389 loop {
365 let isr = self.info.regs.isr().read(); 390 let isr = self.info.regs.isr().read();
366 self.error_occurred(&isr, timeout)?; 391 self.error_occurred(&isr, timeout)?;
367 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() {
368 return Ok(()); 395 return Ok(());
369 } 396 }
370 timeout.check()?; 397 timeout.check()?;
@@ -391,14 +418,20 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
391 address, 418 address,
392 read.len().min(255), 419 read.len().min(255),
393 Stop::Automatic, 420 Stop::Automatic,
394 last_chunk_idx != 0, 421 last_chunk_idx != 0, // reload
395 restart, 422 restart,
396 timeout, 423 timeout,
397 )?; 424 )?;
398 425
399 for (number, chunk) in read.chunks_mut(255).enumerate() { 426 for (number, chunk) in read.chunks_mut(255).enumerate() {
400 if number != 0 { 427 if number != 0 {
401 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 )?;
402 } 435 }
403 436
404 for byte in chunk { 437 for byte in chunk {
@@ -436,6 +469,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
436 write.len().min(255), 469 write.len().min(255),
437 Stop::Software, 470 Stop::Software,
438 last_chunk_idx != 0, 471 last_chunk_idx != 0,
472 false, // restart
439 timeout, 473 timeout,
440 ) { 474 ) {
441 if send_stop { 475 if send_stop {
@@ -446,7 +480,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
446 480
447 for (number, chunk) in write.chunks(255).enumerate() { 481 for (number, chunk) in write.chunks(255).enumerate() {
448 if number != 0 { 482 if number != 0 {
449 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 )?;
450 } 490 }
451 491
452 for byte in chunk { 492 for byte in chunk {
@@ -502,9 +542,215 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
502 /// 542 ///
503 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 543 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
504 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> {
505 let _ = addr; 545 if operations.is_empty() {
506 let _ = operations; 546 return Err(Error::ZeroLengthTransfer);
507 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(())
508 } 754 }
509 755
510 /// Blocking write multiple buffers. 756 /// Blocking write multiple buffers.
@@ -526,6 +772,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
526 first_length.min(255), 772 first_length.min(255),
527 Stop::Software, 773 Stop::Software,
528 (first_length > 255) || (last_slice_index != 0), 774 (first_length > 255) || (last_slice_index != 0),
775 false, // restart
529 timeout, 776 timeout,
530 ) { 777 ) {
531 self.master_stop(); 778 self.master_stop();
@@ -547,6 +794,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
547 self.info, 794 self.info,
548 slice_len.min(255), 795 slice_len.min(255),
549 (idx != last_slice_index) || (slice_len > 255), 796 (idx != last_slice_index) || (slice_len > 255),
797 Stop::Software,
550 timeout, 798 timeout,
551 ) { 799 ) {
552 if err != Error::Nack { 800 if err != Error::Nack {
@@ -562,6 +810,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
562 self.info, 810 self.info,
563 chunk.len(), 811 chunk.len(),
564 (number != last_chunk_idx) || (idx != last_slice_index), 812 (number != last_chunk_idx) || (idx != last_slice_index),
813 Stop::Software,
565 timeout, 814 timeout,
566 ) { 815 ) {
567 if err != Error::Nack { 816 if err != Error::Nack {
@@ -605,6 +854,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
605 first_slice: bool, 854 first_slice: bool,
606 last_slice: bool, 855 last_slice: bool,
607 send_stop: bool, 856 send_stop: bool,
857 restart: bool,
608 timeout: Timeout, 858 timeout: Timeout,
609 ) -> Result<(), Error> { 859 ) -> Result<(), Error> {
610 let total_len = write.len(); 860 let total_len = write.len();
@@ -671,10 +921,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
671 total_len.min(255), 921 total_len.min(255),
672 Stop::Software, 922 Stop::Software,
673 (total_len > 255) || !last_slice, 923 (total_len > 255) || !last_slice,
924 restart,
674 timeout, 925 timeout,
675 )?; 926 )?;
676 } else { 927 } else {
677 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 )?;
678 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 935 self.info.regs.cr1().modify(|w| w.set_tcie(true));
679 } 936 }
680 } else if !(isr.tcr() || isr.tc()) { 937 } else if !(isr.tcr() || isr.tc()) {
@@ -683,9 +940,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
683 } else if remaining_len == 0 { 940 } else if remaining_len == 0 {
684 return Poll::Ready(Ok(())); 941 return Poll::Ready(Ok(()));
685 } else { 942 } else {
686 let last_piece = (remaining_len <= 255) && last_slice; 943 if let Err(e) = Self::reload(
687 944 self.info,
688 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 ) {
689 return Poll::Ready(Err(e)); 950 return Poll::Ready(Err(e));
690 } 951 }
691 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 952 self.info.regs.cr1().modify(|w| w.set_tcie(true));
@@ -697,10 +958,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
697 .await?; 958 .await?;
698 959
699 dma_transfer.await; 960 dma_transfer.await;
700 if last_slice { 961
701 // This should be done already 962 // Always wait for TC after DMA completes - needed for consecutive buffers
702 self.wait_tc(timeout)?; 963 self.wait_tc(timeout)?;
703 }
704 964
705 if last_slice & send_stop { 965 if last_slice & send_stop {
706 self.master_stop(); 966 self.master_stop();
@@ -775,7 +1035,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
775 address, 1035 address,
776 total_len.min(255), 1036 total_len.min(255),
777 Stop::Automatic, 1037 Stop::Automatic,
778 total_len > 255, 1038 total_len > 255, // reload
779 restart, 1039 restart,
780 timeout, 1040 timeout,
781 )?; 1041 )?;
@@ -783,12 +1043,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
783 return Poll::Ready(Ok(())); 1043 return Poll::Ready(Ok(()));
784 } 1044 }
785 } else if isr.tcr() { 1045 } else if isr.tcr() {
786 // poll_fn was woken without an interrupt present 1046 // Transfer Complete Reload - need to set up next chunk
787 return Poll::Pending;
788 } else {
789 let last_piece = remaining_len <= 255; 1047 let last_piece = remaining_len <= 255;
790 1048
791 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) {
792 return Poll::Ready(Err(e)); 1050 return Poll::Ready(Err(e));
793 } 1051 }
794 // Return here if we are on last chunk, 1052 // Return here if we are on last chunk,
@@ -797,6 +1055,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
797 return Poll::Ready(Ok(())); 1055 return Poll::Ready(Ok(()));
798 } 1056 }
799 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;
800 } 1061 }
801 1062
802 remaining_len = remaining_len.saturating_sub(255); 1063 remaining_len = remaining_len.saturating_sub(255);
@@ -814,12 +1075,14 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
814 1075
815 /// Write. 1076 /// Write.
816 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 1077 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
1078 #[cfg(all(feature = "low-power", stm32wlex))]
1079 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
817 let timeout = self.timeout(); 1080 let timeout = self.timeout();
818 if write.is_empty() { 1081 if write.is_empty() {
819 self.write_internal(address.into(), write, true, timeout) 1082 self.write_internal(address.into(), write, true, timeout)
820 } else { 1083 } else {
821 timeout 1084 timeout
822 .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))
823 .await 1086 .await
824 } 1087 }
825 } 1088 }
@@ -828,21 +1091,31 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
828 /// 1091 ///
829 /// The buffers are concatenated in a single write transaction. 1092 /// The buffers are concatenated in a single write transaction.
830 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { 1093 pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> {
1094 #[cfg(all(feature = "low-power", stm32wlex))]
1095 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
831 let timeout = self.timeout(); 1096 let timeout = self.timeout();
832 1097
833 if write.is_empty() { 1098 if write.is_empty() {
834 return Err(Error::ZeroLengthTransfer); 1099 return Err(Error::ZeroLengthTransfer);
835 } 1100 }
836 let mut iter = write.iter();
837 1101
1102 let mut iter = write.iter();
838 let mut first = true; 1103 let mut first = true;
839 let mut current = iter.next(); 1104 let mut current = iter.next();
1105
840 while let Some(c) = current { 1106 while let Some(c) = current {
841 let next = iter.next(); 1107 let next = iter.next();
842 let is_last = next.is_none(); 1108 let is_last = next.is_none();
843 1109
844 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 );
845 timeout.with(fut).await?; 1117 timeout.with(fut).await?;
1118
846 first = false; 1119 first = false;
847 current = next; 1120 current = next;
848 } 1121 }
@@ -851,6 +1124,8 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
851 1124
852 /// Read. 1125 /// Read.
853 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 1126 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
1127 #[cfg(all(feature = "low-power", stm32wlex))]
1128 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
854 let timeout = self.timeout(); 1129 let timeout = self.timeout();
855 1130
856 if buffer.is_empty() { 1131 if buffer.is_empty() {
@@ -863,12 +1138,14 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
863 1138
864 /// Write, restart, read. 1139 /// Write, restart, read.
865 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 1140 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
1141 #[cfg(all(feature = "low-power", stm32wlex))]
1142 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
866 let timeout = self.timeout(); 1143 let timeout = self.timeout();
867 1144
868 if write.is_empty() { 1145 if write.is_empty() {
869 self.write_internal(address.into(), write, false, timeout)?; 1146 self.write_internal(address.into(), write, false, timeout)?;
870 } else { 1147 } else {
871 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);
872 timeout.with(fut).await?; 1149 timeout.with(fut).await?;
873 } 1150 }
874 1151
@@ -888,9 +1165,301 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
888 /// 1165 ///
889 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 1166 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
890 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> {
891 let _ = addr; 1168 #[cfg(all(feature = "low-power", stm32wlex))]
892 let _ = operations; 1169 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
893 todo!() 1170
1171 if operations.is_empty() {
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(())
894 } 1463 }
895} 1464}
896 1465
@@ -1028,7 +1597,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1028 if number == 0 { 1597 if number == 0 {
1029 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1598 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1030 } else { 1599 } else {
1031 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 )?;
1032 } 1607 }
1033 1608
1034 let mut index = 0; 1609 let mut index = 0;
@@ -1077,7 +1652,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1077 if number == 0 { 1652 if number == 0 {
1078 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1653 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1079 } else { 1654 } else {
1080 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 )?;
1081 } 1662 }
1082 1663
1083 let mut index = 0; 1664 let mut index = 0;
@@ -1181,7 +1762,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1181 1762
1182 let regs = self.info.regs; 1763 let regs = self.info.regs;
1183 1764
1184 let dma_transfer = unsafe { 1765 let mut dma_transfer = unsafe {
1185 regs.cr1().modify(|w| { 1766 regs.cr1().modify(|w| {
1186 w.set_rxdmaen(true); 1767 w.set_rxdmaen(true);
1187 w.set_stopie(true); 1768 w.set_stopie(true);
@@ -1213,13 +1794,20 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1213 Poll::Pending 1794 Poll::Pending
1214 } else if isr.tcr() { 1795 } else if isr.tcr() {
1215 let is_last_slice = remaining_len <= 255; 1796 let is_last_slice = remaining_len <= 255;
1216 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 ) {
1217 return Poll::Ready(Err(e)); 1804 return Poll::Ready(Err(e));
1218 } 1805 }
1219 remaining_len = remaining_len.saturating_sub(255); 1806 remaining_len = remaining_len.saturating_sub(255);
1220 regs.cr1().modify(|w| w.set_tcie(true)); 1807 regs.cr1().modify(|w| w.set_tcie(true));
1221 Poll::Pending 1808 Poll::Pending
1222 } else if isr.stopf() { 1809 } else if isr.stopf() {
1810 remaining_len = remaining_len.saturating_add(dma_transfer.get_remaining_transfers() as usize);
1223 regs.icr().write(|reg| reg.set_stopcf(true)); 1811 regs.icr().write(|reg| reg.set_stopcf(true));
1224 let poll = Poll::Ready(Ok(total_len - remaining_len)); 1812 let poll = Poll::Ready(Ok(total_len - remaining_len));
1225 poll 1813 poll
@@ -1229,6 +1817,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1229 }) 1817 })
1230 .await?; 1818 .await?;
1231 1819
1820 dma_transfer.request_pause();
1232 dma_transfer.await; 1821 dma_transfer.await;
1233 1822
1234 drop(on_drop); 1823 drop(on_drop);
@@ -1258,7 +1847,8 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1258 w.set_txdmaen(false); 1847 w.set_txdmaen(false);
1259 w.set_stopie(false); 1848 w.set_stopie(false);
1260 w.set_tcie(false); 1849 w.set_tcie(false);
1261 }) 1850 });
1851 regs.isr().write(|w| w.set_txe(true));
1262 }); 1852 });
1263 1853
1264 let state = self.state; 1854 let state = self.state;
@@ -1274,13 +1864,24 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1274 Poll::Pending 1864 Poll::Pending
1275 } else if isr.tcr() { 1865 } else if isr.tcr() {
1276 let is_last_slice = remaining_len <= 255; 1866 let is_last_slice = remaining_len <= 255;
1277 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 ) {
1278 return Poll::Ready(Err(e)); 1874 return Poll::Ready(Err(e));
1279 } 1875 }
1280 remaining_len = remaining_len.saturating_sub(255); 1876 remaining_len = remaining_len.saturating_sub(255);
1281 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 1877 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1282 Poll::Pending 1878 Poll::Pending
1283 } else if isr.stopf() { 1879 } else if isr.stopf() {
1880 let mut leftover_bytes = dma_transfer.get_remaining_transfers();
1881 if !self.info.regs.isr().read().txe() {
1882 leftover_bytes = leftover_bytes.saturating_add(1);
1883 }
1884 remaining_len = remaining_len.saturating_add(leftover_bytes as usize);
1284 self.info.regs.icr().write(|reg| reg.set_stopcf(true)); 1885 self.info.regs.icr().write(|reg| reg.set_stopcf(true));
1285 if remaining_len > 0 { 1886 if remaining_len > 0 {
1286 dma_transfer.request_pause(); 1887 dma_transfer.request_pause();
@@ -1294,6 +1895,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1294 }) 1895 })
1295 .await?; 1896 .await?;
1296 1897
1898 dma_transfer.request_pause();
1297 dma_transfer.await; 1899 dma_transfer.await;
1298 1900
1299 drop(on_drop); 1901 drop(on_drop);
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index b6d3daf54..df077a3ae 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -3,12 +3,13 @@
3use embassy_futures::join::join; 3use embassy_futures::join::join;
4use stm32_metapac::spi::vals; 4use stm32_metapac::spi::vals;
5 5
6use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; 6use crate::Peri;
7use crate::dma::{ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer, ringbuffer};
7use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; 8use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed};
8use crate::mode::Async; 9use crate::mode::Async;
10use crate::spi::mode::Master;
9use crate::spi::{Config as SpiConfig, RegsExt as _, *}; 11use crate::spi::{Config as SpiConfig, RegsExt as _, *};
10use crate::time::Hertz; 12use crate::time::Hertz;
11use crate::Peri;
12 13
13/// I2S mode 14/// I2S mode
14#[derive(Copy, Clone)] 15#[derive(Copy, Clone)]
@@ -225,7 +226,7 @@ impl<'s, 'd, W: Word> Reader<'s, 'd, W> {
225pub struct I2S<'d, W: Word> { 226pub struct I2S<'d, W: Word> {
226 #[allow(dead_code)] 227 #[allow(dead_code)]
227 mode: Mode, 228 mode: Mode,
228 spi: Spi<'d, Async>, 229 spi: Spi<'d, Async, Master>,
229 txsd: Option<Peri<'d, AnyPin>>, 230 txsd: Option<Peri<'d, AnyPin>>,
230 rxsd: Option<Peri<'d, AnyPin>>, 231 rxsd: Option<Peri<'d, AnyPin>>,
231 ws: Option<Peri<'d, AnyPin>>, 232 ws: Option<Peri<'d, AnyPin>>,
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 670d8332c..10c4a820b 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -1,9 +1,11 @@
1//! Inter-Process Communication Controller (IPCC) 1//! Inter-Process Communication Controller (IPCC)
2 2
3use core::future::poll_fn; 3use core::future::poll_fn;
4use core::sync::atomic::{compiler_fence, Ordering}; 4use core::marker::PhantomData;
5use core::sync::atomic::{Ordering, compiler_fence};
5use core::task::Poll; 6use core::task::Poll;
6 7
8use embassy_hal_internal::Peri;
7use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
8 10
9use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
@@ -17,25 +19,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
17 unsafe fn on_interrupt() { 19 unsafe fn on_interrupt() {
18 let regs = IPCC::regs(); 20 let regs = IPCC::regs();
19 21
20 let channels = [
21 IpccChannel::Channel1,
22 IpccChannel::Channel2,
23 IpccChannel::Channel3,
24 IpccChannel::Channel4,
25 IpccChannel::Channel5,
26 IpccChannel::Channel6,
27 ];
28
29 // Status register gives channel occupied status. For rx, use cpu1. 22 // Status register gives channel occupied status. For rx, use cpu1.
30 let sr = regs.cpu(1).sr().read(); 23 let sr = regs.cpu(1).sr().read();
31 regs.cpu(0).mr().modify(|w| { 24 regs.cpu(0).mr().modify(|w| {
32 for channel in channels { 25 for index in 0..5 {
33 if sr.chf(channel as usize) { 26 if sr.chf(index as usize) {
34 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 27 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
35 w.set_chom(channel as usize, true); 28 w.set_chom(index as usize, true);
36 29
37 // There shouldn't be a race because the channel is masked only if the interrupt has fired 30 // There shouldn't be a race because the channel is masked only if the interrupt has fired
38 IPCC::state().rx_waker_for(channel).wake(); 31 IPCC::state().rx_waker_for(index).wake();
39 } 32 }
40 } 33 }
41 }) 34 })
@@ -49,25 +42,16 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
49 unsafe fn on_interrupt() { 42 unsafe fn on_interrupt() {
50 let regs = IPCC::regs(); 43 let regs = IPCC::regs();
51 44
52 let channels = [
53 IpccChannel::Channel1,
54 IpccChannel::Channel2,
55 IpccChannel::Channel3,
56 IpccChannel::Channel4,
57 IpccChannel::Channel5,
58 IpccChannel::Channel6,
59 ];
60
61 // Status register gives channel occupied status. For tx, use cpu0. 45 // Status register gives channel occupied status. For tx, use cpu0.
62 let sr = regs.cpu(0).sr().read(); 46 let sr = regs.cpu(0).sr().read();
63 regs.cpu(0).mr().modify(|w| { 47 regs.cpu(0).mr().modify(|w| {
64 for channel in channels { 48 for index in 0..5 {
65 if !sr.chf(channel as usize) { 49 if !sr.chf(index as usize) {
66 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 50 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
67 w.set_chfm(channel as usize, true); 51 w.set_chfm(index as usize, true);
68 52
69 // There shouldn't be a race because the channel is masked only if the interrupt has fired 53 // There shouldn't be a race because the channel is masked only if the interrupt has fired
70 IPCC::state().tx_waker_for(channel).wake(); 54 IPCC::state().tx_waker_for(index).wake();
71 } 55 }
72 } 56 }
73 }); 57 });
@@ -82,76 +66,55 @@ pub struct Config {
82 // reserved for future use 66 // reserved for future use
83} 67}
84 68
85/// Channel. 69/// IPCC TX Channel
86#[allow(missing_docs)] 70pub struct IpccTxChannel<'a> {
87#[derive(Debug, Clone, Copy)] 71 index: u8,
88#[repr(C)] 72 _lifetime: PhantomData<&'a mut usize>,
89pub enum IpccChannel {
90 Channel1 = 0,
91 Channel2 = 1,
92 Channel3 = 2,
93 Channel4 = 3,
94 Channel5 = 4,
95 Channel6 = 5,
96} 73}
97 74
98/// IPCC driver. 75impl<'a> IpccTxChannel<'a> {
99pub struct Ipcc; 76 pub(crate) const fn new(index: u8) -> Self {
100 77 core::assert!(index < 6);
101impl Ipcc {
102 /// Enable IPCC.
103 pub fn enable(_config: Config) {
104 rcc::enable_and_reset::<IPCC>();
105 IPCC::set_cpu2(true);
106
107 let regs = IPCC::regs();
108
109 regs.cpu(0).cr().modify(|w| {
110 w.set_rxoie(true);
111 w.set_txfie(true);
112 });
113
114 // enable interrupts
115 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
116 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
117 78
118 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() }; 79 Self {
119 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() }; 80 index: index,
81 _lifetime: PhantomData,
82 }
120 } 83 }
121 84
122 /// Send data to an IPCC channel. The closure is called to write the data when appropriate. 85 /// Send data to an IPCC channel. The closure is called to write the data when appropriate.
123 pub async fn send(channel: IpccChannel, f: impl FnOnce()) { 86 pub async fn send(&mut self, f: impl FnOnce()) {
124 let regs = IPCC::regs(); 87 let regs = IPCC::regs();
125 88
126 Self::flush(channel).await; 89 self.flush().await;
127 90
128 f(); 91 f();
129 92
130 compiler_fence(Ordering::SeqCst); 93 compiler_fence(Ordering::SeqCst);
131 94
132 trace!("ipcc: ch {}: send data", channel as u8); 95 trace!("ipcc: ch {}: send data", self.index as u8);
133 regs.cpu(0).scr().write(|w| w.set_chs(channel as usize, true)); 96 regs.cpu(0).scr().write(|w| w.set_chs(self.index as usize, true));
134 } 97 }
135 98
136 /// Wait for the tx channel to become clear 99 /// Wait for the tx channel to become clear
137 pub async fn flush(channel: IpccChannel) { 100 pub async fn flush(&mut self) {
138 let regs = IPCC::regs(); 101 let regs = IPCC::regs();
139 102
140 // This is a race, but is nice for debugging 103 // This is a race, but is nice for debugging
141 if regs.cpu(0).sr().read().chf(channel as usize) { 104 if regs.cpu(0).sr().read().chf(self.index as usize) {
142 trace!("ipcc: ch {}: wait for tx free", channel as u8); 105 trace!("ipcc: ch {}: wait for tx free", self.index as u8);
143 } 106 }
144 107
145 poll_fn(|cx| { 108 poll_fn(|cx| {
146 IPCC::state().tx_waker_for(channel).register(cx.waker()); 109 IPCC::state().tx_waker_for(self.index).register(cx.waker());
147 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt 110 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
148 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, false)); 111 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, false));
149 112
150 compiler_fence(Ordering::SeqCst); 113 compiler_fence(Ordering::SeqCst);
151 114
152 if !regs.cpu(0).sr().read().chf(channel as usize) { 115 if !regs.cpu(0).sr().read().chf(self.index as usize) {
153 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 116 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
154 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); 117 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
155 118
156 Poll::Ready(()) 119 Poll::Ready(())
157 } else { 120 } else {
@@ -160,27 +123,44 @@ impl Ipcc {
160 }) 123 })
161 .await; 124 .await;
162 } 125 }
126}
127
128/// IPCC RX Channel
129pub struct IpccRxChannel<'a> {
130 index: u8,
131 _lifetime: PhantomData<&'a mut usize>,
132}
133
134impl<'a> IpccRxChannel<'a> {
135 pub(crate) const fn new(index: u8) -> Self {
136 core::assert!(index < 6);
137
138 Self {
139 index: index,
140 _lifetime: PhantomData,
141 }
142 }
163 143
164 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate. 144 /// Receive data from an IPCC channel. The closure is called to read the data when appropriate.
165 pub async fn receive<R>(channel: IpccChannel, mut f: impl FnMut() -> Option<R>) -> R { 145 pub async fn receive<R>(&mut self, mut f: impl FnMut() -> Option<R>) -> R {
166 let regs = IPCC::regs(); 146 let regs = IPCC::regs();
167 147
168 loop { 148 loop {
169 // This is a race, but is nice for debugging 149 // This is a race, but is nice for debugging
170 if !regs.cpu(1).sr().read().chf(channel as usize) { 150 if !regs.cpu(1).sr().read().chf(self.index as usize) {
171 trace!("ipcc: ch {}: wait for rx occupied", channel as u8); 151 trace!("ipcc: ch {}: wait for rx occupied", self.index as u8);
172 } 152 }
173 153
174 poll_fn(|cx| { 154 poll_fn(|cx| {
175 IPCC::state().rx_waker_for(channel).register(cx.waker()); 155 IPCC::state().rx_waker_for(self.index).register(cx.waker());
176 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt 156 // If bit is set to 1 then interrupt is disabled; we want to enable the interrupt
177 regs.cpu(0).mr().modify(|w| w.set_chom(channel as usize, false)); 157 regs.cpu(0).mr().modify(|w| w.set_chom(self.index as usize, false));
178 158
179 compiler_fence(Ordering::SeqCst); 159 compiler_fence(Ordering::SeqCst);
180 160
181 if regs.cpu(1).sr().read().chf(channel as usize) { 161 if regs.cpu(1).sr().read().chf(self.index as usize) {
182 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt 162 // If bit is set to 1 then interrupt is disabled; we want to disable the interrupt
183 regs.cpu(0).mr().modify(|w| w.set_chfm(channel as usize, true)); 163 regs.cpu(0).mr().modify(|w| w.set_chfm(self.index as usize, true));
184 164
185 Poll::Ready(()) 165 Poll::Ready(())
186 } else { 166 } else {
@@ -189,21 +169,111 @@ impl Ipcc {
189 }) 169 })
190 .await; 170 .await;
191 171
192 trace!("ipcc: ch {}: read data", channel as u8); 172 trace!("ipcc: ch {}: read data", self.index as u8);
193 173
194 match f() { 174 match f() {
195 Some(ret) => return ret, 175 Some(ret) => return ret,
196 None => {} 176 None => {}
197 } 177 }
198 178
199 trace!("ipcc: ch {}: clear rx", channel as u8); 179 trace!("ipcc: ch {}: clear rx", self.index as u8);
200 compiler_fence(Ordering::SeqCst); 180 compiler_fence(Ordering::SeqCst);
201 // If the channel is clear and the read function returns none, fetch more data 181 // If the channel is clear and the read function returns none, fetch more data
202 regs.cpu(0).scr().write(|w| w.set_chc(channel as usize, true)); 182 regs.cpu(0).scr().write(|w| w.set_chc(self.index as usize, true));
203 } 183 }
204 } 184 }
205} 185}
206 186
187/// IPCC Channel
188pub struct IpccChannel<'a> {
189 index: u8,
190 _lifetime: PhantomData<&'a mut usize>,
191}
192
193impl<'a> IpccChannel<'a> {
194 pub(crate) const fn new(number: u8) -> Self {
195 core::assert!(number > 0 && number <= 6);
196
197 Self {
198 index: number - 1,
199 _lifetime: PhantomData,
200 }
201 }
202
203 /// Split into a tx and rx channel
204 pub const fn split(self) -> (IpccTxChannel<'a>, IpccRxChannel<'a>) {
205 (IpccTxChannel::new(self.index), IpccRxChannel::new(self.index))
206 }
207}
208
209/// IPCC driver.
210pub struct Ipcc {
211 _private: (),
212}
213
214impl Ipcc {
215 /// Creates a new HardwareSemaphore instance.
216 pub fn new<'d>(
217 _peripheral: Peri<'d, crate::peripherals::IPCC>,
218 _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
219 + interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>
220 + 'd,
221 _config: Config,
222 ) -> Self {
223 rcc::enable_and_reset::<IPCC>();
224 IPCC::set_cpu2(true);
225
226 let regs = IPCC::regs();
227
228 regs.cpu(0).cr().modify(|w| {
229 w.set_rxoie(true);
230 w.set_txfie(true);
231 });
232
233 // enable interrupts
234 crate::interrupt::typelevel::IPCC_C1_RX::unpend();
235 crate::interrupt::typelevel::IPCC_C1_TX::unpend();
236
237 unsafe { crate::interrupt::typelevel::IPCC_C1_RX::enable() };
238 unsafe { crate::interrupt::typelevel::IPCC_C1_TX::enable() };
239
240 Self { _private: () }
241 }
242
243 /// Split into a tx and rx channel
244 pub const fn split<'a>(self) -> [(IpccTxChannel<'a>, IpccRxChannel<'a>); 6] {
245 [
246 IpccChannel::new(1).split(),
247 IpccChannel::new(2).split(),
248 IpccChannel::new(3).split(),
249 IpccChannel::new(4).split(),
250 IpccChannel::new(5).split(),
251 IpccChannel::new(6).split(),
252 ]
253 }
254
255 /// Receive from a channel number
256 pub async unsafe fn receive<R>(number: u8, f: impl FnMut() -> Option<R>) -> R {
257 core::assert!(number > 0 && number <= 6);
258
259 IpccRxChannel::new(number - 1).receive(f).await
260 }
261
262 /// Send to a channel number
263 pub async unsafe fn send(number: u8, f: impl FnOnce()) {
264 core::assert!(number > 0 && number <= 6);
265
266 IpccTxChannel::new(number - 1).send(f).await
267 }
268
269 /// Send to a channel number
270 pub async unsafe fn flush(number: u8) {
271 core::assert!(number > 0 && number <= 6);
272
273 IpccTxChannel::new(number - 1).flush().await
274 }
275}
276
207impl SealedInstance for crate::peripherals::IPCC { 277impl SealedInstance for crate::peripherals::IPCC {
208 fn regs() -> crate::pac::ipcc::Ipcc { 278 fn regs() -> crate::pac::ipcc::Ipcc {
209 crate::pac::IPCC 279 crate::pac::IPCC
@@ -232,26 +302,12 @@ impl State {
232 } 302 }
233 } 303 }
234 304
235 const fn rx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 305 const fn rx_waker_for(&self, index: u8) -> &AtomicWaker {
236 match channel { 306 &self.rx_wakers[index as usize]
237 IpccChannel::Channel1 => &self.rx_wakers[0],
238 IpccChannel::Channel2 => &self.rx_wakers[1],
239 IpccChannel::Channel3 => &self.rx_wakers[2],
240 IpccChannel::Channel4 => &self.rx_wakers[3],
241 IpccChannel::Channel5 => &self.rx_wakers[4],
242 IpccChannel::Channel6 => &self.rx_wakers[5],
243 }
244 } 307 }
245 308
246 const fn tx_waker_for(&self, channel: IpccChannel) -> &AtomicWaker { 309 const fn tx_waker_for(&self, index: u8) -> &AtomicWaker {
247 match channel { 310 &self.tx_wakers[index as usize]
248 IpccChannel::Channel1 => &self.tx_wakers[0],
249 IpccChannel::Channel2 => &self.tx_wakers[1],
250 IpccChannel::Channel3 => &self.tx_wakers[2],
251 IpccChannel::Channel4 => &self.tx_wakers[3],
252 IpccChannel::Channel5 => &self.tx_wakers[4],
253 IpccChannel::Channel6 => &self.tx_wakers[5],
254 }
255 } 311 }
256} 312}
257 313
diff --git a/embassy-stm32/src/lcd.rs b/embassy-stm32/src/lcd.rs
new file mode 100644
index 000000000..ea29f1398
--- /dev/null
+++ b/embassy-stm32/src/lcd.rs
@@ -0,0 +1,510 @@
1//! LCD
2use core::marker::PhantomData;
3
4use embassy_hal_internal::{Peri, PeripheralType};
5
6use crate::gpio::{AfType, AnyPin, SealedPin};
7use crate::peripherals;
8use crate::rcc::{self, RccPeripheral};
9use crate::time::Hertz;
10
11#[cfg(any(stm32u0, stm32l073, stm32l083))]
12const NUM_SEGMENTS: u8 = 52;
13#[cfg(any(stm32wb, stm32l4x6, stm32l15x, stm32l162, stm32l4x3, stm32l4x6))]
14const NUM_SEGMENTS: u8 = 44;
15#[cfg(any(stm32l053, stm32l063, stm32l100))]
16const NUM_SEGMENTS: u8 = 32;
17
18/// LCD configuration struct
19#[non_exhaustive]
20#[derive(Debug, Clone, Copy)]
21pub struct Config {
22 #[cfg(lcd_v2)]
23 /// Enable the voltage output buffer for higher driving capability.
24 ///
25 /// The LCD driving capability is improved as buffers prevent the LCD capacitive loads from loading the resistor
26 /// bridge unacceptably and interfering with its voltage generation.
27 pub use_voltage_output_buffer: bool,
28 /// Enable SEG pin remapping. SEG[31:28] multiplexed with SEG[43:40]
29 pub use_segment_muxing: bool,
30 /// Bias selector
31 pub bias: Bias,
32 /// Duty selector
33 pub duty: Duty,
34 /// Internal or external voltage source
35 pub voltage_source: VoltageSource,
36 /// The frequency used to update the LCD with.
37 /// Should be between ~30 and ~100. Lower is better for power consumption, but has lower visual fidelity.
38 pub target_fps: Hertz,
39 /// LCD driver selector
40 pub drive: Drive,
41}
42
43impl Default for Config {
44 fn default() -> Self {
45 Self {
46 #[cfg(lcd_v2)]
47 use_voltage_output_buffer: false,
48 use_segment_muxing: false,
49 bias: Default::default(),
50 duty: Default::default(),
51 voltage_source: Default::default(),
52 target_fps: Hertz(60),
53 drive: Drive::Medium,
54 }
55 }
56}
57
58/// The number of voltage levels used when driving an LCD.
59/// Your LCD datasheet should tell you what to use.
60#[repr(u8)]
61#[derive(Debug, Default, Clone, Copy)]
62pub enum Bias {
63 /// 1/4 bias
64 #[default]
65 Quarter = 0b00,
66 /// 1/2 bias
67 Half = 0b01,
68 /// 1/3 bias
69 Third = 0b10,
70}
71
72/// The duty used by the LCD driver.
73///
74/// This is essentially how many COM pins you're using.
75#[repr(u8)]
76#[derive(Debug, Default, Clone, Copy)]
77pub enum Duty {
78 #[default]
79 /// Use a single COM pin
80 Static = 0b000,
81 /// Use two COM pins
82 Half = 0b001,
83 /// Use three COM pins
84 Third = 0b010,
85 /// Use four COM pins
86 Quarter = 0b011,
87 /// Use eight COM pins.
88 ///
89 /// In this mode, `COM[7:4]` outputs are available on `SEG[51:48]`.
90 /// This allows reducing the number of available segments.
91 Eigth = 0b100,
92}
93
94impl Duty {
95 fn num_com_pins(&self) -> u8 {
96 match self {
97 Duty::Static => 1,
98 Duty::Half => 2,
99 Duty::Third => 3,
100 Duty::Quarter => 4,
101 Duty::Eigth => 8,
102 }
103 }
104}
105
106/// Whether to use the internal or external voltage source to drive the LCD
107#[repr(u8)]
108#[derive(Debug, Default, Clone, Copy)]
109pub enum VoltageSource {
110 #[default]
111 /// Voltage stepup converter
112 Internal,
113 /// VLCD pin
114 External,
115}
116
117/// Defines the pulse duration in terms of ck_ps pulses.
118///
119/// A short pulse leads to lower power consumption, but displays with high internal resistance
120/// may need a longer pulse to achieve satisfactory contrast.
121/// Note that the pulse is never longer than one half prescaled LCD clock period.
122///
123/// Displays with high internal resistance may need a longer drive time to achieve satisfactory contrast.
124/// `PermanentHighDrive` is useful in this case if some additional power consumption can be tolerated.
125///
126/// Basically, for power usage, you want this as low as possible while still being able to use the LCD
127/// with a good enough contrast.
128#[repr(u8)]
129#[derive(Debug, Clone, Copy)]
130pub enum Drive {
131 /// Zero clock pulse on duration
132 Lowest = 0x00,
133 /// One clock pulse on duration
134 VeryLow = 0x01,
135 /// Two clock pulse on duration
136 Low = 0x02,
137 /// Three clock pulse on duration
138 Medium = 0x03,
139 /// Four clock pulse on duration
140 MediumHigh = 0x04,
141 /// Five clock pulse on duration
142 High = 0x05,
143 /// Six clock pulse on duration
144 VeryHigh = 0x06,
145 /// Seven clock pulse on duration
146 Highest = 0x07,
147 /// Enables the highdrive bit of the hardware
148 PermanentHighDrive = 0x09,
149}
150
151/// LCD driver.
152pub struct Lcd<'d, T: Instance> {
153 _peri: PhantomData<&'d mut T>,
154 duty: Duty,
155 ck_div: u32,
156}
157
158impl<'d, T: Instance> Lcd<'d, T> {
159 /// Initialize the lcd driver.
160 ///
161 /// The `pins` parameter must contain *all* segment and com pins that are connected to the LCD.
162 /// This is not further checked by this driver. Pins not routed to the LCD can be used for other purposes.
163 pub fn new<const N: usize>(
164 _peripheral: Peri<'d, T>,
165 config: Config,
166 vlcd_pin: Peri<'_, impl VlcdPin<T>>,
167 pins: [LcdPin<'d, T>; N],
168 ) -> Self {
169 rcc::enable_and_reset::<T>();
170
171 vlcd_pin.set_as_af(
172 vlcd_pin.af_num(),
173 AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh),
174 );
175
176 assert_eq!(
177 pins.iter().filter(|pin| !pin.is_seg).count(),
178 config.duty.num_com_pins() as usize,
179 "The number of provided COM pins is not the same as the duty configures"
180 );
181
182 // Set the pins
183 for pin in pins {
184 pin.pin.set_as_af(
185 pin.af_num,
186 AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh),
187 );
188 }
189
190 // Initialize the display ram to 0
191 for i in 0..8 {
192 T::regs().ram_com(i).low().write_value(0);
193 T::regs().ram_com(i).high().write_value(0);
194 }
195
196 // Calculate the clock dividers
197 let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc.to_hertz() }) else {
198 panic!("The LCD driver needs the RTC/LCD clock to be running");
199 };
200 let duty_divider = match config.duty {
201 Duty::Static => 1,
202 Duty::Half => 2,
203 Duty::Third => 3,
204 Duty::Quarter => 4,
205 Duty::Eigth => 8,
206 };
207 let target_clock = config.target_fps.0 * duty_divider;
208 let target_division = lcd_clk.0 / target_clock;
209
210 let mut ps = 0;
211 let mut div = 0;
212 let mut best_fps_match = u32::MAX;
213
214 for trial_div in 0..0xF {
215 let trial_ps = (target_division / (trial_div + 16))
216 .next_power_of_two()
217 .trailing_zeros();
218 let fps = lcd_clk.0 / ((1 << trial_ps) * (trial_div + 16)) / duty_divider;
219
220 if fps < config.target_fps.0 {
221 continue;
222 }
223
224 if fps < best_fps_match {
225 ps = trial_ps;
226 div = trial_div;
227 best_fps_match = fps;
228 }
229 }
230
231 let ck_div = lcd_clk.0 / ((1 << ps) * (div + 16));
232
233 trace!(
234 "lcd_clk: {}, fps: {}, ps: {}, div: {}, ck_div: {}",
235 lcd_clk, best_fps_match, ps, div, ck_div
236 );
237
238 if best_fps_match == u32::MAX || ps > 0xF {
239 panic!("Lcd clock error");
240 }
241
242 // Set the frame control
243 T::regs().fcr().modify(|w| {
244 w.set_ps(ps as u8);
245 w.set_div(div as u8);
246 w.set_cc(0b100); // Init in the middle-ish
247 w.set_dead(0b000);
248 w.set_pon(config.drive as u8 & 0x07);
249 w.set_hd((config.drive as u8 & !0x07) != 0);
250 });
251
252 // Wait for the frame control to synchronize
253 while !T::regs().sr().read().fcrsf() {}
254
255 // Set the control register values
256 T::regs().cr().modify(|w| {
257 #[cfg(lcd_v2)]
258 w.set_bufen(config.use_voltage_output_buffer);
259 w.set_mux_seg(config.use_segment_muxing);
260 w.set_bias(config.bias as u8);
261 w.set_duty(config.duty as u8);
262 w.set_vsel(matches!(config.voltage_source, VoltageSource::External));
263 });
264
265 // Enable the lcd
266 T::regs().cr().modify(|w| w.set_lcden(true));
267
268 // Wait for the lcd to be enabled
269 while !T::regs().sr().read().ens() {}
270
271 // Wait for the stepup converter to be ready
272 while !T::regs().sr().read().rdy() {}
273
274 Self {
275 _peri: PhantomData,
276 duty: config.duty,
277 ck_div,
278 }
279 }
280
281 /// Change the contrast by changing the voltage being used.
282 ///
283 /// This is from low at 0 to high at 7.
284 pub fn set_contrast_control(&mut self, value: u8) {
285 assert!((0..=7).contains(&value));
286 T::regs().fcr().modify(|w| w.set_cc(value));
287 }
288
289 /// Change the contrast by introducing a deadtime to the signals
290 /// where the voltages are held at 0V.
291 ///
292 /// This is from no dead time at 0 to high dead time at 7.
293 pub fn set_dead_time(&mut self, value: u8) {
294 assert!((0..=7).contains(&value));
295 T::regs()
296 .fcr()
297 .modify(|w: &mut stm32_metapac::lcd::regs::Fcr| w.set_dead(value));
298 }
299
300 /// Write data into the display RAM. This overwrites the data already in it for the specified com index.
301 ///
302 /// The `com_index` value determines which part of the RAM is written to.
303 /// The `segments` value is a bitmap where each bit represents whether a pixel is turned on or off.
304 ///
305 /// This function waits last update request to be finished, but does not submit the buffer to the LCD with a new request.
306 /// Submission has to be done manually using [Self::submit_frame].
307 pub fn write_com_segments(&mut self, com_index: u8, segments: u64) {
308 while T::regs().sr().read().udr() {}
309
310 assert!(
311 com_index < self.duty.num_com_pins(),
312 "Com index cannot be higher than number of configured com pins (through the Duty setting in the config)"
313 );
314
315 assert!(
316 segments.leading_zeros() >= 64 - self.num_segments() as u32,
317 "Invalid segment pixel set",
318 );
319
320 T::regs()
321 .ram_com(com_index as usize)
322 .low()
323 .write_value((segments & 0xFFFF_FFFF) as u32);
324 T::regs()
325 .ram_com(com_index as usize)
326 .high()
327 .write_value(((segments >> 32) & 0xFFFF_FFFF) as u32);
328 }
329
330 /// Read the data from the display RAM.
331 ///
332 /// The `com_index` value determines which part of the RAM is read from.
333 ///
334 /// This function waits for the last update request to be finished.
335 pub fn read_com_segments(&self, com_index: u8) -> u64 {
336 while T::regs().sr().read().udr() {}
337
338 assert!(
339 com_index < self.duty.num_com_pins(),
340 "Com index cannot be higher than number of configured com pins (through the Duty setting in the config)"
341 );
342
343 let low = T::regs().ram_com(com_index as usize).low().read();
344 let high = T::regs().ram_com(com_index as usize).high().read();
345
346 ((high as u64) << 32) | low as u64
347 }
348
349 /// Submit the current RAM data to the LCD.
350 ///
351 /// This function waits until the RAM is writable, but does not wait for the frame to be drawn.
352 pub fn submit_frame(&mut self) {
353 while T::regs().sr().read().udr() {}
354 // Clear the update done flag
355 T::regs().sr().write(|w| w.set_udd(true));
356 // Set the update request flag
357 T::regs().sr().write(|w| w.set_udr(true));
358 }
359
360 /// Get the number of segments that are supported on this LCD
361 pub fn num_segments(&self) -> u8 {
362 match self.duty {
363 Duty::Eigth => NUM_SEGMENTS - 4, // With 8 coms, 4 of the segment pins turn into com pins
364 _ => NUM_SEGMENTS,
365 }
366 }
367
368 /// Get the pixel mask for the current LCD setup.
369 /// This is a mask of all bits that are allowed to be set in the [Self::write_com_segments] function.
370 pub fn segment_pixel_mask(&self) -> u64 {
371 (1 << self.num_segments()) - 1
372 }
373
374 /// Get the number of COM pins that were configured through the Drive config
375 pub fn num_com_pins(&self) -> u8 {
376 self.duty.num_com_pins()
377 }
378
379 /// Set the blink behavior on some pixels.
380 ///
381 /// The blink frequency is an approximation. It's divided from the clock selected by the FPS.
382 /// Play with the FPS value if you want the blink frequency to be more accurate.
383 ///
384 /// If a blink frequency cannot be attained, this function will panic.
385 pub fn set_blink(&mut self, selector: BlinkSelector, freq: BlinkFreq) {
386 // Freq * 100 to be able to do integer math
387 let scaled_blink_freq = match freq {
388 BlinkFreq::Hz0_25 => 25,
389 BlinkFreq::Hz0_5 => 50,
390 BlinkFreq::Hz1 => 100,
391 BlinkFreq::Hz2 => 200,
392 BlinkFreq::Hz4 => 400,
393 };
394
395 let desired_divider = self.ck_div * 100 / scaled_blink_freq;
396 let target_divider = desired_divider.next_power_of_two();
397 let power_divisions = target_divider.trailing_zeros();
398
399 trace!(
400 "Setting LCD blink frequency -> desired_divider: {}, target_divider: {}",
401 desired_divider, target_divider
402 );
403
404 assert!(
405 (8..=1024).contains(&target_divider),
406 "LCD blink frequency cannot be attained"
407 );
408
409 T::regs().fcr().modify(|reg| {
410 reg.set_blinkf((power_divisions - 3) as u8);
411 reg.set_blink(selector as u8);
412 })
413 }
414}
415
416impl<'d, T: Instance> Drop for Lcd<'d, T> {
417 fn drop(&mut self) {
418 // Disable the lcd
419 T::regs().cr().modify(|w| w.set_lcden(false));
420 rcc::disable::<T>();
421 }
422}
423
424/// Blink frequency
425#[derive(Debug, Clone, Copy, PartialEq, Eq)]
426pub enum BlinkFreq {
427 /// 0.25 hz
428 Hz0_25,
429 /// 0.5 hz
430 Hz0_5,
431 /// 1 hz
432 Hz1,
433 /// 2 hz
434 Hz2,
435 /// 4 hz
436 Hz4,
437}
438
439/// Blink pixel selector
440#[derive(Debug, Clone, Copy, PartialEq, Eq)]
441#[repr(u8)]
442pub enum BlinkSelector {
443 /// No pixels blink
444 None = 0b00,
445 /// The SEG0, COM0 pixel blinks if the pixel is set
446 Seg0Com0 = 0b01,
447 /// The SEG0 pixel of all COMs blinks if the pixel is set
448 Seg0ComAll = 0b10,
449 /// All pixels blink if the pixel is set
450 All = 0b11,
451}
452
453/// A type-erased pin that can be configured as an LCD pin.
454/// This is used for passing pins to the new function in the array.
455pub struct LcdPin<'d, T: Instance> {
456 pin: Peri<'d, AnyPin>,
457 af_num: u8,
458 is_seg: bool,
459 _phantom: PhantomData<T>,
460}
461
462impl<'d, T: Instance> LcdPin<'d, T> {
463 /// Construct an LCD pin from any pin that supports it
464 pub fn new_seg(pin: Peri<'d, impl SegPin<T>>) -> Self {
465 let af = pin.af_num();
466
467 Self {
468 pin: pin.into(),
469 af_num: af,
470 is_seg: true,
471 _phantom: PhantomData,
472 }
473 }
474
475 /// Construct an LCD pin from any pin that supports it
476 pub fn new_com(pin: Peri<'d, impl ComPin<T>>) -> Self {
477 let af = pin.af_num();
478
479 Self {
480 pin: pin.into(),
481 af_num: af,
482 is_seg: false,
483 _phantom: PhantomData,
484 }
485 }
486}
487
488trait SealedInstance: crate::rcc::SealedRccPeripheral + PeripheralType {
489 fn regs() -> crate::pac::lcd::Lcd;
490}
491
492/// DSI instance trait.
493#[allow(private_bounds)]
494pub trait Instance: SealedInstance + RccPeripheral + 'static {}
495
496pin_trait!(SegPin, Instance);
497pin_trait!(ComPin, Instance);
498pin_trait!(VlcdPin, Instance);
499
500foreach_peripheral!(
501 (lcd, $inst:ident) => {
502 impl crate::lcd::SealedInstance for peripherals::$inst {
503 fn regs() -> crate::pac::lcd::Lcd {
504 crate::pac::$inst
505 }
506 }
507
508 impl crate::lcd::Instance for peripherals::$inst {}
509 };
510);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 7e0f7884e..2f783bf64 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,6 @@
1#![cfg_attr(not(test), no_std)] 1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
3#![cfg_attr( 4#![cfg_attr(
4 docsrs, 5 docsrs,
5 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n" 6 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-stm32'>browse the `embassy-stm32` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (stm32h7, stm32h7rs55 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n"
@@ -53,6 +54,8 @@ pub mod timer;
53 54
54#[cfg(adc)] 55#[cfg(adc)]
55pub mod adc; 56pub mod adc;
57#[cfg(backup_sram)]
58pub mod backup_sram;
56#[cfg(can)] 59#[cfg(can)]
57pub mod can; 60pub mod can;
58// FIXME: Cordic driver cause stm32u5a5zj crash 61// FIXME: Cordic driver cause stm32u5a5zj crash
@@ -74,6 +77,7 @@ pub mod dts;
74pub mod eth; 77pub mod eth;
75#[cfg(feature = "exti")] 78#[cfg(feature = "exti")]
76pub mod exti; 79pub mod exti;
80#[cfg(flash)]
77pub mod flash; 81pub mod flash;
78#[cfg(fmc)] 82#[cfg(fmc)]
79pub mod fmc; 83pub mod fmc;
@@ -91,6 +95,8 @@ pub mod i2c;
91pub mod i2s; 95pub mod i2s;
92#[cfg(stm32wb)] 96#[cfg(stm32wb)]
93pub mod ipcc; 97pub mod ipcc;
98#[cfg(lcd)]
99pub mod lcd;
94#[cfg(feature = "low-power")] 100#[cfg(feature = "low-power")]
95pub mod low_power; 101pub mod low_power;
96#[cfg(lptim)] 102#[cfg(lptim)]
@@ -147,7 +153,7 @@ pub use crate::_generated::interrupt;
147/// Macro to bind interrupts to handlers. 153/// Macro to bind interrupts to handlers.
148/// 154///
149/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 155/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
150/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to 156/// and implements the right [`Binding`](crate::interrupt::typelevel::Binding)s for it. You can pass this struct to drivers to
151/// prove at compile-time that the right interrupts have been bound. 157/// prove at compile-time that the right interrupts have been bound.
152/// 158///
153/// Example of how to bind one interrupt: 159/// Example of how to bind one interrupt:
@@ -174,7 +180,10 @@ pub use crate::_generated::interrupt;
174/// } 180/// }
175/// ); 181/// );
176/// ``` 182/// ```
177 183///
184/// Some chips collate multiple interrupt signals into a single interrupt vector. In the above example, I2C2_3 is a
185/// single vector which is activated by events and errors on both peripherals I2C2 and I2C3. Check your chip's list
186/// of interrupt vectors if you get an unexpected compile error trying to bind the standard name.
178// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. 187// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
179#[macro_export] 188#[macro_export]
180macro_rules! bind_interrupts { 189macro_rules! bind_interrupts {
@@ -194,7 +203,7 @@ macro_rules! bind_interrupts {
194 203
195 $( 204 $(
196 #[allow(non_snake_case)] 205 #[allow(non_snake_case)]
197 #[no_mangle] 206 #[unsafe(no_mangle)]
198 $(#[cfg($cond_irq)])? 207 $(#[cfg($cond_irq)])?
199 $(#[doc = $doc])* 208 $(#[doc = $doc])*
200 unsafe extern "C" fn $irq() { 209 unsafe extern "C" fn $irq() {
@@ -222,7 +231,7 @@ macro_rules! bind_interrupts {
222} 231}
223 232
224// Reexports 233// Reexports
225pub use _generated::{peripherals, Peripherals}; 234pub use _generated::{Peripherals, peripherals};
226pub use embassy_hal_internal::{Peri, PeripheralType}; 235pub use embassy_hal_internal::{Peri, PeripheralType};
227#[cfg(feature = "unstable-pac")] 236#[cfg(feature = "unstable-pac")]
228pub use stm32_metapac as pac; 237pub use stm32_metapac as pac;
@@ -240,6 +249,14 @@ pub struct Config {
240 /// RCC config. 249 /// RCC config.
241 pub rcc: rcc::Config, 250 pub rcc: rcc::Config,
242 251
252 #[cfg(feature = "low-power")]
253 /// RTC config
254 pub rtc: rtc::RtcConfig,
255
256 #[cfg(feature = "low-power")]
257 /// Minimum time to stop
258 pub min_stop_pause: embassy_time::Duration,
259
243 /// Enable debug during sleep and stop. 260 /// Enable debug during sleep and stop.
244 /// 261 ///
245 /// May increase power consumption. Defaults to true. 262 /// May increase power consumption. Defaults to true.
@@ -293,6 +310,10 @@ impl Default for Config {
293 fn default() -> Self { 310 fn default() -> Self {
294 Self { 311 Self {
295 rcc: Default::default(), 312 rcc: Default::default(),
313 #[cfg(feature = "low-power")]
314 rtc: Default::default(),
315 #[cfg(feature = "low-power")]
316 min_stop_pause: embassy_time::Duration::from_millis(250),
296 #[cfg(dbgmcu)] 317 #[cfg(dbgmcu)]
297 enable_debug_during_sleep: true, 318 enable_debug_during_sleep: true,
298 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))] 319 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
@@ -495,6 +516,16 @@ fn init_hw(config: Config) -> Peripherals {
495 critical_section::with(|cs| { 516 critical_section::with(|cs| {
496 let p = Peripherals::take_with_cs(cs); 517 let p = Peripherals::take_with_cs(cs);
497 518
519 #[cfg(dbgmcu_n6)]
520 {
521 crate::pac::RCC.miscensr().write(|w| w.set_dbgens(true));
522 crate::pac::RCC.miscenr().read(); // volatile read
523 crate::pac::DBGMCU
524 .cr()
525 .modify(|w| w.set_dbgclken(stm32_metapac::dbgmcu::vals::Dbgclken::B_0X1));
526 crate::pac::DBGMCU.cr().read();
527 }
528
498 #[cfg(dbgmcu)] 529 #[cfg(dbgmcu)]
499 crate::pac::DBGMCU.cr().modify(|cr| { 530 crate::pac::DBGMCU.cr().modify(|cr| {
500 #[cfg(dbgmcu_h5)] 531 #[cfg(dbgmcu_h5)]
@@ -509,7 +540,7 @@ fn init_hw(config: Config) -> Peripherals {
509 } 540 }
510 #[cfg(any( 541 #[cfg(any(
511 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, 542 dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
512 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl 543 dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6
513 ))] 544 ))]
514 { 545 {
515 cr.set_dbg_sleep(config.enable_debug_during_sleep); 546 cr.set_dbg_sleep(config.enable_debug_during_sleep);
@@ -530,7 +561,7 @@ fn init_hw(config: Config) -> Peripherals {
530 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs); 561 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
531 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] 562 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
532 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs); 563 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
533 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] 564 #[cfg(all(flash, not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))))]
534 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs); 565 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
535 566
536 // Enable the VDDIO2 power supply on chips that have it. 567 // Enable the VDDIO2 power supply on chips that have it.
@@ -590,7 +621,7 @@ fn init_hw(config: Config) -> Peripherals {
590 #[cfg(ucpd)] 621 #[cfg(ucpd)]
591 ucpd::init( 622 ucpd::init(
592 cs, 623 cs,
593 #[cfg(peri_ucpd1)] 624 #[cfg(all(peri_ucpd1, not(stm32n6)))]
594 config.enable_ucpd1_dead_battery, 625 config.enable_ucpd1_dead_battery,
595 #[cfg(peri_ucpd2)] 626 #[cfg(peri_ucpd2)]
596 config.enable_ucpd2_dead_battery, 627 config.enable_ucpd2_dead_battery,
@@ -622,8 +653,28 @@ fn init_hw(config: Config) -> Peripherals {
622 exti::init(cs); 653 exti::init(cs);
623 654
624 rcc::init_rcc(cs, config.rcc); 655 rcc::init_rcc(cs, config.rcc);
656
657 #[cfg(feature = "low-power")]
658 rtc::init_rtc(cs, config.rtc, config.min_stop_pause);
659
660 #[cfg(all(stm32wb, feature = "low-power"))]
661 hsem::init_hsem(cs);
625 } 662 }
626 663
627 p 664 p
628 }) 665 })
629} 666}
667
668/// Performs a busy-wait delay for a specified number of microseconds.
669#[allow(unused)]
670pub(crate) fn block_for_us(us: u64) {
671 cfg_if::cfg_if! {
672 // this does strange things on stm32wlx in low power mode depending on exactly when it's called
673 // as in sometimes 15 us (1 tick) would take > 20 seconds.
674 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] {
675 embassy_time::block_for(embassy_time::Duration::from_micros(us));
676 } else {
677 cortex_m::asm::delay(unsafe { rcc::get_freqs().sys.to_hertz().unwrap().0 as u64 * us / 1_000_000 } as u32);
678 }
679 }
680}
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 342f73bc8..bd8290da0 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -14,7 +14,7 @@
14//! 14//!
15//! Since entering and leaving low-power modes typically incurs a significant latency, the 15//! Since entering and leaving low-power modes typically incurs a significant latency, the
16//! low-power executor will only attempt to enter when the next timer event is at least 16//! low-power executor will only attempt to enter when the next timer event is at least
17//! [`time_driver::MIN_STOP_PAUSE`] in the future. 17//! [`time_driver::min_stop_pause`] in the future.
18//! 18//!
19//! Currently there is no macro analogous to `embassy_executor::main` for this executor; 19//! Currently there is no macro analogous to `embassy_executor::main` for this executor;
20//! consequently one must define their entrypoint manually. Moreover, you must relinquish control 20//! consequently one must define their entrypoint manually. Moreover, you must relinquish control
@@ -22,53 +22,73 @@
22//! 22//!
23//! ```rust,no_run 23//! ```rust,no_run
24//! use embassy_executor::Spawner; 24//! use embassy_executor::Spawner;
25//! use embassy_stm32::low_power::Executor; 25//! use embassy_stm32::low_power;
26//! use embassy_stm32::rtc::{Rtc, RtcConfig}; 26//! use embassy_stm32::rtc::{Rtc, RtcConfig};
27//! use static_cell::StaticCell; 27//! use embassy_time::Duration;
28//! 28//!
29//! #[cortex_m_rt::entry] 29//! #[embassy_executor::main(executor = "low_power::Executor")]
30//! fn main() -> ! {
31//! Executor::take().run(|spawner| {
32//! spawner.spawn(unwrap!(async_main(spawner)));
33//! });
34//! }
35//!
36//! #[embassy_executor::task]
37//! async fn async_main(spawner: Spawner) { 30//! async fn async_main(spawner: Spawner) {
38//! // initialize the platform... 31//! // initialize the platform...
39//! let mut config = embassy_stm32::Config::default(); 32//! let mut config = embassy_stm32::Config::default();
33//! // the default value, but can be adjusted
34//! config.min_stop_pause = Duration::from_millis(250);
40//! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working 35//! // when enabled the power-consumption is much higher during stop, but debugging and RTT is working
41//! config.enable_debug_during_sleep = false; 36//! config.enable_debug_during_sleep = false;
42//! let p = embassy_stm32::init(config); 37//! let p = embassy_stm32::init(config);
43//! 38//!
44//! // give the RTC to the executor...
45//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
46//! static RTC: StaticCell<Rtc> = StaticCell::new();
47//! let rtc = RTC.init(rtc);
48//! embassy_stm32::low_power::stop_with_rtc(rtc);
49//!
50//! // your application here... 39//! // your application here...
51//! } 40//! }
52//! ``` 41//! ```
53 42
54// TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.`
55#![allow(static_mut_refs)]
56
57use core::arch::asm; 43use core::arch::asm;
58use core::marker::PhantomData; 44use core::marker::PhantomData;
59use core::sync::atomic::{compiler_fence, Ordering}; 45use core::mem;
46use core::sync::atomic::{Ordering, compiler_fence};
60 47
61use cortex_m::peripheral::SCB; 48use cortex_m::peripheral::SCB;
49use critical_section::CriticalSection;
62use embassy_executor::*; 50use embassy_executor::*;
63 51
64use crate::interrupt; 52use crate::interrupt;
65use crate::time_driver::{get_driver, RtcDriver}; 53pub use crate::rcc::StopMode;
54use crate::rcc::{RCC_CONFIG, REFCOUNT_STOP1, REFCOUNT_STOP2, decrement_stop_refcount, increment_stop_refcount};
55use crate::time_driver::get_driver;
66 56
67const THREAD_PENDER: usize = usize::MAX; 57const THREAD_PENDER: usize = usize::MAX;
68 58
69use crate::rtc::Rtc; 59static mut EXECUTOR_TAKEN: bool = false;
60
61/// Prevent the device from going into the stop mode if held
62pub struct DeviceBusy(StopMode);
63
64impl DeviceBusy {
65 /// Create a new DeviceBusy with stop1.
66 pub fn new_stop1() -> Self {
67 Self::new(StopMode::Stop1)
68 }
69
70 /// Create a new DeviceBusy with stop2.
71 pub fn new_stop2() -> Self {
72 Self::new(StopMode::Stop2)
73 }
70 74
71static mut EXECUTOR: Option<Executor> = None; 75 /// Create a new DeviceBusy.
76 pub fn new(stop_mode: StopMode) -> Self {
77 critical_section::with(|cs| {
78 increment_stop_refcount(cs, stop_mode);
79 });
80
81 Self(stop_mode)
82 }
83}
84
85impl Drop for DeviceBusy {
86 fn drop(&mut self) {
87 critical_section::with(|cs| {
88 decrement_stop_refcount(cs, self.0);
89 });
90 }
91}
72 92
73#[cfg(not(stm32u0))] 93#[cfg(not(stm32u0))]
74foreach_interrupt! { 94foreach_interrupt! {
@@ -76,7 +96,7 @@ foreach_interrupt! {
76 #[interrupt] 96 #[interrupt]
77 #[allow(non_snake_case)] 97 #[allow(non_snake_case)]
78 unsafe fn $irq() { 98 unsafe fn $irq() {
79 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 99 Executor::on_wakeup_irq();
80 } 100 }
81 }; 101 };
82} 102}
@@ -87,55 +107,35 @@ foreach_interrupt! {
87 #[interrupt] 107 #[interrupt]
88 #[allow(non_snake_case)] 108 #[allow(non_snake_case)]
89 unsafe fn $irq() { 109 unsafe fn $irq() {
90 EXECUTOR.as_mut().unwrap().on_wakeup_irq(); 110 Executor::on_wakeup_irq();
91 } 111 }
92 }; 112 };
93} 113}
94 114
95#[allow(dead_code)]
96pub(crate) unsafe fn on_wakeup_irq() {
97 EXECUTOR.as_mut().unwrap().on_wakeup_irq();
98}
99
100/// Configure STOP mode with RTC.
101pub fn stop_with_rtc(rtc: &'static Rtc) {
102 unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
103}
104
105/// Get whether the core is ready to enter the given stop mode. 115/// Get whether the core is ready to enter the given stop mode.
106/// 116///
107/// This will return false if some peripheral driver is in use that 117/// This will return false if some peripheral driver is in use that
108/// prevents entering the given stop mode. 118/// prevents entering the given stop mode.
109pub fn stop_ready(stop_mode: StopMode) -> bool { 119pub fn stop_ready(stop_mode: StopMode) -> bool {
110 match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { 120 critical_section::with(|cs| match Executor::stop_mode(cs) {
111 Some(StopMode::Stop2) => true, 121 Some(StopMode::Standby | StopMode::Stop2) => true,
112 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1, 122 Some(StopMode::Stop1) => stop_mode == StopMode::Stop1,
113 None => false, 123 None => false,
114 } 124 })
115}
116
117/// Available Stop modes.
118#[non_exhaustive]
119#[derive(PartialEq)]
120pub enum StopMode {
121 /// STOP 1
122 Stop1,
123 /// STOP 2
124 Stop2,
125} 125}
126 126
127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 127#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
128use stm32_metapac::pwr::vals::Lpms; 128use crate::pac::pwr::vals::Lpms;
129 129
130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32u0))] 130#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba, stm32wb, stm32wlex, stm32u0))]
131impl Into<Lpms> for StopMode { 131impl Into<Lpms> for StopMode {
132 fn into(self) -> Lpms { 132 fn into(self) -> Lpms {
133 match self { 133 match self {
134 StopMode::Stop1 => Lpms::STOP1, 134 StopMode::Stop1 => Lpms::STOP1,
135 #[cfg(not(stm32wba))] 135 #[cfg(not(any(stm32wb, stm32wba)))]
136 StopMode::Stop2 => Lpms::STOP2, 136 StopMode::Standby | StopMode::Stop2 => Lpms::STOP2,
137 #[cfg(stm32wba)] 137 #[cfg(any(stm32wb, stm32wba))]
138 StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2? 138 StopMode::Standby | StopMode::Stop2 => Lpms::STOP1, // TODO: WBA has no STOP2?
139 } 139 }
140 } 140 }
141} 141}
@@ -153,55 +153,139 @@ impl Into<Lpms> for StopMode {
153pub struct Executor { 153pub struct Executor {
154 inner: raw::Executor, 154 inner: raw::Executor,
155 not_send: PhantomData<*mut ()>, 155 not_send: PhantomData<*mut ()>,
156 scb: SCB,
157 time_driver: &'static RtcDriver,
158} 156}
159 157
160impl Executor { 158impl Executor {
161 /// Create a new Executor. 159 /// Create a new Executor.
162 pub fn take() -> &'static mut Self { 160 pub fn new() -> Self {
163 critical_section::with(|_| unsafe { 161 unsafe {
164 assert!(EXECUTOR.is_none()); 162 if EXECUTOR_TAKEN {
165 163 panic!("Low power executor can only be taken once.");
166 EXECUTOR = Some(Self { 164 } else {
167 inner: raw::Executor::new(THREAD_PENDER as *mut ()), 165 EXECUTOR_TAKEN = true;
168 not_send: PhantomData, 166 }
169 scb: cortex_m::Peripherals::steal().SCB, 167 }
170 time_driver: get_driver(),
171 });
172
173 let executor = EXECUTOR.as_mut().unwrap();
174 168
175 executor 169 Self {
176 }) 170 inner: raw::Executor::new(THREAD_PENDER as *mut ()),
171 not_send: PhantomData,
172 }
177 } 173 }
178 174
179 unsafe fn on_wakeup_irq(&mut self) { 175 pub(crate) unsafe fn on_wakeup_irq() {
180 self.time_driver.resume_time(); 176 critical_section::with(|cs| {
181 trace!("low power: resume"); 177 #[cfg(stm32wlex)]
178 {
179 use crate::pac::rcc::vals::Sw;
180 use crate::pac::{PWR, RCC};
181 use crate::rcc::init as init_rcc;
182
183 let extscr = PWR.extscr().read();
184 if extscr.c1stop2f() || extscr.c1stopf() {
185 // when we wake from any stop mode we need to re-initialize the rcc
186 while RCC.cfgr().read().sws() != Sw::MSI {}
187
188 init_rcc(RCC_CONFIG.unwrap());
189
190 if extscr.c1stop2f() {
191 // when we wake from STOP2, we need to re-initialize the time driver
192 get_driver().init_timer(cs);
193 // reset the refcounts for STOP2 and STOP1 (initializing the time driver will increment one of them for the timer)
194 // and given that we just woke from STOP2, we can reset them
195 REFCOUNT_STOP2 = 0;
196 REFCOUNT_STOP1 = 0;
197 }
198 }
199 }
200 get_driver().resume_time(cs);
201 trace!("low power: resume");
202 });
182 } 203 }
183 204
184 pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { 205 const fn get_scb() -> SCB {
185 self.time_driver.set_rtc(rtc); 206 unsafe { mem::transmute(()) }
186
187 rtc.enable_wakeup_line();
188
189 trace!("low power: stop with rtc configured");
190 } 207 }
191 208
192 fn stop_mode(&self) -> Option<StopMode> { 209 fn stop_mode(_cs: CriticalSection) -> Option<StopMode> {
193 if unsafe { crate::rcc::REFCOUNT_STOP2 == 0 } && unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 210 // We cannot enter standby because we will lose program state.
211 if unsafe { REFCOUNT_STOP2 == 0 && REFCOUNT_STOP1 == 0 } {
212 trace!("low power: stop 2");
194 Some(StopMode::Stop2) 213 Some(StopMode::Stop2)
195 } else if unsafe { crate::rcc::REFCOUNT_STOP1 == 0 } { 214 } else if unsafe { REFCOUNT_STOP1 == 0 } {
215 trace!("low power: stop 1");
196 Some(StopMode::Stop1) 216 Some(StopMode::Stop1)
197 } else { 217 } else {
218 trace!("low power: not ready to stop (refcount_stop1: {})", unsafe {
219 REFCOUNT_STOP1
220 });
198 None 221 None
199 } 222 }
200 } 223 }
201 224
225 #[cfg(all(stm32wb, feature = "low-power"))]
226 fn configure_stop_stm32wb(&self, _cs: CriticalSection) -> Result<(), ()> {
227 use core::task::Poll;
228
229 use embassy_futures::poll_once;
230
231 use crate::hsem::HardwareSemaphoreChannel;
232 use crate::pac::rcc::vals::{Smps, Sw};
233 use crate::pac::{PWR, RCC};
234
235 trace!("low power: trying to get sem3");
236
237 let sem3_mutex = match poll_once(HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(3).lock(0)) {
238 Poll::Pending => None,
239 Poll::Ready(mutex) => Some(mutex),
240 }
241 .ok_or(())?;
242
243 trace!("low power: got sem3");
244
245 let sem4_mutex = HardwareSemaphoreChannel::<crate::peripherals::HSEM>::new(4).try_lock(0);
246 if let Some(sem4_mutex) = sem4_mutex {
247 trace!("low power: got sem4");
248
249 if PWR.extscr().read().c2ds() {
250 drop(sem4_mutex);
251 } else {
252 return Ok(());
253 }
254 }
255
256 // Sem4 not granted
257 // Set HSION
258 RCC.cr().modify(|w| {
259 w.set_hsion(true);
260 });
261
262 // Wait for HSIRDY
263 while !RCC.cr().read().hsirdy() {}
264
265 // Set SW to HSI
266 RCC.cfgr().modify(|w| {
267 w.set_sw(Sw::HSI);
268 });
269
270 // Wait for SWS to report HSI
271 while !RCC.cfgr().read().sws().eq(&Sw::HSI) {}
272
273 // Set SMPSSEL to HSI
274 RCC.smpscr().modify(|w| {
275 w.set_smpssel(Smps::HSI);
276 });
277
278 drop(sem3_mutex);
279
280 Ok(())
281 }
282
202 #[allow(unused_variables)] 283 #[allow(unused_variables)]
203 fn configure_stop(&mut self, stop_mode: StopMode) { 284 fn configure_stop(&self, _cs: CriticalSection, stop_mode: StopMode) -> Result<(), ()> {
204 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wba))] 285 #[cfg(all(stm32wb, feature = "low-power"))]
286 self.configure_stop_stm32wb(_cs)?;
287
288 #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0, stm32wb, stm32wba, stm32wlex))]
205 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 289 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
206 #[cfg(stm32h5)] 290 #[cfg(stm32h5)]
207 crate::pac::PWR.pmcr().modify(|v| { 291 crate::pac::PWR.pmcr().modify(|v| {
@@ -209,34 +293,32 @@ impl Executor {
209 v.set_lpms(vals::Lpms::STOP); 293 v.set_lpms(vals::Lpms::STOP);
210 v.set_svos(vals::Svos::SCALE3); 294 v.set_svos(vals::Svos::SCALE3);
211 }); 295 });
296
297 Ok(())
212 } 298 }
213 299
214 fn configure_pwr(&mut self) { 300 fn configure_pwr(&self) {
215 self.scb.clear_sleepdeep(); 301 Self::get_scb().clear_sleepdeep();
302 // Clear any previous stop flags
303 #[cfg(stm32wlex)]
304 crate::pac::PWR.extscr().modify(|w| {
305 w.set_c1cssf(true);
306 });
216 307
217 compiler_fence(Ordering::SeqCst); 308 compiler_fence(Ordering::SeqCst);
218 309
219 let stop_mode = self.stop_mode(); 310 critical_section::with(|cs| {
311 let _ = unsafe { RCC_CONFIG }?;
312 let stop_mode = Self::stop_mode(cs)?;
313 get_driver().pause_time(cs).ok()?;
314 self.configure_stop(cs, stop_mode).ok()?;
220 315
221 if stop_mode.is_none() { 316 Some(())
222 trace!("low power: not ready to stop"); 317 })
223 return; 318 .map(|_| {
224 } 319 #[cfg(not(feature = "low-power-debug-with-sleep"))]
225 320 Self::get_scb().set_sleepdeep();
226 if self.time_driver.pause_time().is_err() { 321 });
227 trace!("low power: failed to pause time");
228 return;
229 }
230
231 let stop_mode = stop_mode.unwrap();
232 match stop_mode {
233 StopMode::Stop1 => trace!("low power: stop 1"),
234 StopMode::Stop2 => trace!("low power: stop 2"),
235 }
236 self.configure_stop(stop_mode);
237
238 #[cfg(not(feature = "low-power-debug-with-sleep"))]
239 self.scb.set_sleepdeep();
240 } 322 }
241 323
242 /// Run the executor. 324 /// Run the executor.
@@ -258,14 +340,26 @@ impl Executor {
258 /// 340 ///
259 /// This function never returns. 341 /// This function never returns.
260 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 342 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
261 let executor = unsafe { EXECUTOR.as_mut().unwrap() }; 343 init(self.inner.spawner());
262 init(executor.inner.spawner());
263 344
264 loop { 345 loop {
265 unsafe { 346 unsafe {
266 executor.inner.poll(); 347 self.inner.poll();
267 self.configure_pwr(); 348 self.configure_pwr();
268 asm!("wfe"); 349 asm!("wfe");
350 #[cfg(stm32wlex)]
351 {
352 let es = crate::pac::PWR.extscr().read();
353 match (es.c1stopf(), es.c1stop2f()) {
354 (true, false) => debug!("low power: wake from STOP1"),
355 (false, true) => debug!("low power: wake from STOP2"),
356 (true, true) => debug!("low power: wake from STOP1 and STOP2 ???"),
357 (false, false) => trace!("low power: stop mode not entered"),
358 };
359 crate::pac::PWR.extscr().modify(|w| {
360 w.set_c1cssf(false);
361 });
362 }
269 }; 363 };
270 } 364 }
271 } 365 }
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
index 96af9f4d9..a69db3caf 100644
--- a/embassy-stm32/src/lptim/pwm.rs
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -4,12 +4,12 @@ use core::marker::PhantomData;
4 4
5use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
6 6
7use super::timer::Timer;
8#[cfg(not(any(lptim_v2a, lptim_v2b)))] 7#[cfg(not(any(lptim_v2a, lptim_v2b)))]
9use super::OutputPin; 8use super::OutputPin;
10#[cfg(any(lptim_v2a, lptim_v2b))] 9use super::timer::Timer;
11use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
12use super::{BasicInstance, Instance}; 10use super::{BasicInstance, Instance};
11#[cfg(any(lptim_v2a, lptim_v2b))]
12use super::{Channel1Pin, Channel2Pin, channel::Channel, timer::ChannelDirection};
13#[cfg(gpio_v2)] 13#[cfg(gpio_v2)]
14use crate::gpio::Pull; 14use crate::gpio::Pull;
15use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 15use crate::gpio::{AfType, AnyPin, OutputType, Speed};
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index 0f6ef569c..de2db9872 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr};
14use crate::gpio::{AfType, OutputType, Speed}; 14use crate::gpio::{AfType, OutputType, Speed};
15use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::interrupt::{self}; 16use crate::interrupt::{self};
17use crate::{peripherals, rcc, Peri}; 17use crate::{Peri, peripherals, rcc};
18 18
19static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); 19static LTDC_WAKER: AtomicWaker = AtomicWaker::new();
20 20
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index e36719ef3..4a55f5bd3 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -3,19 +3,12 @@
3 3
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::Peri;
7#[cfg(opamp_v5)]
8use crate::block_for_us;
6use crate::pac::opamp::vals::*; 9use crate::pac::opamp::vals::*;
7#[cfg(not(any(stm32g4, stm32f3)))] 10#[cfg(not(any(stm32g4, stm32f3)))]
8use crate::rcc::RccInfo; 11use crate::rcc::RccInfo;
9use crate::Peri;
10
11/// Performs a busy-wait delay for a specified number of microseconds.
12#[cfg(opamp_v5)]
13fn 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 12
20/// Gain 13/// Gain
21#[allow(missing_docs)] 14#[allow(missing_docs)]
@@ -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 {
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index dbcf07469..2d5dbd95a 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -12,14 +12,14 @@ use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; 13use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
14 14
15use crate::dma::{word, ChannelAndRequest}; 15use crate::dma::{ChannelAndRequest, word};
16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 16use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
17use crate::mode::{Async, Blocking, Mode as PeriMode}; 17use crate::mode::{Async, Blocking, Mode as PeriMode};
18use crate::pac::octospi::{vals, Octospi as Regs}; 18use crate::pac::octospi::{Octospi as Regs, vals};
19#[cfg(octospim_v1)] 19#[cfg(octospim_v1)]
20use crate::pac::octospim::Octospim; 20use crate::pac::octospim::Octospim;
21use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri}; 22use crate::{Peri, peripherals};
23 23
24/// OPSI driver config. 24/// OPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index b03cd9009..bb4f4f1d0 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -14,7 +14,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::quadspi::Quadspi as Regs; 15use crate::pac::quadspi::Quadspi as Regs;
16use crate::rcc::{self, RccPeripheral}; 16use crate::rcc::{self, RccPeripheral};
17use crate::{peripherals, Peri}; 17use crate::{Peri, peripherals};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index 63fc195dd..219be208f 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -1,6 +1,10 @@
1use core::sync::atomic::{compiler_fence, Ordering}; 1#[cfg(not(stm32n6))]
2use core::sync::atomic::{Ordering, compiler_fence};
2 3
3use crate::pac::common::{Reg, RW}; 4#[cfg(not(stm32n6))]
5use crate::pac::common::{RW, Reg};
6#[cfg(backup_sram)]
7use crate::pac::pwr::vals::Retention;
4pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; 8pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
5use crate::time::Hertz; 9use crate::time::Hertz;
6 10
@@ -52,7 +56,7 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
52 } 56 }
53} 57}
54 58
55#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))] 59#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0, stm32n6)))]
56type Bdcr = crate::pac::rcc::regs::Bdcr; 60type Bdcr = crate::pac::rcc::regs::Bdcr;
57#[cfg(any(rtc_v2_l0, rtc_v2_l1))] 61#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
58type Bdcr = crate::pac::rcc::regs::Csr; 62type Bdcr = crate::pac::rcc::regs::Csr;
@@ -62,19 +66,22 @@ type Bdcr = crate::pac::rcc::regs::Csr1;
62#[cfg(any(stm32c0))] 66#[cfg(any(stm32c0))]
63fn unlock() {} 67fn unlock() {}
64 68
65#[cfg(not(any(stm32c0)))] 69#[cfg(not(any(stm32c0, stm32n6)))]
66fn unlock() { 70fn unlock() {
67 #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] 71 #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))]
68 let cr = crate::pac::PWR.cr(); 72 let cr = crate::pac::PWR.cr();
69 #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] 73 #[cfg(not(any(
74 stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba, stm32n6
75 )))]
70 let cr = crate::pac::PWR.cr1(); 76 let cr = crate::pac::PWR.cr1();
71 #[cfg(any(stm32u5, stm32h5, stm32wba))] 77 #[cfg(any(stm32u5, stm32h5, stm32wba, stm32n6))]
72 let cr = crate::pac::PWR.dbpcr(); 78 let cr = crate::pac::PWR.dbpcr();
73 79
74 cr.modify(|w| w.set_dbp(true)); 80 cr.modify(|w| w.set_dbp(true));
75 while !cr.read().dbp() {} 81 while !cr.read().dbp() {}
76} 82}
77 83
84#[cfg(not(stm32n6))]
78fn bdcr() -> Reg<Bdcr, RW> { 85fn bdcr() -> Reg<Bdcr, RW> {
79 #[cfg(any(rtc_v2_l0, rtc_v2_l1))] 86 #[cfg(any(rtc_v2_l0, rtc_v2_l1))]
80 return crate::pac::RCC.csr(); 87 return crate::pac::RCC.csr();
@@ -89,6 +96,8 @@ pub struct LsConfig {
89 pub rtc: RtcClockSource, 96 pub rtc: RtcClockSource,
90 pub lsi: bool, 97 pub lsi: bool,
91 pub lse: Option<LseConfig>, 98 pub lse: Option<LseConfig>,
99 #[cfg(backup_sram)]
100 pub enable_backup_sram: bool,
92} 101}
93 102
94impl LsConfig { 103impl LsConfig {
@@ -113,6 +122,8 @@ impl LsConfig {
113 peripherals_clocked: false, 122 peripherals_clocked: false,
114 }), 123 }),
115 lsi: false, 124 lsi: false,
125 #[cfg(backup_sram)]
126 enable_backup_sram: false,
116 } 127 }
117 } 128 }
118 129
@@ -121,6 +132,8 @@ impl LsConfig {
121 rtc: RtcClockSource::LSI, 132 rtc: RtcClockSource::LSI,
122 lsi: true, 133 lsi: true,
123 lse: None, 134 lse: None,
135 #[cfg(backup_sram)]
136 enable_backup_sram: false,
124 } 137 }
125 } 138 }
126 139
@@ -129,6 +142,8 @@ impl LsConfig {
129 rtc: RtcClockSource::DISABLE, 142 rtc: RtcClockSource::DISABLE,
130 lsi: false, 143 lsi: false,
131 lse: None, 144 lse: None,
145 #[cfg(backup_sram)]
146 enable_backup_sram: false,
132 } 147 }
133 } 148 }
134} 149}
@@ -140,6 +155,7 @@ impl Default for LsConfig {
140} 155}
141 156
142impl LsConfig { 157impl LsConfig {
158 #[cfg(not(stm32n6))]
143 pub(crate) fn init(&self) -> Option<Hertz> { 159 pub(crate) fn init(&self) -> Option<Hertz> {
144 let rtc_clk = match self.rtc { 160 let rtc_clk = match self.rtc {
145 RtcClockSource::LSI => { 161 RtcClockSource::LSI => {
@@ -175,14 +191,19 @@ impl LsConfig {
175 if self.lsi { 191 if self.lsi {
176 #[cfg(any(stm32u5, stm32h5, stm32wba))] 192 #[cfg(any(stm32u5, stm32h5, stm32wba))]
177 let csr = crate::pac::RCC.bdcr(); 193 let csr = crate::pac::RCC.bdcr();
178 #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))] 194 #[cfg(stm32n6)]
195 let csr = crate::pac::RCC.sr();
196 #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0, stm32n6)))]
179 let csr = crate::pac::RCC.csr(); 197 let csr = crate::pac::RCC.csr();
180 #[cfg(any(stm32c0))] 198 #[cfg(stm32c0)]
181 let csr = crate::pac::RCC.csr2(); 199 let csr = crate::pac::RCC.csr2();
182 200
183 #[cfg(not(any(rcc_wb, rcc_wba)))] 201 #[cfg(not(any(rcc_wb, rcc_wba, rcc_n6)))]
184 csr.modify(|w| w.set_lsion(true)); 202 csr.modify(|w| w.set_lsion(true));
185 203
204 #[cfg(rcc_n6)]
205 crate::pac::RCC.cr().modify(|w| w.set_lsion(true));
206
186 #[cfg(any(rcc_wb, rcc_wba))] 207 #[cfg(any(rcc_wb, rcc_wba))]
187 csr.modify(|w| w.set_lsi1on(true)); 208 csr.modify(|w| w.set_lsi1on(true));
188 209
@@ -193,28 +214,77 @@ impl LsConfig {
193 while !csr.read().lsi1rdy() {} 214 while !csr.read().lsi1rdy() {}
194 } 215 }
195 216
217 // Enable backup regulator for peristent battery backed sram
218 #[cfg(backup_sram)]
219 {
220 unsafe { super::BKSRAM_RETAINED = crate::pac::PWR.bdcr().read().bren() == Retention::PRESERVED };
221
222 crate::pac::PWR.bdcr().modify(|w| {
223 w.set_bren(match self.enable_backup_sram {
224 true => Retention::PRESERVED,
225 false => Retention::LOST,
226 });
227 });
228
229 // Wait for backup regulator voltage to stabilize
230 while self.enable_backup_sram && !crate::pac::PWR.bdsr().read().brrdy() {}
231 }
232
196 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. 233 // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
197 // once set, changing it requires a backup domain reset. 234 // once set, changing it requires a backup domain reset.
198 // first check if the configuration matches what we want. 235 // first check if the configuration matches what we want.
236 // N6 has all the fields spread across multiple registers under RCC.
199 237
200 // check if it's already enabled and in the source we want. 238 // check if it's already enabled and in the source we want.
239 #[cfg(not(rcc_n6))]
201 let reg = bdcr().read(); 240 let reg = bdcr().read();
241 #[cfg(rcc_n6)]
242 let reg = crate::pac::RCC.cr().read();
243 #[cfg(rcc_n6)]
244 let apb4lenr = crate::pac::RCC.apb4lenr().read();
245 #[cfg(rcc_n6)]
246 let ccipr7 = crate::pac::RCC.ccipr7().read();
247 #[cfg(rcc_n6)]
248 let lsecfgr = crate::pac::RCC.lsecfgr().read();
249
202 let mut ok = true; 250 let mut ok = true;
203 ok &= reg.rtcsel() == self.rtc; 251 #[cfg(not(rcc_n6))]
204 #[cfg(not(rcc_wba))] 252 {
253 ok &= reg.rtcsel() == self.rtc;
254 }
255 #[cfg(rcc_n6)]
256 {
257 ok &= ccipr7.rtcsel() == self.rtc;
258 }
259 #[cfg(not(any(rcc_wba, rcc_n6)))]
205 { 260 {
206 ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE); 261 ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE);
207 } 262 }
263 #[cfg(rcc_n6)]
264 {
265 ok &= apb4lenr.rtcen() == (self.rtc != RtcClockSource::DISABLE);
266 }
208 ok &= reg.lseon() == lse_en; 267 ok &= reg.lseon() == lse_en;
209 ok &= reg.lsebyp() == lse_byp; 268 #[cfg(not(rcc_n6))]
269 {
270 ok &= reg.lsebyp() == lse_byp;
271 }
272 #[cfg(rcc_n6)]
273 {
274 ok &= lsecfgr.lsebyp() == lse_byp;
275 }
210 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] 276 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
211 if let Some(lse_sysen) = lse_sysen { 277 if let Some(lse_sysen) = lse_sysen {
212 ok &= reg.lsesysen() == lse_sysen; 278 ok &= reg.lsesysen() == lse_sysen;
213 } 279 }
214 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 280 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1, rcc_n6)))]
215 if let Some(lse_drv) = lse_drv { 281 if let Some(lse_drv) = lse_drv {
216 ok &= reg.lsedrv() == lse_drv.into(); 282 ok &= reg.lsedrv() == lse_drv.into();
217 } 283 }
284 #[cfg(rcc_n6)]
285 if let Some(lse_drv) = lse_drv {
286 ok &= lsecfgr.lsedrv() == lse_drv.into();
287 }
218 288
219 // if configuration is OK, we're done. 289 // if configuration is OK, we're done.
220 if ok { 290 if ok {
@@ -223,7 +293,7 @@ impl LsConfig {
223 } 293 }
224 294
225 // If not OK, reset backup domain and configure it. 295 // If not OK, reset backup domain and configure it.
226 #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0)))] 296 #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32h7rs, stm32c0, stm32n6)))]
227 { 297 {
228 bdcr().modify(|w| w.set_bdrst(true)); 298 bdcr().modify(|w| w.set_bdrst(true));
229 bdcr().modify(|w| w.set_bdrst(false)); 299 bdcr().modify(|w| w.set_bdrst(false));
@@ -236,7 +306,7 @@ impl LsConfig {
236 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset 306 // STM32H503CB/EB/KB/RB device errata - 2.2.8 SRAM2 unduly erased upon a backup domain reset
237 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset 307 // STM32H562xx/563xx/573xx device errata - 2.2.14 SRAM2 is erased when the backup domain is reset
238 //#[cfg(any(stm32h5, stm32h7rs))] 308 //#[cfg(any(stm32h5, stm32h7rs))]
239 #[cfg(any(stm32h7rs))] 309 #[cfg(any(stm32h7rs, stm32n6))]
240 { 310 {
241 bdcr().modify(|w| w.set_vswrst(true)); 311 bdcr().modify(|w| w.set_vswrst(true));
242 bdcr().modify(|w| w.set_vswrst(false)); 312 bdcr().modify(|w| w.set_vswrst(false));
@@ -248,16 +318,31 @@ impl LsConfig {
248 } 318 }
249 319
250 if lse_en { 320 if lse_en {
251 bdcr().modify(|w| { 321 #[cfg(not(rcc_n6))]
252 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] 322 {
253 if let Some(lse_drv) = lse_drv { 323 bdcr().modify(|w| {
254 w.set_lsedrv(lse_drv.into()); 324 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
255 } 325 if let Some(lse_drv) = lse_drv {
256 w.set_lsebyp(lse_byp); 326 w.set_lsedrv(lse_drv.into());
257 w.set_lseon(true); 327 }
258 }); 328 w.set_lsebyp(lse_byp);
329 w.set_lseon(true);
330 });
331
332 while !bdcr().read().lserdy() {}
333 }
334 #[cfg(rcc_n6)]
335 {
336 crate::pac::RCC.lsecfgr().modify(|w| {
337 if let Some(lse_drv) = lse_drv {
338 w.set_lsedrv(lse_drv.into());
339 }
340 w.set_lsebyp(lse_byp);
341 });
342 crate::pac::RCC.cr().modify(|w| w.set_lseon(true));
259 343
260 while !bdcr().read().lserdy() {} 344 while !crate::pac::RCC.sr().read().lserdy() {}
345 }
261 346
262 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] 347 #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))]
263 if let Some(lse_sysen) = lse_sysen { 348 if let Some(lse_sysen) = lse_sysen {
@@ -272,6 +357,7 @@ impl LsConfig {
272 } 357 }
273 358
274 if self.rtc != RtcClockSource::DISABLE { 359 if self.rtc != RtcClockSource::DISABLE {
360 #[cfg(not(rcc_n6))]
275 bdcr().modify(|w| { 361 bdcr().modify(|w| {
276 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))] 362 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))]
277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 363 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
@@ -280,6 +366,12 @@ impl LsConfig {
280 w.set_rtcen(true); 366 w.set_rtcen(true);
281 w.set_rtcsel(self.rtc); 367 w.set_rtcsel(self.rtc);
282 }); 368 });
369
370 #[cfg(rcc_n6)]
371 {
372 crate::pac::RCC.ccipr7().modify(|w| w.set_rtcsel(self.rtc));
373 crate::pac::RCC.apb4lenr().modify(|w| w.set_rtcen(true))
374 }
283 } 375 }
284 376
285 trace!("BDCR configured: {:08x}", bdcr().read().0); 377 trace!("BDCR configured: {:08x}", bdcr().read().0);
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 8f2e8db5f..d941054cd 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -1,13 +1,13 @@
1use stm32_metapac::flash::vals::Latency; 1use stm32_metapac::flash::vals::Latency;
2 2
3#[cfg(any(stm32f4, stm32f7))]
4use crate::pac::PWR;
3#[cfg(any(stm32f413, stm32f423, stm32f412))] 5#[cfg(any(stm32f413, stm32f423, stm32f412))]
4pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; 6pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource;
5pub use crate::pac::rcc::vals::{ 7pub use crate::pac::rcc::vals::{
6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, 8 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 9 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 10};
9#[cfg(any(stm32f4, stm32f7))]
10use crate::pac::PWR;
11use crate::pac::{FLASH, RCC}; 11use crate::pac::{FLASH, RCC};
12use crate::time::Hertz; 12use crate::time::Hertz;
13 13
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 331bab7a0..485edd390 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -597,7 +597,10 @@ pub(crate) unsafe fn init(config: Config) {
597 Hertz(24_000_000) => Usbrefcksel::MHZ24, 597 Hertz(24_000_000) => Usbrefcksel::MHZ24,
598 Hertz(26_000_000) => Usbrefcksel::MHZ26, 598 Hertz(26_000_000) => Usbrefcksel::MHZ26,
599 Hertz(32_000_000) => Usbrefcksel::MHZ32, 599 Hertz(32_000_000) => Usbrefcksel::MHZ32,
600 _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 600 _ => panic!(
601 "cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
602 clk_val
603 ),
601 }, 604 },
602 None => Usbrefcksel::MHZ24, 605 None => Usbrefcksel::MHZ24,
603 }; 606 };
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index 81b89046e..2e1cbd702 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -499,9 +499,9 @@ pub use pll::*;
499 499
500#[cfg(any(stm32l0, stm32l1))] 500#[cfg(any(stm32l0, stm32l1))]
501mod pll { 501mod pll {
502 use super::{pll_enable, PllInstance}; 502 use super::{PllInstance, pll_enable};
503 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
504 use crate::pac::RCC; 503 use crate::pac::RCC;
504 pub use crate::pac::rcc::vals::{Plldiv as PllDiv, Pllmul as PllMul, Pllsrc as PllSource};
505 use crate::time::Hertz; 505 use crate::time::Hertz;
506 506
507 #[derive(Clone, Copy)] 507 #[derive(Clone, Copy)]
@@ -563,11 +563,11 @@ mod pll {
563 563
564#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] 564#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))]
565mod pll { 565mod pll {
566 use super::{pll_enable, PllInstance}; 566 use super::{PllInstance, pll_enable};
567 use crate::pac::RCC;
567 pub use crate::pac::rcc::vals::{ 568 pub use crate::pac::rcc::vals::{
568 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, 569 Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource,
569 }; 570 };
570 use crate::pac::RCC;
571 use crate::time::Hertz; 571 use crate::time::Hertz;
572 572
573 #[derive(Clone, Copy)] 573 #[derive(Clone, Copy)]
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index fa4b45a20..0624fdf26 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -3,6 +3,7 @@ use core::marker::PhantomData;
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4 4
5use crate::gpio::{AfType, OutputType, Speed}; 5use crate::gpio::{AfType, OutputType, Speed};
6use crate::pac::RCC;
6#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] 7#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
7pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; 8pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
8#[cfg(not(any( 9#[cfg(not(any(
@@ -15,7 +16,8 @@ pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
15 rcc_h7ab, 16 rcc_h7ab,
16 rcc_h7rm0433, 17 rcc_h7rm0433,
17 rcc_h7, 18 rcc_h7,
18 rcc_h7rs 19 rcc_h7rs,
20 rcc_n6
19)))] 21)))]
20pub use crate::pac::rcc::vals::Mcosel as McoSource; 22pub use crate::pac::rcc::vals::Mcosel as McoSource;
21#[cfg(any( 23#[cfg(any(
@@ -28,11 +30,11 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource;
28 rcc_h7ab, 30 rcc_h7ab,
29 rcc_h7rm0433, 31 rcc_h7rm0433,
30 rcc_h7, 32 rcc_h7,
31 rcc_h7rs 33 rcc_h7rs,
34 rcc_n6
32))] 35))]
33pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; 36pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
34use crate::pac::RCC; 37use crate::{Peri, peripherals};
35use crate::{peripherals, Peri};
36 38
37#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] 39#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
38#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] 40#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
@@ -59,10 +61,12 @@ macro_rules! impl_peri {
59 type Source = $source; 61 type Source = $source;
60 62
61 unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { 63 unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) {
62 #[cfg(not(any(stm32u5, stm32wba)))] 64 #[cfg(not(any(stm32u5, stm32wba, stm32n6)))]
63 let r = RCC.cfgr(); 65 let r = RCC.cfgr();
64 #[cfg(any(stm32u5, stm32wba))] 66 #[cfg(any(stm32u5, stm32wba))]
65 let r = RCC.cfgr1(); 67 let r = RCC.cfgr1();
68 #[cfg(any(stm32n6))]
69 let r = RCC.ccipr5();
66 70
67 r.modify(|w| { 71 r.modify(|w| {
68 w.$set_source(source); 72 w.$set_source(source);
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index c41f81816..85434fa83 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -28,12 +28,13 @@ pub use hsi48::*;
28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] 28#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
29#[cfg_attr(stm32u5, path = "u5.rs")] 29#[cfg_attr(stm32u5, path = "u5.rs")]
30#[cfg_attr(stm32wba, path = "wba.rs")] 30#[cfg_attr(stm32wba, path = "wba.rs")]
31#[cfg_attr(stm32n6, path = "n6.rs")]
31mod _version; 32mod _version;
32 33
33pub use _version::*; 34pub use _version::*;
34use stm32_metapac::RCC; 35use stm32_metapac::RCC;
35 36
36pub use crate::_generated::{mux, Clocks}; 37pub use crate::_generated::{Clocks, mux};
37use crate::time::Hertz; 38use crate::time::Hertz;
38 39
39#[cfg(feature = "low-power")] 40#[cfg(feature = "low-power")]
@@ -48,6 +49,12 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
48/// May be read without a critical section 49/// May be read without a critical section
49pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 50pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
50 51
52#[cfg(feature = "low-power")]
53pub(crate) static mut RCC_CONFIG: Option<Config> = None;
54
55#[cfg(backup_sram)]
56pub(crate) static mut BKSRAM_RETAINED: bool = false;
57
51#[cfg(not(feature = "_dual-core"))] 58#[cfg(not(feature = "_dual-core"))]
52/// Frozen clock frequencies 59/// Frozen clock frequencies
53/// 60///
@@ -104,6 +111,32 @@ pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clo
104 unsafe { get_freqs() } 111 unsafe { get_freqs() }
105} 112}
106 113
114#[cfg(feature = "low-power")]
115pub(crate) fn increment_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
116 match stop_mode {
117 StopMode::Standby => {}
118 StopMode::Stop2 => unsafe {
119 REFCOUNT_STOP2 += 1;
120 },
121 StopMode::Stop1 => unsafe {
122 REFCOUNT_STOP1 += 1;
123 },
124 }
125}
126
127#[cfg(feature = "low-power")]
128pub(crate) fn decrement_stop_refcount(_cs: CriticalSection, stop_mode: StopMode) {
129 match stop_mode {
130 StopMode::Standby => {}
131 StopMode::Stop2 => unsafe {
132 REFCOUNT_STOP2 -= 1;
133 },
134 StopMode::Stop1 => unsafe {
135 REFCOUNT_STOP1 -= 1;
136 },
137 }
138}
139
107pub(crate) trait SealedRccPeripheral { 140pub(crate) trait SealedRccPeripheral {
108 fn frequency() -> Hertz; 141 fn frequency() -> Hertz;
109 #[allow(dead_code)] 142 #[allow(dead_code)]
@@ -134,12 +167,19 @@ pub(crate) struct RccInfo {
134 stop_mode: StopMode, 167 stop_mode: StopMode,
135} 168}
136 169
170/// Specifies a limit for the stop mode of the peripheral or the stop mode to be entered.
171/// E.g. if `StopMode::Stop1` is selected, the peripheral prevents the chip from entering Stop1 mode.
137#[cfg(feature = "low-power")] 172#[cfg(feature = "low-power")]
138#[allow(dead_code)] 173#[allow(dead_code)]
139pub(crate) enum StopMode { 174#[derive(Debug, Clone, Copy, PartialEq, Default)]
140 Standby, 175pub enum StopMode {
141 Stop2, 176 #[default]
177 /// Peripheral prevents chip from entering Stop1 or executor will enter Stop1
142 Stop1, 178 Stop1,
179 /// Peripheral prevents chip from entering Stop2 or executor will enter Stop2
180 Stop2,
181 /// Peripheral does not prevent chip from entering Stop
182 Standby,
143} 183}
144 184
145impl RccInfo { 185impl RccInfo {
@@ -195,15 +235,7 @@ impl RccInfo {
195 } 235 }
196 236
197 #[cfg(feature = "low-power")] 237 #[cfg(feature = "low-power")]
198 match self.stop_mode { 238 increment_stop_refcount(_cs, self.stop_mode);
199 StopMode::Standby => {}
200 StopMode::Stop2 => unsafe {
201 REFCOUNT_STOP2 += 1;
202 },
203 StopMode::Stop1 => unsafe {
204 REFCOUNT_STOP1 += 1;
205 },
206 }
207 239
208 // set the xxxRST bit 240 // set the xxxRST bit
209 let reset_ptr = self.reset_ptr(); 241 let reset_ptr = self.reset_ptr();
@@ -261,15 +293,7 @@ impl RccInfo {
261 } 293 }
262 294
263 #[cfg(feature = "low-power")] 295 #[cfg(feature = "low-power")]
264 match self.stop_mode { 296 decrement_stop_refcount(_cs, self.stop_mode);
265 StopMode::Standby => {}
266 StopMode::Stop2 => unsafe {
267 REFCOUNT_STOP2 -= 1;
268 },
269 StopMode::Stop1 => unsafe {
270 REFCOUNT_STOP1 -= 1;
271 },
272 }
273 297
274 // clear the xxxEN bit 298 // clear the xxxEN bit
275 let enable_ptr = self.enable_ptr(); 299 let enable_ptr = self.enable_ptr();
@@ -390,7 +414,7 @@ pub fn disable<T: RccPeripheral>() {
390/// 414///
391/// This should only be called after `init`. 415/// This should only be called after `init`.
392#[cfg(not(feature = "_dual-core"))] 416#[cfg(not(feature = "_dual-core"))]
393pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { 417pub fn reinit(config: Config, _rcc: &'_ mut crate::Peri<'_, crate::peripherals::RCC>) {
394 critical_section::with(|cs| init_rcc(cs, config)) 418 critical_section::with(|cs| init_rcc(cs, config))
395} 419}
396 420
@@ -404,8 +428,39 @@ pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) {
404 428
405 #[cfg(feature = "low-power")] 429 #[cfg(feature = "low-power")]
406 { 430 {
431 RCC_CONFIG = Some(config);
407 REFCOUNT_STOP2 = 0; 432 REFCOUNT_STOP2 = 0;
408 REFCOUNT_STOP1 = 0; 433 REFCOUNT_STOP1 = 0;
409 } 434 }
410 } 435 }
411} 436}
437
438/// Calculate intermediate prescaler number used to calculate peripheral prescalers
439///
440/// This function is intended to calculate a number indicating a minimum division
441/// necessary to result in a frequency lower than the provided `freq_max`.
442///
443/// The returned value indicates the `val + 1` divider is necessary to result in
444/// the output frequency that is below the maximum provided.
445///
446/// For example:
447/// 0 = divider of 1 => no division necessary as the input frequency is below max
448/// 1 = divider of 2 => division by 2 necessary
449/// ...
450///
451/// The provided max frequency is inclusive. So if `freq_in == freq_max` the result
452/// will be 0, indicating that no division is necessary. To accomplish that we subtract
453/// 1 from the input frequency so that the integer rounding plays in our favor.
454///
455/// For example:
456/// Let the input frequency be 110 and the max frequency be 55.
457/// If we naiively do `110/55 = 2` the renult will indicate that we need a divider by 3
458/// which in reality will be rounded up to 4 as usually a 3 division is not available.
459/// In either case the resulting frequency will be either 36 or 27 which is lower than
460/// what we would want. The result should be 1.
461/// If we do the following instead `109/55 = 1` indicating that we need a divide by 2
462/// which will result in the correct 55.
463#[allow(unused)]
464pub(crate) fn raw_prescaler(freq_in: u32, freq_max: u32) -> u32 {
465 freq_in.saturating_sub(1) / freq_max
466}
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs
new file mode 100644
index 000000000..866851bbd
--- /dev/null
+++ b/embassy-stm32/src/rcc/n6.rs
@@ -0,0 +1,1046 @@
1use stm32_metapac::rcc::vals::{
2 Cpusw, Cpusws, Hseext, Hsitrim, Icint, Icsel, Msifreqsel, Plldivm, Pllmodssdis, Pllpdiv, Pllsel, Syssw, Syssws,
3 Timpre,
4};
5pub use stm32_metapac::rcc::vals::{
6 Hpre as AhbPrescaler, Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Ppre as ApbPrescaler,
7};
8
9use crate::pac::{PWR, RCC, SYSCFG};
10use crate::time::Hertz;
11
12pub const HSI_FREQ: Hertz = Hertz(64_000_000);
13pub const LSE_FREQ: Hertz = Hertz(32_768);
14
15#[derive(Clone, Copy, Eq, PartialEq)]
16pub enum HseMode {
17 /// crystal/ceramic oscillator
18 Oscillator,
19 /// oscillator bypassed with external clock (analog)
20 Bypass,
21 /// oscillator bypassed with external digital clock
22 BypassDigital,
23}
24
25#[derive(Clone, Copy, Eq, PartialEq)]
26pub struct Hse {
27 /// HSE frequency.
28 pub freq: Hertz,
29 /// HSE oscillator mode.
30 pub mode: HseMode,
31}
32
33#[derive(Clone, Copy, Eq, PartialEq)]
34pub struct Hsi {
35 pub pre: HsiPrescaler,
36 pub trim: Hsitrim,
37}
38
39#[derive(Clone, Copy, PartialEq)]
40pub enum SupplyConfig {
41 Smps,
42 External,
43}
44
45#[derive(Clone, Copy, PartialEq)]
46pub enum CpuClk {
47 Hse,
48 Ic1 { source: Icsel, divider: Icint },
49 Msi,
50 Hsi,
51}
52
53impl CpuClk {
54 const fn to_bits(self) -> u8 {
55 match self {
56 Self::Hsi => 0x0,
57 Self::Msi => 0x1,
58 Self::Hse => 0x2,
59 Self::Ic1 { .. } => 0x3,
60 }
61 }
62}
63
64#[derive(Clone, Copy, PartialEq)]
65pub struct IcConfig {
66 source: Icsel,
67 divider: Icint,
68}
69
70#[derive(Clone, Copy, PartialEq)]
71pub enum SysClk {
72 Hse,
73 Ic2 {
74 ic2: IcConfig,
75 ic6: IcConfig,
76 ic11: IcConfig,
77 },
78 Msi,
79 Hsi,
80}
81
82impl SysClk {
83 const fn to_bits(self) -> u8 {
84 match self {
85 Self::Hsi => 0x0,
86 Self::Msi => 0x1,
87 Self::Hse => 0x2,
88 Self::Ic2 { .. } => 0x3,
89 }
90 }
91}
92
93#[derive(Clone, Copy, PartialEq)]
94pub struct Msi {
95 pub freq: Msifreqsel,
96 pub trim: u8,
97}
98
99#[derive(Clone, Copy, PartialEq)]
100pub enum Pll {
101 Oscillator {
102 source: Pllsel,
103 divm: Plldivm,
104 fractional: u32,
105 divn: u16,
106 divp1: Pllpdiv,
107 divp2: Pllpdiv,
108 },
109 Bypass {
110 source: Pllsel,
111 },
112}
113
114/// Configuration of the core clocks
115#[non_exhaustive]
116#[derive(Clone, Copy)]
117pub struct Config {
118 pub hsi: Option<Hsi>,
119 pub hse: Option<Hse>,
120 pub msi: Option<Msi>,
121 pub lsi: bool,
122 pub lse: bool,
123
124 pub sys: SysClk,
125 pub cpu: CpuClk,
126
127 pub pll1: Option<Pll>,
128 pub pll2: Option<Pll>,
129 pub pll3: Option<Pll>,
130 pub pll4: Option<Pll>,
131
132 pub ahb: AhbPrescaler,
133 pub apb1: ApbPrescaler,
134 pub apb2: ApbPrescaler,
135 pub apb4: ApbPrescaler,
136 pub apb5: ApbPrescaler,
137
138 pub supply_config: SupplyConfig,
139}
140
141impl Config {
142 pub const fn new() -> Self {
143 Self {
144 hsi: Some(Hsi {
145 pre: HsiPrescaler::DIV1,
146 trim: HsiCalibration::from_bits(32),
147 }),
148 hse: None,
149 msi: None,
150 lsi: true,
151 lse: false,
152 sys: SysClk::Hsi,
153 cpu: CpuClk::Hsi,
154 pll1: Some(Pll::Bypass { source: Pllsel::HSI }),
155 pll2: Some(Pll::Bypass { source: Pllsel::HSI }),
156 pll3: Some(Pll::Bypass { source: Pllsel::HSI }),
157 pll4: Some(Pll::Bypass { source: Pllsel::HSI }),
158
159 ahb: AhbPrescaler::DIV2,
160 apb1: ApbPrescaler::DIV1,
161 apb2: ApbPrescaler::DIV1,
162 apb4: ApbPrescaler::DIV1,
163 apb5: ApbPrescaler::DIV1,
164
165 supply_config: SupplyConfig::Smps,
166 }
167 }
168}
169
170#[allow(dead_code)]
171struct ClocksOutput {
172 cpuclk: Hertz,
173 sysclk: Hertz,
174 pclk_tim: Hertz,
175 ahb: Hertz,
176 apb1: Hertz,
177 apb2: Hertz,
178 apb4: Hertz,
179 apb5: Hertz,
180}
181
182struct ClocksInput {
183 hsi: Option<Hertz>,
184 msi: Option<Hertz>,
185 hse: Option<Hertz>,
186}
187
188fn init_clocks(config: Config, input: &ClocksInput) -> ClocksOutput {
189 // handle increasing dividers
190 debug!("configuring increasing pclk dividers");
191 RCC.cfgr2().modify(|w| {
192 if config.apb1 > w.ppre1() {
193 debug!(" - APB1");
194 w.set_ppre1(config.apb1);
195 }
196 if config.apb2 > w.ppre2() {
197 debug!(" - APB2");
198 w.set_ppre2(config.apb2);
199 }
200 if config.apb4 > w.ppre4() {
201 debug!(" - APB4");
202 w.set_ppre4(config.apb4);
203 }
204 if config.apb5 > w.ppre5() {
205 debug!(" - APB5");
206 w.set_ppre5(config.apb5);
207 }
208 if config.ahb > w.hpre() {
209 debug!(" - AHB");
210 w.set_hpre(config.ahb);
211 }
212 });
213 // cpuclk
214 debug!("configuring cpuclk");
215 match config.cpu {
216 CpuClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"),
217 CpuClk::Ic1 { source, divider } => {
218 if !pll_sources_ready(RCC.iccfgr(0).read().icsel().to_bits(), source.to_bits()) {
219 panic!("ICx clock switch requires both origin and destination clock source to be active")
220 }
221
222 RCC.iccfgr(0).write(|w| {
223 w.set_icsel(source);
224 w.set_icint(divider);
225 });
226 RCC.divensr().modify(|w| w.set_ic1ens(true));
227 }
228 CpuClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"),
229 CpuClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"),
230 _ => {}
231 }
232 // set source
233 let cpusw = Cpusw::from_bits(config.cpu.to_bits());
234 RCC.cfgr().modify(|w| w.set_cpusw(cpusw));
235 // wait for changes to take effect
236 while RCC.cfgr().read().cpusws() != Cpusws::from_bits(config.cpu.to_bits()) {}
237
238 // sysclk
239 debug!("configuring sysclk");
240 match config.sys {
241 SysClk::Hse if !RCC.sr().read().hserdy() => panic!("HSE is not ready to be selected as CPU clock source"),
242 SysClk::Ic2 { ic2, ic6, ic11 } => {
243 if !pll_sources_ready(RCC.iccfgr(1).read().icsel().to_bits(), ic2.source.to_bits()) {
244 panic!("IC2 clock switch requires both origin and destination clock source to be active")
245 }
246 if !pll_sources_ready(RCC.iccfgr(5).read().icsel().to_bits(), ic6.source.to_bits()) {
247 panic!("IC6 clock switch requires both origin and destination clock source to be active")
248 }
249 if !pll_sources_ready(RCC.iccfgr(10).read().icsel().to_bits(), ic11.source.to_bits()) {
250 panic!("IC11 clock switch requires both origin and destination clock source to be active")
251 }
252
253 RCC.iccfgr(1).write(|w| {
254 w.set_icsel(ic2.source);
255 w.set_icint(ic2.divider);
256 });
257 RCC.iccfgr(5).write(|w| {
258 w.set_icsel(ic6.source);
259 w.set_icint(ic6.divider);
260 });
261 RCC.iccfgr(10).write(|w| {
262 w.set_icsel(ic11.source);
263 w.set_icint(ic11.divider);
264 });
265 RCC.divensr().modify(|w| {
266 w.set_ic2ens(true);
267 w.set_ic6ens(true);
268 w.set_ic11ens(true);
269 });
270 }
271 SysClk::Msi if !RCC.sr().read().msirdy() => panic!("MSI is not ready to be selected as CPU clock source"),
272 SysClk::Hsi if !RCC.sr().read().hsirdy() => panic!("HSI is not ready to be selected as CPU clock source"),
273 _ => {}
274 }
275 // switch the system bus clock
276 let syssw = Syssw::from_bits(config.sys.to_bits());
277 RCC.cfgr().modify(|w| w.set_syssw(syssw));
278 // wait for changes to be applied
279 while RCC.cfgr().read().syssws() != Syssws::from_bits(config.sys.to_bits()) {}
280
281 // decreasing dividers
282 debug!("configuring decreasing pclk dividers");
283 RCC.cfgr2().modify(|w| {
284 if config.ahb < w.hpre() {
285 debug!(" - AHB");
286 w.set_hpre(config.ahb);
287 }
288 if config.apb1 < w.ppre1() {
289 debug!(" - APB1");
290 w.set_ppre1(config.apb1);
291 }
292 if config.apb2 < w.ppre2() {
293 debug!(" - APB2");
294 w.set_ppre2(config.apb2);
295 }
296 if config.apb4 < w.ppre4() {
297 debug!(" - APB4");
298 w.set_ppre4(config.apb4);
299 }
300 if config.apb5 < w.ppre5() {
301 debug!(" - APB5");
302 w.set_ppre5(config.apb5);
303 }
304 });
305
306 let cpuclk = match config.cpu {
307 CpuClk::Hsi => unwrap!(input.hsi),
308 CpuClk::Msi => unwrap!(input.msi),
309 CpuClk::Hse => unwrap!(input.hse),
310 CpuClk::Ic1 { .. } => todo!(),
311 };
312
313 let sysclk = match config.sys {
314 SysClk::Hsi => unwrap!(input.hsi),
315 SysClk::Msi => unwrap!(input.msi),
316 SysClk::Hse => unwrap!(input.hse),
317 SysClk::Ic2 { .. } => todo!(),
318 };
319
320 let timpre: u32 = match RCC.cfgr2().read().timpre() {
321 Timpre::DIV1 => 1,
322 Timpre::DIV2 => 2,
323 Timpre::DIV4 => 4,
324 Timpre::_RESERVED_3 => 8,
325 };
326
327 let hpre = periph_prescaler_to_value(config.ahb.to_bits());
328 let ppre1 = periph_prescaler_to_value(config.apb1.to_bits());
329 let ppre2 = periph_prescaler_to_value(config.apb2.to_bits());
330 let ppre4 = periph_prescaler_to_value(config.apb4.to_bits());
331 let ppre5 = periph_prescaler_to_value(config.apb5.to_bits());
332
333 // enable all peripherals in sleep mode
334 enable_low_power_peripherals();
335
336 // enable interrupts
337 unsafe {
338 core::arch::asm!("cpsie i");
339 }
340
341 ClocksOutput {
342 sysclk,
343 cpuclk,
344 pclk_tim: sysclk / timpre,
345 ahb: Hertz(sysclk.0 / hpre as u32),
346 apb1: sysclk / hpre / ppre1,
347 apb2: sysclk / hpre / ppre2,
348 apb4: sysclk / hpre / ppre4,
349 apb5: sysclk / hpre / ppre5,
350 }
351}
352
353fn enable_low_power_peripherals() {
354 // AHB1-5
355 RCC.ahb1lpenr().modify(|w| {
356 w.set_adc12lpen(true);
357 w.set_gpdma1lpen(true);
358 });
359 RCC.ahb2lpenr().modify(|w| {
360 w.set_adf1lpen(true);
361 w.set_mdf1lpen(true);
362 w.set_ramcfglpen(true);
363 });
364 RCC.ahb3lpenr().modify(|w| {
365 w.set_risaflpen(true);
366 w.set_iaclpen(true);
367 w.set_rifsclpen(true);
368 w.set_pkalpen(true);
369 w.set_saeslpen(true);
370 w.set_cryplpen(true);
371 w.set_hashlpen(true);
372 w.set_rnglpen(true);
373 });
374 RCC.ahb4lpenr().modify(|w| {
375 w.set_crclpen(true);
376 w.set_pwrlpen(true);
377 w.set_gpioqlpen(true);
378 w.set_gpioplpen(true);
379 w.set_gpioolpen(true);
380 w.set_gpionlpen(true);
381 w.set_gpiohlpen(true);
382 w.set_gpioglpen(true);
383 w.set_gpioflpen(true);
384 w.set_gpioelpen(true);
385 w.set_gpiodlpen(true);
386 w.set_gpioclpen(true);
387 w.set_gpioblpen(true);
388 w.set_gpioalpen(true);
389 });
390 RCC.ahb5lpenr().modify(|w| {
391 w.set_npulpen(true);
392 w.set_npucachelpen(true);
393 w.set_otg2lpen(true);
394 w.set_otgphy2lpen(true);
395 w.set_otgphy1lpen(true);
396 w.set_otg1lpen(true);
397 w.set_eth1lpen(true);
398 w.set_eth1rxlpen(true);
399 w.set_eth1txlpen(true);
400 w.set_eth1maclpen(true);
401 w.set_gpulpen(true);
402 w.set_gfxmmulpen(true);
403 w.set_mce4lpen(true);
404 w.set_xspi3lpen(true);
405 w.set_mce3lpen(true);
406 w.set_mce2lpen(true);
407 w.set_mce1lpen(true);
408 w.set_xspimlpen(true);
409 w.set_xspi2lpen(true);
410 w.set_sdmmc1lpen(true);
411 w.set_sdmmc2lpen(true);
412 w.set_pssilpen(true);
413 w.set_xspi1lpen(true);
414 w.set_fmclpen(true);
415 w.set_jpeglpen(true);
416 w.set_dma2dlpen(true);
417 w.set_hpdma1lpen(true);
418 });
419
420 // APB1-5
421 RCC.apb1llpenr().modify(|w| {
422 w.set_uart8lpen(true);
423 w.set_uart7lpen(true);
424 w.set_i3c2lpen(true);
425 w.set_i3c1lpen(true);
426 w.set_i2c3lpen(true);
427 w.set_i2c2lpen(true);
428 w.set_i2c1lpen(true);
429 w.set_uart5lpen(true);
430 w.set_uart4lpen(true);
431 w.set_usart3lpen(true);
432 w.set_usart2lpen(true);
433 w.set_spdifrx1lpen(true);
434 w.set_spi3lpen(true);
435 w.set_spi2lpen(true);
436 w.set_tim11lpen(true);
437 w.set_tim10lpen(true);
438 w.set_wwdglpen(true);
439 w.set_lptim1lpen(true);
440 w.set_tim14lpen(true);
441 w.set_tim13lpen(true);
442 w.set_tim12lpen(true);
443 w.set_tim7lpen(true);
444 w.set_tim6lpen(true);
445 w.set_tim5lpen(true);
446 w.set_tim4lpen(true);
447 w.set_tim3lpen(true);
448 w.set_tim2lpen(true);
449 });
450 RCC.apb1hlpenr().modify(|w| {
451 w.set_ucpd1lpen(true);
452 w.set_fdcanlpen(true);
453 w.set_mdioslpen(true);
454 });
455 RCC.apb2lpenr().modify(|w| {
456 w.set_sai2lpen(true);
457 w.set_sai1lpen(true);
458 w.set_spi5lpen(true);
459 w.set_tim9lpen(true);
460 w.set_tim17lpen(true);
461 w.set_tim16lpen(true);
462 w.set_tim15lpen(true);
463 w.set_tim18lpen(true);
464 w.set_spi4lpen(true);
465 w.set_spi1lpen(true);
466 w.set_usart10lpen(true);
467 w.set_uart9lpen(true);
468 w.set_usart6lpen(true);
469 w.set_usart1lpen(true);
470 w.set_tim8lpen(true);
471 w.set_tim1lpen(true);
472 });
473 RCC.apb3lpenr().modify(|w| {
474 w.set_dftlpen(true);
475 });
476 RCC.apb4llpenr().modify(|w| {
477 w.set_rtcapblpen(true);
478 w.set_rtclpen(true);
479 w.set_vrefbuflpen(true);
480 w.set_lptim5lpen(true);
481 w.set_lptim4lpen(true);
482 w.set_lptim3lpen(true);
483 w.set_lptim2lpen(true);
484 w.set_i2c4lpen(true);
485 w.set_spi6lpen(true);
486 w.set_lpuart1lpen(true);
487 w.set_hdplpen(true);
488 });
489 RCC.apb4hlpenr().modify(|w| {
490 w.set_dtslpen(true);
491 w.set_bseclpen(true);
492 w.set_syscfglpen(true);
493 });
494 RCC.apb5lpenr().modify(|w| {
495 w.set_csilpen(true);
496 w.set_venclpen(true);
497 w.set_gfxtimlpen(true);
498 w.set_dcmilpen(true);
499 w.set_ltdclpen(true);
500 });
501
502 RCC.buslpenr().modify(|w| {
503 w.set_aclknclpen(true);
504 w.set_aclknlpen(true);
505 });
506
507 RCC.memlpenr().modify(|w| {
508 w.set_bootromlpen(true);
509 w.set_vencramlpen(true);
510 w.set_npucacheramlpen(true);
511 w.set_flexramlpen(true);
512 w.set_axisram2lpen(true);
513 w.set_axisram1lpen(true);
514 w.set_bkpsramlpen(true);
515 w.set_ahbsram2lpen(true);
516 w.set_ahbsram1lpen(true);
517 w.set_axisram6lpen(true);
518 w.set_axisram5lpen(true);
519 w.set_axisram4lpen(true);
520 w.set_axisram3lpen(true);
521 });
522
523 RCC.misclpenr().modify(|w| {
524 w.set_perlpen(true);
525 w.set_xspiphycomplpen(true);
526 w.set_dbglpen(true);
527 });
528}
529
530const fn periph_prescaler_to_value(bits: u8) -> u8 {
531 match bits {
532 0 => 1,
533 1 => 2,
534 2 => 4,
535 3 => 8,
536 4 => 16,
537 5 => 32,
538 6 => 64,
539 7.. => 128,
540 }
541}
542
543fn pll_source_ready(source: u8) -> bool {
544 match source {
545 0x0 if !RCC.sr().read().pllrdy(0) && !RCC.pllcfgr1(0).read().pllbyp() => false,
546 0x1 if !RCC.sr().read().pllrdy(1) && !RCC.pllcfgr1(1).read().pllbyp() => false,
547 0x2 if !RCC.sr().read().pllrdy(2) && !RCC.pllcfgr1(2).read().pllbyp() => false,
548 0x3 if !RCC.sr().read().pllrdy(3) && !RCC.pllcfgr1(3).read().pllbyp() => false,
549 _ => true,
550 }
551}
552
553fn pll_sources_ready(source1: u8, source2: u8) -> bool {
554 pll_source_ready(source1) && pll_source_ready(source2)
555}
556
557impl Default for Config {
558 fn default() -> Self {
559 Self::new()
560 }
561}
562
563fn power_supply_config(supply_config: SupplyConfig) {
564 // power supply config
565 PWR.cr1().modify(|w| {
566 w.set_sden(match supply_config {
567 SupplyConfig::External => false,
568 SupplyConfig::Smps => true,
569 });
570 });
571
572 // Validate supply configuration
573 while !PWR.voscr().read().actvosrdy() {}
574}
575
576struct PllInput {
577 hsi: Option<Hertz>,
578 msi: Option<Hertz>,
579 hse: Option<Hertz>,
580 i2s_ckin: Option<Hertz>,
581}
582
583#[derive(Clone, Copy, Default)]
584#[allow(dead_code)]
585struct PllOutput {
586 divm: Option<Hertz>,
587 divn: Option<Hertz>,
588 divp1: Option<Hertz>,
589 divp2: Option<Hertz>,
590 output: Option<Hertz>,
591}
592
593fn init_pll(pll_config: Option<Pll>, pll_index: usize, input: &PllInput) -> PllOutput {
594 let cfgr1 = RCC.pllcfgr1(pll_index);
595 let cfgr2 = RCC.pllcfgr2(pll_index);
596 let cfgr3 = RCC.pllcfgr3(pll_index);
597
598 match pll_config {
599 Some(Pll::Oscillator {
600 source,
601 divm,
602 fractional,
603 divn,
604 divp1,
605 divp2,
606 }) => {
607 // ensure pll is disabled
608 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
609 while RCC.sr().read().pllrdy(pll_index) {}
610
611 // ensure PLLxMODSSDIS=1 to work in fractional mode
612 cfgr3.modify(|w| w.set_pllmodssdis(Pllmodssdis::FRACTIONAL_DIVIDE));
613 // clear bypass mode
614 cfgr1.modify(|w| w.set_pllbyp(false));
615 // configure the pll clock source, mul and div factors
616 cfgr1.modify(|w| {
617 w.set_pllsel(source);
618 w.set_plldivm(divm);
619 w.set_plldivn(divn);
620 });
621
622 let in_clk = match source {
623 Pllsel::HSI => unwrap!(input.hsi),
624 Pllsel::MSI => unwrap!(input.msi),
625 Pllsel::HSE => unwrap!(input.hse),
626 Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin),
627 _ => panic!("reserved PLL source not allowed"),
628 };
629
630 let m = divm.to_bits() as u32;
631 let n = divn as u32;
632
633 cfgr3.modify(|w| {
634 w.set_pllpdiv1(divp1);
635 w.set_pllpdiv2(divp2);
636 });
637
638 let p1 = divp1.to_bits() as u32;
639 let p2 = divp2.to_bits() as u32;
640
641 // configure pll divnfrac
642 cfgr2.modify(|w| w.set_plldivnfrac(fractional));
643 // clear pllxmoddsen
644 cfgr3.modify(|w| w.set_pllmoddsen(false));
645 // fractional mode
646 if fractional != 0 {
647 cfgr3.modify(|w| {
648 w.set_pllmoddsen(true);
649 w.set_plldacen(true);
650 })
651 }
652 // enable pll post divider output
653 cfgr3.modify(|w| {
654 w.set_pllmodssrst(true);
655 w.set_pllpdiven(true);
656 });
657 // enable the pll
658 RCC.csr().write(|w| w.pllons(pll_index));
659 // wait until ready
660 while RCC.sr().read().pllrdy(pll_index) {}
661
662 PllOutput {
663 divm: Some(Hertz(m)),
664 divn: Some(Hertz(n)),
665 divp1: Some(Hertz(p1)),
666 divp2: Some(Hertz(p2)),
667 output: Some(Hertz(in_clk.0 / m / n / p1 / p2)),
668 }
669 }
670 Some(Pll::Bypass { source }) => {
671 // check if source is ready
672 if !pll_source_ready(source.to_bits()) {
673 panic!("PLL source is not ready")
674 }
675
676 // ensure pll is disabled
677 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
678 while RCC.sr().read().pllrdy(pll_index) {}
679
680 cfgr1.modify(|w| {
681 w.set_pllbyp(true);
682 w.set_pllsel(source);
683 });
684
685 let in_clk = match source {
686 Pllsel::HSI => unwrap!(input.hsi),
687 Pllsel::MSI => unwrap!(input.msi),
688 Pllsel::HSE => unwrap!(input.hse),
689 Pllsel::I2S_CKIN => unwrap!(input.i2s_ckin),
690 _ => panic!("reserved PLL source not allowed"),
691 };
692
693 PllOutput {
694 output: Some(in_clk),
695 ..Default::default()
696 }
697 }
698 None => {
699 cfgr3.modify(|w| w.set_pllpdiven(false));
700 RCC.ccr().write(|w| w.set_pllonc(pll_index, true));
701 // wait till disabled
702 while RCC.sr().read().pllrdy(pll_index) {}
703
704 // clear bypass mode
705 cfgr1.modify(|w| w.set_pllbyp(false));
706
707 PllOutput::default()
708 }
709 }
710}
711
712#[allow(dead_code)]
713struct OscOutput {
714 hsi: Option<Hertz>,
715 hse: Option<Hertz>,
716 msi: Option<Hertz>,
717 lsi: Option<Hertz>,
718 lse: Option<Hertz>,
719 pll1: Option<Hertz>,
720 pll2: Option<Hertz>,
721 pll3: Option<Hertz>,
722 pll4: Option<Hertz>,
723 ic1sel: Icsel,
724 ic2sel: Icsel,
725 ic6sel: Icsel,
726 ic11sel: Icsel,
727}
728
729fn init_osc(config: Config) -> OscOutput {
730 let (cpu_src, sys_src) = {
731 let reg = RCC.cfgr().read();
732 (reg.cpusws(), reg.syssws())
733 };
734 let pll1_src = RCC.pllcfgr1(0).read().pllsel();
735 let pll2_src = RCC.pllcfgr1(1).read().pllsel();
736 let pll3_src = RCC.pllcfgr1(2).read().pllsel();
737 let pll4_src = RCC.pllcfgr1(3).read().pllsel();
738 let rcc_sr = RCC.sr().read();
739
740 debug!("configuring HSE");
741
742 // hse configuration
743 let hse = if let Some(hse) = config.hse {
744 match hse.mode {
745 HseMode::Oscillator => {
746 debug!("HSE in oscillator mode");
747 }
748 HseMode::Bypass => {
749 debug!("HSE in bypass mode");
750 RCC.hsecfgr().modify(|w| {
751 w.set_hsebyp(true);
752 w.set_hseext(Hseext::ANALOG);
753 });
754 }
755 HseMode::BypassDigital => {
756 debug!("HSE in bypass digital mode");
757 RCC.hsecfgr().modify(|w| {
758 w.set_hsebyp(true);
759 w.set_hseext(Hseext::DIGITAL);
760 });
761 }
762 }
763 RCC.csr().write(|w| w.set_hseons(true));
764
765 // wait until the hse is ready
766 while !RCC.sr().read().hserdy() {}
767
768 Some(hse.freq)
769 } else if cpu_src == Cpusws::HSE
770 || sys_src == Syssws::HSE
771 || (pll1_src == Pllsel::HSE && rcc_sr.pllrdy(0))
772 || (pll2_src == Pllsel::HSE && rcc_sr.pllrdy(1))
773 || (pll3_src == Pllsel::HSE && rcc_sr.pllrdy(2))
774 || (pll4_src == Pllsel::HSE && rcc_sr.pllrdy(3))
775 {
776 panic!(
777 "When the HSE is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
778 );
779 } else {
780 debug!("HSE off");
781
782 RCC.ccr().write(|w| w.set_hseonc(true));
783 RCC.hsecfgr().modify(|w| {
784 w.set_hseext(Hseext::ANALOG);
785 w.set_hsebyp(false);
786 });
787
788 // wait until the hse is disabled
789 while RCC.sr().read().hserdy() {}
790
791 None
792 };
793
794 // hsi configuration
795 debug!("configuring HSI");
796 let hsi = if let Some(hsi) = config.hsi {
797 RCC.csr().write(|w| w.set_hsions(true));
798 while !RCC.sr().read().hsirdy() {}
799
800 // set divider and calibration
801 RCC.hsicfgr().modify(|w| {
802 w.set_hsidiv(hsi.pre);
803 w.set_hsitrim(hsi.trim);
804 });
805
806 Some(HSI_FREQ / hsi.pre)
807 } else if cpu_src == Cpusws::HSI
808 || sys_src == Syssws::HSI
809 || (pll1_src == Pllsel::HSI && rcc_sr.pllrdy(0))
810 || (pll2_src == Pllsel::HSI && rcc_sr.pllrdy(1))
811 || (pll3_src == Pllsel::HSI && rcc_sr.pllrdy(2))
812 || (pll4_src == Pllsel::HSI && rcc_sr.pllrdy(3))
813 {
814 panic!(
815 "When the HSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
816 );
817 } else {
818 debug!("HSI off");
819
820 RCC.ccr().write(|w| w.set_hsionc(true));
821 while RCC.sr().read().hsirdy() {}
822
823 None
824 };
825
826 // msi configuration
827 debug!("configuring MSI");
828 let msi = if let Some(msi) = config.msi {
829 RCC.msicfgr().modify(|w| w.set_msifreqsel(msi.freq));
830 RCC.csr().write(|w| w.set_msions(true));
831 while !RCC.sr().read().msirdy() {}
832 RCC.msicfgr().modify(|w| w.set_msitrim(msi.trim));
833
834 Some(match msi.freq {
835 Msifreqsel::_4MHZ => Hertz::mhz(4),
836 Msifreqsel::_16MHZ => Hertz::mhz(16),
837 })
838 } else if cpu_src == Cpusws::MSI
839 || sys_src == Syssws::MSI
840 || (pll1_src == Pllsel::MSI && rcc_sr.pllrdy(0))
841 || (pll2_src == Pllsel::MSI && rcc_sr.pllrdy(1))
842 || (pll3_src == Pllsel::MSI && rcc_sr.pllrdy(2))
843 || (pll4_src == Pllsel::MSI && rcc_sr.pllrdy(3))
844 {
845 panic!(
846 "When the MSI is used as cpu/system bus clock or clock source for any PLL, it is not allowed to be disabled"
847 );
848 } else {
849 RCC.ccr().write(|w| w.set_msionc(true));
850 while RCC.sr().read().msirdy() {}
851
852 None
853 };
854
855 // lsi configuration
856 debug!("configuring LSI");
857 let lsi = if config.lsi {
858 RCC.csr().write(|w| w.set_lsions(true));
859 while !RCC.sr().read().lsirdy() {}
860 Some(super::LSI_FREQ)
861 } else {
862 RCC.ccr().write(|w| w.set_lsionc(true));
863 while RCC.sr().read().lsirdy() {}
864 None
865 };
866
867 // lse configuration
868 debug!("configuring LSE");
869 let lse = if config.lse {
870 RCC.csr().write(|w| w.set_lseons(true));
871 while !RCC.sr().read().lserdy() {}
872 Some(LSE_FREQ)
873 } else {
874 RCC.ccr().write(|w| w.set_lseonc(true));
875 while RCC.sr().read().lserdy() {}
876 None
877 };
878
879 let pll_input = PllInput {
880 hse,
881 msi,
882 hsi,
883 i2s_ckin: None,
884 };
885
886 // pll1,2,3,4 config
887 let pll_configs = [config.pll1, config.pll2, config.pll3, config.pll4];
888 let mut pll_outputs: [PllOutput; 4] = [PllOutput::default(); 4];
889
890 let ic1_src = RCC.iccfgr(0).read().icsel();
891 let ic2_src = RCC.iccfgr(1).read().icsel();
892 let ic6_src = RCC.iccfgr(5).read().icsel();
893 let ic11_src = RCC.iccfgr(10).read().icsel();
894
895 for (n, (&pll, out)) in pll_configs.iter().zip(pll_outputs.iter_mut()).enumerate() {
896 debug!("configuring PLL{}", n + 1);
897 let pll_ready = RCC.sr().read().pllrdy(n);
898
899 if is_new_pll_config(pll, 0) {
900 let this_pll = Icsel::from_bits(n as u8);
901
902 if cpu_src == Cpusws::IC1 && ic1_src == this_pll {
903 panic!("PLL should not be disabled / reconfigured if used for IC1 (cpuclksrc)")
904 }
905
906 if sys_src == Syssws::IC2 && (ic2_src == this_pll || ic6_src == this_pll || ic11_src == this_pll) {
907 panic!("PLL should not be disabled / reconfigured if used for IC2, IC6 or IC11 (sysclksrc)")
908 }
909
910 *out = init_pll(pll, 0, &pll_input);
911 } else if pll.is_some() && !pll_ready {
912 RCC.csr().write(|w| w.pllons(n));
913 while !RCC.sr().read().pllrdy(n) {}
914 }
915 }
916
917 OscOutput {
918 hsi,
919 hse,
920 msi,
921 lsi,
922 lse,
923 pll1: pll_outputs[0].output,
924 pll2: pll_outputs[1].output,
925 pll3: pll_outputs[2].output,
926 pll4: pll_outputs[3].output,
927 ic1sel: ic1_src,
928 ic2sel: ic2_src,
929 ic6sel: ic6_src,
930 ic11sel: ic11_src,
931 }
932}
933
934fn is_new_pll_config(pll: Option<Pll>, pll_index: usize) -> bool {
935 let cfgr1 = RCC.pllcfgr1(pll_index).read();
936 let cfgr2 = RCC.pllcfgr2(pll_index).read();
937 let cfgr3 = RCC.pllcfgr3(pll_index).read();
938
939 let ready = RCC.sr().read().pllrdy(pll_index);
940 let bypass = cfgr1.pllbyp();
941
942 match (pll, ready, bypass) {
943 (None, true, _) => return true,
944 (Some(_), false, _) => return true,
945 (Some(conf), true, bypass) => match (conf, bypass) {
946 (Pll::Bypass { .. }, false) => return true,
947 (Pll::Oscillator { .. }, true) => return true,
948 _ => {}
949 },
950 _ => {}
951 }
952
953 match pll {
954 Some(Pll::Bypass { source }) => cfgr1.pllsel() != source,
955 Some(Pll::Oscillator {
956 source,
957 divm: m,
958 fractional,
959 divn: n,
960 divp1: p1,
961 divp2: p2,
962 }) => {
963 cfgr1.pllsel() != source
964 || cfgr1.plldivm() != m
965 || cfgr1.plldivn() != n
966 || cfgr2.plldivnfrac() != fractional
967 || cfgr3.pllpdiv1() != p1
968 || cfgr3.pllpdiv2() != p2
969 }
970 None => false,
971 }
972}
973
974pub(crate) unsafe fn init(config: Config) {
975 debug!("enabling SYSCFG");
976 // system configuration setup
977 RCC.apb4hensr().write(|w| w.set_syscfgens(true));
978 // delay after RCC peripheral clock enabling
979 RCC.apb4hensr().read();
980
981 debug!("setting VTOR");
982
983 let vtor = unsafe {
984 let p = cortex_m::Peripherals::steal();
985 p.SCB.vtor.read()
986 };
987
988 // set default vector table location after reset or standby
989 SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor));
990 // read back the value to ensure it is written before deactivating SYSCFG
991 SYSCFG.initsvtorcr().read();
992
993 debug!("deactivating SYSCFG");
994
995 // deactivate SYSCFG
996 RCC.apb4hensr().write(|w| w.set_syscfgens(false));
997
998 debug!("enabling FPU");
999
1000 // enable fpu
1001 unsafe {
1002 let p = cortex_m::Peripherals::steal();
1003 p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22));
1004 }
1005
1006 debug!("setting power supply config");
1007
1008 power_supply_config(config.supply_config);
1009
1010 let osc = init_osc(config);
1011 let clock_inputs = ClocksInput {
1012 hsi: osc.hsi,
1013 msi: osc.msi,
1014 hse: osc.hse,
1015 };
1016 let clocks = init_clocks(config, &clock_inputs);
1017
1018 // TODO: sysb, sysc, sysd must have the same clock source
1019
1020 set_clocks!(
1021 sys: Some(clocks.sysclk),
1022 hsi: osc.hsi,
1023 hsi_div: None,
1024 hse: osc.hse,
1025 msi: osc.msi,
1026 hclk1: Some(clocks.ahb),
1027 hclk2: Some(clocks.ahb),
1028 hclk3: Some(clocks.ahb),
1029 hclk4: Some(clocks.ahb),
1030 hclk5: Some(clocks.ahb),
1031 pclk1: Some(clocks.apb1),
1032 pclk2: Some(clocks.apb2),
1033 pclk1_tim: Some(clocks.pclk_tim),
1034 pclk2_tim: Some(clocks.pclk_tim),
1035 pclk4: Some(clocks.apb4),
1036 pclk5: Some(clocks.apb5),
1037 per: None,
1038 rtc: None,
1039 i2s_ckin: None,
1040 ic8: None,
1041 ic9: None,
1042 ic14: None,
1043 ic17: None,
1044 ic20: None,
1045 );
1046}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 06895a99a..7b0dcb63f 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -6,9 +6,9 @@ pub use crate::pac::rcc::vals::{
6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, 6 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
7}; 7};
8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge}; 8use crate::pac::rcc::vals::{Hseext, Msipllfast, Msipllsel, Msirgsel, Pllmboost, Pllrge};
9#[cfg(all(peri_usb_otg_hs))]
10pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
11use crate::pac::{FLASH, PWR, RCC}; 9use crate::pac::{FLASH, PWR, RCC};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
12use crate::rcc::LSI_FREQ; 12use crate::rcc::LSI_FREQ;
13use crate::time::Hertz; 13use crate::time::Hertz;
14 14
@@ -442,7 +442,10 @@ pub(crate) unsafe fn init(config: Config) {
442 Hertz(24_000_000) => Usbrefcksel::MHZ24, 442 Hertz(24_000_000) => Usbrefcksel::MHZ24,
443 Hertz(26_000_000) => Usbrefcksel::MHZ26, 443 Hertz(26_000_000) => Usbrefcksel::MHZ26,
444 Hertz(32_000_000) => Usbrefcksel::MHZ32, 444 Hertz(32_000_000) => Usbrefcksel::MHZ32,
445 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 445 _ => panic!(
446 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
447 clk_val
448 ),
446 }, 449 },
447 None => Usbrefcksel::MHZ24, 450 None => Usbrefcksel::MHZ24,
448 }; 451 };
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 481437939..2528996d5 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -7,9 +7,9 @@ pub use crate::pac::rcc::vals::{
7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, 7 Hdiv5, Hpre as AHBPrescaler, Hpre5 as AHB5Prescaler, Hsepre as HsePrescaler, Plldiv as PllDiv, Pllm as PllPreDiv,
8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk, 8 Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sai1sel, Sw as Sysclk,
9}; 9};
10#[cfg(all(peri_usb_otg_hs))]
11pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG};
12use crate::pac::{FLASH, RCC}; 10use crate::pac::{FLASH, RCC};
11#[cfg(all(peri_usb_otg_hs))]
12pub use crate::pac::{SYSCFG, syscfg::vals::Usbrefcksel};
13use crate::rcc::LSI_FREQ; 13use crate::rcc::LSI_FREQ;
14use crate::time::Hertz; 14use crate::time::Hertz;
15 15
@@ -245,7 +245,10 @@ pub(crate) unsafe fn init(config: Config) {
245 Hertz(24_000_000) => Usbrefcksel::MHZ24, 245 Hertz(24_000_000) => Usbrefcksel::MHZ24,
246 Hertz(26_000_000) => Usbrefcksel::MHZ26, 246 Hertz(26_000_000) => Usbrefcksel::MHZ26,
247 Hertz(32_000_000) => Usbrefcksel::MHZ32, 247 Hertz(32_000_000) => Usbrefcksel::MHZ32,
248 _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), 248 _ => panic!(
249 "cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz",
250 clk_val
251 ),
249 }, 252 },
250 None => Usbrefcksel::MHZ24, 253 None => Usbrefcksel::MHZ24,
251 }; 254 };
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 63654639e..dada9bda1 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -9,7 +9,7 @@ use embassy_hal_internal::PeripheralType;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, pac, peripherals, rcc, Peri}; 12use crate::{Peri, interrupt, pac, peripherals, rcc};
13 13
14static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 14static RNG_WAKER: AtomicWaker = AtomicWaker::new();
15 15
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index a81ac6746..f049d6b12 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,10 +1,11 @@
1#[cfg(feature = "time")] 1#[cfg(feature = "time")]
2use embassy_time::{Duration, TICK_HZ}; 2use embassy_time::{Duration, TICK_HZ};
3 3
4use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; 4use super::{DateTimeError, Rtc, RtcError, bcd2_to_byte};
5use crate::interrupt::typelevel::Interrupt; 5use crate::interrupt::typelevel::Interrupt;
6use crate::pac::rtc::vals::Wucksel;
6use crate::peripherals::RTC; 7use crate::peripherals::RTC;
7use crate::rtc::SealedInstance; 8use crate::rtc::{RtcTimeProvider, SealedInstance};
8 9
9/// Represents an instant in time that can be substracted to compute a duration 10/// Represents an instant in time that can be substracted to compute a duration
10pub(super) struct RtcInstant { 11pub(super) struct RtcInstant {
@@ -58,66 +59,22 @@ impl core::ops::Sub for RtcInstant {
58 } 59 }
59} 60}
60 61
61#[repr(u8)] 62fn wucksel_compute_min(val: u32) -> (Wucksel, u32) {
62#[derive(Clone, Copy, Debug)] 63 *[
63pub(crate) enum WakeupPrescaler { 64 (Wucksel::DIV2, 2),
64 Div2 = 2, 65 (Wucksel::DIV4, 4),
65 Div4 = 4, 66 (Wucksel::DIV8, 8),
66 Div8 = 8, 67 (Wucksel::DIV16, 16),
67 Div16 = 16, 68 ]
68} 69 .iter()
69 70 .find(|(_, psc)| *psc as u32 > val)
70#[cfg(any( 71 .unwrap_or(&(Wucksel::DIV16, 16))
71 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba
72))]
73impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
74 fn from(val: WakeupPrescaler) -> Self {
75 use crate::pac::rtc::vals::Wucksel;
76
77 match val {
78 WakeupPrescaler::Div2 => Wucksel::DIV2,
79 WakeupPrescaler::Div4 => Wucksel::DIV4,
80 WakeupPrescaler::Div8 => Wucksel::DIV8,
81 WakeupPrescaler::Div16 => Wucksel::DIV16,
82 }
83 }
84}
85
86#[cfg(any(
87 stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0, stm32wba
88))]
89impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
90 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
91 use crate::pac::rtc::vals::Wucksel;
92
93 match val {
94 Wucksel::DIV2 => WakeupPrescaler::Div2,
95 Wucksel::DIV4 => WakeupPrescaler::Div4,
96 Wucksel::DIV8 => WakeupPrescaler::Div8,
97 Wucksel::DIV16 => WakeupPrescaler::Div16,
98 _ => unreachable!(),
99 }
100 }
101}
102
103impl WakeupPrescaler {
104 pub fn compute_min(val: u32) -> Self {
105 *[
106 WakeupPrescaler::Div2,
107 WakeupPrescaler::Div4,
108 WakeupPrescaler::Div8,
109 WakeupPrescaler::Div16,
110 ]
111 .iter()
112 .find(|psc| **psc as u32 > val)
113 .unwrap_or(&WakeupPrescaler::Div16)
114 }
115} 72}
116 73
117impl Rtc { 74impl Rtc {
118 /// Return the current instant. 75 /// Return the current instant.
119 fn instant(&self) -> Result<RtcInstant, RtcError> { 76 fn instant(&self) -> Result<RtcInstant, RtcError> {
120 self.time_provider().read(|_, tr, ss| { 77 RtcTimeProvider::new().read(|_, tr, ss| {
121 let second = bcd2_to_byte((tr.st(), tr.su())); 78 let second = bcd2_to_byte((tr.st(), tr.su()));
122 79
123 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime) 80 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
@@ -127,7 +84,7 @@ impl Rtc {
127 /// start the wakeup alarm and with a duration that is as close to but less than 84 /// start the wakeup alarm and with a duration that is as close to but less than
128 /// the requested duration, and record the instant the wakeup alarm was started 85 /// the requested duration, and record the instant the wakeup alarm was started
129 pub(crate) fn start_wakeup_alarm( 86 pub(crate) fn start_wakeup_alarm(
130 &self, 87 &mut self,
131 requested_duration: embassy_time::Duration, 88 requested_duration: embassy_time::Duration,
132 cs: critical_section::CriticalSection, 89 cs: critical_section::CriticalSection,
133 ) { 90 ) {
@@ -138,7 +95,7 @@ impl Rtc {
138 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); 95 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
139 let rtc_hz = Self::frequency().0 as u64; 96 let rtc_hz = Self::frequency().0 as u64;
140 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ; 97 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
141 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32); 98 let (wucksel, prescaler) = wucksel_compute_min((rtc_ticks / u16::MAX as u64) as u32);
142 99
143 // adjust the rtc ticks to the prescaler and subtract one rtc tick 100 // adjust the rtc ticks to the prescaler and subtract one rtc tick
144 let rtc_ticks = rtc_ticks / prescaler as u64; 101 let rtc_ticks = rtc_ticks / prescaler as u64;
@@ -159,7 +116,7 @@ impl Rtc {
159 while !regs.icsr().read().wutwf() {} 116 while !regs.icsr().read().wutwf() {}
160 } 117 }
161 118
162 regs.cr().modify(|w| w.set_wucksel(prescaler.into())); 119 regs.cr().modify(|w| w.set_wucksel(wucksel));
163 regs.wutr().write(|w| w.set_wut(rtc_ticks)); 120 regs.wutr().write(|w| w.set_wut(rtc_ticks));
164 regs.cr().modify(|w| w.set_wute(true)); 121 regs.cr().modify(|w| w.set_wute(true));
165 regs.cr().modify(|w| w.set_wutie(true)); 122 regs.cr().modify(|w| w.set_wutie(true));
@@ -179,7 +136,10 @@ impl Rtc {
179 136
180 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 137 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
181 /// was called, otherwise none 138 /// was called, otherwise none
182 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 139 pub(crate) fn stop_wakeup_alarm(
140 &mut self,
141 cs: critical_section::CriticalSection,
142 ) -> Option<embassy_time::Duration> {
183 let instant = self.instant().unwrap(); 143 let instant = self.instant().unwrap();
184 if RTC::regs().cr().read().wute() { 144 if RTC::regs().cr().read().wute() {
185 trace!("rtc: stop wakeup alarm at {}", instant); 145 trace!("rtc: stop wakeup alarm at {}", instant);
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 92dec0960..e88bd7ab2 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -5,15 +5,19 @@ mod datetime;
5mod low_power; 5mod low_power;
6 6
7#[cfg(feature = "low-power")] 7#[cfg(feature = "low-power")]
8use core::cell::Cell; 8use core::cell::{Cell, RefCell, RefMut};
9#[cfg(feature = "low-power")]
10use core::ops;
9 11
10#[cfg(feature = "low-power")] 12#[cfg(feature = "low-power")]
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 13use critical_section::CriticalSection;
12#[cfg(feature = "low-power")] 14#[cfg(feature = "low-power")]
13use embassy_sync::blocking_mutex::Mutex; 15use embassy_sync::blocking_mutex::Mutex;
16#[cfg(feature = "low-power")]
17use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14 18
15use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
16pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 19pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
20use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
17use crate::pac::rtc::regs::{Dr, Tr}; 21use crate::pac::rtc::regs::{Dr, Tr};
18use crate::time::Hertz; 22use crate::time::Hertz;
19 23
@@ -25,8 +29,8 @@ mod _version;
25#[allow(unused_imports)] 29#[allow(unused_imports)]
26pub use _version::*; 30pub use _version::*;
27 31
28use crate::peripherals::RTC;
29use crate::Peri; 32use crate::Peri;
33use crate::peripherals::RTC;
30 34
31/// Errors that can occur on methods on [RtcClock] 35/// Errors that can occur on methods on [RtcClock]
32#[non_exhaustive] 36#[non_exhaustive]
@@ -44,11 +48,17 @@ pub enum RtcError {
44} 48}
45 49
46/// Provides immutable access to the current time of the RTC. 50/// Provides immutable access to the current time of the RTC.
51#[derive(Clone)]
47pub struct RtcTimeProvider { 52pub struct RtcTimeProvider {
48 _private: (), 53 _private: (),
49} 54}
50 55
51impl RtcTimeProvider { 56impl RtcTimeProvider {
57 /// Create a new RTC time provider instance.
58 pub(self) const fn new() -> Self {
59 Self { _private: () }
60 }
61
52 /// Return the current datetime. 62 /// Return the current datetime.
53 /// 63 ///
54 /// # Errors 64 /// # Errors
@@ -106,6 +116,50 @@ impl RtcTimeProvider {
106 } 116 }
107} 117}
108 118
119#[cfg(feature = "low-power")]
120/// Contains an RTC driver.
121pub struct RtcContainer {
122 pub(self) mutex: &'static Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
123}
124
125#[cfg(feature = "low-power")]
126impl RtcContainer {
127 pub(self) const fn new() -> Self {
128 Self {
129 mutex: &crate::time_driver::get_driver().rtc,
130 }
131 }
132
133 /// Acquire an RTC borrow.
134 pub fn borrow_mut<'a>(&self, cs: CriticalSection<'a>) -> RtcBorrow<'a> {
135 RtcBorrow {
136 ref_mut: self.mutex.borrow(cs).borrow_mut(),
137 }
138 }
139}
140
141#[cfg(feature = "low-power")]
142/// Contains an RTC borrow.
143pub struct RtcBorrow<'a> {
144 pub(self) ref_mut: RefMut<'a, Option<Rtc>>,
145}
146
147#[cfg(feature = "low-power")]
148impl<'a> ops::Deref for RtcBorrow<'a> {
149 type Target = Rtc;
150
151 fn deref(&self) -> &Self::Target {
152 self.ref_mut.as_ref().unwrap()
153 }
154}
155
156#[cfg(feature = "low-power")]
157impl<'a> ops::DerefMut for RtcBorrow<'a> {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 self.ref_mut.as_mut().unwrap()
160 }
161}
162
109/// RTC driver. 163/// RTC driver.
110pub struct Rtc { 164pub struct Rtc {
111 #[cfg(feature = "low-power")] 165 #[cfg(feature = "low-power")]
@@ -121,13 +175,21 @@ pub struct RtcConfig {
121 /// 175 ///
122 /// A high counter frequency may impact stop power consumption 176 /// A high counter frequency may impact stop power consumption
123 pub frequency: Hertz, 177 pub frequency: Hertz,
178
179 #[cfg(feature = "_allow-disable-rtc")]
180 /// Allow disabling the rtc, even when stop is configured
181 pub _disable_rtc: bool,
124} 182}
125 183
126impl Default for RtcConfig { 184impl Default for RtcConfig {
127 /// LSI with prescalers assuming 32.768 kHz. 185 /// LSI with prescalers assuming 32.768 kHz.
128 /// Raw sub-seconds in 1/256. 186 /// Raw sub-seconds in 1/256.
129 fn default() -> Self { 187 fn default() -> Self {
130 RtcConfig { frequency: Hertz(256) } 188 RtcConfig {
189 frequency: Hertz(256),
190 #[cfg(feature = "_allow-disable-rtc")]
191 _disable_rtc: false,
192 }
131 } 193 }
132} 194}
133 195
@@ -145,8 +207,19 @@ pub enum RtcCalibrationCyclePeriod {
145} 207}
146 208
147impl Rtc { 209impl Rtc {
210 #[cfg(not(feature = "low-power"))]
148 /// Create a new RTC instance. 211 /// Create a new RTC instance.
149 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { 212 pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> (Self, RtcTimeProvider) {
213 (Self::new_inner(rtc_config), RtcTimeProvider::new())
214 }
215
216 #[cfg(feature = "low-power")]
217 /// Create a new RTC instance.
218 pub fn new(_rtc: Peri<'static, RTC>) -> (RtcContainer, RtcTimeProvider) {
219 (RtcContainer::new(), RtcTimeProvider::new())
220 }
221
222 pub(self) fn new_inner(rtc_config: RtcConfig) -> Self {
150 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 223 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
151 crate::rcc::enable_and_reset::<RTC>(); 224 crate::rcc::enable_and_reset::<RTC>();
152 225
@@ -165,10 +238,13 @@ impl Rtc {
165 // Wait for the clock to update after initialization 238 // Wait for the clock to update after initialization
166 #[cfg(not(rtc_v2_f2))] 239 #[cfg(not(rtc_v2_f2))]
167 { 240 {
168 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); 241 let now = RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap();
169 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} 242 while now == RtcTimeProvider::new().read(|_, _, ss| Ok(ss)).unwrap() {}
170 } 243 }
171 244
245 #[cfg(feature = "low-power")]
246 this.enable_wakeup_line();
247
172 this 248 this
173 } 249 }
174 250
@@ -177,11 +253,6 @@ impl Rtc {
177 freqs.rtc.to_hertz().unwrap() 253 freqs.rtc.to_hertz().unwrap()
178 } 254 }
179 255
180 /// Acquire a [`RtcTimeProvider`] instance.
181 pub const fn time_provider(&self) -> RtcTimeProvider {
182 RtcTimeProvider { _private: () }
183 }
184
185 /// Set the datetime to a new value. 256 /// Set the datetime to a new value.
186 /// 257 ///
187 /// # Errors 258 /// # Errors
@@ -225,15 +296,6 @@ impl Rtc {
225 Ok(()) 296 Ok(())
226 } 297 }
227 298
228 /// Return the current datetime.
229 ///
230 /// # Errors
231 ///
232 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
233 pub fn now(&self) -> Result<DateTime, RtcError> {
234 self.time_provider().now()
235 }
236
237 /// Check if daylight savings time is active. 299 /// Check if daylight savings time is active.
238 pub fn get_daylight_savings(&self) -> bool { 300 pub fn get_daylight_savings(&self) -> bool {
239 let cr = RTC::regs().cr().read(); 301 let cr = RTC::regs().cr().read();
@@ -315,3 +377,18 @@ trait SealedInstance {
315 377
316 // fn apply_config(&mut self, rtc_config: RtcConfig); 378 // fn apply_config(&mut self, rtc_config: RtcConfig);
317} 379}
380
381#[cfg(feature = "low-power")]
382pub(crate) fn init_rtc(cs: CriticalSection, config: RtcConfig, min_stop_pause: embassy_time::Duration) {
383 use crate::time_driver::get_driver;
384
385 #[cfg(feature = "_allow-disable-rtc")]
386 if config._disable_rtc {
387 return;
388 }
389
390 get_driver().set_rtc(cs, Rtc::new_inner(config));
391 get_driver().set_min_stop_pause(cs, min_stop_pause);
392
393 trace!("low power: stop with rtc configured");
394}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 23f6ccb0c..8ac022536 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -93,7 +93,7 @@ impl super::Rtc {
93 }) 93 })
94 } 94 }
95 95
96 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 96 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
97 where 97 where
98 F: FnOnce(crate::pac::rtc::Rtc) -> R, 98 F: FnOnce(crate::pac::rtc::Rtc) -> R,
99 { 99 {
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index d0b52049e..f7ebea73e 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -1,4 +1,4 @@
1use stm32_metapac::rtc::vals::{Calp, Calw16, Calw8, Fmt, Key, Osel, Pol, TampalrmType}; 1use stm32_metapac::rtc::vals::{Calp, Calw8, Calw16, Fmt, Key, Osel, Pol, TampalrmType};
2 2
3use super::RtcCalibrationCyclePeriod; 3use super::RtcCalibrationCyclePeriod;
4use crate::pac::rtc::Rtc; 4use crate::pac::rtc::Rtc;
@@ -95,7 +95,7 @@ impl super::Rtc {
95 }) 95 })
96 } 96 }
97 97
98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 98 pub(super) fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
99 where 99 where
100 F: FnOnce(crate::pac::rtc::Rtc) -> R, 100 F: FnOnce(crate::pac::rtc::Rtc) -> R,
101 { 101 {
@@ -131,7 +131,7 @@ impl SealedInstance for crate::peripherals::RTC {
131 131
132 #[cfg(feature = "low-power")] 132 #[cfg(feature = "low-power")]
133 cfg_if::cfg_if!( 133 cfg_if::cfg_if!(
134 if #[cfg(stm32g4)] { 134 if #[cfg(any(stm32g4, stm32wlex))] {
135 const EXTI_WAKEUP_LINE: usize = 20; 135 const EXTI_WAKEUP_LINE: usize = 20;
136 } else if #[cfg(stm32g0)] { 136 } else if #[cfg(stm32g0)] {
137 const EXTI_WAKEUP_LINE: usize = 19; 137 const EXTI_WAKEUP_LINE: usize = 19;
@@ -142,7 +142,7 @@ impl SealedInstance for crate::peripherals::RTC {
142 142
143 #[cfg(feature = "low-power")] 143 #[cfg(feature = "low-power")]
144 cfg_if::cfg_if!( 144 cfg_if::cfg_if!(
145 if #[cfg(stm32g4)] { 145 if #[cfg(any(stm32g4, stm32wlex))] {
146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 146 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
147 } else if #[cfg(any(stm32g0, stm32u0))] { 147 } else if #[cfg(any(stm32g0, stm32u0))] {
148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; 148 type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP;
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index fb8b23b79..ce4bc43c3 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -6,12 +6,12 @@ use core::marker::PhantomData;
6use embassy_hal_internal::PeripheralType; 6use embassy_hal_internal::PeripheralType;
7 7
8pub use crate::dma::word; 8pub use crate::dma::word;
9use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 9use crate::dma::{Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer, ringbuffer};
10use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
11pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider; 11pub use crate::pac::sai::vals::Mckdiv as MasterClockDivider;
12use crate::pac::sai::{vals, Sai as Regs}; 12use crate::pac::sai::{Sai as Regs, vals};
13use crate::rcc::{self, RccPeripheral}; 13use crate::rcc::{self, RccPeripheral};
14use crate::{peripherals, Peri}; 14use crate::{Peri, peripherals};
15 15
16/// SAI error 16/// SAI error
17#[derive(Debug, PartialEq, Eq, Clone, Copy)] 17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -391,7 +391,7 @@ pub struct Config {
391 pub frame_sync_polarity: FrameSyncPolarity, 391 pub frame_sync_polarity: FrameSyncPolarity,
392 pub frame_sync_active_level_length: word::U7, 392 pub frame_sync_active_level_length: word::U7,
393 pub frame_sync_definition: FrameSyncDefinition, 393 pub frame_sync_definition: FrameSyncDefinition,
394 pub frame_length: u8, 394 pub frame_length: u16,
395 pub clock_strobe: ClockStrobe, 395 pub clock_strobe: ClockStrobe,
396 pub output_drive: OutputDrive, 396 pub output_drive: OutputDrive,
397 pub master_clock_divider: Option<MasterClockDivider>, 397 pub master_clock_divider: Option<MasterClockDivider>,
@@ -696,7 +696,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
696 w.set_fspol(config.frame_sync_polarity.fspol()); 696 w.set_fspol(config.frame_sync_polarity.fspol());
697 w.set_fsdef(config.frame_sync_definition.fsdef()); 697 w.set_fsdef(config.frame_sync_definition.fsdef());
698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1); 698 w.set_fsall(config.frame_sync_active_level_length.0 as u8 - 1);
699 w.set_frl(config.frame_length - 1); 699 w.set_frl((config.frame_length - 1).try_into().unwrap());
700 }); 700 });
701 701
702 ch.slotr().modify(|w| { 702 ch.slotr().modify(|w| {
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ccbd16cbf..e05131040 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -11,9 +11,9 @@ use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{Peri, PeripheralType}; 11use embassy_hal_internal::{Peri, PeripheralType};
12use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
13use sdio_host::common_cmd::{self, Resp, ResponseLen}; 13use sdio_host::common_cmd::{self, Resp, ResponseLen};
14use sdio_host::emmc::{ExtCSD, EMMC}; 14use sdio_host::emmc::{EMMC, ExtCSD};
15use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; 15use sdio_host::sd::{BusWidth, CIC, CID, CSD, CardCapacity, CardStatus, CurrentState, OCR, RCA, SCR, SD, SDStatus};
16use sdio_host::{emmc_cmd, sd_cmd, Cmd}; 16use sdio_host::{Cmd, emmc_cmd, sd_cmd};
17 17
18#[cfg(sdmmc_v1)] 18#[cfg(sdmmc_v1)]
19use crate::dma::ChannelAndRequest; 19use crate::dma::ChannelAndRequest;
@@ -1032,12 +1032,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1032 1032
1033 /// Wait for a previously started datapath transfer to complete from an interrupt. 1033 /// Wait for a previously started datapath transfer to complete from an interrupt.
1034 #[inline] 1034 #[inline]
1035 #[allow(unused)]
1035 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> { 1036 async fn complete_datapath_transfer(block: bool) -> Result<(), Error> {
1036 let regs = T::regs();
1037
1038 let res = poll_fn(|cx| { 1037 let res = poll_fn(|cx| {
1038 // Compiler might not be sufficiently constrained here
1039 // https://github.com/embassy-rs/embassy/issues/4723
1039 T::state().register(cx.waker()); 1040 T::state().register(cx.waker());
1040 let status = regs.star().read(); 1041 let status = T::regs().star().read();
1041 1042
1042 if status.dcrcfail() { 1043 if status.dcrcfail() {
1043 return Poll::Ready(Err(Error::Crc)); 1044 return Poll::Ready(Err(Error::Crc));
@@ -1052,10 +1053,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
1052 if status.stbiterr() { 1053 if status.stbiterr() {
1053 return Poll::Ready(Err(Error::StBitErr)); 1054 return Poll::Ready(Err(Error::StBitErr));
1054 } 1055 }
1056 #[cfg(sdmmc_v1)]
1055 let done = match block { 1057 let done = match block {
1056 true => status.dbckend(), 1058 true => status.dbckend(),
1057 false => status.dataend(), 1059 false => status.dataend(),
1058 }; 1060 };
1061 #[cfg(sdmmc_v2)]
1062 let done = status.dataend();
1059 if done { 1063 if done {
1060 return Poll::Ready(Ok(())); 1064 return Poll::Ready(Ok(()));
1061 } 1065 }
diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs
index b0a32d5d1..6f2d24560 100644
--- a/embassy-stm32/src/spdifrx/mod.rs
+++ b/embassy-stm32/src/spdifrx/mod.rs
@@ -13,7 +13,7 @@ use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::spdifrx::Spdifrx as Regs; 14use crate::pac::spdifrx::Spdifrx as Regs;
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 15use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::{interrupt, peripherals, Peri}; 16use crate::{Peri, interrupt, peripherals};
17 17
18/// Possible S/PDIF preamble types. 18/// Possible S/PDIF preamble types.
19#[allow(dead_code)] 19#[allow(dead_code)]
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index c5373a54d..abb80ed26 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -6,15 +6,15 @@ use core::ptr;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{MODE_0, MODE_1, MODE_2, MODE_3, Mode, Phase, Polarity};
10 10
11use crate::dma::{word, ChannelAndRequest}; 11use crate::Peri;
12use crate::dma::{ChannelAndRequest, word};
12use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
13use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
14use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{Spi as Regs, regs, vals};
15use crate::rcc::{RccInfo, SealedRccPeripheral}; 16use crate::rcc::{RccInfo, SealedRccPeripheral};
16use crate::time::Hertz; 17use crate::time::Hertz;
17use crate::Peri;
18 18
19/// SPI error. 19/// SPI error.
20#[derive(Debug, PartialEq, Eq, Clone, Copy)] 20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -125,26 +125,69 @@ impl Config {
125 ) 125 )
126 } 126 }
127} 127}
128
129/// SPI communication mode
130pub mod mode {
131 use stm32_metapac::spi::vals;
132
133 trait SealedMode {}
134
135 /// Trait for SPI communication mode operations.
136 #[allow(private_bounds)]
137 pub trait CommunicationMode: SealedMode {
138 /// Spi communication mode
139 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
140 const MASTER: vals::Mstr;
141 /// Spi communication mode
142 #[cfg(any(spi_v4, spi_v5, spi_v6))]
143 const MASTER: vals::Master;
144 }
145
146 /// Mode allowing for SPI master operations.
147 pub struct Master;
148 /// Mode allowing for SPI slave operations.
149 pub struct Slave;
150
151 impl SealedMode for Master {}
152 impl CommunicationMode for Master {
153 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
154 const MASTER: vals::Mstr = vals::Mstr::MASTER;
155 #[cfg(any(spi_v4, spi_v5, spi_v6))]
156 const MASTER: vals::Master = vals::Master::MASTER;
157 }
158
159 impl SealedMode for Slave {}
160 impl CommunicationMode for Slave {
161 #[cfg(not(any(spi_v4, spi_v5, spi_v6)))]
162 const MASTER: vals::Mstr = vals::Mstr::SLAVE;
163 #[cfg(any(spi_v4, spi_v5, spi_v6))]
164 const MASTER: vals::Master = vals::Master::SLAVE;
165 }
166}
167use mode::{CommunicationMode, Master, Slave};
168
128/// SPI driver. 169/// SPI driver.
129pub struct Spi<'d, M: PeriMode> { 170pub struct Spi<'d, M: PeriMode, CM: CommunicationMode> {
130 pub(crate) info: &'static Info, 171 pub(crate) info: &'static Info,
131 kernel_clock: Hertz, 172 kernel_clock: Hertz,
132 sck: Option<Peri<'d, AnyPin>>, 173 sck: Option<Peri<'d, AnyPin>>,
133 mosi: Option<Peri<'d, AnyPin>>, 174 mosi: Option<Peri<'d, AnyPin>>,
134 miso: Option<Peri<'d, AnyPin>>, 175 miso: Option<Peri<'d, AnyPin>>,
176 nss: Option<Peri<'d, AnyPin>>,
135 tx_dma: Option<ChannelAndRequest<'d>>, 177 tx_dma: Option<ChannelAndRequest<'d>>,
136 rx_dma: Option<ChannelAndRequest<'d>>, 178 rx_dma: Option<ChannelAndRequest<'d>>,
137 _phantom: PhantomData<M>, 179 _phantom: PhantomData<(M, CM)>,
138 current_word_size: word_impl::Config, 180 current_word_size: word_impl::Config,
139 gpio_speed: Speed, 181 gpio_speed: Speed,
140} 182}
141 183
142impl<'d, M: PeriMode> Spi<'d, M> { 184impl<'d, M: PeriMode, CM: CommunicationMode> Spi<'d, M, CM> {
143 fn new_inner<T: Instance>( 185 fn new_inner<T: Instance>(
144 _peri: Peri<'d, T>, 186 _peri: Peri<'d, T>,
145 sck: Option<Peri<'d, AnyPin>>, 187 sck: Option<Peri<'d, AnyPin>>,
146 mosi: Option<Peri<'d, AnyPin>>, 188 mosi: Option<Peri<'d, AnyPin>>,
147 miso: Option<Peri<'d, AnyPin>>, 189 miso: Option<Peri<'d, AnyPin>>,
190 nss: Option<Peri<'d, AnyPin>>,
148 tx_dma: Option<ChannelAndRequest<'d>>, 191 tx_dma: Option<ChannelAndRequest<'d>>,
149 rx_dma: Option<ChannelAndRequest<'d>>, 192 rx_dma: Option<ChannelAndRequest<'d>>,
150 config: Config, 193 config: Config,
@@ -155,6 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
155 sck, 198 sck,
156 mosi, 199 mosi,
157 miso, 200 miso,
201 nss,
158 tx_dma, 202 tx_dma,
159 rx_dma, 203 rx_dma,
160 current_word_size: <u8 as SealedWord>::CONFIG, 204 current_word_size: <u8 as SealedWord>::CONFIG,
@@ -183,12 +227,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
183 w.set_cpha(cpha); 227 w.set_cpha(cpha);
184 w.set_cpol(cpol); 228 w.set_cpol(cpol);
185 229
186 w.set_mstr(vals::Mstr::MASTER); 230 w.set_mstr(CM::MASTER);
187 w.set_br(br); 231 w.set_br(br);
188 w.set_spe(true); 232 w.set_spe(true);
189 w.set_lsbfirst(lsbfirst); 233 w.set_lsbfirst(lsbfirst);
190 w.set_ssi(true); 234 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
191 w.set_ssm(true); 235 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
192 w.set_crcen(false); 236 w.set_crcen(false);
193 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 237 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
194 // we're doing "fake rxonly", by actually writing one 238 // we're doing "fake rxonly", by actually writing one
@@ -210,11 +254,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
210 w.set_cpha(cpha); 254 w.set_cpha(cpha);
211 w.set_cpol(cpol); 255 w.set_cpol(cpol);
212 256
213 w.set_mstr(vals::Mstr::MASTER); 257 w.set_mstr(CM::MASTER);
214 w.set_br(br); 258 w.set_br(br);
215 w.set_lsbfirst(lsbfirst); 259 w.set_lsbfirst(lsbfirst);
216 w.set_ssi(true); 260 w.set_ssi(CM::MASTER == vals::Mstr::MASTER);
217 w.set_ssm(true); 261 w.set_ssm(CM::MASTER == vals::Mstr::MASTER);
218 w.set_crcen(false); 262 w.set_crcen(false);
219 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 263 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
220 w.set_spe(true); 264 w.set_spe(true);
@@ -229,8 +273,8 @@ impl<'d, M: PeriMode> Spi<'d, M> {
229 w.set_cpha(cpha); 273 w.set_cpha(cpha);
230 w.set_cpol(cpol); 274 w.set_cpol(cpol);
231 w.set_lsbfirst(lsbfirst); 275 w.set_lsbfirst(lsbfirst);
232 w.set_ssm(true); 276 w.set_ssm(CM::MASTER == vals::Master::MASTER);
233 w.set_master(vals::Master::MASTER); 277 w.set_master(CM::MASTER);
234 w.set_comm(vals::Comm::FULL_DUPLEX); 278 w.set_comm(vals::Comm::FULL_DUPLEX);
235 w.set_ssom(vals::Ssom::ASSERTED); 279 w.set_ssom(vals::Ssom::ASSERTED);
236 w.set_midi(0); 280 w.set_midi(0);
@@ -469,7 +513,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
469 } 513 }
470} 514}
471 515
472impl<'d> Spi<'d, Blocking> { 516impl<'d> Spi<'d, Blocking, Slave> {
517 /// Create a new blocking SPI slave driver.
518 pub fn new_blocking_slave<T: Instance, #[cfg(afio)] A>(
519 peri: Peri<'d, T>,
520 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
521 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
522 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
523 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
524 config: Config,
525 ) -> Self {
526 Self::new_inner(
527 peri,
528 new_pin!(sck, config.sck_af()),
529 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
530 new_pin!(miso, AfType::input(config.miso_pull)),
531 new_pin!(cs, AfType::input(Pull::None)),
532 None,
533 None,
534 config,
535 )
536 }
537}
538
539impl<'d> Spi<'d, Blocking, Master> {
473 /// Create a new blocking SPI driver. 540 /// Create a new blocking SPI driver.
474 pub fn new_blocking<T: Instance, #[cfg(afio)] A>( 541 pub fn new_blocking<T: Instance, #[cfg(afio)] A>(
475 peri: Peri<'d, T>, 542 peri: Peri<'d, T>,
@@ -485,6 +552,7 @@ impl<'d> Spi<'d, Blocking> {
485 new_pin!(miso, AfType::input(config.miso_pull)), 552 new_pin!(miso, AfType::input(config.miso_pull)),
486 None, 553 None,
487 None, 554 None,
555 None,
488 config, 556 config,
489 ) 557 )
490 } 558 }
@@ -503,6 +571,7 @@ impl<'d> Spi<'d, Blocking> {
503 new_pin!(miso, AfType::input(config.miso_pull)), 571 new_pin!(miso, AfType::input(config.miso_pull)),
504 None, 572 None,
505 None, 573 None,
574 None,
506 config, 575 config,
507 ) 576 )
508 } 577 }
@@ -521,6 +590,7 @@ impl<'d> Spi<'d, Blocking> {
521 None, 590 None,
522 None, 591 None,
523 None, 592 None,
593 None,
524 config, 594 config,
525 ) 595 )
526 } 596 }
@@ -540,12 +610,38 @@ impl<'d> Spi<'d, Blocking> {
540 None, 610 None,
541 None, 611 None,
542 None, 612 None,
613 None,
543 config, 614 config,
544 ) 615 )
545 } 616 }
546} 617}
547 618
548impl<'d> Spi<'d, Async> { 619impl<'d> Spi<'d, Async, Slave> {
620 /// Create a new SPI slave driver.
621 pub fn new_slave<T: Instance, #[cfg(afio)] A>(
622 peri: Peri<'d, T>,
623 sck: Peri<'d, if_afio!(impl SckPin<T, A>)>,
624 mosi: Peri<'d, if_afio!(impl MosiPin<T, A>)>,
625 miso: Peri<'d, if_afio!(impl MisoPin<T, A>)>,
626 cs: Peri<'d, if_afio!(impl CsPin<T, A>)>,
627 tx_dma: Peri<'d, impl TxDma<T>>,
628 rx_dma: Peri<'d, impl RxDma<T>>,
629 config: Config,
630 ) -> Self {
631 Self::new_inner(
632 peri,
633 new_pin!(sck, config.sck_af()),
634 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
635 new_pin!(miso, AfType::input(config.miso_pull)),
636 new_pin!(cs, AfType::input(Pull::None)),
637 new_dma!(tx_dma),
638 new_dma!(rx_dma),
639 config,
640 )
641 }
642}
643
644impl<'d> Spi<'d, Async, Master> {
549 /// Create a new SPI driver. 645 /// Create a new SPI driver.
550 pub fn new<T: Instance, #[cfg(afio)] A>( 646 pub fn new<T: Instance, #[cfg(afio)] A>(
551 peri: Peri<'d, T>, 647 peri: Peri<'d, T>,
@@ -561,6 +657,7 @@ impl<'d> Spi<'d, Async> {
561 new_pin!(sck, config.sck_af()), 657 new_pin!(sck, config.sck_af()),
562 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 658 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
563 new_pin!(miso, AfType::input(config.miso_pull)), 659 new_pin!(miso, AfType::input(config.miso_pull)),
660 None,
564 new_dma!(tx_dma), 661 new_dma!(tx_dma),
565 new_dma!(rx_dma), 662 new_dma!(rx_dma),
566 config, 663 config,
@@ -581,6 +678,7 @@ impl<'d> Spi<'d, Async> {
581 new_pin!(sck, config.sck_af()), 678 new_pin!(sck, config.sck_af()),
582 None, 679 None,
583 new_pin!(miso, AfType::input(config.miso_pull)), 680 new_pin!(miso, AfType::input(config.miso_pull)),
681 None,
584 #[cfg(any(spi_v1, spi_v2, spi_v3))] 682 #[cfg(any(spi_v1, spi_v2, spi_v3))]
585 new_dma!(tx_dma), 683 new_dma!(tx_dma),
586 #[cfg(any(spi_v4, spi_v5, spi_v6))] 684 #[cfg(any(spi_v4, spi_v5, spi_v6))]
@@ -603,6 +701,7 @@ impl<'d> Spi<'d, Async> {
603 new_pin!(sck, config.sck_af()), 701 new_pin!(sck, config.sck_af()),
604 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 702 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
605 None, 703 None,
704 None,
606 new_dma!(tx_dma), 705 new_dma!(tx_dma),
607 None, 706 None,
608 config, 707 config,
@@ -623,6 +722,7 @@ impl<'d> Spi<'d, Async> {
623 None, 722 None,
624 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)), 723 new_pin!(mosi, AfType::output(OutputType::PushPull, config.gpio_speed)),
625 None, 724 None,
725 None,
626 new_dma!(tx_dma), 726 new_dma!(tx_dma),
627 None, 727 None,
628 config, 728 config,
@@ -646,7 +746,7 @@ impl<'d> Spi<'d, Async> {
646 config.bit_order = BitOrder::MsbFirst; 746 config.bit_order = BitOrder::MsbFirst;
647 config.frequency = freq; 747 config.frequency = freq;
648 748
649 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 749 Self::new_inner(peri, None, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
650 } 750 }
651 751
652 #[allow(dead_code)] 752 #[allow(dead_code)]
@@ -656,9 +756,11 @@ impl<'d> Spi<'d, Async> {
656 rx_dma: Option<ChannelAndRequest<'d>>, 756 rx_dma: Option<ChannelAndRequest<'d>>,
657 config: Config, 757 config: Config,
658 ) -> Self { 758 ) -> Self {
659 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config) 759 Self::new_inner(peri, None, None, None, None, tx_dma, rx_dma, config)
660 } 760 }
761}
661 762
763impl<'d, CM: CommunicationMode> Spi<'d, Async, CM> {
662 /// SPI write, using DMA. 764 /// SPI write, using DMA.
663 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> { 765 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
664 if data.is_empty() { 766 if data.is_empty() {
@@ -888,11 +990,12 @@ impl<'d> Spi<'d, Async> {
888 } 990 }
889} 991}
890 992
891impl<'d, M: PeriMode> Drop for Spi<'d, M> { 993impl<'d, M: PeriMode, CM: CommunicationMode> Drop for Spi<'d, M, CM> {
892 fn drop(&mut self) { 994 fn drop(&mut self) {
893 self.sck.as_ref().map(|x| x.set_as_disconnected()); 995 self.sck.as_ref().map(|x| x.set_as_disconnected());
894 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 996 self.mosi.as_ref().map(|x| x.set_as_disconnected());
895 self.miso.as_ref().map(|x| x.set_as_disconnected()); 997 self.miso.as_ref().map(|x| x.set_as_disconnected());
998 self.nss.as_ref().map(|x| x.set_as_disconnected());
896 999
897 self.info.rcc.disable(); 1000 self.info.rcc.disable();
898 } 1001 }
@@ -1127,7 +1230,7 @@ fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1127// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 1230// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
1128macro_rules! impl_blocking { 1231macro_rules! impl_blocking {
1129 ($w:ident) => { 1232 ($w:ident) => {
1130 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M> { 1233 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Write<$w> for Spi<'d, M, CM> {
1131 type Error = Error; 1234 type Error = Error;
1132 1235
1133 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> { 1236 fn write(&mut self, words: &[$w]) -> Result<(), Self::Error> {
@@ -1135,7 +1238,7 @@ macro_rules! impl_blocking {
1135 } 1238 }
1136 } 1239 }
1137 1240
1138 impl<'d, M: PeriMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M> { 1241 impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_02::blocking::spi::Transfer<$w> for Spi<'d, M, CM> {
1139 type Error = Error; 1242 type Error = Error;
1140 1243
1141 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> { 1244 fn transfer<'w>(&mut self, words: &'w mut [$w]) -> Result<&'w [$w], Self::Error> {
@@ -1149,11 +1252,11 @@ macro_rules! impl_blocking {
1149impl_blocking!(u8); 1252impl_blocking!(u8);
1150impl_blocking!(u16); 1253impl_blocking!(u16);
1151 1254
1152impl<'d, M: PeriMode> embedded_hal_1::spi::ErrorType for Spi<'d, M> { 1255impl<'d, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::ErrorType for Spi<'d, M, CM> {
1153 type Error = Error; 1256 type Error = Error;
1154} 1257}
1155 1258
1156impl<'d, W: Word, M: PeriMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M> { 1259impl<'d, W: Word, M: PeriMode, CM: CommunicationMode> embedded_hal_1::spi::SpiBus<W> for Spi<'d, M, CM> {
1157 fn flush(&mut self) -> Result<(), Self::Error> { 1260 fn flush(&mut self) -> Result<(), Self::Error> {
1158 Ok(()) 1261 Ok(())
1159 } 1262 }
@@ -1186,7 +1289,7 @@ impl embedded_hal_1::spi::Error for Error {
1186 } 1289 }
1187} 1290}
1188 1291
1189impl<'d, W: Word> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async> { 1292impl<'d, W: Word, CM: CommunicationMode> embedded_hal_async::spi::SpiBus<W> for Spi<'d, Async, CM> {
1190 async fn flush(&mut self) -> Result<(), Self::Error> { 1293 async fn flush(&mut self) -> Result<(), Self::Error> {
1191 Ok(()) 1294 Ok(())
1192 } 1295 }
@@ -1328,7 +1431,7 @@ foreach_peripheral!(
1328 }; 1431 };
1329); 1432);
1330 1433
1331impl<'d, M: PeriMode> SetConfig for Spi<'d, M> { 1434impl<'d, M: PeriMode, CM: CommunicationMode> SetConfig for Spi<'d, M, CM> {
1332 type Config = Config; 1435 type Config = Config;
1333 type ConfigError = (); 1436 type ConfigError = ();
1334 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { 1437 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 7db74bdf6..0b75aef92 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,14 +1,16 @@
1#![allow(non_snake_case)] 1#![allow(non_snake_case)]
2 2
3use core::cell::{Cell, RefCell}; 3use core::cell::{Cell, RefCell};
4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 4#[cfg(all(feature = "low-power", stm32wlex))]
5use core::sync::atomic::AtomicU16;
6use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
5 7
6use critical_section::CriticalSection; 8use critical_section::CriticalSection;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::blocking_mutex::Mutex; 9use embassy_sync::blocking_mutex::Mutex;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_time_driver::{Driver, TICK_HZ}; 11use embassy_time_driver::{Driver, TICK_HZ};
10use embassy_time_queue_utils::Queue; 12use embassy_time_queue_utils::Queue;
11use stm32_metapac::timer::{regs, TimGp16}; 13use stm32_metapac::timer::{TimGp16, regs};
12 14
13use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
14use crate::pac::timer::vals; 16use crate::pac::timer::vals;
@@ -194,6 +196,11 @@ fn calc_now(period: u32, counter: u16) -> u64 {
194 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) 196 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
195} 197}
196 198
199#[cfg(feature = "low-power")]
200fn calc_period_counter(ticks: u64) -> (u32, u16) {
201 (2 * (ticks >> 16) as u32 + (ticks as u16 >= 0x8000) as u32, ticks as u16)
202}
203
197struct AlarmState { 204struct AlarmState {
198 timestamp: Cell<u64>, 205 timestamp: Cell<u64>,
199} 206}
@@ -213,7 +220,13 @@ pub(crate) struct RtcDriver {
213 period: AtomicU32, 220 period: AtomicU32,
214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>, 221 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
215 #[cfg(feature = "low-power")] 222 #[cfg(feature = "low-power")]
216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 223 pub(crate) rtc: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc>>>,
224 #[cfg(feature = "low-power")]
225 /// The minimum pause time beyond which the executor will enter a low-power state.
226 min_stop_pause: Mutex<CriticalSectionRawMutex, Cell<embassy_time::Duration>>,
227 /// Saved count for the timer (its value is lost when entering STOP2)
228 #[cfg(all(feature = "low-power", stm32wlex))]
229 saved_count: AtomicU16,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>, 230 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
218} 231}
219 232
@@ -221,12 +234,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
221 period: AtomicU32::new(0), 234 period: AtomicU32::new(0),
222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 235 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
223 #[cfg(feature = "low-power")] 236 #[cfg(feature = "low-power")]
224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 237 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), RefCell::new(None)),
238 #[cfg(feature = "low-power")]
239 min_stop_pause: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(embassy_time::Duration::from_millis(0))),
240 #[cfg(all(feature = "low-power", stm32wlex))]
241 saved_count: AtomicU16::new(0),
225 queue: Mutex::new(RefCell::new(Queue::new())) 242 queue: Mutex::new(RefCell::new(Queue::new()))
226}); 243});
227 244
228impl RtcDriver { 245impl RtcDriver {
229 fn init(&'static self, cs: critical_section::CriticalSection) { 246 /// initialize the timer, but don't start it. Used for chips like stm32wle5
247 /// for low power where the timer config is lost in STOP2.
248 pub(crate) fn init_timer(&'static self, cs: critical_section::CriticalSection) {
230 let r = regs_gp16(); 249 let r = regs_gp16();
231 250
232 rcc::enable_and_reset_with_cs::<T>(cs); 251 rcc::enable_and_reset_with_cs::<T>(cs);
@@ -259,10 +278,16 @@ impl RtcDriver {
259 w.set_ccie(0, true); 278 w.set_ccie(0, true);
260 }); 279 });
261 280
281 #[cfg(all(feature = "low-power", stm32wlex))]
282 r.cnt().write(|w| w.set_cnt(self.saved_count.load(Ordering::SeqCst)));
283
262 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend(); 284 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend();
263 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() }; 285 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() };
286 }
264 287
265 r.cr1().modify(|w| w.set_cen(true)); 288 fn init(&'static self, cs: CriticalSection) {
289 self.init_timer(cs);
290 regs_gp16().cr1().modify(|w| w.set_cen(true));
266 } 291 }
267 292
268 fn on_interrupt(&self) { 293 fn on_interrupt(&self) {
@@ -338,34 +363,10 @@ impl RtcDriver {
338 #[cfg(feature = "low-power")] 363 #[cfg(feature = "low-power")]
339 /// Add the given offset to the current time 364 /// Add the given offset to the current time
340 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { 365 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
341 let offset = offset.as_ticks(); 366 let (period, counter) = calc_period_counter(self.now() + offset.as_ticks());
342 let cnt = regs_gp16().cnt().read().cnt() as u32;
343 let period = self.period.load(Ordering::SeqCst);
344
345 // Correct the race, if it exists
346 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
347 period + 1
348 } else {
349 period
350 };
351
352 // Normalize to the full overflow
353 let period = (period / 2) * 2;
354
355 // Add the offset
356 let period = period + 2 * (offset / u16::MAX as u64) as u32;
357 let cnt = cnt + (offset % u16::MAX as u64) as u32;
358
359 let (cnt, period) = if cnt > u16::MAX as u32 {
360 (cnt - u16::MAX as u32, period + 2)
361 } else {
362 (cnt, period)
363 };
364
365 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
366 367
367 self.period.store(period, Ordering::SeqCst); 368 self.period.store(period, Ordering::SeqCst);
368 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 369 regs_gp16().cnt().write(|w| w.set_cnt(counter));
369 370
370 // Now, recompute alarm 371 // Now, recompute alarm
371 let alarm = self.alarm.borrow(cs); 372 let alarm = self.alarm.borrow(cs);
@@ -379,70 +380,64 @@ impl RtcDriver {
379 #[cfg(feature = "low-power")] 380 #[cfg(feature = "low-power")]
380 /// Stop the wakeup alarm, if enabled, and add the appropriate offset 381 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
381 fn stop_wakeup_alarm(&self, cs: CriticalSection) { 382 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
382 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) { 383 if !regs_gp16().cr1().read().cen()
384 && let Some(offset) = self.rtc.borrow(cs).borrow_mut().as_mut().unwrap().stop_wakeup_alarm(cs)
385 {
383 self.add_time(offset, cs); 386 self.add_time(offset, cs);
384 } 387 }
385 } 388 }
386 389
387 /* 390 /*
388 Low-power public functions: all create a critical section 391 Low-power public functions: all require a critical section
389 */ 392 */
390 #[cfg(feature = "low-power")] 393 #[cfg(feature = "low-power")]
391 /// Set the rtc but panic if it's already been set 394 pub(crate) fn set_min_stop_pause(&self, cs: CriticalSection, min_stop_pause: embassy_time::Duration) {
392 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { 395 self.min_stop_pause.borrow(cs).replace(min_stop_pause);
393 critical_section::with(|cs| {
394 rtc.stop_wakeup_alarm(cs);
395
396 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())
397 });
398 } 396 }
399 397
400 #[cfg(feature = "low-power")] 398 #[cfg(feature = "low-power")]
401 /// The minimum pause time beyond which the executor will enter a low-power state. 399 /// Set the rtc but panic if it's already been set
402 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250); 400 pub(crate) fn set_rtc(&self, cs: CriticalSection, mut rtc: Rtc) {
401 rtc.stop_wakeup_alarm(cs);
402
403 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none());
404 }
403 405
404 #[cfg(feature = "low-power")] 406 #[cfg(feature = "low-power")]
405 /// Pause the timer if ready; return err if not 407 /// Pause the timer if ready; return err if not
406 pub(crate) fn pause_time(&self) -> Result<(), ()> { 408 pub(crate) fn pause_time(&self, cs: CriticalSection) -> Result<(), ()> {
407 critical_section::with(|cs| { 409 self.stop_wakeup_alarm(cs);
408 /* 410
409 If the wakeup timer is currently running, then we need to stop it and 411 let time_until_next_alarm = self.time_until_next_alarm(cs);
410 add the elapsed time to the current time, as this will impact the result 412 if time_until_next_alarm < self.min_stop_pause.borrow(cs).get() {
411 of `time_until_next_alarm`. 413 trace!(
412 */ 414 "time_until_next_alarm < self.min_stop_pause ({})",
413 self.stop_wakeup_alarm(cs); 415 time_until_next_alarm
414 416 );
415 let time_until_next_alarm = self.time_until_next_alarm(cs); 417 Err(())
416 if time_until_next_alarm < Self::MIN_STOP_PAUSE { 418 } else {
417 Err(()) 419 self.rtc
418 } else { 420 .borrow(cs)
419 self.rtc 421 .borrow_mut()
420 .borrow(cs) 422 .as_mut()
421 .get() 423 .unwrap()
422 .unwrap() 424 .start_wakeup_alarm(time_until_next_alarm, cs);
423 .start_wakeup_alarm(time_until_next_alarm, cs); 425
424 426 regs_gp16().cr1().modify(|w| w.set_cen(false));
425 regs_gp16().cr1().modify(|w| w.set_cen(false)); 427 // save the count for the timer as its lost in STOP2 for stm32wlex
426 428 #[cfg(stm32wlex)]
427 Ok(()) 429 self.saved_count
428 } 430 .store(regs_gp16().cnt().read().cnt() as u16, Ordering::SeqCst);
429 }) 431 Ok(())
432 }
430 } 433 }
431 434
432 #[cfg(feature = "low-power")] 435 #[cfg(feature = "low-power")]
433 /// Resume the timer with the given offset 436 /// Resume the timer with the given offset
434 pub(crate) fn resume_time(&self) { 437 pub(crate) fn resume_time(&self, cs: CriticalSection) {
435 if regs_gp16().cr1().read().cen() { 438 self.stop_wakeup_alarm(cs);
436 // Time isn't currently stopped
437 439
438 return; 440 regs_gp16().cr1().modify(|w| w.set_cen(true));
439 }
440
441 critical_section::with(|cs| {
442 self.stop_wakeup_alarm(cs);
443
444 regs_gp16().cr1().modify(|w| w.set_cen(true));
445 })
446 } 441 }
447 442
448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 443 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
@@ -514,7 +509,7 @@ impl Driver for RtcDriver {
514} 509}
515 510
516#[cfg(feature = "low-power")] 511#[cfg(feature = "low-power")]
517pub(crate) fn get_driver() -> &'static RtcDriver { 512pub(crate) const fn get_driver() -> &'static RtcDriver {
518 &DRIVER 513 &DRIVER
519} 514}
520 515
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 484aae1d0..6d4c70dff 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -2,16 +2,16 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr}; 5pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr};
6 6
7use super::low_level::{CountingMode, OutputPolarity, Timer}; 7use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin; 8use super::simple_pwm::PwmPin;
9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; 9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10use crate::Peri;
10use crate::gpio::{AnyPin, OutputType}; 11use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::timer::low_level::OutputCompareMode;
13use crate::timer::TimerChannel; 13use crate::timer::TimerChannel;
14use crate::Peri; 14use crate::timer::low_level::OutputCompareMode;
15 15
16/// Complementary PWM pin wrapper. 16/// Complementary PWM pin wrapper.
17/// 17///
@@ -77,8 +77,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
77 77
78 this.inner.set_counting_mode(counting_mode); 78 this.inner.set_counting_mode(counting_mode);
79 this.set_frequency(freq); 79 this.set_frequency(freq);
80 this.inner.start();
81
82 this.inner.enable_outputs(); 80 this.inner.enable_outputs();
83 81
84 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 82 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
@@ -89,6 +87,10 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
89 }); 87 });
90 this.inner.set_autoreload_preload(true); 88 this.inner.set_autoreload_preload(true);
91 89
90 // Generate update event so pre-load registers are written to the shadow registers
91 this.inner.generate_update_event();
92 this.inner.start();
93
92 this 94 this
93 } 95 }
94 96
@@ -136,6 +138,16 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
136 self.inner.get_moe() 138 self.inner.get_moe()
137 } 139 }
138 140
141 /// Set Master Slave Mode 2
142 pub fn set_mms2(&mut self, mms2: Mms2) {
143 self.inner.set_mms2_selection(mms2);
144 }
145
146 /// Set Repetition Counter
147 pub fn set_repetition_counter(&mut self, val: u16) {
148 self.inner.set_repetition_counter(val);
149 }
150
139 /// Enable the given channel. 151 /// Enable the given channel.
140 pub fn enable(&mut self, channel: Channel) { 152 pub fn enable(&mut self, channel: Channel) {
141 self.inner.enable_channel(channel, true); 153 self.inner.enable_channel(channel, true);
@@ -150,8 +162,8 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
150 162
151 /// Set PWM frequency. 163 /// Set PWM frequency.
152 /// 164 ///
153 /// Note: when you call this, the max duty value changes, so you will have to 165 /// Note: that the frequency will not be applied in the timer until an update event
154 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 166 /// occurs.
155 pub fn set_frequency(&mut self, freq: Hertz) { 167 pub fn set_frequency(&mut self, freq: Hertz) {
156 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 168 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
157 2u8 169 2u8
@@ -208,60 +220,57 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
208 /// 220 ///
209 /// Note: 221 /// Note:
210 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
223 #[inline(always)]
211 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 224 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
212 #[allow(clippy::let_unit_value)] // eg. stm32f334 225 self.inner.waveform_up(dma, channel, duty).await
213 let req = dma.request(); 226 }
214
215 let original_duty_state = self.inner.get_compare_value(channel);
216 let original_enable_state = self.inner.get_channel_enable_state(channel);
217 let original_update_dma_state = self.inner.get_update_dma_state();
218
219 if !original_update_dma_state {
220 self.inner.enable_update_dma(true);
221 }
222
223 if !original_enable_state {
224 self.inner.enable_channel(channel, true);
225 }
226
227 unsafe {
228 #[cfg(not(any(bdma, gpdma)))]
229 use crate::dma::{Burst, FifoThreshold};
230 use crate::dma::{Transfer, TransferOptions};
231
232 let dma_transfer_option = TransferOptions {
233 #[cfg(not(any(bdma, gpdma)))]
234 fifo_threshold: Some(FifoThreshold::Full),
235 #[cfg(not(any(bdma, gpdma)))]
236 mburst: Burst::Incr8,
237 ..Default::default()
238 };
239
240 Transfer::new_write(
241 dma,
242 req,
243 duty,
244 self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16,
245 dma_transfer_option,
246 )
247 .await
248 };
249
250 // restore output compare state
251 if !original_enable_state {
252 self.inner.enable_channel(channel, false);
253 }
254 227
255 self.inner.set_compare_value(channel, original_duty_state); 228 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
229 ///
230 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
231 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
232 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
233 ///
234 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
235 /// represents a single update event and each column corresponds to a specific timer channel (starting
236 /// from `starting_channel` up to and including `ending_channel`).
237 ///
238 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
239 ///
240 /// ```rust,ignore
241 /// let dma_buf: [u16; 16] = [
242 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
243 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
244 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
245 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
246 /// ];
247 /// ```
248 ///
249 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
250 /// updating the duty cycles of all selected channels simultaneously.
251 ///
252 /// Note:
253 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
254 /// Also be aware that embassy timers use one of timers internally. It is possible to
255 /// switch this timer by using `time-driver-timX` feature.
256 ///
257 #[inline(always)]
258 pub async fn waveform_up_multi_channel(
259 &mut self,
260 dma: Peri<'_, impl super::UpDma<T>>,
261 starting_channel: Channel,
262 ending_channel: Channel,
263 duty: &[u16],
264 ) {
265 self.inner
266 .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty)
267 .await;
268 }
256 269
257 // Since DMA is closed before timer update event trigger DMA is turn off, 270 /// Generate a sequence of PWM waveform
258 // this can almost always trigger a DMA FIFO error. 271 #[inline(always)]
259 // 272 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
260 // optional TODO: 273 self.inner.waveform(dma, duty).await;
261 // clean FEIF after disable UDE
262 if !original_update_dma_state {
263 self.inner.enable_update_dma(false);
264 }
265 } 274 }
266} 275}
267 276
@@ -388,7 +397,7 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
388 397
389#[cfg(test)] 398#[cfg(test)]
390mod tests { 399mod tests {
391 use super::{compute_dead_time_value, Ckd}; 400 use super::{Ckd, compute_dead_time_value};
392 401
393 #[test] 402 #[test]
394 fn test_compute_dead_time_value() { 403 fn test_compute_dead_time_value() {
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index 7a25e6c21..9cf0f8c34 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -8,11 +8,11 @@ use core::task::{Context, Poll};
8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; 8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin}; 9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin};
10pub use super::{Ch1, Ch2, Ch3, Ch4}; 10pub use super::{Ch1, Ch2, Ch3, Ch4};
11use crate::Peri;
11use crate::gpio::{AfType, AnyPin, Pull}; 12use crate::gpio::{AfType, AnyPin, Pull};
12use crate::interrupt::typelevel::{Binding, Interrupt}; 13use crate::interrupt::typelevel::{Binding, Interrupt};
13use crate::time::Hertz; 14use crate::time::Hertz;
14use crate::timer::TimerChannel; 15use crate::timer::TimerChannel;
15use crate::Peri;
16 16
17/// Capture pin wrapper. 17/// Capture pin wrapper.
18/// 18///
@@ -60,6 +60,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
60 this.inner.set_counting_mode(counting_mode); 60 this.inner.set_counting_mode(counting_mode);
61 this.inner.set_tick_freq(freq); 61 this.inner.set_tick_freq(freq);
62 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 62 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
63 this.inner.generate_update_event();
63 this.inner.start(); 64 this.inner.start();
64 65
65 // enable NVIC interrupt 66 // enable NVIC interrupt
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index ac039bb0d..f0105ece8 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -10,12 +10,12 @@ use core::mem::ManuallyDrop;
10 10
11use embassy_hal_internal::Peri; 11use embassy_hal_internal::Peri;
12// Re-export useful enums 12// Re-export useful enums
13pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; 13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource};
14 14
15use super::*; 15use super::*;
16use crate::pac::timer::vals; 16use crate::pac::timer::vals;
17use crate::rcc;
18use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{dma, rcc};
19 19
20/// Input capture mode. 20/// Input capture mode.
21#[derive(Clone, Copy)] 21#[derive(Clone, Copy)]
@@ -143,20 +143,69 @@ pub enum OutputCompareMode {
143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as 143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
144 /// TIMx_CNT>TIMx_CCRx else inactive. 144 /// TIMx_CNT>TIMx_CCRx else inactive.
145 PwmMode2, 145 PwmMode2,
146 // TODO: there's more modes here depending on the chip family. 146
147 #[cfg(timer_v2)]
148 /// In up-counting mode, the channel is active until a trigger
149 /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM
150 /// mode 1 and the channels becomes active again at the next update. In down-counting
151 /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal).
152 /// Then, a comparison is performed as in PWM mode 1 and the channels becomes
153 /// inactive again at the next update.
154 OnePulseMode1,
155
156 #[cfg(timer_v2)]
157 /// In up-counting mode, the channel is inactive until a
158 /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in
159 /// PWM mode 2 and the channels becomes inactive again at the next update. In down
160 /// counting mode, the channel is active until a trigger event is detected (on tim_trgi
161 /// signal). Then, a comparison is performed as in PWM mode 1 and the channels
162 /// becomes active again at the next update.
163 OnePulseMode2,
164
165 #[cfg(timer_v2)]
166 /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1.
167 /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref.
168 CombinedPwmMode1,
169
170 #[cfg(timer_v2)]
171 /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2.
172 /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref.
173 CombinedPwmMode2,
174
175 #[cfg(timer_v2)]
176 /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref
177 /// when the counter is counting up, tim_oc2ref when it is counting down.
178 AsymmetricPwmMode1,
179
180 #[cfg(timer_v2)]
181 /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref
182 /// when the counter is counting up, tim_oc2ref when it is counting down.
183 AsymmetricPwmMode2,
147} 184}
148 185
149impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 186impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm {
150 fn from(mode: OutputCompareMode) -> Self { 187 fn from(mode: OutputCompareMode) -> Self {
151 match mode { 188 match mode {
152 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, 189 OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN,
153 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, 190 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH,
154 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, 191 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH,
155 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, 192 OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE,
156 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, 193 OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE,
157 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, 194 OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE,
158 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, 195 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1,
159 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, 196 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2,
197 #[cfg(timer_v2)]
198 OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1,
199 #[cfg(timer_v2)]
200 OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2,
201 #[cfg(timer_v2)]
202 OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1,
203 #[cfg(timer_v2)]
204 OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2,
205 #[cfg(timer_v2)]
206 OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1,
207 #[cfg(timer_v2)]
208 OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2,
160 } 209 }
161 } 210 }
162} 211}
@@ -223,6 +272,17 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
223 self.regs_core().cr1().modify(|r| r.set_cen(true)); 272 self.regs_core().cr1().modify(|r| r.set_cen(true));
224 } 273 }
225 274
275 /// Generate timer update event from software.
276 ///
277 /// Set URS to avoid generating interrupt or DMA request. This update event is only
278 /// used to load value from pre-load registers. If called when the timer is running,
279 /// it may disrupt the output waveform.
280 pub fn generate_update_event(&self) {
281 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
282 self.regs_core().egr().write(|r| r.set_ug(true));
283 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
284 }
285
226 /// Stop the timer. 286 /// Stop the timer.
227 pub fn stop(&self) { 287 pub fn stop(&self) {
228 self.regs_core().cr1().modify(|r| r.set_cen(false)); 288 self.regs_core().cr1().modify(|r| r.set_cen(false));
@@ -273,10 +333,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
273 let regs = self.regs_core(); 333 let regs = self.regs_core();
274 regs.psc().write_value(psc); 334 regs.psc().write_value(psc);
275 regs.arr().write(|r| r.set_arr(arr)); 335 regs.arr().write(|r| r.set_arr(arr));
276
277 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
278 regs.egr().write(|r| r.set_ug(true));
279 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
280 } 336 }
281 #[cfg(not(stm32l0))] 337 #[cfg(not(stm32l0))]
282 TimerBits::Bits32 => { 338 TimerBits::Bits32 => {
@@ -286,10 +342,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
286 let regs = self.regs_gp32_unchecked(); 342 let regs = self.regs_gp32_unchecked();
287 regs.psc().write_value(psc); 343 regs.psc().write_value(psc);
288 regs.arr().write_value(arr); 344 regs.arr().write_value(arr);
289
290 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
291 regs.egr().write(|r| r.set_ug(true));
292 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
293 } 345 }
294 } 346 }
295 } 347 }
@@ -607,6 +659,219 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
607 } 659 }
608 } 660 }
609 661
662 /// Generate a sequence of PWM waveform
663 ///
664 /// Note:
665 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
666 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
667 #[allow(clippy::let_unit_value)] // eg. stm32f334
668 let req = dma.request();
669
670 let original_update_dma_state = self.get_update_dma_state();
671
672 if !original_update_dma_state {
673 self.enable_update_dma(true);
674 }
675
676 self.waveform_helper(dma, req, channel, duty).await;
677
678 // Since DMA is closed before timer update event trigger DMA is turn off,
679 // this can almost always trigger a DMA FIFO error.
680 //
681 // optional TODO:
682 // clean FEIF after disable UDE
683 if !original_update_dma_state {
684 self.enable_update_dma(false);
685 }
686 }
687
688 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
689 ///
690 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
691 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
692 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
693 ///
694 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
695 /// represents a single update event and each column corresponds to a specific timer channel (starting
696 /// from `starting_channel` up to and including `ending_channel`).
697 ///
698 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
699 ///
700 /// ```rust,ignore
701 /// let dma_buf: [u16; 16] = [
702 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
703 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
704 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
705 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
706 /// ];
707 /// ```
708 ///
709 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
710 /// updating the duty cycles of all selected channels simultaneously.
711 ///
712 /// Note:
713 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
714 /// Also be aware that embassy timers use one of timers internally. It is possible to
715 /// switch this timer by using `time-driver-timX` feature.
716 ///
717 pub async fn waveform_up_multi_channel(
718 &mut self,
719 dma: Peri<'_, impl super::UpDma<T>>,
720 starting_channel: Channel,
721 ending_channel: Channel,
722 duty: &[u16],
723 ) {
724 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
725 let start_ch_index = starting_channel.index();
726 let end_ch_index = ending_channel.index();
727
728 assert!(start_ch_index <= end_ch_index);
729
730 let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
731 self.regs_gp16()
732 .dcr()
733 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
734 self.regs_gp16()
735 .dcr()
736 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
737
738 #[allow(clippy::let_unit_value)] // eg. stm32f334
739 let req = dma.request();
740
741 let original_update_dma_state = self.get_update_dma_state();
742 if !original_update_dma_state {
743 self.enable_update_dma(true);
744 }
745
746 unsafe {
747 #[cfg(not(any(bdma, gpdma)))]
748 use crate::dma::{Burst, FifoThreshold};
749 use crate::dma::{Transfer, TransferOptions};
750
751 let dma_transfer_option = TransferOptions {
752 #[cfg(not(any(bdma, gpdma)))]
753 fifo_threshold: Some(FifoThreshold::Full),
754 #[cfg(not(any(bdma, gpdma)))]
755 mburst: Burst::Incr4,
756 ..Default::default()
757 };
758
759 Transfer::new_write(
760 dma,
761 req,
762 duty,
763 self.regs_gp16().dmar().as_ptr() as *mut u16,
764 dma_transfer_option,
765 )
766 .await
767 };
768
769 if !original_update_dma_state {
770 self.enable_update_dma(false);
771 }
772 }
773
774 /// Generate a sequence of PWM waveform
775 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
776 use crate::pac::timer::vals::Ccds;
777
778 #[allow(clippy::let_unit_value)] // eg. stm32f334
779 let req = dma.request();
780
781 let cc_channel = C::CHANNEL;
782
783 let original_cc_dma_on_update = self.get_cc_dma_selection() == Ccds::ON_UPDATE;
784 let original_cc_dma_enabled = self.get_cc_dma_enable_state(cc_channel);
785
786 // redirect CC DMA request onto Update Event
787 if !original_cc_dma_on_update {
788 self.set_cc_dma_selection(Ccds::ON_UPDATE)
789 }
790
791 if !original_cc_dma_enabled {
792 self.set_cc_dma_enable_state(cc_channel, true);
793 }
794
795 self.waveform_helper(dma, req, cc_channel, duty).await;
796
797 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
798 // this can almost always trigger a DMA FIFO error.
799 //
800 // optional TODO:
801 // clean FEIF after disable UDE
802 if !original_cc_dma_enabled {
803 self.set_cc_dma_enable_state(cc_channel, false);
804 }
805
806 if !original_cc_dma_on_update {
807 self.set_cc_dma_selection(Ccds::ON_COMPARE)
808 }
809 }
810
811 async fn waveform_helper(
812 &mut self,
813 dma: Peri<'_, impl dma::Channel>,
814 req: dma::Request,
815 channel: Channel,
816 duty: &[u16],
817 ) {
818 let original_duty_state = self.get_compare_value(channel);
819 let original_enable_state = self.get_channel_enable_state(channel);
820
821 if !original_enable_state {
822 self.enable_channel(channel, true);
823 }
824
825 unsafe {
826 #[cfg(not(any(bdma, gpdma)))]
827 use crate::dma::{Burst, FifoThreshold};
828 use crate::dma::{Transfer, TransferOptions};
829
830 let dma_transfer_option = TransferOptions {
831 #[cfg(not(any(bdma, gpdma)))]
832 fifo_threshold: Some(FifoThreshold::Full),
833 #[cfg(not(any(bdma, gpdma)))]
834 mburst: Burst::Incr8,
835 ..Default::default()
836 };
837
838 match self.bits() {
839 TimerBits::Bits16 => {
840 Transfer::new_write(
841 dma,
842 req,
843 duty,
844 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
845 dma_transfer_option,
846 )
847 .await
848 }
849 #[cfg(not(any(stm32l0)))]
850 TimerBits::Bits32 => {
851 #[cfg(not(any(bdma, gpdma)))]
852 panic!("unsupported timer bits");
853
854 #[cfg(any(bdma, gpdma))]
855 Transfer::new_write(
856 dma,
857 req,
858 duty,
859 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
860 dma_transfer_option,
861 )
862 .await
863 }
864 };
865 };
866
867 // restore output compare state
868 if !original_enable_state {
869 self.enable_channel(channel, false);
870 }
871
872 self.set_compare_value(channel, original_duty_state);
873 }
874
610 /// Get capture value for a channel. 875 /// Get capture value for a channel.
611 pub fn get_capture_value(&self, channel: Channel) -> u32 { 876 pub fn get_capture_value(&self, channel: Channel) -> u32 {
612 self.get_compare_value(channel) 877 self.get_compare_value(channel)
@@ -640,6 +905,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
640 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) 905 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
641 } 906 }
642 907
908 /// Set Timer Master Mode
909 pub fn set_master_mode(&self, mms: MasterMode) {
910 self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
911 }
912
643 /// Set Timer Slave Mode 913 /// Set Timer Slave Mode
644 pub fn set_slave_mode(&self, sms: SlaveMode) { 914 pub fn set_slave_mode(&self, sms: SlaveMode) {
645 self.regs_gp16().smcr().modify(|r| r.set_sms(sms)); 915 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
@@ -760,6 +1030,16 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
760 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val)); 1030 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
761 } 1031 }
762 1032
1033 /// Set master mode selection 2
1034 pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
1035 self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
1036 }
1037
1038 /// Set repetition counter
1039 pub fn set_repetition_counter(&self, val: u16) {
1040 self.regs_advanced().rcr().modify(|w| w.set_rep(val));
1041 }
1042
763 /// Trigger software break 1 or 2 1043 /// Trigger software break 1 or 2
764 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware. 1044 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
765 pub fn trigger_software_break(&self, n: usize) { 1045 pub fn trigger_software_break(&self, n: usize) {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index b09bc7166..804d1ef37 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -399,7 +399,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> {
399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { 399impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
400 unsafe fn on_interrupt() { 400 unsafe fn on_interrupt() {
401 #[cfg(feature = "low-power")] 401 #[cfg(feature = "low-power")]
402 crate::low_power::on_wakeup_irq(); 402 crate::low_power::Executor::on_wakeup_irq();
403 403
404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); 404 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
405 405
@@ -429,7 +429,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
429{ 429{
430 unsafe fn on_interrupt() { 430 unsafe fn on_interrupt() {
431 #[cfg(feature = "low-power")] 431 #[cfg(feature = "low-power")]
432 crate::low_power::on_wakeup_irq(); 432 crate::low_power::Executor::on_wakeup_irq();
433 433
434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); 434 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
435 435
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index a75b41bd7..fe8681356 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -11,12 +11,12 @@ use super::low_level::{
11}; 11};
12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin}; 12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
13pub use super::{Ch1, Ch2}; 13pub use super::{Ch1, Ch2};
14use crate::Peri;
14use crate::gpio::{AfType, AnyPin, Pull}; 15use crate::gpio::{AfType, AnyPin, Pull};
15use crate::interrupt::typelevel::{Binding, Interrupt}; 16use crate::interrupt::typelevel::{Binding, Interrupt};
16use crate::pac::timer::vals::Etp; 17use crate::pac::timer::vals::Etp;
17use crate::time::Hertz; 18use crate::time::Hertz;
18use crate::timer::TimerChannel; 19use crate::timer::TimerChannel;
19use crate::Peri;
20 20
21/// External input marker type. 21/// External input marker type.
22pub enum Ext {} 22pub enum Ext {}
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 159b5a177..057ab011a 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -2,9 +2,9 @@
2 2
3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; 3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin}; 4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin};
5use crate::Peri;
5use crate::gpio::{AfType, Pull}; 6use crate::gpio::{AfType, Pull};
6use crate::time::Hertz; 7use crate::time::Hertz;
7use crate::Peri;
8 8
9/// PWM Input driver. 9/// PWM Input driver.
10/// 10///
@@ -47,6 +47,7 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
47 inner.set_counting_mode(CountingMode::EdgeAlignedUp); 47 inner.set_counting_mode(CountingMode::EdgeAlignedUp);
48 inner.set_tick_freq(freq); 48 inner.set_tick_freq(freq);
49 inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 49 inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
50 inner.generate_update_event();
50 inner.start(); 51 inner.start();
51 52
52 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 53 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index bb152731c..a547a2a19 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -5,9 +5,9 @@ use stm32_metapac::timer::vals::{self, Sms};
5use super::low_level::Timer; 5use super::low_level::Timer;
6pub use super::{Ch1, Ch2}; 6pub use super::{Ch1, Ch2};
7use super::{GeneralInstance4Channel, TimerPin}; 7use super::{GeneralInstance4Channel, TimerPin};
8use crate::Peri;
8use crate::gpio::{AfType, AnyPin, Pull}; 9use crate::gpio::{AfType, AnyPin, Pull};
9use crate::timer::TimerChannel; 10use crate::timer::TimerChannel;
10use crate::Peri;
11 11
12/// Qei driver config. 12/// Qei driver config.
13#[cfg_attr(feature = "defmt", derive(defmt::Format))] 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index e6165e42b..6c9ef17e0 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,12 +4,12 @@ use core::marker::PhantomData;
4use core::mem::ManuallyDrop; 4use core::mem::ManuallyDrop;
5 5
6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; 7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin};
8use crate::Peri;
8#[cfg(gpio_v2)] 9#[cfg(gpio_v2)]
9use crate::gpio::Pull; 10use crate::gpio::Pull;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 11use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::time::Hertz; 12use crate::time::Hertz;
12use crate::Peri;
13 13
14/// PWM pin wrapper. 14/// PWM pin wrapper.
15/// 15///
@@ -198,7 +198,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
198 this.inner.set_counting_mode(counting_mode); 198 this.inner.set_counting_mode(counting_mode);
199 this.set_frequency(freq); 199 this.set_frequency(freq);
200 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 200 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
201 this.inner.start();
202 201
203 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 202 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
204 .iter() 203 .iter()
@@ -207,6 +206,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
207 206
208 this.inner.set_output_compare_preload(channel, true); 207 this.inner.set_output_compare_preload(channel, true);
209 }); 208 });
209 this.inner.set_autoreload_preload(true);
210
211 // Generate update event so pre-load registers are written to the shadow registers
212 this.inner.generate_update_event();
213 this.inner.start();
210 214
211 this 215 this
212 } 216 }
@@ -285,8 +289,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
285 289
286 /// Set PWM frequency. 290 /// Set PWM frequency.
287 /// 291 ///
288 /// Note: when you call this, the max duty value changes, so you will have to 292 /// Note: that the frequency will not be applied in the timer until an update event
289 /// call `set_duty` on all channels with the duty calculated based on the new max duty. 293 /// occurs.
290 pub fn set_frequency(&mut self, freq: Hertz) { 294 pub fn set_frequency(&mut self, freq: Hertz) {
291 // TODO: prevent ARR = u16::MAX? 295 // TODO: prevent ARR = u16::MAX?
292 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 296 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
@@ -309,61 +313,12 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
309 /// Generate a sequence of PWM waveform 313 /// Generate a sequence of PWM waveform
310 /// 314 ///
311 /// Note: 315 /// Note:
312 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 316 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
317 /// Also be aware that embassy timers use one of timers internally. It is possible to
318 /// switch this timer by using `time-driver-timX` feature.
319 #[inline(always)]
313 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 320 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
314 #[allow(clippy::let_unit_value)] // eg. stm32f334 321 self.inner.waveform_up(dma, channel, duty).await;
315 let req = dma.request();
316
317 let original_duty_state = self.channel(channel).current_duty_cycle();
318 let original_enable_state = self.channel(channel).is_enabled();
319 let original_update_dma_state = self.inner.get_update_dma_state();
320
321 if !original_update_dma_state {
322 self.inner.enable_update_dma(true);
323 }
324
325 if !original_enable_state {
326 self.channel(channel).enable();
327 }
328
329 unsafe {
330 #[cfg(not(any(bdma, gpdma)))]
331 use crate::dma::{Burst, FifoThreshold};
332 use crate::dma::{Transfer, TransferOptions};
333
334 let dma_transfer_option = TransferOptions {
335 #[cfg(not(any(bdma, gpdma)))]
336 fifo_threshold: Some(FifoThreshold::Full),
337 #[cfg(not(any(bdma, gpdma)))]
338 mburst: Burst::Incr8,
339 ..Default::default()
340 };
341
342 Transfer::new_write(
343 dma,
344 req,
345 duty,
346 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
347 dma_transfer_option,
348 )
349 .await
350 };
351
352 // restore output compare state
353 if !original_enable_state {
354 self.channel(channel).disable();
355 }
356
357 self.channel(channel).set_duty_cycle(original_duty_state);
358
359 // Since DMA is closed before timer update event trigger DMA is turn off,
360 // this can almost always trigger a DMA FIFO error.
361 //
362 // optional TODO:
363 // clean FEIF after disable UDE
364 if !original_update_dma_state {
365 self.inner.enable_update_dma(false);
366 }
367 } 322 }
368 323
369 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. 324 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
@@ -378,18 +333,24 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
378 /// 333 ///
379 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: 334 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
380 /// 335 ///
336 /// ```rust,ignore
381 /// let dma_buf: [u16; 16] = [ 337 /// let dma_buf: [u16; 16] = [
382 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 338 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
383 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 339 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
384 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 340 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
385 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 341 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
386 /// ]; 342 /// ];
343 /// ```
387 /// 344 ///
388 /// Each group of N values (where N = number of channels) is transferred on one update event, 345 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
389 /// updating the duty cycles of all selected channels simultaneously. 346 /// updating the duty cycles of all selected channels simultaneously.
390 /// 347 ///
391 /// Note: 348 /// Note:
392 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 349 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
350 /// Also be aware that embassy timers use one of timers internally. It is possible to
351 /// switch this timer by using `time-driver-timX` feature.
352 ///
353 #[inline(always)]
393 pub async fn waveform_up_multi_channel( 354 pub async fn waveform_up_multi_channel(
394 &mut self, 355 &mut self,
395 dma: Peri<'_, impl super::UpDma<T>>, 356 dma: Peri<'_, impl super::UpDma<T>>,
@@ -397,148 +358,15 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
397 ending_channel: Channel, 358 ending_channel: Channel,
398 duty: &[u16], 359 duty: &[u16],
399 ) { 360 ) {
400 let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32;
401 let start_ch_index = starting_channel.index();
402 let end_ch_index = ending_channel.index();
403
404 assert!(start_ch_index <= end_ch_index);
405
406 let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
407 self.inner
408 .regs_gp16()
409 .dcr()
410 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
411 self.inner 361 self.inner
412 .regs_gp16() 362 .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty)
413 .dcr() 363 .await;
414 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
415
416 #[allow(clippy::let_unit_value)] // eg. stm32f334
417 let req = dma.request();
418
419 let original_update_dma_state = self.inner.get_update_dma_state();
420 if !original_update_dma_state {
421 self.inner.enable_update_dma(true);
422 }
423
424 unsafe {
425 #[cfg(not(any(bdma, gpdma)))]
426 use crate::dma::{Burst, FifoThreshold};
427 use crate::dma::{Transfer, TransferOptions};
428
429 let dma_transfer_option = TransferOptions {
430 #[cfg(not(any(bdma, gpdma)))]
431 fifo_threshold: Some(FifoThreshold::Full),
432 #[cfg(not(any(bdma, gpdma)))]
433 mburst: Burst::Incr4,
434 ..Default::default()
435 };
436
437 Transfer::new_write(
438 dma,
439 req,
440 duty,
441 self.inner.regs_gp16().dmar().as_ptr() as *mut u16,
442 dma_transfer_option,
443 )
444 .await
445 };
446
447 if !original_update_dma_state {
448 self.inner.enable_update_dma(false);
449 }
450 } 364 }
451}
452 365
453impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
454 /// Generate a sequence of PWM waveform 366 /// Generate a sequence of PWM waveform
367 #[inline(always)]
455 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { 368 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
456 use crate::pac::timer::vals::Ccds; 369 self.inner.waveform(dma, duty).await;
457
458 #[allow(clippy::let_unit_value)] // eg. stm32f334
459 let req = dma.request();
460
461 let cc_channel = C::CHANNEL;
462
463 let original_duty_state = self.channel(cc_channel).current_duty_cycle();
464 let original_enable_state = self.channel(cc_channel).is_enabled();
465 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
466 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
467
468 // redirect CC DMA request onto Update Event
469 if !original_cc_dma_on_update {
470 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
471 }
472
473 if !original_cc_dma_enabled {
474 self.inner.set_cc_dma_enable_state(cc_channel, true);
475 }
476
477 if !original_enable_state {
478 self.channel(cc_channel).enable();
479 }
480
481 unsafe {
482 #[cfg(not(any(bdma, gpdma)))]
483 use crate::dma::{Burst, FifoThreshold};
484 use crate::dma::{Transfer, TransferOptions};
485
486 let dma_transfer_option = TransferOptions {
487 #[cfg(not(any(bdma, gpdma)))]
488 fifo_threshold: Some(FifoThreshold::Full),
489 #[cfg(not(any(bdma, gpdma)))]
490 mburst: Burst::Incr8,
491 ..Default::default()
492 };
493
494 match self.inner.bits() {
495 TimerBits::Bits16 => {
496 Transfer::new_write(
497 dma,
498 req,
499 duty,
500 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
501 dma_transfer_option,
502 )
503 .await
504 }
505 #[cfg(not(any(stm32l0)))]
506 TimerBits::Bits32 => {
507 #[cfg(not(any(bdma, gpdma)))]
508 panic!("unsupported timer bits");
509
510 #[cfg(any(bdma, gpdma))]
511 Transfer::new_write(
512 dma,
513 req,
514 duty,
515 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
516 dma_transfer_option,
517 )
518 .await
519 }
520 };
521 };
522
523 // restore output compare state
524 if !original_enable_state {
525 self.channel(cc_channel).disable();
526 }
527
528 self.channel(cc_channel).set_duty_cycle(original_duty_state);
529
530 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
531 // this can almost always trigger a DMA FIFO error.
532 //
533 // optional TODO:
534 // clean FEIF after disable UDE
535 if !original_cc_dma_enabled {
536 self.inner.set_cc_dma_enable_state(cc_channel, false);
537 }
538
539 if !original_cc_dma_on_update {
540 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
541 }
542 } 370 }
543} 371}
544 372
diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs
index 7d6442b48..097cf7942 100644
--- a/embassy-stm32/src/tsc/acquisition_banks.rs
+++ b/embassy-stm32/src/tsc/acquisition_banks.rs
@@ -1,11 +1,11 @@
1use super::TSC_NUM_GROUPS;
1use super::io_pin::*; 2use super::io_pin::*;
2#[cfg(any(tsc_v2, tsc_v3))] 3#[cfg(any(tsc_v2, tsc_v3))]
3use super::pin_groups::G7; 4use super::pin_groups::G7;
4#[cfg(tsc_v3)] 5#[cfg(tsc_v3)]
5use super::pin_groups::G8; 6use super::pin_groups::G8;
6use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; 7use super::pin_groups::{G1, G2, G3, G4, G5, G6, pin_roles};
7use super::types::{Group, GroupStatus}; 8use super::types::{Group, GroupStatus};
8use super::TSC_NUM_GROUPS;
9 9
10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. 10/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank.
11/// 11///
diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs
index 84421f7ff..9347e6bc0 100644
--- a/embassy-stm32/src/tsc/pin_groups.rs
+++ b/embassy-stm32/src/tsc/pin_groups.rs
@@ -1,11 +1,11 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::ops::BitOr; 2use core::ops::BitOr;
3 3
4use super::Instance;
4use super::errors::GroupError; 5use super::errors::GroupError;
5use super::io_pin::*; 6use super::io_pin::*;
6use super::Instance;
7use crate::gpio::{AfType, AnyPin, OutputType, Speed};
8use crate::Peri; 7use crate::Peri;
8use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9 9
10/// Pin type definition to control IO parameters 10/// Pin type definition to control IO parameters
11#[derive(PartialEq, Clone, Copy)] 11#[derive(PartialEq, Clone, Copy)]
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 18aff4fbd..ae86d28f0 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -19,8 +19,8 @@ use core::marker::PhantomData;
19use core::sync::atomic::{AtomicBool, Ordering}; 19use core::sync::atomic::{AtomicBool, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
22use embassy_hal_internal::drop::OnDrop;
23use embassy_hal_internal::PeripheralType; 22use embassy_hal_internal::PeripheralType;
23use embassy_hal_internal::drop::OnDrop;
24use embassy_sync::waitqueue::AtomicWaker; 24use embassy_sync::waitqueue::AtomicWaker;
25 25
26use crate::dma::{ChannelAndRequest, TransferOptions}; 26use crate::dma::{ChannelAndRequest, TransferOptions};
@@ -28,11 +28,11 @@ use crate::interrupt::typelevel::Interrupt;
28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 28use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; 29pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
30use crate::rcc::{self, RccPeripheral}; 30use crate::rcc::{self, RccPeripheral};
31use crate::{interrupt, Peri}; 31use crate::{Peri, interrupt};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
34 _cs: critical_section::CriticalSection, 34 _cs: critical_section::CriticalSection,
35 #[cfg(peri_ucpd1)] ucpd1_db_enable: bool, 35 #[cfg(all(peri_ucpd1, not(stm32n6)))] ucpd1_db_enable: bool,
36 #[cfg(peri_ucpd2)] ucpd2_db_enable: bool, 36 #[cfg(peri_ucpd2)] ucpd2_db_enable: bool,
37) { 37) {
38 #[cfg(stm32g0x1)] 38 #[cfg(stm32g0x1)]
@@ -349,6 +349,7 @@ impl<'d, T: Instance> CcPhy<'d, T> {
349 critical_section::with(|cs| { 349 critical_section::with(|cs| {
350 init( 350 init(
351 cs, 351 cs,
352 #[cfg(not(stm32n6))]
352 false, 353 false,
353 #[cfg(peri_ucpd2)] 354 #[cfg(peri_ucpd2)]
354 false, 355 false,
diff --git a/embassy-stm32/src/uid.rs b/embassy-stm32/src/uid.rs
index 5e38532bd..2d3e2b972 100644
--- a/embassy-stm32/src/uid.rs
+++ b/embassy-stm32/src/uid.rs
@@ -1,8 +1,8 @@
1//! Unique ID (UID) 1//! Unique ID (UID)
2 2
3/// Get this device's unique 96-bit ID. 3/// Get this device's unique 96-bit ID.
4pub fn uid() -> &'static [u8; 12] { 4pub fn uid() -> [u8; 12] {
5 unsafe { &*crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() } 5 unsafe { *crate::pac::UID.uid(0).as_ptr().cast::<[u8; 12]>() }
6} 6}
7 7
8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits. 8/// Get this device's unique 96-bit ID, encoded into a string of 24 hexadecimal ASCII digits.
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 10dc02334..26d2b8991 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -5,16 +5,16 @@ use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
9use embassy_hal_internal::Peri; 8use embassy_hal_internal::Peri;
9use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
13use super::DePin; 13use super::DePin;
14use super::{ 14use super::{
15 Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin,
15 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, 16 clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate,
16 sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, 17 sr, tdr,
17 TxPin,
18}; 18};
19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; 19use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _};
20use crate::interrupt::{self, InterruptExt}; 20use crate::interrupt::{self, InterruptExt};
@@ -87,7 +87,7 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
87 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC) 87 // With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
88 // indicates that all bytes are pushed out from the FIFO. 88 // indicates that all bytes are pushed out from the FIFO.
89 // For other usart variants it shows that last byte from the buffer was just sent. 89 // For other usart variants it shows that last byte from the buffer was just sent.
90 if sr_val.tc() { 90 if sr_val.tc() && r.cr1().read().tcie() {
91 // For others it is cleared above with `clear_interrupt_flags`. 91 // For others it is cleared above with `clear_interrupt_flags`.
92 #[cfg(any(usart_v1, usart_v2))] 92 #[cfg(any(usart_v1, usart_v2))]
93 sr(r).modify(|w| w.set_tc(false)); 93 sr(r).modify(|w| w.set_tc(false));
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 0d2d86aca..0e7da634d 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -4,15 +4,16 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; 7use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering, compiler_fence};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::drop::OnDrop;
12use embassy_hal_internal::PeripheralType; 11use embassy_hal_internal::PeripheralType;
12use embassy_hal_internal::drop::OnDrop;
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures_util::future::{select, Either}; 14use futures_util::future::{Either, select};
15 15
16use crate::Peri;
16use crate::dma::ChannelAndRequest; 17use crate::dma::ChannelAndRequest;
17use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
18use crate::interrupt::typelevel::Interrupt as _; 19use crate::interrupt::typelevel::Interrupt as _;
@@ -25,7 +26,6 @@ use crate::pac::usart::Usart as Regs;
25use crate::pac::usart::{regs, vals}; 26use crate::pac::usart::{regs, vals};
26use crate::rcc::{RccInfo, SealedRccPeripheral}; 27use crate::rcc::{RccInfo, SealedRccPeripheral};
27use crate::time::Hertz; 28use crate::time::Hertz;
28use crate::Peri;
29 29
30/// Interrupt handler. 30/// Interrupt handler.
31pub struct InterruptHandler<T: Instance> { 31pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 27071fb31..bac570d27 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -1,19 +1,21 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::mem; 2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{Ordering, compiler_fence};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embedded_io_async::ReadReady; 7use embedded_io_async::ReadReady;
8use futures_util::future::{select, Either}; 8use futures_util::future::{Either, select};
9 9
10use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; 10use super::{
11 Config, ConfigError, Error, Info, State, UartRx, clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr,
12};
13use crate::Peri;
11use crate::dma::ReadableRingBuffer; 14use crate::dma::ReadableRingBuffer;
12use crate::gpio::{AnyPin, SealedPin as _}; 15use crate::gpio::{AnyPin, SealedPin as _};
13use crate::mode::Async; 16use crate::mode::Async;
14use crate::time::Hertz; 17use crate::time::Hertz;
15use crate::usart::Regs; 18use crate::usart::Regs;
16use crate::Peri;
17 19
18/// Rx-only Ring-buffered UART Driver 20/// Rx-only Ring-buffered UART Driver
19/// 21///
@@ -338,26 +340,16 @@ impl Drop for RingBufferedUartRx<'_> {
338/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags 340/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags
339/// are cleared by a single read to the RDR register. 341/// are cleared by a single read to the RDR register.
340fn check_idle_and_errors(r: Regs) -> Result<bool, Error> { 342fn check_idle_and_errors(r: Regs) -> Result<bool, Error> {
341 // Critical section is required so that the flags aren't set after read and before clear 343 // SAFETY: read only and we only use Rx related flags
342 let sr = critical_section::with(|_| { 344 let sr = sr(r).read();
343 // SAFETY: read only and we only use Rx related flags 345
344 let sr = sr(r).read(); 346 #[cfg(not(any(usart_v3, usart_v4)))]
345 347 unsafe {
346 #[cfg(any(usart_v3, usart_v4))] 348 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
347 r.icr().write(|w| { 349 rdr(r).read_volatile()
348 w.set_idle(true); 350 };
349 w.set_pe(true); 351 clear_interrupt_flags(r, sr);
350 w.set_fe(true); 352
351 w.set_ne(true);
352 w.set_ore(true);
353 });
354 #[cfg(not(any(usart_v3, usart_v4)))]
355 unsafe {
356 // This read also clears the error and idle interrupt flags on v1 (TODO and v2?)
357 rdr(r).read_volatile()
358 };
359 sr
360 });
361 if sr.pe() { 353 if sr.pe() {
362 Err(Error::Parity) 354 Err(Error::Parity)
363 } else if sr.fe() { 355 } else if sr.fe() {
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 5ce81b131..f6b1a81db 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -2,18 +2,18 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::PeripheralType; 3use embassy_hal_internal::PeripheralType;
4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; 4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported};
5use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7pub use embassy_usb_synopsys_otg::Config; 5pub use embassy_usb_synopsys_otg::Config;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
8use embassy_usb_synopsys_otg::{ 8use embassy_usb_synopsys_otg::{
9 on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, 9 Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out, PhyType, State,
10 PhyType, State, 10 on_interrupt as on_interrupt_impl,
11}; 11};
12 12
13use crate::gpio::{AfType, OutputType, Speed}; 13use crate::gpio::{AfType, OutputType, Speed};
14use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
15use crate::rcc::{self, RccPeripheral}; 15use crate::rcc::{self, RccPeripheral};
16use crate::{interrupt, Peri}; 16use crate::{Peri, interrupt};
17 17
18const MAX_EP_COUNT: usize = 9; 18const MAX_EP_COUNT: usize = 9;
19 19
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 9e08d99b3..d405e4802 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -12,11 +12,11 @@ use embassy_usb_driver::{
12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, 12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
13}; 13};
14 14
15use crate::pac::USBRAM;
15use crate::pac::usb::regs; 16use crate::pac::usb::regs;
16use crate::pac::usb::vals::{EpType, Stat}; 17use crate::pac::usb::vals::{EpType, Stat};
17use crate::pac::USBRAM;
18use crate::rcc::RccPeripheral; 18use crate::rcc::RccPeripheral;
19use crate::{interrupt, Peri}; 19use crate::{Peri, interrupt};
20 20
21/// Interrupt handler. 21/// Interrupt handler.
22pub struct InterruptHandler<T: Instance> { 22pub struct InterruptHandler<T: Instance> {
diff --git a/embassy-stm32/src/vrefbuf/mod.rs b/embassy-stm32/src/vrefbuf/mod.rs
index ccbd748d5..43dd9c800 100644
--- a/embassy-stm32/src/vrefbuf/mod.rs
+++ b/embassy-stm32/src/vrefbuf/mod.rs
@@ -14,10 +14,10 @@ pub struct VoltageReferenceBuffer<'d, T: Instance> {
14#[cfg(rcc_wba)] 14#[cfg(rcc_wba)]
15fn get_refbuf_trim(voltage_scale: Vrs) -> usize { 15fn get_refbuf_trim(voltage_scale: Vrs) -> usize {
16 match voltage_scale { 16 match voltage_scale {
17 Vrs::VREF0 => 0x0BFA_07A8usize, 17 Vrs::VREF0 => 0x0BFA_07ABusize,
18 Vrs::VREF1 => 0x0BFA_07A9usize, 18 Vrs::VREF1 => 0x0BFA_07AAusize,
19 Vrs::VREF2 => 0x0BFA_07AAusize, 19 Vrs::VREF2 => 0x0BFA_07A9usize,
20 Vrs::VREF3 => 0x0BFA_07ABusize, 20 Vrs::VREF3 => 0x0BFA_07A8usize,
21 _ => panic!("Incorrect Vrs setting!"), 21 _ => panic!("Incorrect Vrs setting!"),
22 } 22 }
23} 23}
@@ -62,8 +62,7 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> {
62 } 62 }
63 trace!( 63 trace!(
64 "Vrefbuf configured with voltage scale {} and impedance mode {}", 64 "Vrefbuf configured with voltage scale {} and impedance mode {}",
65 voltage_scale as u8, 65 voltage_scale as u8, impedance_mode as u8,
66 impedance_mode as u8,
67 ); 66 );
68 VoltageReferenceBuffer { vrefbuf: PhantomData } 67 VoltageReferenceBuffer { vrefbuf: PhantomData }
69 } 68 }
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index fb5c3d930..1164739ff 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -4,8 +4,8 @@ use core::marker::PhantomData;
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5use stm32_metapac::iwdg::vals::{Key, Pr}; 5use stm32_metapac::iwdg::vals::{Key, Pr};
6 6
7use crate::rcc::LSI_FREQ;
8use crate::Peri; 7use crate::Peri;
8use crate::rcc::LSI_FREQ;
9 9
10/// Independent watchdog (IWDG) driver. 10/// Independent watchdog (IWDG) driver.
11pub struct IndependentWatchdog<'d, T: Instance> { 11pub struct IndependentWatchdog<'d, T: Instance> {
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
index 6f224ab99..466e1a9b4 100644
--- a/embassy-stm32/src/xspi/mod.rs
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -11,15 +11,15 @@ use embassy_embedded_hal::{GetConfig, SetConfig};
11use embassy_hal_internal::PeripheralType; 11use embassy_hal_internal::PeripheralType;
12pub use enums::*; 12pub use enums::*;
13 13
14use crate::dma::{word, ChannelAndRequest}; 14use crate::dma::{ChannelAndRequest, word};
15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 15use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
16use crate::mode::{Async, Blocking, Mode as PeriMode}; 16use crate::mode::{Async, Blocking, Mode as PeriMode};
17use crate::pac::xspi::vals::*;
18use crate::pac::xspi::Xspi as Regs; 17use crate::pac::xspi::Xspi as Regs;
18use crate::pac::xspi::vals::*;
19#[cfg(xspim_v1)] 19#[cfg(xspim_v1)]
20use crate::pac::xspim::Xspim; 20use crate::pac::xspim::Xspim;
21use crate::rcc::{self, RccPeripheral}; 21use crate::rcc::{self, RccPeripheral};
22use crate::{peripherals, Peri}; 22use crate::{Peri, peripherals};
23 23
24/// XPSI driver config. 24/// XPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]