diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-01-04 23:58:13 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-01-05 00:00:44 +0100 |
| commit | 2eb0cc5df78b2abd38228ee1f07b7c446e17d362 (patch) | |
| tree | a9df2ed2c0acc481e19275473f981da098b541f1 | |
| parent | c3fd9a0f44ae898c5cf1272dab6b8f46e119fab3 (diff) | |
stm32/rcc: remove Rcc struct, RccExt trait.
All the RCC configuration is executed in init().
31 files changed, 2427 insertions, 3037 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index c8a0e1705..117f3ed2a 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -43,8 +43,6 @@ pub mod i2c; | |||
| 43 | #[cfg(crc)] | 43 | #[cfg(crc)] |
| 44 | pub mod crc; | 44 | pub mod crc; |
| 45 | pub mod pwm; | 45 | pub mod pwm; |
| 46 | #[cfg(pwr)] | ||
| 47 | pub mod pwr; | ||
| 48 | #[cfg(rng)] | 46 | #[cfg(rng)] |
| 49 | pub mod rng; | 47 | pub mod rng; |
| 50 | #[cfg(sdmmc)] | 48 | #[cfg(sdmmc)] |
diff --git a/embassy-stm32/src/pwr/f3.rs b/embassy-stm32/src/pwr/f3.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/f3.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/pwr/f4.rs b/embassy-stm32/src/pwr/f4.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/f4.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/pwr/f7.rs b/embassy-stm32/src/pwr/f7.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/f7.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/pwr/g0.rs b/embassy-stm32/src/pwr/g0.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/g0.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/pwr/g4.rs b/embassy-stm32/src/pwr/g4.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/g4.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/pwr/h7.rs b/embassy-stm32/src/pwr/h7.rs deleted file mode 100644 index 37b049a85..000000000 --- a/embassy-stm32/src/pwr/h7.rs +++ /dev/null | |||
| @@ -1,78 +0,0 @@ | |||
| 1 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 2 | use crate::peripherals; | ||
| 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 | // NOTE(unsafe) we have the PWR singleton | ||
| 32 | unsafe { | ||
| 33 | // NB. The lower bytes of CR3 can only be written once after | ||
| 34 | // POR, and must be written with a valid combination. Refer to | ||
| 35 | // RM0433 Rev 7 6.8.4. This is partially enforced by dropping | ||
| 36 | // `self` at the end of this method, but of course we cannot | ||
| 37 | // know what happened between the previous POR and here. | ||
| 38 | #[cfg(pwr_h7)] | ||
| 39 | PWR.cr3().modify(|w| { | ||
| 40 | w.set_scuen(true); | ||
| 41 | w.set_ldoen(true); | ||
| 42 | w.set_bypass(false); | ||
| 43 | }); | ||
| 44 | |||
| 45 | #[cfg(pwr_h7smps)] | ||
| 46 | PWR.cr3().modify(|w| { | ||
| 47 | // hardcode "Direct SPMS" for now, this is what works on nucleos with the | ||
| 48 | // default solderbridge configuration. | ||
| 49 | w.set_sden(true); | ||
| 50 | w.set_ldoen(false); | ||
| 51 | }); | ||
| 52 | |||
| 53 | // Validate the supply configuration. If you are stuck here, it is | ||
| 54 | // because the voltages on your board do not match those specified | ||
| 55 | // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset | ||
| 56 | // VOS = Scale 3, so check that the voltage on the VCAP pins = | ||
| 57 | // 1.0V. | ||
| 58 | while !PWR.csr1().read().actvosrdy() {} | ||
| 59 | |||
| 60 | // Go to Scale 1 | ||
| 61 | PWR.d3cr().modify(|w| w.set_vos(0b11)); | ||
| 62 | while !PWR.d3cr().read().vosrdy() {} | ||
| 63 | |||
| 64 | let vos = if !enable_overdrive { | ||
| 65 | VoltageScale::Scale1 | ||
| 66 | } else { | ||
| 67 | critical_section::with(|_| { | ||
| 68 | RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||
| 69 | |||
| 70 | SYSCFG.pwrcr().modify(|w| w.set_oden(1)); | ||
| 71 | }); | ||
| 72 | while !PWR.d3cr().read().vosrdy() {} | ||
| 73 | VoltageScale::Scale0 | ||
| 74 | }; | ||
| 75 | Self { vos } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
diff --git a/embassy-stm32/src/pwr/l1.rs b/embassy-stm32/src/pwr/l1.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/l1.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs deleted file mode 100644 index d948c398d..000000000 --- a/embassy-stm32/src/pwr/mod.rs +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | #[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")] | ||
| 2 | #[cfg_attr(pwr_f3, path = "f3.rs")] | ||
| 3 | #[cfg_attr(pwr_f4, path = "f4.rs")] | ||
| 4 | #[cfg_attr(pwr_f7, path = "f7.rs")] | ||
| 5 | #[cfg_attr(pwr_wl5, path = "wl5.rs")] | ||
| 6 | #[cfg_attr(pwr_g0, path = "g0.rs")] | ||
| 7 | #[cfg_attr(pwr_g4, path = "g4.rs")] | ||
| 8 | #[cfg_attr(pwr_l1, path = "l1.rs")] | ||
| 9 | #[cfg_attr(pwr_u5, path = "u5.rs")] | ||
| 10 | #[cfg_attr(pwr_wb55, path = "wb55.rs")] | ||
| 11 | mod _version; | ||
| 12 | |||
| 13 | pub use _version::*; | ||
diff --git a/embassy-stm32/src/pwr/u5.rs b/embassy-stm32/src/pwr/u5.rs deleted file mode 100644 index a90659d9c..000000000 --- a/embassy-stm32/src/pwr/u5.rs +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | use crate::peripherals; | ||
| 2 | |||
| 3 | /// Voltage Scale | ||
| 4 | /// | ||
| 5 | /// Represents the voltage range feeding the CPU core. The maximum core | ||
| 6 | /// clock frequency depends on this value. | ||
| 7 | #[derive(Copy, Clone, PartialEq)] | ||
| 8 | pub enum VoltageScale { | ||
| 9 | // Highest frequency | ||
| 10 | Range1, | ||
| 11 | Range2, | ||
| 12 | Range3, | ||
| 13 | // Lowest power | ||
| 14 | Range4, | ||
| 15 | } | ||
| 16 | |||
| 17 | /// Power Configuration | ||
| 18 | /// | ||
| 19 | /// Generated when the PWR peripheral is frozen. The existence of this | ||
| 20 | /// value indicates that the voltage scaling configuration can no | ||
| 21 | /// longer be changed. | ||
| 22 | pub struct Power { | ||
| 23 | pub(crate) vos: VoltageScale, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl Power { | ||
| 27 | pub fn new(_peri: peripherals::PWR) -> Self { | ||
| 28 | Self { | ||
| 29 | vos: VoltageScale::Range4, | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
diff --git a/embassy-stm32/src/pwr/wb55.rs b/embassy-stm32/src/pwr/wb55.rs deleted file mode 100644 index e69de29bb..000000000 --- a/embassy-stm32/src/pwr/wb55.rs +++ /dev/null | |||
diff --git a/embassy-stm32/src/pwr/wl5.rs b/embassy-stm32/src/pwr/wl5.rs deleted file mode 100644 index 8b1378917..000000000 --- a/embassy-stm32/src/pwr/wl5.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | |||
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index 07a28cc3e..1527afa05 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs | |||
| @@ -1,9 +1,5 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; |
| 2 | |||
| 3 | use embassy::util::Unborrow; | ||
| 4 | |||
| 5 | use crate::pac::{FLASH, RCC}; | 2 | use crate::pac::{FLASH, RCC}; |
| 6 | use crate::peripherals; | ||
| 7 | use crate::time::Hertz; | 3 | use crate::time::Hertz; |
| 8 | 4 | ||
| 9 | use super::{set_freqs, Clocks}; | 5 | use super::{set_freqs, Clocks}; |
| @@ -28,181 +24,151 @@ pub struct Config { | |||
| 28 | pub pclk: Option<Hertz>, | 24 | pub pclk: Option<Hertz>, |
| 29 | } | 25 | } |
| 30 | 26 | ||
| 31 | pub struct Rcc<'d> { | 27 | pub(crate) unsafe fn init(config: Config) { |
| 32 | inner: PhantomData<&'d ()>, | 28 | let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI); |
| 33 | config: Config, | ||
| 34 | } | ||
| 35 | 29 | ||
| 36 | impl<'d> Rcc<'d> { | 30 | let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { |
| 37 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | 31 | #[cfg(rcc_f0)] |
| 38 | Self { | 32 | if config.hsi48 { |
| 39 | inner: PhantomData, | 33 | return (48_000_000, true); |
| 40 | config, | ||
| 41 | } | 34 | } |
| 42 | } | 35 | (HSI, false) |
| 43 | 36 | }); | |
| 44 | pub fn freeze(self) -> Clocks { | 37 | |
| 45 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; | 38 | let (pllmul_bits, real_sysclk) = if sysclk == src_clk { |
| 46 | 39 | (None, sysclk) | |
| 47 | let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI); | 40 | } else { |
| 48 | 41 | let prediv = if config.hse.is_some() { 1 } else { 2 }; | |
| 49 | let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { | 42 | let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2; |
| 50 | #[cfg(rcc_f0)] | 43 | let pllmul = pllmul.max(2).min(16); |
| 51 | if self.config.hsi48 { | 44 | |
| 52 | return (48_000_000, true); | 45 | let pllmul_bits = pllmul as u8 - 2; |
| 53 | } | 46 | let real_sysclk = pllmul * src_clk / prediv; |
| 54 | (HSI, false) | 47 | (Some(pllmul_bits), real_sysclk) |
| 55 | }); | 48 | }; |
| 56 | 49 | ||
| 57 | let (pllmul_bits, real_sysclk) = if sysclk == src_clk { | 50 | let hpre_bits = config |
| 58 | (None, sysclk) | 51 | .hclk |
| 52 | .map(|hclk| match real_sysclk / hclk.0 { | ||
| 53 | 0 => unreachable!(), | ||
| 54 | 1 => 0b0111, | ||
| 55 | 2 => 0b1000, | ||
| 56 | 3..=5 => 0b1001, | ||
| 57 | 6..=11 => 0b1010, | ||
| 58 | 12..=39 => 0b1011, | ||
| 59 | 40..=95 => 0b1100, | ||
| 60 | 96..=191 => 0b1101, | ||
| 61 | 192..=383 => 0b1110, | ||
| 62 | _ => 0b1111, | ||
| 63 | }) | ||
| 64 | .unwrap_or(0b0111); | ||
| 65 | let hclk = real_sysclk / (1 << (hpre_bits - 0b0111)); | ||
| 66 | |||
| 67 | let ppre_bits = config | ||
| 68 | .pclk | ||
| 69 | .map(|pclk| match hclk / pclk.0 { | ||
| 70 | 0 => unreachable!(), | ||
| 71 | 1 => 0b011, | ||
| 72 | 2 => 0b100, | ||
| 73 | 3..=5 => 0b101, | ||
| 74 | 6..=11 => 0b110, | ||
| 75 | _ => 0b111, | ||
| 76 | }) | ||
| 77 | .unwrap_or(0b011); | ||
| 78 | |||
| 79 | let ppre: u8 = 1 << (ppre_bits - 0b011); | ||
| 80 | let pclk = hclk / u32::from(ppre); | ||
| 81 | |||
| 82 | let timer_mul = if ppre == 1 { 1 } else { 2 }; | ||
| 83 | |||
| 84 | FLASH.acr().write(|w| { | ||
| 85 | let latency = if real_sysclk <= 24_000_000 { | ||
| 86 | 0 | ||
| 87 | } else if real_sysclk <= 48_000_000 { | ||
| 88 | 1 | ||
| 59 | } else { | 89 | } else { |
| 60 | let prediv = if self.config.hse.is_some() { 1 } else { 2 }; | 90 | 2 |
| 61 | let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2; | ||
| 62 | let pllmul = pllmul.max(2).min(16); | ||
| 63 | |||
| 64 | let pllmul_bits = pllmul as u8 - 2; | ||
| 65 | let real_sysclk = pllmul * src_clk / prediv; | ||
| 66 | (Some(pllmul_bits), real_sysclk) | ||
| 67 | }; | 91 | }; |
| 92 | w.latency().0 = latency; | ||
| 93 | }); | ||
| 68 | 94 | ||
| 69 | let hpre_bits = self | 95 | match (config.hse.is_some(), use_hsi48) { |
| 70 | .config | 96 | (true, _) => { |
| 71 | .hclk | 97 | RCC.cr().modify(|w| { |
| 72 | .map(|hclk| match real_sysclk / hclk.0 { | 98 | w.set_csson(true); |
| 73 | 0 => unreachable!(), | 99 | w.set_hseon(true); |
| 74 | 1 => 0b0111, | ||
| 75 | 2 => 0b1000, | ||
| 76 | 3..=5 => 0b1001, | ||
| 77 | 6..=11 => 0b1010, | ||
| 78 | 12..=39 => 0b1011, | ||
| 79 | 40..=95 => 0b1100, | ||
| 80 | 96..=191 => 0b1101, | ||
| 81 | 192..=383 => 0b1110, | ||
| 82 | _ => 0b1111, | ||
| 83 | }) | ||
| 84 | .unwrap_or(0b0111); | ||
| 85 | let hclk = real_sysclk / (1 << (hpre_bits - 0b0111)); | ||
| 86 | |||
| 87 | let ppre_bits = self | ||
| 88 | .config | ||
| 89 | .pclk | ||
| 90 | .map(|pclk| match hclk / pclk.0 { | ||
| 91 | 0 => unreachable!(), | ||
| 92 | 1 => 0b011, | ||
| 93 | 2 => 0b100, | ||
| 94 | 3..=5 => 0b101, | ||
| 95 | 6..=11 => 0b110, | ||
| 96 | _ => 0b111, | ||
| 97 | }) | ||
| 98 | .unwrap_or(0b011); | ||
| 99 | |||
| 100 | let ppre: u8 = 1 << (ppre_bits - 0b011); | ||
| 101 | let pclk = hclk / u32::from(ppre); | ||
| 102 | |||
| 103 | let timer_mul = if ppre == 1 { 1 } else { 2 }; | ||
| 104 | |||
| 105 | // NOTE(safety) Atomic write | ||
| 106 | unsafe { | ||
| 107 | FLASH.acr().write(|w| { | ||
| 108 | let latency = if real_sysclk <= 24_000_000 { | ||
| 109 | 0 | ||
| 110 | } else if real_sysclk <= 48_000_000 { | ||
| 111 | 1 | ||
| 112 | } else { | ||
| 113 | 2 | ||
| 114 | }; | ||
| 115 | w.latency().0 = latency; | ||
| 116 | }); | ||
| 117 | } | ||
| 118 | 100 | ||
| 119 | // NOTE(unsafe) We have exclusive access to the RCC | 101 | if config.bypass_hse { |
| 120 | unsafe { | 102 | w.set_hsebyp(Hsebyp::BYPASSED); |
| 121 | match (self.config.hse.is_some(), use_hsi48) { | ||
| 122 | (true, _) => { | ||
| 123 | RCC.cr().modify(|w| { | ||
| 124 | w.set_csson(true); | ||
| 125 | w.set_hseon(true); | ||
| 126 | |||
| 127 | if self.config.bypass_hse { | ||
| 128 | w.set_hsebyp(Hsebyp::BYPASSED); | ||
| 129 | } | ||
| 130 | }); | ||
| 131 | while !RCC.cr().read().hserdy() {} | ||
| 132 | |||
| 133 | if pllmul_bits.is_some() { | ||
| 134 | RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV)) | ||
| 135 | } | ||
| 136 | } | ||
| 137 | (false, true) => { | ||
| 138 | // use_hsi48 will always be false for rcc_f0x0 | ||
| 139 | #[cfg(rcc_f0)] | ||
| 140 | RCC.cr2().modify(|w| w.set_hsi48on(true)); | ||
| 141 | #[cfg(rcc_f0)] | ||
| 142 | while !RCC.cr2().read().hsi48rdy() {} | ||
| 143 | |||
| 144 | #[cfg(rcc_f0)] | ||
| 145 | if pllmul_bits.is_some() { | ||
| 146 | RCC.cfgr() | ||
| 147 | .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV)) | ||
| 148 | } | ||
| 149 | } | 103 | } |
| 150 | _ => { | 104 | }); |
| 151 | RCC.cr().modify(|w| w.set_hsion(true)); | 105 | while !RCC.cr().read().hserdy() {} |
| 152 | while !RCC.cr().read().hsirdy() {} | ||
| 153 | 106 | ||
| 154 | if pllmul_bits.is_some() { | 107 | if pllmul_bits.is_some() { |
| 155 | RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2)) | 108 | RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV)) |
| 156 | } | ||
| 157 | } | ||
| 158 | } | 109 | } |
| 110 | } | ||
| 111 | (false, true) => { | ||
| 112 | // use_hsi48 will always be false for rcc_f0x0 | ||
| 113 | #[cfg(rcc_f0)] | ||
| 114 | RCC.cr2().modify(|w| w.set_hsi48on(true)); | ||
| 115 | #[cfg(rcc_f0)] | ||
| 116 | while !RCC.cr2().read().hsi48rdy() {} | ||
| 159 | 117 | ||
| 160 | if self.config.usb_pll { | 118 | #[cfg(rcc_f0)] |
| 161 | RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK)); | 119 | if pllmul_bits.is_some() { |
| 120 | RCC.cfgr() | ||
| 121 | .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV)) | ||
| 162 | } | 122 | } |
| 163 | // TODO: Option to use CRS (Clock Recovery) | 123 | } |
| 124 | _ => { | ||
| 125 | RCC.cr().modify(|w| w.set_hsion(true)); | ||
| 126 | while !RCC.cr().read().hsirdy() {} | ||
| 164 | 127 | ||
| 165 | if let Some(pllmul_bits) = pllmul_bits { | 128 | if pllmul_bits.is_some() { |
| 166 | RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); | 129 | RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2)) |
| 130 | } | ||
| 131 | } | ||
| 132 | } | ||
| 167 | 133 | ||
| 168 | RCC.cr().modify(|w| w.set_pllon(true)); | 134 | if config.usb_pll { |
| 169 | while !RCC.cr().read().pllrdy() {} | 135 | RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK)); |
| 136 | } | ||
| 137 | // TODO: Option to use CRS (Clock Recovery) | ||
| 170 | 138 | ||
| 171 | RCC.cfgr().modify(|w| { | 139 | if let Some(pllmul_bits) = pllmul_bits { |
| 172 | w.set_ppre(Ppre(ppre_bits)); | 140 | RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); |
| 173 | w.set_hpre(Hpre(hpre_bits)); | 141 | |
| 174 | w.set_sw(Sw::PLL) | 142 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 175 | }); | 143 | while !RCC.cr().read().pllrdy() {} |
| 144 | |||
| 145 | RCC.cfgr().modify(|w| { | ||
| 146 | w.set_ppre(Ppre(ppre_bits)); | ||
| 147 | w.set_hpre(Hpre(hpre_bits)); | ||
| 148 | w.set_sw(Sw::PLL) | ||
| 149 | }); | ||
| 150 | } else { | ||
| 151 | RCC.cfgr().modify(|w| { | ||
| 152 | w.set_ppre(Ppre(ppre_bits)); | ||
| 153 | w.set_hpre(Hpre(hpre_bits)); | ||
| 154 | |||
| 155 | if config.hse.is_some() { | ||
| 156 | w.set_sw(Sw::HSE); | ||
| 157 | } else if use_hsi48 { | ||
| 158 | #[cfg(rcc_f0)] | ||
| 159 | w.set_sw(Sw::HSI48); | ||
| 176 | } else { | 160 | } else { |
| 177 | RCC.cfgr().modify(|w| { | 161 | w.set_sw(Sw::HSI) |
| 178 | w.set_ppre(Ppre(ppre_bits)); | ||
| 179 | w.set_hpre(Hpre(hpre_bits)); | ||
| 180 | |||
| 181 | if self.config.hse.is_some() { | ||
| 182 | w.set_sw(Sw::HSE); | ||
| 183 | } else if use_hsi48 { | ||
| 184 | #[cfg(rcc_f0)] | ||
| 185 | w.set_sw(Sw::HSI48); | ||
| 186 | } else { | ||
| 187 | w.set_sw(Sw::HSI) | ||
| 188 | } | ||
| 189 | }) | ||
| 190 | } | 162 | } |
| 191 | } | 163 | }) |
| 192 | |||
| 193 | Clocks { | ||
| 194 | sys: Hertz(real_sysclk), | ||
| 195 | apb1: Hertz(pclk), | ||
| 196 | apb2: Hertz(pclk), | ||
| 197 | apb1_tim: Hertz(pclk * timer_mul), | ||
| 198 | apb2_tim: Hertz(pclk * timer_mul), | ||
| 199 | ahb: Hertz(hclk), | ||
| 200 | } | ||
| 201 | } | 164 | } |
| 202 | } | ||
| 203 | 165 | ||
| 204 | pub(crate) unsafe fn init(config: Config) { | 166 | set_freqs(Clocks { |
| 205 | let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); | 167 | sys: Hertz(real_sysclk), |
| 206 | let clocks = rcc.freeze(); | 168 | apb1: Hertz(pclk), |
| 207 | set_freqs(clocks); | 169 | apb2: Hertz(pclk), |
| 170 | apb1_tim: Hertz(pclk * timer_mul), | ||
| 171 | apb2_tim: Hertz(pclk * timer_mul), | ||
| 172 | ahb: Hertz(hclk), | ||
| 173 | }); | ||
| 208 | } | 174 | } |
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index c9d09ee33..d44544d28 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs | |||
| @@ -1,15 +1,11 @@ | |||
| 1 | use core::convert::TryFrom; | 1 | use core::convert::TryFrom; |
| 2 | use core::marker::PhantomData; | ||
| 3 | |||
| 4 | use embassy::util::Unborrow; | ||
| 5 | 2 | ||
| 3 | use super::{set_freqs, Clocks}; | ||
| 6 | use crate::pac::flash::vals::Latency; | 4 | use crate::pac::flash::vals::Latency; |
| 5 | use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre}; | ||
| 7 | use crate::pac::{FLASH, RCC}; | 6 | use crate::pac::{FLASH, RCC}; |
| 8 | use crate::peripherals; | ||
| 9 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| 10 | 8 | ||
| 11 | use super::{set_freqs, Clocks}; | ||
| 12 | |||
| 13 | const HSI: u32 = 8_000_000; | 9 | const HSI: u32 = 8_000_000; |
| 14 | 10 | ||
| 15 | /// Configuration of the clocks | 11 | /// Configuration of the clocks |
| @@ -26,189 +22,158 @@ pub struct Config { | |||
| 26 | pub adcclk: Option<Hertz>, | 22 | pub adcclk: Option<Hertz>, |
| 27 | } | 23 | } |
| 28 | 24 | ||
| 29 | pub struct Rcc<'d> { | 25 | pub(crate) unsafe fn init(config: Config) { |
| 30 | inner: PhantomData<&'d ()>, | 26 | let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI / 2); |
| 31 | config: Config, | 27 | let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); |
| 32 | } | 28 | let pllmul = sysclk / pllsrcclk; |
| 33 | 29 | ||
| 34 | impl<'d> Rcc<'d> { | 30 | let (pllmul_bits, real_sysclk) = if pllmul == 1 { |
| 35 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | 31 | (None, config.hse.map(|hse| hse.0).unwrap_or(HSI)) |
| 36 | Self { | 32 | } else { |
| 37 | inner: PhantomData, | 33 | let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); |
| 38 | config, | 34 | (Some(pllmul as u8 - 2), pllsrcclk * pllmul) |
| 39 | } | 35 | }; |
| 36 | |||
| 37 | assert!(real_sysclk <= 72_000_000); | ||
| 38 | |||
| 39 | let hpre_bits = config | ||
| 40 | .hclk | ||
| 41 | .map(|hclk| match real_sysclk / hclk.0 { | ||
| 42 | 0 => unreachable!(), | ||
| 43 | 1 => 0b0111, | ||
| 44 | 2 => 0b1000, | ||
| 45 | 3..=5 => 0b1001, | ||
| 46 | 6..=11 => 0b1010, | ||
| 47 | 12..=39 => 0b1011, | ||
| 48 | 40..=95 => 0b1100, | ||
| 49 | 96..=191 => 0b1101, | ||
| 50 | 192..=383 => 0b1110, | ||
| 51 | _ => 0b1111, | ||
| 52 | }) | ||
| 53 | .unwrap_or(0b0111); | ||
| 54 | |||
| 55 | let hclk = if hpre_bits >= 0b1100 { | ||
| 56 | real_sysclk / (1 << (hpre_bits - 0b0110)) | ||
| 57 | } else { | ||
| 58 | real_sysclk / (1 << (hpre_bits - 0b0111)) | ||
| 59 | }; | ||
| 60 | |||
| 61 | assert!(hclk <= 72_000_000); | ||
| 62 | |||
| 63 | let ppre1_bits = config | ||
| 64 | .pclk1 | ||
| 65 | .map(|pclk1| match hclk / pclk1.0 { | ||
| 66 | 0 => unreachable!(), | ||
| 67 | 1 => 0b011, | ||
| 68 | 2 => 0b100, | ||
| 69 | 3..=5 => 0b101, | ||
| 70 | 6..=11 => 0b110, | ||
| 71 | _ => 0b111, | ||
| 72 | }) | ||
| 73 | .unwrap_or(0b011); | ||
| 74 | |||
| 75 | let ppre1 = 1 << (ppre1_bits - 0b011); | ||
| 76 | let pclk1 = hclk / u32::try_from(ppre1).unwrap(); | ||
| 77 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 78 | |||
| 79 | assert!(pclk1 <= 36_000_000); | ||
| 80 | |||
| 81 | let ppre2_bits = config | ||
| 82 | .pclk2 | ||
| 83 | .map(|pclk2| match hclk / pclk2.0 { | ||
| 84 | 0 => unreachable!(), | ||
| 85 | 1 => 0b011, | ||
| 86 | 2 => 0b100, | ||
| 87 | 3..=5 => 0b101, | ||
| 88 | 6..=11 => 0b110, | ||
| 89 | _ => 0b111, | ||
| 90 | }) | ||
| 91 | .unwrap_or(0b011); | ||
| 92 | |||
| 93 | let ppre2 = 1 << (ppre2_bits - 0b011); | ||
| 94 | let pclk2 = hclk / u32::try_from(ppre2).unwrap(); | ||
| 95 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 96 | |||
| 97 | assert!(pclk2 <= 72_000_000); | ||
| 98 | |||
| 99 | // Only needed for stm32f103? | ||
| 100 | FLASH.acr().write(|w| { | ||
| 101 | w.set_latency(if real_sysclk <= 24_000_000 { | ||
| 102 | Latency(0b000) | ||
| 103 | } else if real_sysclk <= 48_000_000 { | ||
| 104 | Latency(0b001) | ||
| 105 | } else { | ||
| 106 | Latency(0b010) | ||
| 107 | }); | ||
| 108 | }); | ||
| 109 | |||
| 110 | // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the | ||
| 111 | // PLL output frequency is a supported one. | ||
| 112 | // usbpre == false: divide clock by 1.5, otherwise no division | ||
| 113 | let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) { | ||
| 114 | (Some(_), Some(_), 72_000_000) => (false, true), | ||
| 115 | (Some(_), Some(_), 48_000_000) => (true, true), | ||
| 116 | _ => (true, false), | ||
| 117 | }; | ||
| 118 | |||
| 119 | let apre_bits: u8 = config | ||
| 120 | .adcclk | ||
| 121 | .map(|adcclk| match pclk2 / adcclk.0 { | ||
| 122 | 0..=2 => 0b00, | ||
| 123 | 3..=4 => 0b01, | ||
| 124 | 5..=7 => 0b10, | ||
| 125 | _ => 0b11, | ||
| 126 | }) | ||
| 127 | .unwrap_or(0b11); | ||
| 128 | |||
| 129 | let apre = (apre_bits + 1) << 1; | ||
| 130 | let adcclk = pclk2 / unwrap!(u32::try_from(apre)); | ||
| 131 | |||
| 132 | assert!(adcclk <= 14_000_000); | ||
| 133 | |||
| 134 | if config.hse.is_some() { | ||
| 135 | // enable HSE and wait for it to be ready | ||
| 136 | RCC.cr().modify(|w| w.set_hseon(true)); | ||
| 137 | while !RCC.cr().read().hserdy() {} | ||
| 40 | } | 138 | } |
| 41 | 139 | ||
| 42 | pub fn freeze(self) -> Clocks { | 140 | if let Some(pllmul_bits) = pllmul_bits { |
| 43 | use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre}; | 141 | // enable PLL and wait for it to be ready |
| 44 | 142 | RCC.cfgr().modify(|w| { | |
| 45 | let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI / 2); | 143 | w.set_pllmul(Pllmul(pllmul_bits)); |
| 46 | let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); | 144 | w.set_pllsrc(Pllsrc(config.hse.is_some() as u8)); |
| 47 | let pllmul = sysclk / pllsrcclk; | 145 | }); |
| 48 | 146 | ||
| 49 | let (pllmul_bits, real_sysclk) = if pllmul == 1 { | 147 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 50 | (None, self.config.hse.map(|hse| hse.0).unwrap_or(HSI)) | 148 | while !RCC.cr().read().pllrdy() {} |
| 51 | } else { | ||
| 52 | let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); | ||
| 53 | (Some(pllmul as u8 - 2), pllsrcclk * pllmul) | ||
| 54 | }; | ||
| 55 | |||
| 56 | assert!(real_sysclk <= 72_000_000); | ||
| 57 | |||
| 58 | let hpre_bits = self | ||
| 59 | .config | ||
| 60 | .hclk | ||
| 61 | .map(|hclk| match real_sysclk / hclk.0 { | ||
| 62 | 0 => unreachable!(), | ||
| 63 | 1 => 0b0111, | ||
| 64 | 2 => 0b1000, | ||
| 65 | 3..=5 => 0b1001, | ||
| 66 | 6..=11 => 0b1010, | ||
| 67 | 12..=39 => 0b1011, | ||
| 68 | 40..=95 => 0b1100, | ||
| 69 | 96..=191 => 0b1101, | ||
| 70 | 192..=383 => 0b1110, | ||
| 71 | _ => 0b1111, | ||
| 72 | }) | ||
| 73 | .unwrap_or(0b0111); | ||
| 74 | |||
| 75 | let hclk = if hpre_bits >= 0b1100 { | ||
| 76 | real_sysclk / (1 << (hpre_bits - 0b0110)) | ||
| 77 | } else { | ||
| 78 | real_sysclk / (1 << (hpre_bits - 0b0111)) | ||
| 79 | }; | ||
| 80 | |||
| 81 | assert!(hclk <= 72_000_000); | ||
| 82 | |||
| 83 | let ppre1_bits = self | ||
| 84 | .config | ||
| 85 | .pclk1 | ||
| 86 | .map(|pclk1| match hclk / pclk1.0 { | ||
| 87 | 0 => unreachable!(), | ||
| 88 | 1 => 0b011, | ||
| 89 | 2 => 0b100, | ||
| 90 | 3..=5 => 0b101, | ||
| 91 | 6..=11 => 0b110, | ||
| 92 | _ => 0b111, | ||
| 93 | }) | ||
| 94 | .unwrap_or(0b011); | ||
| 95 | |||
| 96 | let ppre1 = 1 << (ppre1_bits - 0b011); | ||
| 97 | let pclk1 = hclk / u32::try_from(ppre1).unwrap(); | ||
| 98 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 99 | |||
| 100 | assert!(pclk1 <= 36_000_000); | ||
| 101 | |||
| 102 | let ppre2_bits = self | ||
| 103 | .config | ||
| 104 | .pclk2 | ||
| 105 | .map(|pclk2| match hclk / pclk2.0 { | ||
| 106 | 0 => unreachable!(), | ||
| 107 | 1 => 0b011, | ||
| 108 | 2 => 0b100, | ||
| 109 | 3..=5 => 0b101, | ||
| 110 | 6..=11 => 0b110, | ||
| 111 | _ => 0b111, | ||
| 112 | }) | ||
| 113 | .unwrap_or(0b011); | ||
| 114 | |||
| 115 | let ppre2 = 1 << (ppre2_bits - 0b011); | ||
| 116 | let pclk2 = hclk / u32::try_from(ppre2).unwrap(); | ||
| 117 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 118 | |||
| 119 | assert!(pclk2 <= 72_000_000); | ||
| 120 | |||
| 121 | // Only needed for stm32f103? | ||
| 122 | // NOTE(safety) Atomic write | ||
| 123 | unsafe { | ||
| 124 | FLASH.acr().write(|w| { | ||
| 125 | w.set_latency(if real_sysclk <= 24_000_000 { | ||
| 126 | Latency(0b000) | ||
| 127 | } else if real_sysclk <= 48_000_000 { | ||
| 128 | Latency(0b001) | ||
| 129 | } else { | ||
| 130 | Latency(0b010) | ||
| 131 | }); | ||
| 132 | }) | ||
| 133 | } | ||
| 134 | |||
| 135 | // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the | ||
| 136 | // PLL output frequency is a supported one. | ||
| 137 | // usbpre == false: divide clock by 1.5, otherwise no division | ||
| 138 | let (usbpre, _usbclk_valid) = match (self.config.hse, pllmul_bits, real_sysclk) { | ||
| 139 | (Some(_), Some(_), 72_000_000) => (false, true), | ||
| 140 | (Some(_), Some(_), 48_000_000) => (true, true), | ||
| 141 | _ => (true, false), | ||
| 142 | }; | ||
| 143 | |||
| 144 | let apre_bits: u8 = self | ||
| 145 | .config | ||
| 146 | .adcclk | ||
| 147 | .map(|adcclk| match pclk2 / adcclk.0 { | ||
| 148 | 0..=2 => 0b00, | ||
| 149 | 3..=4 => 0b01, | ||
| 150 | 5..=7 => 0b10, | ||
| 151 | _ => 0b11, | ||
| 152 | }) | ||
| 153 | .unwrap_or(0b11); | ||
| 154 | |||
| 155 | let apre = (apre_bits + 1) << 1; | ||
| 156 | let adcclk = pclk2 / unwrap!(u32::try_from(apre)); | ||
| 157 | |||
| 158 | assert!(adcclk <= 14_000_000); | ||
| 159 | |||
| 160 | unsafe { | ||
| 161 | if self.config.hse.is_some() { | ||
| 162 | // enable HSE and wait for it to be ready | ||
| 163 | RCC.cr().modify(|w| w.set_hseon(true)); | ||
| 164 | while !RCC.cr().read().hserdy() {} | ||
| 165 | } | ||
| 166 | |||
| 167 | if let Some(pllmul_bits) = pllmul_bits { | ||
| 168 | // enable PLL and wait for it to be ready | ||
| 169 | RCC.cfgr().modify(|w| { | ||
| 170 | w.set_pllmul(Pllmul(pllmul_bits)); | ||
| 171 | w.set_pllsrc(Pllsrc(self.config.hse.is_some() as u8)); | ||
| 172 | }); | ||
| 173 | |||
| 174 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 175 | while !RCC.cr().read().pllrdy() {} | ||
| 176 | } | ||
| 177 | |||
| 178 | // Only needed for stm32f103? | ||
| 179 | RCC.cfgr().modify(|w| { | ||
| 180 | w.set_adcpre(Adcpre(apre_bits)); | ||
| 181 | w.set_ppre2(Ppre1(ppre2_bits)); | ||
| 182 | w.set_ppre1(Ppre1(ppre1_bits)); | ||
| 183 | w.set_hpre(Hpre(hpre_bits)); | ||
| 184 | w.set_usbpre(Usbpre(usbpre as u8)); | ||
| 185 | w.set_sw(Sw(if pllmul_bits.is_some() { | ||
| 186 | // PLL | ||
| 187 | 0b10 | ||
| 188 | } else if self.config.hse.is_some() { | ||
| 189 | // HSE | ||
| 190 | 0b1 | ||
| 191 | } else { | ||
| 192 | // HSI | ||
| 193 | 0b0 | ||
| 194 | })); | ||
| 195 | }); | ||
| 196 | } | ||
| 197 | |||
| 198 | Clocks { | ||
| 199 | sys: Hertz(real_sysclk), | ||
| 200 | apb1: Hertz(pclk1), | ||
| 201 | apb2: Hertz(pclk2), | ||
| 202 | apb1_tim: Hertz(pclk1 * timer_mul1), | ||
| 203 | apb2_tim: Hertz(pclk2 * timer_mul2), | ||
| 204 | ahb: Hertz(hclk), | ||
| 205 | adc: Hertz(adcclk), | ||
| 206 | } | ||
| 207 | } | 149 | } |
| 208 | } | ||
| 209 | 150 | ||
| 210 | pub(crate) unsafe fn init(config: Config) { | 151 | // Only needed for stm32f103? |
| 211 | let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); | 152 | RCC.cfgr().modify(|w| { |
| 212 | let clocks = rcc.freeze(); | 153 | w.set_adcpre(Adcpre(apre_bits)); |
| 213 | set_freqs(clocks); | 154 | w.set_ppre2(Ppre1(ppre2_bits)); |
| 155 | w.set_ppre1(Ppre1(ppre1_bits)); | ||
| 156 | w.set_hpre(Hpre(hpre_bits)); | ||
| 157 | w.set_usbpre(Usbpre(usbpre as u8)); | ||
| 158 | w.set_sw(Sw(if pllmul_bits.is_some() { | ||
| 159 | // PLL | ||
| 160 | 0b10 | ||
| 161 | } else if config.hse.is_some() { | ||
| 162 | // HSE | ||
| 163 | 0b1 | ||
| 164 | } else { | ||
| 165 | // HSI | ||
| 166 | 0b0 | ||
| 167 | })); | ||
| 168 | }); | ||
| 169 | |||
| 170 | set_freqs(Clocks { | ||
| 171 | sys: Hertz(real_sysclk), | ||
| 172 | apb1: Hertz(pclk1), | ||
| 173 | apb2: Hertz(pclk2), | ||
| 174 | apb1_tim: Hertz(pclk1 * timer_mul1), | ||
| 175 | apb2_tim: Hertz(pclk2 * timer_mul2), | ||
| 176 | ahb: Hertz(hclk), | ||
| 177 | adc: Hertz(adcclk), | ||
| 178 | }); | ||
| 214 | } | 179 | } |
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 7b5e0cce7..e16e1e499 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs | |||
| @@ -1,23 +1,11 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use crate::pac::flash::vals::Latency; |
| 2 | use embassy::util::Unborrow; | 2 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; |
| 3 | 3 | use crate::pac::{FLASH, RCC}; | |
| 4 | use crate::pac::{ | ||
| 5 | flash::vals::Latency, | ||
| 6 | rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}, | ||
| 7 | FLASH, RCC, | ||
| 8 | }; | ||
| 9 | use crate::peripherals; | ||
| 10 | use crate::rcc::{set_freqs, Clocks}; | 4 | use crate::rcc::{set_freqs, Clocks}; |
| 11 | use crate::time::Hertz; | 5 | use crate::time::Hertz; |
| 12 | 6 | ||
| 13 | const HSI: u32 = 8_000_000; | 7 | const HSI: u32 = 8_000_000; |
| 14 | 8 | ||
| 15 | /// RCC peripheral | ||
| 16 | pub struct Rcc<'d> { | ||
| 17 | config: Config, | ||
| 18 | phantom: PhantomData<&'d mut peripherals::RCC>, | ||
| 19 | } | ||
| 20 | |||
| 21 | /// Clocks configutation | 9 | /// Clocks configutation |
| 22 | #[non_exhaustive] | 10 | #[non_exhaustive] |
| 23 | #[derive(Default)] | 11 | #[derive(Default)] |
| @@ -55,259 +43,228 @@ struct PllConfig { | |||
| 55 | 43 | ||
| 56 | /// Initialize and Set the clock frequencies | 44 | /// Initialize and Set the clock frequencies |
| 57 | pub(crate) unsafe fn init(config: Config) { | 45 | pub(crate) unsafe fn init(config: Config) { |
| 58 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 46 | // Calculate the real System clock, and PLL configuration if applicable |
| 59 | let clocks = Rcc::new(r, config).freeze(); | 47 | let (Hertz(sysclk), pll_config) = get_sysclk(&config); |
| 60 | set_freqs(clocks); | 48 | assert!(sysclk <= 72_000_000); |
| 61 | } | ||
| 62 | |||
| 63 | impl<'d> Rcc<'d> { | ||
| 64 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | ||
| 65 | Self { | ||
| 66 | config, | ||
| 67 | phantom: PhantomData, | ||
| 68 | } | ||
| 69 | } | ||
| 70 | 49 | ||
| 71 | fn freeze(self) -> Clocks { | 50 | // Calculate real AHB clock |
| 72 | // Calculate the real System clock, and PLL configuration if applicable | 51 | let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); |
| 73 | let (Hertz(sysclk), pll_config) = self.get_sysclk(); | 52 | let (hpre_bits, hpre_div) = match sysclk / hclk { |
| 74 | assert!(sysclk <= 72_000_000); | 53 | 0 => unreachable!(), |
| 54 | 1 => (Hpre::DIV1, 1), | ||
| 55 | 2 => (Hpre::DIV2, 2), | ||
| 56 | 3..=5 => (Hpre::DIV4, 4), | ||
| 57 | 6..=11 => (Hpre::DIV8, 8), | ||
| 58 | 12..=39 => (Hpre::DIV16, 16), | ||
| 59 | 40..=95 => (Hpre::DIV64, 64), | ||
| 60 | 96..=191 => (Hpre::DIV128, 128), | ||
| 61 | 192..=383 => (Hpre::DIV256, 256), | ||
| 62 | _ => (Hpre::DIV512, 512), | ||
| 63 | }; | ||
| 64 | let hclk = sysclk / hpre_div; | ||
| 65 | assert!(hclk <= 72_000_000); | ||
| 75 | 66 | ||
| 76 | // Calculate real AHB clock | 67 | // Calculate real APB1 clock |
| 77 | let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); | 68 | let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk); |
| 78 | let (hpre_bits, hpre_div) = match sysclk / hclk { | 69 | let (ppre1_bits, ppre1) = match hclk / pclk1 { |
| 79 | 0 => unreachable!(), | 70 | 0 => unreachable!(), |
| 80 | 1 => (Hpre::DIV1, 1), | 71 | 1 => (Ppre::DIV1, 1), |
| 81 | 2 => (Hpre::DIV2, 2), | 72 | 2 => (Ppre::DIV2, 2), |
| 82 | 3..=5 => (Hpre::DIV4, 4), | 73 | 3..=5 => (Ppre::DIV4, 4), |
| 83 | 6..=11 => (Hpre::DIV8, 8), | 74 | 6..=11 => (Ppre::DIV8, 8), |
| 84 | 12..=39 => (Hpre::DIV16, 16), | 75 | _ => (Ppre::DIV16, 16), |
| 85 | 40..=95 => (Hpre::DIV64, 64), | 76 | }; |
| 86 | 96..=191 => (Hpre::DIV128, 128), | 77 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; |
| 87 | 192..=383 => (Hpre::DIV256, 256), | 78 | let pclk1 = hclk / ppre1; |
| 88 | _ => (Hpre::DIV512, 512), | 79 | assert!(pclk1 <= 36_000_000); |
| 89 | }; | ||
| 90 | let hclk = sysclk / hpre_div; | ||
| 91 | assert!(hclk <= 72_000_000); | ||
| 92 | 80 | ||
| 93 | // Calculate real APB1 clock | 81 | // Calculate real APB2 clock |
| 94 | let pclk1 = self.config.pclk1.map(|p| p.0).unwrap_or(hclk); | 82 | let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk); |
| 95 | let (ppre1_bits, ppre1) = match hclk / pclk1 { | 83 | let (ppre2_bits, ppre2) = match hclk / pclk2 { |
| 96 | 0 => unreachable!(), | 84 | 0 => unreachable!(), |
| 97 | 1 => (Ppre::DIV1, 1), | 85 | 1 => (Ppre::DIV1, 1), |
| 98 | 2 => (Ppre::DIV2, 2), | 86 | 2 => (Ppre::DIV2, 2), |
| 99 | 3..=5 => (Ppre::DIV4, 4), | 87 | 3..=5 => (Ppre::DIV4, 4), |
| 100 | 6..=11 => (Ppre::DIV8, 8), | 88 | 6..=11 => (Ppre::DIV8, 8), |
| 101 | _ => (Ppre::DIV16, 16), | 89 | _ => (Ppre::DIV16, 16), |
| 102 | }; | 90 | }; |
| 103 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | 91 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; |
| 104 | let pclk1 = hclk / ppre1; | 92 | let pclk2 = hclk / ppre2; |
| 105 | assert!(pclk1 <= 36_000_000); | 93 | assert!(pclk2 <= 72_000_000); |
| 106 | 94 | ||
| 107 | // Calculate real APB2 clock | 95 | // Set latency based on HCLK frquency |
| 108 | let pclk2 = self.config.pclk2.map(|p| p.0).unwrap_or(hclk); | 96 | FLASH.acr().write(|w| { |
| 109 | let (ppre2_bits, ppre2) = match hclk / pclk2 { | 97 | w.set_latency(if hclk <= 24_000_000 { |
| 110 | 0 => unreachable!(), | 98 | Latency::WS0 |
| 111 | 1 => (Ppre::DIV1, 1), | 99 | } else if hclk <= 48_000_000 { |
| 112 | 2 => (Ppre::DIV2, 2), | 100 | Latency::WS1 |
| 113 | 3..=5 => (Ppre::DIV4, 4), | 101 | } else { |
| 114 | 6..=11 => (Ppre::DIV8, 8), | 102 | Latency::WS2 |
| 115 | _ => (Ppre::DIV16, 16), | 103 | }); |
| 116 | }; | 104 | }); |
| 117 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 118 | let pclk2 = hclk / ppre2; | ||
| 119 | assert!(pclk2 <= 72_000_000); | ||
| 120 | 105 | ||
| 121 | // Set latency based on HCLK frquency | 106 | // Enable HSE |
| 122 | // NOTE(safety) Atomic write | 107 | if config.hse.is_some() { |
| 123 | unsafe { | 108 | RCC.cr().write(|w| { |
| 124 | FLASH.acr().write(|w| { | 109 | w.set_hsebyp(if config.bypass_hse { |
| 125 | w.set_latency(if hclk <= 24_000_000 { | 110 | Hsebyp::BYPASSED |
| 126 | Latency::WS0 | 111 | } else { |
| 127 | } else if hclk <= 48_000_000 { | 112 | Hsebyp::NOTBYPASSED |
| 128 | Latency::WS1 | 113 | }); |
| 129 | } else { | 114 | // We turn on clock security to switch to HSI when HSE fails |
| 130 | Latency::WS2 | 115 | w.set_csson(true); |
| 131 | }); | 116 | w.set_hseon(true); |
| 132 | }) | 117 | }); |
| 133 | } | 118 | while !RCC.cr().read().hserdy() {} |
| 119 | } | ||
| 134 | 120 | ||
| 135 | // Enable HSE | 121 | // Enable PLL |
| 136 | if self.config.hse.is_some() { | 122 | if let Some(ref pll_config) = pll_config { |
| 137 | // NOTE(unsafe) We own the peripheral block | 123 | RCC.cfgr().write(|w| { |
| 138 | unsafe { | 124 | w.set_pllmul(pll_config.pll_mul); |
| 139 | RCC.cr().write(|w| { | 125 | w.set_pllsrc(pll_config.pll_src); |
| 140 | w.set_hsebyp(if self.config.bypass_hse { | 126 | }); |
| 141 | Hsebyp::BYPASSED | 127 | if let Some(pll_div) = pll_config.pll_div { |
| 142 | } else { | 128 | RCC.cfgr2().write(|w| w.set_prediv(pll_div)); |
| 143 | Hsebyp::NOTBYPASSED | ||
| 144 | }); | ||
| 145 | // We turn on clock security to switch to HSI when HSE fails | ||
| 146 | w.set_csson(true); | ||
| 147 | w.set_hseon(true); | ||
| 148 | }); | ||
| 149 | while !RCC.cr().read().hserdy() {} | ||
| 150 | } | ||
| 151 | } | 129 | } |
| 130 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 131 | while !RCC.cr().read().pllrdy() {} | ||
| 132 | } | ||
| 152 | 133 | ||
| 153 | // Enable PLL | 134 | if config.pll48 { |
| 154 | if let Some(ref pll_config) = pll_config { | 135 | let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config); |
| 155 | // NOTE(unsafe) We own the peripheral block | 136 | RCC.cfgr().write(|w| { |
| 156 | unsafe { | 137 | w.set_usbpre(usb_pre); |
| 157 | RCC.cfgr().write(|w| { | 138 | }); |
| 158 | w.set_pllmul(pll_config.pll_mul); | 139 | } |
| 159 | w.set_pllsrc(pll_config.pll_src); | ||
| 160 | }); | ||
| 161 | if let Some(pll_div) = pll_config.pll_div { | ||
| 162 | RCC.cfgr2().write(|w| w.set_prediv(pll_div)); | ||
| 163 | } | ||
| 164 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 165 | while !RCC.cr().read().pllrdy() {} | ||
| 166 | } | ||
| 167 | } | ||
| 168 | 140 | ||
| 169 | if self.config.pll48 { | 141 | // Set prescalers |
| 170 | let usb_pre = self.get_usb_pre(sysclk, pclk1, &pll_config); | 142 | RCC.cfgr().write(|w| { |
| 171 | // NOTE(unsafe) We own the peripheral block | 143 | w.set_ppre2(ppre2_bits); |
| 172 | unsafe { | 144 | w.set_ppre1(ppre1_bits); |
| 173 | RCC.cfgr().write(|w| { | 145 | w.set_hpre(hpre_bits); |
| 174 | w.set_usbpre(usb_pre); | 146 | }); |
| 175 | }); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | 147 | ||
| 179 | // Set prescalers | 148 | // Wait for the new prescalers to kick in |
| 180 | unsafe { | 149 | // "The clocks are divided with the new prescaler factor from |
| 181 | // NOTE(unsafe) We own the peripheral block | 150 | // 1 to 16 AHB cycles after write" |
| 182 | RCC.cfgr().write(|w| { | 151 | cortex_m::asm::delay(16); |
| 183 | w.set_ppre2(ppre2_bits); | ||
| 184 | w.set_ppre1(ppre1_bits); | ||
| 185 | w.set_hpre(hpre_bits); | ||
| 186 | }); | ||
| 187 | 152 | ||
| 188 | // Wait for the new prescalers to kick in | 153 | RCC.cfgr().write(|w| { |
| 189 | // "The clocks are divided with the new prescaler factor from | 154 | w.set_sw(match (pll_config, config.hse) { |
| 190 | // 1 to 16 AHB cycles after write" | 155 | (Some(_), _) => Sw::PLL, |
| 191 | cortex_m::asm::delay(16); | 156 | (None, Some(_)) => Sw::HSE, |
| 157 | (None, None) => Sw::HSI, | ||
| 158 | }) | ||
| 159 | }); | ||
| 192 | 160 | ||
| 193 | // NOTE(unsafe) We own the peripheral block | 161 | set_freqs(Clocks { |
| 194 | RCC.cfgr().write(|w| { | 162 | sys: Hertz(sysclk), |
| 195 | w.set_sw(match (pll_config, self.config.hse) { | 163 | apb1: Hertz(pclk1), |
| 196 | (Some(_), _) => Sw::PLL, | 164 | apb2: Hertz(pclk2), |
| 197 | (None, Some(_)) => Sw::HSE, | 165 | apb1_tim: Hertz(pclk1 * timer_mul1), |
| 198 | (None, None) => Sw::HSI, | 166 | apb2_tim: Hertz(pclk2 * timer_mul2), |
| 199 | }) | 167 | ahb: Hertz(hclk), |
| 200 | }); | 168 | }); |
| 201 | } | 169 | } |
| 202 | 170 | ||
| 203 | Clocks { | 171 | #[inline] |
| 204 | sys: Hertz(sysclk), | 172 | fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) { |
| 205 | apb1: Hertz(pclk1), | 173 | match (config.sysclk, config.hse) { |
| 206 | apb2: Hertz(pclk2), | 174 | (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), |
| 207 | apb1_tim: Hertz(pclk1 * timer_mul1), | 175 | (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None), |
| 208 | apb2_tim: Hertz(pclk2 * timer_mul2), | 176 | // If the user selected System clock is different from HSI or HSE |
| 209 | ahb: Hertz(hclk), | 177 | // we will have to setup PLL clock source |
| 178 | (Some(sysclk), _) => { | ||
| 179 | let (sysclk, pll_config) = calc_pll(config, sysclk); | ||
| 180 | (sysclk, Some(pll_config)) | ||
| 210 | } | 181 | } |
| 182 | (None, Some(hse)) => (hse, None), | ||
| 183 | (None, None) => (Hertz(HSI), None), | ||
| 211 | } | 184 | } |
| 185 | } | ||
| 212 | 186 | ||
| 213 | #[inline] | 187 | #[inline] |
| 214 | fn get_sysclk(&self) -> (Hertz, Option<PllConfig>) { | 188 | fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { |
| 215 | match (self.config.sysclk, self.config.hse) { | 189 | // Calculates the Multiplier and the Divisor to arrive at |
| 216 | (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None), | 190 | // the required System clock from PLL source frequency |
| 217 | (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None), | 191 | let get_mul_div = |sysclk, pllsrcclk| { |
| 218 | // If the user selected System clock is different from HSI or HSE | 192 | let common_div = gcd(sysclk, pllsrcclk); |
| 219 | // we will have to setup PLL clock source | 193 | let mut multiplier = sysclk / common_div; |
| 220 | (Some(sysclk), _) => { | 194 | let mut divisor = pllsrcclk / common_div; |
| 221 | let (sysclk, pll_config) = self.calc_pll(sysclk); | 195 | // Minimum PLL multiplier is two |
| 222 | (sysclk, Some(pll_config)) | 196 | if multiplier == 1 { |
| 223 | } | 197 | multiplier *= 2; |
| 224 | (None, Some(hse)) => (hse, None), | 198 | divisor *= 2; |
| 225 | (None, None) => (Hertz(HSI), None), | ||
| 226 | } | 199 | } |
| 227 | } | 200 | assert!(multiplier <= 16); |
| 228 | 201 | assert!(divisor <= 16); | |
| 229 | #[inline] | 202 | (multiplier, divisor) |
| 230 | fn calc_pll(&self, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { | 203 | }; |
| 231 | // Calculates the Multiplier and the Divisor to arrive at | 204 | // Based on the source of Pll, we calculate the actual system clock |
| 232 | // the required System clock from PLL source frequency | 205 | // frequency, PLL's source identifier, multiplier and divisor |
| 233 | let get_mul_div = |sysclk, pllsrcclk| { | 206 | let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse { |
| 234 | let common_div = gcd(sysclk, pllsrcclk); | 207 | Some(Hertz(hse)) => { |
| 235 | let mut multiplier = sysclk / common_div; | 208 | let (multiplier, divisor) = get_mul_div(sysclk, hse); |
| 236 | let mut divisor = pllsrcclk / common_div; | 209 | ( |
| 237 | // Minimum PLL multiplier is two | 210 | Hertz((hse / divisor) * multiplier), |
| 238 | if multiplier == 1 { | 211 | Pllsrc::HSE_DIV_PREDIV, |
| 239 | multiplier *= 2; | 212 | into_pll_mul(multiplier), |
| 240 | divisor *= 2; | 213 | Some(into_pre_div(divisor)), |
| 241 | } | 214 | ) |
| 242 | assert!(multiplier <= 16); | 215 | } |
| 243 | assert!(divisor <= 16); | 216 | None => { |
| 244 | (multiplier, divisor) | 217 | cfg_if::cfg_if! { |
| 245 | }; | 218 | // For some chips PREDIV is always two, and cannot be changed |
| 246 | // Based on the source of Pll, we calculate the actual system clock | 219 | if #[cfg(any( |
| 247 | // frequency, PLL's source identifier, multiplier and divisor | 220 | feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd", |
| 248 | let (act_sysclk, pll_src, pll_mul, pll_div) = match self.config.hse { | 221 | feature="stm32f303xe", feature="stm32f398xe" |
| 249 | Some(Hertz(hse)) => { | 222 | ))] { |
| 250 | let (multiplier, divisor) = get_mul_div(sysclk, hse); | 223 | let (multiplier, divisor) = get_mul_div(sysclk, HSI); |
| 251 | ( | 224 | ( |
| 252 | Hertz((hse / divisor) * multiplier), | 225 | Hertz((hse / divisor) * multiplier), |
| 253 | Pllsrc::HSE_DIV_PREDIV, | 226 | Pllsrc::HSI_DIV_PREDIV, |
| 254 | into_pll_mul(multiplier), | 227 | into_pll_mul(multiplier), |
| 255 | Some(into_pre_div(divisor)), | 228 | Some(into_pre_div(divisor)), |
| 256 | ) | 229 | ) |
| 257 | } | 230 | } else { |
| 258 | None => { | 231 | let pllsrcclk = HSI / 2; |
| 259 | cfg_if::cfg_if! { | 232 | let multiplier = sysclk / pllsrcclk; |
| 260 | // For some chips PREDIV is always two, and cannot be changed | 233 | assert!(multiplier <= 16); |
| 261 | if #[cfg(any( | 234 | ( |
| 262 | feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd", | 235 | Hertz(pllsrcclk * multiplier), |
| 263 | feature="stm32f303xe", feature="stm32f398xe" | 236 | Pllsrc::HSI_DIV2, |
| 264 | ))] { | 237 | into_pll_mul(multiplier), |
| 265 | let (multiplier, divisor) = get_mul_div(sysclk, HSI); | 238 | None, |
| 266 | ( | 239 | ) |
| 267 | Hertz((hse / divisor) * multiplier), | ||
| 268 | Pllsrc::HSI_DIV_PREDIV, | ||
| 269 | into_pll_mul(multiplier), | ||
| 270 | Some(into_pre_div(divisor)), | ||
| 271 | ) | ||
| 272 | } else { | ||
| 273 | let pllsrcclk = HSI / 2; | ||
| 274 | let multiplier = sysclk / pllsrcclk; | ||
| 275 | assert!(multiplier <= 16); | ||
| 276 | ( | ||
| 277 | Hertz(pllsrcclk * multiplier), | ||
| 278 | Pllsrc::HSI_DIV2, | ||
| 279 | into_pll_mul(multiplier), | ||
| 280 | None, | ||
| 281 | ) | ||
| 282 | } | ||
| 283 | } | 240 | } |
| 284 | } | 241 | } |
| 285 | }; | 242 | } |
| 286 | ( | 243 | }; |
| 287 | act_sysclk, | 244 | ( |
| 288 | PllConfig { | 245 | act_sysclk, |
| 289 | pll_src, | 246 | PllConfig { |
| 290 | pll_mul, | 247 | pll_src, |
| 291 | pll_div, | 248 | pll_mul, |
| 292 | }, | 249 | pll_div, |
| 293 | ) | 250 | }, |
| 294 | } | 251 | ) |
| 252 | } | ||
| 295 | 253 | ||
| 296 | #[inline] | 254 | #[inline] |
| 297 | fn get_usb_pre(&self, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre { | 255 | fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre { |
| 298 | cfg_if::cfg_if! { | 256 | cfg_if::cfg_if! { |
| 299 | // Some chips do not have USB | 257 | // Some chips do not have USB |
| 300 | if #[cfg(any(stm32f301, stm32f318, stm32f334))] { | 258 | if #[cfg(any(stm32f301, stm32f318, stm32f334))] { |
| 301 | panic!("USB clock not supported by the chip"); | 259 | panic!("USB clock not supported by the chip"); |
| 302 | } else { | 260 | } else { |
| 303 | let usb_ok = self.config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); | 261 | let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); |
| 304 | match (usb_ok, sysclk) { | 262 | match (usb_ok, sysclk) { |
| 305 | (true, 72_000_000) => Usbpre::DIV1_5, | 263 | (true, 72_000_000) => Usbpre::DIV1_5, |
| 306 | (true, 48_000_000) => Usbpre::DIV1, | 264 | (true, 48_000_000) => Usbpre::DIV1, |
| 307 | _ => panic!( | 265 | _ => panic!( |
| 308 | "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" | 266 | "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" |
| 309 | ), | 267 | ), |
| 310 | } | ||
| 311 | } | 268 | } |
| 312 | } | 269 | } |
| 313 | } | 270 | } |
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 58a08adbf..aba8fc0ef 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | use super::sealed::RccPeripheral; | ||
| 2 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; | ||
| 1 | use crate::pac::{FLASH, PWR, RCC}; | 3 | use crate::pac::{FLASH, PWR, RCC}; |
| 2 | use crate::peripherals; | 4 | use crate::rcc::{set_freqs, Clocks}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | 5 | use crate::time::Hertz; |
| 5 | use core::marker::PhantomData; | ||
| 6 | use embassy::util::Unborrow; | ||
| 7 | 6 | ||
| 8 | const HSI: u32 = 16_000_000; | 7 | const HSI: u32 = 16_000_000; |
| 9 | 8 | ||
| @@ -21,284 +20,240 @@ pub struct Config { | |||
| 21 | pub pll48: bool, | 20 | pub pll48: bool, |
| 22 | } | 21 | } |
| 23 | 22 | ||
| 24 | /// RCC peripheral | 23 | unsafe fn setup_pll( |
| 25 | pub struct Rcc<'d> { | 24 | pllsrcclk: u32, |
| 26 | config: Config, | 25 | use_hse: bool, |
| 27 | phantom: PhantomData<&'d mut peripherals::RCC>, | 26 | pllsysclk: Option<u32>, |
| 28 | } | 27 | pll48clk: bool, |
| 29 | 28 | ) -> PllResults { | |
| 30 | impl<'d> Rcc<'d> { | 29 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; |
| 31 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | 30 | |
| 32 | Self { | 31 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); |
| 33 | config, | 32 | if pllsysclk.is_none() && !pll48clk { |
| 34 | phantom: PhantomData, | 33 | RCC.pllcfgr() |
| 35 | } | 34 | .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); |
| 36 | } | 35 | |
| 37 | 36 | return PllResults { | |
| 38 | fn freeze(mut self) -> Clocks { | 37 | use_pll: false, |
| 39 | use super::sealed::RccPeripheral; | 38 | pllsysclk: None, |
| 40 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; | 39 | pll48clk: None, |
| 41 | |||
| 42 | peripherals::PWR::enable(); | ||
| 43 | |||
| 44 | let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); | ||
| 45 | let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); | ||
| 46 | let sysclk_on_pll = sysclk != pllsrcclk; | ||
| 47 | |||
| 48 | let plls = self.setup_pll( | ||
| 49 | pllsrcclk, | ||
| 50 | self.config.hse.is_some(), | ||
| 51 | if sysclk_on_pll { Some(sysclk) } else { None }, | ||
| 52 | self.config.pll48, | ||
| 53 | ); | ||
| 54 | |||
| 55 | if self.config.pll48 { | ||
| 56 | let freq = unwrap!(plls.pll48clk); | ||
| 57 | |||
| 58 | assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); | ||
| 59 | } | ||
| 60 | |||
| 61 | let sysclk = if sysclk_on_pll { | ||
| 62 | unwrap!(plls.pllsysclk) | ||
| 63 | } else { | ||
| 64 | sysclk | ||
| 65 | }; | ||
| 66 | |||
| 67 | // AHB prescaler | ||
| 68 | let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); | ||
| 69 | let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { | ||
| 70 | 0 => unreachable!(), | ||
| 71 | 1 => (Hpre::DIV1, 1), | ||
| 72 | 2 => (Hpre::DIV2, 2), | ||
| 73 | 3..=5 => (Hpre::DIV4, 4), | ||
| 74 | 6..=11 => (Hpre::DIV8, 8), | ||
| 75 | 12..=39 => (Hpre::DIV16, 16), | ||
| 76 | 40..=95 => (Hpre::DIV64, 64), | ||
| 77 | 96..=191 => (Hpre::DIV128, 128), | ||
| 78 | 192..=383 => (Hpre::DIV256, 256), | ||
| 79 | _ => (Hpre::DIV512, 512), | ||
| 80 | }; | ||
| 81 | |||
| 82 | // Calculate real AHB clock | ||
| 83 | let hclk = sysclk / hpre_div; | ||
| 84 | |||
| 85 | let pclk1 = self | ||
| 86 | .config | ||
| 87 | .pclk1 | ||
| 88 | .map(|p| p.0) | ||
| 89 | .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); | ||
| 90 | |||
| 91 | let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { | ||
| 92 | 0 => unreachable!(), | ||
| 93 | 1 => (0b000, 1), | ||
| 94 | 2 => (0b100, 2), | ||
| 95 | 3..=5 => (0b101, 4), | ||
| 96 | 6..=11 => (0b110, 8), | ||
| 97 | _ => (0b111, 16), | ||
| 98 | }; | ||
| 99 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 100 | |||
| 101 | // Calculate real APB1 clock | ||
| 102 | let pclk1 = hclk / ppre1; | ||
| 103 | assert!(pclk1 <= max::PCLK1_MAX); | ||
| 104 | |||
| 105 | let pclk2 = self | ||
| 106 | .config | ||
| 107 | .pclk2 | ||
| 108 | .map(|p| p.0) | ||
| 109 | .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); | ||
| 110 | let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { | ||
| 111 | 0 => unreachable!(), | ||
| 112 | 1 => (0b000, 1), | ||
| 113 | 2 => (0b100, 2), | ||
| 114 | 3..=5 => (0b101, 4), | ||
| 115 | 6..=11 => (0b110, 8), | ||
| 116 | _ => (0b111, 16), | ||
| 117 | }; | 40 | }; |
| 118 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | 41 | } |
| 119 | 42 | // Input divisor from PLL source clock, must result to frequency in | |
| 120 | // Calculate real APB2 clock | 43 | // the range from 1 to 2 MHz |
| 121 | let pclk2 = hclk / ppre2; | 44 | let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; |
| 122 | assert!(pclk2 <= max::PCLK2_MAX); | 45 | let pllm_max = pllsrcclk / 1_000_000; |
| 123 | 46 | ||
| 124 | Self::flash_setup(sysclk); | 47 | // Sysclk output divisor must be one of 2, 4, 6 or 8 |
| 125 | 48 | let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); | |
| 126 | if self.config.hse.is_some() { | 49 | |
| 127 | // NOTE(unsafe) We own the peripheral block | 50 | let target_freq = if pll48clk { |
| 128 | unsafe { | 51 | 48_000_000 |
| 129 | RCC.cr().modify(|w| { | 52 | } else { |
| 130 | w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8)); | 53 | sysclk * sysclk_div |
| 131 | w.set_hseon(true); | 54 | }; |
| 132 | }); | 55 | |
| 133 | while !RCC.cr().read().hserdy() {} | 56 | // Find the lowest pllm value that minimize the difference between |
| 134 | } | 57 | // target frequency and the real vco_out frequency. |
| 135 | } | 58 | let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { |
| 136 | 59 | let vco_in = pllsrcclk / pllm; | |
| 137 | if plls.use_pll { | 60 | let plln = target_freq / vco_in; |
| 138 | unsafe { | 61 | target_freq - vco_in * plln |
| 139 | RCC.cr().modify(|w| w.set_pllon(true)); | 62 | })); |
| 63 | |||
| 64 | let vco_in = pllsrcclk / pllm; | ||
| 65 | assert!((1_000_000..=2_000_000).contains(&vco_in)); | ||
| 66 | |||
| 67 | // Main scaler, must result in >= 100MHz (>= 192MHz for F401) | ||
| 68 | // and <= 432MHz, min 50, max 432 | ||
| 69 | let plln = if pll48clk { | ||
| 70 | // try the different valid pllq according to the valid | ||
| 71 | // main scaller values, and take the best | ||
| 72 | let pllq = unwrap!((4..=9).min_by_key(|pllq| { | ||
| 73 | let plln = 48_000_000 * pllq / vco_in; | ||
| 74 | let pll48_diff = 48_000_000 - vco_in * plln / pllq; | ||
| 75 | let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); | ||
| 76 | (pll48_diff, sysclk_diff) | ||
| 77 | })); | ||
| 78 | 48_000_000 * pllq / vco_in | ||
| 79 | } else { | ||
| 80 | sysclk * sysclk_div / vco_in | ||
| 81 | }; | ||
| 82 | |||
| 83 | let pllp = (sysclk_div / 2) - 1; | ||
| 84 | |||
| 85 | let pllq = (vco_in * plln + 47_999_999) / 48_000_000; | ||
| 86 | let real_pll48clk = vco_in * plln / pllq; | ||
| 87 | |||
| 88 | RCC.pllcfgr().modify(|w| { | ||
| 89 | w.set_pllm(pllm as u8); | ||
| 90 | w.set_plln(plln as u16); | ||
| 91 | w.set_pllp(Pllp(pllp as u8)); | ||
| 92 | w.set_pllq(pllq as u8); | ||
| 93 | w.set_pllsrc(Pllsrc(use_hse as u8)); | ||
| 94 | }); | ||
| 95 | |||
| 96 | let real_pllsysclk = vco_in * plln / sysclk_div; | ||
| 97 | |||
| 98 | PllResults { | ||
| 99 | use_pll: true, | ||
| 100 | pllsysclk: Some(real_pllsysclk), | ||
| 101 | pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, | ||
| 102 | } | ||
| 103 | } | ||
| 140 | 104 | ||
| 141 | if hclk > max::HCLK_OVERDRIVE_FREQUENCY { | 105 | unsafe fn flash_setup(sysclk: u32) { |
| 142 | PWR.cr1().modify(|w| w.set_oden(true)); | 106 | use crate::pac::flash::vals::Latency; |
| 143 | while !PWR.csr1().read().odrdy() {} | ||
| 144 | 107 | ||
| 145 | PWR.cr1().modify(|w| w.set_odswen(true)); | 108 | // Be conservative with voltage ranges |
| 146 | while !PWR.csr1().read().odswrdy() {} | 109 | const FLASH_LATENCY_STEP: u32 = 30_000_000; |
| 147 | } | ||
| 148 | 110 | ||
| 149 | while !RCC.cr().read().pllrdy() {} | 111 | critical_section::with(|_| { |
| 150 | } | 112 | FLASH |
| 151 | } | 113 | .acr() |
| 114 | .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); | ||
| 115 | }); | ||
| 116 | } | ||
| 152 | 117 | ||
| 153 | unsafe { | 118 | pub(crate) unsafe fn init(config: Config) { |
| 154 | RCC.cfgr().modify(|w| { | 119 | crate::peripherals::PWR::enable(); |
| 155 | w.set_ppre2(Ppre(ppre2_bits)); | ||
| 156 | w.set_ppre1(Ppre(ppre1_bits)); | ||
| 157 | w.set_hpre(hpre_bits); | ||
| 158 | }); | ||
| 159 | |||
| 160 | // Wait for the new prescalers to kick in | ||
| 161 | // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" | ||
| 162 | cortex_m::asm::delay(16); | ||
| 163 | |||
| 164 | RCC.cfgr().modify(|w| { | ||
| 165 | w.set_sw(if sysclk_on_pll { | ||
| 166 | Sw::PLL | ||
| 167 | } else if self.config.hse.is_some() { | ||
| 168 | Sw::HSE | ||
| 169 | } else { | ||
| 170 | Sw::HSI | ||
| 171 | }) | ||
| 172 | }); | ||
| 173 | } | ||
| 174 | 120 | ||
| 175 | Clocks { | 121 | let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI); |
| 176 | sys: Hertz(sysclk), | 122 | let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); |
| 177 | apb1: Hertz(pclk1), | 123 | let sysclk_on_pll = sysclk != pllsrcclk; |
| 178 | apb2: Hertz(pclk2), | ||
| 179 | 124 | ||
| 180 | apb1_tim: Hertz(pclk1 * timer_mul1), | 125 | let plls = setup_pll( |
| 181 | apb2_tim: Hertz(pclk2 * timer_mul2), | 126 | pllsrcclk, |
| 127 | config.hse.is_some(), | ||
| 128 | if sysclk_on_pll { Some(sysclk) } else { None }, | ||
| 129 | config.pll48, | ||
| 130 | ); | ||
| 182 | 131 | ||
| 183 | ahb1: Hertz(hclk), | 132 | if config.pll48 { |
| 184 | ahb2: Hertz(hclk), | 133 | let freq = unwrap!(plls.pll48clk); |
| 185 | ahb3: Hertz(hclk), | ||
| 186 | 134 | ||
| 187 | pll48: plls.pll48clk.map(Hertz), | 135 | assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); |
| 188 | } | ||
| 189 | } | 136 | } |
| 190 | 137 | ||
| 191 | // Safety: RCC init must have been called | 138 | let sysclk = if sysclk_on_pll { |
| 192 | pub fn clocks(&self) -> &'static Clocks { | 139 | unwrap!(plls.pllsysclk) |
| 193 | unsafe { get_freqs() } | 140 | } else { |
| 141 | sysclk | ||
| 142 | }; | ||
| 143 | |||
| 144 | // AHB prescaler | ||
| 145 | let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); | ||
| 146 | let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { | ||
| 147 | 0 => unreachable!(), | ||
| 148 | 1 => (Hpre::DIV1, 1), | ||
| 149 | 2 => (Hpre::DIV2, 2), | ||
| 150 | 3..=5 => (Hpre::DIV4, 4), | ||
| 151 | 6..=11 => (Hpre::DIV8, 8), | ||
| 152 | 12..=39 => (Hpre::DIV16, 16), | ||
| 153 | 40..=95 => (Hpre::DIV64, 64), | ||
| 154 | 96..=191 => (Hpre::DIV128, 128), | ||
| 155 | 192..=383 => (Hpre::DIV256, 256), | ||
| 156 | _ => (Hpre::DIV512, 512), | ||
| 157 | }; | ||
| 158 | |||
| 159 | // Calculate real AHB clock | ||
| 160 | let hclk = sysclk / hpre_div; | ||
| 161 | |||
| 162 | let pclk1 = config | ||
| 163 | .pclk1 | ||
| 164 | .map(|p| p.0) | ||
| 165 | .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); | ||
| 166 | |||
| 167 | let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { | ||
| 168 | 0 => unreachable!(), | ||
| 169 | 1 => (0b000, 1), | ||
| 170 | 2 => (0b100, 2), | ||
| 171 | 3..=5 => (0b101, 4), | ||
| 172 | 6..=11 => (0b110, 8), | ||
| 173 | _ => (0b111, 16), | ||
| 174 | }; | ||
| 175 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 176 | |||
| 177 | // Calculate real APB1 clock | ||
| 178 | let pclk1 = hclk / ppre1; | ||
| 179 | assert!(pclk1 <= max::PCLK1_MAX); | ||
| 180 | |||
| 181 | let pclk2 = config | ||
| 182 | .pclk2 | ||
| 183 | .map(|p| p.0) | ||
| 184 | .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); | ||
| 185 | let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { | ||
| 186 | 0 => unreachable!(), | ||
| 187 | 1 => (0b000, 1), | ||
| 188 | 2 => (0b100, 2), | ||
| 189 | 3..=5 => (0b101, 4), | ||
| 190 | 6..=11 => (0b110, 8), | ||
| 191 | _ => (0b111, 16), | ||
| 192 | }; | ||
| 193 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 194 | |||
| 195 | // Calculate real APB2 clock | ||
| 196 | let pclk2 = hclk / ppre2; | ||
| 197 | assert!(pclk2 <= max::PCLK2_MAX); | ||
| 198 | |||
| 199 | flash_setup(sysclk); | ||
| 200 | |||
| 201 | if config.hse.is_some() { | ||
| 202 | RCC.cr().modify(|w| { | ||
| 203 | w.set_hsebyp(Hsebyp(config.bypass_hse as u8)); | ||
| 204 | w.set_hseon(true); | ||
| 205 | }); | ||
| 206 | while !RCC.cr().read().hserdy() {} | ||
| 194 | } | 207 | } |
| 195 | 208 | ||
| 196 | fn setup_pll( | 209 | if plls.use_pll { |
| 197 | &mut self, | 210 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 198 | pllsrcclk: u32, | ||
| 199 | use_hse: bool, | ||
| 200 | pllsysclk: Option<u32>, | ||
| 201 | pll48clk: bool, | ||
| 202 | ) -> PllResults { | ||
| 203 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; | ||
| 204 | |||
| 205 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); | ||
| 206 | if pllsysclk.is_none() && !pll48clk { | ||
| 207 | // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock | ||
| 208 | unsafe { | ||
| 209 | RCC.pllcfgr() | ||
| 210 | .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); | ||
| 211 | } | ||
| 212 | |||
| 213 | return PllResults { | ||
| 214 | use_pll: false, | ||
| 215 | pllsysclk: None, | ||
| 216 | pll48clk: None, | ||
| 217 | }; | ||
| 218 | } | ||
| 219 | // Input divisor from PLL source clock, must result to frequency in | ||
| 220 | // the range from 1 to 2 MHz | ||
| 221 | let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; | ||
| 222 | let pllm_max = pllsrcclk / 1_000_000; | ||
| 223 | |||
| 224 | // Sysclk output divisor must be one of 2, 4, 6 or 8 | ||
| 225 | let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); | ||
| 226 | |||
| 227 | let target_freq = if pll48clk { | ||
| 228 | 48_000_000 | ||
| 229 | } else { | ||
| 230 | sysclk * sysclk_div | ||
| 231 | }; | ||
| 232 | |||
| 233 | // Find the lowest pllm value that minimize the difference between | ||
| 234 | // target frequency and the real vco_out frequency. | ||
| 235 | let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { | ||
| 236 | let vco_in = pllsrcclk / pllm; | ||
| 237 | let plln = target_freq / vco_in; | ||
| 238 | target_freq - vco_in * plln | ||
| 239 | })); | ||
| 240 | |||
| 241 | let vco_in = pllsrcclk / pllm; | ||
| 242 | assert!((1_000_000..=2_000_000).contains(&vco_in)); | ||
| 243 | |||
| 244 | // Main scaler, must result in >= 100MHz (>= 192MHz for F401) | ||
| 245 | // and <= 432MHz, min 50, max 432 | ||
| 246 | let plln = if pll48clk { | ||
| 247 | // try the different valid pllq according to the valid | ||
| 248 | // main scaller values, and take the best | ||
| 249 | let pllq = unwrap!((4..=9).min_by_key(|pllq| { | ||
| 250 | let plln = 48_000_000 * pllq / vco_in; | ||
| 251 | let pll48_diff = 48_000_000 - vco_in * plln / pllq; | ||
| 252 | let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); | ||
| 253 | (pll48_diff, sysclk_diff) | ||
| 254 | })); | ||
| 255 | 48_000_000 * pllq / vco_in | ||
| 256 | } else { | ||
| 257 | sysclk * sysclk_div / vco_in | ||
| 258 | }; | ||
| 259 | 211 | ||
| 260 | let pllp = (sysclk_div / 2) - 1; | 212 | if hclk > max::HCLK_OVERDRIVE_FREQUENCY { |
| 213 | PWR.cr1().modify(|w| w.set_oden(true)); | ||
| 214 | while !PWR.csr1().read().odrdy() {} | ||
| 261 | 215 | ||
| 262 | let pllq = (vco_in * plln + 47_999_999) / 48_000_000; | 216 | PWR.cr1().modify(|w| w.set_odswen(true)); |
| 263 | let real_pll48clk = vco_in * plln / pllq; | 217 | while !PWR.csr1().read().odswrdy() {} |
| 264 | |||
| 265 | unsafe { | ||
| 266 | RCC.pllcfgr().modify(|w| { | ||
| 267 | w.set_pllm(pllm as u8); | ||
| 268 | w.set_plln(plln as u16); | ||
| 269 | w.set_pllp(Pllp(pllp as u8)); | ||
| 270 | w.set_pllq(pllq as u8); | ||
| 271 | w.set_pllsrc(Pllsrc(use_hse as u8)); | ||
| 272 | }); | ||
| 273 | } | 218 | } |
| 274 | 219 | ||
| 275 | let real_pllsysclk = vco_in * plln / sysclk_div; | 220 | while !RCC.cr().read().pllrdy() {} |
| 276 | |||
| 277 | PllResults { | ||
| 278 | use_pll: true, | ||
| 279 | pllsysclk: Some(real_pllsysclk), | ||
| 280 | pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, | ||
| 281 | } | ||
| 282 | } | 221 | } |
| 283 | 222 | ||
| 284 | fn flash_setup(sysclk: u32) { | 223 | RCC.cfgr().modify(|w| { |
| 285 | use crate::pac::flash::vals::Latency; | 224 | w.set_ppre2(Ppre(ppre2_bits)); |
| 225 | w.set_ppre1(Ppre(ppre1_bits)); | ||
| 226 | w.set_hpre(hpre_bits); | ||
| 227 | }); | ||
| 228 | |||
| 229 | // Wait for the new prescalers to kick in | ||
| 230 | // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" | ||
| 231 | cortex_m::asm::delay(16); | ||
| 232 | |||
| 233 | RCC.cfgr().modify(|w| { | ||
| 234 | w.set_sw(if sysclk_on_pll { | ||
| 235 | Sw::PLL | ||
| 236 | } else if config.hse.is_some() { | ||
| 237 | Sw::HSE | ||
| 238 | } else { | ||
| 239 | Sw::HSI | ||
| 240 | }) | ||
| 241 | }); | ||
| 286 | 242 | ||
| 287 | // Be conservative with voltage ranges | 243 | set_freqs(Clocks { |
| 288 | const FLASH_LATENCY_STEP: u32 = 30_000_000; | 244 | sys: Hertz(sysclk), |
| 245 | apb1: Hertz(pclk1), | ||
| 246 | apb2: Hertz(pclk2), | ||
| 289 | 247 | ||
| 290 | critical_section::with(|_| unsafe { | 248 | apb1_tim: Hertz(pclk1 * timer_mul1), |
| 291 | FLASH | 249 | apb2_tim: Hertz(pclk2 * timer_mul2), |
| 292 | .acr() | ||
| 293 | .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); | ||
| 294 | }); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | 250 | ||
| 298 | pub(crate) unsafe fn init(config: Config) { | 251 | ahb1: Hertz(hclk), |
| 299 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 252 | ahb2: Hertz(hclk), |
| 300 | let clocks = Rcc::new(r, config).freeze(); | 253 | ahb3: Hertz(hclk), |
| 301 | set_freqs(clocks); | 254 | |
| 255 | pll48: plls.pll48clk.map(Hertz), | ||
| 256 | }); | ||
| 302 | } | 257 | } |
| 303 | 258 | ||
| 304 | struct PllResults { | 259 | struct PllResults { |
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index d29ba31f0..1a0530296 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | use super::sealed::RccPeripheral; | ||
| 2 | use crate::pac::pwr::vals::Vos; | ||
| 3 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; | ||
| 1 | use crate::pac::{FLASH, PWR, RCC}; | 4 | use crate::pac::{FLASH, PWR, RCC}; |
| 2 | use crate::peripherals; | 5 | use crate::rcc::{set_freqs, Clocks}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 5 | use core::marker::PhantomData; | ||
| 6 | use embassy::util::Unborrow; | ||
| 7 | 7 | ||
| 8 | const HSI: u32 = 16_000_000; | 8 | const HSI: u32 = 16_000_000; |
| 9 | 9 | ||
| @@ -21,318 +21,274 @@ pub struct Config { | |||
| 21 | pub pll48: bool, | 21 | pub pll48: bool, |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | /// RCC peripheral | 24 | unsafe fn setup_pll( |
| 25 | pub struct Rcc<'d> { | 25 | pllsrcclk: u32, |
| 26 | config: Config, | 26 | use_hse: bool, |
| 27 | phantom: PhantomData<&'d mut peripherals::RCC>, | 27 | pllsysclk: Option<u32>, |
| 28 | } | 28 | pll48clk: bool, |
| 29 | 29 | ) -> PllResults { | |
| 30 | impl<'d> Rcc<'d> { | 30 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; |
| 31 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | 31 | |
| 32 | if let Some(hse) = config.hse { | 32 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); |
| 33 | if config.bypass_hse { | 33 | if pllsysclk.is_none() && !pll48clk { |
| 34 | assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); | 34 | RCC.pllcfgr() |
| 35 | } else { | 35 | .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); |
| 36 | assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0)); | 36 | |
| 37 | } | 37 | return PllResults { |
| 38 | } | 38 | use_pll: false, |
| 39 | Self { | 39 | pllsysclk: None, |
| 40 | config, | 40 | pll48clk: None, |
| 41 | phantom: PhantomData, | 41 | }; |
| 42 | } | ||
| 43 | } | 42 | } |
| 43 | // Input divisor from PLL source clock, must result to frequency in | ||
| 44 | // the range from 1 to 2 MHz | ||
| 45 | let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; | ||
| 46 | let pllm_max = pllsrcclk / 1_000_000; | ||
| 47 | |||
| 48 | // Sysclk output divisor must be one of 2, 4, 6 or 8 | ||
| 49 | let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); | ||
| 50 | |||
| 51 | let target_freq = if pll48clk { | ||
| 52 | 48_000_000 | ||
| 53 | } else { | ||
| 54 | sysclk * sysclk_div | ||
| 55 | }; | ||
| 56 | |||
| 57 | // Find the lowest pllm value that minimize the difference between | ||
| 58 | // target frequency and the real vco_out frequency. | ||
| 59 | let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { | ||
| 60 | let vco_in = pllsrcclk / pllm; | ||
| 61 | let plln = target_freq / vco_in; | ||
| 62 | target_freq - vco_in * plln | ||
| 63 | })); | ||
| 64 | |||
| 65 | let vco_in = pllsrcclk / pllm; | ||
| 66 | assert!((1_000_000..=2_000_000).contains(&vco_in)); | ||
| 67 | |||
| 68 | // Main scaler, must result in >= 100MHz (>= 192MHz for F401) | ||
| 69 | // and <= 432MHz, min 50, max 432 | ||
| 70 | let plln = if pll48clk { | ||
| 71 | // try the different valid pllq according to the valid | ||
| 72 | // main scaller values, and take the best | ||
| 73 | let pllq = unwrap!((4..=9).min_by_key(|pllq| { | ||
| 74 | let plln = 48_000_000 * pllq / vco_in; | ||
| 75 | let pll48_diff = 48_000_000 - vco_in * plln / pllq; | ||
| 76 | let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); | ||
| 77 | (pll48_diff, sysclk_diff) | ||
| 78 | })); | ||
| 79 | 48_000_000 * pllq / vco_in | ||
| 80 | } else { | ||
| 81 | sysclk * sysclk_div / vco_in | ||
| 82 | }; | ||
| 83 | |||
| 84 | let pllp = (sysclk_div / 2) - 1; | ||
| 85 | |||
| 86 | let pllq = (vco_in * plln + 47_999_999) / 48_000_000; | ||
| 87 | let real_pll48clk = vco_in * plln / pllq; | ||
| 88 | |||
| 89 | RCC.pllcfgr().modify(|w| { | ||
| 90 | w.set_pllm(pllm as u8); | ||
| 91 | w.set_plln(plln as u16); | ||
| 92 | w.set_pllp(Pllp(pllp as u8)); | ||
| 93 | w.set_pllq(pllq as u8); | ||
| 94 | w.set_pllsrc(Pllsrc(use_hse as u8)); | ||
| 95 | }); | ||
| 96 | |||
| 97 | let real_pllsysclk = vco_in * plln / sysclk_div; | ||
| 98 | |||
| 99 | PllResults { | ||
| 100 | use_pll: true, | ||
| 101 | pllsysclk: Some(real_pllsysclk), | ||
| 102 | pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, | ||
| 103 | } | ||
| 104 | } | ||
| 44 | 105 | ||
| 45 | fn freeze(mut self) -> Clocks { | 106 | unsafe fn flash_setup(sysclk: u32) { |
| 46 | use super::sealed::RccPeripheral; | 107 | use crate::pac::flash::vals::Latency; |
| 47 | use crate::pac::pwr::vals::Vos; | ||
| 48 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw}; | ||
| 49 | |||
| 50 | peripherals::PWR::enable(); | ||
| 51 | |||
| 52 | let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI); | ||
| 53 | let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); | ||
| 54 | let sysclk_on_pll = sysclk != pllsrcclk; | ||
| 55 | |||
| 56 | assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk)); | ||
| 57 | 108 | ||
| 58 | let plls = self.setup_pll( | 109 | // Be conservative with voltage ranges |
| 59 | pllsrcclk, | 110 | const FLASH_LATENCY_STEP: u32 = 30_000_000; |
| 60 | self.config.hse.is_some(), | ||
| 61 | if sysclk_on_pll { Some(sysclk) } else { None }, | ||
| 62 | self.config.pll48, | ||
| 63 | ); | ||
| 64 | 111 | ||
| 65 | if self.config.pll48 { | 112 | critical_section::with(|_| { |
| 66 | let freq = unwrap!(plls.pll48clk); | 113 | FLASH |
| 114 | .acr() | ||
| 115 | .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); | ||
| 116 | }); | ||
| 117 | } | ||
| 67 | 118 | ||
| 68 | assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); | 119 | pub(crate) unsafe fn init(config: Config) { |
| 69 | } | 120 | crate::peripherals::PWR::enable(); |
| 70 | 121 | ||
| 71 | let sysclk = if sysclk_on_pll { | 122 | if let Some(hse) = config.hse { |
| 72 | unwrap!(plls.pllsysclk) | 123 | if config.bypass_hse { |
| 124 | assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0)); | ||
| 73 | } else { | 125 | } else { |
| 74 | sysclk | 126 | assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0)); |
| 75 | }; | ||
| 76 | |||
| 77 | // AHB prescaler | ||
| 78 | let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk); | ||
| 79 | let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { | ||
| 80 | 0 => unreachable!(), | ||
| 81 | 1 => (Hpre::DIV1, 1), | ||
| 82 | 2 => (Hpre::DIV2, 2), | ||
| 83 | 3..=5 => (Hpre::DIV4, 4), | ||
| 84 | 6..=11 => (Hpre::DIV8, 8), | ||
| 85 | 12..=39 => (Hpre::DIV16, 16), | ||
| 86 | 40..=95 => (Hpre::DIV64, 64), | ||
| 87 | 96..=191 => (Hpre::DIV128, 128), | ||
| 88 | 192..=383 => (Hpre::DIV256, 256), | ||
| 89 | _ => (Hpre::DIV512, 512), | ||
| 90 | }; | ||
| 91 | |||
| 92 | // Calculate real AHB clock | ||
| 93 | let hclk = sysclk / hpre_div; | ||
| 94 | |||
| 95 | assert!(hclk < max::HCLK_MAX); | ||
| 96 | |||
| 97 | let pclk1 = self | ||
| 98 | .config | ||
| 99 | .pclk1 | ||
| 100 | .map(|p| p.0) | ||
| 101 | .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); | ||
| 102 | |||
| 103 | let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { | ||
| 104 | 0 => unreachable!(), | ||
| 105 | 1 => (0b000, 1), | ||
| 106 | 2 => (0b100, 2), | ||
| 107 | 3..=5 => (0b101, 4), | ||
| 108 | 6..=11 => (0b110, 8), | ||
| 109 | _ => (0b111, 16), | ||
| 110 | }; | ||
| 111 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 112 | |||
| 113 | // Calculate real APB1 clock | ||
| 114 | let pclk1 = hclk / ppre1; | ||
| 115 | assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1)); | ||
| 116 | |||
| 117 | let pclk2 = self | ||
| 118 | .config | ||
| 119 | .pclk2 | ||
| 120 | .map(|p| p.0) | ||
| 121 | .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); | ||
| 122 | let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { | ||
| 123 | 0 => unreachable!(), | ||
| 124 | 1 => (0b000, 1), | ||
| 125 | 2 => (0b100, 2), | ||
| 126 | 3..=5 => (0b101, 4), | ||
| 127 | 6..=11 => (0b110, 8), | ||
| 128 | _ => (0b111, 16), | ||
| 129 | }; | ||
| 130 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 131 | |||
| 132 | // Calculate real APB2 clock | ||
| 133 | let pclk2 = hclk / ppre2; | ||
| 134 | assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2)); | ||
| 135 | |||
| 136 | Self::flash_setup(sysclk); | ||
| 137 | |||
| 138 | if self.config.hse.is_some() { | ||
| 139 | // NOTE(unsafe) We own the peripheral block | ||
| 140 | unsafe { | ||
| 141 | RCC.cr().modify(|w| { | ||
| 142 | w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8)); | ||
| 143 | w.set_hseon(true); | ||
| 144 | }); | ||
| 145 | while !RCC.cr().read().hserdy() {} | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | if plls.use_pll { | ||
| 150 | unsafe { | ||
| 151 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 152 | |||
| 153 | // enable PWR and setup VOSScale | ||
| 154 | |||
| 155 | RCC.apb1enr().modify(|w| w.set_pwren(true)); | ||
| 156 | |||
| 157 | let vos_scale = if sysclk <= 144_000_000 { | ||
| 158 | 3 | ||
| 159 | } else if sysclk <= 168_000_000 { | ||
| 160 | 2 | ||
| 161 | } else { | ||
| 162 | 1 | ||
| 163 | }; | ||
| 164 | PWR.cr1().modify(|w| { | ||
| 165 | w.set_vos(match vos_scale { | ||
| 166 | 3 => Vos::SCALE3, | ||
| 167 | 2 => Vos::SCALE2, | ||
| 168 | 1 => Vos::SCALE1, | ||
| 169 | _ => panic!("Invalid VOS Scale."), | ||
| 170 | }) | ||
| 171 | }); | ||
| 172 | |||
| 173 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 174 | |||
| 175 | if hclk > max::HCLK_OVERDRIVE_FREQUENCY { | ||
| 176 | PWR.cr1().modify(|w| w.set_oden(true)); | ||
| 177 | while !PWR.csr1().read().odrdy() {} | ||
| 178 | |||
| 179 | PWR.cr1().modify(|w| w.set_odswen(true)); | ||
| 180 | while !PWR.csr1().read().odswrdy() {} | ||
| 181 | } | ||
| 182 | |||
| 183 | while !RCC.cr().read().pllrdy() {} | ||
| 184 | } | ||
| 185 | } | 127 | } |
| 128 | } | ||
| 186 | 129 | ||
| 187 | unsafe { | 130 | let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI); |
| 188 | RCC.cfgr().modify(|w| { | 131 | let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); |
| 189 | w.set_ppre2(Ppre(ppre2_bits)); | 132 | let sysclk_on_pll = sysclk != pllsrcclk; |
| 190 | w.set_ppre1(Ppre(ppre1_bits)); | ||
| 191 | w.set_hpre(hpre_bits); | ||
| 192 | }); | ||
| 193 | |||
| 194 | // Wait for the new prescalers to kick in | ||
| 195 | // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" | ||
| 196 | cortex_m::asm::delay(16); | ||
| 197 | |||
| 198 | RCC.cfgr().modify(|w| { | ||
| 199 | w.set_sw(if sysclk_on_pll { | ||
| 200 | Sw::PLL | ||
| 201 | } else if self.config.hse.is_some() { | ||
| 202 | Sw::HSE | ||
| 203 | } else { | ||
| 204 | Sw::HSI | ||
| 205 | }) | ||
| 206 | }); | ||
| 207 | } | ||
| 208 | 133 | ||
| 209 | Clocks { | 134 | assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk)); |
| 210 | sys: Hertz(sysclk), | ||
| 211 | apb1: Hertz(pclk1), | ||
| 212 | apb2: Hertz(pclk2), | ||
| 213 | 135 | ||
| 214 | apb1_tim: Hertz(pclk1 * timer_mul1), | 136 | let plls = setup_pll( |
| 215 | apb2_tim: Hertz(pclk2 * timer_mul2), | 137 | pllsrcclk, |
| 138 | config.hse.is_some(), | ||
| 139 | if sysclk_on_pll { Some(sysclk) } else { None }, | ||
| 140 | config.pll48, | ||
| 141 | ); | ||
| 216 | 142 | ||
| 217 | ahb1: Hertz(hclk), | 143 | if config.pll48 { |
| 218 | ahb2: Hertz(hclk), | 144 | let freq = unwrap!(plls.pll48clk); |
| 219 | ahb3: Hertz(hclk), | ||
| 220 | 145 | ||
| 221 | pll48: plls.pll48clk.map(Hertz), | 146 | assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); |
| 222 | } | ||
| 223 | } | 147 | } |
| 224 | 148 | ||
| 225 | // Safety: RCC init must have been called | 149 | let sysclk = if sysclk_on_pll { |
| 226 | pub fn clocks(&self) -> &'static Clocks { | 150 | unwrap!(plls.pllsysclk) |
| 227 | unsafe { get_freqs() } | 151 | } else { |
| 152 | sysclk | ||
| 153 | }; | ||
| 154 | |||
| 155 | // AHB prescaler | ||
| 156 | let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); | ||
| 157 | let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { | ||
| 158 | 0 => unreachable!(), | ||
| 159 | 1 => (Hpre::DIV1, 1), | ||
| 160 | 2 => (Hpre::DIV2, 2), | ||
| 161 | 3..=5 => (Hpre::DIV4, 4), | ||
| 162 | 6..=11 => (Hpre::DIV8, 8), | ||
| 163 | 12..=39 => (Hpre::DIV16, 16), | ||
| 164 | 40..=95 => (Hpre::DIV64, 64), | ||
| 165 | 96..=191 => (Hpre::DIV128, 128), | ||
| 166 | 192..=383 => (Hpre::DIV256, 256), | ||
| 167 | _ => (Hpre::DIV512, 512), | ||
| 168 | }; | ||
| 169 | |||
| 170 | // Calculate real AHB clock | ||
| 171 | let hclk = sysclk / hpre_div; | ||
| 172 | |||
| 173 | assert!(hclk < max::HCLK_MAX); | ||
| 174 | |||
| 175 | let pclk1 = config | ||
| 176 | .pclk1 | ||
| 177 | .map(|p| p.0) | ||
| 178 | .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); | ||
| 179 | |||
| 180 | let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { | ||
| 181 | 0 => unreachable!(), | ||
| 182 | 1 => (0b000, 1), | ||
| 183 | 2 => (0b100, 2), | ||
| 184 | 3..=5 => (0b101, 4), | ||
| 185 | 6..=11 => (0b110, 8), | ||
| 186 | _ => (0b111, 16), | ||
| 187 | }; | ||
| 188 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 189 | |||
| 190 | // Calculate real APB1 clock | ||
| 191 | let pclk1 = hclk / ppre1; | ||
| 192 | assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1)); | ||
| 193 | |||
| 194 | let pclk2 = config | ||
| 195 | .pclk2 | ||
| 196 | .map(|p| p.0) | ||
| 197 | .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); | ||
| 198 | let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { | ||
| 199 | 0 => unreachable!(), | ||
| 200 | 1 => (0b000, 1), | ||
| 201 | 2 => (0b100, 2), | ||
| 202 | 3..=5 => (0b101, 4), | ||
| 203 | 6..=11 => (0b110, 8), | ||
| 204 | _ => (0b111, 16), | ||
| 205 | }; | ||
| 206 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 207 | |||
| 208 | // Calculate real APB2 clock | ||
| 209 | let pclk2 = hclk / ppre2; | ||
| 210 | assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2)); | ||
| 211 | |||
| 212 | flash_setup(sysclk); | ||
| 213 | |||
| 214 | if config.hse.is_some() { | ||
| 215 | RCC.cr().modify(|w| { | ||
| 216 | w.set_hsebyp(Hsebyp(config.bypass_hse as u8)); | ||
| 217 | w.set_hseon(true); | ||
| 218 | }); | ||
| 219 | while !RCC.cr().read().hserdy() {} | ||
| 228 | } | 220 | } |
| 229 | 221 | ||
| 230 | fn setup_pll( | 222 | if plls.use_pll { |
| 231 | &mut self, | 223 | RCC.cr().modify(|w| w.set_pllon(false)); |
| 232 | pllsrcclk: u32, | ||
| 233 | use_hse: bool, | ||
| 234 | pllsysclk: Option<u32>, | ||
| 235 | pll48clk: bool, | ||
| 236 | ) -> PllResults { | ||
| 237 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; | ||
| 238 | |||
| 239 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); | ||
| 240 | if pllsysclk.is_none() && !pll48clk { | ||
| 241 | // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock | ||
| 242 | unsafe { | ||
| 243 | RCC.pllcfgr() | ||
| 244 | .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); | ||
| 245 | } | ||
| 246 | |||
| 247 | return PllResults { | ||
| 248 | use_pll: false, | ||
| 249 | pllsysclk: None, | ||
| 250 | pll48clk: None, | ||
| 251 | }; | ||
| 252 | } | ||
| 253 | // Input divisor from PLL source clock, must result to frequency in | ||
| 254 | // the range from 1 to 2 MHz | ||
| 255 | let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; | ||
| 256 | let pllm_max = pllsrcclk / 1_000_000; | ||
| 257 | 224 | ||
| 258 | // Sysclk output divisor must be one of 2, 4, 6 or 8 | 225 | // enable PWR and setup VOSScale |
| 259 | let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); | ||
| 260 | 226 | ||
| 261 | let target_freq = if pll48clk { | 227 | RCC.apb1enr().modify(|w| w.set_pwren(true)); |
| 262 | 48_000_000 | ||
| 263 | } else { | ||
| 264 | sysclk * sysclk_div | ||
| 265 | }; | ||
| 266 | 228 | ||
| 267 | // Find the lowest pllm value that minimize the difference between | 229 | let vos_scale = if sysclk <= 144_000_000 { |
| 268 | // target frequency and the real vco_out frequency. | 230 | 3 |
| 269 | let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { | 231 | } else if sysclk <= 168_000_000 { |
| 270 | let vco_in = pllsrcclk / pllm; | 232 | 2 |
| 271 | let plln = target_freq / vco_in; | ||
| 272 | target_freq - vco_in * plln | ||
| 273 | })); | ||
| 274 | |||
| 275 | let vco_in = pllsrcclk / pllm; | ||
| 276 | assert!((1_000_000..=2_000_000).contains(&vco_in)); | ||
| 277 | |||
| 278 | // Main scaler, must result in >= 100MHz (>= 192MHz for F401) | ||
| 279 | // and <= 432MHz, min 50, max 432 | ||
| 280 | let plln = if pll48clk { | ||
| 281 | // try the different valid pllq according to the valid | ||
| 282 | // main scaller values, and take the best | ||
| 283 | let pllq = unwrap!((4..=9).min_by_key(|pllq| { | ||
| 284 | let plln = 48_000_000 * pllq / vco_in; | ||
| 285 | let pll48_diff = 48_000_000 - vco_in * plln / pllq; | ||
| 286 | let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); | ||
| 287 | (pll48_diff, sysclk_diff) | ||
| 288 | })); | ||
| 289 | 48_000_000 * pllq / vco_in | ||
| 290 | } else { | 233 | } else { |
| 291 | sysclk * sysclk_div / vco_in | 234 | 1 |
| 292 | }; | 235 | }; |
| 236 | PWR.cr1().modify(|w| { | ||
| 237 | w.set_vos(match vos_scale { | ||
| 238 | 3 => Vos::SCALE3, | ||
| 239 | 2 => Vos::SCALE2, | ||
| 240 | 1 => Vos::SCALE1, | ||
| 241 | _ => panic!("Invalid VOS Scale."), | ||
| 242 | }) | ||
| 243 | }); | ||
| 293 | 244 | ||
| 294 | let pllp = (sysclk_div / 2) - 1; | 245 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 295 | 246 | ||
| 296 | let pllq = (vco_in * plln + 47_999_999) / 48_000_000; | 247 | if hclk > max::HCLK_OVERDRIVE_FREQUENCY { |
| 297 | let real_pll48clk = vco_in * plln / pllq; | 248 | PWR.cr1().modify(|w| w.set_oden(true)); |
| 249 | while !PWR.csr1().read().odrdy() {} | ||
| 298 | 250 | ||
| 299 | unsafe { | 251 | PWR.cr1().modify(|w| w.set_odswen(true)); |
| 300 | RCC.pllcfgr().modify(|w| { | 252 | while !PWR.csr1().read().odswrdy() {} |
| 301 | w.set_pllm(pllm as u8); | ||
| 302 | w.set_plln(plln as u16); | ||
| 303 | w.set_pllp(Pllp(pllp as u8)); | ||
| 304 | w.set_pllq(pllq as u8); | ||
| 305 | w.set_pllsrc(Pllsrc(use_hse as u8)); | ||
| 306 | }); | ||
| 307 | } | 253 | } |
| 308 | 254 | ||
| 309 | let real_pllsysclk = vco_in * plln / sysclk_div; | 255 | while !RCC.cr().read().pllrdy() {} |
| 310 | |||
| 311 | PllResults { | ||
| 312 | use_pll: true, | ||
| 313 | pllsysclk: Some(real_pllsysclk), | ||
| 314 | pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, | ||
| 315 | } | ||
| 316 | } | 256 | } |
| 317 | 257 | ||
| 318 | fn flash_setup(sysclk: u32) { | 258 | RCC.cfgr().modify(|w| { |
| 319 | use crate::pac::flash::vals::Latency; | 259 | w.set_ppre2(Ppre(ppre2_bits)); |
| 260 | w.set_ppre1(Ppre(ppre1_bits)); | ||
| 261 | w.set_hpre(hpre_bits); | ||
| 262 | }); | ||
| 263 | |||
| 264 | // Wait for the new prescalers to kick in | ||
| 265 | // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" | ||
| 266 | cortex_m::asm::delay(16); | ||
| 267 | |||
| 268 | RCC.cfgr().modify(|w| { | ||
| 269 | w.set_sw(if sysclk_on_pll { | ||
| 270 | Sw::PLL | ||
| 271 | } else if config.hse.is_some() { | ||
| 272 | Sw::HSE | ||
| 273 | } else { | ||
| 274 | Sw::HSI | ||
| 275 | }) | ||
| 276 | }); | ||
| 320 | 277 | ||
| 321 | // Be conservative with voltage ranges | 278 | set_freqs(Clocks { |
| 322 | const FLASH_LATENCY_STEP: u32 = 30_000_000; | 279 | sys: Hertz(sysclk), |
| 280 | apb1: Hertz(pclk1), | ||
| 281 | apb2: Hertz(pclk2), | ||
| 323 | 282 | ||
| 324 | critical_section::with(|_| unsafe { | 283 | apb1_tim: Hertz(pclk1 * timer_mul1), |
| 325 | FLASH | 284 | apb2_tim: Hertz(pclk2 * timer_mul2), |
| 326 | .acr() | ||
| 327 | .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); | ||
| 328 | }); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | 285 | ||
| 332 | pub(crate) unsafe fn init(config: Config) { | 286 | ahb1: Hertz(hclk), |
| 333 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 287 | ahb2: Hertz(hclk), |
| 334 | let clocks = Rcc::new(r, config).freeze(); | 288 | ahb3: Hertz(hclk), |
| 335 | set_freqs(clocks); | 289 | |
| 290 | pll48: plls.pll48clk.map(Hertz), | ||
| 291 | }); | ||
| 336 | } | 292 | } |
| 337 | 293 | ||
| 338 | struct PllResults { | 294 | struct PllResults { |
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index df11ff36d..a3a4c197f 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs | |||
| @@ -1,11 +1,7 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::{PWR, RCC}; |
| 2 | use crate::peripherals::{self, RCC}; | 2 | use crate::rcc::{set_freqs, Clocks}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | 3 | use crate::time::Hertz; |
| 5 | use crate::time::U32Ext; | 4 | use crate::time::U32Ext; |
| 6 | use core::marker::PhantomData; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy_hal_common::unborrow; | ||
| 9 | 5 | ||
| 10 | /// HSI speed | 6 | /// HSI speed |
| 11 | pub const HSI_FREQ: u32 = 16_000_000; | 7 | pub const HSI_FREQ: u32 = 16_000_000; |
| @@ -120,115 +116,68 @@ impl Default for Config { | |||
| 120 | } | 116 | } |
| 121 | } | 117 | } |
| 122 | 118 | ||
| 123 | /// RCC peripheral | 119 | pub(crate) unsafe fn init(config: Config) { |
| 124 | pub struct Rcc<'d> { | 120 | let (sys_clk, sw) = match config.mux { |
| 125 | _rb: peripherals::RCC, | 121 | ClockSrc::HSI16(div) => { |
| 126 | phantom: PhantomData<&'d mut peripherals::RCC>, | 122 | // Enable HSI16 |
| 127 | } | 123 | let div: u8 = div.into(); |
| 124 | RCC.cr().write(|w| { | ||
| 125 | w.set_hsidiv(div); | ||
| 126 | w.set_hsion(true) | ||
| 127 | }); | ||
| 128 | while !RCC.cr().read().hsirdy() {} | ||
| 128 | 129 | ||
| 129 | impl<'d> Rcc<'d> { | 130 | (HSI_FREQ >> div, 0x00) |
| 130 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 131 | unborrow!(rcc); | ||
| 132 | Self { | ||
| 133 | _rb: rcc, | ||
| 134 | phantom: PhantomData, | ||
| 135 | } | 131 | } |
| 136 | } | 132 | ClockSrc::HSE(freq) => { |
| 137 | 133 | // Enable HSE | |
| 138 | // Safety: RCC init must have been called | 134 | RCC.cr().write(|w| w.set_hseon(true)); |
| 139 | pub fn clocks(&self) -> &'static Clocks { | 135 | while !RCC.cr().read().hserdy() {} |
| 140 | unsafe { get_freqs() } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 145 | pub trait RccExt { | ||
| 146 | fn freeze(self, config: Config) -> Clocks; | ||
| 147 | } | ||
| 148 | 136 | ||
| 149 | impl RccExt for RCC { | 137 | (freq.0, 0x01) |
| 150 | #[inline] | ||
| 151 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 152 | let rcc = pac::RCC; | ||
| 153 | let (sys_clk, sw) = match cfgr.mux { | ||
| 154 | ClockSrc::HSI16(div) => { | ||
| 155 | // Enable HSI16 | ||
| 156 | let div: u8 = div.into(); | ||
| 157 | unsafe { | ||
| 158 | rcc.cr().write(|w| { | ||
| 159 | w.set_hsidiv(div); | ||
| 160 | w.set_hsion(true) | ||
| 161 | }); | ||
| 162 | while !rcc.cr().read().hsirdy() {} | ||
| 163 | } | ||
| 164 | |||
| 165 | (HSI_FREQ >> div, 0x00) | ||
| 166 | } | ||
| 167 | ClockSrc::HSE(freq) => { | ||
| 168 | // Enable HSE | ||
| 169 | unsafe { | ||
| 170 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 171 | while !rcc.cr().read().hserdy() {} | ||
| 172 | } | ||
| 173 | |||
| 174 | (freq.0, 0x01) | ||
| 175 | } | ||
| 176 | ClockSrc::LSI => { | ||
| 177 | // Enable LSI | ||
| 178 | unsafe { | ||
| 179 | rcc.csr().write(|w| w.set_lsion(true)); | ||
| 180 | while !rcc.csr().read().lsirdy() {} | ||
| 181 | } | ||
| 182 | (LSI_FREQ, 0x03) | ||
| 183 | } | ||
| 184 | }; | ||
| 185 | |||
| 186 | unsafe { | ||
| 187 | rcc.cfgr().modify(|w| { | ||
| 188 | w.set_sw(sw.into()); | ||
| 189 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 190 | w.set_ppre(cfgr.apb_pre.into()); | ||
| 191 | }); | ||
| 192 | } | 138 | } |
| 193 | 139 | ClockSrc::LSI => { | |
| 194 | let ahb_freq: u32 = match cfgr.ahb_pre { | 140 | // Enable LSI |
| 195 | AHBPrescaler::NotDivided => sys_clk, | 141 | RCC.csr().write(|w| w.set_lsion(true)); |
| 196 | pre => { | 142 | while !RCC.csr().read().lsirdy() {} |
| 197 | let pre: u8 = pre.into(); | 143 | (LSI_FREQ, 0x03) |
| 198 | let pre = 1 << (pre as u32 - 7); | ||
| 199 | sys_clk / pre | ||
| 200 | } | ||
| 201 | }; | ||
| 202 | |||
| 203 | let (apb_freq, apb_tim_freq) = match cfgr.apb_pre { | ||
| 204 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 205 | pre => { | ||
| 206 | let pre: u8 = pre.into(); | ||
| 207 | let pre: u8 = 1 << (pre - 3); | ||
| 208 | let freq = ahb_freq / pre as u32; | ||
| 209 | (freq, freq * 2) | ||
| 210 | } | ||
| 211 | }; | ||
| 212 | |||
| 213 | let pwr = pac::PWR; | ||
| 214 | if cfgr.low_power_run { | ||
| 215 | assert!(sys_clk.hz() <= 2_000_000.hz()); | ||
| 216 | unsafe { | ||
| 217 | pwr.cr1().modify(|w| w.set_lpr(true)); | ||
| 218 | } | ||
| 219 | } | 144 | } |
| 220 | 145 | }; | |
| 221 | Clocks { | 146 | |
| 222 | sys: sys_clk.hz(), | 147 | RCC.cfgr().modify(|w| { |
| 223 | ahb: ahb_freq.hz(), | 148 | w.set_sw(sw.into()); |
| 224 | apb: apb_freq.hz(), | 149 | w.set_hpre(config.ahb_pre.into()); |
| 225 | apb_tim: apb_tim_freq.hz(), | 150 | w.set_ppre(config.apb_pre.into()); |
| 151 | }); | ||
| 152 | |||
| 153 | let ahb_freq: u32 = match config.ahb_pre { | ||
| 154 | AHBPrescaler::NotDivided => sys_clk, | ||
| 155 | pre => { | ||
| 156 | let pre: u8 = pre.into(); | ||
| 157 | let pre = 1 << (pre as u32 - 7); | ||
| 158 | sys_clk / pre | ||
| 226 | } | 159 | } |
| 160 | }; | ||
| 161 | |||
| 162 | let (apb_freq, apb_tim_freq) = match config.apb_pre { | ||
| 163 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 164 | pre => { | ||
| 165 | let pre: u8 = pre.into(); | ||
| 166 | let pre: u8 = 1 << (pre - 3); | ||
| 167 | let freq = ahb_freq / pre as u32; | ||
| 168 | (freq, freq * 2) | ||
| 169 | } | ||
| 170 | }; | ||
| 171 | |||
| 172 | if config.low_power_run { | ||
| 173 | assert!(sys_clk.hz() <= 2_000_000.hz()); | ||
| 174 | PWR.cr1().modify(|w| w.set_lpr(true)); | ||
| 227 | } | 175 | } |
| 228 | } | ||
| 229 | 176 | ||
| 230 | pub(crate) unsafe fn init(config: Config) { | 177 | set_freqs(Clocks { |
| 231 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 178 | sys: sys_clk.hz(), |
| 232 | let clocks = r.freeze(config); | 179 | ahb: ahb_freq.hz(), |
| 233 | set_freqs(clocks); | 180 | apb: apb_freq.hz(), |
| 181 | apb_tim: apb_tim_freq.hz(), | ||
| 182 | }); | ||
| 234 | } | 183 | } |
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index ee49e2ece..ce8cca45d 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs | |||
| @@ -1,11 +1,7 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::{PWR, RCC}; |
| 2 | use crate::peripherals::{self, RCC}; | 2 | use crate::rcc::{set_freqs, Clocks}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | 3 | use crate::time::Hertz; |
| 5 | use crate::time::U32Ext; | 4 | use crate::time::U32Ext; |
| 6 | use core::marker::PhantomData; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy_hal_common::unborrow; | ||
| 9 | 5 | ||
| 10 | /// HSI speed | 6 | /// HSI speed |
| 11 | pub const HSI_FREQ: u32 = 16_000_000; | 7 | pub const HSI_FREQ: u32 = 16_000_000; |
| @@ -94,117 +90,72 @@ impl Default for Config { | |||
| 94 | } | 90 | } |
| 95 | } | 91 | } |
| 96 | 92 | ||
| 97 | /// RCC peripheral | 93 | pub(crate) unsafe fn init(config: Config) { |
| 98 | pub struct Rcc<'d> { | 94 | let (sys_clk, sw) = match config.mux { |
| 99 | _rb: peripherals::RCC, | 95 | ClockSrc::HSI16 => { |
| 100 | phantom: PhantomData<&'d mut peripherals::RCC>, | 96 | // Enable HSI16 |
| 101 | } | 97 | RCC.cr().write(|w| w.set_hsion(true)); |
| 98 | while !RCC.cr().read().hsirdy() {} | ||
| 102 | 99 | ||
| 103 | impl<'d> Rcc<'d> { | 100 | (HSI_FREQ, 0x01) |
| 104 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 105 | unborrow!(rcc); | ||
| 106 | Self { | ||
| 107 | _rb: rcc, | ||
| 108 | phantom: PhantomData, | ||
| 109 | } | 101 | } |
| 110 | } | 102 | ClockSrc::HSE(freq) => { |
| 111 | 103 | // Enable HSE | |
| 112 | // Safety: RCC init must have been called | 104 | RCC.cr().write(|w| w.set_hseon(true)); |
| 113 | pub fn clocks(&self) -> &'static Clocks { | 105 | while !RCC.cr().read().hserdy() {} |
| 114 | unsafe { get_freqs() } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 119 | pub trait RccExt { | ||
| 120 | fn freeze(self, config: Config) -> Clocks; | ||
| 121 | } | ||
| 122 | 106 | ||
| 123 | impl RccExt for RCC { | 107 | (freq.0, 0x02) |
| 124 | #[inline] | ||
| 125 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 126 | let rcc = pac::RCC; | ||
| 127 | let (sys_clk, sw) = match cfgr.mux { | ||
| 128 | ClockSrc::HSI16 => { | ||
| 129 | // Enable HSI16 | ||
| 130 | unsafe { | ||
| 131 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 132 | while !rcc.cr().read().hsirdy() {} | ||
| 133 | } | ||
| 134 | |||
| 135 | (HSI_FREQ, 0x01) | ||
| 136 | } | ||
| 137 | ClockSrc::HSE(freq) => { | ||
| 138 | // Enable HSE | ||
| 139 | unsafe { | ||
| 140 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 141 | while !rcc.cr().read().hserdy() {} | ||
| 142 | } | ||
| 143 | |||
| 144 | (freq.0, 0x02) | ||
| 145 | } | ||
| 146 | }; | ||
| 147 | |||
| 148 | unsafe { | ||
| 149 | rcc.cfgr().modify(|w| { | ||
| 150 | w.set_sw(sw.into()); | ||
| 151 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 152 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 153 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 154 | }); | ||
| 155 | } | 108 | } |
| 156 | 109 | }; | |
| 157 | let ahb_freq: u32 = match cfgr.ahb_pre { | 110 | |
| 158 | AHBPrescaler::NotDivided => sys_clk, | 111 | RCC.cfgr().modify(|w| { |
| 159 | pre => { | 112 | w.set_sw(sw.into()); |
| 160 | let pre: u8 = pre.into(); | 113 | w.set_hpre(config.ahb_pre.into()); |
| 161 | let pre = 1 << (pre as u32 - 7); | 114 | w.set_ppre1(config.apb1_pre.into()); |
| 162 | sys_clk / pre | 115 | w.set_ppre2(config.apb2_pre.into()); |
| 163 | } | 116 | }); |
| 164 | }; | 117 | |
| 165 | 118 | let ahb_freq: u32 = match config.ahb_pre { | |
| 166 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | 119 | AHBPrescaler::NotDivided => sys_clk, |
| 167 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 120 | pre => { |
| 168 | pre => { | 121 | let pre: u8 = pre.into(); |
| 169 | let pre: u8 = pre.into(); | 122 | let pre = 1 << (pre as u32 - 7); |
| 170 | let pre: u8 = 1 << (pre - 3); | 123 | sys_clk / pre |
| 171 | let freq = ahb_freq / pre as u32; | ||
| 172 | (freq, freq * 2) | ||
| 173 | } | ||
| 174 | }; | ||
| 175 | |||
| 176 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | ||
| 177 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 178 | pre => { | ||
| 179 | let pre: u8 = pre.into(); | ||
| 180 | let pre: u8 = 1 << (pre - 3); | ||
| 181 | let freq = ahb_freq / pre as u32; | ||
| 182 | (freq, freq * 2) | ||
| 183 | } | ||
| 184 | }; | ||
| 185 | |||
| 186 | let pwr = pac::PWR; | ||
| 187 | if cfgr.low_power_run { | ||
| 188 | assert!(sys_clk.hz() <= 2_000_000.hz()); | ||
| 189 | unsafe { | ||
| 190 | pwr.cr1().modify(|w| w.set_lpr(true)); | ||
| 191 | } | ||
| 192 | } | 124 | } |
| 193 | 125 | }; | |
| 194 | Clocks { | 126 | |
| 195 | sys: sys_clk.hz(), | 127 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 196 | ahb1: ahb_freq.hz(), | 128 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |
| 197 | ahb2: ahb_freq.hz(), | 129 | pre => { |
| 198 | apb1: apb1_freq.hz(), | 130 | let pre: u8 = pre.into(); |
| 199 | apb1_tim: apb1_tim_freq.hz(), | 131 | let pre: u8 = 1 << (pre - 3); |
| 200 | apb2: apb2_freq.hz(), | 132 | let freq = ahb_freq / pre as u32; |
| 201 | apb2_tim: apb2_tim_freq.hz(), | 133 | (freq, freq * 2) |
| 134 | } | ||
| 135 | }; | ||
| 136 | |||
| 137 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 138 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 139 | pre => { | ||
| 140 | let pre: u8 = pre.into(); | ||
| 141 | let pre: u8 = 1 << (pre - 3); | ||
| 142 | let freq = ahb_freq / pre as u32; | ||
| 143 | (freq, freq * 2) | ||
| 202 | } | 144 | } |
| 145 | }; | ||
| 146 | |||
| 147 | if config.low_power_run { | ||
| 148 | assert!(sys_clk.hz() <= 2_000_000.hz()); | ||
| 149 | PWR.cr1().modify(|w| w.set_lpr(true)); | ||
| 203 | } | 150 | } |
| 204 | } | ||
| 205 | 151 | ||
| 206 | pub(crate) unsafe fn init(config: Config) { | 152 | set_freqs(Clocks { |
| 207 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 153 | sys: sys_clk.hz(), |
| 208 | let clocks = r.freeze(config); | 154 | ahb1: ahb_freq.hz(), |
| 209 | set_freqs(clocks); | 155 | ahb2: ahb_freq.hz(), |
| 156 | apb1: apb1_freq.hz(), | ||
| 157 | apb1_tim: apb1_tim_freq.hz(), | ||
| 158 | apb2: apb2_freq.hz(), | ||
| 159 | apb2_tim: apb2_tim_freq.hz(), | ||
| 160 | }); | ||
| 210 | } | 161 | } |
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index ac4d033ba..55ddf073a 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs | |||
| @@ -7,9 +7,9 @@ use stm32_metapac::rcc::vals::{Mco1, Mco2}; | |||
| 7 | use crate::gpio::sealed::Pin as __GpioPin; | 7 | use crate::gpio::sealed::Pin as __GpioPin; |
| 8 | use crate::gpio::Pin; | 8 | use crate::gpio::Pin; |
| 9 | use crate::pac::rcc::vals::Timpre; | 9 | use crate::pac::rcc::vals::Timpre; |
| 10 | use crate::pac::{RCC, SYSCFG}; | 10 | use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw}; |
| 11 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 11 | use crate::peripherals; | 12 | use crate::peripherals; |
| 12 | use crate::pwr::{Power, VoltageScale}; | ||
| 13 | use crate::rcc::{set_freqs, Clocks}; | 13 | use crate::rcc::{set_freqs, Clocks}; |
| 14 | use crate::time::Hertz; | 14 | use crate::time::Hertz; |
| 15 | 15 | ||
| @@ -20,6 +20,22 @@ const CSI: Hertz = Hertz(4_000_000); | |||
| 20 | const HSI48: Hertz = Hertz(48_000_000); | 20 | const HSI48: Hertz = Hertz(48_000_000); |
| 21 | const LSI: Hertz = Hertz(32_000); | 21 | const LSI: Hertz = Hertz(32_000); |
| 22 | 22 | ||
| 23 | /// Voltage Scale | ||
| 24 | /// | ||
| 25 | /// Represents the voltage range feeding the CPU core. The maximum core | ||
| 26 | /// clock frequency depends on this value. | ||
| 27 | #[derive(Copy, Clone, PartialEq)] | ||
| 28 | pub enum VoltageScale { | ||
| 29 | /// VOS 0 range VCORE 1.26V - 1.40V | ||
| 30 | Scale0, | ||
| 31 | /// VOS 1 range VCORE 1.15V - 1.26V | ||
| 32 | Scale1, | ||
| 33 | /// VOS 2 range VCORE 1.05V - 1.15V | ||
| 34 | Scale2, | ||
| 35 | /// VOS 3 range VCORE 0.95V - 1.05V | ||
| 36 | Scale3, | ||
| 37 | } | ||
| 38 | |||
| 23 | /// Core clock frequencies | 39 | /// Core clock frequencies |
| 24 | #[derive(Clone, Copy)] | 40 | #[derive(Clone, Copy)] |
| 25 | pub struct CoreClocks { | 41 | pub struct CoreClocks { |
| @@ -72,439 +88,151 @@ pub struct Config { | |||
| 72 | pub pll3: PllConfig, | 88 | pub pll3: PllConfig, |
| 73 | } | 89 | } |
| 74 | 90 | ||
| 75 | pub struct Rcc<'d> { | 91 | /// Setup traceclk |
| 76 | inner: PhantomData<&'d ()>, | 92 | /// Returns a pll1_r_ck |
| 77 | config: Config, | 93 | fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) { |
| 94 | let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) { | ||
| 95 | // pll1_p_ck selected as system clock but pll1_r_ck not | ||
| 96 | // set. The traceclk mux is synchronous with the system | ||
| 97 | // clock mux, but has pll1_r_ck as an input. In order to | ||
| 98 | // keep traceclk running, we force a pll1_r_ck. | ||
| 99 | (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)), | ||
| 100 | |||
| 101 | // Either pll1 not selected as system clock, free choice | ||
| 102 | // of pll1_r_ck. Or pll1 is selected, assume user has set | ||
| 103 | // a suitable pll1_r_ck frequency. | ||
| 104 | _ => config.pll1.r_ck, | ||
| 105 | }; | ||
| 106 | config.pll1.r_ck = pll1_r_ck; | ||
| 78 | } | 107 | } |
| 79 | 108 | ||
| 80 | impl<'d> Rcc<'d> { | 109 | /// Divider calculator for pclk 1 - 4 |
| 81 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | 110 | /// |
| 82 | Self { | 111 | /// Returns real pclk, bits, ppre and the timer kernel clock |
| 83 | inner: PhantomData, | 112 | fn ppre_calculate( |
| 84 | config, | 113 | requested_pclk: u32, |
| 85 | } | 114 | hclk: u32, |
| 86 | } | 115 | max_pclk: u32, |
| 87 | 116 | tim_pre: Option<Timpre>, | |
| 88 | /// Freeze the core clocks, returning a Core Clocks Distribution | 117 | ) -> (u32, u8, u8, Option<u32>) { |
| 89 | /// and Reset (CCDR) structure. The actual frequency of the clocks | 118 | let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { |
| 90 | /// configured is returned in the `clocks` member of the CCDR | 119 | 0 => panic!(), |
| 91 | /// structure. | 120 | 1 => (0b000, 1), |
| 92 | /// | 121 | 2 => (0b100, 2), |
| 93 | /// Note that `freeze` will never result in a clock _faster_ than | 122 | 3..=5 => (0b101, 4), |
| 94 | /// that specified. It may result in a clock that is a factor of [1, | 123 | 6..=11 => (0b110, 8), |
| 95 | /// 2) slower. | 124 | _ => (0b111, 16), |
| 96 | /// | 125 | }; |
| 97 | /// `syscfg` is required to enable the I/O compensation cell. | 126 | let real_pclk = hclk / u32::from(ppre); |
| 98 | /// | 127 | assert!(real_pclk <= max_pclk); |
| 99 | /// # Panics | 128 | |
| 100 | /// | 129 | let tim_ker_clk = if let Some(tim_pre) = tim_pre { |
| 101 | /// If a clock specification cannot be achieved within the | 130 | let clk = match (bits, tim_pre) { |
| 102 | /// hardware specification then this function will panic. This | 131 | (0b101, Timpre::DEFAULTX2) => hclk / 2, |
| 103 | /// function may also panic if a clock specification can be | 132 | (0b110, Timpre::DEFAULTX4) => hclk / 2, |
| 104 | /// achieved, but the mechanism for doing so is not yet | 133 | (0b110, Timpre::DEFAULTX2) => hclk / 4, |
| 105 | /// implemented here. | 134 | (0b111, Timpre::DEFAULTX4) => hclk / 4, |
| 106 | pub fn freeze(mut self, pwr: &Power) -> CoreClocks { | 135 | (0b111, Timpre::DEFAULTX2) => hclk / 8, |
| 107 | use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw}; | 136 | _ => hclk, |
| 108 | |||
| 109 | let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks | ||
| 110 | let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk); | ||
| 111 | |||
| 112 | // Configure traceclk from PLL if needed | ||
| 113 | self.traceclk_setup(sys_use_pll1_p); | ||
| 114 | |||
| 115 | // NOTE(unsafe) We have exclusive access to the RCC | ||
| 116 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = | ||
| 117 | unsafe { pll::pll_setup(srcclk.0, &self.config.pll1, 0) }; | ||
| 118 | let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = | ||
| 119 | unsafe { pll::pll_setup(srcclk.0, &self.config.pll2, 1) }; | ||
| 120 | let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = | ||
| 121 | unsafe { pll::pll_setup(srcclk.0, &self.config.pll3, 2) }; | ||
| 122 | |||
| 123 | let sys_ck = if sys_use_pll1_p { | ||
| 124 | Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup | ||
| 125 | } else { | ||
| 126 | sys_ck | ||
| 127 | }; | ||
| 128 | |||
| 129 | // NOTE(unsafe) We own the regblock | ||
| 130 | unsafe { | ||
| 131 | // This routine does not support HSIDIV != 1. To | ||
| 132 | // do so it would need to ensure all PLLxON bits are clear | ||
| 133 | // before changing the value of HSIDIV | ||
| 134 | let cr = RCC.cr().read(); | ||
| 135 | assert!(cr.hsion()); | ||
| 136 | assert!(cr.hsidiv() == Hsidiv::DIV1); | ||
| 137 | |||
| 138 | RCC.csr().modify(|w| w.set_lsion(true)); | ||
| 139 | while !RCC.csr().read().lsirdy() {} | ||
| 140 | } | ||
| 141 | |||
| 142 | // per_ck from HSI by default | ||
| 143 | let (per_ck, ckpersel) = match (self.config.per_ck == self.config.hse, self.config.per_ck) { | ||
| 144 | (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE | ||
| 145 | (_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI | ||
| 146 | _ => (HSI, Ckpersel::HSI), // HSI | ||
| 147 | }; | ||
| 148 | |||
| 149 | // D1 Core Prescaler | ||
| 150 | // Set to 1 | ||
| 151 | let d1cpre_bits = 0; | ||
| 152 | let d1cpre_div = 1; | ||
| 153 | let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; | ||
| 154 | |||
| 155 | // Refer to part datasheet "General operating conditions" | ||
| 156 | // table for (rev V). We do not assert checks for earlier | ||
| 157 | // revisions which may have lower limits. | ||
| 158 | let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr.vos { | ||
| 159 | VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), | ||
| 160 | VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), | ||
| 161 | VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), | ||
| 162 | _ => (200_000_000, 100_000_000, 50_000_000), | ||
| 163 | }; | ||
| 164 | assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); | ||
| 165 | |||
| 166 | let rcc_hclk = self | ||
| 167 | .config | ||
| 168 | .rcc_hclk | ||
| 169 | .map(|v| v.0) | ||
| 170 | .unwrap_or(sys_d1cpre_ck / 2); | ||
| 171 | assert!(rcc_hclk <= rcc_hclk_max); | ||
| 172 | |||
| 173 | // Estimate divisor | ||
| 174 | let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { | ||
| 175 | 0 => panic!(), | ||
| 176 | 1 => (Hpre::DIV1, 1), | ||
| 177 | 2 => (Hpre::DIV2, 2), | ||
| 178 | 3..=5 => (Hpre::DIV4, 4), | ||
| 179 | 6..=11 => (Hpre::DIV8, 8), | ||
| 180 | 12..=39 => (Hpre::DIV16, 16), | ||
| 181 | 40..=95 => (Hpre::DIV64, 64), | ||
| 182 | 96..=191 => (Hpre::DIV128, 128), | ||
| 183 | 192..=383 => (Hpre::DIV256, 256), | ||
| 184 | _ => (Hpre::DIV512, 512), | ||
| 185 | }; | 137 | }; |
| 186 | // Calculate real AXI and AHB clock | 138 | Some(clk) |
| 187 | let rcc_hclk = sys_d1cpre_ck / hpre_div; | 139 | } else { |
| 188 | assert!(rcc_hclk <= rcc_hclk_max); | 140 | None |
| 189 | let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 | 141 | }; |
| 190 | // Timer prescaler selection | 142 | (real_pclk, bits, ppre, tim_ker_clk) |
| 191 | let timpre = Timpre::DEFAULTX2; | 143 | } |
| 192 | |||
| 193 | let requested_pclk1 = self | ||
| 194 | .config | ||
| 195 | .pclk1 | ||
| 196 | .map(|v| v.0) | ||
| 197 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 198 | let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = | ||
| 199 | Self::ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); | ||
| 200 | |||
| 201 | let requested_pclk2 = self | ||
| 202 | .config | ||
| 203 | .pclk2 | ||
| 204 | .map(|v| v.0) | ||
| 205 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 206 | let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = | ||
| 207 | Self::ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); | ||
| 208 | |||
| 209 | let requested_pclk3 = self | ||
| 210 | .config | ||
| 211 | .pclk3 | ||
| 212 | .map(|v| v.0) | ||
| 213 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 214 | let (rcc_pclk3, ppre3_bits, ppre3, _) = | ||
| 215 | Self::ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); | ||
| 216 | |||
| 217 | let requested_pclk4 = self | ||
| 218 | .config | ||
| 219 | .pclk4 | ||
| 220 | .map(|v| v.0) | ||
| 221 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 222 | let (rcc_pclk4, ppre4_bits, ppre4, _) = | ||
| 223 | Self::ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); | ||
| 224 | |||
| 225 | Self::flash_setup(rcc_aclk, pwr.vos); | ||
| 226 | |||
| 227 | // Start switching clocks ------------------- | ||
| 228 | // NOTE(unsafe) We have the RCC singleton | ||
| 229 | unsafe { | ||
| 230 | // Ensure CSI is on and stable | ||
| 231 | RCC.cr().modify(|w| w.set_csion(true)); | ||
| 232 | while !RCC.cr().read().csirdy() {} | ||
| 233 | |||
| 234 | // Ensure HSI48 is on and stable | ||
| 235 | RCC.cr().modify(|w| w.set_hsi48on(true)); | ||
| 236 | while !RCC.cr().read().hsi48on() {} | ||
| 237 | |||
| 238 | // XXX: support MCO ? | ||
| 239 | |||
| 240 | let hse_ck = match self.config.hse { | ||
| 241 | Some(hse) => { | ||
| 242 | // Ensure HSE is on and stable | ||
| 243 | RCC.cr().modify(|w| { | ||
| 244 | w.set_hseon(true); | ||
| 245 | w.set_hsebyp(if self.config.bypass_hse { | ||
| 246 | Hsebyp::BYPASSED | ||
| 247 | } else { | ||
| 248 | Hsebyp::NOTBYPASSED | ||
| 249 | }); | ||
| 250 | }); | ||
| 251 | while !RCC.cr().read().hserdy() {} | ||
| 252 | Some(hse) | ||
| 253 | } | ||
| 254 | None => None, | ||
| 255 | }; | ||
| 256 | |||
| 257 | let pllsrc = if self.config.hse.is_some() { | ||
| 258 | Pllsrc::HSE | ||
| 259 | } else { | ||
| 260 | Pllsrc::HSI | ||
| 261 | }; | ||
| 262 | RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); | ||
| 263 | |||
| 264 | let enable_pll = |pll| { | ||
| 265 | RCC.cr().modify(|w| w.set_pllon(pll, true)); | ||
| 266 | while !RCC.cr().read().pllrdy(pll) {} | ||
| 267 | }; | ||
| 268 | |||
| 269 | if pll1_p_ck.is_some() { | ||
| 270 | enable_pll(0); | ||
| 271 | } | ||
| 272 | |||
| 273 | if pll2_p_ck.is_some() { | ||
| 274 | enable_pll(1); | ||
| 275 | } | ||
| 276 | |||
| 277 | if pll3_p_ck.is_some() { | ||
| 278 | enable_pll(2); | ||
| 279 | } | ||
| 280 | |||
| 281 | // Core Prescaler / AHB Prescaler / APB3 Prescaler | ||
| 282 | RCC.d1cfgr().modify(|w| { | ||
| 283 | w.set_d1cpre(Hpre(d1cpre_bits)); | ||
| 284 | w.set_d1ppre(Dppre(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(Dppre(ppre1_bits)); | ||
| 294 | w.set_d2ppre2(Dppre(ppre2_bits)); | ||
| 295 | }); | ||
| 296 | |||
| 297 | // APB4 Prescaler | ||
| 298 | RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(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().modify(|w| w.set_syscfgen(true)); | ||
| 318 | 144 | ||
| 319 | // Enable the compensation cell, using back-bias voltage code | 145 | /// Setup sys_ck |
| 320 | // provide by the cell. | 146 | /// Returns sys_ck frequency, and a pll1_p_ck |
| 321 | critical_section::with(|_| { | 147 | fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) { |
| 322 | SYSCFG.cccsr().modify(|w| { | 148 | // Compare available with wanted clocks |
| 323 | w.set_en(true); | 149 | let sys_ck = config.sys_ck.unwrap_or(srcclk); |
| 324 | w.set_cs(false); | 150 | |
| 325 | w.set_hslv(false); | 151 | if sys_ck != srcclk { |
| 326 | }) | 152 | // The requested system clock is not the immediately available |
| 327 | }); | 153 | // HSE/HSI clock. Perhaps there are other ways of obtaining |
| 328 | while !SYSCFG.cccsr().read().ready() {} | 154 | // the requested system clock (such as `HSIDIV`) but we will |
| 329 | 155 | // ignore those for now. | |
| 330 | CoreClocks { | 156 | // |
| 331 | hclk: Hertz(rcc_hclk), | 157 | // Therefore we must use pll1_p_ck |
| 332 | pclk1: Hertz(rcc_pclk1), | 158 | let pll1_p_ck = match config.pll1.p_ck { |
| 333 | pclk2: Hertz(rcc_pclk2), | 159 | Some(p_ck) => { |
| 334 | pclk3: Hertz(rcc_pclk3), | 160 | assert!(p_ck == sys_ck, |
| 335 | pclk4: Hertz(rcc_pclk4), | 161 | "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"); |
| 336 | ppre1, | 162 | Some(p_ck) |
| 337 | ppre2, | ||
| 338 | ppre3, | ||
| 339 | ppre4, | ||
| 340 | csi_ck: Some(CSI), | ||
| 341 | hsi_ck: Some(HSI), | ||
| 342 | hsi48_ck: Some(HSI48), | ||
| 343 | lsi_ck: Some(LSI), | ||
| 344 | per_ck: Some(per_ck), | ||
| 345 | hse_ck, | ||
| 346 | pll1_p_ck: pll1_p_ck.map(Hertz), | ||
| 347 | pll1_q_ck: pll1_q_ck.map(Hertz), | ||
| 348 | pll1_r_ck: pll1_r_ck.map(Hertz), | ||
| 349 | pll2_p_ck: pll2_p_ck.map(Hertz), | ||
| 350 | pll2_q_ck: pll2_q_ck.map(Hertz), | ||
| 351 | pll2_r_ck: pll2_r_ck.map(Hertz), | ||
| 352 | pll3_p_ck: pll3_p_ck.map(Hertz), | ||
| 353 | pll3_q_ck: pll3_q_ck.map(Hertz), | ||
| 354 | pll3_r_ck: pll3_r_ck.map(Hertz), | ||
| 355 | timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), | ||
| 356 | timy_ker_ck: rcc_timery_ker_ck.map(Hertz), | ||
| 357 | sys_ck, | ||
| 358 | c_ck: Hertz(sys_d1cpre_ck), | ||
| 359 | } | 163 | } |
| 360 | } | 164 | None => Some(sys_ck), |
| 361 | } | ||
| 362 | |||
| 363 | /// Setup traceclk | ||
| 364 | /// Returns a pll1_r_ck | ||
| 365 | fn traceclk_setup(&mut self, sys_use_pll1_p: bool) { | ||
| 366 | let pll1_r_ck = match (sys_use_pll1_p, self.config.pll1.r_ck) { | ||
| 367 | // pll1_p_ck selected as system clock but pll1_r_ck not | ||
| 368 | // set. The traceclk mux is synchronous with the system | ||
| 369 | // clock mux, but has pll1_r_ck as an input. In order to | ||
| 370 | // keep traceclk running, we force a pll1_r_ck. | ||
| 371 | (true, None) => Some(Hertz(unwrap!(self.config.pll1.p_ck).0 / 2)), | ||
| 372 | |||
| 373 | // Either pll1 not selected as system clock, free choice | ||
| 374 | // of pll1_r_ck. Or pll1 is selected, assume user has set | ||
| 375 | // a suitable pll1_r_ck frequency. | ||
| 376 | _ => self.config.pll1.r_ck, | ||
| 377 | }; | ||
| 378 | self.config.pll1.r_ck = pll1_r_ck; | ||
| 379 | } | ||
| 380 | |||
| 381 | /// Divider calculator for pclk 1 - 4 | ||
| 382 | /// | ||
| 383 | /// Returns real pclk, bits, ppre and the timer kernel clock | ||
| 384 | fn ppre_calculate( | ||
| 385 | requested_pclk: u32, | ||
| 386 | hclk: u32, | ||
| 387 | max_pclk: u32, | ||
| 388 | tim_pre: Option<Timpre>, | ||
| 389 | ) -> (u32, u8, u8, Option<u32>) { | ||
| 390 | let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk { | ||
| 391 | 0 => panic!(), | ||
| 392 | 1 => (0b000, 1), | ||
| 393 | 2 => (0b100, 2), | ||
| 394 | 3..=5 => (0b101, 4), | ||
| 395 | 6..=11 => (0b110, 8), | ||
| 396 | _ => (0b111, 16), | ||
| 397 | }; | ||
| 398 | let real_pclk = hclk / u32::from(ppre); | ||
| 399 | assert!(real_pclk <= max_pclk); | ||
| 400 | |||
| 401 | let tim_ker_clk = if let Some(tim_pre) = tim_pre { | ||
| 402 | let clk = match (bits, tim_pre) { | ||
| 403 | (0b101, Timpre::DEFAULTX2) => hclk / 2, | ||
| 404 | (0b110, Timpre::DEFAULTX4) => hclk / 2, | ||
| 405 | (0b110, Timpre::DEFAULTX2) => hclk / 4, | ||
| 406 | (0b111, Timpre::DEFAULTX4) => hclk / 4, | ||
| 407 | (0b111, Timpre::DEFAULTX2) => hclk / 8, | ||
| 408 | _ => hclk, | ||
| 409 | }; | ||
| 410 | Some(clk) | ||
| 411 | } else { | ||
| 412 | None | ||
| 413 | }; | 165 | }; |
| 414 | (real_pclk, bits, ppre, tim_ker_clk) | 166 | config.pll1.p_ck = pll1_p_ck; |
| 415 | } | ||
| 416 | 167 | ||
| 417 | /// Setup sys_ck | 168 | (sys_ck, true) |
| 418 | /// Returns sys_ck frequency, and a pll1_p_ck | 169 | } else { |
| 419 | fn sys_ck_setup(&mut self, srcclk: Hertz) -> (Hertz, bool) { | 170 | // sys_ck is derived directly from a source clock |
| 420 | // Compare available with wanted clocks | 171 | // (HSE/HSI). pll1_p_ck can be as requested |
| 421 | let sys_ck = self.config.sys_ck.unwrap_or(srcclk); | 172 | (sys_ck, false) |
| 422 | |||
| 423 | if sys_ck != srcclk { | ||
| 424 | // The requested system clock is not the immediately available | ||
| 425 | // HSE/HSI clock. Perhaps there are other ways of obtaining | ||
| 426 | // the requested system clock (such as `HSIDIV`) but we will | ||
| 427 | // ignore those for now. | ||
| 428 | // | ||
| 429 | // Therefore we must use pll1_p_ck | ||
| 430 | let pll1_p_ck = match self.config.pll1.p_ck { | ||
| 431 | Some(p_ck) => { | ||
| 432 | assert!(p_ck == sys_ck, | ||
| 433 | "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"); | ||
| 434 | Some(p_ck) | ||
| 435 | } | ||
| 436 | None => Some(sys_ck), | ||
| 437 | }; | ||
| 438 | self.config.pll1.p_ck = pll1_p_ck; | ||
| 439 | |||
| 440 | (sys_ck, true) | ||
| 441 | } else { | ||
| 442 | // sys_ck is derived directly from a source clock | ||
| 443 | // (HSE/HSI). pll1_p_ck can be as requested | ||
| 444 | (sys_ck, false) | ||
| 445 | } | ||
| 446 | } | 173 | } |
| 174 | } | ||
| 447 | 175 | ||
| 448 | fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | 176 | fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { |
| 449 | use crate::pac::FLASH; | 177 | use crate::pac::FLASH; |
| 450 | 178 | ||
| 451 | // ACLK in MHz, round down and subtract 1 from integers. eg. | 179 | // ACLK in MHz, round down and subtract 1 from integers. eg. |
| 452 | // 61_999_999 -> 61MHz | 180 | // 61_999_999 -> 61MHz |
| 453 | // 62_000_000 -> 61MHz | 181 | // 62_000_000 -> 61MHz |
| 454 | // 62_000_001 -> 62MHz | 182 | // 62_000_001 -> 62MHz |
| 455 | let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; | 183 | let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000; |
| 456 | 184 | ||
| 457 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait | 185 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait |
| 458 | // states and programming delay | 186 | // states and programming delay |
| 459 | let (wait_states, progr_delay) = match vos { | 187 | let (wait_states, progr_delay) = match vos { |
| 460 | // VOS 0 range VCORE 1.26V - 1.40V | 188 | // VOS 0 range VCORE 1.26V - 1.40V |
| 461 | VoltageScale::Scale0 => match rcc_aclk_mhz { | 189 | VoltageScale::Scale0 => match rcc_aclk_mhz { |
| 462 | 0..=69 => (0, 0), | 190 | 0..=69 => (0, 0), |
| 463 | 70..=139 => (1, 1), | 191 | 70..=139 => (1, 1), |
| 464 | 140..=184 => (2, 1), | 192 | 140..=184 => (2, 1), |
| 465 | 185..=209 => (2, 2), | 193 | 185..=209 => (2, 2), |
| 466 | 210..=224 => (3, 2), | 194 | 210..=224 => (3, 2), |
| 467 | 225..=239 => (4, 2), | 195 | 225..=239 => (4, 2), |
| 468 | _ => (7, 3), | 196 | _ => (7, 3), |
| 469 | }, | 197 | }, |
| 470 | // VOS 1 range VCORE 1.15V - 1.26V | 198 | // VOS 1 range VCORE 1.15V - 1.26V |
| 471 | VoltageScale::Scale1 => match rcc_aclk_mhz { | 199 | VoltageScale::Scale1 => match rcc_aclk_mhz { |
| 472 | 0..=69 => (0, 0), | 200 | 0..=69 => (0, 0), |
| 473 | 70..=139 => (1, 1), | 201 | 70..=139 => (1, 1), |
| 474 | 140..=184 => (2, 1), | 202 | 140..=184 => (2, 1), |
| 475 | 185..=209 => (2, 2), | 203 | 185..=209 => (2, 2), |
| 476 | 210..=224 => (3, 2), | 204 | 210..=224 => (3, 2), |
| 477 | _ => (7, 3), | 205 | _ => (7, 3), |
| 478 | }, | 206 | }, |
| 479 | // VOS 2 range VCORE 1.05V - 1.15V | 207 | // VOS 2 range VCORE 1.05V - 1.15V |
| 480 | VoltageScale::Scale2 => match rcc_aclk_mhz { | 208 | VoltageScale::Scale2 => match rcc_aclk_mhz { |
| 481 | 0..=54 => (0, 0), | 209 | 0..=54 => (0, 0), |
| 482 | 55..=109 => (1, 1), | 210 | 55..=109 => (1, 1), |
| 483 | 110..=164 => (2, 1), | 211 | 110..=164 => (2, 1), |
| 484 | 165..=224 => (3, 2), | 212 | 165..=224 => (3, 2), |
| 485 | _ => (7, 3), | 213 | _ => (7, 3), |
| 486 | }, | 214 | }, |
| 487 | // VOS 3 range VCORE 0.95V - 1.05V | 215 | // VOS 3 range VCORE 0.95V - 1.05V |
| 488 | VoltageScale::Scale3 => match rcc_aclk_mhz { | 216 | VoltageScale::Scale3 => match rcc_aclk_mhz { |
| 489 | 0..=44 => (0, 0), | 217 | 0..=44 => (0, 0), |
| 490 | 45..=89 => (1, 1), | 218 | 45..=89 => (1, 1), |
| 491 | 90..=134 => (2, 1), | 219 | 90..=134 => (2, 1), |
| 492 | 135..=179 => (3, 2), | 220 | 135..=179 => (3, 2), |
| 493 | 180..=224 => (4, 2), | 221 | 180..=224 => (4, 2), |
| 494 | _ => (7, 3), | 222 | _ => (7, 3), |
| 495 | }, | 223 | }, |
| 496 | }; | 224 | }; |
| 497 | 225 | ||
| 498 | // NOTE(unsafe) Atomic write | 226 | // NOTE(unsafe) Atomic write |
| 499 | unsafe { | 227 | unsafe { |
| 500 | FLASH.acr().write(|w| { | 228 | FLASH.acr().write(|w| { |
| 501 | w.set_wrhighfreq(progr_delay); | 229 | w.set_wrhighfreq(progr_delay); |
| 502 | w.set_latency(wait_states) | 230 | w.set_latency(wait_states) |
| 503 | }); | 231 | }); |
| 504 | while FLASH.acr().read().latency() != wait_states {} | 232 | while FLASH.acr().read().latency() != wait_states {} |
| 505 | } | ||
| 506 | } | 233 | } |
| 507 | } | 234 | } |
| 235 | |||
| 508 | pub enum McoClock { | 236 | pub enum McoClock { |
| 509 | Disabled, | 237 | Disabled, |
| 510 | Bypassed, | 238 | Bypassed, |
| @@ -681,10 +409,309 @@ impl<'d, T: McoInstance> Mco<'d, T> { | |||
| 681 | } | 409 | } |
| 682 | } | 410 | } |
| 683 | 411 | ||
| 684 | pub(crate) unsafe fn init(config: Config) { | 412 | pub(crate) unsafe fn init(mut config: Config) { |
| 685 | let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false); | 413 | // TODO make configurable? |
| 686 | let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); | 414 | let enable_overdrive = false; |
| 687 | let core_clocks = rcc.freeze(&mut power); | 415 | |
| 416 | // NB. The lower bytes of CR3 can only be written once after | ||
| 417 | // POR, and must be written with a valid combination. Refer to | ||
| 418 | // RM0433 Rev 7 6.8.4. This is partially enforced by dropping | ||
| 419 | // `self` at the end of this method, but of course we cannot | ||
| 420 | // know what happened between the previous POR and here. | ||
| 421 | #[cfg(pwr_h7)] | ||
| 422 | PWR.cr3().modify(|w| { | ||
| 423 | w.set_scuen(true); | ||
| 424 | w.set_ldoen(true); | ||
| 425 | w.set_bypass(false); | ||
| 426 | }); | ||
| 427 | |||
| 428 | #[cfg(pwr_h7smps)] | ||
| 429 | PWR.cr3().modify(|w| { | ||
| 430 | // hardcode "Direct SPMS" for now, this is what works on nucleos with the | ||
| 431 | // default solderbridge configuration. | ||
| 432 | w.set_sden(true); | ||
| 433 | w.set_ldoen(false); | ||
| 434 | }); | ||
| 435 | |||
| 436 | // Validate the supply configuration. If you are stuck here, it is | ||
| 437 | // because the voltages on your board do not match those specified | ||
| 438 | // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset | ||
| 439 | // VOS = Scale 3, so check that the voltage on the VCAP pins = | ||
| 440 | // 1.0V. | ||
| 441 | while !PWR.csr1().read().actvosrdy() {} | ||
| 442 | |||
| 443 | // Go to Scale 1 | ||
| 444 | PWR.d3cr().modify(|w| w.set_vos(0b11)); | ||
| 445 | while !PWR.d3cr().read().vosrdy() {} | ||
| 446 | |||
| 447 | let pwr_vos = if !enable_overdrive { | ||
| 448 | VoltageScale::Scale1 | ||
| 449 | } else { | ||
| 450 | critical_section::with(|_| { | ||
| 451 | RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||
| 452 | |||
| 453 | SYSCFG.pwrcr().modify(|w| w.set_oden(1)); | ||
| 454 | }); | ||
| 455 | while !PWR.d3cr().read().vosrdy() {} | ||
| 456 | VoltageScale::Scale0 | ||
| 457 | }; | ||
| 458 | |||
| 459 | // Freeze the core clocks, returning a Core Clocks Distribution | ||
| 460 | // and Reset (CCDR) structure. The actual frequency of the clocks | ||
| 461 | // configured is returned in the `clocks` member of the CCDR | ||
| 462 | // structure. | ||
| 463 | // | ||
| 464 | // Note that `freeze` will never result in a clock _faster_ than | ||
| 465 | // that specified. It may result in a clock that is a factor of [1, | ||
| 466 | // 2) slower. | ||
| 467 | // | ||
| 468 | // `syscfg` is required to enable the I/O compensation cell. | ||
| 469 | // | ||
| 470 | // # Panics | ||
| 471 | // | ||
| 472 | // If a clock specification cannot be achieved within the | ||
| 473 | // hardware specification then this function will panic. This | ||
| 474 | // function may also panic if a clock specification can be | ||
| 475 | // achieved, but the mechanism for doing so is not yet | ||
| 476 | // implemented here. | ||
| 477 | |||
| 478 | let srcclk = config.hse.unwrap_or(HSI); // Available clocks | ||
| 479 | let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk); | ||
| 480 | |||
| 481 | // Configure traceclk from PLL if needed | ||
| 482 | traceclk_setup(&mut config, sys_use_pll1_p); | ||
| 483 | |||
| 484 | // NOTE(unsafe) We have exclusive access to the RCC | ||
| 485 | let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0); | ||
| 486 | let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1); | ||
| 487 | let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2); | ||
| 488 | |||
| 489 | let sys_ck = if sys_use_pll1_p { | ||
| 490 | Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup | ||
| 491 | } else { | ||
| 492 | sys_ck | ||
| 493 | }; | ||
| 494 | |||
| 495 | // This routine does not support HSIDIV != 1. To | ||
| 496 | // do so it would need to ensure all PLLxON bits are clear | ||
| 497 | // before changing the value of HSIDIV | ||
| 498 | let cr = RCC.cr().read(); | ||
| 499 | assert!(cr.hsion()); | ||
| 500 | assert!(cr.hsidiv() == Hsidiv::DIV1); | ||
| 501 | |||
| 502 | RCC.csr().modify(|w| w.set_lsion(true)); | ||
| 503 | while !RCC.csr().read().lsirdy() {} | ||
| 504 | |||
| 505 | // per_ck from HSI by default | ||
| 506 | let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) { | ||
| 507 | (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE | ||
| 508 | (_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI | ||
| 509 | _ => (HSI, Ckpersel::HSI), // HSI | ||
| 510 | }; | ||
| 511 | |||
| 512 | // D1 Core Prescaler | ||
| 513 | // Set to 1 | ||
| 514 | let d1cpre_bits = 0; | ||
| 515 | let d1cpre_div = 1; | ||
| 516 | let sys_d1cpre_ck = sys_ck.0 / d1cpre_div; | ||
| 517 | |||
| 518 | // Refer to part datasheet "General operating conditions" | ||
| 519 | // table for (rev V). We do not assert checks for earlier | ||
| 520 | // revisions which may have lower limits. | ||
| 521 | let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos { | ||
| 522 | VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000), | ||
| 523 | VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000), | ||
| 524 | VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000), | ||
| 525 | _ => (200_000_000, 100_000_000, 50_000_000), | ||
| 526 | }; | ||
| 527 | assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max); | ||
| 528 | |||
| 529 | let rcc_hclk = config.rcc_hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2); | ||
| 530 | assert!(rcc_hclk <= rcc_hclk_max); | ||
| 531 | |||
| 532 | // Estimate divisor | ||
| 533 | let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk { | ||
| 534 | 0 => panic!(), | ||
| 535 | 1 => (Hpre::DIV1, 1), | ||
| 536 | 2 => (Hpre::DIV2, 2), | ||
| 537 | 3..=5 => (Hpre::DIV4, 4), | ||
| 538 | 6..=11 => (Hpre::DIV8, 8), | ||
| 539 | 12..=39 => (Hpre::DIV16, 16), | ||
| 540 | 40..=95 => (Hpre::DIV64, 64), | ||
| 541 | 96..=191 => (Hpre::DIV128, 128), | ||
| 542 | 192..=383 => (Hpre::DIV256, 256), | ||
| 543 | _ => (Hpre::DIV512, 512), | ||
| 544 | }; | ||
| 545 | // Calculate real AXI and AHB clock | ||
| 546 | let rcc_hclk = sys_d1cpre_ck / hpre_div; | ||
| 547 | assert!(rcc_hclk <= rcc_hclk_max); | ||
| 548 | let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7 | ||
| 549 | // Timer prescaler selection | ||
| 550 | let timpre = Timpre::DEFAULTX2; | ||
| 551 | |||
| 552 | let requested_pclk1 = config | ||
| 553 | .pclk1 | ||
| 554 | .map(|v| v.0) | ||
| 555 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 556 | let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) = | ||
| 557 | ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre)); | ||
| 558 | |||
| 559 | let requested_pclk2 = config | ||
| 560 | .pclk2 | ||
| 561 | .map(|v| v.0) | ||
| 562 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 563 | let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) = | ||
| 564 | ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre)); | ||
| 565 | |||
| 566 | let requested_pclk3 = config | ||
| 567 | .pclk3 | ||
| 568 | .map(|v| v.0) | ||
| 569 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 570 | let (rcc_pclk3, ppre3_bits, ppre3, _) = | ||
| 571 | ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None); | ||
| 572 | |||
| 573 | let requested_pclk4 = config | ||
| 574 | .pclk4 | ||
| 575 | .map(|v| v.0) | ||
| 576 | .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | ||
| 577 | let (rcc_pclk4, ppre4_bits, ppre4, _) = | ||
| 578 | ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); | ||
| 579 | |||
| 580 | flash_setup(rcc_aclk, pwr_vos); | ||
| 581 | |||
| 582 | // Start switching clocks ------------------- | ||
| 583 | |||
| 584 | // Ensure CSI is on and stable | ||
| 585 | RCC.cr().modify(|w| w.set_csion(true)); | ||
| 586 | while !RCC.cr().read().csirdy() {} | ||
| 587 | |||
| 588 | // Ensure HSI48 is on and stable | ||
| 589 | RCC.cr().modify(|w| w.set_hsi48on(true)); | ||
| 590 | while !RCC.cr().read().hsi48on() {} | ||
| 591 | |||
| 592 | // XXX: support MCO ? | ||
| 593 | |||
| 594 | let hse_ck = match config.hse { | ||
| 595 | Some(hse) => { | ||
| 596 | // Ensure HSE is on and stable | ||
| 597 | RCC.cr().modify(|w| { | ||
| 598 | w.set_hseon(true); | ||
| 599 | w.set_hsebyp(if config.bypass_hse { | ||
| 600 | Hsebyp::BYPASSED | ||
| 601 | } else { | ||
| 602 | Hsebyp::NOTBYPASSED | ||
| 603 | }); | ||
| 604 | }); | ||
| 605 | while !RCC.cr().read().hserdy() {} | ||
| 606 | Some(hse) | ||
| 607 | } | ||
| 608 | None => None, | ||
| 609 | }; | ||
| 610 | |||
| 611 | let pllsrc = if config.hse.is_some() { | ||
| 612 | Pllsrc::HSE | ||
| 613 | } else { | ||
| 614 | Pllsrc::HSI | ||
| 615 | }; | ||
| 616 | RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc)); | ||
| 617 | |||
| 618 | let enable_pll = |pll| { | ||
| 619 | RCC.cr().modify(|w| w.set_pllon(pll, true)); | ||
| 620 | while !RCC.cr().read().pllrdy(pll) {} | ||
| 621 | }; | ||
| 622 | |||
| 623 | if pll1_p_ck.is_some() { | ||
| 624 | enable_pll(0); | ||
| 625 | } | ||
| 626 | |||
| 627 | if pll2_p_ck.is_some() { | ||
| 628 | enable_pll(1); | ||
| 629 | } | ||
| 630 | |||
| 631 | if pll3_p_ck.is_some() { | ||
| 632 | enable_pll(2); | ||
| 633 | } | ||
| 634 | |||
| 635 | // Core Prescaler / AHB Prescaler / APB3 Prescaler | ||
| 636 | RCC.d1cfgr().modify(|w| { | ||
| 637 | w.set_d1cpre(Hpre(d1cpre_bits)); | ||
| 638 | w.set_d1ppre(Dppre(ppre3_bits)); | ||
| 639 | w.set_hpre(hpre_bits) | ||
| 640 | }); | ||
| 641 | // Ensure core prescaler value is valid before future lower | ||
| 642 | // core voltage | ||
| 643 | while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} | ||
| 644 | |||
| 645 | // APB1 / APB2 Prescaler | ||
| 646 | RCC.d2cfgr().modify(|w| { | ||
| 647 | w.set_d2ppre1(Dppre(ppre1_bits)); | ||
| 648 | w.set_d2ppre2(Dppre(ppre2_bits)); | ||
| 649 | }); | ||
| 650 | |||
| 651 | // APB4 Prescaler | ||
| 652 | RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits))); | ||
| 653 | |||
| 654 | // Peripheral Clock (per_ck) | ||
| 655 | RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); | ||
| 656 | |||
| 657 | // Set timer clocks prescaler setting | ||
| 658 | RCC.cfgr().modify(|w| w.set_timpre(timpre)); | ||
| 659 | |||
| 660 | // Select system clock source | ||
| 661 | let sw = match (sys_use_pll1_p, config.hse.is_some()) { | ||
| 662 | (true, _) => Sw::PLL1, | ||
| 663 | (false, true) => Sw::HSE, | ||
| 664 | _ => Sw::HSI, | ||
| 665 | }; | ||
| 666 | RCC.cfgr().modify(|w| w.set_sw(sw)); | ||
| 667 | while RCC.cfgr().read().sws() != sw.0 {} | ||
| 668 | |||
| 669 | // IO compensation cell - Requires CSI clock and SYSCFG | ||
| 670 | assert!(RCC.cr().read().csirdy()); | ||
| 671 | RCC.apb4enr().modify(|w| w.set_syscfgen(true)); | ||
| 672 | |||
| 673 | // Enable the compensation cell, using back-bias voltage code | ||
| 674 | // provide by the cell. | ||
| 675 | critical_section::with(|_| { | ||
| 676 | SYSCFG.cccsr().modify(|w| { | ||
| 677 | w.set_en(true); | ||
| 678 | w.set_cs(false); | ||
| 679 | w.set_hslv(false); | ||
| 680 | }) | ||
| 681 | }); | ||
| 682 | while !SYSCFG.cccsr().read().ready() {} | ||
| 683 | |||
| 684 | let core_clocks = CoreClocks { | ||
| 685 | hclk: Hertz(rcc_hclk), | ||
| 686 | pclk1: Hertz(rcc_pclk1), | ||
| 687 | pclk2: Hertz(rcc_pclk2), | ||
| 688 | pclk3: Hertz(rcc_pclk3), | ||
| 689 | pclk4: Hertz(rcc_pclk4), | ||
| 690 | ppre1, | ||
| 691 | ppre2, | ||
| 692 | ppre3, | ||
| 693 | ppre4, | ||
| 694 | csi_ck: Some(CSI), | ||
| 695 | hsi_ck: Some(HSI), | ||
| 696 | hsi48_ck: Some(HSI48), | ||
| 697 | lsi_ck: Some(LSI), | ||
| 698 | per_ck: Some(per_ck), | ||
| 699 | hse_ck, | ||
| 700 | pll1_p_ck: pll1_p_ck.map(Hertz), | ||
| 701 | pll1_q_ck: pll1_q_ck.map(Hertz), | ||
| 702 | pll1_r_ck: pll1_r_ck.map(Hertz), | ||
| 703 | pll2_p_ck: pll2_p_ck.map(Hertz), | ||
| 704 | pll2_q_ck: pll2_q_ck.map(Hertz), | ||
| 705 | pll2_r_ck: pll2_r_ck.map(Hertz), | ||
| 706 | pll3_p_ck: pll3_p_ck.map(Hertz), | ||
| 707 | pll3_q_ck: pll3_q_ck.map(Hertz), | ||
| 708 | pll3_r_ck: pll3_r_ck.map(Hertz), | ||
| 709 | timx_ker_ck: rcc_timerx_ker_ck.map(Hertz), | ||
| 710 | timy_ker_ck: rcc_timery_ker_ck.map(Hertz), | ||
| 711 | sys_ck, | ||
| 712 | c_ck: Hertz(sys_d1cpre_ck), | ||
| 713 | }; | ||
| 714 | |||
| 688 | set_freqs(Clocks { | 715 | set_freqs(Clocks { |
| 689 | sys: core_clocks.c_ck, | 716 | sys: core_clocks.c_ck, |
| 690 | ahb1: core_clocks.hclk, | 717 | ahb1: core_clocks.hclk, |
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index fc70ef0ac..25daeedf0 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs | |||
| @@ -1,18 +1,11 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; |
| 2 | use crate::peripherals::{self, CRS, RCC, SYSCFG}; | 2 | use crate::pac::{CRS, RCC, SYSCFG}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | 3 | use crate::rcc::{set_freqs, Clocks}; |
| 4 | use crate::time::Hertz; | 4 | use crate::time::Hertz; |
| 5 | use crate::time::U32Ext; | 5 | use crate::time::U32Ext; |
| 6 | use core::marker::PhantomData; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy_hal_common::unborrow; | ||
| 9 | use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; | ||
| 10 | 6 | ||
| 11 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 7 | /// HSI16 speed |
| 12 | /// and with the addition of the init function to configure a system clock. | 8 | pub const HSI16_FREQ: u32 = 16_000_000; |
| 13 | |||
| 14 | /// HSI speed | ||
| 15 | pub const HSI_FREQ: u32 = 16_000_000; | ||
| 16 | 9 | ||
| 17 | /// System clock mux source | 10 | /// System clock mux source |
| 18 | #[derive(Clone, Copy)] | 11 | #[derive(Clone, Copy)] |
| @@ -104,9 +97,9 @@ pub enum PLLSource { | |||
| 104 | HSE(Hertz), | 97 | HSE(Hertz), |
| 105 | } | 98 | } |
| 106 | 99 | ||
| 107 | impl Into<Pllmul> for PLLMul { | 100 | impl From<PLLMul> for Pllmul { |
| 108 | fn into(self) -> Pllmul { | 101 | fn from(val: PLLMul) -> Pllmul { |
| 109 | match self { | 102 | match val { |
| 110 | PLLMul::Mul3 => Pllmul::MUL3, | 103 | PLLMul::Mul3 => Pllmul::MUL3, |
| 111 | PLLMul::Mul4 => Pllmul::MUL4, | 104 | PLLMul::Mul4 => Pllmul::MUL4, |
| 112 | PLLMul::Mul6 => Pllmul::MUL6, | 105 | PLLMul::Mul6 => Pllmul::MUL6, |
| @@ -120,9 +113,9 @@ impl Into<Pllmul> for PLLMul { | |||
| 120 | } | 113 | } |
| 121 | } | 114 | } |
| 122 | 115 | ||
| 123 | impl Into<Plldiv> for PLLDiv { | 116 | impl From<PLLDiv> for Plldiv { |
| 124 | fn into(self) -> Plldiv { | 117 | fn from(val: PLLDiv) -> Plldiv { |
| 125 | match self { | 118 | match val { |
| 126 | PLLDiv::Div2 => Plldiv::DIV2, | 119 | PLLDiv::Div2 => Plldiv::DIV2, |
| 127 | PLLDiv::Div3 => Plldiv::DIV3, | 120 | PLLDiv::Div3 => Plldiv::DIV3, |
| 128 | PLLDiv::Div4 => Plldiv::DIV4, | 121 | PLLDiv::Div4 => Plldiv::DIV4, |
| @@ -130,18 +123,18 @@ impl Into<Plldiv> for PLLDiv { | |||
| 130 | } | 123 | } |
| 131 | } | 124 | } |
| 132 | 125 | ||
| 133 | impl Into<Pllsrc> for PLLSource { | 126 | impl From<PLLSource> for Pllsrc { |
| 134 | fn into(self) -> Pllsrc { | 127 | fn from(val: PLLSource) -> Pllsrc { |
| 135 | match self { | 128 | match val { |
| 136 | PLLSource::HSI16 => Pllsrc::HSI16, | 129 | PLLSource::HSI16 => Pllsrc::HSI16, |
| 137 | PLLSource::HSE(_) => Pllsrc::HSE, | 130 | PLLSource::HSE(_) => Pllsrc::HSE, |
| 138 | } | 131 | } |
| 139 | } | 132 | } |
| 140 | } | 133 | } |
| 141 | 134 | ||
| 142 | impl Into<Ppre> for APBPrescaler { | 135 | impl From<APBPrescaler> for Ppre { |
| 143 | fn into(self) -> Ppre { | 136 | fn from(val: APBPrescaler) -> Ppre { |
| 144 | match self { | 137 | match val { |
| 145 | APBPrescaler::NotDivided => Ppre::DIV1, | 138 | APBPrescaler::NotDivided => Ppre::DIV1, |
| 146 | APBPrescaler::Div2 => Ppre::DIV2, | 139 | APBPrescaler::Div2 => Ppre::DIV2, |
| 147 | APBPrescaler::Div4 => Ppre::DIV4, | 140 | APBPrescaler::Div4 => Ppre::DIV4, |
| @@ -151,9 +144,9 @@ impl Into<Ppre> for APBPrescaler { | |||
| 151 | } | 144 | } |
| 152 | } | 145 | } |
| 153 | 146 | ||
| 154 | impl Into<Hpre> for AHBPrescaler { | 147 | impl From<AHBPrescaler> for Hpre { |
| 155 | fn into(self) -> Hpre { | 148 | fn from(val: AHBPrescaler) -> Hpre { |
| 156 | match self { | 149 | match val { |
| 157 | AHBPrescaler::NotDivided => Hpre::DIV1, | 150 | AHBPrescaler::NotDivided => Hpre::DIV1, |
| 158 | AHBPrescaler::Div2 => Hpre::DIV2, | 151 | AHBPrescaler::Div2 => Hpre::DIV2, |
| 159 | AHBPrescaler::Div4 => Hpre::DIV4, | 152 | AHBPrescaler::Div4 => Hpre::DIV4, |
| @@ -167,9 +160,9 @@ impl Into<Hpre> for AHBPrescaler { | |||
| 167 | } | 160 | } |
| 168 | } | 161 | } |
| 169 | 162 | ||
| 170 | impl Into<Msirange> for MSIRange { | 163 | impl From<MSIRange> for Msirange { |
| 171 | fn into(self) -> Msirange { | 164 | fn from(val: MSIRange) -> Msirange { |
| 172 | match self { | 165 | match val { |
| 173 | MSIRange::Range0 => Msirange::RANGE0, | 166 | MSIRange::Range0 => Msirange::RANGE0, |
| 174 | MSIRange::Range1 => Msirange::RANGE1, | 167 | MSIRange::Range1 => Msirange::RANGE1, |
| 175 | MSIRange::Range2 => Msirange::RANGE2, | 168 | MSIRange::Range2 => Msirange::RANGE2, |
| @@ -187,6 +180,7 @@ pub struct Config { | |||
| 187 | pub ahb_pre: AHBPrescaler, | 180 | pub ahb_pre: AHBPrescaler, |
| 188 | pub apb1_pre: APBPrescaler, | 181 | pub apb1_pre: APBPrescaler, |
| 189 | pub apb2_pre: APBPrescaler, | 182 | pub apb2_pre: APBPrescaler, |
| 183 | pub enable_hsi48: bool, | ||
| 190 | } | 184 | } |
| 191 | 185 | ||
| 192 | impl Default for Config { | 186 | impl Default for Config { |
| @@ -197,241 +191,172 @@ impl Default for Config { | |||
| 197 | ahb_pre: AHBPrescaler::NotDivided, | 191 | ahb_pre: AHBPrescaler::NotDivided, |
| 198 | apb1_pre: APBPrescaler::NotDivided, | 192 | apb1_pre: APBPrescaler::NotDivided, |
| 199 | apb2_pre: APBPrescaler::NotDivided, | 193 | apb2_pre: APBPrescaler::NotDivided, |
| 194 | enable_hsi48: false, | ||
| 200 | } | 195 | } |
| 201 | } | 196 | } |
| 202 | } | 197 | } |
| 203 | 198 | ||
| 204 | /// RCC peripheral | 199 | pub(crate) unsafe fn init(config: Config) { |
| 205 | pub struct Rcc<'d> { | 200 | let (sys_clk, sw) = match config.mux { |
| 206 | _rb: peripherals::RCC, | 201 | ClockSrc::MSI(range) => { |
| 207 | phantom: PhantomData<&'d mut peripherals::RCC>, | 202 | // Set MSI range |
| 208 | } | 203 | RCC.icscr().write(|w| w.set_msirange(range.into())); |
| 209 | |||
| 210 | impl<'d> Rcc<'d> { | ||
| 211 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 212 | unborrow!(rcc); | ||
| 213 | Self { | ||
| 214 | _rb: rcc, | ||
| 215 | phantom: PhantomData, | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | // Safety: RCC init must have been called | ||
| 220 | pub fn clocks(&self) -> &'static Clocks { | ||
| 221 | unsafe { get_freqs() } | ||
| 222 | } | ||
| 223 | |||
| 224 | pub fn enable_hsi48(&mut self, _syscfg: &mut SYSCFG, _crs: CRS) -> HSI48 { | ||
| 225 | let rcc = pac::RCC; | ||
| 226 | unsafe { | ||
| 227 | // Reset SYSCFG peripheral | ||
| 228 | rcc.apb2rstr().modify(|w| w.set_syscfgrst(true)); | ||
| 229 | rcc.apb2rstr().modify(|w| w.set_syscfgrst(false)); | ||
| 230 | |||
| 231 | // Enable SYSCFG peripheral | ||
| 232 | rcc.apb2enr().modify(|w| w.set_syscfgen(true)); | ||
| 233 | |||
| 234 | // Reset CRS peripheral | ||
| 235 | rcc.apb1rstr().modify(|w| w.set_crsrst(true)); | ||
| 236 | rcc.apb1rstr().modify(|w| w.set_crsrst(false)); | ||
| 237 | 204 | ||
| 238 | // Enable CRS peripheral | 205 | // Enable MSI |
| 239 | rcc.apb1enr().modify(|w| w.set_crsen(true)); | 206 | RCC.cr().write(|w| w.set_msion(true)); |
| 207 | while !RCC.cr().read().msirdy() {} | ||
| 240 | 208 | ||
| 241 | // Initialize CRS | 209 | let freq = 32_768 * (1 << (range as u8 + 1)); |
| 242 | let crs = pac::CRS; | 210 | (freq, Sw::MSI) |
| 243 | crs.cfgr().write(|w| | 211 | } |
| 212 | ClockSrc::HSI16 => { | ||
| 213 | // Enable HSI16 | ||
| 214 | RCC.cr().write(|w| w.set_hsi16on(true)); | ||
| 215 | while !RCC.cr().read().hsi16rdyf() {} | ||
| 244 | 216 | ||
| 245 | // Select LSE as synchronization source | 217 | (HSI16_FREQ, Sw::HSI16) |
| 246 | w.set_syncsrc(0b01)); | 218 | } |
| 247 | crs.cr().modify(|w| { | 219 | ClockSrc::HSE(freq) => { |
| 248 | w.set_autotrimen(true); | 220 | // Enable HSE |
| 249 | w.set_cen(true); | 221 | RCC.cr().write(|w| w.set_hseon(true)); |
| 250 | }); | 222 | while !RCC.cr().read().hserdy() {} |
| 251 | 223 | ||
| 252 | // Enable VREFINT reference for HSI48 oscillator | 224 | (freq.0, Sw::HSE) |
| 253 | let syscfg = pac::SYSCFG; | 225 | } |
| 254 | syscfg.cfgr3().modify(|w| { | 226 | ClockSrc::PLL(src, mul, div) => { |
| 255 | w.set_enref_hsi48(true); | 227 | let freq = match src { |
| 256 | w.set_en_vrefint(true); | 228 | PLLSource::HSE(freq) => { |
| 229 | // Enable HSE | ||
| 230 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 231 | while !RCC.cr().read().hserdy() {} | ||
| 232 | freq.0 | ||
| 233 | } | ||
| 234 | PLLSource::HSI16 => { | ||
| 235 | // Enable HSI | ||
| 236 | RCC.cr().write(|w| w.set_hsi16on(true)); | ||
| 237 | while !RCC.cr().read().hsi16rdyf() {} | ||
| 238 | HSI16_FREQ | ||
| 239 | } | ||
| 240 | }; | ||
| 241 | |||
| 242 | // Disable PLL | ||
| 243 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 244 | while RCC.cr().read().pllrdy() {} | ||
| 245 | |||
| 246 | let freq = match mul { | ||
| 247 | PLLMul::Mul3 => freq * 3, | ||
| 248 | PLLMul::Mul4 => freq * 4, | ||
| 249 | PLLMul::Mul6 => freq * 6, | ||
| 250 | PLLMul::Mul8 => freq * 8, | ||
| 251 | PLLMul::Mul12 => freq * 12, | ||
| 252 | PLLMul::Mul16 => freq * 16, | ||
| 253 | PLLMul::Mul24 => freq * 24, | ||
| 254 | PLLMul::Mul32 => freq * 32, | ||
| 255 | PLLMul::Mul48 => freq * 48, | ||
| 256 | }; | ||
| 257 | |||
| 258 | let freq = match div { | ||
| 259 | PLLDiv::Div2 => freq / 2, | ||
| 260 | PLLDiv::Div3 => freq / 3, | ||
| 261 | PLLDiv::Div4 => freq / 4, | ||
| 262 | }; | ||
| 263 | assert!(freq <= 32_u32.mhz().0); | ||
| 264 | |||
| 265 | RCC.cfgr().write(move |w| { | ||
| 266 | w.set_pllmul(mul.into()); | ||
| 267 | w.set_plldiv(div.into()); | ||
| 268 | w.set_pllsrc(src.into()); | ||
| 257 | }); | 269 | }); |
| 258 | 270 | ||
| 259 | // Select HSI48 as USB clock | 271 | // Enable PLL |
| 260 | rcc.ccipr().modify(|w| w.set_hsi48msel(true)); | 272 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 273 | while !RCC.cr().read().pllrdy() {} | ||
| 261 | 274 | ||
| 262 | // Enable dedicated USB clock | 275 | (freq, Sw::PLL) |
| 263 | rcc.crrcr().modify(|w| w.set_hsi48on(true)); | ||
| 264 | while !rcc.crrcr().read().hsi48rdy() {} | ||
| 265 | } | 276 | } |
| 277 | }; | ||
| 278 | |||
| 279 | RCC.cfgr().modify(|w| { | ||
| 280 | w.set_sw(sw); | ||
| 281 | w.set_hpre(config.ahb_pre.into()); | ||
| 282 | w.set_ppre1(config.apb1_pre.into()); | ||
| 283 | w.set_ppre2(config.apb2_pre.into()); | ||
| 284 | }); | ||
| 285 | |||
| 286 | let ahb_freq: u32 = match config.ahb_pre { | ||
| 287 | AHBPrescaler::NotDivided => sys_clk, | ||
| 288 | pre => { | ||
| 289 | let pre: Hpre = pre.into(); | ||
| 290 | let pre = 1 << (pre.0 as u32 - 7); | ||
| 291 | sys_clk / pre | ||
| 292 | } | ||
| 293 | }; | ||
| 294 | |||
| 295 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 296 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 297 | pre => { | ||
| 298 | let pre: Ppre = pre.into(); | ||
| 299 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 300 | let freq = ahb_freq / pre as u32; | ||
| 301 | (freq, freq * 2) | ||
| 302 | } | ||
| 303 | }; | ||
| 304 | |||
| 305 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 306 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 307 | pre => { | ||
| 308 | let pre: Ppre = pre.into(); | ||
| 309 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 310 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 311 | (freq, freq * 2) | ||
| 312 | } | ||
| 313 | }; | ||
| 266 | 314 | ||
| 267 | HSI48(()) | 315 | if config.enable_hsi48 { |
| 268 | } | 316 | // Reset SYSCFG peripheral |
| 269 | } | 317 | RCC.apb2rstr().modify(|w| w.set_syscfgrst(true)); |
| 270 | 318 | RCC.apb2rstr().modify(|w| w.set_syscfgrst(false)); | |
| 271 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 272 | pub trait RccExt { | ||
| 273 | fn freeze(self, config: Config) -> Clocks; | ||
| 274 | } | ||
| 275 | |||
| 276 | impl RccExt for RCC { | ||
| 277 | // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by | ||
| 278 | // marking this function and all `Config` constructors and setters as `#[inline]`. | ||
| 279 | // This saves ~900 Bytes for the `pwr.rs` example. | ||
| 280 | #[inline] | ||
| 281 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 282 | let rcc = pac::RCC; | ||
| 283 | let (sys_clk, sw) = match cfgr.mux { | ||
| 284 | ClockSrc::MSI(range) => { | ||
| 285 | // Set MSI range | ||
| 286 | unsafe { | ||
| 287 | rcc.icscr().write(|w| w.set_msirange(range.into())); | ||
| 288 | } | ||
| 289 | 319 | ||
| 290 | // Enable MSI | 320 | // Enable SYSCFG peripheral |
| 291 | unsafe { | 321 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); |
| 292 | rcc.cr().write(|w| w.set_msion(true)); | ||
| 293 | while !rcc.cr().read().msirdy() {} | ||
| 294 | } | ||
| 295 | 322 | ||
| 296 | let freq = 32_768 * (1 << (range as u8 + 1)); | 323 | // Reset CRS peripheral |
| 297 | (freq, Sw::MSI) | 324 | RCC.apb1rstr().modify(|w| w.set_crsrst(true)); |
| 298 | } | 325 | RCC.apb1rstr().modify(|w| w.set_crsrst(false)); |
| 299 | ClockSrc::HSI16 => { | ||
| 300 | // Enable HSI16 | ||
| 301 | unsafe { | ||
| 302 | rcc.cr().write(|w| w.set_hsi16on(true)); | ||
| 303 | while !rcc.cr().read().hsi16rdyf() {} | ||
| 304 | } | ||
| 305 | 326 | ||
| 306 | (HSI_FREQ, Sw::HSI16) | 327 | // Enable CRS peripheral |
| 307 | } | 328 | RCC.apb1enr().modify(|w| w.set_crsen(true)); |
| 308 | ClockSrc::HSE(freq) => { | ||
| 309 | // Enable HSE | ||
| 310 | unsafe { | ||
| 311 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 312 | while !rcc.cr().read().hserdy() {} | ||
| 313 | } | ||
| 314 | 329 | ||
| 315 | (freq.0, Sw::HSE) | 330 | // Initialize CRS |
| 316 | } | 331 | CRS.cfgr().write(|w| |
| 317 | ClockSrc::PLL(src, mul, div) => { | ||
| 318 | let freq = match src { | ||
| 319 | PLLSource::HSE(freq) => { | ||
| 320 | // Enable HSE | ||
| 321 | unsafe { | ||
| 322 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 323 | while !rcc.cr().read().hserdy() {} | ||
| 324 | } | ||
| 325 | freq.0 | ||
| 326 | } | ||
| 327 | PLLSource::HSI16 => { | ||
| 328 | // Enable HSI | ||
| 329 | unsafe { | ||
| 330 | rcc.cr().write(|w| w.set_hsi16on(true)); | ||
| 331 | while !rcc.cr().read().hsi16rdyf() {} | ||
| 332 | } | ||
| 333 | HSI_FREQ | ||
| 334 | } | ||
| 335 | }; | ||
| 336 | |||
| 337 | // Disable PLL | ||
| 338 | unsafe { | ||
| 339 | rcc.cr().modify(|w| w.set_pllon(false)); | ||
| 340 | while rcc.cr().read().pllrdy() {} | ||
| 341 | } | ||
| 342 | 332 | ||
| 343 | let freq = match mul { | 333 | // Select LSE as synchronization source |
| 344 | PLLMul::Mul3 => freq * 3, | 334 | w.set_syncsrc(0b01)); |
| 345 | PLLMul::Mul4 => freq * 4, | 335 | CRS.cr().modify(|w| { |
| 346 | PLLMul::Mul6 => freq * 6, | 336 | w.set_autotrimen(true); |
| 347 | PLLMul::Mul8 => freq * 8, | 337 | w.set_cen(true); |
| 348 | PLLMul::Mul12 => freq * 12, | 338 | }); |
| 349 | PLLMul::Mul16 => freq * 16, | ||
| 350 | PLLMul::Mul24 => freq * 24, | ||
| 351 | PLLMul::Mul32 => freq * 32, | ||
| 352 | PLLMul::Mul48 => freq * 48, | ||
| 353 | }; | ||
| 354 | |||
| 355 | let freq = match div { | ||
| 356 | PLLDiv::Div2 => freq / 2, | ||
| 357 | PLLDiv::Div3 => freq / 3, | ||
| 358 | PLLDiv::Div4 => freq / 4, | ||
| 359 | }; | ||
| 360 | assert!(freq <= 32_u32.mhz().0); | ||
| 361 | |||
| 362 | unsafe { | ||
| 363 | rcc.cfgr().write(move |w| { | ||
| 364 | w.set_pllmul(mul.into()); | ||
| 365 | w.set_plldiv(div.into()); | ||
| 366 | w.set_pllsrc(src.into()); | ||
| 367 | }); | ||
| 368 | |||
| 369 | // Enable PLL | ||
| 370 | rcc.cr().modify(|w| w.set_pllon(true)); | ||
| 371 | while !rcc.cr().read().pllrdy() {} | ||
| 372 | } | ||
| 373 | 339 | ||
| 374 | (freq, Sw::PLL) | 340 | // Enable VREFINT reference for HSI48 oscillator |
| 375 | } | 341 | SYSCFG.cfgr3().modify(|w| { |
| 376 | }; | 342 | w.set_enref_hsi48(true); |
| 343 | w.set_en_vrefint(true); | ||
| 344 | }); | ||
| 377 | 345 | ||
| 378 | unsafe { | 346 | // Select HSI48 as USB clock |
| 379 | rcc.cfgr().modify(|w| { | 347 | RCC.ccipr().modify(|w| w.set_hsi48msel(true)); |
| 380 | w.set_sw(sw.into()); | ||
| 381 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 382 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 383 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 384 | }); | ||
| 385 | } | ||
| 386 | 348 | ||
| 387 | let ahb_freq: u32 = match cfgr.ahb_pre { | 349 | // Enable dedicated USB clock |
| 388 | AHBPrescaler::NotDivided => sys_clk, | 350 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); |
| 389 | pre => { | 351 | while !RCC.crrcr().read().hsi48rdy() {} |
| 390 | let pre: Hpre = pre.into(); | ||
| 391 | let pre = 1 << (pre.0 as u32 - 7); | ||
| 392 | sys_clk / pre | ||
| 393 | } | ||
| 394 | }; | ||
| 395 | |||
| 396 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | ||
| 397 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 398 | pre => { | ||
| 399 | let pre: Ppre = pre.into(); | ||
| 400 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 401 | let freq = ahb_freq / pre as u32; | ||
| 402 | (freq, freq * 2) | ||
| 403 | } | ||
| 404 | }; | ||
| 405 | |||
| 406 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | ||
| 407 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 408 | pre => { | ||
| 409 | let pre: Ppre = pre.into(); | ||
| 410 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 411 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 412 | (freq, freq * 2) | ||
| 413 | } | ||
| 414 | }; | ||
| 415 | |||
| 416 | Clocks { | ||
| 417 | sys: sys_clk.hz(), | ||
| 418 | ahb: ahb_freq.hz(), | ||
| 419 | apb1: apb1_freq.hz(), | ||
| 420 | apb2: apb2_freq.hz(), | ||
| 421 | apb1_tim: apb1_tim_freq.hz(), | ||
| 422 | apb2_tim: apb2_tim_freq.hz(), | ||
| 423 | } | ||
| 424 | } | 352 | } |
| 425 | } | ||
| 426 | 353 | ||
| 427 | /// Token that exists only, if the HSI48 clock has been enabled | 354 | set_freqs(Clocks { |
| 428 | /// | 355 | sys: sys_clk.hz(), |
| 429 | /// You can get an instance of this struct by calling [`Rcc::enable_hsi48`]. | 356 | ahb: ahb_freq.hz(), |
| 430 | #[derive(Clone, Copy)] | 357 | apb1: apb1_freq.hz(), |
| 431 | pub struct HSI48(()); | 358 | apb2: apb2_freq.hz(), |
| 432 | 359 | apb1_tim: apb1_tim_freq.hz(), | |
| 433 | pub(crate) unsafe fn init(config: Config) { | 360 | apb2_tim: apb2_tim_freq.hz(), |
| 434 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 361 | }); |
| 435 | let clocks = r.freeze(config); | ||
| 436 | set_freqs(clocks); | ||
| 437 | } | 362 | } |
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index 746433c12..517869ca4 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs | |||
| @@ -1,13 +1,8 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; |
| 2 | use crate::peripherals::{self, RCC}; | 2 | use crate::pac::RCC; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | 3 | use crate::rcc::{set_freqs, Clocks}; |
| 4 | use crate::time::Hertz; | 4 | use crate::time::Hertz; |
| 5 | use crate::time::U32Ext; | 5 | use crate::time::U32Ext; |
| 6 | use core::marker::PhantomData; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy_hal_common::unborrow; | ||
| 9 | |||
| 10 | /// Most of clock setup is copied from rcc/l0 | ||
| 11 | 6 | ||
| 12 | /// HSI speed | 7 | /// HSI speed |
| 13 | pub const HSI_FREQ: u32 = 16_000_000; | 8 | pub const HSI_FREQ: u32 = 16_000_000; |
| @@ -16,6 +11,7 @@ pub const HSI_FREQ: u32 = 16_000_000; | |||
| 16 | #[derive(Clone, Copy)] | 11 | #[derive(Clone, Copy)] |
| 17 | pub enum ClockSrc { | 12 | pub enum ClockSrc { |
| 18 | MSI(MSIRange), | 13 | MSI(MSIRange), |
| 14 | PLL(PLLSource, PLLMul, PLLDiv), | ||
| 19 | HSE(Hertz), | 15 | HSE(Hertz), |
| 20 | HSI, | 16 | HSI, |
| 21 | } | 17 | } |
| @@ -48,6 +44,28 @@ impl Default for MSIRange { | |||
| 48 | } | 44 | } |
| 49 | } | 45 | } |
| 50 | 46 | ||
| 47 | /// PLL divider | ||
| 48 | #[derive(Clone, Copy)] | ||
| 49 | pub enum PLLDiv { | ||
| 50 | Div2, | ||
| 51 | Div3, | ||
| 52 | Div4, | ||
| 53 | } | ||
| 54 | |||
| 55 | /// PLL multiplier | ||
| 56 | #[derive(Clone, Copy)] | ||
| 57 | pub enum PLLMul { | ||
| 58 | Mul3, | ||
| 59 | Mul4, | ||
| 60 | Mul6, | ||
| 61 | Mul8, | ||
| 62 | Mul12, | ||
| 63 | Mul16, | ||
| 64 | Mul24, | ||
| 65 | Mul32, | ||
| 66 | Mul48, | ||
| 67 | } | ||
| 68 | |||
| 51 | /// AHB prescaler | 69 | /// AHB prescaler |
| 52 | #[derive(Clone, Copy, PartialEq)] | 70 | #[derive(Clone, Copy, PartialEq)] |
| 53 | pub enum AHBPrescaler { | 71 | pub enum AHBPrescaler { |
| @@ -72,46 +90,86 @@ pub enum APBPrescaler { | |||
| 72 | Div16, | 90 | Div16, |
| 73 | } | 91 | } |
| 74 | 92 | ||
| 75 | type Ppre = u8; | 93 | /// PLL clock input source |
| 76 | impl Into<Ppre> for APBPrescaler { | 94 | #[derive(Clone, Copy)] |
| 77 | fn into(self) -> Ppre { | 95 | pub enum PLLSource { |
| 78 | match self { | 96 | HSI, |
| 79 | APBPrescaler::NotDivided => 0b000, | 97 | HSE(Hertz), |
| 80 | APBPrescaler::Div2 => 0b100, | 98 | } |
| 81 | APBPrescaler::Div4 => 0b101, | 99 | |
| 82 | APBPrescaler::Div8 => 0b110, | 100 | impl From<PLLMul> for Pllmul { |
| 83 | APBPrescaler::Div16 => 0b111, | 101 | fn from(val: PLLMul) -> Pllmul { |
| 102 | match val { | ||
| 103 | PLLMul::Mul3 => Pllmul::MUL3, | ||
| 104 | PLLMul::Mul4 => Pllmul::MUL4, | ||
| 105 | PLLMul::Mul6 => Pllmul::MUL6, | ||
| 106 | PLLMul::Mul8 => Pllmul::MUL8, | ||
| 107 | PLLMul::Mul12 => Pllmul::MUL12, | ||
| 108 | PLLMul::Mul16 => Pllmul::MUL16, | ||
| 109 | PLLMul::Mul24 => Pllmul::MUL24, | ||
| 110 | PLLMul::Mul32 => Pllmul::MUL32, | ||
| 111 | PLLMul::Mul48 => Pllmul::MUL48, | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | impl From<PLLDiv> for Plldiv { | ||
| 117 | fn from(val: PLLDiv) -> Plldiv { | ||
| 118 | match val { | ||
| 119 | PLLDiv::Div2 => Plldiv::DIV2, | ||
| 120 | PLLDiv::Div3 => Plldiv::DIV3, | ||
| 121 | PLLDiv::Div4 => Plldiv::DIV4, | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | impl From<PLLSource> for Pllsrc { | ||
| 127 | fn from(val: PLLSource) -> Pllsrc { | ||
| 128 | match val { | ||
| 129 | PLLSource::HSI => Pllsrc::HSI, | ||
| 130 | PLLSource::HSE(_) => Pllsrc::HSE, | ||
| 131 | } | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | impl From<APBPrescaler> for Ppre { | ||
| 136 | fn from(val: APBPrescaler) -> Ppre { | ||
| 137 | match val { | ||
| 138 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 139 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 140 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 141 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 142 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 84 | } | 143 | } |
| 85 | } | 144 | } |
| 86 | } | 145 | } |
| 87 | 146 | ||
| 88 | type Hpre = u8; | 147 | impl From<AHBPrescaler> for Hpre { |
| 89 | impl Into<Hpre> for AHBPrescaler { | 148 | fn from(val: AHBPrescaler) -> Hpre { |
| 90 | fn into(self) -> Hpre { | 149 | match val { |
| 91 | match self { | 150 | AHBPrescaler::NotDivided => Hpre::DIV1, |
| 92 | AHBPrescaler::NotDivided => 0b0000, | 151 | AHBPrescaler::Div2 => Hpre::DIV2, |
| 93 | AHBPrescaler::Div2 => 0b1000, | 152 | AHBPrescaler::Div4 => Hpre::DIV4, |
| 94 | AHBPrescaler::Div4 => 0b1001, | 153 | AHBPrescaler::Div8 => Hpre::DIV8, |
| 95 | AHBPrescaler::Div8 => 0b1010, | 154 | AHBPrescaler::Div16 => Hpre::DIV16, |
| 96 | AHBPrescaler::Div16 => 0b1011, | 155 | AHBPrescaler::Div64 => Hpre::DIV64, |
| 97 | AHBPrescaler::Div64 => 0b1100, | 156 | AHBPrescaler::Div128 => Hpre::DIV128, |
| 98 | AHBPrescaler::Div128 => 0b1101, | 157 | AHBPrescaler::Div256 => Hpre::DIV256, |
| 99 | AHBPrescaler::Div256 => 0b1110, | 158 | AHBPrescaler::Div512 => Hpre::DIV512, |
| 100 | AHBPrescaler::Div512 => 0b1111, | ||
| 101 | } | 159 | } |
| 102 | } | 160 | } |
| 103 | } | 161 | } |
| 104 | 162 | ||
| 105 | impl Into<u8> for MSIRange { | 163 | impl From<MSIRange> for Msirange { |
| 106 | fn into(self) -> u8 { | 164 | fn from(val: MSIRange) -> Msirange { |
| 107 | match self { | 165 | match val { |
| 108 | MSIRange::Range0 => 0b000, | 166 | MSIRange::Range0 => Msirange::RANGE0, |
| 109 | MSIRange::Range1 => 0b001, | 167 | MSIRange::Range1 => Msirange::RANGE1, |
| 110 | MSIRange::Range2 => 0b010, | 168 | MSIRange::Range2 => Msirange::RANGE2, |
| 111 | MSIRange::Range3 => 0b011, | 169 | MSIRange::Range3 => Msirange::RANGE3, |
| 112 | MSIRange::Range4 => 0b100, | 170 | MSIRange::Range4 => Msirange::RANGE4, |
| 113 | MSIRange::Range5 => 0b101, | 171 | MSIRange::Range5 => Msirange::RANGE5, |
| 114 | MSIRange::Range6 => 0b110, | 172 | MSIRange::Range6 => Msirange::RANGE6, |
| 115 | } | 173 | } |
| 116 | } | 174 | } |
| 117 | } | 175 | } |
| @@ -136,126 +194,128 @@ impl Default for Config { | |||
| 136 | } | 194 | } |
| 137 | } | 195 | } |
| 138 | 196 | ||
| 139 | /// RCC peripheral | 197 | pub(crate) unsafe fn init(config: Config) { |
| 140 | pub struct Rcc<'d> { | 198 | let (sys_clk, sw) = match config.mux { |
| 141 | _rb: peripherals::RCC, | 199 | ClockSrc::MSI(range) => { |
| 142 | phantom: PhantomData<&'d mut peripherals::RCC>, | 200 | // Set MSI range |
| 143 | } | 201 | RCC.icscr().write(|w| w.set_msirange(range.into())); |
| 144 | 202 | ||
| 145 | impl<'d> Rcc<'d> { | 203 | // Enable MSI |
| 146 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | 204 | RCC.cr().write(|w| w.set_msion(true)); |
| 147 | unborrow!(rcc); | 205 | while !RCC.cr().read().msirdy() {} |
| 148 | Self { | ||
| 149 | _rb: rcc, | ||
| 150 | phantom: PhantomData, | ||
| 151 | } | ||
| 152 | } | ||
| 153 | 206 | ||
| 154 | // Safety: RCC init must have been called | 207 | let freq = 32_768 * (1 << (range as u8 + 1)); |
| 155 | pub fn clocks(&self) -> &'static Clocks { | 208 | (freq, Sw::MSI) |
| 156 | unsafe { get_freqs() } | 209 | } |
| 157 | } | 210 | ClockSrc::HSI => { |
| 158 | } | 211 | // Enable HSI |
| 212 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 213 | while !RCC.cr().read().hsirdy() {} | ||
| 159 | 214 | ||
| 160 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | 215 | (HSI_FREQ, Sw::HSI) |
| 161 | pub trait RccExt { | 216 | } |
| 162 | fn freeze(self, config: Config) -> Clocks; | 217 | ClockSrc::HSE(freq) => { |
| 163 | } | 218 | // Enable HSE |
| 219 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 220 | while !RCC.cr().read().hserdy() {} | ||
| 164 | 221 | ||
| 165 | impl RccExt for RCC { | 222 | (freq.0, Sw::HSE) |
| 166 | // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by | 223 | } |
| 167 | // marking this function and all `Config` constructors and setters as `#[inline]`. | 224 | ClockSrc::PLL(src, mul, div) => { |
| 168 | // This saves ~900 Bytes for the `pwr.rs` example. | 225 | let freq = match src { |
| 169 | #[inline] | 226 | PLLSource::HSE(freq) => { |
| 170 | fn freeze(self, cfgr: Config) -> Clocks { | 227 | // Enable HSE |
| 171 | let rcc = pac::RCC; | 228 | RCC.cr().write(|w| w.set_hseon(true)); |
| 172 | let (sys_clk, sw) = match cfgr.mux { | 229 | while !RCC.cr().read().hserdy() {} |
| 173 | ClockSrc::MSI(range) => { | 230 | freq.0 |
| 174 | // Set MSI range | ||
| 175 | unsafe { | ||
| 176 | rcc.icscr().write(|w| w.set_msirange(range.into())); | ||
| 177 | } | 231 | } |
| 178 | 232 | PLLSource::HSI => { | |
| 179 | // Enable MSI | 233 | // Enable HSI |
| 180 | unsafe { | 234 | RCC.cr().write(|w| w.set_hsion(true)); |
| 181 | rcc.cr().write(|w| w.set_msion(true)); | 235 | while !RCC.cr().read().hsirdy() {} |
| 182 | while !rcc.cr().read().msirdy() {} | 236 | HSI_FREQ |
| 183 | } | 237 | } |
| 238 | }; | ||
| 184 | 239 | ||
| 185 | let freq = 32_768 * (1 << (range as u8 + 1)); | 240 | // Disable PLL |
| 186 | (freq, 0b00) | 241 | RCC.cr().modify(|w| w.set_pllon(false)); |
| 187 | } | 242 | while RCC.cr().read().pllrdy() {} |
| 188 | ClockSrc::HSI => { | ||
| 189 | // Enable HSI | ||
| 190 | unsafe { | ||
| 191 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 192 | while !rcc.cr().read().hsirdy() {} | ||
| 193 | } | ||
| 194 | 243 | ||
| 195 | (HSI_FREQ, 0b01) | 244 | let freq = match mul { |
| 196 | } | 245 | PLLMul::Mul3 => freq * 3, |
| 197 | ClockSrc::HSE(freq) => { | 246 | PLLMul::Mul4 => freq * 4, |
| 198 | // Enable HSE | 247 | PLLMul::Mul6 => freq * 6, |
| 199 | unsafe { | 248 | PLLMul::Mul8 => freq * 8, |
| 200 | rcc.cr().write(|w| w.set_hseon(true)); | 249 | PLLMul::Mul12 => freq * 12, |
| 201 | while !rcc.cr().read().hserdy() {} | 250 | PLLMul::Mul16 => freq * 16, |
| 202 | } | 251 | PLLMul::Mul24 => freq * 24, |
| 252 | PLLMul::Mul32 => freq * 32, | ||
| 253 | PLLMul::Mul48 => freq * 48, | ||
| 254 | }; | ||
| 203 | 255 | ||
| 204 | (freq.0, 0b10) | 256 | let freq = match div { |
| 205 | } | 257 | PLLDiv::Div2 => freq / 2, |
| 206 | }; | 258 | PLLDiv::Div3 => freq / 3, |
| 259 | PLLDiv::Div4 => freq / 4, | ||
| 260 | }; | ||
| 261 | assert!(freq <= 32_u32.mhz().0); | ||
| 207 | 262 | ||
| 208 | unsafe { | 263 | RCC.cfgr().write(move |w| { |
| 209 | rcc.cfgr().modify(|w| { | 264 | w.set_pllmul(mul.into()); |
| 210 | w.set_sw(sw.into()); | 265 | w.set_plldiv(div.into()); |
| 211 | w.set_hpre(cfgr.ahb_pre.into()); | 266 | w.set_pllsrc(src.into()); |
| 212 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 213 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 214 | }); | 267 | }); |
| 268 | |||
| 269 | // Enable PLL | ||
| 270 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 271 | while !RCC.cr().read().pllrdy() {} | ||
| 272 | |||
| 273 | (freq, Sw::PLL) | ||
| 215 | } | 274 | } |
| 275 | }; | ||
| 276 | |||
| 277 | RCC.cfgr().modify(|w| { | ||
| 278 | w.set_sw(sw); | ||
| 279 | w.set_hpre(config.ahb_pre.into()); | ||
| 280 | w.set_ppre1(config.apb1_pre.into()); | ||
| 281 | w.set_ppre2(config.apb2_pre.into()); | ||
| 282 | }); | ||
| 216 | 283 | ||
| 217 | let ahb_freq: u32 = match cfgr.ahb_pre { | 284 | let ahb_freq: u32 = match config.ahb_pre { |
| 218 | AHBPrescaler::NotDivided => sys_clk, | 285 | AHBPrescaler::NotDivided => sys_clk, |
| 219 | pre => { | 286 | pre => { |
| 220 | let pre: Hpre = pre.into(); | 287 | let pre: Hpre = pre.into(); |
| 221 | let pre = 1 << (pre as u32 - 7); | 288 | let pre = 1 << (pre.0 as u32 - 7); |
| 222 | sys_clk / pre | 289 | sys_clk / pre |
| 223 | } | ||
| 224 | }; | ||
| 225 | |||
| 226 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | ||
| 227 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 228 | pre => { | ||
| 229 | let pre: Ppre = pre.into(); | ||
| 230 | let pre: u8 = 1 << (pre - 3); | ||
| 231 | let freq = ahb_freq / pre as u32; | ||
| 232 | (freq, freq * 2) | ||
| 233 | } | ||
| 234 | }; | ||
| 235 | |||
| 236 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | ||
| 237 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 238 | pre => { | ||
| 239 | let pre: Ppre = pre.into(); | ||
| 240 | let pre: u8 = 1 << (pre - 3); | ||
| 241 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 242 | (freq, freq * 2) | ||
| 243 | } | ||
| 244 | }; | ||
| 245 | |||
| 246 | Clocks { | ||
| 247 | sys: sys_clk.hz(), | ||
| 248 | ahb: ahb_freq.hz(), | ||
| 249 | apb1: apb1_freq.hz(), | ||
| 250 | apb2: apb2_freq.hz(), | ||
| 251 | apb1_tim: apb1_tim_freq.hz(), | ||
| 252 | apb2_tim: apb2_tim_freq.hz(), | ||
| 253 | } | 290 | } |
| 254 | } | 291 | }; |
| 255 | } | ||
| 256 | 292 | ||
| 257 | pub(crate) unsafe fn init(config: Config) { | 293 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 258 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 294 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |
| 259 | let clocks = r.freeze(config); | 295 | pre => { |
| 260 | set_freqs(clocks); | 296 | let pre: Ppre = pre.into(); |
| 297 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 298 | let freq = ahb_freq / pre as u32; | ||
| 299 | (freq, freq * 2) | ||
| 300 | } | ||
| 301 | }; | ||
| 302 | |||
| 303 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 304 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 305 | pre => { | ||
| 306 | let pre: Ppre = pre.into(); | ||
| 307 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 308 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 309 | (freq, freq * 2) | ||
| 310 | } | ||
| 311 | }; | ||
| 312 | |||
| 313 | set_freqs(Clocks { | ||
| 314 | sys: sys_clk.hz(), | ||
| 315 | ahb: ahb_freq.hz(), | ||
| 316 | apb1: apb1_freq.hz(), | ||
| 317 | apb2: apb2_freq.hz(), | ||
| 318 | apb1_tim: apb1_tim_freq.hz(), | ||
| 319 | apb2_tim: apb2_tim_freq.hz(), | ||
| 320 | }); | ||
| 261 | } | 321 | } |
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 510cbddfa..68b960d7c 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs | |||
| @@ -1,17 +1,8 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; |
| 2 | use crate::peripherals::{self, RCC}; | 2 | use crate::pac::{FLASH, RCC}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | 3 | use crate::rcc::{set_freqs, Clocks}; |
| 4 | use crate::time::Hertz; | 4 | use crate::time::Hertz; |
| 5 | use crate::time::U32Ext; | 5 | use crate::time::U32Ext; |
| 6 | use core::marker::PhantomData; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy_hal_common::unborrow; | ||
| 9 | use stm32_metapac::rcc::vals::Msirange; | ||
| 10 | |||
| 11 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | ||
| 12 | /// and with the addition of the init function to configure a system clock. | ||
| 13 | |||
| 14 | /// Only the basic setup using the HSE and HSI clocks are supported as of now. | ||
| 15 | 6 | ||
| 16 | /// HSI16 speed | 7 | /// HSI16 speed |
| 17 | pub const HSI16_FREQ: u32 = 16_000_000; | 8 | pub const HSI16_FREQ: u32 = 16_000_000; |
| @@ -19,8 +10,8 @@ pub const HSI16_FREQ: u32 = 16_000_000; | |||
| 19 | /// System clock mux source | 10 | /// System clock mux source |
| 20 | #[derive(Clone, Copy)] | 11 | #[derive(Clone, Copy)] |
| 21 | pub enum ClockSrc { | 12 | pub enum ClockSrc { |
| 22 | PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>), | ||
| 23 | MSI(MSIRange), | 13 | MSI(MSIRange), |
| 14 | PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>), | ||
| 24 | HSE(Hertz), | 15 | HSE(Hertz), |
| 25 | HSI16, | 16 | HSI16, |
| 26 | } | 17 | } |
| @@ -57,25 +48,6 @@ pub enum MSIRange { | |||
| 57 | Range11, | 48 | Range11, |
| 58 | } | 49 | } |
| 59 | 50 | ||
| 60 | impl Into<u32> for MSIRange { | ||
| 61 | fn into(self) -> u32 { | ||
| 62 | match self { | ||
| 63 | MSIRange::Range0 => 100_000, | ||
| 64 | MSIRange::Range1 => 200_000, | ||
| 65 | MSIRange::Range2 => 400_000, | ||
| 66 | MSIRange::Range3 => 800_000, | ||
| 67 | MSIRange::Range4 => 1_000_000, | ||
| 68 | MSIRange::Range5 => 2_000_000, | ||
| 69 | MSIRange::Range6 => 4_000_000, | ||
| 70 | MSIRange::Range7 => 8_000_000, | ||
| 71 | MSIRange::Range8 => 16_000_000, | ||
| 72 | MSIRange::Range9 => 24_000_000, | ||
| 73 | MSIRange::Range10 => 32_000_000, | ||
| 74 | MSIRange::Range11 => 48_000_000, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | impl Default for MSIRange { | 51 | impl Default for MSIRange { |
| 80 | fn default() -> MSIRange { | 52 | fn default() -> MSIRange { |
| 81 | MSIRange::Range6 | 53 | MSIRange::Range6 |
| @@ -131,9 +103,9 @@ seq_macro::seq!(N in 8..=86 { | |||
| 131 | )* | 103 | )* |
| 132 | } | 104 | } |
| 133 | 105 | ||
| 134 | impl Into<u8> for PLLMul { | 106 | impl From<PLLMul> for u8 { |
| 135 | fn into(self) -> u8 { | 107 | fn from(val: PLLMul) -> u8 { |
| 136 | match self { | 108 | match val { |
| 137 | #( | 109 | #( |
| 138 | PLLMul::Mul#N => N, | 110 | PLLMul::Mul#N => N, |
| 139 | )* | 111 | )* |
| @@ -163,13 +135,13 @@ pub enum PLLClkDiv { | |||
| 163 | impl PLLClkDiv { | 135 | impl PLLClkDiv { |
| 164 | pub fn to_div(self) -> u32 { | 136 | pub fn to_div(self) -> u32 { |
| 165 | let val: u8 = self.into(); | 137 | let val: u8 = self.into(); |
| 166 | val as u32 + 1 * 2 | 138 | (val as u32 + 1) * 2 |
| 167 | } | 139 | } |
| 168 | } | 140 | } |
| 169 | 141 | ||
| 170 | impl Into<u8> for PLLClkDiv { | 142 | impl From<PLLClkDiv> for u8 { |
| 171 | fn into(self) -> u8 { | 143 | fn from(val: PLLClkDiv) -> u8 { |
| 172 | match self { | 144 | match val { |
| 173 | PLLClkDiv::Div2 => 0b00, | 145 | PLLClkDiv::Div2 => 0b00, |
| 174 | PLLClkDiv::Div4 => 0b01, | 146 | PLLClkDiv::Div4 => 0b01, |
| 175 | PLLClkDiv::Div6 => 0b10, | 147 | PLLClkDiv::Div6 => 0b10, |
| @@ -197,9 +169,9 @@ impl PLLSrcDiv { | |||
| 197 | } | 169 | } |
| 198 | } | 170 | } |
| 199 | 171 | ||
| 200 | impl Into<u8> for PLLSrcDiv { | 172 | impl From<PLLSrcDiv> for u8 { |
| 201 | fn into(self) -> u8 { | 173 | fn from(val: PLLSrcDiv) -> u8 { |
| 202 | match self { | 174 | match val { |
| 203 | PLLSrcDiv::Div1 => 0b000, | 175 | PLLSrcDiv::Div1 => 0b000, |
| 204 | PLLSrcDiv::Div2 => 0b001, | 176 | PLLSrcDiv::Div2 => 0b001, |
| 205 | PLLSrcDiv::Div3 => 0b010, | 177 | PLLSrcDiv::Div3 => 0b010, |
| @@ -212,18 +184,46 @@ impl Into<u8> for PLLSrcDiv { | |||
| 212 | } | 184 | } |
| 213 | } | 185 | } |
| 214 | 186 | ||
| 215 | impl Into<u8> for PLLSource { | 187 | impl From<PLLSource> for Pllsrc { |
| 216 | fn into(self) -> u8 { | 188 | fn from(val: PLLSource) -> Pllsrc { |
| 217 | match self { | 189 | match val { |
| 218 | PLLSource::HSI16 => 0b10, | 190 | PLLSource::HSI16 => Pllsrc::HSI16, |
| 219 | PLLSource::HSE(_) => 0b11, | 191 | PLLSource::HSE(_) => Pllsrc::HSE, |
| 220 | } | 192 | } |
| 221 | } | 193 | } |
| 222 | } | 194 | } |
| 223 | 195 | ||
| 224 | impl Into<Msirange> for MSIRange { | 196 | impl From<APBPrescaler> for Ppre { |
| 225 | fn into(self) -> Msirange { | 197 | fn from(val: APBPrescaler) -> Ppre { |
| 226 | match self { | 198 | match val { |
| 199 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 200 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 201 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 202 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 203 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 204 | } | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | impl From<AHBPrescaler> for Hpre { | ||
| 209 | fn from(val: AHBPrescaler) -> Hpre { | ||
| 210 | match val { | ||
| 211 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 212 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 213 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 214 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 215 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 216 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 217 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 218 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 219 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | impl From<MSIRange> for Msirange { | ||
| 225 | fn from(val: MSIRange) -> Msirange { | ||
| 226 | match val { | ||
| 227 | MSIRange::Range0 => Msirange::RANGE100K, | 227 | MSIRange::Range0 => Msirange::RANGE100K, |
| 228 | MSIRange::Range1 => Msirange::RANGE200K, | 228 | MSIRange::Range1 => Msirange::RANGE200K, |
| 229 | MSIRange::Range2 => Msirange::RANGE400K, | 229 | MSIRange::Range2 => Msirange::RANGE400K, |
| @@ -239,30 +239,22 @@ impl Into<Msirange> for MSIRange { | |||
| 239 | } | 239 | } |
| 240 | } | 240 | } |
| 241 | } | 241 | } |
| 242 | impl Into<u8> for APBPrescaler { | ||
| 243 | fn into(self) -> u8 { | ||
| 244 | match self { | ||
| 245 | APBPrescaler::NotDivided => 1, | ||
| 246 | APBPrescaler::Div2 => 0x04, | ||
| 247 | APBPrescaler::Div4 => 0x05, | ||
| 248 | APBPrescaler::Div8 => 0x06, | ||
| 249 | APBPrescaler::Div16 => 0x07, | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 253 | 242 | ||
| 254 | impl Into<u8> for AHBPrescaler { | 243 | impl From<MSIRange> for u32 { |
| 255 | fn into(self) -> u8 { | 244 | fn from(val: MSIRange) -> u32 { |
| 256 | match self { | 245 | match val { |
| 257 | AHBPrescaler::NotDivided => 1, | 246 | MSIRange::Range0 => 100_000, |
| 258 | AHBPrescaler::Div2 => 0x08, | 247 | MSIRange::Range1 => 200_000, |
| 259 | AHBPrescaler::Div4 => 0x09, | 248 | MSIRange::Range2 => 400_000, |
| 260 | AHBPrescaler::Div8 => 0x0a, | 249 | MSIRange::Range3 => 800_000, |
| 261 | AHBPrescaler::Div16 => 0x0b, | 250 | MSIRange::Range4 => 1_000_000, |
| 262 | AHBPrescaler::Div64 => 0x0c, | 251 | MSIRange::Range5 => 2_000_000, |
| 263 | AHBPrescaler::Div128 => 0x0d, | 252 | MSIRange::Range6 => 4_000_000, |
| 264 | AHBPrescaler::Div256 => 0x0e, | 253 | MSIRange::Range7 => 8_000_000, |
| 265 | AHBPrescaler::Div512 => 0x0f, | 254 | MSIRange::Range8 => 16_000_000, |
| 255 | MSIRange::Range9 => 24_000_000, | ||
| 256 | MSIRange::Range10 => 32_000_000, | ||
| 257 | MSIRange::Range11 => 48_000_000, | ||
| 266 | } | 258 | } |
| 267 | } | 259 | } |
| 268 | } | 260 | } |
| @@ -287,203 +279,151 @@ impl Default for Config { | |||
| 287 | } | 279 | } |
| 288 | } | 280 | } |
| 289 | 281 | ||
| 290 | /// RCC peripheral | 282 | pub(crate) unsafe fn init(config: Config) { |
| 291 | pub struct Rcc<'d> { | 283 | let (sys_clk, sw) = match config.mux { |
| 292 | _rb: peripherals::RCC, | 284 | ClockSrc::MSI(range) => { |
| 293 | phantom: PhantomData<&'d mut peripherals::RCC>, | 285 | // Enable MSI |
| 294 | } | 286 | RCC.cr().write(|w| { |
| 287 | let bits: Msirange = range.into(); | ||
| 288 | w.set_msirange(bits); | ||
| 289 | w.set_msipllen(false); | ||
| 290 | w.set_msirgsel(true); | ||
| 291 | w.set_msion(true); | ||
| 292 | }); | ||
| 293 | while !RCC.cr().read().msirdy() {} | ||
| 295 | 294 | ||
| 296 | impl<'d> Rcc<'d> { | 295 | // Enable as clock source for USB, RNG if running at 48 MHz |
| 297 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | 296 | if let MSIRange::Range11 = range { |
| 298 | unborrow!(rcc); | 297 | RCC.ccipr().modify(|w| { |
| 299 | Self { | 298 | w.set_clk48sel(0b11); |
| 300 | _rb: rcc, | 299 | }); |
| 301 | phantom: PhantomData, | 300 | } |
| 301 | (range.into(), Sw::MSI) | ||
| 302 | } | 302 | } |
| 303 | } | 303 | ClockSrc::HSI16 => { |
| 304 | // Enable HSI16 | ||
| 305 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 306 | while !RCC.cr().read().hsirdy() {} | ||
| 304 | 307 | ||
| 305 | // Safety: RCC init must have been called | 308 | (HSI16_FREQ, Sw::HSI16) |
| 306 | pub fn clocks(&self) -> &'static Clocks { | 309 | } |
| 307 | unsafe { get_freqs() } | 310 | ClockSrc::HSE(freq) => { |
| 308 | } | 311 | // Enable HSE |
| 309 | } | 312 | RCC.cr().write(|w| w.set_hseon(true)); |
| 310 | 313 | while !RCC.cr().read().hserdy() {} | |
| 311 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 312 | pub trait RccExt { | ||
| 313 | fn freeze(self, config: Config) -> Clocks; | ||
| 314 | } | ||
| 315 | 314 | ||
| 316 | impl RccExt for RCC { | 315 | (freq.0, Sw::HSE) |
| 317 | #[inline] | 316 | } |
| 318 | fn freeze(self, cfgr: Config) -> Clocks { | 317 | ClockSrc::PLL(src, div, prediv, mul, pll48div) => { |
| 319 | let rcc = pac::RCC; | 318 | let freq = match src { |
| 320 | let (sys_clk, sw) = match cfgr.mux { | 319 | PLLSource::HSE(freq) => { |
| 321 | ClockSrc::HSI16 => { | 320 | // Enable HSE |
| 322 | // Enable HSI16 | 321 | RCC.cr().write(|w| w.set_hseon(true)); |
| 323 | unsafe { | 322 | while !RCC.cr().read().hserdy() {} |
| 324 | rcc.cr().write(|w| w.set_hsion(true)); | 323 | freq.0 |
| 325 | while !rcc.cr().read().hsirdy() {} | ||
| 326 | } | 324 | } |
| 327 | 325 | PLLSource::HSI16 => { | |
| 328 | (HSI16_FREQ, 0b01) | 326 | // Enable HSI |
| 329 | } | 327 | RCC.cr().write(|w| w.set_hsion(true)); |
| 330 | ClockSrc::HSE(freq) => { | 328 | while !RCC.cr().read().hsirdy() {} |
| 331 | // Enable HSE | 329 | HSI16_FREQ |
| 332 | unsafe { | ||
| 333 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 334 | while !rcc.cr().read().hserdy() {} | ||
| 335 | } | 330 | } |
| 331 | }; | ||
| 336 | 332 | ||
| 337 | (freq.0, 0b10) | 333 | // Disable PLL |
| 338 | } | 334 | RCC.cr().modify(|w| w.set_pllon(false)); |
| 339 | ClockSrc::MSI(range) => { | 335 | while RCC.cr().read().pllrdy() {} |
| 340 | // Enable MSI | ||
| 341 | unsafe { | ||
| 342 | rcc.cr().write(|w| { | ||
| 343 | let bits: Msirange = range.into(); | ||
| 344 | w.set_msirange(bits); | ||
| 345 | w.set_msipllen(false); | ||
| 346 | w.set_msirgsel(true); | ||
| 347 | w.set_msion(true); | ||
| 348 | }); | ||
| 349 | while !rcc.cr().read().msirdy() {} | ||
| 350 | |||
| 351 | // Enable as clock source for USB, RNG if running at 48 MHz | ||
| 352 | if let MSIRange::Range11 = range { | ||
| 353 | rcc.ccipr().modify(|w| { | ||
| 354 | w.set_clk48sel(0b11); | ||
| 355 | }); | ||
| 356 | } | ||
| 357 | } | ||
| 358 | (range.into(), 0b00) | ||
| 359 | } | ||
| 360 | ClockSrc::PLL(src, div, prediv, mul, pll48div) => { | ||
| 361 | let freq = match src { | ||
| 362 | PLLSource::HSE(freq) => { | ||
| 363 | // Enable HSE | ||
| 364 | unsafe { | ||
| 365 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 366 | while !rcc.cr().read().hserdy() {} | ||
| 367 | } | ||
| 368 | freq.0 | ||
| 369 | } | ||
| 370 | PLLSource::HSI16 => { | ||
| 371 | // Enable HSI | ||
| 372 | unsafe { | ||
| 373 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 374 | while !rcc.cr().read().hsirdy() {} | ||
| 375 | } | ||
| 376 | HSI16_FREQ | ||
| 377 | } | ||
| 378 | }; | ||
| 379 | |||
| 380 | // Disable PLL | ||
| 381 | unsafe { | ||
| 382 | rcc.cr().modify(|w| w.set_pllon(false)); | ||
| 383 | while rcc.cr().read().pllrdy() {} | ||
| 384 | } | ||
| 385 | 336 | ||
| 386 | let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div(); | 337 | let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div(); |
| 387 | |||
| 388 | assert!(freq <= 80_000_000); | ||
| 389 | |||
| 390 | unsafe { | ||
| 391 | rcc.pllcfgr().write(move |w| { | ||
| 392 | w.set_plln(mul.into()); | ||
| 393 | w.set_pllm(prediv.into()); | ||
| 394 | w.set_pllr(div.into()); | ||
| 395 | if let Some(pll48div) = pll48div { | ||
| 396 | w.set_pllq(pll48div.into()); | ||
| 397 | w.set_pllqen(true); | ||
| 398 | } | ||
| 399 | w.set_pllsrc(src.into()); | ||
| 400 | }); | ||
| 401 | |||
| 402 | // Enable as clock source for USB, RNG if PLL48 divisor is provided | ||
| 403 | if pll48div.is_some() { | ||
| 404 | rcc.ccipr().modify(|w| { | ||
| 405 | w.set_clk48sel(0b10); | ||
| 406 | }); | ||
| 407 | } | ||
| 408 | |||
| 409 | // Enable PLL | ||
| 410 | rcc.cr().modify(|w| w.set_pllon(true)); | ||
| 411 | while !rcc.cr().read().pllrdy() {} | ||
| 412 | rcc.pllcfgr().modify(|w| w.set_pllren(true)); | ||
| 413 | } | ||
| 414 | (freq, 0b11) | ||
| 415 | } | ||
| 416 | }; | ||
| 417 | |||
| 418 | unsafe { | ||
| 419 | // Set flash wait states | ||
| 420 | pac::FLASH.acr().modify(|w| { | ||
| 421 | w.set_latency(if sys_clk <= 16_000_000 { | ||
| 422 | 0b000 | ||
| 423 | } else if sys_clk <= 32_000_000 { | ||
| 424 | 0b001 | ||
| 425 | } else if sys_clk <= 48_000_000 { | ||
| 426 | 0b010 | ||
| 427 | } else if sys_clk <= 64_000_000 { | ||
| 428 | 0b011 | ||
| 429 | } else { | ||
| 430 | 0b100 | ||
| 431 | }); | ||
| 432 | }); | ||
| 433 | 338 | ||
| 434 | // Switch active clocks to new clock source | 339 | assert!(freq <= 80_000_000); |
| 435 | rcc.cfgr().modify(|w| { | 340 | |
| 436 | w.set_sw(sw.into()); | 341 | RCC.pllcfgr().write(move |w| { |
| 437 | w.set_hpre(cfgr.ahb_pre.into()); | 342 | w.set_plln(mul.into()); |
| 438 | w.set_ppre1(cfgr.apb1_pre.into()); | 343 | w.set_pllm(prediv.into()); |
| 439 | w.set_ppre2(cfgr.apb2_pre.into()); | 344 | w.set_pllr(div.into()); |
| 345 | if let Some(pll48div) = pll48div { | ||
| 346 | w.set_pllq(pll48div.into()); | ||
| 347 | w.set_pllqen(true); | ||
| 348 | } | ||
| 349 | w.set_pllsrc(src.into()); | ||
| 440 | }); | 350 | }); |
| 441 | } | ||
| 442 | 351 | ||
| 443 | let ahb_freq: u32 = match cfgr.ahb_pre { | 352 | // Enable as clock source for USB, RNG if PLL48 divisor is provided |
| 444 | AHBPrescaler::NotDivided => sys_clk, | 353 | if pll48div.is_some() { |
| 445 | pre => { | 354 | RCC.ccipr().modify(|w| { |
| 446 | let pre: u8 = pre.into(); | 355 | w.set_clk48sel(0b10); |
| 447 | let pre = 1 << (pre as u32 - 7); | 356 | }); |
| 448 | sys_clk / pre | ||
| 449 | } | ||
| 450 | }; | ||
| 451 | |||
| 452 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | ||
| 453 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 454 | pre => { | ||
| 455 | let pre: u8 = pre.into(); | ||
| 456 | let pre: u8 = 1 << (pre - 3); | ||
| 457 | let freq = ahb_freq / pre as u32; | ||
| 458 | (freq, freq * 2) | ||
| 459 | } | ||
| 460 | }; | ||
| 461 | |||
| 462 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | ||
| 463 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 464 | pre => { | ||
| 465 | let pre: u8 = pre.into(); | ||
| 466 | let pre: u8 = 1 << (pre - 3); | ||
| 467 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 468 | (freq, freq * 2) | ||
| 469 | } | 357 | } |
| 470 | }; | ||
| 471 | |||
| 472 | Clocks { | ||
| 473 | sys: sys_clk.hz(), | ||
| 474 | ahb1: ahb_freq.hz(), | ||
| 475 | ahb2: ahb_freq.hz(), | ||
| 476 | ahb3: ahb_freq.hz(), | ||
| 477 | apb1: apb1_freq.hz(), | ||
| 478 | apb2: apb2_freq.hz(), | ||
| 479 | apb1_tim: apb1_tim_freq.hz(), | ||
| 480 | apb2_tim: apb2_tim_freq.hz(), | ||
| 481 | } | ||
| 482 | } | ||
| 483 | } | ||
| 484 | 358 | ||
| 485 | pub(crate) unsafe fn init(config: Config) { | 359 | // Enable PLL |
| 486 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 360 | RCC.cr().modify(|w| w.set_pllon(true)); |
| 487 | let clocks = r.freeze(config); | 361 | while !RCC.cr().read().pllrdy() {} |
| 488 | set_freqs(clocks); | 362 | RCC.pllcfgr().modify(|w| w.set_pllren(true)); |
| 363 | |||
| 364 | (freq, Sw::PLL) | ||
| 365 | } | ||
| 366 | }; | ||
| 367 | |||
| 368 | // Set flash wait states | ||
| 369 | FLASH.acr().modify(|w| { | ||
| 370 | w.set_latency(if sys_clk <= 16_000_000 { | ||
| 371 | 0b000 | ||
| 372 | } else if sys_clk <= 32_000_000 { | ||
| 373 | 0b001 | ||
| 374 | } else if sys_clk <= 48_000_000 { | ||
| 375 | 0b010 | ||
| 376 | } else if sys_clk <= 64_000_000 { | ||
| 377 | 0b011 | ||
| 378 | } else { | ||
| 379 | 0b100 | ||
| 380 | }); | ||
| 381 | }); | ||
| 382 | |||
| 383 | RCC.cfgr().modify(|w| { | ||
| 384 | w.set_sw(sw); | ||
| 385 | w.set_hpre(config.ahb_pre.into()); | ||
| 386 | w.set_ppre1(config.apb1_pre.into()); | ||
| 387 | w.set_ppre2(config.apb2_pre.into()); | ||
| 388 | }); | ||
| 389 | |||
| 390 | let ahb_freq: u32 = match config.ahb_pre { | ||
| 391 | AHBPrescaler::NotDivided => sys_clk, | ||
| 392 | pre => { | ||
| 393 | let pre: Hpre = pre.into(); | ||
| 394 | let pre = 1 << (pre.0 as u32 - 7); | ||
| 395 | sys_clk / pre | ||
| 396 | } | ||
| 397 | }; | ||
| 398 | |||
| 399 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 400 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 401 | pre => { | ||
| 402 | let pre: Ppre = pre.into(); | ||
| 403 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 404 | let freq = ahb_freq / pre as u32; | ||
| 405 | (freq, freq * 2) | ||
| 406 | } | ||
| 407 | }; | ||
| 408 | |||
| 409 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 410 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 411 | pre => { | ||
| 412 | let pre: Ppre = pre.into(); | ||
| 413 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 414 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 415 | (freq, freq * 2) | ||
| 416 | } | ||
| 417 | }; | ||
| 418 | |||
| 419 | set_freqs(Clocks { | ||
| 420 | sys: sys_clk.hz(), | ||
| 421 | ahb1: ahb_freq.hz(), | ||
| 422 | ahb2: ahb_freq.hz(), | ||
| 423 | ahb3: ahb_freq.hz(), | ||
| 424 | apb1: apb1_freq.hz(), | ||
| 425 | apb2: apb2_freq.hz(), | ||
| 426 | apb1_tim: apb1_tim_freq.hz(), | ||
| 427 | apb2_tim: apb2_tim_freq.hz(), | ||
| 428 | }); | ||
| 489 | } | 429 | } |
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index e8bd82718..ac1cd06c8 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::{FLASH, RCC}; |
| 2 | use crate::peripherals::{self, RCC}; | ||
| 3 | use crate::pwr::{Power, VoltageScale}; | ||
| 4 | use crate::rcc::{set_freqs, Clocks}; | 2 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::time::{Hertz, U32Ext}; | 3 | use crate::time::{Hertz, U32Ext}; |
| 6 | use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}; | 4 | use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}; |
| @@ -8,6 +6,20 @@ use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw} | |||
| 8 | /// HSI16 speed | 6 | /// HSI16 speed |
| 9 | pub const HSI16_FREQ: u32 = 16_000_000; | 7 | pub const HSI16_FREQ: u32 = 16_000_000; |
| 10 | 8 | ||
| 9 | /// Voltage Scale | ||
| 10 | /// | ||
| 11 | /// Represents the voltage range feeding the CPU core. The maximum core | ||
| 12 | /// clock frequency depends on this value. | ||
| 13 | #[derive(Copy, Clone, PartialEq)] | ||
| 14 | pub enum VoltageScale { | ||
| 15 | // Highest frequency | ||
| 16 | Range1, | ||
| 17 | Range2, | ||
| 18 | Range3, | ||
| 19 | // Lowest power | ||
| 20 | Range4, | ||
| 21 | } | ||
| 22 | |||
| 11 | #[derive(Copy, Clone)] | 23 | #[derive(Copy, Clone)] |
| 12 | pub enum ClockSrc { | 24 | pub enum ClockSrc { |
| 13 | MSI(MSIRange), | 25 | MSI(MSIRange), |
| @@ -293,218 +305,188 @@ impl Default for Config { | |||
| 293 | } | 305 | } |
| 294 | } | 306 | } |
| 295 | 307 | ||
| 296 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | 308 | pub(crate) unsafe fn init(config: Config) { |
| 297 | pub trait RccExt { | 309 | let sys_clk = match config.mux { |
| 298 | fn freeze(self, config: Config, power: &Power) -> Clocks; | 310 | ClockSrc::MSI(range) => { |
| 299 | } | 311 | RCC.icscr1().modify(|w| { |
| 300 | 312 | let bits: Msirange = range.into(); | |
| 301 | impl RccExt for RCC { | 313 | w.set_msisrange(bits); |
| 302 | #[inline] | 314 | w.set_msirgsel(Msirgsel::RCC_ICSCR1); |
| 303 | fn freeze(self, cfgr: Config, power: &Power) -> Clocks { | 315 | }); |
| 304 | let rcc = pac::RCC; | 316 | RCC.cr().write(|w| { |
| 305 | 317 | w.set_msipllen(false); | |
| 306 | let sys_clk = match cfgr.mux { | 318 | w.set_msison(true); |
| 307 | ClockSrc::MSI(range) => { | 319 | w.set_msison(true); |
| 308 | unsafe { | 320 | }); |
| 309 | rcc.icscr1().modify(|w| { | 321 | while !RCC.cr().read().msisrdy() {} |
| 310 | let bits: Msirange = range.into(); | ||
| 311 | w.set_msisrange(bits); | ||
| 312 | w.set_msirgsel(Msirgsel::RCC_ICSCR1); | ||
| 313 | }); | ||
| 314 | rcc.cr().write(|w| { | ||
| 315 | w.set_msipllen(false); | ||
| 316 | w.set_msison(true); | ||
| 317 | w.set_msison(true); | ||
| 318 | }); | ||
| 319 | while !rcc.cr().read().msisrdy() {} | ||
| 320 | } | ||
| 321 | |||
| 322 | range.into() | ||
| 323 | } | ||
| 324 | ClockSrc::HSE(freq) => { | ||
| 325 | unsafe { | ||
| 326 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 327 | while !rcc.cr().read().hserdy() {} | ||
| 328 | } | ||
| 329 | |||
| 330 | freq.0 | ||
| 331 | } | ||
| 332 | ClockSrc::HSI16 => { | ||
| 333 | unsafe { | ||
| 334 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 335 | while !rcc.cr().read().hsirdy() {} | ||
| 336 | } | ||
| 337 | 322 | ||
| 338 | HSI16_FREQ | 323 | range.into() |
| 339 | } | 324 | } |
| 340 | ClockSrc::PLL1R(src, m, n, div) => { | 325 | ClockSrc::HSE(freq) => { |
| 341 | let freq = match src { | 326 | RCC.cr().write(|w| w.set_hseon(true)); |
| 342 | PllSrc::MSI(_) => MSIRange::default().into(), | 327 | while !RCC.cr().read().hserdy() {} |
| 343 | PllSrc::HSE(hertz) => hertz.0, | ||
| 344 | PllSrc::HSI16 => HSI16_FREQ, | ||
| 345 | }; | ||
| 346 | |||
| 347 | // disable | ||
| 348 | unsafe { | ||
| 349 | rcc.cr().modify(|w| w.set_pllon(0, false)); | ||
| 350 | while rcc.cr().read().pllrdy(0) {} | ||
| 351 | } | ||
| 352 | |||
| 353 | let vco = freq * n as u8 as u32; | ||
| 354 | let pll_ck = vco / (div as u8 as u32 + 1); | ||
| 355 | |||
| 356 | unsafe { | ||
| 357 | rcc.pll1cfgr().write(|w| { | ||
| 358 | w.set_pllm(m.into()); | ||
| 359 | w.set_pllsrc(src.into()); | ||
| 360 | }); | ||
| 361 | |||
| 362 | rcc.pll1divr().modify(|w| { | ||
| 363 | w.set_pllr(div.to_div()); | ||
| 364 | w.set_plln(n.to_mul()); | ||
| 365 | }); | ||
| 366 | |||
| 367 | // Enable PLL | ||
| 368 | rcc.cr().modify(|w| w.set_pllon(0, true)); | ||
| 369 | while !rcc.cr().read().pllrdy(0) {} | ||
| 370 | rcc.pll1cfgr().modify(|w| w.set_pllren(true)); | ||
| 371 | } | ||
| 372 | |||
| 373 | unsafe { | ||
| 374 | rcc.cr().write(|w| w.set_pllon(0, true)); | ||
| 375 | while !rcc.cr().read().pllrdy(0) {} | ||
| 376 | } | ||
| 377 | |||
| 378 | pll_ck | ||
| 379 | } | ||
| 380 | }; | ||
| 381 | |||
| 382 | // states and programming delay | ||
| 383 | let wait_states = match power.vos { | ||
| 384 | // VOS 0 range VCORE 1.26V - 1.40V | ||
| 385 | VoltageScale::Range1 => { | ||
| 386 | if sys_clk < 32_000_000 { | ||
| 387 | 0 | ||
| 388 | } else if sys_clk < 64_000_000 { | ||
| 389 | 1 | ||
| 390 | } else if sys_clk < 96_000_000 { | ||
| 391 | 2 | ||
| 392 | } else if sys_clk < 128_000_000 { | ||
| 393 | 3 | ||
| 394 | } else { | ||
| 395 | 4 | ||
| 396 | } | ||
| 397 | } | ||
| 398 | // VOS 1 range VCORE 1.15V - 1.26V | ||
| 399 | VoltageScale::Range2 => { | ||
| 400 | if sys_clk < 30_000_000 { | ||
| 401 | 0 | ||
| 402 | } else if sys_clk < 60_000_000 { | ||
| 403 | 1 | ||
| 404 | } else if sys_clk < 90_000_000 { | ||
| 405 | 2 | ||
| 406 | } else { | ||
| 407 | 3 | ||
| 408 | } | ||
| 409 | } | ||
| 410 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 411 | VoltageScale::Range3 => { | ||
| 412 | if sys_clk < 24_000_000 { | ||
| 413 | 0 | ||
| 414 | } else if sys_clk < 48_000_000 { | ||
| 415 | 1 | ||
| 416 | } else { | ||
| 417 | 2 | ||
| 418 | } | ||
| 419 | } | ||
| 420 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 421 | VoltageScale::Range4 => { | ||
| 422 | if sys_clk < 12_000_000 { | ||
| 423 | 0 | ||
| 424 | } else { | ||
| 425 | 1 | ||
| 426 | } | ||
| 427 | } | ||
| 428 | }; | ||
| 429 | 328 | ||
| 430 | unsafe { | 329 | freq.0 |
| 431 | pac::FLASH.acr().modify(|w| { | ||
| 432 | w.set_latency(wait_states); | ||
| 433 | }) | ||
| 434 | } | 330 | } |
| 331 | ClockSrc::HSI16 => { | ||
| 332 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 333 | while !RCC.cr().read().hsirdy() {} | ||
| 435 | 334 | ||
| 436 | unsafe { | 335 | HSI16_FREQ |
| 437 | rcc.cfgr1().modify(|w| { | 336 | } |
| 438 | w.set_sw(cfgr.mux.into()); | 337 | ClockSrc::PLL1R(src, m, n, div) => { |
| 338 | let freq = match src { | ||
| 339 | PllSrc::MSI(_) => MSIRange::default().into(), | ||
| 340 | PllSrc::HSE(hertz) => hertz.0, | ||
| 341 | PllSrc::HSI16 => HSI16_FREQ, | ||
| 342 | }; | ||
| 343 | |||
| 344 | // disable | ||
| 345 | RCC.cr().modify(|w| w.set_pllon(0, false)); | ||
| 346 | while RCC.cr().read().pllrdy(0) {} | ||
| 347 | |||
| 348 | let vco = freq * n as u8 as u32; | ||
| 349 | let pll_ck = vco / (div as u8 as u32 + 1); | ||
| 350 | |||
| 351 | RCC.pll1cfgr().write(|w| { | ||
| 352 | w.set_pllm(m.into()); | ||
| 353 | w.set_pllsrc(src.into()); | ||
| 439 | }); | 354 | }); |
| 440 | 355 | ||
| 441 | rcc.cfgr2().modify(|w| { | 356 | RCC.pll1divr().modify(|w| { |
| 442 | w.set_hpre(cfgr.ahb_pre.into()); | 357 | w.set_pllr(div.to_div()); |
| 443 | w.set_ppre1(cfgr.apb1_pre.into()); | 358 | w.set_plln(n.to_mul()); |
| 444 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 445 | }); | 359 | }); |
| 446 | 360 | ||
| 447 | rcc.cfgr3().modify(|w| { | 361 | // Enable PLL |
| 448 | w.set_ppre3(cfgr.apb3_pre.into()); | 362 | RCC.cr().modify(|w| w.set_pllon(0, true)); |
| 449 | }); | 363 | while !RCC.cr().read().pllrdy(0) {} |
| 450 | } | 364 | RCC.pll1cfgr().modify(|w| w.set_pllren(true)); |
| 365 | |||
| 366 | RCC.cr().write(|w| w.set_pllon(0, true)); | ||
| 367 | while !RCC.cr().read().pllrdy(0) {} | ||
| 451 | 368 | ||
| 452 | let ahb_freq: u32 = match cfgr.ahb_pre { | 369 | pll_ck |
| 453 | AHBPrescaler::NotDivided => sys_clk, | 370 | } |
| 454 | pre => { | 371 | }; |
| 455 | let pre: u8 = pre.into(); | 372 | |
| 456 | let pre = 1 << (pre as u32 - 7); | 373 | // TODO make configurable |
| 457 | sys_clk / pre | 374 | let power_vos = VoltageScale::Range4; |
| 375 | |||
| 376 | // states and programming delay | ||
| 377 | let wait_states = match power_vos { | ||
| 378 | // VOS 0 range VCORE 1.26V - 1.40V | ||
| 379 | VoltageScale::Range1 => { | ||
| 380 | if sys_clk < 32_000_000 { | ||
| 381 | 0 | ||
| 382 | } else if sys_clk < 64_000_000 { | ||
| 383 | 1 | ||
| 384 | } else if sys_clk < 96_000_000 { | ||
| 385 | 2 | ||
| 386 | } else if sys_clk < 128_000_000 { | ||
| 387 | 3 | ||
| 388 | } else { | ||
| 389 | 4 | ||
| 458 | } | 390 | } |
| 459 | }; | 391 | } |
| 460 | 392 | // VOS 1 range VCORE 1.15V - 1.26V | |
| 461 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | 393 | VoltageScale::Range2 => { |
| 462 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 394 | if sys_clk < 30_000_000 { |
| 463 | pre => { | 395 | 0 |
| 464 | let pre: u8 = pre.into(); | 396 | } else if sys_clk < 60_000_000 { |
| 465 | let pre: u8 = 1 << (pre - 3); | 397 | 1 |
| 466 | let freq = ahb_freq / pre as u32; | 398 | } else if sys_clk < 90_000_000 { |
| 467 | (freq, freq * 2) | 399 | 2 |
| 400 | } else { | ||
| 401 | 3 | ||
| 468 | } | 402 | } |
| 469 | }; | 403 | } |
| 470 | 404 | // VOS 2 range VCORE 1.05V - 1.15V | |
| 471 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | 405 | VoltageScale::Range3 => { |
| 472 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 406 | if sys_clk < 24_000_000 { |
| 473 | pre => { | 407 | 0 |
| 474 | let pre: u8 = pre.into(); | 408 | } else if sys_clk < 48_000_000 { |
| 475 | let pre: u8 = 1 << (pre - 3); | 409 | 1 |
| 476 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | 410 | } else { |
| 477 | (freq, freq * 2) | 411 | 2 |
| 478 | } | 412 | } |
| 479 | }; | 413 | } |
| 480 | 414 | // VOS 3 range VCORE 0.95V - 1.05V | |
| 481 | let (apb3_freq, _apb3_tim_freq) = match cfgr.apb3_pre { | 415 | VoltageScale::Range4 => { |
| 482 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 416 | if sys_clk < 12_000_000 { |
| 483 | pre => { | 417 | 0 |
| 484 | let pre: u8 = pre.into(); | 418 | } else { |
| 485 | let pre: u8 = 1 << (pre - 3); | 419 | 1 |
| 486 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 487 | (freq, freq * 2) | ||
| 488 | } | 420 | } |
| 489 | }; | ||
| 490 | |||
| 491 | Clocks { | ||
| 492 | sys: sys_clk.hz(), | ||
| 493 | ahb1: ahb_freq.hz(), | ||
| 494 | ahb2: ahb_freq.hz(), | ||
| 495 | ahb3: ahb_freq.hz(), | ||
| 496 | apb1: apb1_freq.hz(), | ||
| 497 | apb2: apb2_freq.hz(), | ||
| 498 | apb3: apb3_freq.hz(), | ||
| 499 | apb1_tim: apb1_tim_freq.hz(), | ||
| 500 | apb2_tim: apb2_tim_freq.hz(), | ||
| 501 | } | 421 | } |
| 502 | } | 422 | }; |
| 503 | } | 423 | |
| 504 | 424 | FLASH.acr().modify(|w| { | |
| 505 | pub(crate) unsafe fn init(config: Config) { | 425 | w.set_latency(wait_states); |
| 506 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 426 | }); |
| 507 | let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal()); | 427 | |
| 508 | let clocks = r.freeze(config, &power); | 428 | RCC.cfgr1().modify(|w| { |
| 509 | set_freqs(clocks); | 429 | w.set_sw(config.mux.into()); |
| 430 | }); | ||
| 431 | |||
| 432 | RCC.cfgr2().modify(|w| { | ||
| 433 | w.set_hpre(config.ahb_pre.into()); | ||
| 434 | w.set_ppre1(config.apb1_pre.into()); | ||
| 435 | w.set_ppre2(config.apb2_pre.into()); | ||
| 436 | }); | ||
| 437 | |||
| 438 | RCC.cfgr3().modify(|w| { | ||
| 439 | w.set_ppre3(config.apb3_pre.into()); | ||
| 440 | }); | ||
| 441 | |||
| 442 | let ahb_freq: u32 = match config.ahb_pre { | ||
| 443 | AHBPrescaler::NotDivided => sys_clk, | ||
| 444 | pre => { | ||
| 445 | let pre: u8 = pre.into(); | ||
| 446 | let pre = 1 << (pre as u32 - 7); | ||
| 447 | sys_clk / pre | ||
| 448 | } | ||
| 449 | }; | ||
| 450 | |||
| 451 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 452 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 453 | pre => { | ||
| 454 | let pre: u8 = pre.into(); | ||
| 455 | let pre: u8 = 1 << (pre - 3); | ||
| 456 | let freq = ahb_freq / pre as u32; | ||
| 457 | (freq, freq * 2) | ||
| 458 | } | ||
| 459 | }; | ||
| 460 | |||
| 461 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 462 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 463 | pre => { | ||
| 464 | let pre: u8 = pre.into(); | ||
| 465 | let pre: u8 = 1 << (pre - 3); | ||
| 466 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 467 | (freq, freq * 2) | ||
| 468 | } | ||
| 469 | }; | ||
| 470 | |||
| 471 | let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { | ||
| 472 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 473 | pre => { | ||
| 474 | let pre: u8 = pre.into(); | ||
| 475 | let pre: u8 = 1 << (pre - 3); | ||
| 476 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 477 | (freq, freq * 2) | ||
| 478 | } | ||
| 479 | }; | ||
| 480 | |||
| 481 | set_freqs(Clocks { | ||
| 482 | sys: sys_clk.hz(), | ||
| 483 | ahb1: ahb_freq.hz(), | ||
| 484 | ahb2: ahb_freq.hz(), | ||
| 485 | ahb3: ahb_freq.hz(), | ||
| 486 | apb1: apb1_freq.hz(), | ||
| 487 | apb2: apb2_freq.hz(), | ||
| 488 | apb3: apb3_freq.hz(), | ||
| 489 | apb1_tim: apb1_tim_freq.hz(), | ||
| 490 | apb2_tim: apb2_tim_freq.hz(), | ||
| 491 | }); | ||
| 510 | } | 492 | } |
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index 58146d4bd..eae7c9464 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs | |||
| @@ -1,11 +1,7 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::RCC; |
| 2 | use crate::peripherals::{self, RCC}; | 2 | use crate::rcc::{set_freqs, Clocks}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | 3 | use crate::time::Hertz; |
| 5 | use crate::time::U32Ext; | 4 | use crate::time::U32Ext; |
| 6 | use core::marker::PhantomData; | ||
| 7 | use embassy::util::Unborrow; | ||
| 8 | use embassy_hal_common::unborrow; | ||
| 9 | 5 | ||
| 10 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 6 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| 11 | /// and with the addition of the init function to configure a system clock. | 7 | /// and with the addition of the init function to configure a system clock. |
| @@ -104,110 +100,68 @@ impl Default for Config { | |||
| 104 | } | 100 | } |
| 105 | } | 101 | } |
| 106 | 102 | ||
| 107 | /// RCC peripheral | 103 | pub(crate) unsafe fn init(config: Config) { |
| 108 | pub struct Rcc<'d> { | 104 | let (sys_clk, sw) = match config.mux { |
| 109 | _rb: peripherals::RCC, | 105 | ClockSrc::HSI16 => { |
| 110 | phantom: PhantomData<&'d mut peripherals::RCC>, | 106 | // Enable HSI16 |
| 111 | } | 107 | RCC.cr().write(|w| w.set_hsion(true)); |
| 108 | while !RCC.cr().read().hsirdy() {} | ||
| 112 | 109 | ||
| 113 | impl<'d> Rcc<'d> { | 110 | (HSI_FREQ, 0x01) |
| 114 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 115 | unborrow!(rcc); | ||
| 116 | Self { | ||
| 117 | _rb: rcc, | ||
| 118 | phantom: PhantomData, | ||
| 119 | } | 111 | } |
| 120 | } | 112 | ClockSrc::HSE(freq) => { |
| 121 | 113 | // Enable HSE | |
| 122 | // Safety: RCC init must have been called | 114 | RCC.cr().write(|w| w.set_hseon(true)); |
| 123 | pub fn clocks(&self) -> &'static Clocks { | 115 | while !RCC.cr().read().hserdy() {} |
| 124 | unsafe { get_freqs() } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | ||
| 129 | pub trait RccExt { | ||
| 130 | fn freeze(self, config: Config) -> Clocks; | ||
| 131 | } | ||
| 132 | 116 | ||
| 133 | impl RccExt for RCC { | 117 | (freq.0, 0x02) |
| 134 | #[inline] | ||
| 135 | fn freeze(self, cfgr: Config) -> Clocks { | ||
| 136 | let rcc = pac::RCC; | ||
| 137 | let (sys_clk, sw) = match cfgr.mux { | ||
| 138 | ClockSrc::HSI16 => { | ||
| 139 | // Enable HSI16 | ||
| 140 | unsafe { | ||
| 141 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 142 | while !rcc.cr().read().hsirdy() {} | ||
| 143 | } | ||
| 144 | |||
| 145 | (HSI_FREQ, 0x01) | ||
| 146 | } | ||
| 147 | ClockSrc::HSE(freq) => { | ||
| 148 | // Enable HSE | ||
| 149 | unsafe { | ||
| 150 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 151 | while !rcc.cr().read().hserdy() {} | ||
| 152 | } | ||
| 153 | |||
| 154 | (freq.0, 0x02) | ||
| 155 | } | ||
| 156 | }; | ||
| 157 | |||
| 158 | unsafe { | ||
| 159 | rcc.cfgr().modify(|w| { | ||
| 160 | w.set_sw(sw.into()); | ||
| 161 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 162 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 163 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 164 | }); | ||
| 165 | } | 118 | } |
| 166 | 119 | }; | |
| 167 | let ahb_freq: u32 = match cfgr.ahb_pre { | 120 | |
| 168 | AHBPrescaler::NotDivided => sys_clk, | 121 | RCC.cfgr().modify(|w| { |
| 169 | pre => { | 122 | w.set_sw(sw.into()); |
| 170 | let pre: u8 = pre.into(); | 123 | w.set_hpre(config.ahb_pre.into()); |
| 171 | let pre = 1 << (pre as u32 - 7); | 124 | w.set_ppre1(config.apb1_pre.into()); |
| 172 | sys_clk / pre | 125 | w.set_ppre2(config.apb2_pre.into()); |
| 173 | } | 126 | }); |
| 174 | }; | 127 | |
| 175 | 128 | let ahb_freq: u32 = match config.ahb_pre { | |
| 176 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | 129 | AHBPrescaler::NotDivided => sys_clk, |
| 177 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 130 | pre => { |
| 178 | pre => { | 131 | let pre: u8 = pre.into(); |
| 179 | let pre: u8 = pre.into(); | 132 | let pre = 1 << (pre as u32 - 7); |
| 180 | let pre: u8 = 1 << (pre - 3); | 133 | sys_clk / pre |
| 181 | let freq = ahb_freq / pre as u32; | ||
| 182 | (freq, freq * 2) | ||
| 183 | } | ||
| 184 | }; | ||
| 185 | |||
| 186 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | ||
| 187 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 188 | pre => { | ||
| 189 | let pre: u8 = pre.into(); | ||
| 190 | let pre: u8 = 1 << (pre - 3); | ||
| 191 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 192 | (freq, freq * 2) | ||
| 193 | } | ||
| 194 | }; | ||
| 195 | |||
| 196 | Clocks { | ||
| 197 | sys: sys_clk.hz(), | ||
| 198 | ahb1: ahb_freq.hz(), | ||
| 199 | ahb2: ahb_freq.hz(), | ||
| 200 | ahb3: ahb_freq.hz(), | ||
| 201 | apb1: apb1_freq.hz(), | ||
| 202 | apb2: apb2_freq.hz(), | ||
| 203 | apb1_tim: apb1_tim_freq.hz(), | ||
| 204 | apb2_tim: apb2_tim_freq.hz(), | ||
| 205 | } | 134 | } |
| 206 | } | 135 | }; |
| 207 | } | 136 | |
| 208 | 137 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | |
| 209 | pub(crate) unsafe fn init(config: Config) { | 138 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |
| 210 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 139 | pre => { |
| 211 | let clocks = r.freeze(config); | 140 | let pre: u8 = pre.into(); |
| 212 | set_freqs(clocks); | 141 | let pre: u8 = 1 << (pre - 3); |
| 142 | let freq = ahb_freq / pre as u32; | ||
| 143 | (freq, freq * 2) | ||
| 144 | } | ||
| 145 | }; | ||
| 146 | |||
| 147 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 148 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 149 | pre => { | ||
| 150 | let pre: u8 = pre.into(); | ||
| 151 | let pre: u8 = 1 << (pre - 3); | ||
| 152 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 153 | (freq, freq * 2) | ||
| 154 | } | ||
| 155 | }; | ||
| 156 | |||
| 157 | set_freqs(Clocks { | ||
| 158 | sys: sys_clk.hz(), | ||
| 159 | ahb1: ahb_freq.hz(), | ||
| 160 | ahb2: ahb_freq.hz(), | ||
| 161 | ahb3: ahb_freq.hz(), | ||
| 162 | apb1: apb1_freq.hz(), | ||
| 163 | apb2: apb2_freq.hz(), | ||
| 164 | apb1_tim: apb1_tim_freq.hz(), | ||
| 165 | apb2_tim: apb2_tim_freq.hz(), | ||
| 166 | }); | ||
| 213 | } | 167 | } |
diff --git a/embassy-stm32/src/rcc/wl5.rs b/embassy-stm32/src/rcc/wl5.rs index 00b91dfec..fb2dd9986 100644 --- a/embassy-stm32/src/rcc/wl5.rs +++ b/embassy-stm32/src/rcc/wl5.rs | |||
| @@ -1,10 +1,6 @@ | |||
| 1 | use crate::pac; | 1 | use crate::pac::RCC; |
| 2 | use crate::peripherals::{self, RCC}; | 2 | use crate::rcc::{set_freqs, Clocks}; |
| 3 | use crate::rcc::{get_freqs, set_freqs, Clocks}; | ||
| 4 | use crate::time::U32Ext; | 3 | use crate::time::U32Ext; |
| 5 | use core::marker::PhantomData; | ||
| 6 | use embassy::util::Unborrow; | ||
| 7 | use embassy_hal_common::unborrow; | ||
| 8 | 4 | ||
| 9 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 5 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| 10 | /// and with the addition of the init function to configure a system clock. | 6 | /// and with the addition of the init function to configure a system clock. |
| @@ -91,6 +87,7 @@ pub struct Config { | |||
| 91 | pub ahb_pre: AHBPrescaler, | 87 | pub ahb_pre: AHBPrescaler, |
| 92 | pub apb1_pre: APBPrescaler, | 88 | pub apb1_pre: APBPrescaler, |
| 93 | pub apb2_pre: APBPrescaler, | 89 | pub apb2_pre: APBPrescaler, |
| 90 | pub enable_lsi: bool, | ||
| 94 | } | 91 | } |
| 95 | 92 | ||
| 96 | impl Default for Config { | 93 | impl Default for Config { |
| @@ -101,136 +98,92 @@ impl Default for Config { | |||
| 101 | ahb_pre: AHBPrescaler::NotDivided, | 98 | ahb_pre: AHBPrescaler::NotDivided, |
| 102 | apb1_pre: APBPrescaler::NotDivided, | 99 | apb1_pre: APBPrescaler::NotDivided, |
| 103 | apb2_pre: APBPrescaler::NotDivided, | 100 | apb2_pre: APBPrescaler::NotDivided, |
| 101 | enable_lsi: false, | ||
| 104 | } | 102 | } |
| 105 | } | 103 | } |
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | /// RCC peripheral | 106 | pub(crate) unsafe fn init(config: Config) { |
| 109 | pub struct Rcc<'d> { | 107 | let (sys_clk, sw) = match config.mux { |
| 110 | _rb: peripherals::RCC, | 108 | ClockSrc::HSI16 => { |
| 111 | phantom: PhantomData<&'d mut peripherals::RCC>, | 109 | // Enable HSI16 |
| 112 | } | 110 | RCC.cr().write(|w| w.set_hsion(true)); |
| 111 | while !RCC.cr().read().hsirdy() {} | ||
| 113 | 112 | ||
| 114 | impl<'d> Rcc<'d> { | 113 | (HSI_FREQ, 0x01) |
| 115 | pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self { | ||
| 116 | unborrow!(rcc); | ||
| 117 | Self { | ||
| 118 | _rb: rcc, | ||
| 119 | phantom: PhantomData, | ||
| 120 | } | 114 | } |
| 121 | } | 115 | ClockSrc::HSE32 => { |
| 116 | // Enable HSE32 | ||
| 117 | RCC.cr().write(|w| { | ||
| 118 | w.set_hsebyppwr(true); | ||
| 119 | w.set_hseon(true); | ||
| 120 | }); | ||
| 121 | while !RCC.cr().read().hserdy() {} | ||
| 122 | 122 | ||
| 123 | pub fn enable_lsi(&mut self) { | 123 | (HSE32_FREQ, 0x02) |
| 124 | let rcc = pac::RCC; | ||
| 125 | unsafe { | ||
| 126 | let csr = rcc.csr().read(); | ||
| 127 | if !csr.lsion() { | ||
| 128 | rcc.csr().modify(|w| w.set_lsion(true)); | ||
| 129 | while !rcc.csr().read().lsirdy() {} | ||
| 130 | } | ||
| 131 | } | 124 | } |
| 132 | } | 125 | }; |
| 133 | 126 | ||
| 134 | // Safety: RCC init must have been called | 127 | RCC.cfgr().modify(|w| { |
| 135 | pub fn clocks(&self) -> &'static Clocks { | 128 | w.set_sw(sw.into()); |
| 136 | unsafe { get_freqs() } | 129 | if config.ahb_pre == AHBPrescaler::NotDivided { |
| 137 | } | 130 | w.set_hpre(0); |
| 138 | } | 131 | } else { |
| 139 | 132 | w.set_hpre(config.ahb_pre.into()); | |
| 140 | /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration | 133 | } |
| 141 | pub trait RccExt { | 134 | w.set_ppre1(config.apb1_pre.into()); |
| 142 | fn freeze(self, config: Config) -> Clocks; | 135 | w.set_ppre2(config.apb2_pre.into()); |
| 143 | } | 136 | }); |
| 144 | 137 | ||
| 145 | impl RccExt for RCC { | 138 | let ahb_freq: u32 = match config.ahb_pre { |
| 146 | #[inline] | 139 | AHBPrescaler::NotDivided => sys_clk, |
| 147 | fn freeze(self, cfgr: Config) -> Clocks { | 140 | pre => { |
| 148 | let rcc = pac::RCC; | 141 | let pre: u8 = pre.into(); |
| 149 | let (sys_clk, sw) = match cfgr.mux { | 142 | let pre = 1 << (pre as u32 - 7); |
| 150 | ClockSrc::HSI16 => { | 143 | sys_clk / pre |
| 151 | // Enable HSI16 | 144 | } |
| 152 | unsafe { | 145 | }; |
| 153 | rcc.cr().write(|w| w.set_hsion(true)); | 146 | |
| 154 | while !rcc.cr().read().hsirdy() {} | 147 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 155 | } | 148 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |
| 156 | 149 | pre => { | |
| 157 | (HSI_FREQ, 0x01) | 150 | let pre: u8 = pre.into(); |
| 158 | } | 151 | let pre: u8 = 1 << (pre - 3); |
| 159 | ClockSrc::HSE32 => { | 152 | let freq = ahb_freq / pre as u32; |
| 160 | // Enable HSE32 | 153 | (freq, freq * 2) |
| 161 | unsafe { | ||
| 162 | rcc.cr().write(|w| { | ||
| 163 | w.set_hsebyppwr(true); | ||
| 164 | w.set_hseon(true); | ||
| 165 | }); | ||
| 166 | while !rcc.cr().read().hserdy() {} | ||
| 167 | } | ||
| 168 | |||
| 169 | (HSE32_FREQ, 0x02) | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | |||
| 173 | unsafe { | ||
| 174 | rcc.cfgr().modify(|w| { | ||
| 175 | w.set_sw(sw.into()); | ||
| 176 | if cfgr.ahb_pre == AHBPrescaler::NotDivided { | ||
| 177 | w.set_hpre(0); | ||
| 178 | } else { | ||
| 179 | w.set_hpre(cfgr.ahb_pre.into()); | ||
| 180 | } | ||
| 181 | w.set_ppre1(cfgr.apb1_pre.into()); | ||
| 182 | w.set_ppre2(cfgr.apb2_pre.into()); | ||
| 183 | }); | ||
| 184 | } | 154 | } |
| 155 | }; | ||
| 156 | |||
| 157 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 158 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 159 | pre => { | ||
| 160 | let pre: u8 = pre.into(); | ||
| 161 | let pre: u8 = 1 << (pre - 3); | ||
| 162 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 163 | (freq, freq * 2) | ||
| 164 | } | ||
| 165 | }; | ||
| 166 | |||
| 167 | // TODO: completely untested | ||
| 168 | let apb3_freq = ahb_freq; | ||
| 185 | 169 | ||
| 186 | let ahb_freq: u32 = match cfgr.ahb_pre { | 170 | if config.enable_lsi { |
| 187 | AHBPrescaler::NotDivided => sys_clk, | 171 | let csr = RCC.csr().read(); |
| 188 | pre => { | 172 | if !csr.lsion() { |
| 189 | let pre: u8 = pre.into(); | 173 | RCC.csr().modify(|w| w.set_lsion(true)); |
| 190 | let pre = 1 << (pre as u32 - 7); | 174 | while !RCC.csr().read().lsirdy() {} |
| 191 | sys_clk / pre | ||
| 192 | } | ||
| 193 | }; | ||
| 194 | |||
| 195 | let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { | ||
| 196 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 197 | pre => { | ||
| 198 | let pre: u8 = pre.into(); | ||
| 199 | let pre: u8 = 1 << (pre - 3); | ||
| 200 | let freq = ahb_freq / pre as u32; | ||
| 201 | (freq, freq * 2) | ||
| 202 | } | ||
| 203 | }; | ||
| 204 | |||
| 205 | let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { | ||
| 206 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 207 | pre => { | ||
| 208 | let pre: u8 = pre.into(); | ||
| 209 | let pre: u8 = 1 << (pre - 3); | ||
| 210 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 211 | (freq, freq * 2) | ||
| 212 | } | ||
| 213 | }; | ||
| 214 | |||
| 215 | // TODO: completely untested | ||
| 216 | let apb3_freq = ahb_freq; | ||
| 217 | |||
| 218 | Clocks { | ||
| 219 | sys: sys_clk.hz(), | ||
| 220 | ahb1: ahb_freq.hz(), | ||
| 221 | ahb2: ahb_freq.hz(), | ||
| 222 | ahb3: ahb_freq.hz(), | ||
| 223 | apb1: apb1_freq.hz(), | ||
| 224 | apb2: apb2_freq.hz(), | ||
| 225 | apb3: apb3_freq.hz(), | ||
| 226 | apb1_tim: apb1_tim_freq.hz(), | ||
| 227 | apb2_tim: apb2_tim_freq.hz(), | ||
| 228 | } | 175 | } |
| 229 | } | 176 | } |
| 230 | } | ||
| 231 | 177 | ||
| 232 | pub(crate) unsafe fn init(config: Config) { | 178 | set_freqs(Clocks { |
| 233 | let r = <peripherals::RCC as embassy::util::Steal>::steal(); | 179 | sys: sys_clk.hz(), |
| 234 | let clocks = r.freeze(config); | 180 | ahb1: ahb_freq.hz(), |
| 235 | set_freqs(clocks); | 181 | ahb2: ahb_freq.hz(), |
| 182 | ahb3: ahb_freq.hz(), | ||
| 183 | apb1: apb1_freq.hz(), | ||
| 184 | apb2: apb2_freq.hz(), | ||
| 185 | apb3: apb3_freq.hz(), | ||
| 186 | apb1_tim: apb1_tim_freq.hz(), | ||
| 187 | apb2_tim: apb2_tim_freq.hz(), | ||
| 188 | }); | ||
| 236 | } | 189 | } |
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs index 20d6f5555..88c75ce6d 100644 --- a/examples/stm32l0/src/bin/button_exti.rs +++ b/examples/stm32l0/src/bin/button_exti.rs | |||
| @@ -8,16 +8,18 @@ mod example_common; | |||
| 8 | use embassy::executor::Spawner; | 8 | use embassy::executor::Spawner; |
| 9 | use embassy_stm32::exti::ExtiInput; | 9 | use embassy_stm32::exti::ExtiInput; |
| 10 | use embassy_stm32::gpio::{Input, Pull}; | 10 | use embassy_stm32::gpio::{Input, Pull}; |
| 11 | use embassy_stm32::{rcc, Peripherals}; | 11 | use embassy_stm32::Peripherals; |
| 12 | use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; | 12 | use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; |
| 13 | use example_common::*; | 13 | use example_common::*; |
| 14 | 14 | ||
| 15 | #[embassy::main] | 15 | fn config() -> embassy_stm32::Config { |
| 16 | async fn main(_spawner: Spawner, mut p: Peripherals) { | 16 | let mut config = embassy_stm32::Config::default(); |
| 17 | let mut rcc = rcc::Rcc::new(p.RCC); | 17 | config.rcc.enable_hsi48 = true; |
| 18 | // Enables SYSCFG | 18 | config |
| 19 | let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS); | 19 | } |
| 20 | 20 | ||
| 21 | #[embassy::main(config = "config()")] | ||
| 22 | async fn main(_spawner: Spawner, p: Peripherals) { | ||
| 21 | let button = Input::new(p.PB2, Pull::Up); | 23 | let button = Input::new(p.PB2, Pull::Up); |
| 22 | let mut button = ExtiInput::new(button, p.EXTI2); | 24 | let mut button = ExtiInput::new(button, p.EXTI2); |
| 23 | 25 | ||
diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs index 7ce859a8d..df08ba18c 100644 --- a/examples/stm32l0/src/bin/lorawan.rs +++ b/examples/stm32l0/src/bin/lorawan.rs | |||
| @@ -11,10 +11,8 @@ mod example_common; | |||
| 11 | 11 | ||
| 12 | use embassy_lora::{sx127x::*, LoraTimer}; | 12 | use embassy_lora::{sx127x::*, LoraTimer}; |
| 13 | use embassy_stm32::{ | 13 | use embassy_stm32::{ |
| 14 | dbgmcu::Dbgmcu, | ||
| 15 | exti::ExtiInput, | 14 | exti::ExtiInput, |
| 16 | gpio::{Input, Level, Output, Pull, Speed}, | 15 | gpio::{Input, Level, Output, Pull, Speed}, |
| 17 | rcc, | ||
| 18 | rng::Rng, | 16 | rng::Rng, |
| 19 | spi, | 17 | spi, |
| 20 | time::U32Ext, | 18 | time::U32Ext, |
| @@ -26,18 +24,12 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto; | |||
| 26 | fn config() -> embassy_stm32::Config { | 24 | fn config() -> embassy_stm32::Config { |
| 27 | let mut config = embassy_stm32::Config::default(); | 25 | let mut config = embassy_stm32::Config::default(); |
| 28 | config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; | 26 | config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; |
| 27 | config.rcc.enable_hsi48 = true; | ||
| 29 | config | 28 | config |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | #[embassy::main(config = "config()")] | 31 | #[embassy::main(config = "config()")] |
| 33 | async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) { | 32 | async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { |
| 34 | unsafe { | ||
| 35 | Dbgmcu::enable_all(); | ||
| 36 | } | ||
| 37 | |||
| 38 | let mut rcc = rcc::Rcc::new(p.RCC); | ||
| 39 | let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS); | ||
| 40 | |||
| 41 | // SPI for sx127x | 33 | // SPI for sx127x |
| 42 | let spi = spi::Spi::new( | 34 | let spi = spi::Spi::new( |
| 43 | p.SPI1, | 35 | p.SPI1, |
diff --git a/examples/stm32wl55/src/bin/lorawan.rs b/examples/stm32wl55/src/bin/lorawan.rs index 7048a5814..5d26dead2 100644 --- a/examples/stm32wl55/src/bin/lorawan.rs +++ b/examples/stm32wl55/src/bin/lorawan.rs | |||
| @@ -10,10 +10,9 @@ mod example_common; | |||
| 10 | 10 | ||
| 11 | use embassy_lora::{stm32wl::*, LoraTimer}; | 11 | use embassy_lora::{stm32wl::*, LoraTimer}; |
| 12 | use embassy_stm32::{ | 12 | use embassy_stm32::{ |
| 13 | dbgmcu::Dbgmcu, | ||
| 14 | dma::NoDma, | 13 | dma::NoDma, |
| 15 | gpio::{Level, Output, Pin, Speed}, | 14 | gpio::{Level, Output, Pin, Speed}, |
| 16 | interrupt, pac, rcc, | 15 | interrupt, pac, |
| 17 | rng::Rng, | 16 | rng::Rng, |
| 18 | subghz::*, | 17 | subghz::*, |
| 19 | Peripherals, | 18 | Peripherals, |
| @@ -24,19 +23,13 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto; | |||
| 24 | fn config() -> embassy_stm32::Config { | 23 | fn config() -> embassy_stm32::Config { |
| 25 | let mut config = embassy_stm32::Config::default(); | 24 | let mut config = embassy_stm32::Config::default(); |
| 26 | config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; | 25 | config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; |
| 26 | config.rcc.enable_lsi = true; | ||
| 27 | config | 27 | config |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | #[embassy::main(config = "config()")] | 30 | #[embassy::main(config = "config()")] |
| 31 | async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { | 31 | async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { |
| 32 | unsafe { | 32 | unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) } |
| 33 | Dbgmcu::enable_all(); | ||
| 34 | let mut rcc = rcc::Rcc::new(p.RCC); | ||
| 35 | rcc.enable_lsi(); | ||
| 36 | pac::RCC.ccipr().modify(|w| { | ||
| 37 | w.set_rngsel(0b01); | ||
| 38 | }); | ||
| 39 | } | ||
| 40 | 33 | ||
| 41 | let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High); | 34 | let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High); |
| 42 | let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High); | 35 | let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High); |
diff --git a/examples/stm32wl55/src/bin/subghz.rs b/examples/stm32wl55/src/bin/subghz.rs index a73c361c2..52fe6e9fa 100644 --- a/examples/stm32wl55/src/bin/subghz.rs +++ b/examples/stm32wl55/src/bin/subghz.rs | |||
| @@ -11,7 +11,6 @@ mod example_common; | |||
| 11 | use embassy::channel::signal::Signal; | 11 | use embassy::channel::signal::Signal; |
| 12 | use embassy::interrupt::{Interrupt, InterruptExt}; | 12 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 13 | use embassy::traits::gpio::WaitForRisingEdge; | 13 | use embassy::traits::gpio::WaitForRisingEdge; |
| 14 | use embassy_stm32::dbgmcu::Dbgmcu; | ||
| 15 | use embassy_stm32::dma::NoDma; | 14 | use embassy_stm32::dma::NoDma; |
| 16 | use embassy_stm32::exti::ExtiInput; | 15 | use embassy_stm32::exti::ExtiInput; |
| 17 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; | 16 | use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; |
| @@ -72,10 +71,6 @@ fn config() -> embassy_stm32::Config { | |||
| 72 | 71 | ||
| 73 | #[embassy::main(config = "config()")] | 72 | #[embassy::main(config = "config()")] |
| 74 | async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { | 73 | async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { |
| 75 | unsafe { | ||
| 76 | Dbgmcu::enable_all(); | ||
| 77 | } | ||
| 78 | |||
| 79 | let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); | 74 | let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); |
| 80 | let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low); | 75 | let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low); |
| 81 | let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low); | 76 | let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low); |
diff --git a/stm32-data b/stm32-data | |||
| Subproject 8530a19ffdcdcbc608a97b40895827d09e670eb | Subproject 3fa97966f07d43a28c0031175591e1c2ff5d083 | ||
