diff options
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/wba.rs | 64 | ||||
| -rw-r--r-- | embassy-stm32/src/usb/mod.rs | 8 | ||||
| -rw-r--r-- | embassy-stm32/src/usb/otg.rs | 10 | ||||
| -rw-r--r-- | examples/stm32wba/src/bin/usb_hs_serial.rs | 24 |
5 files changed, 83 insertions, 25 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index c7a33ed72..d893f1b54 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -546,7 +546,7 @@ fn init_hw(config: Config) -> Peripherals { | |||
| 546 | { | 546 | { |
| 547 | use crate::pac::pwr::vals; | 547 | use crate::pac::pwr::vals; |
| 548 | crate::pac::PWR.svmcr().modify(|w| { | 548 | crate::pac::PWR.svmcr().modify(|w| { |
| 549 | w.set_io2sv(vals::Io2sv::B_0X1); | 549 | w.set_io2sv(if config.enable_independent_io_supply {vals::Io2sv::B_0X1} else {vals::Io2sv::B_0X0}); |
| 550 | }); | 550 | }); |
| 551 | } | 551 | } |
| 552 | #[cfg(stm32u5)] | 552 | #[cfg(stm32u5)] |
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index a5e6b33ff..0025d2a51 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | pub use crate::pac::pwr::vals::Vos as VoltageScale; | 1 | pub use crate::pac::pwr::vals::Vos as VoltageScale; |
| 2 | use crate::pac::rcc::regs::Cfgr1; | 2 | use crate::pac::rcc::regs::Cfgr1; |
| 3 | use core::ops::Div; | ||
| 3 | pub use crate::pac::rcc::vals::{ | 4 | pub use crate::pac::rcc::vals::{ |
| 4 | Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource, | 5 | Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource, |
| 5 | Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, | 6 | Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Hpre5 as AHB5Prescaler, Hdiv5, |
| 6 | }; | 7 | }; |
| 7 | use crate::pac::rcc::vals::Pllrge; | 8 | use crate::pac::rcc::vals::Pllrge; |
| 8 | use crate::pac::{FLASH, RCC}; | 9 | use crate::pac::{FLASH, RCC}; |
| @@ -20,6 +21,23 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000); | |||
| 20 | // HSE speed | 21 | // HSE speed |
| 21 | pub const HSE_FREQ: Hertz = Hertz(32_000_000); | 22 | pub const HSE_FREQ: Hertz = Hertz(32_000_000); |
| 22 | 23 | ||
| 24 | // Allow dividing a Hertz value by an AHB5 prescaler directly | ||
| 25 | impl Div<AHB5Prescaler> for Hertz { | ||
| 26 | type Output = Hertz; | ||
| 27 | fn div(self, rhs: AHB5Prescaler) -> Hertz { | ||
| 28 | // Map the prescaler enum to its integer divisor | ||
| 29 | let divisor = match rhs { | ||
| 30 | AHB5Prescaler::DIV1 => 1, | ||
| 31 | AHB5Prescaler::DIV2 => 2, | ||
| 32 | AHB5Prescaler::DIV3 => 3, | ||
| 33 | AHB5Prescaler::DIV4 => 4, | ||
| 34 | AHB5Prescaler::DIV6 => 6, | ||
| 35 | _ => unreachable!("Invalid AHB5 prescaler: {:?}", rhs), | ||
| 36 | }; | ||
| 37 | Hertz(self.0 / divisor) | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 23 | #[derive(Clone, Copy, Eq, PartialEq)] | 41 | #[derive(Clone, Copy, Eq, PartialEq)] |
| 24 | pub struct Hse { | 42 | pub struct Hse { |
| 25 | pub prescaler: HsePrescaler, | 43 | pub prescaler: HsePrescaler, |
| @@ -71,6 +89,7 @@ pub struct Config { | |||
| 71 | // sysclk, buses. | 89 | // sysclk, buses. |
| 72 | pub sys: Sysclk, | 90 | pub sys: Sysclk, |
| 73 | pub ahb_pre: AHBPrescaler, | 91 | pub ahb_pre: AHBPrescaler, |
| 92 | pub ahb5_pre: AHB5Prescaler, | ||
| 74 | pub apb1_pre: APBPrescaler, | 93 | pub apb1_pre: APBPrescaler, |
| 75 | pub apb2_pre: APBPrescaler, | 94 | pub apb2_pre: APBPrescaler, |
| 76 | pub apb7_pre: APBPrescaler, | 95 | pub apb7_pre: APBPrescaler, |
| @@ -93,6 +112,7 @@ impl Config { | |||
| 93 | pll1: None, | 112 | pll1: None, |
| 94 | sys: Sysclk::HSI, | 113 | sys: Sysclk::HSI, |
| 95 | ahb_pre: AHBPrescaler::DIV1, | 114 | ahb_pre: AHBPrescaler::DIV1, |
| 115 | ahb5_pre: AHB5Prescaler::DIV1, | ||
| 96 | apb1_pre: APBPrescaler::DIV1, | 116 | apb1_pre: APBPrescaler::DIV1, |
| 97 | apb2_pre: APBPrescaler::DIV1, | 117 | apb2_pre: APBPrescaler::DIV1, |
| 98 | apb7_pre: APBPrescaler::DIV1, | 118 | apb7_pre: APBPrescaler::DIV1, |
| @@ -165,7 +185,6 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 165 | let hclk1 = sys_clk / config.ahb_pre; | 185 | let hclk1 = sys_clk / config.ahb_pre; |
| 166 | let hclk2 = hclk1; | 186 | let hclk2 = hclk1; |
| 167 | let hclk4 = hclk1; | 187 | let hclk4 = hclk1; |
| 168 | // TODO: hclk5 | ||
| 169 | let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre); | 188 | let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre); |
| 170 | let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); | 189 | let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); |
| 171 | let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre); | 190 | let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre); |
| @@ -211,6 +230,27 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 211 | w.set_ppre2(config.apb2_pre); | 230 | w.set_ppre2(config.apb2_pre); |
| 212 | }); | 231 | }); |
| 213 | 232 | ||
| 233 | // Set AHB5 prescaler depending on sysclk source | ||
| 234 | RCC.cfgr4().modify(|w| match config.sys { | ||
| 235 | // When using HSI or HSE, use HDIV5 bit (0 = div1, 1 = div2) | ||
| 236 | Sysclk::HSI | Sysclk::HSE => { | ||
| 237 | // Only Div1 and Div2 are valid for HDIV5, enforce this | ||
| 238 | match config.ahb5_pre { | ||
| 239 | AHB5Prescaler::DIV1 => w.set_hdiv5(Hdiv5::DIV1), | ||
| 240 | AHB5Prescaler::DIV2 => w.set_hdiv5(Hdiv5::DIV2), | ||
| 241 | _ => panic!("Invalid ahb5_pre for HSI/HSE sysclk: only DIV1 and DIV2 are allowed"), | ||
| 242 | }; | ||
| 243 | } | ||
| 244 | // When using PLL1, use HPRE5 bits [2:0] | ||
| 245 | Sysclk::PLL1_R => { | ||
| 246 | w.set_hpre5(config.ahb5_pre); | ||
| 247 | } | ||
| 248 | _ => {} | ||
| 249 | }); | ||
| 250 | |||
| 251 | let hclk5 = sys_clk / config.ahb5_pre; | ||
| 252 | |||
| 253 | |||
| 214 | #[cfg(all(stm32wba, peri_usb_otg_hs))] | 254 | #[cfg(all(stm32wba, peri_usb_otg_hs))] |
| 215 | let usb_refck = match config.mux.otghssel { | 255 | let usb_refck = match config.mux.otghssel { |
| 216 | Otghssel::HSE => hse, | 256 | Otghssel::HSE => hse, |
| @@ -245,6 +285,7 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 245 | hclk1: Some(hclk1), | 285 | hclk1: Some(hclk1), |
| 246 | hclk2: Some(hclk2), | 286 | hclk2: Some(hclk2), |
| 247 | hclk4: Some(hclk4), | 287 | hclk4: Some(hclk4), |
| 288 | hclk5: Some(hclk5), | ||
| 248 | pclk1: Some(pclk1), | 289 | pclk1: Some(pclk1), |
| 249 | pclk2: Some(pclk2), | 290 | pclk2: Some(pclk2), |
| 250 | pclk7: Some(pclk7), | 291 | pclk7: Some(pclk7), |
| @@ -294,8 +335,15 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) | |||
| 294 | PllSource::_RESERVED_1 => panic!("must not select RESERVED_1 source as DISABLE"), | 335 | PllSource::_RESERVED_1 => panic!("must not select RESERVED_1 source as DISABLE"), |
| 295 | }; | 336 | }; |
| 296 | 337 | ||
| 297 | let hse_div = RCC.cr().read().hsepre(); | 338 | // Only divide by the HSE prescaler when the PLL source is HSE |
| 298 | let src_freq = pre_src_freq / hse_div; | 339 | let src_freq = match pll.source { |
| 340 | PllSource::HSE => { | ||
| 341 | // read the prescaler bits and divide | ||
| 342 | let hsepre = RCC.cr().read().hsepre(); | ||
| 343 | pre_src_freq / hsepre | ||
| 344 | } | ||
| 345 | _ => pre_src_freq, | ||
| 346 | }; | ||
| 299 | 347 | ||
| 300 | // Calculate the reference clock, which is the source divided by m | 348 | // Calculate the reference clock, which is the source divided by m |
| 301 | let ref_freq = src_freq / pll.prediv; | 349 | let ref_freq = src_freq / pll.prediv; |
| @@ -309,7 +357,11 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) | |||
| 309 | }; | 357 | }; |
| 310 | 358 | ||
| 311 | // Calculate the PLL VCO clock | 359 | // Calculate the PLL VCO clock |
| 312 | let vco_freq = ref_freq * pll.mul; | 360 | // let vco_freq = ref_freq * pll.mul; |
| 361 | // Calculate VCO frequency including fractional part: FVCO = Fref_ck × (N + FRAC/2^13) | ||
| 362 | let numerator = (ref_freq.0 as u64) * (((pll.mul as u64) + 1 << 13) + pll.frac.unwrap_or(0) as u64); | ||
| 363 | let vco_hz = (numerator >> 13) as u32; | ||
| 364 | let vco_freq = Hertz(vco_hz); | ||
| 313 | assert!(vco_freq >= vco_min && vco_freq <= vco_max); | 365 | assert!(vco_freq >= vco_min && vco_freq <= vco_max); |
| 314 | 366 | ||
| 315 | // Calculate output clocks. | 367 | // Calculate output clocks. |
| @@ -329,7 +381,7 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale) | |||
| 329 | w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1)); | 381 | w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1)); |
| 330 | w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1)); | 382 | w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1)); |
| 331 | }); | 383 | }); |
| 332 | RCC.pll1fracr().write(|w| {w.set_pllfracn(pll.frac.unwrap_or(1));}); | 384 | RCC.pll1fracr().write(|w| {w.set_pllfracn(pll.frac.unwrap_or(0));}); |
| 333 | 385 | ||
| 334 | let input_range = match ref_freq.0 { | 386 | let input_range = match ref_freq.0 { |
| 335 | ..=8_000_000 => Pllrge::FREQ_4TO8MHZ, | 387 | ..=8_000_000 => Pllrge::FREQ_4TO8MHZ, |
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 692897b59..d987a056d 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs | |||
| @@ -108,7 +108,12 @@ fn common_init<T: Instance>() { | |||
| 108 | critical_section::with(|_| { | 108 | critical_section::with(|_| { |
| 109 | crate::pac::PWR.svmcr().modify(|w| { | 109 | crate::pac::PWR.svmcr().modify(|w| { |
| 110 | w.set_usv(crate::pac::pwr::vals::Usv::B_0X1); | 110 | w.set_usv(crate::pac::pwr::vals::Usv::B_0X1); |
| 111 | // w.set_uvmen(true); | 111 | }); |
| 112 | crate::pac::PWR.vosr().modify(|w| { | ||
| 113 | w.set_vdd11usbdis(true); | ||
| 114 | }); | ||
| 115 | crate::pac::PWR.vosr().modify(|w| { | ||
| 116 | w.set_usbpwren(true); | ||
| 112 | }) | 117 | }) |
| 113 | }); | 118 | }); |
| 114 | 119 | ||
| @@ -119,7 +124,6 @@ fn common_init<T: Instance>() { | |||
| 119 | #[cfg(peri_usb_otg_hs)] | 124 | #[cfg(peri_usb_otg_hs)] |
| 120 | { | 125 | { |
| 121 | crate::pac::PWR.vosr().modify(|w| { | 126 | crate::pac::PWR.vosr().modify(|w| { |
| 122 | w.set_usbpwren(true); | ||
| 123 | w.set_usbboosten(true); | 127 | w.set_usbboosten(true); |
| 124 | }); | 128 | }); |
| 125 | while !crate::pac::PWR.vosr().read().usbboostrdy() {} | 129 | while !crate::pac::PWR.vosr().read().usbboostrdy() {} |
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 6b28ac980..abf54cbad 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs | |||
| @@ -330,9 +330,9 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 330 | #[cfg(all(stm32wba, peri_usb_otg_hs))] | 330 | #[cfg(all(stm32wba, peri_usb_otg_hs))] |
| 331 | { | 331 | { |
| 332 | critical_section::with(|_| { | 332 | critical_section::with(|_| { |
| 333 | crate::pac::RCC.apb7enr().modify(|w| { | 333 | // crate::pac::RCC.apb7enr().modify(|w| { |
| 334 | w.set_syscfgen(true); | 334 | // w.set_syscfgen(true); |
| 335 | }); | 335 | // }); |
| 336 | crate::pac::RCC.ahb2enr().modify(|w| { | 336 | crate::pac::RCC.ahb2enr().modify(|w| { |
| 337 | w.set_usb_otg_hsen(true); | 337 | w.set_usb_otg_hsen(true); |
| 338 | w.set_usb_otg_hs_phyen(true); | 338 | w.set_usb_otg_hs_phyen(true); |
| @@ -366,8 +366,8 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 366 | // Configuring Vbus sense and SOF output | 366 | // Configuring Vbus sense and SOF output |
| 367 | match core_id { | 367 | match core_id { |
| 368 | 0x0000_1200 | 0x0000_1100 | 0x0000_1000 => self.inner.config_v1(), | 368 | 0x0000_1200 | 0x0000_1100 | 0x0000_1000 => self.inner.config_v1(), |
| 369 | 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 | 0x0000_6100 => self.inner.config_v2v3(), | 369 | 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), |
| 370 | 0x0000_5000 => self.inner.config_v5(), | 370 | 0x0000_5000 | 0x0000_6100 => self.inner.config_v5(), |
| 371 | _ => unimplemented!("Unknown USB core id {:X}", core_id), | 371 | _ => unimplemented!("Unknown USB core id {:X}", core_id), |
| 372 | } | 372 | } |
| 373 | } | 373 | } |
diff --git a/examples/stm32wba/src/bin/usb_hs_serial.rs b/examples/stm32wba/src/bin/usb_hs_serial.rs index bda4a5013..393f8be6b 100644 --- a/examples/stm32wba/src/bin/usb_hs_serial.rs +++ b/examples/stm32wba/src/bin/usb_hs_serial.rs | |||
| @@ -6,7 +6,7 @@ use defmt_rtt as _; // global logger | |||
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_futures::join::join; | 7 | use embassy_futures::join::join; |
| 8 | use embassy_stm32::rcc::{PllSource, PllPreDiv, PllMul, PllDiv}; | 8 | use embassy_stm32::rcc::{PllSource, PllPreDiv, PllMul, PllDiv}; |
| 9 | use embassy_stm32::rcc::{mux, AHBPrescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale}; | 9 | use embassy_stm32::rcc::{mux, AHBPrescaler, AHB5Prescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale}; |
| 10 | use embassy_stm32::usb::{Driver, Instance}; | 10 | use embassy_stm32::usb::{Driver, Instance}; |
| 11 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; | 11 | use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; |
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| @@ -25,26 +25,28 @@ async fn main(_spawner: Spawner) { | |||
| 25 | let mut config = Config::default(); | 25 | let mut config = Config::default(); |
| 26 | 26 | ||
| 27 | // External HSE (32 MHz) setup | 27 | // External HSE (32 MHz) setup |
| 28 | config.rcc.hse = Some(Hse { | 28 | // config.rcc.hse = Some(Hse { |
| 29 | prescaler: HsePrescaler::DIV2, | 29 | // prescaler: HsePrescaler::DIV2, |
| 30 | }); | 30 | // }); |
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | // Fine-tune PLL1 dividers/multipliers | 33 | // Fine-tune PLL1 dividers/multipliers |
| 34 | config.rcc.pll1 = Some(embassy_stm32::rcc::Pll { | 34 | config.rcc.pll1 = Some(embassy_stm32::rcc::Pll { |
| 35 | source: PllSource::HSE, | 35 | source: PllSource::HSI, |
| 36 | prediv: PllPreDiv::DIV2, // PLLM = 2 → HSE / 2 = 8 MHz | 36 | prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz |
| 37 | mul: PllMul::MUL60, // PLLN = 60 → 8 MHz * 60 = 480 MHz VCO | 37 | mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO |
| 38 | divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) | 38 | divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) |
| 39 | divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (USB) | 39 | // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED) |
| 40 | divp: Some(PllDiv::DIV15), // PLLP = 15 → 32 MHz (USBOTG) | 40 | divq: None, |
| 41 | frac: Some(4096), // Fractional part (enabled) | 41 | divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG) |
| 42 | frac: Some(0), // Fractional part (enabled) | ||
| 42 | }); | 43 | }); |
| 43 | 44 | ||
| 44 | config.rcc.ahb_pre = AHBPrescaler::DIV1; | 45 | config.rcc.ahb_pre = AHBPrescaler::DIV1; |
| 45 | config.rcc.apb1_pre = APBPrescaler::DIV1; | 46 | config.rcc.apb1_pre = APBPrescaler::DIV1; |
| 46 | config.rcc.apb2_pre = APBPrescaler::DIV1; | 47 | config.rcc.apb2_pre = APBPrescaler::DIV1; |
| 47 | config.rcc.apb7_pre = APBPrescaler::DIV1; | 48 | config.rcc.apb7_pre = APBPrescaler::DIV1; |
| 49 | config.rcc.ahb5_pre = AHB5Prescaler::DIV4; | ||
| 48 | 50 | ||
| 49 | // voltage scale for max performance | 51 | // voltage scale for max performance |
| 50 | config.rcc.voltage_scale = VoltageScale::RANGE1; | 52 | config.rcc.voltage_scale = VoltageScale::RANGE1; |
