diff options
| author | Thales Fragoso <[email protected]> | 2021-05-20 22:08:07 -0300 |
|---|---|---|
| committer | Thales Fragoso <[email protected]> | 2021-05-21 20:16:25 -0300 |
| commit | 7f65f491e528c64e4e72286624d076331020d1d7 (patch) | |
| tree | 853682979b4181e6bc159eebc9b6c6083c06b75f | |
| parent | 82ca5b495e67685af1bd5063d125476269e6ce18 (diff) | |
Finish initial H7 RCC support
| -rw-r--r-- | embassy-stm32/src/lib.rs | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/pwr/h7.rs | 71 | ||||
| -rw-r--r-- | embassy-stm32/src/pwr/mod.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/mod.rs | 380 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/pll.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/sdmmc/v2.rs | 1 |
6 files changed, 424 insertions, 37 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 8d7b67b74..2fc07cd5e 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -13,7 +13,8 @@ pub mod fmt; | |||
| 13 | pub mod dma; | 13 | pub mod dma; |
| 14 | pub mod exti; | 14 | pub mod exti; |
| 15 | pub mod gpio; | 15 | pub mod gpio; |
| 16 | mod rcc; | 16 | pub mod pwr; |
| 17 | pub mod rcc; | ||
| 17 | #[cfg(feature = "_rng")] | 18 | #[cfg(feature = "_rng")] |
| 18 | pub mod rng; | 19 | pub mod rng; |
| 19 | #[cfg(feature = "_sdmmc")] | 20 | #[cfg(feature = "_sdmmc")] |
diff --git a/embassy-stm32/src/pwr/h7.rs b/embassy-stm32/src/pwr/h7.rs new file mode 100644 index 000000000..939e93eb2 --- /dev/null +++ b/embassy-stm32/src/pwr/h7.rs | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | use crate::pac::peripherals; | ||
| 2 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 3 | |||
| 4 | /// Voltage Scale | ||
| 5 | /// | ||
| 6 | /// Represents the voltage range feeding the CPU core. The maximum core | ||
| 7 | /// clock frequency depends on this value. | ||
| 8 | #[derive(Copy, Clone, PartialEq)] | ||
| 9 | pub enum VoltageScale { | ||
| 10 | /// VOS 0 range VCORE 1.26V - 1.40V | ||
| 11 | Scale0, | ||
| 12 | /// VOS 1 range VCORE 1.15V - 1.26V | ||
| 13 | Scale1, | ||
| 14 | /// VOS 2 range VCORE 1.05V - 1.15V | ||
| 15 | Scale2, | ||
| 16 | /// VOS 3 range VCORE 0.95V - 1.05V | ||
| 17 | Scale3, | ||
| 18 | } | ||
| 19 | |||
| 20 | /// Power Configuration | ||
| 21 | /// | ||
| 22 | /// Generated when the PWR peripheral is frozen. The existence of this | ||
| 23 | /// value indicates that the voltage scaling configuration can no | ||
| 24 | /// longer be changed. | ||
| 25 | pub struct Power { | ||
| 26 | pub(crate) vos: VoltageScale, | ||
| 27 | } | ||
| 28 | |||
| 29 | impl Power { | ||
| 30 | pub fn new(_peri: peripherals::PWR, enable_overdrive: bool) -> Self { | ||
| 31 | use crate::pac::rcc::vals::Apb4enrSyscfgen; | ||
| 32 | |||
| 33 | // NOTE(unsafe) we have the PWR singleton | ||
| 34 | unsafe { | ||
| 35 | // NB. The lower bytes of CR3 can only be written once after | ||
| 36 | // POR, and must be written with a valid combination. Refer to | ||
| 37 | // RM0433 Rev 7 6.8.4. This is partially enforced by dropping | ||
| 38 | // `self` at the end of this method, but of course we cannot | ||
| 39 | // know what happened between the previous POR and here. | ||
| 40 | PWR.cr3().modify(|w| { | ||
| 41 | w.set_scuen(true); | ||
| 42 | w.set_ldoen(true); | ||
| 43 | w.set_bypass(false); | ||
| 44 | }); | ||
| 45 | // Validate the supply configuration. If you are stuck here, it is | ||
| 46 | // because the voltages on your board do not match those specified | ||
| 47 | // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset | ||
| 48 | // VOS = Scale 3, so check that the voltage on the VCAP pins = | ||
| 49 | // 1.0V. | ||
| 50 | while !PWR.csr1().read().actvosrdy() {} | ||
| 51 | |||
| 52 | // Go to Scale 1 | ||
| 53 | PWR.d3cr().modify(|w| w.set_vos(0b11)); | ||
| 54 | while !PWR.d3cr().read().vosrdy() {} | ||
| 55 | |||
| 56 | let vos = if !enable_overdrive { | ||
| 57 | VoltageScale::Scale1 | ||
| 58 | } else { | ||
| 59 | critical_section::with(|_| { | ||
| 60 | RCC.apb4enr() | ||
| 61 | .modify(|w| w.set_syscfgen(Apb4enrSyscfgen::ENABLED)); | ||
| 62 | |||
| 63 | SYSCFG.pwrcr().modify(|w| w.set_oden(1)); | ||
| 64 | }); | ||
| 65 | while !PWR.d3cr().read().vosrdy() {} | ||
| 66 | VoltageScale::Scale0 | ||
| 67 | }; | ||
| 68 | Self { vos } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs new file mode 100644 index 000000000..0bf62ef7c --- /dev/null +++ b/embassy-stm32/src/pwr/mod.rs | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | #[cfg(feature = "_stm32h7")] | ||
| 2 | mod h7; | ||
| 3 | #[cfg(feature = "_stm32h7")] | ||
| 4 | pub use h7::*; | ||
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs index b27eff747..8112ae999 100644 --- a/embassy-stm32/src/rcc/h7/mod.rs +++ b/embassy-stm32/src/rcc/h7/mod.rs | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use core::marker::PhantomData; |
| 2 | 2 | ||
| 3 | use embassy::util::Unborrow; | 3 | use embassy::util::Unborrow; |
| 4 | use embassy_extras::unborrow; | ||
| 5 | 4 | ||
| 6 | use crate::fmt::assert; | 5 | use crate::fmt::{assert, panic}; |
| 7 | use crate::pac::peripherals; | 6 | use crate::pac::peripherals; |
| 8 | use crate::pac::RCC; | 7 | use crate::pac::rcc::vals::Timpre; |
| 8 | use crate::pac::{RCC, SYSCFG}; | ||
| 9 | use crate::pwr::{Power, VoltageScale}; | ||
| 9 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 10 | 11 | ||
| 11 | mod pll; | 12 | mod pll; |
| @@ -17,6 +18,39 @@ const CSI: Hertz = Hertz(4_000_000); | |||
| 17 | const HSI48: Hertz = Hertz(48_000_000); | 18 | const HSI48: Hertz = Hertz(48_000_000); |
| 18 | const LSI: Hertz = Hertz(32_000); | 19 | const LSI: Hertz = Hertz(32_000); |
| 19 | 20 | ||
| 21 | /// Core clock frequencies | ||
| 22 | #[derive(Clone, Copy)] | ||
| 23 | pub struct CoreClocks { | ||
| 24 | pub hclk: Hertz, | ||
| 25 | pub pclk1: Hertz, | ||
| 26 | pub pclk2: Hertz, | ||
| 27 | pub pclk3: Hertz, | ||
| 28 | pub pclk4: Hertz, | ||
| 29 | pub ppre1: u8, | ||
| 30 | pub ppre2: u8, | ||
| 31 | pub ppre3: u8, | ||
| 32 | pub ppre4: u8, | ||
| 33 | pub csi_ck: Option<Hertz>, | ||
| 34 | pub hsi_ck: Option<Hertz>, | ||
| 35 | pub hsi48_ck: Option<Hertz>, | ||
| 36 | pub lsi_ck: Option<Hertz>, | ||
| 37 | pub per_ck: Option<Hertz>, | ||
| 38 | pub hse_ck: Option<Hertz>, | ||
| 39 | pub pll1_p_ck: Option<Hertz>, | ||
| 40 | pub pll1_q_ck: Option<Hertz>, | ||
| 41 | pub pll1_r_ck: Option<Hertz>, | ||
| 42 | pub pll2_p_ck: Option<Hertz>, | ||
| 43 | pub pll2_q_ck: Option<Hertz>, | ||
| 44 | pub pll2_r_ck: Option<Hertz>, | ||
| 45 | pub pll3_p_ck: Option<Hertz>, | ||
| 46 | pub pll3_q_ck: Option<Hertz>, | ||
| 47 | pub pll3_r_ck: Option<Hertz>, | ||
| 48 | pub timx_ker_ck: Option<Hertz>, | ||
| 49 | pub timy_ker_ck: Option<Hertz>, | ||
| 50 | pub sys_ck: Hertz, | ||
| 51 | pub c_ck: Hertz, | ||
| 52 | } | ||
| 53 | |||
| 20 | /// Configuration of the core clocks | 54 | /// Configuration of the core clocks |
| 21 | #[non_exhaustive] | 55 | #[non_exhaustive] |
| 22 | #[derive(Default)] | 56 | #[derive(Default)] |
| @@ -34,29 +68,6 @@ pub struct Config { | |||
| 34 | pub pll1: PllConfig, | 68 | pub pll1: PllConfig, |
| 35 | pub pll2: PllConfig, | 69 | pub pll2: PllConfig, |
| 36 | pub pll3: PllConfig, | 70 | pub pll3: PllConfig, |
| 37 | pub vos: VoltageScale, | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Voltage Scale | ||
| 41 | /// | ||
| 42 | /// Represents the voltage range feeding the CPU core. The maximum core | ||
| 43 | /// clock frequency depends on this value. | ||
| 44 | #[derive(Copy, Clone, PartialEq)] | ||
| 45 | pub enum VoltageScale { | ||
| 46 | /// VOS 0 range VCORE 1.26V - 1.40V | ||
| 47 | Scale0, | ||
| 48 | /// VOS 1 range VCORE 1.15V - 1.26V | ||
| 49 | Scale1, | ||
| 50 | /// VOS 2 range VCORE 1.05V - 1.15V | ||
| 51 | Scale2, | ||
| 52 | /// VOS 3 range VCORE 0.95V - 1.05V | ||
| 53 | Scale3, | ||
| 54 | } | ||
| 55 | |||
| 56 | impl Default for VoltageScale { | ||
| 57 | fn default() -> Self { | ||
| 58 | Self::Scale1 | ||
| 59 | } | ||
| 60 | } | 71 | } |
| 61 | 72 | ||
| 62 | pub struct Rcc<'d> { | 73 | pub struct Rcc<'d> { |
| @@ -91,12 +102,18 @@ impl<'d> Rcc<'d> { | |||
| 91 | /// function may also panic if a clock specification can be | 102 | /// function may also panic if a clock specification can be |
| 92 | /// achieved, but the mechanism for doing so is not yet | 103 | /// achieved, but the mechanism for doing so is not yet |
| 93 | /// implemented here. | 104 | /// implemented here. |
| 94 | pub fn freeze(mut self) { | 105 | pub fn freeze(mut self, pwr: &Power) -> CoreClocks { |
| 95 | use crate::pac::rcc::vals::{Ckpersel, Hpre, Hsidiv, Hsion, Lsion, Timpre}; | 106 | use crate::pac::rcc::vals::{ |
| 107 | Apb4enrSyscfgen, Ckpersel, D1ppre, D2ppre1, D3ppre, Hpre, Hsebyp, Hsidiv, Hsion, Lsion, | ||
| 108 | Pllsrc, Sw, | ||
| 109 | }; | ||
| 96 | 110 | ||
| 97 | let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks | 111 | let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks |
| 98 | let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk); | 112 | let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk); |
| 99 | 113 | ||
| 114 | // Configure traceclk from PLL if needed | ||
| 115 | self.traceclk_setup(sys_use_pll1_p); | ||
| 116 | |||
| 100 | // NOTE(unsafe) We have exclusive access to the RCC | 117 | // NOTE(unsafe) We have exclusive access to the RCC |
| 101 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = | 118 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = |
| 102 | unsafe { pll_setup(srcclk.0, &self.config.pll1, 0) }; | 119 | unsafe { pll_setup(srcclk.0, &self.config.pll1, 0) }; |
| @@ -137,13 +154,10 @@ impl<'d> Rcc<'d> { | |||
| 137 | let d1cpre_div = 1; | 154 | let d1cpre_div = 1; |
| 138 | let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; | 155 | let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; |
| 139 | 156 | ||
| 140 | // Timer prescaler selection | ||
| 141 | let timpre = Timpre::DEFAULTX2; | ||
| 142 | |||
| 143 | // Refer to part datasheet "General operating conditions" | 157 | // Refer to part datasheet "General operating conditions" |
| 144 | // table for (rev V). We do not assert checks for earlier | 158 | // table for (rev V). We do not assert checks for earlier |
| 145 | // revisions which may have lower limits. | 159 | // revisions which may have lower limits. |
| 146 | let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match self.config.vos { | 160 | let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr.vos { |
| 147 | VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), | 161 | VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), |
| 148 | VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), | 162 | VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), |
| 149 | VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), | 163 | VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), |
| @@ -160,7 +174,7 @@ impl<'d> Rcc<'d> { | |||
| 160 | 174 | ||
| 161 | // Estimate divisor | 175 | // Estimate divisor |
| 162 | let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { | 176 | let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { |
| 163 | 0 => unreachable!(), | 177 | 0 => panic!(), |
| 164 | 1 => (Hpre::DIV1, 1), | 178 | 1 => (Hpre::DIV1, 1), |
| 165 | 2 => (Hpre::DIV2, 2), | 179 | 2 => (Hpre::DIV2, 2), |
| 166 | 3..=5 => (Hpre::DIV4, 4), | 180 | 3..=5 => (Hpre::DIV4, 4), |
| @@ -175,8 +189,246 @@ impl<'d> Rcc<'d> { | |||
| 175 | let rcc_hclk = sys_d1cpre_ck / hpre_div; | 189 | let rcc_hclk = sys_d1cpre_ck / hpre_div; |
| 176 | assert!(rcc_hclk <= rcc_hclk_max); | 190 | assert!(rcc_hclk <= rcc_hclk_max); |
| 177 | let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 | 191 | let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 |
| 192 | // Timer prescaler selection | ||
| 193 | let timpre = Timpre::DEFAULTX2; | ||
| 194 | |||
| 195 | let requested_pclk1 = self | ||
| 196 | .config | ||
| 197 | .pclk1 | ||
| 198 | .map(|v| v.0) | ||
| 199 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 200 | let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = | ||
| 201 | Self::ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); | ||
| 202 | |||
| 203 | let requested_pclk2 = self | ||
| 204 | .config | ||
| 205 | .pclk2 | ||
| 206 | .map(|v| v.0) | ||
| 207 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 208 | let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = | ||
| 209 | Self::ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); | ||
| 210 | |||
| 211 | let requested_pclk3 = self | ||
| 212 | .config | ||
| 213 | .pclk3 | ||
| 214 | .map(|v| v.0) | ||
| 215 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 216 | let (rcc_pclk3, ppre3_bits, ppre3, _) = | ||
| 217 | Self::ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); | ||
| 218 | |||
| 219 | let requested_pclk4 = self | ||
| 220 | .config | ||
| 221 | .pclk4 | ||
| 222 | .map(|v| v.0) | ||
| 223 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 224 | let (rcc_pclk4, ppre4_bits, ppre4, _) = | ||
| 225 | Self::ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); | ||
| 226 | |||
| 227 | Self::flash_setup(rcc_aclk, pwr.vos); | ||
| 228 | |||
| 229 | // Start switching clocks ------------------- | ||
| 230 | // NOTE(unsafe) We have the RCC singleton | ||
| 231 | unsafe { | ||
| 232 | // Ensure CSI is on and stable | ||
| 233 | RCC.cr().modify(|w| w.set_csion(Hsion::ON)); | ||
| 234 | while !RCC.cr().read().csirdy() {} | ||
| 235 | |||
| 236 | // Ensure HSI48 is on and stable | ||
| 237 | RCC.cr().modify(|w| w.set_hsi48on(Hsion::ON)); | ||
| 238 | while RCC.cr().read().hsi48on() == Hsion::OFF {} | ||
| 239 | |||
| 240 | // XXX: support MCO ? | ||
| 241 | |||
| 242 | let hse_ck = match self.config.hse { | ||
| 243 | Some(hse) => { | ||
| 244 | // Ensure HSE is on and stable | ||
| 245 | RCC.cr().modify(|w| { | ||
| 246 | w.set_hseon(Hsion::ON); | ||
| 247 | w.set_hsebyp(if self.config.bypass_hse { | ||
| 248 | Hsebyp::BYPASSED | ||
| 249 | } else { | ||
| 250 | Hsebyp::NOTBYPASSED | ||
| 251 | }); | ||
| 252 | }); | ||
| 253 | while !RCC.cr().read().hserdy() {} | ||
| 254 | Some(hse) | ||
| 255 | } | ||
| 256 | None => None, | ||
| 257 | }; | ||
| 258 | |||
| 259 | let pllsrc = if self.config.hse.is_some() { | ||
| 260 | Pllsrc::HSE | ||
| 261 | } else { | ||
| 262 | Pllsrc::HSI | ||
| 263 | }; | ||
| 264 | RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); | ||
| 265 | |||
| 266 | if pll1_p_ck.is_some() { | ||
| 267 | RCC.cr().modify(|w| w.set_pll1on(Hsion::ON)); | ||
| 268 | while !RCC.cr().read().pll1rdy() {} | ||
| 269 | } | ||
| 270 | |||
| 271 | if pll2_p_ck.is_some() { | ||
| 272 | RCC.cr().modify(|w| w.set_pll2on(Hsion::ON)); | ||
| 273 | while !RCC.cr().read().pll2rdy() {} | ||
| 274 | } | ||
| 275 | |||
| 276 | if pll3_p_ck.is_some() { | ||
| 277 | RCC.cr().modify(|w| w.set_pll3on(Hsion::ON)); | ||
| 278 | while !RCC.cr().read().pll3rdy() {} | ||
| 279 | } | ||
| 178 | 280 | ||
| 179 | todo!() | 281 | // Core Prescaler / AHB Prescaler / APB3 Prescaler |
| 282 | RCC.d1cfgr().modify(|w| { | ||
| 283 | w.set_d1cpre(Hpre(d1cpre_bits)); | ||
| 284 | w.set_d1ppre(D1ppre(ppre3_bits)); | ||
| 285 | w.set_hpre(hpre_bits) | ||
| 286 | }); | ||
| 287 | // Ensure core prescaler value is valid before future lower | ||
| 288 | // core voltage | ||
| 289 | while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} | ||
| 290 | |||
| 291 | // APB1 / APB2 Prescaler | ||
| 292 | RCC.d2cfgr().modify(|w| { | ||
| 293 | w.set_d2ppre1(D2ppre1(ppre1_bits)); | ||
| 294 | w.set_d2ppre2(D2ppre1(ppre2_bits)); | ||
| 295 | }); | ||
| 296 | |||
| 297 | // APB4 Prescaler | ||
| 298 | RCC.d3cfgr().modify(|w| w.set_d3ppre(D3ppre(ppre4_bits))); | ||
| 299 | |||
| 300 | // Peripheral Clock (per_ck) | ||
| 301 | RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); | ||
| 302 | |||
| 303 | // Set timer clocks prescaler setting | ||
| 304 | RCC.cfgr().modify(|w| w.set_timpre(timpre)); | ||
| 305 | |||
| 306 | // Select system clock source | ||
| 307 | let sw = match (sys_use_pll1_p, self.config.hse.is_some()) { | ||
| 308 | (true, _) => Sw::PLL1, | ||
| 309 | (false, true) => Sw::HSE, | ||
| 310 | _ => Sw::HSI, | ||
| 311 | }; | ||
| 312 | RCC.cfgr().modify(|w| w.set_sw(sw)); | ||
| 313 | while RCC.cfgr().read().sws() != sw.0 {} | ||
| 314 | |||
| 315 | // IO compensation cell - Requires CSI clock and SYSCFG | ||
| 316 | assert!(RCC.cr().read().csirdy()); | ||
| 317 | RCC.apb4enr() | ||
| 318 | .modify(|w| w.set_syscfgen(Apb4enrSyscfgen::ENABLED)); | ||
| 319 | |||
| 320 | // Enable the compensation cell, using back-bias voltage code | ||
| 321 | // provide by the cell. | ||
| 322 | critical_section::with(|_| { | ||
| 323 | SYSCFG.cccsr().modify(|w| { | ||
| 324 | w.set_en(true); | ||
| 325 | w.set_cs(false); | ||
| 326 | w.set_hslv(false); | ||
| 327 | }) | ||
| 328 | }); | ||
| 329 | while !SYSCFG.cccsr().read().ready() {} | ||
| 330 | |||
| 331 | CoreClocks { | ||
| 332 | hclk: Hertz(rcc_hclk), | ||
| 333 | pclk1: Hertz(rcc_pclk1), | ||
| 334 | pclk2: Hertz(rcc_pclk2), | ||
| 335 | pclk3: Hertz(rcc_pclk3), | ||
| 336 | pclk4: Hertz(rcc_pclk4), | ||
| 337 | ppre1, | ||
| 338 | ppre2, | ||
| 339 | ppre3, | ||
| 340 | ppre4, | ||
| 341 | csi_ck: Some(CSI), | ||
| 342 | hsi_ck: Some(HSI), | ||
| 343 | hsi48_ck: Some(HSI48), | ||
| 344 | lsi_ck: Some(LSI), | ||
| 345 | per_ck: Some(per_ck), | ||
| 346 | hse_ck, | ||
| 347 | pll1_p_ck: pll1_p_ck.map(Hertz), | ||
| 348 | pll1_q_ck: pll1_q_ck.map(Hertz), | ||
| 349 | pll1_r_ck: pll1_r_ck.map(Hertz), | ||
| 350 | pll2_p_ck: pll2_p_ck.map(Hertz), | ||
| 351 | pll2_q_ck: pll2_q_ck.map(Hertz), | ||
| 352 | pll2_r_ck: pll2_r_ck.map(Hertz), | ||
| 353 | pll3_p_ck: pll3_p_ck.map(Hertz), | ||
| 354 | pll3_q_ck: pll3_q_ck.map(Hertz), | ||
| 355 | pll3_r_ck: pll3_r_ck.map(Hertz), | ||
| 356 | timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), | ||
| 357 | timy_ker_ck: rcc_timery_ker_ck.map(Hertz), | ||
| 358 | sys_ck, | ||
| 359 | c_ck: Hertz(sys_d1cpre_ck), | ||
| 360 | } | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | /// Enables debugging during WFI/WFE | ||
| 365 | /// | ||
| 366 | /// Set `enable_dma1` to true if you do not have at least one bus master (other than the CPU) | ||
| 367 | /// enable during WFI/WFE | ||
| 368 | pub fn enable_debug_wfe(&mut self, enable_dma1: bool) { | ||
| 369 | use crate::pac::rcc::vals::Ahb1enrDma1en; | ||
| 370 | |||
| 371 | // NOTE(unsafe) We have exclusive access to the RCC | ||
| 372 | unsafe { | ||
| 373 | if enable_dma1 { | ||
| 374 | RCC.ahb1enr() | ||
| 375 | .modify(|w| w.set_dma1en(Ahb1enrDma1en::ENABLED)); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | /// Setup traceclk | ||
| 381 | /// Returns a pll1_r_ck | ||
| 382 | fn traceclk_setup(&mut self, sys_use_pll1_p: bool) { | ||
| 383 | let pll1_r_ck = match (sys_use_pll1_p, self.config.pll1.r_ck) { | ||
| 384 | // pll1_p_ck selected as system clock but pll1_r_ck not | ||
| 385 | // set. The traceclk mux is synchronous with the system | ||
| 386 | // clock mux, but has pll1_r_ck as an input. In order to | ||
| 387 | // keep traceclk running, we force a pll1_r_ck. | ||
| 388 | (true, None) => Some(Hertz(self.config.pll1.p_ck.unwrap().0 / 2)), | ||
| 389 | |||
| 390 | // Either pll1 not selected as system clock, free choice | ||
| 391 | // of pll1_r_ck. Or pll1 is selected, assume user has set | ||
| 392 | // a suitable pll1_r_ck frequency. | ||
| 393 | _ => self.config.pll1.r_ck, | ||
| 394 | }; | ||
| 395 | self.config.pll1.r_ck = pll1_r_ck; | ||
| 396 | } | ||
| 397 | |||
| 398 | /// Divider calculator for pclk 1 - 4 | ||
| 399 | /// | ||
| 400 | /// Returns real pclk, bits, ppre and the timer kernel clock | ||
| 401 | fn ppre_calculate( | ||
| 402 | requested_pclk: u32, | ||
| 403 | hclk: u32, | ||
| 404 | max_pclk: u32, | ||
| 405 | tim_pre: Option<Timpre>, | ||
| 406 | ) -> (u32, u8, u8, Option<u32>) { | ||
| 407 | let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { | ||
| 408 | 0 => panic!(), | ||
| 409 | 1 => (0b000, 1), | ||
| 410 | 2 => (0b100, 2), | ||
| 411 | 3..=5 => (0b101, 4), | ||
| 412 | 6..=11 => (0b110, 8), | ||
| 413 | _ => (0b111, 16), | ||
| 414 | }; | ||
| 415 | let real_pclk = hclk / u32::from(ppre); | ||
| 416 | assert!(real_pclk < max_pclk); | ||
| 417 | |||
| 418 | let tim_ker_clk = if let Some(tim_pre) = tim_pre { | ||
| 419 | let clk = match (bits, tim_pre) { | ||
| 420 | (0b101, Timpre::DEFAULTX2) => hclk / 2, | ||
| 421 | (0b110, Timpre::DEFAULTX4) => hclk / 2, | ||
| 422 | (0b110, Timpre::DEFAULTX2) => hclk / 4, | ||
| 423 | (0b111, Timpre::DEFAULTX4) => hclk / 4, | ||
| 424 | (0b111, Timpre::DEFAULTX2) => hclk / 8, | ||
| 425 | _ => hclk, | ||
| 426 | }; | ||
| 427 | Some(clk) | ||
| 428 | } else { | ||
| 429 | None | ||
| 430 | }; | ||
| 431 | (real_pclk, bits, ppre, tim_ker_clk) | ||
| 180 | } | 432 | } |
| 181 | 433 | ||
| 182 | /// Setup sys_ck | 434 | /// Setup sys_ck |
| @@ -209,4 +461,64 @@ impl<'d> Rcc<'d> { | |||
| 209 | (sys_ck, false) | 461 | (sys_ck, false) |
| 210 | } | 462 | } |
| 211 | } | 463 | } |
| 464 | |||
| 465 | fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | ||
| 466 | use crate::pac::FLASH; | ||
| 467 | |||
| 468 | // ACLK in MHz, round down and subtract 1 from integers. eg. | ||
| 469 | // 61_999_999 -> 61MHz | ||
| 470 | // 62_000_000 -> 61MHz | ||
| 471 | // 62_000_001 -> 62MHz | ||
| 472 | let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; | ||
| 473 | |||
| 474 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait | ||
| 475 | // states and programming delay | ||
| 476 | let (wait_states, progr_delay) = match vos { | ||
| 477 | // VOS 0 range VCORE 1.26V - 1.40V | ||
| 478 | VoltageScale::Scale0 => match rcc_aclk_mhz { | ||
| 479 | 0..=69 => (0, 0), | ||
| 480 | 70..=139 => (1, 1), | ||
| 481 | 140..=184 => (2, 1), | ||
| 482 | 185..=209 => (2, 2), | ||
| 483 | 210..=224 => (3, 2), | ||
| 484 | 225..=239 => (4, 2), | ||
| 485 | _ => (7, 3), | ||
| 486 | }, | ||
| 487 | // VOS 1 range VCORE 1.15V - 1.26V | ||
| 488 | VoltageScale::Scale1 => match rcc_aclk_mhz { | ||
| 489 | 0..=69 => (0, 0), | ||
| 490 | 70..=139 => (1, 1), | ||
| 491 | 140..=184 => (2, 1), | ||
| 492 | 185..=209 => (2, 2), | ||
| 493 | 210..=224 => (3, 2), | ||
| 494 | _ => (7, 3), | ||
| 495 | }, | ||
| 496 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 497 | VoltageScale::Scale2 => match rcc_aclk_mhz { | ||
| 498 | 0..=54 => (0, 0), | ||
| 499 | 55..=109 => (1, 1), | ||
| 500 | 110..=164 => (2, 1), | ||
| 501 | 165..=224 => (3, 2), | ||
| 502 | _ => (7, 3), | ||
| 503 | }, | ||
| 504 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 505 | VoltageScale::Scale3 => match rcc_aclk_mhz { | ||
| 506 | 0..=44 => (0, 0), | ||
| 507 | 45..=89 => (1, 1), | ||
| 508 | 90..=134 => (2, 1), | ||
| 509 | 135..=179 => (3, 2), | ||
| 510 | 180..=224 => (4, 2), | ||
| 511 | _ => (7, 3), | ||
| 512 | }, | ||
| 513 | }; | ||
| 514 | |||
| 515 | // NOTE(unsafe) Atomic write | ||
| 516 | unsafe { | ||
| 517 | FLASH.acr().write(|w| { | ||
| 518 | w.set_wrhighfreq(progr_delay); | ||
| 519 | w.set_latency(wait_states) | ||
| 520 | }); | ||
| 521 | while FLASH.acr().read().latency() != wait_states {} | ||
| 522 | } | ||
| 523 | } | ||
| 212 | } | 524 | } |
diff --git a/embassy-stm32/src/rcc/h7/pll.rs b/embassy-stm32/src/rcc/h7/pll.rs index ead33e81e..af958d093 100644 --- a/embassy-stm32/src/rcc/h7/pll.rs +++ b/embassy-stm32/src/rcc/h7/pll.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use super::{Config, Hertz, HSI, RCC}; | 1 | use super::{Hertz, RCC}; |
| 2 | use crate::fmt::assert; | 2 | use crate::fmt::assert; |
| 3 | 3 | ||
| 4 | const VCO_MIN: u32 = 150_000_000; | 4 | const VCO_MIN: u32 = 150_000_000; |
diff --git a/embassy-stm32/src/sdmmc/v2.rs b/embassy-stm32/src/sdmmc/v2.rs index a4da4be8e..d1d485c29 100644 --- a/embassy-stm32/src/sdmmc/v2.rs +++ b/embassy-stm32/src/sdmmc/v2.rs | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | use core::default::Default; | 3 | use core::default::Default; |
| 4 | use core::future::Future; | ||
| 5 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 6 | use core::task::Poll; | 5 | use core::task::Poll; |
| 7 | 6 | ||
