diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f4.rs | 400 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f4f7.rs (renamed from embassy-stm32/src/rcc/f7.rs) | 67 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 3 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/eth.rs | 22 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/hello.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/sdmmc.rs | 23 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_ethernet.rs | 24 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_serial.rs | 24 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 22 |
10 files changed, 168 insertions, 425 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ab7b92219..3b9220bc7 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -58,7 +58,7 @@ rand_core = "0.6.3" | |||
| 58 | sdio-host = "0.5.0" | 58 | sdio-host = "0.5.0" |
| 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 59 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 60 | critical-section = "1.1" | 60 | critical-section = "1.1" |
| 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6f7449303bf8af60a63704d35df9af46006c6148" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5b04234fbe61ea875f1a904cd5f68795daaeb526" } |
| 62 | vcell = "0.1.3" | 62 | vcell = "0.1.3" |
| 63 | bxcan = "0.7.0" | 63 | bxcan = "0.7.0" |
| 64 | nb = "1.0.0" | 64 | nb = "1.0.0" |
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 76 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 77 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 78 | quote = "1.0.15" |
| 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6f7449303bf8af60a63704d35df9af46006c6148", default-features = false, features = ["metadata"]} | 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5b04234fbe61ea875f1a904cd5f68795daaeb526", default-features = false, features = ["metadata"]} |
| 80 | 80 | ||
| 81 | 81 | ||
| 82 | [features] | 82 | [features] |
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs deleted file mode 100644 index eb51dc89a..000000000 --- a/embassy-stm32/src/rcc/f4.rs +++ /dev/null | |||
| @@ -1,400 +0,0 @@ | |||
| 1 | use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, Sw}; | ||
| 2 | use crate::pac::{FLASH, PWR, RCC}; | ||
| 3 | use crate::rcc::{set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | ||
| 5 | |||
| 6 | /// HSI speed | ||
| 7 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | ||
| 8 | |||
| 9 | /// Clocks configuration | ||
| 10 | #[non_exhaustive] | ||
| 11 | #[derive(Default)] | ||
| 12 | pub struct Config { | ||
| 13 | pub hse: Option<Hertz>, | ||
| 14 | pub bypass_hse: bool, | ||
| 15 | pub hclk: Option<Hertz>, | ||
| 16 | pub sys_ck: Option<Hertz>, | ||
| 17 | pub pclk1: Option<Hertz>, | ||
| 18 | pub pclk2: Option<Hertz>, | ||
| 19 | |||
| 20 | #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] | ||
| 21 | pub plli2s: Option<Hertz>, | ||
| 22 | |||
| 23 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 24 | pub pllsai: Option<Hertz>, | ||
| 25 | |||
| 26 | pub pll48: bool, | ||
| 27 | pub ls: super::LsConfig, | ||
| 28 | } | ||
| 29 | |||
| 30 | #[cfg(stm32f410)] | ||
| 31 | fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | ||
| 32 | None | ||
| 33 | } | ||
| 34 | |||
| 35 | // Not currently implemented, but will be in the future | ||
| 36 | #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] | ||
| 37 | fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> { | ||
| 38 | None | ||
| 39 | } | ||
| 40 | |||
| 41 | #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423)))] | ||
| 42 | fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> { | ||
| 43 | let min_div = 2; | ||
| 44 | let target = match target { | ||
| 45 | Some(target) => target, | ||
| 46 | None => return None, | ||
| 47 | }; | ||
| 48 | |||
| 49 | // We loop through the possible divider values to find the best configuration. Looping | ||
| 50 | // through all possible "N" values would result in more iterations. | ||
| 51 | let (n, outdiv, output, _error) = (min_div..=max_div) | ||
| 52 | .filter_map(|outdiv| { | ||
| 53 | let target_vco_out = match target.checked_mul(outdiv) { | ||
| 54 | Some(x) => x, | ||
| 55 | None => return None, | ||
| 56 | }; | ||
| 57 | let n = (target_vco_out + (vco_in >> 1)) / vco_in; | ||
| 58 | let vco_out = vco_in * n; | ||
| 59 | if !(100_000_000..=432_000_000).contains(&vco_out) { | ||
| 60 | return None; | ||
| 61 | } | ||
| 62 | let output = vco_out / outdiv; | ||
| 63 | let error = (output as i32 - target as i32).unsigned_abs(); | ||
| 64 | Some((n, outdiv, output, error)) | ||
| 65 | }) | ||
| 66 | .min_by_key(|(_, _, _, error)| *error)?; | ||
| 67 | |||
| 68 | Some((n, outdiv, output)) | ||
| 69 | } | ||
| 70 | |||
| 71 | #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] | ||
| 72 | fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> { | ||
| 73 | let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 7, plli2s)?; | ||
| 74 | |||
| 75 | RCC.plli2scfgr().modify(|w| { | ||
| 76 | w.set_plli2sn(n as u16); | ||
| 77 | w.set_plli2sr(outdiv as u8); | ||
| 78 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 79 | w.set_plli2sq(outdiv as u8); //set sai divider same as i2s | ||
| 80 | }); | ||
| 81 | |||
| 82 | Some(output) | ||
| 83 | } | ||
| 84 | |||
| 85 | #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))] | ||
| 86 | fn setup_sai_pll(_vco_in: u32, _pllsai: Option<u32>) -> Option<u32> { | ||
| 87 | None | ||
| 88 | } | ||
| 89 | |||
| 90 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 91 | fn setup_sai_pll(vco_in: u32, pllsai: Option<u32>) -> Option<u32> { | ||
| 92 | let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 15, pllsai)?; | ||
| 93 | |||
| 94 | RCC.pllsaicfgr().modify(|w| { | ||
| 95 | w.set_pllsain(n as u16); | ||
| 96 | w.set_pllsaiq(outdiv as u8); | ||
| 97 | }); | ||
| 98 | |||
| 99 | Some(output) | ||
| 100 | } | ||
| 101 | |||
| 102 | fn setup_pll( | ||
| 103 | pllsrcclk: u32, | ||
| 104 | use_hse: bool, | ||
| 105 | pllsysclk: Option<u32>, | ||
| 106 | plli2s: Option<u32>, | ||
| 107 | pllsai: Option<u32>, | ||
| 108 | pll48clk: bool, | ||
| 109 | ) -> PllResults { | ||
| 110 | use crate::pac::rcc::vals::{Pllp, Pllsrc}; | ||
| 111 | |||
| 112 | let sysclk = pllsysclk.unwrap_or(pllsrcclk); | ||
| 113 | if pllsysclk.is_none() && !pll48clk { | ||
| 114 | RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8))); | ||
| 115 | |||
| 116 | return PllResults { | ||
| 117 | use_pll: false, | ||
| 118 | pllsysclk: None, | ||
| 119 | pll48clk: None, | ||
| 120 | plli2sclk: None, | ||
| 121 | pllsaiclk: None, | ||
| 122 | }; | ||
| 123 | } | ||
| 124 | // Input divisor from PLL source clock, must result to frequency in | ||
| 125 | // the range from 1 to 2 MHz | ||
| 126 | let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000; | ||
| 127 | let pllm_max = pllsrcclk / 1_000_000; | ||
| 128 | |||
| 129 | // Sysclk output divisor must be one of 2, 4, 6 or 8 | ||
| 130 | let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1); | ||
| 131 | |||
| 132 | let target_freq = if pll48clk { 48_000_000 } else { sysclk * sysclk_div }; | ||
| 133 | |||
| 134 | // Find the lowest pllm value that minimize the difference between | ||
| 135 | // target frequency and the real vco_out frequency. | ||
| 136 | let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| { | ||
| 137 | let vco_in = pllsrcclk / pllm; | ||
| 138 | let plln = target_freq / vco_in; | ||
| 139 | target_freq - vco_in * plln | ||
| 140 | })); | ||
| 141 | |||
| 142 | let vco_in = pllsrcclk / pllm; | ||
| 143 | assert!((1_000_000..=2_000_000).contains(&vco_in)); | ||
| 144 | |||
| 145 | // Main scaler, must result in >= 100MHz (>= 192MHz for F401) | ||
| 146 | // and <= 432MHz, min 50, max 432 | ||
| 147 | let plln = if pll48clk { | ||
| 148 | // try the different valid pllq according to the valid | ||
| 149 | // main scaller values, and take the best | ||
| 150 | let pllq = unwrap!((4..=9).min_by_key(|pllq| { | ||
| 151 | let plln = 48_000_000 * pllq / vco_in; | ||
| 152 | let pll48_diff = 48_000_000 - vco_in * plln / pllq; | ||
| 153 | let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs(); | ||
| 154 | (pll48_diff, sysclk_diff) | ||
| 155 | })); | ||
| 156 | 48_000_000 * pllq / vco_in | ||
| 157 | } else { | ||
| 158 | sysclk * sysclk_div / vco_in | ||
| 159 | }; | ||
| 160 | |||
| 161 | let pllp = (sysclk_div / 2) - 1; | ||
| 162 | |||
| 163 | let pllq = (vco_in * plln + 47_999_999) / 48_000_000; | ||
| 164 | let real_pll48clk = vco_in * plln / pllq; | ||
| 165 | |||
| 166 | RCC.pllcfgr().modify(|w| { | ||
| 167 | w.set_pllm(Pllm::from_bits(pllm as u8)); | ||
| 168 | w.set_plln(Plln::from_bits(plln as u16)); | ||
| 169 | w.set_pllp(Pllp::from_bits(pllp as u8)); | ||
| 170 | w.set_pllq(Pllq::from_bits(pllq as u8)); | ||
| 171 | w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); | ||
| 172 | w.set_pllr(Pllr::from_bits(0)); | ||
| 173 | }); | ||
| 174 | |||
| 175 | let real_pllsysclk = vco_in * plln / sysclk_div; | ||
| 176 | |||
| 177 | PllResults { | ||
| 178 | use_pll: true, | ||
| 179 | pllsysclk: Some(real_pllsysclk), | ||
| 180 | pll48clk: if pll48clk { Some(real_pll48clk) } else { None }, | ||
| 181 | plli2sclk: setup_i2s_pll(vco_in, plli2s), | ||
| 182 | pllsaiclk: setup_sai_pll(vco_in, pllsai), | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | fn flash_setup(sysclk: u32) { | ||
| 187 | use crate::pac::flash::vals::Latency; | ||
| 188 | |||
| 189 | // Be conservative with voltage ranges | ||
| 190 | const FLASH_LATENCY_STEP: u32 = 30_000_000; | ||
| 191 | |||
| 192 | critical_section::with(|_| { | ||
| 193 | FLASH | ||
| 194 | .acr() | ||
| 195 | .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); | ||
| 196 | }); | ||
| 197 | } | ||
| 198 | |||
| 199 | pub(crate) unsafe fn init(config: Config) { | ||
| 200 | let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0); | ||
| 201 | let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); | ||
| 202 | let sysclk_on_pll = sysclk != pllsrcclk; | ||
| 203 | |||
| 204 | let plls = setup_pll( | ||
| 205 | pllsrcclk, | ||
| 206 | config.hse.is_some(), | ||
| 207 | if sysclk_on_pll { Some(sysclk) } else { None }, | ||
| 208 | #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] | ||
| 209 | config.plli2s.map(|i2s| i2s.0), | ||
| 210 | #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] | ||
| 211 | None, | ||
| 212 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 213 | config.pllsai.map(|sai| sai.0), | ||
| 214 | #[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))] | ||
| 215 | None, | ||
| 216 | config.pll48, | ||
| 217 | ); | ||
| 218 | |||
| 219 | if config.pll48 { | ||
| 220 | let freq = unwrap!(plls.pll48clk); | ||
| 221 | |||
| 222 | assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32); | ||
| 223 | } | ||
| 224 | |||
| 225 | let sysclk = if sysclk_on_pll { unwrap!(plls.pllsysclk) } else { sysclk }; | ||
| 226 | |||
| 227 | // AHB prescaler | ||
| 228 | let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); | ||
| 229 | let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk { | ||
| 230 | 0 => unreachable!(), | ||
| 231 | 1 => (Hpre::DIV1, 1), | ||
| 232 | 2 => (Hpre::DIV2, 2), | ||
| 233 | 3..=5 => (Hpre::DIV4, 4), | ||
| 234 | 6..=11 => (Hpre::DIV8, 8), | ||
| 235 | 12..=39 => (Hpre::DIV16, 16), | ||
| 236 | 40..=95 => (Hpre::DIV64, 64), | ||
| 237 | 96..=191 => (Hpre::DIV128, 128), | ||
| 238 | 192..=383 => (Hpre::DIV256, 256), | ||
| 239 | _ => (Hpre::DIV512, 512), | ||
| 240 | }; | ||
| 241 | |||
| 242 | // Calculate real AHB clock | ||
| 243 | let hclk = sysclk / hpre_div; | ||
| 244 | |||
| 245 | let pclk1 = config | ||
| 246 | .pclk1 | ||
| 247 | .map(|p| p.0) | ||
| 248 | .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk)); | ||
| 249 | |||
| 250 | let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 { | ||
| 251 | 0 => unreachable!(), | ||
| 252 | 1 => (0b000, 1), | ||
| 253 | 2 => (0b100, 2), | ||
| 254 | 3..=5 => (0b101, 4), | ||
| 255 | 6..=11 => (0b110, 8), | ||
| 256 | _ => (0b111, 16), | ||
| 257 | }; | ||
| 258 | let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; | ||
| 259 | |||
| 260 | // Calculate real APB1 clock | ||
| 261 | let pclk1 = hclk / ppre1; | ||
| 262 | assert!(pclk1 <= max::PCLK1_MAX); | ||
| 263 | |||
| 264 | let pclk2 = config | ||
| 265 | .pclk2 | ||
| 266 | .map(|p| p.0) | ||
| 267 | .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk)); | ||
| 268 | let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 { | ||
| 269 | 0 => unreachable!(), | ||
| 270 | 1 => (0b000, 1), | ||
| 271 | 2 => (0b100, 2), | ||
| 272 | 3..=5 => (0b101, 4), | ||
| 273 | 6..=11 => (0b110, 8), | ||
| 274 | _ => (0b111, 16), | ||
| 275 | }; | ||
| 276 | let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; | ||
| 277 | |||
| 278 | // Calculate real APB2 clock | ||
| 279 | let pclk2 = hclk / ppre2; | ||
| 280 | assert!(pclk2 <= max::PCLK2_MAX); | ||
| 281 | |||
| 282 | flash_setup(sysclk); | ||
| 283 | |||
| 284 | if config.hse.is_some() { | ||
| 285 | RCC.cr().modify(|w| { | ||
| 286 | w.set_hsebyp(config.bypass_hse); | ||
| 287 | w.set_hseon(true); | ||
| 288 | }); | ||
| 289 | while !RCC.cr().read().hserdy() {} | ||
| 290 | } | ||
| 291 | |||
| 292 | if plls.use_pll { | ||
| 293 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 294 | |||
| 295 | if hclk > max::HCLK_OVERDRIVE_FREQUENCY { | ||
| 296 | PWR.cr1().modify(|w| w.set_oden(true)); | ||
| 297 | while !PWR.csr1().read().odrdy() {} | ||
| 298 | |||
| 299 | PWR.cr1().modify(|w| w.set_odswen(true)); | ||
| 300 | while !PWR.csr1().read().odswrdy() {} | ||
| 301 | } | ||
| 302 | |||
| 303 | while !RCC.cr().read().pllrdy() {} | ||
| 304 | } | ||
| 305 | |||
| 306 | #[cfg(not(stm32f410))] | ||
| 307 | if plls.plli2sclk.is_some() { | ||
| 308 | RCC.cr().modify(|w| w.set_plli2son(true)); | ||
| 309 | |||
| 310 | while !RCC.cr().read().plli2srdy() {} | ||
| 311 | } | ||
| 312 | |||
| 313 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 314 | if plls.pllsaiclk.is_some() { | ||
| 315 | RCC.cr().modify(|w| w.set_pllsaion(true)); | ||
| 316 | while !RCC.cr().read().pllsairdy() {} | ||
| 317 | } | ||
| 318 | |||
| 319 | RCC.cfgr().modify(|w| { | ||
| 320 | w.set_ppre2(Ppre::from_bits(ppre2_bits)); | ||
| 321 | w.set_ppre1(Ppre::from_bits(ppre1_bits)); | ||
| 322 | w.set_hpre(hpre_bits); | ||
| 323 | }); | ||
| 324 | |||
| 325 | // Wait for the new prescalers to kick in | ||
| 326 | // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write" | ||
| 327 | cortex_m::asm::delay(16); | ||
| 328 | |||
| 329 | RCC.cfgr().modify(|w| { | ||
| 330 | w.set_sw(if sysclk_on_pll { | ||
| 331 | Sw::PLL1_P | ||
| 332 | } else if config.hse.is_some() { | ||
| 333 | Sw::HSE | ||
| 334 | } else { | ||
| 335 | Sw::HSI | ||
| 336 | }) | ||
| 337 | }); | ||
| 338 | |||
| 339 | let rtc = config.ls.init(); | ||
| 340 | |||
| 341 | set_freqs(Clocks { | ||
| 342 | sys: Hertz(sysclk), | ||
| 343 | pclk1: Hertz(pclk1), | ||
| 344 | pclk2: Hertz(pclk2), | ||
| 345 | |||
| 346 | pclk1_tim: Hertz(pclk1 * timer_mul1), | ||
| 347 | pclk2_tim: Hertz(pclk2 * timer_mul2), | ||
| 348 | |||
| 349 | hclk1: Hertz(hclk), | ||
| 350 | hclk2: Hertz(hclk), | ||
| 351 | hclk3: Hertz(hclk), | ||
| 352 | |||
| 353 | pll1_q: plls.pll48clk.map(Hertz), | ||
| 354 | |||
| 355 | #[cfg(not(stm32f410))] | ||
| 356 | plli2s1_q: plls.plli2sclk.map(Hertz), | ||
| 357 | #[cfg(not(stm32f410))] | ||
| 358 | plli2s1_r: None, | ||
| 359 | |||
| 360 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 361 | pllsai1_q: plls.pllsaiclk.map(Hertz), | ||
| 362 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 363 | pllsai1_r: None, | ||
| 364 | |||
| 365 | rtc, | ||
| 366 | }); | ||
| 367 | } | ||
| 368 | |||
| 369 | struct PllResults { | ||
| 370 | use_pll: bool, | ||
| 371 | pllsysclk: Option<u32>, | ||
| 372 | pll48clk: Option<u32>, | ||
| 373 | #[allow(dead_code)] | ||
| 374 | plli2sclk: Option<u32>, | ||
| 375 | #[allow(dead_code)] | ||
| 376 | pllsaiclk: Option<u32>, | ||
| 377 | } | ||
| 378 | |||
| 379 | mod max { | ||
| 380 | #[cfg(stm32f401)] | ||
| 381 | pub(crate) const SYSCLK_MAX: u32 = 84_000_000; | ||
| 382 | #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))] | ||
| 383 | pub(crate) const SYSCLK_MAX: u32 = 168_000_000; | ||
| 384 | #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))] | ||
| 385 | pub(crate) const SYSCLK_MAX: u32 = 100_000_000; | ||
| 386 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,))] | ||
| 387 | pub(crate) const SYSCLK_MAX: u32 = 180_000_000; | ||
| 388 | |||
| 389 | pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 168_000_000; | ||
| 390 | |||
| 391 | pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2; | ||
| 392 | |||
| 393 | #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))] | ||
| 394 | pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX; | ||
| 395 | #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))] | ||
| 396 | pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2; | ||
| 397 | |||
| 398 | pub(crate) const PLL_48_CLK: u32 = 48_000_000; | ||
| 399 | pub(crate) const PLL_48_TOLERANCE: u32 = 120_000; | ||
| 400 | } | ||
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f4f7.rs index a984e4f4b..de37eab72 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f4f7.rs | |||
| @@ -6,6 +6,20 @@ use crate::pac::{FLASH, PWR, RCC}; | |||
| 6 | use crate::rcc::{set_freqs, Clocks}; | 6 | use crate::rcc::{set_freqs, Clocks}; |
| 7 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| 8 | 8 | ||
| 9 | // TODO: on some F4s, PLLM is shared between all PLLs. Enforce that. | ||
| 10 | // TODO: on some F4s, add support for plli2s_src | ||
| 11 | // | ||
| 12 | // plli2s plli2s_m plli2s_src pllsai pllsai_m | ||
| 13 | // f401 y shared | ||
| 14 | // f410 | ||
| 15 | // f411 y individual | ||
| 16 | // f412 y individual y | ||
| 17 | // f4[12]3 y individual y | ||
| 18 | // f446 y individual y individual | ||
| 19 | // f4[67]9 y shared y shared | ||
| 20 | // f4[23][79] y shared y shared | ||
| 21 | // f4[01][57] y shared | ||
| 22 | |||
| 9 | /// HSI speed | 23 | /// HSI speed |
| 10 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 24 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| 11 | 25 | ||
| @@ -51,7 +65,9 @@ pub struct Config { | |||
| 51 | pub pll_src: PllSource, | 65 | pub pll_src: PllSource, |
| 52 | 66 | ||
| 53 | pub pll: Option<Pll>, | 67 | pub pll: Option<Pll>, |
| 68 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | ||
| 54 | pub plli2s: Option<Pll>, | 69 | pub plli2s: Option<Pll>, |
| 70 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | ||
| 55 | pub pllsai: Option<Pll>, | 71 | pub pllsai: Option<Pll>, |
| 56 | 72 | ||
| 57 | pub ahb_pre: AHBPrescaler, | 73 | pub ahb_pre: AHBPrescaler, |
| @@ -69,7 +85,9 @@ impl Default for Config { | |||
| 69 | sys: Sysclk::HSI, | 85 | sys: Sysclk::HSI, |
| 70 | pll_src: PllSource::HSI, | 86 | pll_src: PllSource::HSI, |
| 71 | pll: None, | 87 | pll: None, |
| 88 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | ||
| 72 | plli2s: None, | 89 | plli2s: None, |
| 90 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | ||
| 73 | pllsai: None, | 91 | pllsai: None, |
| 74 | 92 | ||
| 75 | ahb_pre: AHBPrescaler::DIV1, | 93 | ahb_pre: AHBPrescaler::DIV1, |
| @@ -128,7 +146,9 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 128 | source: config.pll_src, | 146 | source: config.pll_src, |
| 129 | }; | 147 | }; |
| 130 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); | 148 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); |
| 149 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | ||
| 131 | let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); | 150 | let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input); |
| 151 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | ||
| 132 | let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); | 152 | let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input); |
| 133 | 153 | ||
| 134 | // Configure sysclk | 154 | // Configure sysclk |
| @@ -171,6 +191,15 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 171 | pclk2_tim, | 191 | pclk2_tim, |
| 172 | rtc, | 192 | rtc, |
| 173 | pll1_q: pll.q, | 193 | pll1_q: pll.q, |
| 194 | #[cfg(all(rcc_f4, not(stm32f410)))] | ||
| 195 | plli2s1_q: _plli2s.q, | ||
| 196 | #[cfg(all(rcc_f4, not(stm32f410)))] | ||
| 197 | plli2s1_r: _plli2s.r, | ||
| 198 | |||
| 199 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 200 | pllsai1_q: _pllsai.q, | ||
| 201 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] | ||
| 202 | pllsai1_r: _pllsai.r, | ||
| 174 | }); | 203 | }); |
| 175 | } | 204 | } |
| 176 | 205 | ||
| @@ -191,7 +220,9 @@ struct PllOutput { | |||
| 191 | #[derive(PartialEq, Eq, Clone, Copy)] | 220 | #[derive(PartialEq, Eq, Clone, Copy)] |
| 192 | enum PllInstance { | 221 | enum PllInstance { |
| 193 | Pll, | 222 | Pll, |
| 223 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | ||
| 194 | Plli2s, | 224 | Plli2s, |
| 225 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | ||
| 195 | Pllsai, | 226 | Pllsai, |
| 196 | } | 227 | } |
| 197 | 228 | ||
| @@ -201,10 +232,12 @@ fn pll_enable(instance: PllInstance, enabled: bool) { | |||
| 201 | RCC.cr().modify(|w| w.set_pllon(enabled)); | 232 | RCC.cr().modify(|w| w.set_pllon(enabled)); |
| 202 | while RCC.cr().read().pllrdy() != enabled {} | 233 | while RCC.cr().read().pllrdy() != enabled {} |
| 203 | } | 234 | } |
| 235 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | ||
| 204 | PllInstance::Plli2s => { | 236 | PllInstance::Plli2s => { |
| 205 | RCC.cr().modify(|w| w.set_plli2son(enabled)); | 237 | RCC.cr().modify(|w| w.set_plli2son(enabled)); |
| 206 | while RCC.cr().read().plli2srdy() != enabled {} | 238 | while RCC.cr().read().plli2srdy() != enabled {} |
| 207 | } | 239 | } |
| 240 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | ||
| 208 | PllInstance::Pllsai => { | 241 | PllInstance::Pllsai => { |
| 209 | RCC.cr().modify(|w| w.set_pllsaion(enabled)); | 242 | RCC.cr().modify(|w| w.set_pllsaion(enabled)); |
| 210 | while RCC.cr().read().pllsairdy() != enabled {} | 243 | while RCC.cr().read().pllsairdy() != enabled {} |
| @@ -255,9 +288,11 @@ fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> Pll | |||
| 255 | w.set_pllsrc(input.source); | 288 | w.set_pllsrc(input.source); |
| 256 | write_fields!(w); | 289 | write_fields!(w); |
| 257 | }), | 290 | }), |
| 291 | #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] | ||
| 258 | PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { | 292 | PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { |
| 259 | write_fields!(w); | 293 | write_fields!(w); |
| 260 | }), | 294 | }), |
| 295 | #[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))] | ||
| 261 | PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| { | 296 | PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| { |
| 262 | write_fields!(w); | 297 | write_fields!(w); |
| 263 | }), | 298 | }), |
| @@ -294,6 +329,7 @@ where | |||
| 294 | (pclk, pclk_tim) | 329 | (pclk, pclk_tim) |
| 295 | } | 330 | } |
| 296 | 331 | ||
| 332 | #[cfg(stm32f7)] | ||
| 297 | mod max { | 333 | mod max { |
| 298 | use core::ops::RangeInclusive; | 334 | use core::ops::RangeInclusive; |
| 299 | 335 | ||
| @@ -310,3 +346,34 @@ mod max { | |||
| 310 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000); | 346 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000); |
| 311 | pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000); | 347 | pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000); |
| 312 | } | 348 | } |
| 349 | |||
| 350 | #[cfg(stm32f4)] | ||
| 351 | mod max { | ||
| 352 | use core::ops::RangeInclusive; | ||
| 353 | |||
| 354 | use crate::time::Hertz; | ||
| 355 | |||
| 356 | pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000); | ||
| 357 | pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000); | ||
| 358 | |||
| 359 | #[cfg(stm32f401)] | ||
| 360 | pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(84_000_000); | ||
| 361 | #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))] | ||
| 362 | pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(168_000_000); | ||
| 363 | #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))] | ||
| 364 | pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(100_000_000); | ||
| 365 | #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,))] | ||
| 366 | pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(180_000_000); | ||
| 367 | |||
| 368 | pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0); | ||
| 369 | |||
| 370 | pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(PCLK2.end().0 / 2); | ||
| 371 | |||
| 372 | #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))] | ||
| 373 | pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(HCLK.end().0); | ||
| 374 | #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))] | ||
| 375 | pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(HCLK.end().0 / 2); | ||
| 376 | |||
| 377 | pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000); | ||
| 378 | pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000); | ||
| 379 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index d587a1988..49174b27f 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -13,8 +13,7 @@ pub use mco::*; | |||
| 13 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] | 13 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] |
| 14 | #[cfg_attr(rcc_f2, path = "f2.rs")] | 14 | #[cfg_attr(rcc_f2, path = "f2.rs")] |
| 15 | #[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")] | 15 | #[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")] |
| 16 | #[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] | 16 | #[cfg_attr(any(rcc_f4, rcc_f410, rcc_f7), path = "f4f7.rs")] |
| 17 | #[cfg_attr(rcc_f7, path = "f7.rs")] | ||
| 18 | #[cfg_attr(rcc_c0, path = "c0.rs")] | 17 | #[cfg_attr(rcc_c0, path = "c0.rs")] |
| 19 | #[cfg_attr(rcc_g0, path = "g0.rs")] | 18 | #[cfg_attr(rcc_g0, path = "g0.rs")] |
| 20 | #[cfg_attr(rcc_g4, path = "g4.rs")] | 19 | #[cfg_attr(rcc_g4, path = "g4.rs")] |
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index ddf8596ae..1747bbf4b 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs | |||
| @@ -10,7 +10,7 @@ use embassy_stm32::eth::generic_smi::GenericSMI; | |||
| 10 | use embassy_stm32::eth::{Ethernet, PacketQueue}; | 10 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 11 | use embassy_stm32::peripherals::ETH; | 11 | use embassy_stm32::peripherals::ETH; |
| 12 | use embassy_stm32::rng::Rng; | 12 | use embassy_stm32::rng::Rng; |
| 13 | use embassy_stm32::time::mhz; | 13 | use embassy_stm32::time::Hertz; |
| 14 | use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; | 14 | use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; |
| 15 | use embassy_time::Timer; | 15 | use embassy_time::Timer; |
| 16 | use embedded_io_async::Write; | 16 | use embedded_io_async::Write; |
| @@ -32,7 +32,25 @@ async fn net_task(stack: &'static Stack<Device>) -> ! { | |||
| 32 | #[embassy_executor::main] | 32 | #[embassy_executor::main] |
| 33 | async fn main(spawner: Spawner) -> ! { | 33 | async fn main(spawner: Spawner) -> ! { |
| 34 | let mut config = Config::default(); | 34 | let mut config = Config::default(); |
| 35 | config.rcc.sys_ck = Some(mhz(200)); | 35 | { |
| 36 | use embassy_stm32::rcc::*; | ||
| 37 | config.rcc.hse = Some(Hse { | ||
| 38 | freq: Hertz(8_000_000), | ||
| 39 | mode: HseMode::Bypass, | ||
| 40 | }); | ||
| 41 | config.rcc.pll_src = PllSource::HSE; | ||
| 42 | config.rcc.pll = Some(Pll { | ||
| 43 | prediv: PllPreDiv::DIV4, | ||
| 44 | mul: PllMul::MUL180, | ||
| 45 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | ||
| 46 | divq: None, | ||
| 47 | divr: None, | ||
| 48 | }); | ||
| 49 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 50 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 51 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 52 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 53 | } | ||
| 36 | let p = embassy_stm32::init(config); | 54 | let p = embassy_stm32::init(config); |
| 37 | 55 | ||
| 38 | info!("Hello World!"); | 56 | info!("Hello World!"); |
diff --git a/examples/stm32f4/src/bin/hello.rs b/examples/stm32f4/src/bin/hello.rs index 27ee83aa5..a2a287110 100644 --- a/examples/stm32f4/src/bin/hello.rs +++ b/examples/stm32f4/src/bin/hello.rs | |||
| @@ -4,15 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::Config; | 7 | use embassy_stm32::Config; |
| 9 | use embassy_time::Timer; | 8 | use embassy_time::Timer; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 10 | ||
| 12 | #[embassy_executor::main] | 11 | #[embassy_executor::main] |
| 13 | async fn main(_spawner: Spawner) -> ! { | 12 | async fn main(_spawner: Spawner) -> ! { |
| 14 | let mut config = Config::default(); | 13 | let config = Config::default(); |
| 15 | config.rcc.sys_ck = Some(Hertz(84_000_000)); | ||
| 16 | let _p = embassy_stm32::init(config); | 14 | let _p = embassy_stm32::init(config); |
| 17 | 15 | ||
| 18 | loop { | 16 | loop { |
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 6ec7d0fec..37e42384b 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; | 7 | use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; |
| 8 | use embassy_stm32::time::mhz; | 8 | use embassy_stm32::time::{mhz, Hertz}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| @@ -20,8 +20,25 @@ bind_interrupts!(struct Irqs { | |||
| 20 | #[embassy_executor::main] | 20 | #[embassy_executor::main] |
| 21 | async fn main(_spawner: Spawner) { | 21 | async fn main(_spawner: Spawner) { |
| 22 | let mut config = Config::default(); | 22 | let mut config = Config::default(); |
| 23 | config.rcc.sys_ck = Some(mhz(48)); | 23 | { |
| 24 | config.rcc.pll48 = true; | 24 | use embassy_stm32::rcc::*; |
| 25 | config.rcc.hse = Some(Hse { | ||
| 26 | freq: Hertz(8_000_000), | ||
| 27 | mode: HseMode::Bypass, | ||
| 28 | }); | ||
| 29 | config.rcc.pll_src = PllSource::HSE; | ||
| 30 | config.rcc.pll = Some(Pll { | ||
| 31 | prediv: PllPreDiv::DIV4, | ||
| 32 | mul: PllMul::MUL168, | ||
| 33 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | ||
| 34 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | ||
| 35 | divr: None, | ||
| 36 | }); | ||
| 37 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 38 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 39 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 40 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 41 | } | ||
| 25 | let p = embassy_stm32::init(config); | 42 | let p = embassy_stm32::init(config); |
| 26 | info!("Hello World!"); | 43 | info!("Hello World!"); |
| 27 | 44 | ||
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 763e3a9e7..7c0644aeb 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs | |||
| @@ -7,7 +7,7 @@ use embassy_executor::Spawner; | |||
| 7 | use embassy_net::tcp::TcpSocket; | 7 | use embassy_net::tcp::TcpSocket; |
| 8 | use embassy_net::{Stack, StackResources}; | 8 | use embassy_net::{Stack, StackResources}; |
| 9 | use embassy_stm32::rng::{self, Rng}; | 9 | use embassy_stm32::rng::{self, Rng}; |
| 10 | use embassy_stm32::time::mhz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::usb_otg::Driver; | 11 | use embassy_stm32::usb_otg::Driver; |
| 12 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 12 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; |
| 13 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 13 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| @@ -46,9 +46,25 @@ async fn main(spawner: Spawner) { | |||
| 46 | info!("Hello World!"); | 46 | info!("Hello World!"); |
| 47 | 47 | ||
| 48 | let mut config = Config::default(); | 48 | let mut config = Config::default(); |
| 49 | config.rcc.pll48 = true; | 49 | { |
| 50 | config.rcc.sys_ck = Some(mhz(48)); | 50 | use embassy_stm32::rcc::*; |
| 51 | 51 | config.rcc.hse = Some(Hse { | |
| 52 | freq: Hertz(8_000_000), | ||
| 53 | mode: HseMode::Bypass, | ||
| 54 | }); | ||
| 55 | config.rcc.pll_src = PllSource::HSE; | ||
| 56 | config.rcc.pll = Some(Pll { | ||
| 57 | prediv: PllPreDiv::DIV4, | ||
| 58 | mul: PllMul::MUL168, | ||
| 59 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | ||
| 60 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | ||
| 61 | divr: None, | ||
| 62 | }); | ||
| 63 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 64 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 65 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 66 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 67 | } | ||
| 52 | let p = embassy_stm32::init(config); | 68 | let p = embassy_stm32::init(config); |
| 53 | 69 | ||
| 54 | // Create the driver, from the HAL. | 70 | // Create the driver, from the HAL. |
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 4ff6452ef..004ff038d 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::{panic, *}; | 5 | use defmt::{panic, *}; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::time::mhz; | 7 | use embassy_stm32::time::Hertz; |
| 8 | use embassy_stm32::usb_otg::{Driver, Instance}; | 8 | use embassy_stm32::usb_otg::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| @@ -22,9 +22,25 @@ async fn main(_spawner: Spawner) { | |||
| 22 | info!("Hello World!"); | 22 | info!("Hello World!"); |
| 23 | 23 | ||
| 24 | let mut config = Config::default(); | 24 | let mut config = Config::default(); |
| 25 | config.rcc.pll48 = true; | 25 | { |
| 26 | config.rcc.sys_ck = Some(mhz(48)); | 26 | use embassy_stm32::rcc::*; |
| 27 | 27 | config.rcc.hse = Some(Hse { | |
| 28 | freq: Hertz(8_000_000), | ||
| 29 | mode: HseMode::Bypass, | ||
| 30 | }); | ||
| 31 | config.rcc.pll_src = PllSource::HSE; | ||
| 32 | config.rcc.pll = Some(Pll { | ||
| 33 | prediv: PllPreDiv::DIV4, | ||
| 34 | mul: PllMul::MUL168, | ||
| 35 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz. | ||
| 36 | divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz. | ||
| 37 | divr: None, | ||
| 38 | }); | ||
| 39 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 40 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 41 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 42 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 43 | } | ||
| 28 | let p = embassy_stm32::init(config); | 44 | let p = embassy_stm32::init(config); |
| 29 | 45 | ||
| 30 | // Create the driver, from the HAL. | 46 | // Create the driver, from the HAL. |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 7bc741416..8dde71fb3 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -224,11 +224,23 @@ pub fn config() -> Config { | |||
| 224 | 224 | ||
| 225 | #[cfg(feature = "stm32f429zi")] | 225 | #[cfg(feature = "stm32f429zi")] |
| 226 | { | 226 | { |
| 227 | // TODO: stm32f429zi can do up to 180mhz, but that makes tests fail. | 227 | use embassy_stm32::rcc::*; |
| 228 | // perhaps we have some bug w.r.t overdrive. | 228 | config.rcc.hse = Some(Hse { |
| 229 | config.rcc.sys_ck = Some(Hertz(168_000_000)); | 229 | freq: Hertz(8_000_000), |
| 230 | config.rcc.pclk1 = Some(Hertz(42_000_000)); | 230 | mode: HseMode::Bypass, |
| 231 | config.rcc.pclk2 = Some(Hertz(84_000_000)); | 231 | }); |
| 232 | config.rcc.pll_src = PllSource::HSE; | ||
| 233 | config.rcc.pll = Some(Pll { | ||
| 234 | prediv: PllPreDiv::DIV4, | ||
| 235 | mul: PllMul::MUL180, | ||
| 236 | divp: Some(Pllp::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. | ||
| 237 | divq: None, | ||
| 238 | divr: None, | ||
| 239 | }); | ||
| 240 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | ||
| 241 | config.rcc.apb1_pre = APBPrescaler::DIV4; | ||
| 242 | config.rcc.apb2_pre = APBPrescaler::DIV2; | ||
| 243 | config.rcc.sys = Sysclk::PLL1_P; | ||
| 232 | } | 244 | } |
| 233 | 245 | ||
| 234 | #[cfg(feature = "stm32f767zi")] | 246 | #[cfg(feature = "stm32f767zi")] |
