diff options
| author | Thales Fragoso <[email protected]> | 2021-06-22 20:07:48 -0300 |
|---|---|---|
| committer | Thales Fragoso <[email protected]> | 2021-06-24 19:21:56 -0300 |
| commit | 409884be2a749ddf91733dd3595c28c800358c32 (patch) | |
| tree | 904a004c8a488701edd82fa5e6a62d24b56e5fee | |
| parent | 797534d1a623b8dc0390e1df2b389612595a8643 (diff) | |
Add F0 RCC
| -rw-r--r-- | embassy-stm32/src/rcc/f0/mod.rs | 231 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 8 | ||||
| m--------- | stm32-data | 0 |
3 files changed, 238 insertions, 1 deletions
diff --git a/embassy-stm32/src/rcc/f0/mod.rs b/embassy-stm32/src/rcc/f0/mod.rs new file mode 100644 index 000000000..8ddacb8ef --- /dev/null +++ b/embassy-stm32/src/rcc/f0/mod.rs | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy::util::Unborrow; | ||
| 4 | |||
| 5 | use crate::pac::{DBGMCU, FLASH, RCC}; | ||
| 6 | use crate::peripherals; | ||
| 7 | use crate::time::Hertz; | ||
| 8 | |||
| 9 | use super::{set_freqs, Clocks}; | ||
| 10 | |||
| 11 | const HSI: u32 = 8_000_000; | ||
| 12 | |||
| 13 | /// Configuration of the clocks | ||
| 14 | /// | ||
| 15 | /// hse takes precedence over hsi48 if both are enabled | ||
| 16 | #[non_exhaustive] | ||
| 17 | #[derive(Default)] | ||
| 18 | pub struct Config { | ||
| 19 | pub hse: Option<Hertz>, | ||
| 20 | pub bypass_hse: bool, | ||
| 21 | pub usb_pll: bool, | ||
| 22 | |||
| 23 | #[cfg(rcc_f0)] | ||
| 24 | pub hsi48: bool, | ||
| 25 | |||
| 26 | pub sys_ck: Option<Hertz>, | ||
| 27 | pub hclk: Option<Hertz>, | ||
| 28 | pub pclk: Option<Hertz>, | ||
| 29 | pub enable_debug_wfe: bool, | ||
| 30 | } | ||
| 31 | |||
| 32 | pub struct Rcc<'d> { | ||
| 33 | inner: PhantomData<&'d ()>, | ||
| 34 | config: Config, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl<'d> Rcc<'d> { | ||
| 38 | pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self { | ||
| 39 | Self { | ||
| 40 | inner: PhantomData, | ||
| 41 | config, | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn freeze(self) -> Clocks { | ||
| 46 | use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; | ||
| 47 | |||
| 48 | let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI); | ||
| 49 | |||
| 50 | let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| { | ||
| 51 | #[cfg(rcc_f0)] | ||
| 52 | if self.config.hsi48 { | ||
| 53 | return (48_000_000, true); | ||
| 54 | } | ||
| 55 | (HSI, false) | ||
| 56 | }); | ||
| 57 | |||
| 58 | let (pllmul_bits, real_sysclk) = if sysclk == src_clk { | ||
| 59 | (None, sysclk) | ||
| 60 | } else { | ||
| 61 | let prediv = if self.config.hse.is_some() { 1 } else { 2 }; | ||
| 62 | let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2; | ||
| 63 | let pllmul = pllmul.max(2).min(16); | ||
| 64 | |||
| 65 | let pllmul_bits = pllmul as u8 - 2; | ||
| 66 | let real_sysclk = pllmul * src_clk / prediv; | ||
| 67 | (Some(pllmul_bits), real_sysclk) | ||
| 68 | }; | ||
| 69 | |||
| 70 | let hpre_bits = self | ||
| 71 | .config | ||
| 72 | .hclk | ||
| 73 | .map(|hclk| match real_sysclk / hclk.0 { | ||
| 74 | 0 => unreachable!(), | ||
| 75 | 1 => 0b0111, | ||
| 76 | 2 => 0b1000, | ||
| 77 | 3..=5 => 0b1001, | ||
| 78 | 6..=11 => 0b1010, | ||
| 79 | 12..=39 => 0b1011, | ||
| 80 | 40..=95 => 0b1100, | ||
| 81 | 96..=191 => 0b1101, | ||
| 82 | 192..=383 => 0b1110, | ||
| 83 | _ => 0b1111, | ||
| 84 | }) | ||
| 85 | .unwrap_or(0b0111); | ||
| 86 | let hclk = real_sysclk / (1 << (hpre_bits - 0b0111)); | ||
| 87 | |||
| 88 | let ppre_bits = self | ||
| 89 | .config | ||
| 90 | .pclk | ||
| 91 | .map(|pclk| match hclk / pclk.0 { | ||
| 92 | 0 => unreachable!(), | ||
| 93 | 1 => 0b011, | ||
| 94 | 2 => 0b100, | ||
| 95 | 3..=5 => 0b101, | ||
| 96 | 6..=11 => 0b110, | ||
| 97 | _ => 0b111, | ||
| 98 | }) | ||
| 99 | .unwrap_or(0b011); | ||
| 100 | |||
| 101 | let ppre: u8 = 1 << (ppre_bits - 0b011); | ||
| 102 | let pclk = hclk / u32::from(ppre); | ||
| 103 | |||
| 104 | let timer_mul = if ppre == 1 { 1 } else { 2 }; | ||
| 105 | |||
| 106 | // NOTE(safety) Atomic write | ||
| 107 | unsafe { | ||
| 108 | FLASH.acr().write(|w| { | ||
| 109 | let latency = if real_sysclk <= 24_000_000 { | ||
| 110 | 0 | ||
| 111 | } else if real_sysclk <= 48_000_000 { | ||
| 112 | 1 | ||
| 113 | } else { | ||
| 114 | 2 | ||
| 115 | }; | ||
| 116 | w.latency().0 = latency; | ||
| 117 | }); | ||
| 118 | } | ||
| 119 | |||
| 120 | // NOTE(unsafe) We have exclusive access to the RCC | ||
| 121 | unsafe { | ||
| 122 | match (self.config.hse.is_some(), use_hsi48) { | ||
| 123 | (true, _) => { | ||
| 124 | RCC.cr().modify(|w| { | ||
| 125 | w.set_csson(true); | ||
| 126 | w.set_hseon(true); | ||
| 127 | |||
| 128 | if self.config.bypass_hse { | ||
| 129 | w.set_hsebyp(Hsebyp::BYPASSED); | ||
| 130 | } | ||
| 131 | }); | ||
| 132 | while !RCC.cr().read().hserdy() {} | ||
| 133 | |||
| 134 | if pllmul_bits.is_some() { | ||
| 135 | RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV)) | ||
| 136 | } | ||
| 137 | } | ||
| 138 | (false, true) => { | ||
| 139 | // use_hsi48 will always be false for rcc_f0x0 | ||
| 140 | #[cfg(rcc_f0)] | ||
| 141 | RCC.cr2().modify(|w| w.set_hsi48on(true)); | ||
| 142 | #[cfg(rcc_f0)] | ||
| 143 | while !RCC.cr2().read().hsi48rdy() {} | ||
| 144 | |||
| 145 | #[cfg(rcc_f0)] | ||
| 146 | if pllmul_bits.is_some() { | ||
| 147 | RCC.cfgr() | ||
| 148 | .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV)) | ||
| 149 | } | ||
| 150 | } | ||
| 151 | _ => { | ||
| 152 | RCC.cr().modify(|w| w.set_hsion(true)); | ||
| 153 | while !RCC.cr().read().hsirdy() {} | ||
| 154 | |||
| 155 | if pllmul_bits.is_some() { | ||
| 156 | RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2)) | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | if self.config.usb_pll { | ||
| 162 | RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK)); | ||
| 163 | } | ||
| 164 | // TODO: Option to use CRS (Clock Recovery) | ||
| 165 | |||
| 166 | if let Some(pllmul_bits) = pllmul_bits { | ||
| 167 | RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); | ||
| 168 | |||
| 169 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 170 | while !RCC.cr().read().pllrdy() {} | ||
| 171 | |||
| 172 | RCC.cfgr().modify(|w| { | ||
| 173 | w.set_ppre(Ppre(ppre_bits)); | ||
| 174 | w.set_hpre(Hpre(hpre_bits)); | ||
| 175 | w.set_sw(Sw::PLL) | ||
| 176 | }); | ||
| 177 | } else { | ||
| 178 | RCC.cfgr().modify(|w| { | ||
| 179 | w.set_ppre(Ppre(ppre_bits)); | ||
| 180 | w.set_hpre(Hpre(hpre_bits)); | ||
| 181 | |||
| 182 | if self.config.hse.is_some() { | ||
| 183 | w.set_sw(Sw::HSE); | ||
| 184 | } else if use_hsi48 { | ||
| 185 | #[cfg(rcc_f0)] | ||
| 186 | w.set_sw(Sw::HSI48); | ||
| 187 | } else { | ||
| 188 | w.set_sw(Sw::HSI) | ||
| 189 | } | ||
| 190 | }) | ||
| 191 | } | ||
| 192 | |||
| 193 | if self.config.enable_debug_wfe { | ||
| 194 | RCC.ahbenr().modify(|w| w.set_dmaen(true)); | ||
| 195 | |||
| 196 | critical_section::with(|_| { | ||
| 197 | DBGMCU.cr().modify(|w| { | ||
| 198 | w.set_dbg_standby(true); | ||
| 199 | w.set_dbg_stop(true); | ||
| 200 | }); | ||
| 201 | }); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | Clocks { | ||
| 206 | sys: Hertz(real_sysclk), | ||
| 207 | apb1: Hertz(pclk), | ||
| 208 | apb1_tim: Hertz(pclk * timer_mul), | ||
| 209 | apb2_tim: Hertz(0), | ||
| 210 | ahb: Hertz(hclk), | ||
| 211 | } | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | pub unsafe fn init(config: Config) { | ||
| 216 | RCC.ahbenr().modify(|w| { | ||
| 217 | w.set_iopaen(true); | ||
| 218 | w.set_iopben(true); | ||
| 219 | w.set_iopcen(true); | ||
| 220 | w.set_iopden(true); | ||
| 221 | |||
| 222 | #[cfg(rcc_f0)] | ||
| 223 | w.set_iopeen(true); | ||
| 224 | |||
| 225 | w.set_iopfen(true); | ||
| 226 | }); | ||
| 227 | |||
| 228 | let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config); | ||
| 229 | let clocks = rcc.freeze(); | ||
| 230 | set_freqs(clocks); | ||
| 231 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index e84021272..91e8b5bef 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -9,11 +9,14 @@ mod types; | |||
| 9 | pub struct Clocks { | 9 | pub struct Clocks { |
| 10 | pub sys: Hertz, | 10 | pub sys: Hertz, |
| 11 | pub apb1: Hertz, | 11 | pub apb1: Hertz, |
| 12 | |||
| 13 | #[cfg(not(any(rcc_f0, rcc_f0x0)))] | ||
| 12 | pub apb2: Hertz, | 14 | pub apb2: Hertz, |
| 15 | |||
| 13 | pub apb1_tim: Hertz, | 16 | pub apb1_tim: Hertz, |
| 14 | pub apb2_tim: Hertz, | 17 | pub apb2_tim: Hertz, |
| 15 | 18 | ||
| 16 | #[cfg(any(rcc_l0))] | 19 | #[cfg(any(rcc_l0, rcc_f0, rcc_f0x0))] |
| 17 | pub ahb: Hertz, | 20 | pub ahb: Hertz, |
| 18 | 21 | ||
| 19 | #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55, rcc_wl5x))] | 22 | #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55, rcc_wl5x))] |
| @@ -65,6 +68,9 @@ cfg_if::cfg_if! { | |||
| 65 | } else if #[cfg(rcc_wl5x)] { | 68 | } else if #[cfg(rcc_wl5x)] { |
| 66 | mod wl5x; | 69 | mod wl5x; |
| 67 | pub use wl5x::*; | 70 | pub use wl5x::*; |
| 71 | } else if #[cfg(any(rcc_f0, rcc_f0x0))] { | ||
| 72 | mod f0; | ||
| 73 | pub use f0::*; | ||
| 68 | } | 74 | } |
| 69 | } | 75 | } |
| 70 | 76 | ||
diff --git a/stm32-data b/stm32-data | |||
| Subproject 18f86c83123771048f971350c99c4f810385d7d | Subproject eb76ee900ac67b51497196572250323e82666b4 | ||
