diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-04-08 02:57:48 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-04-08 03:11:38 +0200 |
| commit | 50ff63ab888352b6818898617588cc844250c9b7 (patch) | |
| tree | acb609024d48d3e2a81c408ff63cbfdba253f278 | |
| parent | 37da84129da12280cfb0a4f016639d517a0f637e (diff) | |
Add STM32L5 support.
| -rwxr-xr-x | ci.sh | 1 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/dac/v2.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l5.rs | 468 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/mod.rs | 6 | ||||
| m--------- | stm32-data | 0 | ||||
| -rw-r--r-- | stm32-gen-features/src/lib.rs | 1 |
8 files changed, 496 insertions, 4 deletions
| @@ -54,6 +54,7 @@ cargo batch \ | |||
| 54 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ | 54 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ |
| 55 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ | 55 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ |
| 56 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ | 56 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ |
| 57 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \ | ||
| 57 | --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ | 58 | --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ |
| 58 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ | 59 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ |
| 59 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ | 60 | --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 991558acb..5579631af 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -1276,6 +1276,23 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ] | |||
| 1276 | stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] | 1276 | stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ] |
| 1277 | stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] | 1277 | stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ] |
| 1278 | stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] | 1278 | stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ] |
| 1279 | stm32l552cc = [ "stm32-metapac/stm32l552cc" ] | ||
| 1280 | stm32l552ce = [ "stm32-metapac/stm32l552ce" ] | ||
| 1281 | stm32l552me = [ "stm32-metapac/stm32l552me" ] | ||
| 1282 | stm32l552qc = [ "stm32-metapac/stm32l552qc" ] | ||
| 1283 | stm32l552qe = [ "stm32-metapac/stm32l552qe" ] | ||
| 1284 | stm32l552rc = [ "stm32-metapac/stm32l552rc" ] | ||
| 1285 | stm32l552re = [ "stm32-metapac/stm32l552re" ] | ||
| 1286 | stm32l552vc = [ "stm32-metapac/stm32l552vc" ] | ||
| 1287 | stm32l552ve = [ "stm32-metapac/stm32l552ve" ] | ||
| 1288 | stm32l552zc = [ "stm32-metapac/stm32l552zc" ] | ||
| 1289 | stm32l552ze = [ "stm32-metapac/stm32l552ze" ] | ||
| 1290 | stm32l562ce = [ "stm32-metapac/stm32l562ce" ] | ||
| 1291 | stm32l562me = [ "stm32-metapac/stm32l562me" ] | ||
| 1292 | stm32l562qe = [ "stm32-metapac/stm32l562qe" ] | ||
| 1293 | stm32l562re = [ "stm32-metapac/stm32l562re" ] | ||
| 1294 | stm32l562ve = [ "stm32-metapac/stm32l562ve" ] | ||
| 1295 | stm32l562ze = [ "stm32-metapac/stm32l562ze" ] | ||
| 1279 | stm32u575ag = [ "stm32-metapac/stm32u575ag" ] | 1296 | stm32u575ag = [ "stm32-metapac/stm32u575ag" ] |
| 1280 | stm32u575ai = [ "stm32-metapac/stm32u575ai" ] | 1297 | stm32u575ai = [ "stm32-metapac/stm32u575ai" ] |
| 1281 | stm32u575cg = [ "stm32-metapac/stm32u575cg" ] | 1298 | stm32u575cg = [ "stm32-metapac/stm32u575cg" ] |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 3221cf5ef..68d941604 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -14,7 +14,7 @@ fn enable() { | |||
| 14 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); | 14 | crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); |
| 15 | #[cfg(stm32g0)] | 15 | #[cfg(stm32g0)] |
| 16 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); | 16 | crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); |
| 17 | #[cfg(any(stm32l4, stm32wb))] | 17 | #[cfg(any(stm32l4, stm32l5, stm32wb))] |
| 18 | crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); | 18 | crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); |
| 19 | }); | 19 | }); |
| 20 | } | 20 | } |
| @@ -286,6 +286,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 286 | #[cfg(not(stm32g0))] // TODO is this supposed to be public? | 286 | #[cfg(not(stm32g0))] // TODO is this supposed to be public? |
| 287 | #[allow(unused)] // TODO is this supposed to be public? | 287 | #[allow(unused)] // TODO is this supposed to be public? |
| 288 | fn calibrate(&mut self, vref: &mut Vref) { | 288 | fn calibrate(&mut self, vref: &mut Vref) { |
| 289 | #[cfg(stm32l5)] | ||
| 290 | let vref_cal: u32 = todo!(); | ||
| 291 | #[cfg(not(stm32l5))] | ||
| 289 | let vref_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() }; | 292 | let vref_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() }; |
| 290 | let old_sample_time = self.sample_time; | 293 | let old_sample_time = self.sample_time; |
| 291 | 294 | ||
diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs index 35facdd25..006602439 100644 --- a/embassy-stm32/src/dac/v2.rs +++ b/embassy-stm32/src/dac/v2.rs | |||
| @@ -134,7 +134,7 @@ impl<'d, T: Instance> Dac<'d, T> { | |||
| 134 | enable!(apb1lenr, set_dac1en, apb1lrstr, set_dac1rst); | 134 | enable!(apb1lenr, set_dac1en, apb1lrstr, set_dac1rst); |
| 135 | #[cfg(stm32g0)] | 135 | #[cfg(stm32g0)] |
| 136 | enable!(apbenr1, set_dac1en, apbrstr1, set_dac1rst); | 136 | enable!(apbenr1, set_dac1en, apbrstr1, set_dac1rst); |
| 137 | #[cfg(stm32l4)] | 137 | #[cfg(any(stm32l4, stm32l5))] |
| 138 | enable!(apb1enr1, set_dac1en, apb1rstr1, set_dac1rst); | 138 | enable!(apb1enr1, set_dac1en, apb1rstr1, set_dac1rst); |
| 139 | }); | 139 | }); |
| 140 | 140 | ||
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs new file mode 100644 index 000000000..a502cb4e2 --- /dev/null +++ b/embassy-stm32/src/rcc/l5.rs | |||
| @@ -0,0 +1,468 @@ | |||
| 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; | ||
| 2 | use crate::pac::{FLASH, RCC}; | ||
| 3 | use crate::rcc::{set_freqs, Clocks}; | ||
| 4 | use crate::time::Hertz; | ||
| 5 | use crate::time::U32Ext; | ||
| 6 | |||
| 7 | /// HSI16 speed | ||
| 8 | pub const HSI16_FREQ: u32 = 16_000_000; | ||
| 9 | |||
| 10 | /// System clock mux source | ||
| 11 | #[derive(Clone, Copy)] | ||
| 12 | pub enum ClockSrc { | ||
| 13 | MSI(MSIRange), | ||
| 14 | PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>), | ||
| 15 | HSE(Hertz), | ||
| 16 | HSI16, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// MSI Clock Range | ||
| 20 | /// | ||
| 21 | /// These ranges control the frequency of the MSI. Internally, these ranges map | ||
| 22 | /// to the `MSIRANGE` bits in the `RCC_ICSCR` register. | ||
| 23 | #[derive(Clone, Copy)] | ||
| 24 | pub enum MSIRange { | ||
| 25 | /// Around 100 kHz | ||
| 26 | Range0, | ||
| 27 | /// Around 200 kHz | ||
| 28 | Range1, | ||
| 29 | /// Around 400 kHz | ||
| 30 | Range2, | ||
| 31 | /// Around 800 kHz | ||
| 32 | Range3, | ||
| 33 | /// Around 1 MHz | ||
| 34 | Range4, | ||
| 35 | /// Around 2 MHz | ||
| 36 | Range5, | ||
| 37 | /// Around 4 MHz (reset value) | ||
| 38 | Range6, | ||
| 39 | /// Around 8 MHz | ||
| 40 | Range7, | ||
| 41 | /// Around 16 MHz | ||
| 42 | Range8, | ||
| 43 | /// Around 24 MHz | ||
| 44 | Range9, | ||
| 45 | /// Around 32 MHz | ||
| 46 | Range10, | ||
| 47 | /// Around 48 MHz | ||
| 48 | Range11, | ||
| 49 | } | ||
| 50 | |||
| 51 | impl Default for MSIRange { | ||
| 52 | fn default() -> MSIRange { | ||
| 53 | MSIRange::Range6 | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pub type PLL48Div = PLLClkDiv; | ||
| 58 | pub type PLLSAI1RDiv = PLLClkDiv; | ||
| 59 | pub type PLLSAI1QDiv = PLLClkDiv; | ||
| 60 | pub type PLLSAI1PDiv = PLLClkDiv; | ||
| 61 | |||
| 62 | /// PLL divider | ||
| 63 | #[derive(Clone, Copy)] | ||
| 64 | pub enum PLLDiv { | ||
| 65 | Div2, | ||
| 66 | Div3, | ||
| 67 | Div4, | ||
| 68 | } | ||
| 69 | |||
| 70 | /// AHB prescaler | ||
| 71 | #[derive(Clone, Copy, PartialEq)] | ||
| 72 | pub enum AHBPrescaler { | ||
| 73 | NotDivided, | ||
| 74 | Div2, | ||
| 75 | Div4, | ||
| 76 | Div8, | ||
| 77 | Div16, | ||
| 78 | Div64, | ||
| 79 | Div128, | ||
| 80 | Div256, | ||
| 81 | Div512, | ||
| 82 | } | ||
| 83 | |||
| 84 | /// APB prescaler | ||
| 85 | #[derive(Clone, Copy)] | ||
| 86 | pub enum APBPrescaler { | ||
| 87 | NotDivided, | ||
| 88 | Div2, | ||
| 89 | Div4, | ||
| 90 | Div8, | ||
| 91 | Div16, | ||
| 92 | } | ||
| 93 | |||
| 94 | /// PLL clock input source | ||
| 95 | #[derive(Clone, Copy)] | ||
| 96 | pub enum PLLSource { | ||
| 97 | HSI16, | ||
| 98 | HSE(Hertz), | ||
| 99 | } | ||
| 100 | |||
| 101 | seq_macro::seq!(N in 8..=86 { | ||
| 102 | #[derive(Clone, Copy)] | ||
| 103 | pub enum PLLMul { | ||
| 104 | #( | ||
| 105 | Mul#N, | ||
| 106 | )* | ||
| 107 | } | ||
| 108 | |||
| 109 | impl From<PLLMul> for u8 { | ||
| 110 | fn from(val: PLLMul) -> u8 { | ||
| 111 | match val { | ||
| 112 | #( | ||
| 113 | PLLMul::Mul#N => N, | ||
| 114 | )* | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | impl PLLMul { | ||
| 120 | pub fn to_mul(self) -> u32 { | ||
| 121 | match self { | ||
| 122 | #( | ||
| 123 | PLLMul::Mul#N => N, | ||
| 124 | )* | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | }); | ||
| 129 | |||
| 130 | #[derive(Clone, Copy)] | ||
| 131 | pub enum PLLClkDiv { | ||
| 132 | Div2, | ||
| 133 | Div4, | ||
| 134 | Div6, | ||
| 135 | Div8, | ||
| 136 | } | ||
| 137 | |||
| 138 | impl PLLClkDiv { | ||
| 139 | pub fn to_div(self) -> u32 { | ||
| 140 | let val: u8 = self.into(); | ||
| 141 | (val as u32 + 1) * 2 | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | impl From<PLLClkDiv> for u8 { | ||
| 146 | fn from(val: PLLClkDiv) -> u8 { | ||
| 147 | match val { | ||
| 148 | PLLClkDiv::Div2 => 0b00, | ||
| 149 | PLLClkDiv::Div4 => 0b01, | ||
| 150 | PLLClkDiv::Div6 => 0b10, | ||
| 151 | PLLClkDiv::Div8 => 0b11, | ||
| 152 | } | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | #[derive(Clone, Copy)] | ||
| 157 | pub enum PLLSrcDiv { | ||
| 158 | Div1, | ||
| 159 | Div2, | ||
| 160 | Div3, | ||
| 161 | Div4, | ||
| 162 | Div5, | ||
| 163 | Div6, | ||
| 164 | Div7, | ||
| 165 | Div8, | ||
| 166 | } | ||
| 167 | |||
| 168 | impl PLLSrcDiv { | ||
| 169 | pub fn to_div(self) -> u32 { | ||
| 170 | let val: u8 = self.into(); | ||
| 171 | val as u32 + 1 | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | impl From<PLLSrcDiv> for u8 { | ||
| 176 | fn from(val: PLLSrcDiv) -> u8 { | ||
| 177 | match val { | ||
| 178 | PLLSrcDiv::Div1 => 0b000, | ||
| 179 | PLLSrcDiv::Div2 => 0b001, | ||
| 180 | PLLSrcDiv::Div3 => 0b010, | ||
| 181 | PLLSrcDiv::Div4 => 0b011, | ||
| 182 | PLLSrcDiv::Div5 => 0b100, | ||
| 183 | PLLSrcDiv::Div6 => 0b101, | ||
| 184 | PLLSrcDiv::Div7 => 0b110, | ||
| 185 | PLLSrcDiv::Div8 => 0b111, | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | impl From<PLLSource> for Pllsrc { | ||
| 191 | fn from(val: PLLSource) -> Pllsrc { | ||
| 192 | match val { | ||
| 193 | PLLSource::HSI16 => Pllsrc::HSI16, | ||
| 194 | PLLSource::HSE(_) => Pllsrc::HSE, | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | impl From<APBPrescaler> for Ppre { | ||
| 200 | fn from(val: APBPrescaler) -> Ppre { | ||
| 201 | match val { | ||
| 202 | APBPrescaler::NotDivided => Ppre::DIV1, | ||
| 203 | APBPrescaler::Div2 => Ppre::DIV2, | ||
| 204 | APBPrescaler::Div4 => Ppre::DIV4, | ||
| 205 | APBPrescaler::Div8 => Ppre::DIV8, | ||
| 206 | APBPrescaler::Div16 => Ppre::DIV16, | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | impl From<AHBPrescaler> for Hpre { | ||
| 212 | fn from(val: AHBPrescaler) -> Hpre { | ||
| 213 | match val { | ||
| 214 | AHBPrescaler::NotDivided => Hpre::DIV1, | ||
| 215 | AHBPrescaler::Div2 => Hpre::DIV2, | ||
| 216 | AHBPrescaler::Div4 => Hpre::DIV4, | ||
| 217 | AHBPrescaler::Div8 => Hpre::DIV8, | ||
| 218 | AHBPrescaler::Div16 => Hpre::DIV16, | ||
| 219 | AHBPrescaler::Div64 => Hpre::DIV64, | ||
| 220 | AHBPrescaler::Div128 => Hpre::DIV128, | ||
| 221 | AHBPrescaler::Div256 => Hpre::DIV256, | ||
| 222 | AHBPrescaler::Div512 => Hpre::DIV512, | ||
| 223 | } | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | impl From<MSIRange> for Msirange { | ||
| 228 | fn from(val: MSIRange) -> Msirange { | ||
| 229 | match val { | ||
| 230 | MSIRange::Range0 => Msirange::RANGE100K, | ||
| 231 | MSIRange::Range1 => Msirange::RANGE200K, | ||
| 232 | MSIRange::Range2 => Msirange::RANGE400K, | ||
| 233 | MSIRange::Range3 => Msirange::RANGE800K, | ||
| 234 | MSIRange::Range4 => Msirange::RANGE1M, | ||
| 235 | MSIRange::Range5 => Msirange::RANGE2M, | ||
| 236 | MSIRange::Range6 => Msirange::RANGE4M, | ||
| 237 | MSIRange::Range7 => Msirange::RANGE8M, | ||
| 238 | MSIRange::Range8 => Msirange::RANGE16M, | ||
| 239 | MSIRange::Range9 => Msirange::RANGE24M, | ||
| 240 | MSIRange::Range10 => Msirange::RANGE32M, | ||
| 241 | MSIRange::Range11 => Msirange::RANGE48M, | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | impl From<MSIRange> for u32 { | ||
| 247 | fn from(val: MSIRange) -> u32 { | ||
| 248 | match val { | ||
| 249 | MSIRange::Range0 => 100_000, | ||
| 250 | MSIRange::Range1 => 200_000, | ||
| 251 | MSIRange::Range2 => 400_000, | ||
| 252 | MSIRange::Range3 => 800_000, | ||
| 253 | MSIRange::Range4 => 1_000_000, | ||
| 254 | MSIRange::Range5 => 2_000_000, | ||
| 255 | MSIRange::Range6 => 4_000_000, | ||
| 256 | MSIRange::Range7 => 8_000_000, | ||
| 257 | MSIRange::Range8 => 16_000_000, | ||
| 258 | MSIRange::Range9 => 24_000_000, | ||
| 259 | MSIRange::Range10 => 32_000_000, | ||
| 260 | MSIRange::Range11 => 48_000_000, | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | /// Clocks configutation | ||
| 266 | pub struct Config { | ||
| 267 | pub mux: ClockSrc, | ||
| 268 | pub ahb_pre: AHBPrescaler, | ||
| 269 | pub apb1_pre: APBPrescaler, | ||
| 270 | pub apb2_pre: APBPrescaler, | ||
| 271 | pub pllsai1: Option<( | ||
| 272 | PLLMul, | ||
| 273 | PLLSrcDiv, | ||
| 274 | Option<PLLSAI1RDiv>, | ||
| 275 | Option<PLLSAI1QDiv>, | ||
| 276 | Option<PLLSAI1PDiv>, | ||
| 277 | )>, | ||
| 278 | } | ||
| 279 | |||
| 280 | impl Default for Config { | ||
| 281 | #[inline] | ||
| 282 | fn default() -> Config { | ||
| 283 | Config { | ||
| 284 | mux: ClockSrc::MSI(MSIRange::Range6), | ||
| 285 | ahb_pre: AHBPrescaler::NotDivided, | ||
| 286 | apb1_pre: APBPrescaler::NotDivided, | ||
| 287 | apb2_pre: APBPrescaler::NotDivided, | ||
| 288 | pllsai1: None, | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | pub(crate) unsafe fn init(config: Config) { | ||
| 294 | let (sys_clk, sw) = match config.mux { | ||
| 295 | ClockSrc::MSI(range) => { | ||
| 296 | // Enable MSI | ||
| 297 | RCC.cr().write(|w| { | ||
| 298 | let bits: Msirange = range.into(); | ||
| 299 | w.set_msirange(bits); | ||
| 300 | w.set_msipllen(false); | ||
| 301 | w.set_msirgsel(true); | ||
| 302 | w.set_msion(true); | ||
| 303 | }); | ||
| 304 | while !RCC.cr().read().msirdy() {} | ||
| 305 | |||
| 306 | // Enable as clock source for USB, RNG if running at 48 MHz | ||
| 307 | if let MSIRange::Range11 = range { | ||
| 308 | RCC.ccipr1().modify(|w| { | ||
| 309 | w.set_clk48msel(0b11); | ||
| 310 | }); | ||
| 311 | } | ||
| 312 | (range.into(), Sw::MSI) | ||
| 313 | } | ||
| 314 | ClockSrc::HSI16 => { | ||
| 315 | // Enable HSI16 | ||
| 316 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 317 | while !RCC.cr().read().hsirdy() {} | ||
| 318 | |||
| 319 | (HSI16_FREQ, Sw::HSI16) | ||
| 320 | } | ||
| 321 | ClockSrc::HSE(freq) => { | ||
| 322 | // Enable HSE | ||
| 323 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 324 | while !RCC.cr().read().hserdy() {} | ||
| 325 | |||
| 326 | (freq.0, Sw::HSE) | ||
| 327 | } | ||
| 328 | ClockSrc::PLL(src, div, prediv, mul, pll48div) => { | ||
| 329 | let src_freq = match src { | ||
| 330 | PLLSource::HSE(freq) => { | ||
| 331 | // Enable HSE | ||
| 332 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 333 | while !RCC.cr().read().hserdy() {} | ||
| 334 | freq.0 | ||
| 335 | } | ||
| 336 | PLLSource::HSI16 => { | ||
| 337 | // Enable HSI | ||
| 338 | RCC.cr().write(|w| w.set_hsion(true)); | ||
| 339 | while !RCC.cr().read().hsirdy() {} | ||
| 340 | HSI16_FREQ | ||
| 341 | } | ||
| 342 | }; | ||
| 343 | |||
| 344 | // Disable PLL | ||
| 345 | RCC.cr().modify(|w| w.set_pllon(false)); | ||
| 346 | while RCC.cr().read().pllrdy() {} | ||
| 347 | |||
| 348 | let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); | ||
| 349 | |||
| 350 | #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] | ||
| 351 | assert!(freq <= 120_000_000); | ||
| 352 | #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] | ||
| 353 | assert!(freq <= 80_000_000); | ||
| 354 | |||
| 355 | RCC.pllcfgr().write(move |w| { | ||
| 356 | w.set_plln(mul.into()); | ||
| 357 | w.set_pllm(prediv.into()); | ||
| 358 | w.set_pllr(div.into()); | ||
| 359 | if let Some(pll48div) = pll48div { | ||
| 360 | w.set_pllq(pll48div.into()); | ||
| 361 | w.set_pllqen(true); | ||
| 362 | } | ||
| 363 | w.set_pllsrc(src.into()); | ||
| 364 | }); | ||
| 365 | |||
| 366 | // Enable as clock source for USB, RNG if PLL48 divisor is provided | ||
| 367 | if pll48div.is_some() { | ||
| 368 | RCC.ccipr1().modify(|w| { | ||
| 369 | w.set_clk48msel(0b10); | ||
| 370 | }); | ||
| 371 | } | ||
| 372 | |||
| 373 | if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { | ||
| 374 | RCC.pllsai1cfgr().write(move |w| { | ||
| 375 | w.set_pllsai1n(mul.into()); | ||
| 376 | w.set_pllsai1m(prediv.into()); | ||
| 377 | if let Some(r_div) = r_div { | ||
| 378 | w.set_pllsai1r(r_div.into()); | ||
| 379 | w.set_pllsai1ren(true); | ||
| 380 | } | ||
| 381 | if let Some(q_div) = q_div { | ||
| 382 | w.set_pllsai1q(q_div.into()); | ||
| 383 | w.set_pllsai1qen(true); | ||
| 384 | let freq = (src_freq / prediv.to_div() * mul.to_mul()) / q_div.to_div(); | ||
| 385 | if freq == 48_000_000 { | ||
| 386 | RCC.ccipr1().modify(|w| { | ||
| 387 | w.set_clk48msel(0b1); | ||
| 388 | }); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | if let Some(p_div) = p_div { | ||
| 392 | w.set_pllsai1pdiv(p_div.into()); | ||
| 393 | w.set_pllsai1pen(true); | ||
| 394 | } | ||
| 395 | }); | ||
| 396 | |||
| 397 | RCC.cr().modify(|w| w.set_pllsai1on(true)); | ||
| 398 | } | ||
| 399 | |||
| 400 | // Enable PLL | ||
| 401 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 402 | while !RCC.cr().read().pllrdy() {} | ||
| 403 | RCC.pllcfgr().modify(|w| w.set_pllren(true)); | ||
| 404 | |||
| 405 | (freq, Sw::PLL) | ||
| 406 | } | ||
| 407 | }; | ||
| 408 | |||
| 409 | // Set flash wait states | ||
| 410 | // VCORE Range 0 (performance), others TODO | ||
| 411 | FLASH.acr().modify(|w| { | ||
| 412 | w.set_latency(match sys_clk { | ||
| 413 | 0..=20_000_000 => 0, | ||
| 414 | 0..=40_000_000 => 1, | ||
| 415 | 0..=60_000_000 => 2, | ||
| 416 | 0..=80_000_000 => 3, | ||
| 417 | 0..=100_000_000 => 4, | ||
| 418 | _ => 5, | ||
| 419 | }) | ||
| 420 | }); | ||
| 421 | |||
| 422 | RCC.cfgr().modify(|w| { | ||
| 423 | w.set_sw(sw); | ||
| 424 | w.set_hpre(config.ahb_pre.into()); | ||
| 425 | w.set_ppre1(config.apb1_pre.into()); | ||
| 426 | w.set_ppre2(config.apb2_pre.into()); | ||
| 427 | }); | ||
| 428 | |||
| 429 | let ahb_freq: u32 = match config.ahb_pre { | ||
| 430 | AHBPrescaler::NotDivided => sys_clk, | ||
| 431 | pre => { | ||
| 432 | let pre: Hpre = pre.into(); | ||
| 433 | let pre = 1 << (pre.0 as u32 - 7); | ||
| 434 | sys_clk / pre | ||
| 435 | } | ||
| 436 | }; | ||
| 437 | |||
| 438 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 439 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 440 | pre => { | ||
| 441 | let pre: Ppre = pre.into(); | ||
| 442 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 443 | let freq = ahb_freq / pre as u32; | ||
| 444 | (freq, freq * 2) | ||
| 445 | } | ||
| 446 | }; | ||
| 447 | |||
| 448 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | ||
| 449 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | ||
| 450 | pre => { | ||
| 451 | let pre: Ppre = pre.into(); | ||
| 452 | let pre: u8 = 1 << (pre.0 - 3); | ||
| 453 | let freq = ahb_freq / (1 << (pre as u8 - 3)); | ||
| 454 | (freq, freq * 2) | ||
| 455 | } | ||
| 456 | }; | ||
| 457 | |||
| 458 | set_freqs(Clocks { | ||
| 459 | sys: sys_clk.hz(), | ||
| 460 | ahb1: ahb_freq.hz(), | ||
| 461 | ahb2: ahb_freq.hz(), | ||
| 462 | ahb3: ahb_freq.hz(), | ||
| 463 | apb1: apb1_freq.hz(), | ||
| 464 | apb2: apb2_freq.hz(), | ||
| 465 | apb1_tim: apb1_tim_freq.hz(), | ||
| 466 | apb2_tim: apb2_tim_freq.hz(), | ||
| 467 | }); | ||
| 468 | } | ||
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3090b416c..37ecf8fba 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -15,6 +15,7 @@ use core::mem::MaybeUninit; | |||
| 15 | #[cfg_attr(rcc_l0, path = "l0.rs")] | 15 | #[cfg_attr(rcc_l0, path = "l0.rs")] |
| 16 | #[cfg_attr(rcc_l1, path = "l1.rs")] | 16 | #[cfg_attr(rcc_l1, path = "l1.rs")] |
| 17 | #[cfg_attr(rcc_l4, path = "l4.rs")] | 17 | #[cfg_attr(rcc_l4, path = "l4.rs")] |
| 18 | #[cfg_attr(rcc_l5, path = "l5.rs")] | ||
| 18 | #[cfg_attr(rcc_u5, path = "u5.rs")] | 19 | #[cfg_attr(rcc_u5, path = "u5.rs")] |
| 19 | #[cfg_attr(rcc_wb, path = "wb.rs")] | 20 | #[cfg_attr(rcc_wb, path = "wb.rs")] |
| 20 | #[cfg_attr(rcc_wl5, path = "wl5.rs")] | 21 | #[cfg_attr(rcc_wl5, path = "wl5.rs")] |
| @@ -40,11 +41,12 @@ pub struct Clocks { | |||
| 40 | // AHB | 41 | // AHB |
| 41 | pub ahb1: Hertz, | 42 | pub ahb1: Hertz, |
| 42 | #[cfg(any( | 43 | #[cfg(any( |
| 43 | rcc_l4, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, rcc_wl5 | 44 | rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, |
| 45 | rcc_wl5 | ||
| 44 | ))] | 46 | ))] |
| 45 | pub ahb2: Hertz, | 47 | pub ahb2: Hertz, |
| 46 | #[cfg(any( | 48 | #[cfg(any( |
| 47 | rcc_l4, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5 | 49 | rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5 |
| 48 | ))] | 50 | ))] |
| 49 | pub ahb3: Hertz, | 51 | pub ahb3: Hertz, |
| 50 | #[cfg(any(rcc_h7, rcc_h7ab))] | 52 | #[cfg(any(rcc_h7, rcc_h7ab))] |
diff --git a/stm32-data b/stm32-data | |||
| Subproject 246e21c634e15b5c8337c51cb50e52b9df51ad3 | Subproject bd1c21fdc26f8e2213bf3f78eaa935f1bd3785f | ||
diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs index d184827cc..c9768cdbb 100644 --- a/stm32-gen-features/src/lib.rs +++ b/stm32-gen-features/src/lib.rs | |||
| @@ -14,6 +14,7 @@ const SUPPORTED_FAMILIES: &[&str] = &[ | |||
| 14 | "stm32l0", | 14 | "stm32l0", |
| 15 | "stm32l1", | 15 | "stm32l1", |
| 16 | "stm32l4", | 16 | "stm32l4", |
| 17 | "stm32l5", | ||
| 17 | "stm32h7", | 18 | "stm32h7", |
| 18 | "stm32u5", | 19 | "stm32u5", |
| 19 | "stm32wb55", | 20 | "stm32wb55", |
