diff options
| author | Vincent Stakenburg <[email protected]> | 2021-09-24 16:50:53 +0200 |
|---|---|---|
| committer | Ulf Lilleengen <[email protected]> | 2021-09-24 18:27:39 +0200 |
| commit | 7d6d274d55098b66c1dc529b10139c57eb9dcfaa (patch) | |
| tree | 7ee48417c4ef711b8c99637cea470b94377acde1 | |
| parent | b6fc19182b4ae02ea1e9107ca28b88f4a3b0b60a (diff) | |
Add MSI and PLL clock source for L4
| -rw-r--r-- | embassy-stm32/Cargo.toml | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l4/mod.rs | 188 |
2 files changed, 189 insertions, 0 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3e91040f0..aedb54b74 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -27,6 +27,7 @@ atomic-polyfill = "0.1.3" | |||
| 27 | stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] } | 27 | stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt"] } |
| 28 | vcell = { version = "0.1.3", optional = true } | 28 | vcell = { version = "0.1.3", optional = true } |
| 29 | bxcan = "0.5.1" | 29 | bxcan = "0.5.1" |
| 30 | seq-macro = "0.2.2" | ||
| 30 | 31 | ||
| 31 | cfg-if = "1.0.0" | 32 | cfg-if = "1.0.0" |
| 32 | 33 | ||
diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4/mod.rs index 4247d8ffb..aac0febe2 100644 --- a/embassy-stm32/src/rcc/l4/mod.rs +++ b/embassy-stm32/src/rcc/l4/mod.rs | |||
| @@ -7,6 +7,7 @@ use crate::time::U32Ext; | |||
| 7 | use core::marker::PhantomData; | 7 | use core::marker::PhantomData; |
| 8 | use embassy::util::Unborrow; | 8 | use embassy::util::Unborrow; |
| 9 | use embassy_hal_common::unborrow; | 9 | use embassy_hal_common::unborrow; |
| 10 | use stm32_metapac::rcc::vals::Msirange; | ||
| 10 | 11 | ||
| 11 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 12 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| 12 | /// and with the addition of the init function to configure a system clock. | 13 | /// and with the addition of the init function to configure a system clock. |
| @@ -19,10 +20,123 @@ pub const HSI_FREQ: u32 = 16_000_000; | |||
| 19 | /// System clock mux source | 20 | /// System clock mux source |
| 20 | #[derive(Clone, Copy)] | 21 | #[derive(Clone, Copy)] |
| 21 | pub enum ClockSrc { | 22 | pub enum ClockSrc { |
| 23 | PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul), | ||
| 24 | MSI(MSIRange), | ||
| 22 | HSE(Hertz), | 25 | HSE(Hertz), |
| 23 | HSI16, | 26 | HSI16, |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 29 | seq_macro::seq!(N in 8..=86 { | ||
| 30 | #[derive(Clone, Copy)] | ||
| 31 | pub enum PLLMul { | ||
| 32 | #( | ||
| 33 | Mul#N, | ||
| 34 | )* | ||
| 35 | } | ||
| 36 | |||
| 37 | impl Into<u8> for PLLMul { | ||
| 38 | fn into(self) -> u8 { | ||
| 39 | match self { | ||
| 40 | #( | ||
| 41 | PLLMul::Mul#N => N, | ||
| 42 | )* | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | impl PLLMul { | ||
| 48 | pub fn to_mul(self) -> u32 { | ||
| 49 | match self { | ||
| 50 | #( | ||
| 51 | PLLMul::Mul#N => N, | ||
| 52 | )* | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | }); | ||
| 57 | |||
| 58 | #[derive(Clone, Copy)] | ||
| 59 | pub enum PLLClkDiv { | ||
| 60 | Div2, | ||
| 61 | Div4, | ||
| 62 | Div6, | ||
| 63 | Div8, | ||
| 64 | } | ||
| 65 | |||
| 66 | impl PLLClkDiv { | ||
| 67 | pub fn to_div(self) -> u32 { | ||
| 68 | let val: u8 = self.into(); | ||
| 69 | val as u32 + 1 * 2 | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | impl Into<u8> for PLLClkDiv { | ||
| 74 | fn into(self) -> u8 { | ||
| 75 | match self { | ||
| 76 | PLLClkDiv::Div2 => 0b00, | ||
| 77 | PLLClkDiv::Div4 => 0b01, | ||
| 78 | PLLClkDiv::Div6 => 0b10, | ||
| 79 | PLLClkDiv::Div8 => 0b11, | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | #[derive(Clone, Copy)] | ||
| 85 | pub enum PLLSrcDiv { | ||
| 86 | Div1, | ||
| 87 | Div2, | ||
| 88 | Div3, | ||
| 89 | Div4, | ||
| 90 | Div5, | ||
| 91 | Div6, | ||
| 92 | Div7, | ||
| 93 | Div8, | ||
| 94 | } | ||
| 95 | |||
| 96 | impl PLLSrcDiv { | ||
| 97 | pub fn to_div(self) -> u32 { | ||
| 98 | let val: u8 = self.into(); | ||
| 99 | val as u32 + 1 | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | impl Into<u8> for PLLSrcDiv { | ||
| 104 | fn into(self) -> u8 { | ||
| 105 | match self { | ||
| 106 | PLLSrcDiv::Div1 => 0b000, | ||
| 107 | PLLSrcDiv::Div2 => 0b001, | ||
| 108 | PLLSrcDiv::Div3 => 0b010, | ||
| 109 | PLLSrcDiv::Div4 => 0b011, | ||
| 110 | PLLSrcDiv::Div5 => 0b100, | ||
| 111 | PLLSrcDiv::Div6 => 0b101, | ||
| 112 | PLLSrcDiv::Div7 => 0b110, | ||
| 113 | PLLSrcDiv::Div8 => 0b111, | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | impl Into<u8> for PLLSource { | ||
| 119 | fn into(self) -> u8 { | ||
| 120 | match self { | ||
| 121 | PLLSource::HSI16 => 0b10, | ||
| 122 | PLLSource::HSE(_) => 0b11, | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | impl Into<Msirange> for MSIRange { | ||
| 128 | fn into(self) -> Msirange { | ||
| 129 | match self { | ||
| 130 | MSIRange::Range0 => Msirange::RANGE100K, | ||
| 131 | MSIRange::Range1 => Msirange::RANGE200K, | ||
| 132 | MSIRange::Range2 => Msirange::RANGE400K, | ||
| 133 | MSIRange::Range3 => Msirange::RANGE800K, | ||
| 134 | MSIRange::Range4 => Msirange::RANGE1M, | ||
| 135 | MSIRange::Range5 => Msirange::RANGE2M, | ||
| 136 | MSIRange::Range6 => Msirange::RANGE4M, | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 26 | impl Into<u8> for APBPrescaler { | 140 | impl Into<u8> for APBPrescaler { |
| 27 | fn into(self) -> u8 { | 141 | fn into(self) -> u8 { |
| 28 | match self { | 142 | match self { |
| @@ -146,9 +260,83 @@ impl RccExt for RCC { | |||
| 146 | 260 | ||
| 147 | (freq.0, 0x02) | 261 | (freq.0, 0x02) |
| 148 | } | 262 | } |
| 263 | ClockSrc::MSI(range) => { | ||
| 264 | // Enable MSI | ||
| 265 | unsafe { | ||
| 266 | rcc.cr().write(|w| { | ||
| 267 | w.set_msirange(range.into()); | ||
| 268 | w.set_msion(true); | ||
| 269 | }); | ||
| 270 | while !rcc.cr().read().msirdy() {} | ||
| 271 | } | ||
| 272 | |||
| 273 | let freq = 32_768 * (1 << (range as u8 + 1)); | ||
| 274 | (freq, 0b00) | ||
| 275 | } | ||
| 276 | ClockSrc::PLL(src, div, prediv, mul) => { | ||
| 277 | let freq = match src { | ||
| 278 | PLLSource::HSE(freq) => { | ||
| 279 | // Enable HSE | ||
| 280 | unsafe { | ||
| 281 | rcc.cr().write(|w| w.set_hseon(true)); | ||
| 282 | while !rcc.cr().read().hserdy() {} | ||
| 283 | } | ||
| 284 | freq.0 | ||
| 285 | } | ||
| 286 | PLLSource::HSI16 => { | ||
| 287 | // Enable HSI | ||
| 288 | unsafe { | ||
| 289 | rcc.cr().write(|w| w.set_hsion(true)); | ||
| 290 | while !rcc.cr().read().hsirdy() {} | ||
| 291 | } | ||
| 292 | HSI_FREQ | ||
| 293 | } | ||
| 294 | }; | ||
| 295 | |||
| 296 | // Disable PLL | ||
| 297 | unsafe { | ||
| 298 | rcc.cr().modify(|w| w.set_pllon(false)); | ||
| 299 | while rcc.cr().read().pllrdy() {} | ||
| 300 | } | ||
| 301 | |||
| 302 | let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div(); | ||
| 303 | |||
| 304 | assert!(freq <= 80_000_000); | ||
| 305 | |||
| 306 | unsafe { | ||
| 307 | rcc.pllcfgr().write(move |w| { | ||
| 308 | w.set_plln(mul.into()); | ||
| 309 | w.set_pllm(prediv.into()); | ||
| 310 | w.set_pllr(div.into()); | ||
| 311 | w.set_pllsrc(src.into()); | ||
| 312 | }); | ||
| 313 | |||
| 314 | // Enable PLL | ||
| 315 | rcc.cr().modify(|w| w.set_pllon(true)); | ||
| 316 | while !rcc.cr().read().pllrdy() {} | ||
| 317 | rcc.pllcfgr().modify(|w| w.set_pllren(true)); | ||
| 318 | } | ||
| 319 | (freq, 0b11) | ||
| 320 | } | ||
| 149 | }; | 321 | }; |
| 150 | 322 | ||
| 151 | unsafe { | 323 | unsafe { |
| 324 | // Set flash wait states | ||
| 325 | pac::FLASH.acr().modify(|w| { | ||
| 326 | w.set_latency(if sys_clk <= 16_000_000 { | ||
| 327 | 0b000 | ||
| 328 | } else if sys_clk <= 32_000_000 { | ||
| 329 | 0b001 | ||
| 330 | } else if sys_clk <= 48_000_000 { | ||
| 331 | 0b010 | ||
| 332 | } else if sys_clk <= 64_000_000 { | ||
| 333 | 0b011 | ||
| 334 | } else { | ||
| 335 | 0b100 | ||
| 336 | }); | ||
| 337 | }); | ||
| 338 | |||
| 339 | // Switch active clocks to new clock source | ||
| 152 | rcc.cfgr().modify(|w| { | 340 | rcc.cfgr().modify(|w| { |
| 153 | w.set_sw(sw.into()); | 341 | w.set_sw(sw.into()); |
| 154 | w.set_hpre(cfgr.ahb_pre.into()); | 342 | w.set_hpre(cfgr.ahb_pre.into()); |
