mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 04:10:25 +00:00
Moved from HSE to HSI to generate USB_OTG_HS_CLK
This commit is contained in:
parent
ba5156b6cb
commit
75c1039aa1
@ -546,7 +546,7 @@ fn init_hw(config: Config) -> Peripherals {
|
||||
{
|
||||
use crate::pac::pwr::vals;
|
||||
crate::pac::PWR.svmcr().modify(|w| {
|
||||
w.set_io2sv(vals::Io2sv::B_0X1);
|
||||
w.set_io2sv(if config.enable_independent_io_supply {vals::Io2sv::B_0X1} else {vals::Io2sv::B_0X0});
|
||||
});
|
||||
}
|
||||
#[cfg(stm32u5)]
|
||||
|
@ -1,8 +1,9 @@
|
||||
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||
use crate::pac::rcc::regs::Cfgr1;
|
||||
use core::ops::Div;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource,
|
||||
Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
|
||||
Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Hpre5 as AHB5Prescaler, Hdiv5,
|
||||
};
|
||||
use crate::pac::rcc::vals::Pllrge;
|
||||
use crate::pac::{FLASH, RCC};
|
||||
@ -20,6 +21,23 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||
// HSE speed
|
||||
pub const HSE_FREQ: Hertz = Hertz(32_000_000);
|
||||
|
||||
// Allow dividing a Hertz value by an AHB5 prescaler directly
|
||||
impl Div<AHB5Prescaler> for Hertz {
|
||||
type Output = Hertz;
|
||||
fn div(self, rhs: AHB5Prescaler) -> Hertz {
|
||||
// Map the prescaler enum to its integer divisor
|
||||
let divisor = match rhs {
|
||||
AHB5Prescaler::DIV1 => 1,
|
||||
AHB5Prescaler::DIV2 => 2,
|
||||
AHB5Prescaler::DIV3 => 3,
|
||||
AHB5Prescaler::DIV4 => 4,
|
||||
AHB5Prescaler::DIV6 => 6,
|
||||
_ => unreachable!("Invalid AHB5 prescaler: {:?}", rhs),
|
||||
};
|
||||
Hertz(self.0 / divisor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub struct Hse {
|
||||
pub prescaler: HsePrescaler,
|
||||
@ -71,6 +89,7 @@ pub struct Config {
|
||||
// sysclk, buses.
|
||||
pub sys: Sysclk,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub ahb5_pre: AHB5Prescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
pub apb2_pre: APBPrescaler,
|
||||
pub apb7_pre: APBPrescaler,
|
||||
@ -93,6 +112,7 @@ impl Config {
|
||||
pll1: None,
|
||||
sys: Sysclk::HSI,
|
||||
ahb_pre: AHBPrescaler::DIV1,
|
||||
ahb5_pre: AHB5Prescaler::DIV1,
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
apb7_pre: APBPrescaler::DIV1,
|
||||
@ -165,7 +185,6 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
let hclk1 = sys_clk / config.ahb_pre;
|
||||
let hclk2 = hclk1;
|
||||
let hclk4 = hclk1;
|
||||
// TODO: hclk5
|
||||
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
|
||||
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
|
||||
let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre);
|
||||
@ -211,6 +230,27 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
w.set_ppre2(config.apb2_pre);
|
||||
});
|
||||
|
||||
// Set AHB5 prescaler depending on sysclk source
|
||||
RCC.cfgr4().modify(|w| match config.sys {
|
||||
// When using HSI or HSE, use HDIV5 bit (0 = div1, 1 = div2)
|
||||
Sysclk::HSI | Sysclk::HSE => {
|
||||
// Only Div1 and Div2 are valid for HDIV5, enforce this
|
||||
match config.ahb5_pre {
|
||||
AHB5Prescaler::DIV1 => w.set_hdiv5(Hdiv5::DIV1),
|
||||
AHB5Prescaler::DIV2 => w.set_hdiv5(Hdiv5::DIV2),
|
||||
_ => panic!("Invalid ahb5_pre for HSI/HSE sysclk: only DIV1 and DIV2 are allowed"),
|
||||
};
|
||||
}
|
||||
// When using PLL1, use HPRE5 bits [2:0]
|
||||
Sysclk::PLL1_R => {
|
||||
w.set_hpre5(config.ahb5_pre);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
|
||||
let hclk5 = sys_clk / config.ahb5_pre;
|
||||
|
||||
|
||||
#[cfg(all(stm32wba, peri_usb_otg_hs))]
|
||||
let usb_refck = match config.mux.otghssel {
|
||||
Otghssel::HSE => hse,
|
||||
@ -245,6 +285,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
hclk1: Some(hclk1),
|
||||
hclk2: Some(hclk2),
|
||||
hclk4: Some(hclk4),
|
||||
hclk5: Some(hclk5),
|
||||
pclk1: Some(pclk1),
|
||||
pclk2: Some(pclk2),
|
||||
pclk7: Some(pclk7),
|
||||
@ -294,8 +335,15 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale)
|
||||
PllSource::_RESERVED_1 => panic!("must not select RESERVED_1 source as DISABLE"),
|
||||
};
|
||||
|
||||
let hse_div = RCC.cr().read().hsepre();
|
||||
let src_freq = pre_src_freq / hse_div;
|
||||
// Only divide by the HSE prescaler when the PLL source is HSE
|
||||
let src_freq = match pll.source {
|
||||
PllSource::HSE => {
|
||||
// read the prescaler bits and divide
|
||||
let hsepre = RCC.cr().read().hsepre();
|
||||
pre_src_freq / hsepre
|
||||
}
|
||||
_ => pre_src_freq,
|
||||
};
|
||||
|
||||
// Calculate the reference clock, which is the source divided by m
|
||||
let ref_freq = src_freq / pll.prediv;
|
||||
@ -309,7 +357,11 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale)
|
||||
};
|
||||
|
||||
// Calculate the PLL VCO clock
|
||||
let vco_freq = ref_freq * pll.mul;
|
||||
// let vco_freq = ref_freq * pll.mul;
|
||||
// Calculate VCO frequency including fractional part: FVCO = Fref_ck × (N + FRAC/2^13)
|
||||
let numerator = (ref_freq.0 as u64) * (((pll.mul as u64) + 1 << 13) + pll.frac.unwrap_or(0) as u64);
|
||||
let vco_hz = (numerator >> 13) as u32;
|
||||
let vco_freq = Hertz(vco_hz);
|
||||
assert!(vco_freq >= vco_min && vco_freq <= vco_max);
|
||||
|
||||
// Calculate output clocks.
|
||||
@ -329,7 +381,7 @@ fn init_pll(config: Option<Pll>, input: &PllInput, voltage_range: VoltageScale)
|
||||
w.set_pllq(pll.divq.unwrap_or(PllDiv::DIV1));
|
||||
w.set_pllr(pll.divr.unwrap_or(PllDiv::DIV1));
|
||||
});
|
||||
RCC.pll1fracr().write(|w| {w.set_pllfracn(pll.frac.unwrap_or(1));});
|
||||
RCC.pll1fracr().write(|w| {w.set_pllfracn(pll.frac.unwrap_or(0));});
|
||||
|
||||
let input_range = match ref_freq.0 {
|
||||
..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
|
||||
|
@ -108,7 +108,12 @@ fn common_init<T: Instance>() {
|
||||
critical_section::with(|_| {
|
||||
crate::pac::PWR.svmcr().modify(|w| {
|
||||
w.set_usv(crate::pac::pwr::vals::Usv::B_0X1);
|
||||
// w.set_uvmen(true);
|
||||
});
|
||||
crate::pac::PWR.vosr().modify(|w| {
|
||||
w.set_vdd11usbdis(true);
|
||||
});
|
||||
crate::pac::PWR.vosr().modify(|w| {
|
||||
w.set_usbpwren(true);
|
||||
})
|
||||
});
|
||||
|
||||
@ -119,7 +124,6 @@ fn common_init<T: Instance>() {
|
||||
#[cfg(peri_usb_otg_hs)]
|
||||
{
|
||||
crate::pac::PWR.vosr().modify(|w| {
|
||||
w.set_usbpwren(true);
|
||||
w.set_usbboosten(true);
|
||||
});
|
||||
while !crate::pac::PWR.vosr().read().usbboostrdy() {}
|
||||
|
@ -330,9 +330,9 @@ impl<'d, T: Instance> Bus<'d, T> {
|
||||
#[cfg(all(stm32wba, peri_usb_otg_hs))]
|
||||
{
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.apb7enr().modify(|w| {
|
||||
w.set_syscfgen(true);
|
||||
});
|
||||
// crate::pac::RCC.apb7enr().modify(|w| {
|
||||
// w.set_syscfgen(true);
|
||||
// });
|
||||
crate::pac::RCC.ahb2enr().modify(|w| {
|
||||
w.set_usb_otg_hsen(true);
|
||||
w.set_usb_otg_hs_phyen(true);
|
||||
@ -366,8 +366,8 @@ impl<'d, T: Instance> Bus<'d, T> {
|
||||
// Configuring Vbus sense and SOF output
|
||||
match core_id {
|
||||
0x0000_1200 | 0x0000_1100 | 0x0000_1000 => self.inner.config_v1(),
|
||||
0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 | 0x0000_6100 => self.inner.config_v2v3(),
|
||||
0x0000_5000 => self.inner.config_v5(),
|
||||
0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
|
||||
0x0000_5000 | 0x0000_6100 => self.inner.config_v5(),
|
||||
_ => unimplemented!("Unknown USB core id {:X}", core_id),
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use defmt_rtt as _; // global logger
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::join::join;
|
||||
use embassy_stm32::rcc::{PllSource, PllPreDiv, PllMul, PllDiv};
|
||||
use embassy_stm32::rcc::{mux, AHBPrescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale};
|
||||
use embassy_stm32::rcc::{mux, AHBPrescaler, AHB5Prescaler, APBPrescaler, Hse, HsePrescaler, Sysclk, VoltageScale};
|
||||
use embassy_stm32::usb::{Driver, Instance};
|
||||
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
|
||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||
@ -25,26 +25,28 @@ async fn main(_spawner: Spawner) {
|
||||
let mut config = Config::default();
|
||||
|
||||
// External HSE (32 MHz) setup
|
||||
config.rcc.hse = Some(Hse {
|
||||
prescaler: HsePrescaler::DIV2,
|
||||
});
|
||||
// config.rcc.hse = Some(Hse {
|
||||
// prescaler: HsePrescaler::DIV2,
|
||||
// });
|
||||
|
||||
|
||||
// Fine-tune PLL1 dividers/multipliers
|
||||
config.rcc.pll1 = Some(embassy_stm32::rcc::Pll {
|
||||
source: PllSource::HSE,
|
||||
prediv: PllPreDiv::DIV2, // PLLM = 2 → HSE / 2 = 8 MHz
|
||||
mul: PllMul::MUL60, // PLLN = 60 → 8 MHz * 60 = 480 MHz VCO
|
||||
divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
|
||||
divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (USB)
|
||||
divp: Some(PllDiv::DIV15), // PLLP = 15 → 32 MHz (USBOTG)
|
||||
frac: Some(4096), // Fractional part (enabled)
|
||||
source: PllSource::HSI,
|
||||
prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz
|
||||
mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO
|
||||
divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
|
||||
// divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED)
|
||||
divq: None,
|
||||
divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG)
|
||||
frac: Some(0), // Fractional part (enabled)
|
||||
});
|
||||
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV1;
|
||||
config.rcc.apb1_pre = APBPrescaler::DIV1;
|
||||
config.rcc.apb2_pre = APBPrescaler::DIV1;
|
||||
config.rcc.apb7_pre = APBPrescaler::DIV1;
|
||||
config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
|
||||
|
||||
// voltage scale for max performance
|
||||
config.rcc.voltage_scale = VoltageScale::RANGE1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user