diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-10-15 03:08:14 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-10-15 03:08:49 +0200 |
| commit | 8a10948ce97fa3b3c29cf55c91585789dd0f360c (patch) | |
| tree | 4ad52bcc18d35459e4431b4f65c66c243a152efb | |
| parent | 7045c5317091c8e81b0dbe64c9788bb2667472b1 (diff) | |
stm32/rcc: port L4 to the "flattened" API like h5/h7.
| -rw-r--r-- | embassy-stm32/src/rcc/l4.rs | 379 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/rng.rs | 20 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/rtc.rs | 28 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 19 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usb_serial.rs | 11 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 20 |
6 files changed, 279 insertions, 198 deletions
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 1e5733d31..020f4e200 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | use crate::pac::rcc::regs::Cfgr; | 1 | use crate::pac::rcc::regs::Cfgr; |
| 2 | pub use crate::pac::rcc::vals::{ | 2 | 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, | 3 | Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, |
| 4 | Pllr as PllRDiv, Ppre as APBPrescaler, | 4 | Pllr as PllRDiv, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc, |
| 5 | }; | 5 | }; |
| 6 | use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw}; | ||
| 7 | use crate::pac::{FLASH, RCC}; | 6 | use crate::pac::{FLASH, RCC}; |
| 8 | use crate::rcc::{set_freqs, Clocks}; | 7 | use crate::rcc::{set_freqs, Clocks}; |
| 9 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| @@ -11,42 +10,47 @@ use crate::time::Hertz; | |||
| 11 | /// HSI speed | 10 | /// HSI speed |
| 12 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 11 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| 13 | 12 | ||
| 14 | /// System clock mux source | ||
| 15 | #[derive(Clone, Copy)] | 13 | #[derive(Clone, Copy)] |
| 16 | pub enum ClockSrc { | 14 | pub struct Pll { |
| 17 | MSI(MSIRange), | 15 | /// PLL pre-divider (DIVM). |
| 18 | PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option<PllQDiv>), | 16 | pub prediv: PllPreDiv, |
| 19 | HSE(Hertz), | 17 | |
| 20 | HSI16, | 18 | /// PLL multiplication factor. |
| 21 | } | 19 | pub mul: PllMul, |
| 22 | 20 | ||
| 23 | /// PLL clock input source | 21 | /// PLL P division factor. If None, PLL P output is disabled. |
| 24 | #[derive(Clone, Copy)] | 22 | pub divp: Option<PllPDiv>, |
| 25 | pub enum PLLSource { | 23 | /// PLL Q division factor. If None, PLL Q output is disabled. |
| 26 | HSI16, | 24 | pub divq: Option<PllQDiv>, |
| 27 | HSE(Hertz), | 25 | /// PLL R division factor. If None, PLL R output is disabled. |
| 28 | MSI(MSIRange), | 26 | pub divr: Option<PllRDiv>, |
| 29 | } | ||
| 30 | |||
| 31 | impl From<PLLSource> for Pllsrc { | ||
| 32 | fn from(val: PLLSource) -> Pllsrc { | ||
| 33 | match val { | ||
| 34 | PLLSource::HSI16 => Pllsrc::HSI16, | ||
| 35 | PLLSource::HSE(_) => Pllsrc::HSE, | ||
| 36 | PLLSource::MSI(_) => Pllsrc::MSI, | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | 27 | } |
| 40 | 28 | ||
| 41 | /// Clocks configutation | 29 | /// Clocks configutation |
| 42 | pub struct Config { | 30 | pub struct Config { |
| 31 | // base clock sources | ||
| 32 | pub msi: Option<MSIRange>, | ||
| 33 | pub hsi16: bool, | ||
| 34 | pub hse: Option<Hertz>, | ||
| 35 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | ||
| 36 | pub hsi48: bool, | ||
| 37 | |||
| 38 | // pll | ||
| 39 | pub pll_src: PLLSource, | ||
| 40 | pub pll: Option<Pll>, | ||
| 41 | pub pllsai1: Option<Pll>, | ||
| 42 | #[cfg(any( | ||
| 43 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 44 | ))] | ||
| 45 | pub pllsai2: Option<Pll>, | ||
| 46 | |||
| 47 | // sysclk, buses. | ||
| 43 | pub mux: ClockSrc, | 48 | pub mux: ClockSrc, |
| 44 | pub ahb_pre: AHBPrescaler, | 49 | pub ahb_pre: AHBPrescaler, |
| 45 | pub apb1_pre: APBPrescaler, | 50 | pub apb1_pre: APBPrescaler, |
| 46 | pub apb2_pre: APBPrescaler, | 51 | pub apb2_pre: APBPrescaler, |
| 47 | pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>, | 52 | |
| 48 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 53 | // low speed LSI/LSE/RTC |
| 49 | pub hsi48: bool, | ||
| 50 | pub ls: super::LsConfig, | 54 | pub ls: super::LsConfig, |
| 51 | } | 55 | } |
| 52 | 56 | ||
| @@ -54,11 +58,20 @@ impl Default for Config { | |||
| 54 | #[inline] | 58 | #[inline] |
| 55 | fn default() -> Config { | 59 | fn default() -> Config { |
| 56 | Config { | 60 | Config { |
| 57 | mux: ClockSrc::MSI(MSIRange::RANGE4M), | 61 | hse: None, |
| 62 | hsi16: false, | ||
| 63 | msi: Some(MSIRange::RANGE4M), | ||
| 64 | mux: ClockSrc::MSI, | ||
| 58 | ahb_pre: AHBPrescaler::DIV1, | 65 | ahb_pre: AHBPrescaler::DIV1, |
| 59 | apb1_pre: APBPrescaler::DIV1, | 66 | apb1_pre: APBPrescaler::DIV1, |
| 60 | apb2_pre: APBPrescaler::DIV1, | 67 | apb2_pre: APBPrescaler::DIV1, |
| 68 | pll_src: PLLSource::NONE, | ||
| 69 | pll: None, | ||
| 61 | pllsai1: None, | 70 | pllsai1: None, |
| 71 | #[cfg(any( | ||
| 72 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 73 | ))] | ||
| 74 | pllsai2: None, | ||
| 62 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 75 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] |
| 63 | hsi48: false, | 76 | hsi48: false, |
| 64 | ls: Default::default(), | 77 | ls: Default::default(), |
| @@ -80,154 +93,204 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 80 | // Wait until MSI is running | 93 | // Wait until MSI is running |
| 81 | while !RCC.cr().read().msirdy() {} | 94 | while !RCC.cr().read().msirdy() {} |
| 82 | } | 95 | } |
| 83 | if RCC.cfgr().read().sws() != Sw::MSI { | 96 | if RCC.cfgr().read().sws() != ClockSrc::MSI { |
| 84 | // Set MSI as a clock source, reset prescalers. | 97 | // Set MSI as a clock source, reset prescalers. |
| 85 | RCC.cfgr().write_value(Cfgr::default()); | 98 | RCC.cfgr().write_value(Cfgr::default()); |
| 86 | // Wait for clock switch status bits to change. | 99 | // Wait for clock switch status bits to change. |
| 87 | while RCC.cfgr().read().sws() != Sw::MSI {} | 100 | while RCC.cfgr().read().sws() != ClockSrc::MSI {} |
| 88 | } | 101 | } |
| 89 | 102 | ||
| 90 | let rtc = config.ls.init(); | 103 | let rtc = config.ls.init(); |
| 91 | 104 | ||
| 92 | let (sys_clk, sw) = match config.mux { | 105 | let msi = config.msi.map(|range| { |
| 93 | ClockSrc::MSI(range) => { | 106 | // Enable MSI |
| 94 | // Enable MSI | 107 | RCC.cr().write(|w| { |
| 95 | RCC.cr().write(|w| { | 108 | w.set_msirange(range); |
| 96 | w.set_msirange(range); | 109 | w.set_msirgsel(true); |
| 97 | w.set_msirgsel(true); | 110 | w.set_msion(true); |
| 98 | w.set_msion(true); | ||
| 99 | |||
| 100 | // If LSE is enabled, enable calibration of MSI | ||
| 101 | w.set_msipllen(config.ls.lse.is_some()); | ||
| 102 | }); | ||
| 103 | while !RCC.cr().read().msirdy() {} | ||
| 104 | |||
| 105 | // Enable as clock source for USB, RNG if running at 48 MHz | ||
| 106 | if range == MSIRange::RANGE48M { | ||
| 107 | RCC.ccipr().modify(|w| { | ||
| 108 | w.set_clk48sel(0b11); | ||
| 109 | }); | ||
| 110 | } | ||
| 111 | (msirange_to_hertz(range), Sw::MSI) | ||
| 112 | } | ||
| 113 | ClockSrc::HSI16 => { | ||
| 114 | // Enable HSI16 | ||
| 115 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 116 | while !RCC.cr().read().hsirdy() {} | ||
| 117 | 111 | ||
| 118 | (HSI_FREQ, Sw::HSI16) | 112 | // If LSE is enabled, enable calibration of MSI |
| 119 | } | 113 | w.set_msipllen(config.ls.lse.is_some()); |
| 120 | ClockSrc::HSE(freq) => { | 114 | }); |
| 121 | // Enable HSE | 115 | while !RCC.cr().read().msirdy() {} |
| 122 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 123 | while !RCC.cr().read().hserdy() {} | ||
| 124 | 116 | ||
| 125 | (freq, Sw::HSE) | 117 | // Enable as clock source for USB, RNG if running at 48 MHz |
| 118 | if range == MSIRange::RANGE48M { | ||
| 119 | RCC.ccipr().modify(|w| w.set_clk48sel(0b11)); | ||
| 126 | } | 120 | } |
| 127 | ClockSrc::PLL(src, divr, prediv, mul, divq) => { | ||
| 128 | let src_freq = match src { | ||
| 129 | PLLSource::HSE(freq) => { | ||
| 130 | // Enable HSE | ||
| 131 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 132 | while !RCC.cr().read().hserdy() {} | ||
| 133 | freq | ||
| 134 | } | ||
| 135 | PLLSource::HSI16 => { | ||
| 136 | // Enable HSI | ||
| 137 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 138 | while !RCC.cr().read().hsirdy() {} | ||
| 139 | HSI_FREQ | ||
| 140 | } | ||
| 141 | PLLSource::MSI(range) => { | ||
| 142 | // Enable MSI | ||
| 143 | RCC.cr().write(|w| { | ||
| 144 | w.set_msirange(range); | ||
| 145 | w.set_msipllen(false); // should be turned on if LSE is started | ||
| 146 | w.set_msirgsel(true); | ||
| 147 | w.set_msion(true); | ||
| 148 | }); | ||
| 149 | while !RCC.cr().read().msirdy() {} | ||
| 150 | |||
| 151 | msirange_to_hertz(range) | ||
| 152 | } | ||
| 153 | }; | ||
| 154 | |||
| 155 | // Disable PLL | ||
| 156 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 157 | while RCC.cr().read().pllrdy() {} | ||
| 158 | |||
| 159 | let freq = src_freq / prediv * mul / divr; | ||
| 160 | |||
| 161 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | ||
| 162 | assert!(freq.0 <= 120_000_000); | ||
| 163 | #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] | ||
| 164 | assert!(freq.0 <= 80_000_000); | ||
| 165 | |||
| 166 | RCC.pllcfgr().write(move |w| { | ||
| 167 | w.set_plln(mul); | ||
| 168 | w.set_pllm(prediv); | ||
| 169 | w.set_pllr(divr); | ||
| 170 | if let Some(divq) = divq { | ||
| 171 | w.set_pllq(divq); | ||
| 172 | w.set_pllqen(true); | ||
| 173 | } | ||
| 174 | w.set_pllsrc(src.into()); | ||
| 175 | }); | ||
| 176 | |||
| 177 | // Enable as clock source for USB, RNG if PLL48 divisor is provided | ||
| 178 | if let Some(divq) = divq { | ||
| 179 | let freq = src_freq / prediv * mul / divq; | ||
| 180 | assert!(freq.0 == 48_000_000); | ||
| 181 | RCC.ccipr().modify(|w| { | ||
| 182 | w.set_clk48sel(0b10); | ||
| 183 | }); | ||
| 184 | } | ||
| 185 | 121 | ||
| 186 | if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { | 122 | msirange_to_hertz(range) |
| 187 | RCC.pllsai1cfgr().write(move |w| { | 123 | }); |
| 188 | w.set_plln(mul); | ||
| 189 | w.set_pllm(prediv); | ||
| 190 | if let Some(r_div) = r_div { | ||
| 191 | w.set_pllr(r_div); | ||
| 192 | w.set_pllren(true); | ||
| 193 | } | ||
| 194 | if let Some(q_div) = q_div { | ||
| 195 | w.set_pllq(q_div); | ||
| 196 | w.set_pllqen(true); | ||
| 197 | let freq = src_freq / prediv * mul / q_div; | ||
| 198 | if freq.0 == 48_000_000 { | ||
| 199 | RCC.ccipr().modify(|w| { | ||
| 200 | w.set_clk48sel(0b1); | ||
| 201 | }); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | if let Some(p_div) = p_div { | ||
| 205 | w.set_pllp(p_div); | ||
| 206 | w.set_pllpen(true); | ||
| 207 | } | ||
| 208 | }); | ||
| 209 | |||
| 210 | RCC.cr().modify(|w| w.set_pllsai1on(true)); | ||
| 211 | } | ||
| 212 | 124 | ||
| 213 | // Enable PLL | 125 | let hsi16 = config.hsi16.then(|| { |
| 214 | RCC.cr().modify(|w| w.set_pllon(true)); | 126 | RCC.cr().write(|w| w.set_hsion(true)); |
| 215 | while !RCC.cr().read().pllrdy() {} | 127 | while !RCC.cr().read().hsirdy() {} |
| 216 | RCC.pllcfgr().modify(|w| w.set_pllren(true)); | ||
| 217 | 128 | ||
| 218 | (freq, Sw::PLL) | 129 | HSI_FREQ |
| 219 | } | 130 | }); |
| 220 | }; | 131 | |
| 132 | let hse = config.hse.map(|freq| { | ||
| 133 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 134 | while !RCC.cr().read().hserdy() {} | ||
| 135 | |||
| 136 | freq | ||
| 137 | }); | ||
| 221 | 138 | ||
| 222 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | 139 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] |
| 223 | if config.hsi48 { | 140 | let _hsi48 = config.hsi48.then(|| { |
| 224 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); | 141 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); |
| 225 | while !RCC.crrcr().read().hsi48rdy() {} | 142 | while !RCC.crrcr().read().hsi48rdy() {} |
| 226 | 143 | ||
| 227 | // Enable as clock source for USB, RNG and SDMMC | 144 | // Enable as clock source for USB, RNG and SDMMC |
| 228 | RCC.ccipr().modify(|w| w.set_clk48sel(0)); | 145 | RCC.ccipr().modify(|w| w.set_clk48sel(0)); |
| 146 | |||
| 147 | Hertz(48_000_000) | ||
| 148 | }); | ||
| 149 | |||
| 150 | let pll_src = match config.pll_src { | ||
| 151 | PLLSource::NONE => None, | ||
| 152 | PLLSource::HSE => hse, | ||
| 153 | PLLSource::HSI16 => hsi16, | ||
| 154 | PLLSource::MSI => msi, | ||
| 155 | }; | ||
| 156 | |||
| 157 | let mut _pllp = None; | ||
| 158 | let mut _pllq = None; | ||
| 159 | let mut _pllr = None; | ||
| 160 | if let Some(pll) = config.pll { | ||
| 161 | let pll_src = pll_src.unwrap(); | ||
| 162 | |||
| 163 | // Disable PLL | ||
| 164 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 165 | while RCC.cr().read().pllrdy() {} | ||
| 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 | |||
| 244 | #[cfg(any( | ||
| 245 | stm32l47x, stm32l48x, stm32l49x, stm32l4ax, stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx | ||
| 246 | ))] | ||
| 247 | if let Some(pll) = config.pllsai2 { | ||
| 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() {} | ||
| 229 | } | 280 | } |
| 230 | 281 | ||
| 282 | let sys_clk = match config.mux { | ||
| 283 | ClockSrc::HSE => hse.unwrap(), | ||
| 284 | ClockSrc::HSI16 => hsi16.unwrap(), | ||
| 285 | ClockSrc::MSI => msi.unwrap(), | ||
| 286 | ClockSrc::PLL => _pllr.unwrap(), | ||
| 287 | }; | ||
| 288 | |||
| 289 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | ||
| 290 | assert!(sys_clk.0 <= 120_000_000); | ||
| 291 | #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] | ||
| 292 | assert!(sys_clk.0 <= 80_000_000); | ||
| 293 | |||
| 231 | // Set flash wait states | 294 | // Set flash wait states |
| 232 | FLASH.acr().modify(|w| { | 295 | FLASH.acr().modify(|w| { |
| 233 | w.set_latency(match sys_clk.0 { | 296 | w.set_latency(match sys_clk.0 { |
| @@ -240,7 +303,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 240 | }); | 303 | }); |
| 241 | 304 | ||
| 242 | RCC.cfgr().modify(|w| { | 305 | RCC.cfgr().modify(|w| { |
| 243 | w.set_sw(sw); | 306 | w.set_sw(config.mux); |
| 244 | w.set_hpre(config.ahb_pre); | 307 | w.set_hpre(config.ahb_pre); |
| 245 | w.set_ppre1(config.apb1_pre); | 308 | w.set_ppre1(config.apb1_pre); |
| 246 | w.set_ppre2(config.apb2_pre); | 309 | w.set_ppre2(config.apb2_pre); |
| @@ -277,7 +340,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 277 | }); | 340 | }); |
| 278 | } | 341 | } |
| 279 | 342 | ||
| 280 | fn msirange_to_hertz(range: Msirange) -> Hertz { | 343 | fn msirange_to_hertz(range: MSIRange) -> Hertz { |
| 281 | match range { | 344 | match range { |
| 282 | MSIRange::RANGE100K => Hertz(100_000), | 345 | MSIRange::RANGE100K => Hertz(100_000), |
| 283 | MSIRange::RANGE200K => Hertz(200_000), | 346 | MSIRange::RANGE200K => Hertz(200_000), |
diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index d0208d8a3..94251c12c 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllQDiv, PllRDiv}; | 7 | use embassy_stm32::rcc::{ClockSrc, PLLSource, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv}; |
| 8 | use embassy_stm32::rng::Rng; | 8 | use embassy_stm32::rng::Rng; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | 9 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| @@ -16,14 +16,16 @@ bind_interrupts!(struct Irqs { | |||
| 16 | #[embassy_executor::main] | 16 | #[embassy_executor::main] |
| 17 | async fn main(_spawner: Spawner) { | 17 | async fn main(_spawner: Spawner) { |
| 18 | let mut config = Config::default(); | 18 | let mut config = Config::default(); |
| 19 | // 72Mhz clock (16 / 1 * 18 / 4) | 19 | config.rcc.mux = ClockSrc::PLL; |
| 20 | config.rcc.mux = ClockSrc::PLL( | 20 | config.rcc.hsi16 = true; |
| 21 | PLLSource::HSI16, | 21 | config.rcc.pll_src = PLLSource::HSI16; |
| 22 | PllRDiv::DIV4, | 22 | config.rcc.pll = Some(Pll { |
| 23 | PllPreDiv::DIV1, | 23 | prediv: PllPreDiv::DIV1, |
| 24 | PllMul::MUL18, | 24 | mul: PllMul::MUL18, |
| 25 | Some(PllQDiv::DIV6), // 48Mhz (16 / 1 * 18 / 6) | 25 | divp: None, |
| 26 | ); | 26 | divq: Some(PllQDiv::DIV6), // 48Mhz (16 / 1 * 18 / 6) |
| 27 | divr: Some(PllRDiv::DIV4), // sysclk 72Mhz clock (16 / 1 * 18 / 4) | ||
| 28 | }); | ||
| 27 | let p = embassy_stm32::init(config); | 29 | let p = embassy_stm32::init(config); |
| 28 | 30 | ||
| 29 | info!("Hello World!"); | 31 | info!("Hello World!"); |
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index f5d46e95f..cd9f72ff3 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | use chrono::{NaiveDate, NaiveDateTime}; | 5 | use chrono::{NaiveDate, NaiveDateTime}; |
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_stm32::rcc::{ClockSrc, LsConfig, PLLSource, PllMul, PllPreDiv, PllRDiv}; | 8 | use embassy_stm32::rcc::{ClockSrc, LsConfig, PLLSource, Pll, PllMul, PllPreDiv, PllRDiv}; |
| 9 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | 9 | use embassy_stm32::rtc::{Rtc, RtcConfig}; |
| 10 | use embassy_stm32::time::Hertz; | 10 | use embassy_stm32::time::Hertz; |
| 11 | use embassy_stm32::Config; | 11 | use embassy_stm32::Config; |
| @@ -14,18 +14,20 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 14 | 14 | ||
| 15 | #[embassy_executor::main] | 15 | #[embassy_executor::main] |
| 16 | async fn main(_spawner: Spawner) { | 16 | async fn main(_spawner: Spawner) { |
| 17 | let p = { | 17 | let mut config = Config::default(); |
| 18 | let mut config = Config::default(); | 18 | config.rcc.mux = ClockSrc::PLL; |
| 19 | config.rcc.mux = ClockSrc::PLL( | 19 | config.rcc.hse = Some(Hertz::mhz(8)); |
| 20 | PLLSource::HSE(Hertz::mhz(8)), | 20 | config.rcc.pll_src = PLLSource::HSE; |
| 21 | PllRDiv::DIV2, | 21 | config.rcc.pll = Some(Pll { |
| 22 | PllPreDiv::DIV1, | 22 | prediv: PllPreDiv::DIV1, |
| 23 | PllMul::MUL20, | 23 | mul: PllMul::MUL20, |
| 24 | None, | 24 | divp: None, |
| 25 | ); | 25 | divq: None, |
| 26 | config.rcc.ls = LsConfig::default_lse(); | 26 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz clock (8 / 1 * 20 / 2) |
| 27 | embassy_stm32::init(config) | 27 | }); |
| 28 | }; | 28 | config.rcc.ls = LsConfig::default_lse(); |
| 29 | let p = embassy_stm32::init(config); | ||
| 30 | |||
| 29 | info!("Hello World!"); | 31 | info!("Hello World!"); |
| 30 | 32 | ||
| 31 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) | 33 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) |
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index e2ac22d09..c1a27cf83 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs | |||
| @@ -48,7 +48,7 @@ use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; | |||
| 48 | use embedded_hal_bus::spi::ExclusiveDevice; | 48 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 49 | use hal::gpio::Pull; | 49 | use hal::gpio::Pull; |
| 50 | use hal::i2c::Config as I2C_Config; | 50 | use hal::i2c::Config as I2C_Config; |
| 51 | use hal::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllRDiv}; | 51 | use hal::rcc::{ClockSrc, PLLSource, Pll, PllMul, PllPreDiv, PllRDiv}; |
| 52 | use hal::spi::{Config as SPI_Config, Spi}; | 52 | use hal::spi::{Config as SPI_Config, Spi}; |
| 53 | use hal::time::Hertz; | 53 | use hal::time::Hertz; |
| 54 | 54 | ||
| @@ -77,13 +77,16 @@ async fn main(spawner: Spawner) { | |||
| 77 | 77 | ||
| 78 | // 80Mhz clock (Source: 8 / SrcDiv: 1 * PLLMul 20 / ClkDiv 2) | 78 | // 80Mhz clock (Source: 8 / SrcDiv: 1 * PLLMul 20 / ClkDiv 2) |
| 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 | PLLSource::HSE(Hertz(8_000_000)), | 81 | config.rcc.hse = Some(Hertz::mhz(8)); |
| 82 | PllRDiv::DIV2, | 82 | config.rcc.pll_src = PLLSource::HSE; |
| 83 | PllPreDiv::DIV1, | 83 | config.rcc.pll = Some(Pll { |
| 84 | PllMul::MUL20, | 84 | prediv: PllPreDiv::DIV1, |
| 85 | None, | 85 | mul: PllMul::MUL20, |
| 86 | ); | 86 | divp: None, |
| 87 | divq: None, | ||
| 88 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz clock (8 / 1 * 20 / 2) | ||
| 89 | }); | ||
| 87 | config.rcc.hsi48 = true; // needed for rng | 90 | config.rcc.hsi48 = true; // needed for rng |
| 88 | 91 | ||
| 89 | let dp = embassy_stm32::init(config); | 92 | let dp = embassy_stm32::init(config); |
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index dc0d98ad4..8f6eeef32 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs | |||
| @@ -23,8 +23,17 @@ async fn main(_spawner: Spawner) { | |||
| 23 | info!("Hello World!"); | 23 | info!("Hello World!"); |
| 24 | 24 | ||
| 25 | let mut config = Config::default(); | 25 | let mut config = Config::default(); |
| 26 | config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); | ||
| 27 | config.rcc.hsi48 = true; | 26 | config.rcc.hsi48 = true; |
| 27 | config.rcc.mux = ClockSrc::PLL; | ||
| 28 | config.rcc.hsi16 = true; | ||
| 29 | config.rcc.pll_src = PLLSource::HSI16; | ||
| 30 | config.rcc.pll = Some(Pll { | ||
| 31 | prediv: PllPreDiv::DIV1, | ||
| 32 | mul: PllMul::MUL10, | ||
| 33 | divp: None, | ||
| 34 | divq: None, | ||
| 35 | divr: Some(PllRDiv::DIV2), // sysclk 80Mhz (16 / 1 * 10 / 2) | ||
| 36 | }); | ||
| 28 | 37 | ||
| 29 | let p = embassy_stm32::init(config); | 38 | let p = embassy_stm32::init(config); |
| 30 | 39 | ||
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 2bf500798..e1d7855fc 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -284,17 +284,19 @@ pub fn config() -> Config { | |||
| 284 | config.rcc.adc_clock_source = AdcClockSource::PLL2_P; | 284 | config.rcc.adc_clock_source = AdcClockSource::PLL2_P; |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | #[cfg(any(feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] | 287 | #[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))] |
| 288 | { | 288 | { |
| 289 | use embassy_stm32::rcc::*; | 289 | use embassy_stm32::rcc::*; |
| 290 | config.rcc.mux = ClockSrc::PLL( | 290 | config.rcc.mux = ClockSrc::PLL; |
| 291 | // 72Mhz clock (16 / 1 * 18 / 4) | 291 | config.rcc.hsi16 = true; |
| 292 | PLLSource::HSI16, | 292 | config.rcc.pll_src = PLLSource::HSI16; |
| 293 | PllRDiv::DIV4, | 293 | config.rcc.pll = Some(Pll { |
| 294 | PllPreDiv::DIV1, | 294 | prediv: PllPreDiv::DIV1, |
| 295 | PllMul::MUL18, | 295 | mul: PllMul::MUL18, |
| 296 | Some(PllQDiv::DIV6), // 48Mhz (16 / 1 * 18 / 6) | 296 | divp: None, |
| 297 | ); | 297 | divq: Some(PllQDiv::DIV6), // 48Mhz (16 / 1 * 18 / 6) |
| 298 | divr: Some(PllRDiv::DIV4), // sysclk 72Mhz clock (16 / 1 * 18 / 4) | ||
| 299 | }); | ||
| 298 | } | 300 | } |
| 299 | 301 | ||
| 300 | #[cfg(any(feature = "stm32l552ze"))] | 302 | #[cfg(any(feature = "stm32l552ze"))] |
