diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-02-23 00:37:20 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-02-23 00:37:20 +0000 |
| commit | 2855bb69680a42a721fe88168657ea1e634e8766 (patch) | |
| tree | bf0fb98be948566b5c3064a1e5392299f889d11e | |
| parent | 4481c5f3ccf29da071538ef4f1e48fc5372a72a5 (diff) | |
| parent | d24349f57ce7435e70fcf1cd9aac20d1740995d4 (diff) | |
Merge pull request #2617 from embassy-rs/u5-rcc
stm32/rcc: port U5 to new API, add all PLLs, all HSE modes.
| -rw-r--r-- | embassy-stm32/src/rcc/u5.rs | 627 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/usb_serial.rs | 27 | ||||
| -rw-r--r-- | tests/stm32/Cargo.toml | 2 | ||||
| -rw-r--r-- | tests/stm32/build.rs | 1 | ||||
| -rw-r--r-- | tests/stm32/src/common.rs | 13 |
5 files changed, 311 insertions, 359 deletions
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 20cc3112a..72613f0f3 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs | |||
| @@ -1,134 +1,83 @@ | |||
| 1 | pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; | 1 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 2 | use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; | 2 | pub use crate::pac::rcc::vals::{ |
| 3 | Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, | ||
| 4 | Pllsrc as PllSource, Ppre as APBPrescaler, Sw as ClockSrc, | ||
| 5 | }; | ||
| 6 | use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; | ||
| 3 | use crate::pac::{FLASH, PWR, RCC}; | 7 | use crate::pac::{FLASH, PWR, RCC}; |
| 4 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 5 | 9 | ||
| 6 | /// HSI speed | 10 | /// HSI speed |
| 7 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 11 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| 8 | 12 | ||
| 9 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | 13 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 10 | 14 | pub enum HseMode { | |
| 11 | #[derive(Copy, Clone)] | 15 | /// crystal/ceramic oscillator (HSEBYP=0) |
| 12 | #[allow(non_camel_case_types)] | 16 | Oscillator, |
| 13 | pub enum ClockSrc { | 17 | /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) |
| 14 | /// Use an internal medium speed oscillator (MSIS) as the system clock. | 18 | Bypass, |
| 15 | MSI(Msirange), | 19 | /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) |
| 16 | /// Use the external high speed clock as the system clock. | 20 | BypassDigital, |
| 17 | /// | ||
| 18 | /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must | ||
| 19 | /// never exceed 50 MHz. | ||
| 20 | HSE(Hertz), | ||
| 21 | /// Use the 16 MHz internal high speed oscillator as the system clock. | ||
| 22 | HSI, | ||
| 23 | /// Use PLL1 as the system clock. | ||
| 24 | PLL1_R(PllConfig), | ||
| 25 | } | 21 | } |
| 26 | 22 | ||
| 27 | impl Default for ClockSrc { | 23 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 28 | fn default() -> Self { | 24 | pub struct Hse { |
| 29 | // The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9 | 25 | /// HSE frequency. |
| 30 | ClockSrc::MSI(Msirange::RANGE_4MHZ) | 26 | pub freq: Hertz, |
| 31 | } | 27 | /// HSE mode. |
| 28 | pub mode: HseMode, | ||
| 32 | } | 29 | } |
| 33 | 30 | ||
| 34 | #[derive(Clone, Copy)] | 31 | #[derive(Clone, Copy)] |
| 35 | pub struct PllConfig { | 32 | pub struct Pll { |
| 36 | /// The clock source for the PLL. | 33 | /// The clock source for the PLL. |
| 37 | pub source: PllSource, | 34 | pub source: PllSource, |
| 38 | /// The PLL prescaler. | 35 | /// The PLL pre-divider. |
| 39 | /// | 36 | /// |
| 40 | /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. | 37 | /// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz. |
| 41 | pub m: Pllm, | 38 | pub prediv: PllPreDiv, |
| 42 | /// The PLL multiplier. | 39 | /// The PLL multiplier. |
| 43 | /// | 40 | /// |
| 44 | /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 | 41 | /// The multiplied clock – `source` divided by `m` times `n` – must be between 128 and 544 |
| 45 | /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. | 42 | /// MHz. The upper limit may be lower depending on the `Config { voltage_range }`. |
| 46 | pub n: Plln, | 43 | pub mul: PllMul, |
| 47 | /// The divider for the P output. | 44 | /// The divider for the P output. |
| 48 | /// | 45 | /// |
| 49 | /// The P output is one of several options | 46 | /// The P output is one of several options |
| 50 | /// that can be used to feed the SAI/MDF/ADF Clock mux's. | 47 | /// that can be used to feed the SAI/MDF/ADF Clock mux's. |
| 51 | pub p: Plldiv, | 48 | pub divp: Option<PllDiv>, |
| 52 | /// The divider for the Q output. | 49 | /// The divider for the Q output. |
| 53 | /// | 50 | /// |
| 54 | /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks | 51 | /// The Q ouput is one of severals options that can be used to feed the 48MHz clocks |
| 55 | /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. | 52 | /// and the OCTOSPI clock. It may also be used on the MDF/ADF clock mux's. |
| 56 | pub q: Plldiv, | 53 | pub divq: Option<PllDiv>, |
| 57 | /// The divider for the R output. | 54 | /// The divider for the R output. |
| 58 | /// | 55 | /// |
| 59 | /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` | 56 | /// When used to drive the system clock, `source` divided by `m` times `n` divided by `r` |
| 60 | /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default | 57 | /// must not exceed 160 MHz. System clocks above 55 MHz require a non-default |
| 61 | /// `Config { voltage_range }`. | 58 | /// `Config { voltage_range }`. |
| 62 | pub r: Plldiv, | 59 | pub divr: Option<PllDiv>, |
| 63 | } | ||
| 64 | |||
| 65 | impl PllConfig { | ||
| 66 | /// A configuration for HSI / 1 * 10 / 1 = 160 MHz | ||
| 67 | pub const fn hsi_160mhz() -> Self { | ||
| 68 | PllConfig { | ||
| 69 | source: PllSource::HSI, | ||
| 70 | m: Pllm::DIV1, | ||
| 71 | n: Plln::MUL10, | ||
| 72 | p: Plldiv::DIV3, | ||
| 73 | q: Plldiv::DIV2, | ||
| 74 | r: Plldiv::DIV1, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz | ||
| 79 | pub const fn msis_160mhz() -> Self { | ||
| 80 | PllConfig { | ||
| 81 | source: PllSource::MSIS(Msirange::RANGE_48MHZ), | ||
| 82 | m: Pllm::DIV3, | ||
| 83 | n: Plln::MUL10, | ||
| 84 | p: Plldiv::DIV3, | ||
| 85 | q: Plldiv::DIV2, | ||
| 86 | r: Plldiv::DIV1, | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | #[derive(Clone, Copy)] | ||
| 92 | pub enum PllSource { | ||
| 93 | /// Use an internal medium speed oscillator as the PLL source. | ||
| 94 | MSIS(Msirange), | ||
| 95 | /// Use the external high speed clock as the system PLL source. | ||
| 96 | /// | ||
| 97 | /// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must | ||
| 98 | /// never exceed 50 MHz. | ||
| 99 | HSE(Hertz), | ||
| 100 | /// Use the 16 MHz internal high speed oscillator as the PLL source. | ||
| 101 | HSI, | ||
| 102 | } | 60 | } |
| 103 | 61 | ||
| 104 | impl Into<Pllsrc> for PllSource { | 62 | pub struct Config { |
| 105 | fn into(self) -> Pllsrc { | 63 | // base clock sources |
| 106 | match self { | 64 | pub msi: Option<MSIRange>, |
| 107 | PllSource::MSIS(..) => Pllsrc::MSIS, | 65 | pub hsi: bool, |
| 108 | PllSource::HSE(..) => Pllsrc::HSE, | 66 | pub hse: Option<Hse>, |
| 109 | PllSource::HSI => Pllsrc::HSI, | 67 | pub hsi48: Option<super::Hsi48Config>, |
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | 68 | ||
| 114 | impl Into<Sw> for ClockSrc { | 69 | // pll |
| 115 | fn into(self) -> Sw { | 70 | pub pll1: Option<Pll>, |
| 116 | match self { | 71 | pub pll2: Option<Pll>, |
| 117 | ClockSrc::MSI(..) => Sw::MSIS, | 72 | pub pll3: Option<Pll>, |
| 118 | ClockSrc::HSE(..) => Sw::HSE, | ||
| 119 | ClockSrc::HSI => Sw::HSI, | ||
| 120 | ClockSrc::PLL1_R(..) => Sw::PLL1_R, | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | 73 | ||
| 125 | pub struct Config { | 74 | // sysclk, buses. |
| 126 | pub mux: ClockSrc, | 75 | pub mux: ClockSrc, |
| 127 | pub ahb_pre: AHBPrescaler, | 76 | pub ahb_pre: AHBPrescaler, |
| 128 | pub apb1_pre: APBPrescaler, | 77 | pub apb1_pre: APBPrescaler, |
| 129 | pub apb2_pre: APBPrescaler, | 78 | pub apb2_pre: APBPrescaler, |
| 130 | pub apb3_pre: APBPrescaler, | 79 | pub apb3_pre: APBPrescaler, |
| 131 | pub hsi48: Option<super::Hsi48Config>, | 80 | |
| 132 | /// The voltage range influences the maximum clock frequencies for different parts of the | 81 | /// The voltage range influences the maximum clock frequencies for different parts of the |
| 133 | /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks | 82 | /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks |
| 134 | /// exceeding 55 MHz require at least `RANGE2`. | 83 | /// exceeding 55 MHz require at least `RANGE2`. |
| @@ -138,35 +87,35 @@ pub struct Config { | |||
| 138 | pub ls: super::LsConfig, | 87 | pub ls: super::LsConfig, |
| 139 | } | 88 | } |
| 140 | 89 | ||
| 141 | impl Config { | 90 | impl Default for Config { |
| 142 | unsafe fn init_hsi(&self) -> Hertz { | 91 | fn default() -> Self { |
| 143 | RCC.cr().write(|w| w.set_hsion(true)); | 92 | Self { |
| 144 | while !RCC.cr().read().hsirdy() {} | 93 | msi: Some(Msirange::RANGE_4MHZ), |
| 145 | 94 | hse: None, | |
| 146 | HSI_FREQ | 95 | hsi: false, |
| 147 | } | 96 | hsi48: Some(Default::default()), |
| 148 | 97 | pll1: None, | |
| 149 | unsafe fn init_hse(&self, frequency: Hertz) -> Hertz { | 98 | pll2: None, |
| 150 | // Check frequency limits per RM456 § 11.4.10 | 99 | pll3: None, |
| 151 | match self.voltage_range { | 100 | mux: ClockSrc::MSIS, |
| 152 | VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { | 101 | ahb_pre: AHBPrescaler::DIV1, |
| 153 | assert!(frequency.0 <= 50_000_000); | 102 | apb1_pre: APBPrescaler::DIV1, |
| 154 | } | 103 | apb2_pre: APBPrescaler::DIV1, |
| 155 | VoltageScale::RANGE4 => { | 104 | apb3_pre: APBPrescaler::DIV1, |
| 156 | assert!(frequency.0 <= 25_000_000); | 105 | voltage_range: VoltageScale::RANGE1, |
| 157 | } | 106 | ls: Default::default(), |
| 158 | } | 107 | } |
| 159 | |||
| 160 | // Enable HSE, and wait for it to stabilize | ||
| 161 | RCC.cr().write(|w| w.set_hseon(true)); | ||
| 162 | while !RCC.cr().read().hserdy() {} | ||
| 163 | |||
| 164 | frequency | ||
| 165 | } | 108 | } |
| 109 | } | ||
| 110 | |||
| 111 | pub(crate) unsafe fn init(config: Config) { | ||
| 112 | // Set the requested power mode | ||
| 113 | PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); | ||
| 114 | while !PWR.vosr().read().vosrdy() {} | ||
| 166 | 115 | ||
| 167 | unsafe fn init_msis(&self, range: Msirange) -> Hertz { | 116 | let msi = config.msi.map(|range| { |
| 168 | // Check MSI output per RM0456 § 11.4.10 | 117 | // Check MSI output per RM0456 § 11.4.10 |
| 169 | match self.voltage_range { | 118 | match config.voltage_range { |
| 170 | VoltageScale::RANGE4 => { | 119 | VoltageScale::RANGE4 => { |
| 171 | assert!(msirange_to_hertz(range).0 <= 24_000_000); | 120 | assert!(msirange_to_hertz(range).0 <= 24_000_000); |
| 172 | } | 121 | } |
| @@ -191,223 +140,98 @@ impl Config { | |||
| 191 | }); | 140 | }); |
| 192 | while !RCC.cr().read().msisrdy() {} | 141 | while !RCC.cr().read().msisrdy() {} |
| 193 | msirange_to_hertz(range) | 142 | msirange_to_hertz(range) |
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | impl Default for Config { | ||
| 198 | fn default() -> Self { | ||
| 199 | Self { | ||
| 200 | mux: ClockSrc::default(), | ||
| 201 | ahb_pre: AHBPrescaler::DIV1, | ||
| 202 | apb1_pre: APBPrescaler::DIV1, | ||
| 203 | apb2_pre: APBPrescaler::DIV1, | ||
| 204 | apb3_pre: APBPrescaler::DIV1, | ||
| 205 | hsi48: Some(Default::default()), | ||
| 206 | voltage_range: VoltageScale::RANGE3, | ||
| 207 | ls: Default::default(), | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | pub(crate) unsafe fn init(config: Config) { | ||
| 213 | // Ensure PWR peripheral clock is enabled | ||
| 214 | RCC.ahb3enr().modify(|w| { | ||
| 215 | w.set_pwren(true); | ||
| 216 | }); | 143 | }); |
| 217 | RCC.ahb3enr().read(); // synchronize | ||
| 218 | 144 | ||
| 219 | // Set the requested power mode | 145 | let hsi = config.hsi.then(|| { |
| 220 | PWR.vosr().modify(|w| { | 146 | RCC.cr().write(|w| w.set_hsion(true)); |
| 221 | w.set_vos(config.voltage_range); | 147 | while !RCC.cr().read().hsirdy() {} |
| 148 | |||
| 149 | HSI_FREQ | ||
| 222 | }); | 150 | }); |
| 223 | while !PWR.vosr().read().vosrdy() {} | ||
| 224 | 151 | ||
| 225 | let sys_clk = match config.mux { | 152 | let hse = config.hse.map(|hse| { |
| 226 | ClockSrc::MSI(range) => config.init_msis(range), | 153 | // Check frequency limits per RM456 § 11.4.10 |
| 227 | ClockSrc::HSE(freq) => config.init_hse(freq), | 154 | match config.voltage_range { |
| 228 | ClockSrc::HSI => config.init_hsi(), | 155 | VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => { |
| 229 | ClockSrc::PLL1_R(pll) => { | 156 | assert!(hse.freq.0 <= 50_000_000); |
| 230 | // Configure the PLL source | ||
| 231 | let source_clk = match pll.source { | ||
| 232 | PllSource::MSIS(range) => config.init_msis(range), | ||
| 233 | PllSource::HSE(hertz) => config.init_hse(hertz), | ||
| 234 | PllSource::HSI => config.init_hsi(), | ||
| 235 | }; | ||
| 236 | |||
| 237 | // Calculate the reference clock, which is the source divided by m | ||
| 238 | let reference_clk = source_clk / pll.m; | ||
| 239 | |||
| 240 | // Check limits per RM0456 § 11.4.6 | ||
| 241 | assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16)); | ||
| 242 | |||
| 243 | // Calculate the PLL1 VCO clock and PLL1 R output clock | ||
| 244 | let pll1_clk = reference_clk * pll.n; | ||
| 245 | let pll1r_clk = pll1_clk / pll.r; | ||
| 246 | |||
| 247 | // Check system clock per RM0456 § 11.4.9 | ||
| 248 | assert!(pll1r_clk <= Hertz::mhz(160)); | ||
| 249 | |||
| 250 | // Check PLL clocks per RM0456 § 11.4.10 | ||
| 251 | match config.voltage_range { | ||
| 252 | VoltageScale::RANGE1 => { | ||
| 253 | assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); | ||
| 254 | assert!(pll1r_clk <= Hertz::mhz(208)); | ||
| 255 | } | ||
| 256 | VoltageScale::RANGE2 => { | ||
| 257 | assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544)); | ||
| 258 | assert!(pll1r_clk <= Hertz::mhz(110)); | ||
| 259 | } | ||
| 260 | VoltageScale::RANGE3 => { | ||
| 261 | assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330)); | ||
| 262 | assert!(pll1r_clk <= Hertz::mhz(55)); | ||
| 263 | } | ||
| 264 | VoltageScale::RANGE4 => { | ||
| 265 | panic!("PLL is unavailable in voltage range 4"); | ||
| 266 | } | ||
| 267 | } | 157 | } |
| 158 | VoltageScale::RANGE4 => { | ||
| 159 | assert!(hse.freq.0 <= 25_000_000); | ||
| 160 | } | ||
| 161 | } | ||
| 268 | 162 | ||
| 269 | // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler | 163 | // Enable HSE, and wait for it to stabilize |
| 270 | // value that results in an output between 4 and 16 MHz for the PWR EPOD boost | 164 | RCC.cr().write(|w| { |
| 271 | let mboost = if pll1r_clk >= Hertz::mhz(55) { | 165 | w.set_hseon(true); |
| 272 | // source_clk can be up to 50 MHz, so there's just a few cases: | 166 | w.set_hsebyp(hse.mode != HseMode::Oscillator); |
| 273 | if source_clk > Hertz::mhz(32) { | 167 | w.set_hseext(match hse.mode { |
| 274 | // Divide by 4, giving EPOD 8-12.5 MHz | 168 | HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG, |
| 275 | Pllmboost::DIV4 | 169 | HseMode::BypassDigital => Hseext::DIGITAL, |
| 276 | } else if source_clk > Hertz::mhz(16) { | ||
| 277 | // Divide by 2, giving EPOD 8-16 MHz | ||
| 278 | Pllmboost::DIV2 | ||
| 279 | } else { | ||
| 280 | // Bypass, giving EPOD 4-16 MHz | ||
| 281 | Pllmboost::DIV1 | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | // Nothing to do | ||
| 285 | Pllmboost::DIV1 | ||
| 286 | }; | ||
| 287 | |||
| 288 | // Disable the PLL, and wait for it to disable | ||
| 289 | RCC.cr().modify(|w| w.set_pllon(0, false)); | ||
| 290 | while RCC.cr().read().pllrdy(0) {} | ||
| 291 | |||
| 292 | // Configure the PLL | ||
| 293 | RCC.pll1cfgr().write(|w| { | ||
| 294 | // Configure PLL1 source and prescaler | ||
| 295 | w.set_pllsrc(pll.source.into()); | ||
| 296 | w.set_pllm(pll.m); | ||
| 297 | |||
| 298 | // Configure PLL1 input frequncy range | ||
| 299 | let input_range = if reference_clk <= Hertz::mhz(8) { | ||
| 300 | Pllrge::FREQ_4TO8MHZ | ||
| 301 | } else { | ||
| 302 | Pllrge::FREQ_8TO16MHZ | ||
| 303 | }; | ||
| 304 | w.set_pllrge(input_range); | ||
| 305 | |||
| 306 | // Set the prescaler for PWR EPOD | ||
| 307 | w.set_pllmboost(mboost); | ||
| 308 | |||
| 309 | // Enable PLL1_R output | ||
| 310 | w.set_pllren(true); | ||
| 311 | }); | 170 | }); |
| 171 | }); | ||
| 172 | while !RCC.cr().read().hserdy() {} | ||
| 312 | 173 | ||
| 313 | // Configure the PLL divisors | 174 | hse.freq |
| 314 | RCC.pll1divr().modify(|w| { | 175 | }); |
| 315 | // Set the VCO multiplier | ||
| 316 | w.set_plln(pll.n); | ||
| 317 | w.set_pllp(pll.p); | ||
| 318 | w.set_pllq(pll.q); | ||
| 319 | // Set the R output divisor | ||
| 320 | w.set_pllr(pll.r); | ||
| 321 | }); | ||
| 322 | 176 | ||
| 323 | // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? | 177 | let hsi48 = config.hsi48.map(super::init_hsi48); |
| 324 | if pll1r_clk >= Hertz::mhz(55) { | ||
| 325 | // Enable the booster | ||
| 326 | PWR.vosr().modify(|w| { | ||
| 327 | w.set_boosten(true); | ||
| 328 | }); | ||
| 329 | while !PWR.vosr().read().boostrdy() {} | ||
| 330 | } | ||
| 331 | 178 | ||
| 332 | // Enable the PLL | 179 | let pll_input = PllInput { hse, hsi, msi }; |
| 333 | RCC.cr().modify(|w| w.set_pllon(0, true)); | 180 | let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); |
| 334 | while !RCC.cr().read().pllrdy(0) {} | 181 | let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); |
| 182 | let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range); | ||
| 335 | 183 | ||
| 336 | pll1r_clk | 184 | let sys_clk = match config.mux { |
| 337 | } | 185 | ClockSrc::HSE => hse.unwrap(), |
| 186 | ClockSrc::HSI => hsi.unwrap(), | ||
| 187 | ClockSrc::MSIS => msi.unwrap(), | ||
| 188 | ClockSrc::PLL1_R => pll1.r.unwrap(), | ||
| 338 | }; | 189 | }; |
| 339 | 190 | ||
| 340 | let hsi48 = config.hsi48.map(super::init_hsi48); | 191 | // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? |
| 192 | if sys_clk >= Hertz::mhz(55) { | ||
| 193 | // Enable the booster | ||
| 194 | PWR.vosr().modify(|w| w.set_boosten(true)); | ||
| 195 | while !PWR.vosr().read().boostrdy() {} | ||
| 196 | } | ||
| 341 | 197 | ||
| 342 | // The clock source is ready | 198 | // The clock source is ready |
| 343 | // Calculate and set the flash wait states | 199 | // Calculate and set the flash wait states |
| 344 | let wait_states = match config.voltage_range { | 200 | let wait_states = match config.voltage_range { |
| 345 | // VOS 1 range VCORE 1.26V - 1.40V | 201 | // VOS 1 range VCORE 1.26V - 1.40V |
| 346 | VoltageScale::RANGE1 => { | 202 | VoltageScale::RANGE1 => match sys_clk.0 { |
| 347 | if sys_clk.0 < 32_000_000 { | 203 | ..=32_000_000 => 0, |
| 348 | 0 | 204 | ..=64_000_000 => 1, |
| 349 | } else if sys_clk.0 < 64_000_000 { | 205 | ..=96_000_000 => 2, |
| 350 | 1 | 206 | ..=128_000_000 => 3, |
| 351 | } else if sys_clk.0 < 96_000_000 { | 207 | _ => 4, |
| 352 | 2 | 208 | }, |
| 353 | } else if sys_clk.0 < 128_000_000 { | ||
| 354 | 3 | ||
| 355 | } else { | ||
| 356 | 4 | ||
| 357 | } | ||
| 358 | } | ||
| 359 | // VOS 2 range VCORE 1.15V - 1.26V | 209 | // VOS 2 range VCORE 1.15V - 1.26V |
| 360 | VoltageScale::RANGE2 => { | 210 | VoltageScale::RANGE2 => match sys_clk.0 { |
| 361 | if sys_clk.0 < 30_000_000 { | 211 | ..=30_000_000 => 0, |
| 362 | 0 | 212 | ..=60_000_000 => 1, |
| 363 | } else if sys_clk.0 < 60_000_000 { | 213 | ..=90_000_000 => 2, |
| 364 | 1 | 214 | _ => 3, |
| 365 | } else if sys_clk.0 < 90_000_000 { | 215 | }, |
| 366 | 2 | ||
| 367 | } else { | ||
| 368 | 3 | ||
| 369 | } | ||
| 370 | } | ||
| 371 | // VOS 3 range VCORE 1.05V - 1.15V | 216 | // VOS 3 range VCORE 1.05V - 1.15V |
| 372 | VoltageScale::RANGE3 => { | 217 | VoltageScale::RANGE3 => match sys_clk.0 { |
| 373 | if sys_clk.0 < 24_000_000 { | 218 | ..=24_000_000 => 0, |
| 374 | 0 | 219 | ..=48_000_000 => 1, |
| 375 | } else if sys_clk.0 < 48_000_000 { | 220 | _ => 2, |
| 376 | 1 | 221 | }, |
| 377 | } else { | ||
| 378 | 2 | ||
| 379 | } | ||
| 380 | } | ||
| 381 | // VOS 4 range VCORE 0.95V - 1.05V | 222 | // VOS 4 range VCORE 0.95V - 1.05V |
| 382 | VoltageScale::RANGE4 => { | 223 | VoltageScale::RANGE4 => match sys_clk.0 { |
| 383 | if sys_clk.0 < 12_000_000 { | 224 | ..=12_000_000 => 0, |
| 384 | 0 | 225 | _ => 1, |
| 385 | } else { | 226 | }, |
| 386 | 1 | ||
| 387 | } | ||
| 388 | } | ||
| 389 | }; | 227 | }; |
| 390 | FLASH.acr().modify(|w| { | 228 | FLASH.acr().modify(|w| { |
| 391 | w.set_latency(wait_states); | 229 | w.set_latency(wait_states); |
| 392 | }); | 230 | }); |
| 393 | 231 | ||
| 394 | // Switch the system clock source | 232 | // Switch the system clock source |
| 395 | RCC.cfgr1().modify(|w| { | 233 | RCC.cfgr1().modify(|w| w.set_sw(config.mux)); |
| 396 | w.set_sw(config.mux.into()); | 234 | while RCC.cfgr1().read().sws() != config.mux {} |
| 397 | }); | ||
| 398 | |||
| 399 | // RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus | ||
| 400 | // frequency for each voltage range exactly matches the maximum permitted PLL output frequency. | ||
| 401 | // Given that: | ||
| 402 | // | ||
| 403 | // 1. Any bus frequency can never exceed the system clock frequency; | ||
| 404 | // 2. We checked the PLL output frequency if we're using it as a system clock; | ||
| 405 | // 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and | ||
| 406 | // we checked the HSE frequency if configured as a system clock; and | ||
| 407 | // 4. The maximum frequencies from the other clock sources are lower than the lowest bus | ||
| 408 | // frequency limit | ||
| 409 | // | ||
| 410 | // ...then we do not need to perform additional bus-related frequency checks. | ||
| 411 | 235 | ||
| 412 | // Configure the bus prescalers | 236 | // Configure the bus prescalers |
| 413 | RCC.cfgr2().modify(|w| { | 237 | RCC.cfgr2().modify(|w| { |
| @@ -419,64 +243,52 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 419 | w.set_ppre3(config.apb3_pre); | 243 | w.set_ppre3(config.apb3_pre); |
| 420 | }); | 244 | }); |
| 421 | 245 | ||
| 422 | let ahb_freq = sys_clk / config.ahb_pre; | 246 | let hclk = sys_clk / config.ahb_pre; |
| 423 | |||
| 424 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | ||
| 425 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | ||
| 426 | pre => { | ||
| 427 | let freq = ahb_freq / pre; | ||
| 428 | (freq, freq * 2u32) | ||
| 429 | } | ||
| 430 | }; | ||
| 431 | 247 | ||
| 432 | let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { | 248 | let hclk_max = match config.voltage_range { |
| 433 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | 249 | VoltageScale::RANGE1 => Hertz::mhz(160), |
| 434 | pre => { | 250 | VoltageScale::RANGE2 => Hertz::mhz(110), |
| 435 | let freq = ahb_freq / pre; | 251 | VoltageScale::RANGE3 => Hertz::mhz(55), |
| 436 | (freq, freq * 2u32) | 252 | VoltageScale::RANGE4 => Hertz::mhz(25), |
| 437 | } | ||
| 438 | }; | 253 | }; |
| 254 | assert!(hclk <= hclk_max); | ||
| 439 | 255 | ||
| 440 | let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { | 256 | let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); |
| 441 | APBPrescaler::DIV1 => (ahb_freq, ahb_freq), | 257 | let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); |
| 442 | pre => { | 258 | let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre); |
| 443 | let freq = ahb_freq / pre; | ||
| 444 | (freq, freq * 2u32) | ||
| 445 | } | ||
| 446 | }; | ||
| 447 | 259 | ||
| 448 | let rtc = config.ls.init(); | 260 | let rtc = config.ls.init(); |
| 449 | 261 | ||
| 450 | set_clocks!( | 262 | set_clocks!( |
| 451 | sys: Some(sys_clk), | 263 | sys: Some(sys_clk), |
| 452 | hclk1: Some(ahb_freq), | 264 | hclk1: Some(hclk), |
| 453 | hclk2: Some(ahb_freq), | 265 | hclk2: Some(hclk), |
| 454 | hclk3: Some(ahb_freq), | 266 | hclk3: Some(hclk), |
| 455 | pclk1: Some(apb1_freq), | 267 | pclk1: Some(pclk1), |
| 456 | pclk2: Some(apb2_freq), | 268 | pclk2: Some(pclk2), |
| 457 | pclk3: Some(apb3_freq), | 269 | pclk3: Some(pclk3), |
| 458 | pclk1_tim: Some(apb1_tim_freq), | 270 | pclk1_tim: Some(pclk1_tim), |
| 459 | pclk2_tim: Some(apb2_tim_freq), | 271 | pclk2_tim: Some(pclk2_tim), |
| 460 | hsi48: hsi48, | 272 | hsi48: hsi48, |
| 461 | rtc: rtc, | 273 | rtc: rtc, |
| 274 | hse: hse, | ||
| 275 | hsi: hsi, | ||
| 276 | pll1_p: pll1.p, | ||
| 277 | pll1_q: pll1.q, | ||
| 278 | pll1_r: pll1.r, | ||
| 279 | pll2_p: pll2.p, | ||
| 280 | pll2_q: pll2.q, | ||
| 281 | pll2_r: pll2.r, | ||
| 282 | pll3_p: pll3.p, | ||
| 283 | pll3_q: pll3.q, | ||
| 284 | pll3_r: pll3.r, | ||
| 462 | 285 | ||
| 463 | // TODO | 286 | // TODO |
| 464 | hse: None, | ||
| 465 | hsi: None, | ||
| 466 | audioclk: None, | 287 | audioclk: None, |
| 467 | hsi48_div_2: None, | 288 | hsi48_div_2: None, |
| 468 | lse: None, | 289 | lse: None, |
| 469 | lsi: None, | 290 | lsi: None, |
| 470 | msik: None, | 291 | msik: None, |
| 471 | pll1_p: None, | ||
| 472 | pll1_q: None, | ||
| 473 | pll1_r: None, | ||
| 474 | pll2_p: None, | ||
| 475 | pll2_q: None, | ||
| 476 | pll2_r: None, | ||
| 477 | pll3_p: None, | ||
| 478 | pll3_q: None, | ||
| 479 | pll3_r: None, | ||
| 480 | iclk: None, | 292 | iclk: None, |
| 481 | ); | 293 | ); |
| 482 | } | 294 | } |
| @@ -501,3 +313,126 @@ fn msirange_to_hertz(range: Msirange) -> Hertz { | |||
| 501 | Msirange::RANGE_100KHZ => Hertz(100_000), | 313 | Msirange::RANGE_100KHZ => Hertz(100_000), |
| 502 | } | 314 | } |
| 503 | } | 315 | } |
| 316 | |||
| 317 | pub(super) struct PllInput { | ||
| 318 | pub hsi: Option<Hertz>, | ||
| 319 | pub hse: Option<Hertz>, | ||
| 320 | pub msi: Option<Hertz>, | ||
| 321 | } | ||
| 322 | |||
| 323 | #[allow(unused)] | ||
| 324 | #[derive(Default)] | ||
| 325 | pub(super) struct PllOutput { | ||
| 326 | pub p: Option<Hertz>, | ||
| 327 | pub q: Option<Hertz>, | ||
| 328 | pub r: Option<Hertz>, | ||
| 329 | } | ||
| 330 | |||
| 331 | #[derive(PartialEq, Eq, Clone, Copy)] | ||
| 332 | enum PllInstance { | ||
| 333 | Pll1 = 0, | ||
| 334 | Pll2 = 1, | ||
| 335 | Pll3 = 2, | ||
| 336 | } | ||
| 337 | |||
| 338 | fn pll_enable(instance: PllInstance, enabled: bool) { | ||
| 339 | RCC.cr().modify(|w| w.set_pllon(instance as _, enabled)); | ||
| 340 | while RCC.cr().read().pllrdy(instance as _) != enabled {} | ||
| 341 | } | ||
| 342 | |||
| 343 | fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) -> PllOutput { | ||
| 344 | // Disable PLL | ||
| 345 | pll_enable(instance, false); | ||
| 346 | |||
| 347 | let Some(pll) = config else { return PllOutput::default() }; | ||
| 348 | |||
| 349 | let src_freq = match pll.source { | ||
| 350 | PllSource::DISABLE => panic!("must not select PLL source as DISABLE"), | ||
| 351 | PllSource::HSE => unwrap!(input.hse), | ||
| 352 | PllSource::HSI => unwrap!(input.hsi), | ||
| 353 | PllSource::MSIS => unwrap!(input.msi), | ||
| 354 | }; | ||
| 355 | |||
| 356 | // Calculate the reference clock, which is the source divided by m | ||
| 357 | let ref_freq = src_freq / pll.prediv; | ||
| 358 | // Check limits per RM0456 § 11.4.6 | ||
| 359 | assert!(Hertz::mhz(4) <= ref_freq && ref_freq <= Hertz::mhz(16)); | ||
| 360 | |||
| 361 | // Check PLL clocks per RM0456 § 11.4.10 | ||
| 362 | let (vco_min, vco_max, out_max) = match voltage_range { | ||
| 363 | VoltageScale::RANGE1 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(208)), | ||
| 364 | VoltageScale::RANGE2 => (Hertz::mhz(128), Hertz::mhz(544), Hertz::mhz(110)), | ||
| 365 | VoltageScale::RANGE3 => (Hertz::mhz(128), Hertz::mhz(330), Hertz::mhz(55)), | ||
| 366 | VoltageScale::RANGE4 => panic!("PLL is unavailable in voltage range 4"), | ||
| 367 | }; | ||
| 368 | |||
| 369 | // Calculate the PLL VCO clock | ||
| 370 | let vco_freq = ref_freq * pll.mul; | ||
| 371 | assert!(vco_freq >= vco_min && vco_freq <= vco_max); | ||
| 372 | |||
| 373 | // Calculate output clocks. | ||
| 374 | let p = pll.divp.map(|div| vco_freq / div); | ||
| 375 | let q = pll.divq.map(|div| vco_freq / div); | ||
| 376 | let r = pll.divr.map(|div| vco_freq / div); | ||
| 377 | for freq in [p, q, r] { | ||
| 378 | if let Some(freq) = freq { | ||
| 379 | assert!(freq <= out_max); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | let divr = match instance { | ||
| 384 | PllInstance::Pll1 => RCC.pll1divr(), | ||
| 385 | PllInstance::Pll2 => RCC.pll2divr(), | ||
| 386 | PllInstance::Pll3 => RCC.pll3divr(), | ||
| 387 | }; | ||
| 388 | divr.write(|w| { | ||
| 389 | w.set_plln(pll.mul); | ||
| 390 | w.set_pllp(pll.divp.unwrap_or(PllDiv::DIV1)); | ||
| 391 | w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1)); | ||
| 392 | w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1)); | ||
| 393 | }); | ||
| 394 | |||
| 395 | let input_range = match ref_freq.0 { | ||
| 396 | ..=8_000_000 => Pllrge::FREQ_4TO8MHZ, | ||
| 397 | _ => Pllrge::FREQ_8TO16MHZ, | ||
| 398 | }; | ||
| 399 | |||
| 400 | macro_rules! write_fields { | ||
| 401 | ($w:ident) => { | ||
| 402 | $w.set_pllpen(pll.divp.is_some()); | ||
| 403 | $w.set_pllqen(pll.divq.is_some()); | ||
| 404 | $w.set_pllren(pll.divr.is_some()); | ||
| 405 | $w.set_pllm(pll.prediv); | ||
| 406 | $w.set_pllsrc(pll.source); | ||
| 407 | $w.set_pllrge(input_range); | ||
| 408 | }; | ||
| 409 | } | ||
| 410 | |||
| 411 | match instance { | ||
| 412 | PllInstance::Pll1 => RCC.pll1cfgr().write(|w| { | ||
| 413 | // § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler | ||
| 414 | // value that results in an output between 4 and 16 MHz for the PWR EPOD boost | ||
| 415 | if r.unwrap() >= Hertz::mhz(55) { | ||
| 416 | // source_clk can be up to 50 MHz, so there's just a few cases: | ||
| 417 | let mboost = match src_freq.0 { | ||
| 418 | ..=16_000_000 => Pllmboost::DIV1, // Bypass, giving EPOD 4-16 MHz | ||
| 419 | ..=32_000_000 => Pllmboost::DIV2, // Divide by 2, giving EPOD 8-16 MHz | ||
| 420 | _ => Pllmboost::DIV4, // Divide by 4, giving EPOD 8-12.5 MHz | ||
| 421 | }; | ||
| 422 | w.set_pllmboost(mboost); | ||
| 423 | } | ||
| 424 | write_fields!(w); | ||
| 425 | }), | ||
| 426 | PllInstance::Pll2 => RCC.pll2cfgr().write(|w| { | ||
| 427 | write_fields!(w); | ||
| 428 | }), | ||
| 429 | PllInstance::Pll3 => RCC.pll3cfgr().write(|w| { | ||
| 430 | write_fields!(w); | ||
| 431 | }), | ||
| 432 | } | ||
| 433 | |||
| 434 | // Enable PLL | ||
| 435 | pll_enable(instance, true); | ||
| 436 | |||
| 437 | PllOutput { p, q, r } | ||
| 438 | } | ||
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index dca34fd0e..99cdeacc9 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs | |||
| @@ -4,7 +4,6 @@ | |||
| 4 | use defmt::{panic, *}; | 4 | use defmt::{panic, *}; |
| 5 | use defmt_rtt as _; // global logger | 5 | use defmt_rtt as _; // global logger |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::rcc::*; | ||
| 8 | use embassy_stm32::usb_otg::{Driver, Instance}; | 7 | use embassy_stm32::usb_otg::{Driver, Instance}; |
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; | 8 | use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config}; |
| 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| @@ -22,22 +21,28 @@ async fn main(_spawner: Spawner) { | |||
| 22 | info!("Hello World!"); | 21 | info!("Hello World!"); |
| 23 | 22 | ||
| 24 | let mut config = Config::default(); | 23 | let mut config = Config::default(); |
| 25 | config.rcc.mux = ClockSrc::PLL1_R(PllConfig { | 24 | { |
| 26 | source: PllSource::HSI, | 25 | use embassy_stm32::rcc::*; |
| 27 | m: Pllm::DIV2, | 26 | config.rcc.hsi = true; |
| 28 | n: Plln::MUL10, | 27 | config.rcc.pll1 = Some(Pll { |
| 29 | p: Plldiv::DIV1, | 28 | source: PllSource::HSI, // 16 MHz |
| 30 | q: Plldiv::DIV1, | 29 | prediv: PllPreDiv::DIV1, |
| 31 | r: Plldiv::DIV1, | 30 | mul: PllMul::MUL10, |
| 32 | }); | 31 | divp: None, |
| 33 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | 32 | divq: None, |
| 33 | divr: Some(PllDiv::DIV1), // 160 MHz | ||
| 34 | }); | ||
| 35 | config.rcc.mux = ClockSrc::PLL1_R; | ||
| 36 | config.rcc.voltage_range = VoltageScale::RANGE1; | ||
| 37 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 38 | } | ||
| 34 | 39 | ||
| 35 | let p = embassy_stm32::init(config); | 40 | let p = embassy_stm32::init(config); |
| 36 | 41 | ||
| 37 | // Create the driver, from the HAL. | 42 | // Create the driver, from the HAL. |
| 38 | let mut ep_out_buffer = [0u8; 256]; | 43 | let mut ep_out_buffer = [0u8; 256]; |
| 39 | let mut config = embassy_stm32::usb_otg::Config::default(); | 44 | let mut config = embassy_stm32::usb_otg::Config::default(); |
| 40 | config.vbus_detection = true; | 45 | config.vbus_detection = false; |
| 41 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | 46 | let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); |
| 42 | 47 | ||
| 43 | // Create embassy-usb Config | 48 | // Create embassy-usb Config |
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 5b28b5849..828a28e2c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -26,7 +26,7 @@ stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash" | |||
| 26 | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] | 26 | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] |
| 27 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] | 27 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] |
| 28 | stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] | 28 | stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] |
| 29 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng"] | 29 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] |
| 30 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] | 30 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] |
| 31 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] | 31 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] |
| 32 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | 32 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] |
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs index bc5589164..176adff62 100644 --- a/tests/stm32/build.rs +++ b/tests/stm32/build.rs | |||
| @@ -16,6 +16,7 @@ fn main() -> Result<(), Box<dyn Error>> { | |||
| 16 | feature = "stm32l073rz", | 16 | feature = "stm32l073rz", |
| 17 | // wrong ram size in stm32-data | 17 | // wrong ram size in stm32-data |
| 18 | feature = "stm32wl55jc", | 18 | feature = "stm32wl55jc", |
| 19 | feature = "stm32u5a5zj", | ||
| 19 | // no VTOR, so interrupts can't work when running from RAM | 20 | // no VTOR, so interrupts can't work when running from RAM |
| 20 | feature = "stm32f091rc", | 21 | feature = "stm32f091rc", |
| 21 | )) { | 22 | )) { |
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 50a7f9bae..1e6b1cce9 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs | |||
| @@ -577,7 +577,18 @@ pub fn config() -> Config { | |||
| 577 | #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] | 577 | #[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))] |
| 578 | { | 578 | { |
| 579 | use embassy_stm32::rcc::*; | 579 | use embassy_stm32::rcc::*; |
| 580 | config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_48MHZ); | 580 | config.rcc.hsi = true; |
| 581 | config.rcc.pll1 = Some(Pll { | ||
| 582 | source: PllSource::HSI, // 16 MHz | ||
| 583 | prediv: PllPreDiv::DIV1, | ||
| 584 | mul: PllMul::MUL10, | ||
| 585 | divp: None, | ||
| 586 | divq: None, | ||
| 587 | divr: Some(PllDiv::DIV1), // 160 MHz | ||
| 588 | }); | ||
| 589 | config.rcc.mux = ClockSrc::PLL1_R; | ||
| 590 | config.rcc.voltage_range = VoltageScale::RANGE1; | ||
| 591 | config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB | ||
| 581 | } | 592 | } |
| 582 | 593 | ||
| 583 | #[cfg(feature = "stm32wba52cg")] | 594 | #[cfg(feature = "stm32wba52cg")] |
