diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-09-29 06:58:33 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-09-29 06:58:33 +0200 |
| commit | d9e2d176256ef4959c1ba60893ea361363d480d3 (patch) | |
| tree | de6fcb6723eb424fdcd364f4e2e20535ade78a6c | |
| parent | b6f84efd90b3c2751e6fe03183229d1a7d456091 (diff) | |
| parent | 006bbea51afeeb01fac8c7adb3ae0ff549d4ecf0 (diff) | |
Merge pull request #380 from bgamari/stm32g0-adc
Fix STM32G0 ADC
| -rw-r--r-- | embassy-stm32/src/adc/g0.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 250 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/v2.rs | 15 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/g0/mod.rs | 57 |
5 files changed, 251 insertions, 77 deletions
diff --git a/embassy-stm32/src/adc/g0.rs b/embassy-stm32/src/adc/g0.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/adc/g0.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9955502a6..f292d0208 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg_attr(adc_v3, path = "v3.rs")] | 3 | #[cfg_attr(adc_v3, path = "v3.rs")] |
| 4 | #[cfg_attr(adc_g0, path = "g0.rs")] | 4 | #[cfg_attr(adc_g0, path = "v3.rs")] |
| 5 | mod _version; | 5 | mod _version; |
| 6 | 6 | ||
| 7 | #[allow(unused)] | 7 | #[allow(unused)] |
| @@ -72,6 +72,9 @@ macro_rules! impl_pin { | |||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | crate::pac::peripheral_pins!( | 74 | crate::pac::peripheral_pins!( |
| 75 | ($inst:ident, adc, ADC, $pin:ident, IN0) => { | ||
| 76 | impl_pin!($inst, $pin, 0); | ||
| 77 | }; | ||
| 75 | ($inst:ident, adc, ADC, $pin:ident, IN1) => { | 78 | ($inst:ident, adc, ADC, $pin:ident, IN1) => { |
| 76 | impl_pin!($inst, $pin, 1); | 79 | impl_pin!($inst, $pin, 1); |
| 77 | }; | 80 | }; |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 2781fc4dc..ddf06deae 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -6,6 +6,17 @@ use embedded_hal::blocking::delay::DelayUs; | |||
| 6 | 6 | ||
| 7 | pub const VDDA_CALIB_MV: u32 = 3000; | 7 | pub const VDDA_CALIB_MV: u32 = 3000; |
| 8 | 8 | ||
| 9 | /// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock | ||
| 10 | /// configuration. | ||
| 11 | unsafe fn enable() { | ||
| 12 | #[cfg(rcc_h7)] | ||
| 13 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); | ||
| 14 | #[cfg(rcc_g0)] | ||
| 15 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); | ||
| 16 | #[cfg(rcc_l4)] | ||
| 17 | crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | ||
| 18 | } | ||
| 19 | |||
| 9 | pub enum Resolution { | 20 | pub enum Resolution { |
| 10 | TwelveBit, | 21 | TwelveBit, |
| 11 | TenBit, | 22 | TenBit, |
| @@ -43,7 +54,11 @@ pub struct Vref; | |||
| 43 | impl<T: Instance> AdcPin<T> for Vref {} | 54 | impl<T: Instance> AdcPin<T> for Vref {} |
| 44 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | 55 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { |
| 45 | fn channel(&self) -> u8 { | 56 | fn channel(&self) -> u8 { |
| 46 | 0 | 57 | #[cfg(not(rcc_g0))] |
| 58 | let val = 0; | ||
| 59 | #[cfg(rcc_g0)] | ||
| 60 | let val = 13; | ||
| 61 | val | ||
| 47 | } | 62 | } |
| 48 | } | 63 | } |
| 49 | 64 | ||
| @@ -51,7 +66,11 @@ pub struct Temperature; | |||
| 51 | impl<T: Instance> AdcPin<T> for Temperature {} | 66 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 52 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 67 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { |
| 53 | fn channel(&self) -> u8 { | 68 | fn channel(&self) -> u8 { |
| 54 | 17 | 69 | #[cfg(not(rcc_g0))] |
| 70 | let val = 17; | ||
| 71 | #[cfg(rcc_g0)] | ||
| 72 | let val = 12; | ||
| 73 | val | ||
| 55 | } | 74 | } |
| 56 | } | 75 | } |
| 57 | 76 | ||
| @@ -59,61 +78,124 @@ pub struct Vbat; | |||
| 59 | impl<T: Instance> AdcPin<T> for Vbat {} | 78 | impl<T: Instance> AdcPin<T> for Vbat {} |
| 60 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { | 79 | impl<T: Instance> super::sealed::AdcPin<T> for Vbat { |
| 61 | fn channel(&self) -> u8 { | 80 | fn channel(&self) -> u8 { |
| 62 | 18 | 81 | #[cfg(not(rcc_g0))] |
| 82 | let val = 18; | ||
| 83 | #[cfg(rcc_g0)] | ||
| 84 | let val = 14; | ||
| 85 | val | ||
| 63 | } | 86 | } |
| 64 | } | 87 | } |
| 65 | 88 | ||
| 66 | /// ADC sample time | 89 | #[cfg(not(adc_g0))] |
| 67 | /// | 90 | mod sample_time { |
| 68 | /// The default setting is 2.5 ADC clock cycles. | 91 | /// ADC sample time |
| 69 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] | 92 | /// |
| 70 | pub enum SampleTime { | 93 | /// The default setting is 2.5 ADC clock cycles. |
| 71 | /// 2.5 ADC clock cycles | 94 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] |
| 72 | Cycles2_5 = 0b000, | 95 | pub enum SampleTime { |
| 96 | /// 2.5 ADC clock cycles | ||
| 97 | Cycles2_5 = 0b000, | ||
| 73 | 98 | ||
| 74 | /// 6.5 ADC clock cycles | 99 | /// 6.5 ADC clock cycles |
| 75 | Cycles6_5 = 0b001, | 100 | Cycles6_5 = 0b001, |
| 76 | 101 | ||
| 77 | /// 12.5 ADC clock cycles | 102 | /// 12.5 ADC clock cycles |
| 78 | Cycles12_5 = 0b010, | 103 | Cycles12_5 = 0b010, |
| 79 | 104 | ||
| 80 | /// 24.5 ADC clock cycles | 105 | /// 24.5 ADC clock cycles |
| 81 | Cycles24_5 = 0b011, | 106 | Cycles24_5 = 0b011, |
| 82 | 107 | ||
| 83 | /// 47.5 ADC clock cycles | 108 | /// 47.5 ADC clock cycles |
| 84 | Cycles47_5 = 0b100, | 109 | Cycles47_5 = 0b100, |
| 85 | 110 | ||
| 86 | /// 92.5 ADC clock cycles | 111 | /// 92.5 ADC clock cycles |
| 87 | Cycles92_5 = 0b101, | 112 | Cycles92_5 = 0b101, |
| 88 | 113 | ||
| 89 | /// 247.5 ADC clock cycles | 114 | /// 247.5 ADC clock cycles |
| 90 | Cycles247_5 = 0b110, | 115 | Cycles247_5 = 0b110, |
| 91 | 116 | ||
| 92 | /// 640.5 ADC clock cycles | 117 | /// 640.5 ADC clock cycles |
| 93 | Cycles640_5 = 0b111, | 118 | Cycles640_5 = 0b111, |
| 94 | } | 119 | } |
| 95 | 120 | ||
| 96 | impl SampleTime { | 121 | impl SampleTime { |
| 97 | fn sample_time(&self) -> crate::pac::adc::vals::SampleTime { | 122 | pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime { |
| 98 | match self { | 123 | match self { |
| 99 | SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5, | 124 | SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5, |
| 100 | SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5, | 125 | SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5, |
| 101 | SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5, | 126 | SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5, |
| 102 | SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5, | 127 | SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5, |
| 103 | SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5, | 128 | SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5, |
| 104 | SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5, | 129 | SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5, |
| 105 | SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5, | 130 | SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5, |
| 106 | SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5, | 131 | SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5, |
| 132 | } | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | impl Default for SampleTime { | ||
| 137 | fn default() -> Self { | ||
| 138 | Self::Cycles2_5 | ||
| 107 | } | 139 | } |
| 108 | } | 140 | } |
| 109 | } | 141 | } |
| 110 | 142 | ||
| 111 | impl Default for SampleTime { | 143 | #[cfg(adc_g0)] |
| 112 | fn default() -> Self { | 144 | mod sample_time { |
| 113 | Self::Cycles2_5 | 145 | /// ADC sample time |
| 146 | /// | ||
| 147 | /// The default setting is 1.5 ADC clock cycles. | ||
| 148 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] | ||
| 149 | pub enum SampleTime { | ||
| 150 | /// 1.5 ADC clock cycles | ||
| 151 | Cycles1_5 = 0b000, | ||
| 152 | |||
| 153 | /// 3.5 ADC clock cycles | ||
| 154 | Cycles3_5 = 0b001, | ||
| 155 | |||
| 156 | /// 7.5 ADC clock cycles | ||
| 157 | Cycles7_5 = 0b010, | ||
| 158 | |||
| 159 | /// 12.5 ADC clock cycles | ||
| 160 | Cycles12_5 = 0b011, | ||
| 161 | |||
| 162 | /// 19.5 ADC clock cycles | ||
| 163 | Cycles19_5 = 0b100, | ||
| 164 | |||
| 165 | /// 39.5 ADC clock cycles | ||
| 166 | Cycles39_5 = 0b101, | ||
| 167 | |||
| 168 | /// 79.5 ADC clock cycles | ||
| 169 | Cycles79_5 = 0b110, | ||
| 170 | |||
| 171 | /// 160.5 ADC clock cycles | ||
| 172 | Cycles160_5 = 0b111, | ||
| 173 | } | ||
| 174 | |||
| 175 | impl SampleTime { | ||
| 176 | pub(crate) fn sample_time(&self) -> crate::pac::adc::vals::SampleTime { | ||
| 177 | match self { | ||
| 178 | SampleTime::Cycles1_5 => crate::pac::adc::vals::SampleTime::CYCLES1_5, | ||
| 179 | SampleTime::Cycles3_5 => crate::pac::adc::vals::SampleTime::CYCLES3_5, | ||
| 180 | SampleTime::Cycles7_5 => crate::pac::adc::vals::SampleTime::CYCLES7_5, | ||
| 181 | SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5, | ||
| 182 | SampleTime::Cycles19_5 => crate::pac::adc::vals::SampleTime::CYCLES19_5, | ||
| 183 | SampleTime::Cycles39_5 => crate::pac::adc::vals::SampleTime::CYCLES39_5, | ||
| 184 | SampleTime::Cycles79_5 => crate::pac::adc::vals::SampleTime::CYCLES79_5, | ||
| 185 | SampleTime::Cycles160_5 => crate::pac::adc::vals::SampleTime::CYCLES160_5, | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | impl Default for SampleTime { | ||
| 191 | fn default() -> Self { | ||
| 192 | Self::Cycles1_5 | ||
| 193 | } | ||
| 114 | } | 194 | } |
| 115 | } | 195 | } |
| 116 | 196 | ||
| 197 | pub use sample_time::SampleTime; | ||
| 198 | |||
| 117 | pub struct Adc<'d, T: Instance> { | 199 | pub struct Adc<'d, T: Instance> { |
| 118 | sample_time: SampleTime, | 200 | sample_time: SampleTime, |
| 119 | calibrated_vdda: u32, | 201 | calibrated_vdda: u32, |
| @@ -125,15 +207,26 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 125 | pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | 207 | pub fn new(_peri: impl Unborrow<Target = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { |
| 126 | unborrow!(_peri); | 208 | unborrow!(_peri); |
| 127 | unsafe { | 209 | unsafe { |
| 210 | enable(); | ||
| 128 | T::regs().cr().modify(|reg| { | 211 | T::regs().cr().modify(|reg| { |
| 212 | #[cfg(not(adc_g0))] | ||
| 129 | reg.set_deeppwd(false); | 213 | reg.set_deeppwd(false); |
| 130 | reg.set_advregen(true); | 214 | reg.set_advregen(true); |
| 131 | }); | 215 | }); |
| 216 | |||
| 217 | #[cfg(adc_g0)] | ||
| 218 | T::regs().cfgr1().modify(|reg| { | ||
| 219 | reg.set_chselrmod(true); | ||
| 220 | }); | ||
| 132 | } | 221 | } |
| 133 | 222 | ||
| 134 | delay.delay_us(20); | 223 | delay.delay_us(20); |
| 135 | 224 | ||
| 136 | unsafe { | 225 | unsafe { |
| 226 | T::regs().cr().modify(|reg| { | ||
| 227 | reg.set_adcal(true); | ||
| 228 | }); | ||
| 229 | |||
| 137 | while T::regs().cr().read().adcal() { | 230 | while T::regs().cr().read().adcal() { |
| 138 | // spin | 231 | // spin |
| 139 | } | 232 | } |
| @@ -229,6 +322,27 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 229 | } | 322 | } |
| 230 | */ | 323 | */ |
| 231 | 324 | ||
| 325 | /// Perform a single conversion. | ||
| 326 | fn convert(&mut self) -> u16 { | ||
| 327 | unsafe { | ||
| 328 | T::regs().isr().modify(|reg| { | ||
| 329 | reg.set_eos(true); | ||
| 330 | reg.set_eoc(true); | ||
| 331 | }); | ||
| 332 | |||
| 333 | // Start conversion | ||
| 334 | T::regs().cr().modify(|reg| { | ||
| 335 | reg.set_adstart(true); | ||
| 336 | }); | ||
| 337 | |||
| 338 | while !T::regs().isr().read().eos() { | ||
| 339 | // spin | ||
| 340 | } | ||
| 341 | |||
| 342 | T::regs().dr().read().0 as u16 | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 232 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | 346 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 233 | unsafe { | 347 | unsafe { |
| 234 | // Make sure bits are off | 348 | // Make sure bits are off |
| @@ -249,48 +363,36 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 249 | } | 363 | } |
| 250 | 364 | ||
| 251 | // Configure ADC | 365 | // Configure ADC |
| 366 | #[cfg(not(rcc_g0))] | ||
| 252 | T::regs() | 367 | T::regs() |
| 253 | .cfgr() | 368 | .cfgr() |
| 254 | .modify(|reg| reg.set_res(self.resolution.res())); | 369 | .modify(|reg| reg.set_res(self.resolution.res())); |
| 370 | #[cfg(rcc_g0)] | ||
| 371 | T::regs() | ||
| 372 | .cfgr1() | ||
| 373 | .modify(|reg| reg.set_res(self.resolution.res())); | ||
| 255 | 374 | ||
| 256 | // Configure channel | 375 | // Configure channel |
| 257 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | 376 | Self::set_channel_sample_time(pin.channel(), self.sample_time); |
| 258 | 377 | ||
| 259 | // Select channel | 378 | // Select channel |
| 379 | #[cfg(not(rcc_g0))] | ||
| 260 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); | 380 | T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); |
| 381 | #[cfg(rcc_g0)] | ||
| 382 | T::regs() | ||
| 383 | .chselr() | ||
| 384 | .write(|reg| reg.set_chsel(pin.channel() as u32)); | ||
| 261 | 385 | ||
| 262 | // Start conversion | 386 | // Some models are affected by an erratum: |
| 263 | T::regs().isr().modify(|reg| { | 387 | // If we perform conversions slower than 1 kHz, the first read ADC value can be |
| 264 | reg.set_eos(true); | 388 | // corrupted, so we discard it and measure again. |
| 265 | reg.set_eoc(true); | 389 | // |
| 266 | }); | 390 | // STM32L471xx: Section 2.7.3 |
| 267 | T::regs().cr().modify(|reg| { | 391 | // STM32G4: Section 2.7.3 |
| 268 | reg.set_adstart(true); | 392 | #[cfg(any(rcc_l4, rcc_g4))] |
| 269 | }); | 393 | let _ = self.convert(); |
| 270 | |||
| 271 | while !T::regs().isr().read().eos() { | ||
| 272 | // spin | ||
| 273 | } | ||
| 274 | |||
| 275 | // Read ADC value first time and discard it, as per errata sheet. | ||
| 276 | // The errata states that if we do conversions slower than 1 kHz, the | ||
| 277 | // first read ADC value can be corrupted, so we discard it and measure again. | ||
| 278 | |||
| 279 | let _ = T::regs().dr().read(); | ||
| 280 | |||
| 281 | T::regs().isr().modify(|reg| { | ||
| 282 | reg.set_eos(true); | ||
| 283 | reg.set_eoc(true); | ||
| 284 | }); | ||
| 285 | T::regs().cr().modify(|reg| { | ||
| 286 | reg.set_adstart(true); | ||
| 287 | }); | ||
| 288 | |||
| 289 | while !T::regs().isr().read().eos() { | ||
| 290 | // spin | ||
| 291 | } | ||
| 292 | 394 | ||
| 293 | let val = T::regs().dr().read().0 as u16; | 395 | let val = self.convert(); |
| 294 | 396 | ||
| 295 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 397 | T::regs().cr().modify(|reg| reg.set_addis(true)); |
| 296 | 398 | ||
| @@ -298,6 +400,14 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 298 | } | 400 | } |
| 299 | } | 401 | } |
| 300 | 402 | ||
| 403 | #[cfg(rcc_g0)] | ||
| 404 | unsafe fn set_channel_sample_time(_ch: u8, sample_time: SampleTime) { | ||
| 405 | T::regs() | ||
| 406 | .smpr() | ||
| 407 | .modify(|reg| reg.set_smp1(sample_time.sample_time())); | ||
| 408 | } | ||
| 409 | |||
| 410 | #[cfg(not(rcc_g0))] | ||
| 301 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 411 | unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 302 | if ch <= 9 { | 412 | if ch <= 9 { |
| 303 | T::regs() | 413 | T::regs() |
diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs index f46145b8d..55a881d89 100644 --- a/embassy-stm32/src/dac/v2.rs +++ b/embassy-stm32/src/dac/v2.rs | |||
| @@ -5,6 +5,17 @@ use core::marker::PhantomData; | |||
| 5 | use embassy::util::Unborrow; | 5 | use embassy::util::Unborrow; |
| 6 | use embassy_hal_common::unborrow; | 6 | use embassy_hal_common::unborrow; |
| 7 | 7 | ||
| 8 | /// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent DAC clock | ||
| 9 | /// configuration. | ||
| 10 | unsafe fn enable() { | ||
| 11 | #[cfg(rcc_h7)] | ||
| 12 | crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); | ||
| 13 | #[cfg(rcc_g0)] | ||
| 14 | crate::pac::RCC.apbenr1().modify(|w| w.set_dac1en(true)); | ||
| 15 | #[cfg(rcc_l4)] | ||
| 16 | crate::pac::RCC.apb1enr1().modify(|w| w.set_dac1en(true)); | ||
| 17 | } | ||
| 18 | |||
| 8 | #[derive(Debug)] | 19 | #[derive(Debug)] |
| 9 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 10 | pub enum Error { | 21 | pub enum Error { |
| @@ -91,6 +102,10 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 91 | ) -> Self { | 102 | ) -> Self { |
| 92 | unborrow!(ch1, ch2); | 103 | unborrow!(ch1, ch2); |
| 93 | 104 | ||
| 105 | unsafe { | ||
| 106 | enable(); | ||
| 107 | } | ||
| 108 | |||
| 94 | let ch1 = ch1.degrade_optional(); | 109 | let ch1 = ch1.degrade_optional(); |
| 95 | if ch1.is_some() { | 110 | if ch1.is_some() { |
| 96 | unsafe { | 111 | unsafe { |
diff --git a/embassy-stm32/src/rcc/g0/mod.rs b/embassy-stm32/src/rcc/g0/mod.rs index 863db709d..c0b5b14e3 100644 --- a/embassy-stm32/src/rcc/g0/mod.rs +++ b/embassy-stm32/src/rcc/g0/mod.rs | |||
| @@ -18,10 +18,37 @@ pub const LSI_FREQ: u32 = 32_000; | |||
| 18 | #[derive(Clone, Copy)] | 18 | #[derive(Clone, Copy)] |
| 19 | pub enum ClockSrc { | 19 | pub enum ClockSrc { |
| 20 | HSE(Hertz), | 20 | HSE(Hertz), |
| 21 | HSI16, | 21 | HSI16(HSI16Prescaler), |
| 22 | LSI, | 22 | LSI, |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | #[derive(Clone, Copy)] | ||
| 26 | pub enum HSI16Prescaler { | ||
| 27 | NotDivided, | ||
| 28 | Div2, | ||
| 29 | Div4, | ||
| 30 | Div8, | ||
| 31 | Div16, | ||
| 32 | Div32, | ||
| 33 | Div64, | ||
| 34 | Div128, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl Into<u8> for HSI16Prescaler { | ||
| 38 | fn into(self) -> u8 { | ||
| 39 | match self { | ||
| 40 | HSI16Prescaler::NotDivided => 0x00, | ||
| 41 | HSI16Prescaler::Div2 => 0x01, | ||
| 42 | HSI16Prescaler::Div4 => 0x02, | ||
| 43 | HSI16Prescaler::Div8 => 0x03, | ||
| 44 | HSI16Prescaler::Div16 => 0x04, | ||
| 45 | HSI16Prescaler::Div32 => 0x05, | ||
| 46 | HSI16Prescaler::Div64 => 0x06, | ||
| 47 | HSI16Prescaler::Div128 => 0x07, | ||
| 48 | } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 25 | impl Into<u8> for APBPrescaler { | 52 | impl Into<u8> for APBPrescaler { |
| 26 | fn into(self) -> u8 { | 53 | fn into(self) -> u8 { |
| 27 | match self { | 54 | match self { |
| @@ -55,15 +82,17 @@ pub struct Config { | |||
| 55 | mux: ClockSrc, | 82 | mux: ClockSrc, |
| 56 | ahb_pre: AHBPrescaler, | 83 | ahb_pre: AHBPrescaler, |
| 57 | apb_pre: APBPrescaler, | 84 | apb_pre: APBPrescaler, |
| 85 | low_power_run: bool, | ||
| 58 | } | 86 | } |
| 59 | 87 | ||
| 60 | impl Default for Config { | 88 | impl Default for Config { |
| 61 | #[inline] | 89 | #[inline] |
| 62 | fn default() -> Config { | 90 | fn default() -> Config { |
| 63 | Config { | 91 | Config { |
| 64 | mux: ClockSrc::HSI16, | 92 | mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), |
| 65 | ahb_pre: AHBPrescaler::NotDivided, | 93 | ahb_pre: AHBPrescaler::NotDivided, |
| 66 | apb_pre: APBPrescaler::NotDivided, | 94 | apb_pre: APBPrescaler::NotDivided, |
| 95 | low_power_run: false, | ||
| 67 | } | 96 | } |
| 68 | } | 97 | } |
| 69 | } | 98 | } |
| @@ -86,6 +115,12 @@ impl Config { | |||
| 86 | self.apb_pre = pre; | 115 | self.apb_pre = pre; |
| 87 | self | 116 | self |
| 88 | } | 117 | } |
| 118 | |||
| 119 | #[inline] | ||
| 120 | pub fn low_power_run(mut self, on: bool) -> Self { | ||
| 121 | self.low_power_run = on; | ||
| 122 | self | ||
| 123 | } | ||
| 89 | } | 124 | } |
| 90 | 125 | ||
| 91 | /// RCC peripheral | 126 | /// RCC peripheral |
| @@ -119,14 +154,18 @@ impl RccExt for RCC { | |||
| 119 | fn freeze(self, cfgr: Config) -> Clocks { | 154 | fn freeze(self, cfgr: Config) -> Clocks { |
| 120 | let rcc = pac::RCC; | 155 | let rcc = pac::RCC; |
| 121 | let (sys_clk, sw) = match cfgr.mux { | 156 | let (sys_clk, sw) = match cfgr.mux { |
| 122 | ClockSrc::HSI16 => { | 157 | ClockSrc::HSI16(div) => { |
| 123 | // Enable HSI16 | 158 | // Enable HSI16 |
| 159 | let div: u8 = div.into(); | ||
| 124 | unsafe { | 160 | unsafe { |
| 125 | rcc.cr().write(|w| w.set_hsion(true)); | 161 | rcc.cr().write(|w| { |
| 162 | w.set_hsidiv(div); | ||
| 163 | w.set_hsion(true) | ||
| 164 | }); | ||
| 126 | while !rcc.cr().read().hsirdy() {} | 165 | while !rcc.cr().read().hsirdy() {} |
| 127 | } | 166 | } |
| 128 | 167 | ||
| 129 | (HSI_FREQ, 0x00) | 168 | (HSI_FREQ >> div, 0x00) |
| 130 | } | 169 | } |
| 131 | ClockSrc::HSE(freq) => { | 170 | ClockSrc::HSE(freq) => { |
| 132 | // Enable HSE | 171 | // Enable HSE |
| @@ -174,6 +213,14 @@ impl RccExt for RCC { | |||
| 174 | } | 213 | } |
| 175 | }; | 214 | }; |
| 176 | 215 | ||
| 216 | let pwr = pac::PWR; | ||
| 217 | if cfgr.low_power_run { | ||
| 218 | assert!(sys_clk.hz() <= 2_000_000.hz()); | ||
| 219 | unsafe { | ||
| 220 | pwr.cr1().modify(|w| w.set_lpr(true)); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 177 | Clocks { | 224 | Clocks { |
| 178 | sys: sys_clk.hz(), | 225 | sys: sys_clk.hz(), |
| 179 | ahb: ahb_freq.hz(), | 226 | ahb: ahb_freq.hz(), |
