diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-10-16 01:41:40 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-16 01:41:40 +0000 |
| commit | 870dcc5970cbd043049e0ce2c9cde208c11a7d32 (patch) | |
| tree | 3f397b190810b92564bc6e416f9f591b85c03748 | |
| parent | f54753beaade16a5c56c27c70b51adaac175e0ae (diff) | |
| parent | 5c5e6818195b364199e583eb559b0042d392b3e7 (diff) | |
Merge pull request #2069 from embassy-rs/rcc-no-spaghetti
stm32/rcc: add better support for L4/L4+ differences.
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l4.rs | 335 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l5.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/adc.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/rng.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/rtc.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 2 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usb_serial.rs | 2 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 2 |
10 files changed, 207 insertions, 156 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 290bcf6aa..50ccd7934 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-01a757e40df688efcda23607185640e1c2396ba9" } | 61 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73e3f8a965a01fd5a168c3543b93ce49d475e130" } |
| 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-01a757e40df688efcda23607185640e1c2396ba9", default-features = false, features = ["metadata"]} | 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73e3f8a965a01fd5a168c3543b93ce49d475e130", default-features = false, features = ["metadata"]} |
| 80 | 80 | ||
| 81 | 81 | ||
| 82 | [features] | 82 | [features] |
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 43c29281e..aceafc490 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | use crate::pac::rcc::regs::Cfgr; | 1 | use crate::pac::rcc::regs::Cfgr; |
| 2 | use crate::pac::rcc::vals::Msirgsel; | ||
| 2 | pub use crate::pac::rcc::vals::{ | 3 | pub use crate::pac::rcc::vals::{ |
| 3 | Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, | 4 | Clk48sel as Clk48Src, Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, |
| 4 | Pllr as PllRDiv, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc, | 5 | Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc, |
| 5 | }; | 6 | }; |
| 6 | use crate::pac::{FLASH, RCC}; | 7 | use crate::pac::{FLASH, RCC}; |
| 7 | use crate::rcc::{set_freqs, Clocks}; | 8 | use crate::rcc::{set_freqs, Clocks}; |
| @@ -12,6 +13,9 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); | |||
| 12 | 13 | ||
| 13 | #[derive(Clone, Copy)] | 14 | #[derive(Clone, Copy)] |
| 14 | pub struct Pll { | 15 | pub struct Pll { |
| 16 | /// PLL source | ||
| 17 | pub source: PLLSource, | ||
| 18 | |||
| 15 | /// PLL pre-divider (DIVM). | 19 | /// PLL pre-divider (DIVM). |
| 16 | pub prediv: PllPreDiv, | 20 | pub prediv: PllPreDiv, |
| 17 | 21 | ||
| @@ -32,11 +36,10 @@ pub struct Config { | |||
| 32 | pub msi: Option<MSIRange>, | 36 | pub msi: Option<MSIRange>, |
| 33 | pub hsi16: bool, | 37 | pub hsi16: bool, |
| 34 | pub hse: Option<Hertz>, | 38 | pub hse: Option<Hertz>, |
| 35 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 39 | #[cfg(not(any(stm32l47x, stm32l48x)))] |
| 36 | pub hsi48: bool, | 40 | pub hsi48: bool, |
| 37 | 41 | ||
| 38 | // pll | 42 | // pll |
| 39 | pub pll_src: PLLSource, | ||
| 40 | pub pll: Option<Pll>, | 43 | pub pll: Option<Pll>, |
| 41 | pub pllsai1: Option<Pll>, | 44 | pub pllsai1: Option<Pll>, |
| 42 | #[cfg(any( | 45 | #[cfg(any( |
| @@ -50,6 +53,9 @@ pub struct Config { | |||
| 50 | pub apb1_pre: APBPrescaler, | 53 | pub apb1_pre: APBPrescaler, |
| 51 | pub apb2_pre: APBPrescaler, | 54 | pub apb2_pre: APBPrescaler, |
| 52 | 55 | ||
| 56 | // muxes | ||
| 57 | pub clk48_src: Clk48Src, | ||
| 58 | |||
| 53 | // low speed LSI/LSE/RTC | 59 | // low speed LSI/LSE/RTC |
| 54 | pub ls: super::LsConfig, | 60 | pub ls: super::LsConfig, |
| 55 | } | 61 | } |
| @@ -65,7 +71,6 @@ impl Default for Config { | |||
| 65 | ahb_pre: AHBPrescaler::DIV1, | 71 | ahb_pre: AHBPrescaler::DIV1, |
| 66 | apb1_pre: APBPrescaler::DIV1, | 72 | apb1_pre: APBPrescaler::DIV1, |
| 67 | apb2_pre: APBPrescaler::DIV1, | 73 | apb2_pre: APBPrescaler::DIV1, |
| 68 | pll_src: PLLSource::NONE, | ||
| 69 | pll: None, | 74 | pll: None, |
| 70 | pllsai1: None, | 75 | pllsai1: None, |
| 71 | #[cfg(any( | 76 | #[cfg(any( |
| @@ -73,7 +78,8 @@ impl Default for Config { | |||
| 73 | ))] | 78 | ))] |
| 74 | pllsai2: None, | 79 | pllsai2: None, |
| 75 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 80 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] |
| 76 | hsi48: false, | 81 | hsi48: true, |
| 82 | clk48_src: Clk48Src::HSI48, | ||
| 77 | ls: Default::default(), | 83 | ls: Default::default(), |
| 78 | } | 84 | } |
| 79 | } | 85 | } |
| @@ -84,7 +90,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 84 | if !RCC.cr().read().msion() { | 90 | if !RCC.cr().read().msion() { |
| 85 | // Turn on MSI and configure it to 4MHz. | 91 | // Turn on MSI and configure it to 4MHz. |
| 86 | RCC.cr().modify(|w| { | 92 | RCC.cr().modify(|w| { |
| 87 | w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0]. | 93 | w.set_msirgsel(Msirgsel::CR); |
| 88 | w.set_msirange(MSIRange::RANGE4M); | 94 | w.set_msirange(MSIRange::RANGE4M); |
| 89 | w.set_msipllen(false); | 95 | w.set_msipllen(false); |
| 90 | w.set_msion(true) | 96 | w.set_msion(true) |
| @@ -106,7 +112,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 106 | // Enable MSI | 112 | // Enable MSI |
| 107 | RCC.cr().write(|w| { | 113 | RCC.cr().write(|w| { |
| 108 | w.set_msirange(range); | 114 | w.set_msirange(range); |
| 109 | w.set_msirgsel(true); | 115 | w.set_msirgsel(Msirgsel::CR); |
| 110 | w.set_msion(true); | 116 | w.set_msion(true); |
| 111 | 117 | ||
| 112 | // If LSE is enabled, enable calibration of MSI | 118 | // If LSE is enabled, enable calibration of MSI |
| @@ -115,9 +121,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 115 | while !RCC.cr().read().msirdy() {} | 121 | while !RCC.cr().read().msirdy() {} |
| 116 | 122 | ||
| 117 | // Enable as clock source for USB, RNG if running at 48 MHz | 123 | // Enable as clock source for USB, RNG if running at 48 MHz |
| 118 | if range == MSIRange::RANGE48M { | 124 | if range == MSIRange::RANGE48M {} |
| 119 | RCC.ccipr().modify(|w| w.set_clk48sel(0b11)); | ||
| 120 | } | ||
| 121 | 125 | ||
| 122 | msirange_to_hertz(range) | 126 | msirange_to_hertz(range) |
| 123 | }); | 127 | }); |
| @@ -136,154 +140,66 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 136 | freq | 140 | freq |
| 137 | }); | 141 | }); |
| 138 | 142 | ||
| 139 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 143 | #[cfg(not(any(stm32l47x, stm32l48x)))] |
| 140 | let _hsi48 = config.hsi48.then(|| { | 144 | let hsi48 = config.hsi48.then(|| { |
| 141 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); | 145 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); |
| 142 | while !RCC.crrcr().read().hsi48rdy() {} | 146 | while !RCC.crrcr().read().hsi48rdy() {} |
| 143 | 147 | ||
| 144 | // Enable as clock source for USB, RNG and SDMMC | ||
| 145 | RCC.ccipr().modify(|w| w.set_clk48sel(0)); | ||
| 146 | |||
| 147 | Hertz(48_000_000) | 148 | Hertz(48_000_000) |
| 148 | }); | 149 | }); |
| 149 | 150 | #[cfg(any(stm32l47x, stm32l48x))] | |
| 150 | let pll_src = match config.pll_src { | 151 | let hsi48 = None; |
| 151 | PLLSource::NONE => None, | 152 | |
| 152 | PLLSource::HSE => hse, | 153 | let _plls = [ |
| 153 | PLLSource::HSI16 => hsi16, | 154 | &config.pll, |
| 154 | PLLSource::MSI => msi, | 155 | &config.pllsai1, |
| 156 | #[cfg(any( | ||
| 157 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 158 | ))] | ||
| 159 | &config.pllsai2, | ||
| 160 | ]; | ||
| 161 | |||
| 162 | // L4 has shared PLLSRC, PLLM, check it's equal in all PLLs. | ||
| 163 | #[cfg(all(stm32l4, not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))))] | ||
| 164 | match get_equal(_plls.into_iter().flatten().map(|p| (p.source, p.prediv))) { | ||
| 165 | Err(()) => panic!("Source must be equal across all enabled PLLs."), | ||
| 166 | Ok(None) => {} | ||
| 167 | Ok(Some((source, prediv))) => RCC.pllcfgr().write(|w| { | ||
| 168 | w.set_pllm(prediv); | ||
| 169 | w.set_pllsrc(source); | ||
| 170 | }), | ||
| 155 | }; | 171 | }; |
| 156 | 172 | ||
| 157 | let mut _pllp = None; | 173 | // L4+ has shared PLLSRC, check it's equal in all PLLs. |
| 158 | let mut _pllq = None; | 174 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] |
| 159 | let mut _pllr = None; | 175 | match get_equal(_plls.into_iter().flatten().map(|p| p.source)) { |
| 160 | if let Some(pll) = config.pll { | 176 | Err(()) => panic!("Source must be equal across all enabled PLLs."), |
| 161 | let pll_src = pll_src.unwrap(); | 177 | Ok(None) => {} |
| 162 | 178 | Ok(Some(source)) => RCC.pllcfgr().write(|w| { | |
| 163 | // Disable PLL | 179 | w.set_pllsrc(source); |
| 164 | RCC.cr().modify(|w| w.set_pllon(false)); | 180 | }), |
| 165 | while RCC.cr().read().pllrdy() {} | 181 | }; |
| 166 | |||
| 167 | let vco_freq = pll_src / pll.prediv * pll.mul; | ||
| 168 | |||
| 169 | _pllp = pll.divp.map(|div| vco_freq / div); | ||
| 170 | _pllq = pll.divq.map(|div| vco_freq / div); | ||
| 171 | _pllr = pll.divr.map(|div| vco_freq / div); | ||
| 172 | |||
| 173 | RCC.pllcfgr().write(move |w| { | ||
| 174 | w.set_plln(pll.mul); | ||
| 175 | w.set_pllm(pll.prediv); | ||
| 176 | w.set_pllsrc(config.pll_src); | ||
| 177 | if let Some(divp) = pll.divp { | ||
| 178 | w.set_pllp(divp); | ||
| 179 | w.set_pllpen(true); | ||
| 180 | } | ||
| 181 | if let Some(divq) = pll.divq { | ||
| 182 | w.set_pllq(divq); | ||
| 183 | w.set_pllqen(true); | ||
| 184 | } | ||
| 185 | if let Some(divr) = pll.divr { | ||
| 186 | w.set_pllr(divr); | ||
| 187 | w.set_pllren(true); | ||
| 188 | } | ||
| 189 | }); | ||
| 190 | |||
| 191 | if _pllq == Some(Hertz(48_000_000)) { | ||
| 192 | RCC.ccipr().modify(|w| w.set_clk48sel(0b10)); | ||
| 193 | } | ||
| 194 | |||
| 195 | // Enable PLL | ||
| 196 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 197 | while !RCC.cr().read().pllrdy() {} | ||
| 198 | } else { | ||
| 199 | // even if we're not using the main pll, set the source for pllsai | ||
| 200 | RCC.pllcfgr().write(move |w| { | ||
| 201 | w.set_pllsrc(config.pll_src); | ||
| 202 | }); | ||
| 203 | } | ||
| 204 | |||
| 205 | if let Some(pll) = config.pllsai1 { | ||
| 206 | let pll_src = pll_src.unwrap(); | ||
| 207 | |||
| 208 | // Disable PLL | ||
| 209 | RCC.cr().modify(|w| w.set_pllsai1on(false)); | ||
| 210 | while RCC.cr().read().pllsai1rdy() {} | ||
| 211 | |||
| 212 | let vco_freq = pll_src / pll.prediv * pll.mul; | ||
| 213 | |||
| 214 | let _pllp = pll.divp.map(|div| vco_freq / div); | ||
| 215 | let _pllq = pll.divq.map(|div| vco_freq / div); | ||
| 216 | let _pllr = pll.divr.map(|div| vco_freq / div); | ||
| 217 | |||
| 218 | RCC.pllsai1cfgr().write(move |w| { | ||
| 219 | w.set_plln(pll.mul); | ||
| 220 | w.set_pllm(pll.prediv); | ||
| 221 | if let Some(divp) = pll.divp { | ||
| 222 | w.set_pllp(divp); | ||
| 223 | w.set_pllpen(true); | ||
| 224 | } | ||
| 225 | if let Some(divq) = pll.divq { | ||
| 226 | w.set_pllq(divq); | ||
| 227 | w.set_pllqen(true); | ||
| 228 | } | ||
| 229 | if let Some(divr) = pll.divr { | ||
| 230 | w.set_pllr(divr); | ||
| 231 | w.set_pllren(true); | ||
| 232 | } | ||
| 233 | }); | ||
| 234 | |||
| 235 | if _pllq == Some(Hertz(48_000_000)) { | ||
| 236 | RCC.ccipr().modify(|w| w.set_clk48sel(0b01)); | ||
| 237 | } | ||
| 238 | |||
| 239 | // Enable PLL | ||
| 240 | RCC.cr().modify(|w| w.set_pllsai1on(true)); | ||
| 241 | while !RCC.cr().read().pllsai1rdy() {} | ||
| 242 | } | ||
| 243 | 182 | ||
| 183 | let pll_input = PllInput { hse, hsi16, msi }; | ||
| 184 | let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); | ||
| 185 | let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input); | ||
| 244 | #[cfg(any( | 186 | #[cfg(any( |
| 245 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | 187 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx |
| 246 | ))] | 188 | ))] |
| 247 | if let Some(pll) = config.pllsai2 { | 189 | let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input); |
| 248 | let pll_src = pll_src.unwrap(); | ||
| 249 | |||
| 250 | // Disable PLL | ||
| 251 | RCC.cr().modify(|w| w.set_pllsai2on(false)); | ||
| 252 | while RCC.cr().read().pllsai2rdy() {} | ||
| 253 | |||
| 254 | let vco_freq = pll_src / pll.prediv * pll.mul; | ||
| 255 | |||
| 256 | let _pllp = pll.divp.map(|div| vco_freq / div); | ||
| 257 | let _pllq = pll.divq.map(|div| vco_freq / div); | ||
| 258 | let _pllr = pll.divr.map(|div| vco_freq / div); | ||
| 259 | |||
| 260 | RCC.pllsai2cfgr().write(move |w| { | ||
| 261 | w.set_plln(pll.mul); | ||
| 262 | w.set_pllm(pll.prediv); | ||
| 263 | if let Some(divp) = pll.divp { | ||
| 264 | w.set_pllp(divp); | ||
| 265 | w.set_pllpen(true); | ||
| 266 | } | ||
| 267 | if let Some(divq) = pll.divq { | ||
| 268 | w.set_pllq(divq); | ||
| 269 | w.set_pllqen(true); | ||
| 270 | } | ||
| 271 | if let Some(divr) = pll.divr { | ||
| 272 | w.set_pllr(divr); | ||
| 273 | w.set_pllren(true); | ||
| 274 | } | ||
| 275 | }); | ||
| 276 | |||
| 277 | // Enable PLL | ||
| 278 | RCC.cr().modify(|w| w.set_pllsai2on(true)); | ||
| 279 | while !RCC.cr().read().pllsai2rdy() {} | ||
| 280 | } | ||
| 281 | 190 | ||
| 282 | let sys_clk = match config.mux { | 191 | let sys_clk = match config.mux { |
| 283 | ClockSrc::HSE => hse.unwrap(), | 192 | ClockSrc::HSE => hse.unwrap(), |
| 284 | ClockSrc::HSI16 => hsi16.unwrap(), | 193 | ClockSrc::HSI16 => hsi16.unwrap(), |
| 285 | ClockSrc::MSI => msi.unwrap(), | 194 | ClockSrc::MSI => msi.unwrap(), |
| 286 | ClockSrc::PLL => _pllr.unwrap(), | 195 | ClockSrc::PLL => pll._r.unwrap(), |
| 196 | }; | ||
| 197 | |||
| 198 | let _clk48 = match config.clk48_src { | ||
| 199 | Clk48Src::HSI48 => hsi48, | ||
| 200 | Clk48Src::MSI => msi, | ||
| 201 | Clk48Src::PLLSAI1_Q => pllsai1._q, | ||
| 202 | Clk48Src::PLL_Q => pll._q, | ||
| 287 | }; | 203 | }; |
| 288 | 204 | ||
| 289 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | 205 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] |
| @@ -357,3 +273,136 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz { | |||
| 357 | _ => unreachable!(), | 273 | _ => unreachable!(), |
| 358 | } | 274 | } |
| 359 | } | 275 | } |
| 276 | |||
| 277 | fn get_equal<T: Eq>(mut iter: impl Iterator<Item = T>) -> Result<Option<T>, ()> { | ||
| 278 | let Some(x) = iter.next() else { return Ok(None) }; | ||
| 279 | if !iter.all(|y| y == x) { | ||
| 280 | return Err(()); | ||
| 281 | } | ||
| 282 | return Ok(Some(x)); | ||
| 283 | } | ||
| 284 | |||
| 285 | struct PllInput { | ||
| 286 | hsi16: Option<Hertz>, | ||
| 287 | hse: Option<Hertz>, | ||
| 288 | msi: Option<Hertz>, | ||
| 289 | } | ||
| 290 | |||
| 291 | #[derive(Default)] | ||
| 292 | struct PllOutput { | ||
| 293 | _p: Option<Hertz>, | ||
| 294 | _q: Option<Hertz>, | ||
| 295 | _r: Option<Hertz>, | ||
| 296 | } | ||
| 297 | |||
| 298 | #[derive(PartialEq, Eq, Clone, Copy)] | ||
| 299 | enum PllInstance { | ||
| 300 | Pll, | ||
| 301 | Pllsai1, | ||
| 302 | #[cfg(any( | ||
| 303 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 304 | ))] | ||
| 305 | Pllsai2, | ||
| 306 | } | ||
| 307 | |||
| 308 | fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput { | ||
| 309 | // Disable PLL | ||
| 310 | match instance { | ||
| 311 | PllInstance::Pll => { | ||
| 312 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 313 | while RCC.cr().read().pllrdy() {} | ||
| 314 | } | ||
| 315 | PllInstance::Pllsai1 => { | ||
| 316 | RCC.cr().modify(|w| w.set_pllsai1on(false)); | ||
| 317 | while RCC.cr().read().pllsai1rdy() {} | ||
| 318 | } | ||
| 319 | #[cfg(any( | ||
| 320 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 321 | ))] | ||
| 322 | PllInstance::Pllsai2 => { | ||
| 323 | RCC.cr().modify(|w| w.set_pllsai2on(false)); | ||
| 324 | while RCC.cr().read().pllsai2rdy() {} | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | let Some(pll) = config else { return PllOutput::default() }; | ||
| 329 | |||
| 330 | let pll_src = match pll.source { | ||
| 331 | PLLSource::NONE => panic!("must not select PLL source as NONE"), | ||
| 332 | PLLSource::HSE => input.hse, | ||
| 333 | PLLSource::HSI16 => input.hsi16, | ||
| 334 | PLLSource::MSI => input.msi, | ||
| 335 | }; | ||
| 336 | |||
| 337 | let pll_src = pll_src.unwrap(); | ||
| 338 | |||
| 339 | let vco_freq = pll_src / pll.prediv * pll.mul; | ||
| 340 | |||
| 341 | let p = pll.divp.map(|div| vco_freq / div); | ||
| 342 | let q = pll.divq.map(|div| vco_freq / div); | ||
| 343 | let r = pll.divr.map(|div| vco_freq / div); | ||
| 344 | |||
| 345 | macro_rules! write_fields { | ||
| 346 | ($w:ident) => { | ||
| 347 | $w.set_plln(pll.mul); | ||
| 348 | if let Some(divp) = pll.divp { | ||
| 349 | $w.set_pllp(divp); | ||
| 350 | $w.set_pllpen(true); | ||
| 351 | } | ||
| 352 | if let Some(divq) = pll.divq { | ||
| 353 | $w.set_pllq(divq); | ||
| 354 | $w.set_pllqen(true); | ||
| 355 | } | ||
| 356 | if let Some(divr) = pll.divr { | ||
| 357 | $w.set_pllr(divr); | ||
| 358 | $w.set_pllren(true); | ||
| 359 | } | ||
| 360 | }; | ||
| 361 | } | ||
| 362 | |||
| 363 | match instance { | ||
| 364 | PllInstance::Pll => RCC.pllcfgr().write(|w| { | ||
| 365 | w.set_pllm(pll.prediv); | ||
| 366 | w.set_pllsrc(pll.source); | ||
| 367 | write_fields!(w); | ||
| 368 | }), | ||
| 369 | PllInstance::Pllsai1 => RCC.pllsai1cfgr().write(|w| { | ||
| 370 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx, stm32l5))] | ||
| 371 | w.set_pllm(pll.prediv); | ||
| 372 | #[cfg(stm32l5)] | ||
| 373 | w.set_pllsrc(pll.source); | ||
| 374 | write_fields!(w); | ||
| 375 | }), | ||
| 376 | #[cfg(any( | ||
| 377 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 378 | ))] | ||
| 379 | PllInstance::Pllsai2 => RCC.pllsai2cfgr().write(|w| { | ||
| 380 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx, stm32l5))] | ||
| 381 | w.set_pllm(pll.prediv); | ||
| 382 | #[cfg(stm32l5)] | ||
| 383 | w.set_pllsrc(pll.source); | ||
| 384 | write_fields!(w); | ||
| 385 | }), | ||
| 386 | } | ||
| 387 | |||
| 388 | // Enable PLL | ||
| 389 | match instance { | ||
| 390 | PllInstance::Pll => { | ||
| 391 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 392 | while !RCC.cr().read().pllrdy() {} | ||
| 393 | } | ||
| 394 | PllInstance::Pllsai1 => { | ||
| 395 | RCC.cr().modify(|w| w.set_pllsai1on(true)); | ||
| 396 | while !RCC.cr().read().pllsai1rdy() {} | ||
| 397 | } | ||
| 398 | #[cfg(any( | ||
| 399 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 400 | ))] | ||
| 401 | PllInstance::Pllsai2 => { | ||
| 402 | RCC.cr().modify(|w| w.set_pllsai2on(true)); | ||
| 403 | while !RCC.cr().read().pllsai2rdy() {} | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | PllOutput { _p: p, _q: q, _r: r } | ||
| 408 | } | ||
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 289217b19..7e095a6b2 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs | |||
| @@ -104,7 +104,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 104 | // Enable as clock source for USB, RNG if running at 48 MHz | 104 | // Enable as clock source for USB, RNG if running at 48 MHz |
| 105 | if range == MSIRange::RANGE48M { | 105 | if range == MSIRange::RANGE48M { |
| 106 | RCC.ccipr1().modify(|w| { | 106 | RCC.ccipr1().modify(|w| { |
| 107 | w.set_clk48msel(0b11); | 107 | w.set_clk48sel(0b11); |
| 108 | }); | 108 | }); |
| 109 | } | 109 | } |
| 110 | (msirange_to_hertz(range), Sw::MSI) | 110 | (msirange_to_hertz(range), Sw::MSI) |
| @@ -173,7 +173,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 173 | let freq = src_freq / prediv * mul / divq; | 173 | let freq = src_freq / prediv * mul / divq; |
| 174 | assert!(freq.0 == 48_000_000); | 174 | assert!(freq.0 == 48_000_000); |
| 175 | RCC.ccipr1().modify(|w| { | 175 | RCC.ccipr1().modify(|w| { |
| 176 | w.set_clk48msel(0b10); | 176 | w.set_clk48sel(0b10); |
| 177 | }); | 177 | }); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| @@ -191,7 +191,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 191 | let freq = src_freq / prediv * mul / q_div; | 191 | let freq = src_freq / prediv * mul / q_div; |
| 192 | if freq.0 == 48_000_000 { | 192 | if freq.0 == 48_000_000 { |
| 193 | RCC.ccipr1().modify(|w| { | 193 | RCC.ccipr1().modify(|w| { |
| 194 | w.set_clk48msel(0b1); | 194 | w.set_clk48sel(0b1); |
| 195 | }); | 195 | }); |
| 196 | } | 196 | } |
| 197 | } | 197 | } |
| @@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 218 | while !RCC.crrcr().read().hsi48rdy() {} | 218 | while !RCC.crrcr().read().hsi48rdy() {} |
| 219 | 219 | ||
| 220 | // Enable as clock source for USB, RNG and SDMMC | 220 | // Enable as clock source for USB, RNG and SDMMC |
| 221 | RCC.ccipr1().modify(|w| w.set_clk48msel(0)); | 221 | RCC.ccipr1().modify(|w| w.set_clk48sel(0)); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | // Set flash wait states | 224 | // Set flash wait states |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 9df40baac..76c9f34b0 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -20,7 +20,7 @@ pub use mco::*; | |||
| 20 | #[cfg_attr(rcc_g4, path = "g4.rs")] | 20 | #[cfg_attr(rcc_g4, path = "g4.rs")] |
| 21 | #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] | 21 | #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] |
| 22 | #[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")] | 22 | #[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")] |
| 23 | #[cfg_attr(rcc_l4, path = "l4.rs")] | 23 | #[cfg_attr(any(rcc_l4, rcc_l4plus), path = "l4.rs")] |
| 24 | #[cfg_attr(rcc_l5, path = "l5.rs")] | 24 | #[cfg_attr(rcc_l5, path = "l5.rs")] |
| 25 | #[cfg_attr(rcc_u5, path = "u5.rs")] | 25 | #[cfg_attr(rcc_u5, path = "u5.rs")] |
| 26 | #[cfg_attr(rcc_wb, path = "wb.rs")] | 26 | #[cfg_attr(rcc_wb, path = "wb.rs")] |
| @@ -65,6 +65,7 @@ pub struct Clocks { | |||
| 65 | pub hclk1: Hertz, | 65 | pub hclk1: Hertz, |
| 66 | #[cfg(any( | 66 | #[cfg(any( |
| 67 | rcc_l4, | 67 | rcc_l4, |
| 68 | rcc_l4plus, | ||
| 68 | rcc_l5, | 69 | rcc_l5, |
| 69 | rcc_f2, | 70 | rcc_f2, |
| 70 | rcc_f4, | 71 | rcc_f4, |
| @@ -85,6 +86,7 @@ pub struct Clocks { | |||
| 85 | pub hclk2: Hertz, | 86 | pub hclk2: Hertz, |
| 86 | #[cfg(any( | 87 | #[cfg(any( |
| 87 | rcc_l4, | 88 | rcc_l4, |
| 89 | rcc_l4plus, | ||
| 88 | rcc_l5, | 90 | rcc_l5, |
| 89 | rcc_f2, | 91 | rcc_f2, |
| 90 | rcc_f4, | 92 | rcc_f4, |
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index 1771e5202..3d0c623fd 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs | |||
| @@ -13,7 +13,7 @@ fn main() -> ! { | |||
| 13 | info!("Hello World!"); | 13 | info!("Hello World!"); |
| 14 | 14 | ||
| 15 | pac::RCC.ccipr().modify(|w| { | 15 | pac::RCC.ccipr().modify(|w| { |
| 16 | w.set_adcsel(0b11); | 16 | w.set_adcsel(pac::rcc::vals::Adcsel::SYSCLK); |
| 17 | }); | 17 | }); |
| 18 | pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | 18 | pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); |
| 19 | 19 | ||
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index 94251c12c..d184bcf77 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs | |||
| @@ -18,8 +18,8 @@ async fn main(_spawner: Spawner) { | |||
| 18 | let mut config = Config::default(); | 18 | let mut config = Config::default(); |
| 19 | config.rcc.mux = ClockSrc::PLL; | 19 | config.rcc.mux = ClockSrc::PLL; |
| 20 | config.rcc.hsi16 = true; | 20 | config.rcc.hsi16 = true; |
| 21 | config.rcc.pll_src = PLLSource::HSI16; | ||
| 22 | config.rcc.pll = Some(Pll { | 21 | config.rcc.pll = Some(Pll { |
| 22 | source: PLLSource::HSI16, | ||
| 23 | prediv: PllPreDiv::DIV1, | 23 | prediv: PllPreDiv::DIV1, |
| 24 | mul: PllMul::MUL18, | 24 | mul: PllMul::MUL18, |
| 25 | divp: None, | 25 | divp: None, |
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index cd9f72ff3..a1b41f84a 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs | |||
| @@ -17,8 +17,8 @@ async fn main(_spawner: Spawner) { | |||
| 17 | let mut config = Config::default(); | 17 | let mut config = Config::default(); |
| 18 | config.rcc.mux = ClockSrc::PLL; | 18 | config.rcc.mux = ClockSrc::PLL; |
| 19 | config.rcc.hse = Some(Hertz::mhz(8)); | 19 | config.rcc.hse = Some(Hertz::mhz(8)); |
| 20 | config.rcc.pll_src = PLLSource::HSE; | ||
| 21 | config.rcc.pll = Some(Pll { | 20 | config.rcc.pll = Some(Pll { |
| 21 | source: PLLSource::HSE, | ||
| 22 | prediv: PllPreDiv::DIV1, | 22 | prediv: PllPreDiv::DIV1, |
| 23 | mul: PllMul::MUL20, | 23 | mul: PllMul::MUL20, |
| 24 | divp: None, | 24 | divp: None, |
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index c1a27cf83..278d65438 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs | |||
| @@ -79,8 +79,8 @@ async fn main(spawner: Spawner) { | |||
| 79 | // 80MHz highest frequency for flash 0 wait. | 79 | // 80MHz highest frequency for flash 0 wait. |
| 80 | config.rcc.mux = ClockSrc::PLL; | 80 | config.rcc.mux = ClockSrc::PLL; |
| 81 | config.rcc.hse = Some(Hertz::mhz(8)); | 81 | config.rcc.hse = Some(Hertz::mhz(8)); |
| 82 | config.rcc.pll_src = PLLSource::HSE; | ||
| 83 | config.rcc.pll = Some(Pll { | 82 | config.rcc.pll = Some(Pll { |
| 83 | source: PLLSource::HSE, | ||
| 84 | prediv: PllPreDiv::DIV1, | 84 | prediv: PllPreDiv::DIV1, |
| 85 | mul: PllMul::MUL20, | 85 | mul: PllMul::MUL20, |
| 86 | divp: None, | 86 | divp: None, |
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 8f6eeef32..3785c6898 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs | |||
| @@ -26,8 +26,8 @@ async fn main(_spawner: Spawner) { | |||
| 26 | config.rcc.hsi48 = true; | 26 | config.rcc.hsi48 = true; |
| 27 | config.rcc.mux = ClockSrc::PLL; | 27 | config.rcc.mux = ClockSrc::PLL; |
| 28 | config.rcc.hsi16 = true; | 28 | config.rcc.hsi16 = true; |
| 29 | config.rcc.pll_src = PLLSource::HSI16; | ||
| 30 | config.rcc.pll = Some(Pll { | 29 | config.rcc.pll = Some(Pll { |
| 30 | source: PLLSource::HSI16, | ||
| 31 | prediv: PllPreDiv::DIV1, | 31 | prediv: PllPreDiv::DIV1, |
| 32 | mul: PllMul::MUL10, | 32 | mul: PllMul::MUL10, |
| 33 | divp: None, | 33 | divp: None, |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index e1d7855fc..c5a24044a 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -289,8 +289,8 @@ pub fn config() -> Config { | |||
| 289 | use embassy_stm32::rcc::*; | 289 | use embassy_stm32::rcc::*; |
| 290 | config.rcc.mux = ClockSrc::PLL; | 290 | config.rcc.mux = ClockSrc::PLL; |
| 291 | config.rcc.hsi16 = true; | 291 | config.rcc.hsi16 = true; |
| 292 | config.rcc.pll_src = PLLSource::HSI16; | ||
| 293 | config.rcc.pll = Some(Pll { | 292 | config.rcc.pll = Some(Pll { |
| 293 | source: PLLSource::HSI16, | ||
| 294 | prediv: PllPreDiv::DIV1, | 294 | prediv: PllPreDiv::DIV1, |
| 295 | mul: PllMul::MUL18, | 295 | mul: PllMul::MUL18, |
| 296 | divp: None, | 296 | divp: None, |
