aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/rcc/wba.rs64
-rw-r--r--embassy-stm32/src/usb/mod.rs8
-rw-r--r--embassy-stm32/src/usb/otg.rs10
-rw-r--r--examples/stm32wba/src/bin/usb_hs_serial.rs24
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 @@
1pub use crate::pac::pwr::vals::Vos as VoltageScale; 1pub use crate::pac::pwr::vals::Vos as VoltageScale;
2use crate::pac::rcc::regs::Cfgr1; 2use crate::pac::rcc::regs::Cfgr1;
3use core::ops::Div;
3pub use crate::pac::rcc::vals::{ 4pub 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};
7use crate::pac::rcc::vals::Pllrge; 8use crate::pac::rcc::vals::Pllrge;
8use crate::pac::{FLASH, RCC}; 9use crate::pac::{FLASH, RCC};
@@ -20,6 +21,23 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
20// HSE speed 21// HSE speed
21pub const HSE_FREQ: Hertz = Hertz(32_000_000); 22pub const HSE_FREQ: Hertz = Hertz(32_000_000);
22 23
24// Allow dividing a Hertz value by an AHB5 prescaler directly
25impl 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)]
24pub struct Hse { 42pub 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
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join; 7use embassy_futures::join::join;
8use embassy_stm32::rcc::{PllSource, PllPreDiv, PllMul, PllDiv}; 8use embassy_stm32::rcc::{PllSource, PllPreDiv, PllMul, PllDiv};
9use embassy_stm32::rcc::{mux, AHBPrescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale}; 9use embassy_stm32::rcc::{mux, AHBPrescaler, AHB5Prescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale};
10use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
11use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; 11use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 12use 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;