mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-30 13:50:37 +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;
|
use crate::pac::pwr::vals;
|
||||||
crate::pac::PWR.svmcr().modify(|w| {
|
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)]
|
#[cfg(stm32u5)]
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||||
use crate::pac::rcc::regs::Cfgr1;
|
use crate::pac::rcc::regs::Cfgr1;
|
||||||
|
use core::ops::Div;
|
||||||
pub use crate::pac::rcc::vals::{
|
pub use crate::pac::rcc::vals::{
|
||||||
Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk, Pllsrc as PllSource,
|
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::rcc::vals::Pllrge;
|
||||||
use crate::pac::{FLASH, RCC};
|
use crate::pac::{FLASH, RCC};
|
||||||
@ -20,6 +21,23 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
|||||||
// HSE speed
|
// HSE speed
|
||||||
pub const HSE_FREQ: Hertz = Hertz(32_000_000);
|
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)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub struct Hse {
|
pub struct Hse {
|
||||||
pub prescaler: HsePrescaler,
|
pub prescaler: HsePrescaler,
|
||||||
@ -71,6 +89,7 @@ pub struct Config {
|
|||||||
// sysclk, buses.
|
// sysclk, buses.
|
||||||
pub sys: Sysclk,
|
pub sys: Sysclk,
|
||||||
pub ahb_pre: AHBPrescaler,
|
pub ahb_pre: AHBPrescaler,
|
||||||
|
pub ahb5_pre: AHB5Prescaler,
|
||||||
pub apb1_pre: APBPrescaler,
|
pub apb1_pre: APBPrescaler,
|
||||||
pub apb2_pre: APBPrescaler,
|
pub apb2_pre: APBPrescaler,
|
||||||
pub apb7_pre: APBPrescaler,
|
pub apb7_pre: APBPrescaler,
|
||||||
@ -93,6 +112,7 @@ impl Config {
|
|||||||
pll1: None,
|
pll1: None,
|
||||||
sys: Sysclk::HSI,
|
sys: Sysclk::HSI,
|
||||||
ahb_pre: AHBPrescaler::DIV1,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
|
ahb5_pre: AHB5Prescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::DIV1,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::DIV1,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
apb7_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 hclk1 = sys_clk / config.ahb_pre;
|
||||||
let hclk2 = hclk1;
|
let hclk2 = hclk1;
|
||||||
let hclk4 = hclk1;
|
let hclk4 = hclk1;
|
||||||
// TODO: hclk5
|
|
||||||
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
|
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 (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
|
||||||
let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_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);
|
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))]
|
#[cfg(all(stm32wba, peri_usb_otg_hs))]
|
||||||
let usb_refck = match config.mux.otghssel {
|
let usb_refck = match config.mux.otghssel {
|
||||||
Otghssel::HSE => hse,
|
Otghssel::HSE => hse,
|
||||||
@ -245,6 +285,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
hclk1: Some(hclk1),
|
hclk1: Some(hclk1),
|
||||||
hclk2: Some(hclk2),
|
hclk2: Some(hclk2),
|
||||||
hclk4: Some(hclk4),
|
hclk4: Some(hclk4),
|
||||||
|
hclk5: Some(hclk5),
|
||||||
pclk1: Some(pclk1),
|
pclk1: Some(pclk1),
|
||||||
pclk2: Some(pclk2),
|
pclk2: Some(pclk2),
|
||||||
pclk7: Some(pclk7),
|
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"),
|
PllSource::_RESERVED_1 => panic!("must not select RESERVED_1 source as DISABLE"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let hse_div = RCC.cr().read().hsepre();
|
// Only divide by the HSE prescaler when the PLL source is HSE
|
||||||
let src_freq = pre_src_freq / hse_div;
|
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
|
// Calculate the reference clock, which is the source divided by m
|
||||||
let ref_freq = src_freq / pll.prediv;
|
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
|
// 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);
|
assert!(vco_freq >= vco_min && vco_freq <= vco_max);
|
||||||
|
|
||||||
// Calculate output clocks.
|
// 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_pllq(pll.divq.unwrap_or(PllDiv::DIV1));
|
||||||
w.set_pllr(pll.divr.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 {
|
let input_range = match ref_freq.0 {
|
||||||
..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
|
..=8_000_000 => Pllrge::FREQ_4TO8MHZ,
|
||||||
|
@ -108,7 +108,12 @@ fn common_init<T: Instance>() {
|
|||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
crate::pac::PWR.svmcr().modify(|w| {
|
crate::pac::PWR.svmcr().modify(|w| {
|
||||||
w.set_usv(crate::pac::pwr::vals::Usv::B_0X1);
|
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)]
|
#[cfg(peri_usb_otg_hs)]
|
||||||
{
|
{
|
||||||
crate::pac::PWR.vosr().modify(|w| {
|
crate::pac::PWR.vosr().modify(|w| {
|
||||||
w.set_usbpwren(true);
|
|
||||||
w.set_usbboosten(true);
|
w.set_usbboosten(true);
|
||||||
});
|
});
|
||||||
while !crate::pac::PWR.vosr().read().usbboostrdy() {}
|
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))]
|
#[cfg(all(stm32wba, peri_usb_otg_hs))]
|
||||||
{
|
{
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.apb7enr().modify(|w| {
|
// crate::pac::RCC.apb7enr().modify(|w| {
|
||||||
w.set_syscfgen(true);
|
// w.set_syscfgen(true);
|
||||||
});
|
// });
|
||||||
crate::pac::RCC.ahb2enr().modify(|w| {
|
crate::pac::RCC.ahb2enr().modify(|w| {
|
||||||
w.set_usb_otg_hsen(true);
|
w.set_usb_otg_hsen(true);
|
||||||
w.set_usb_otg_hs_phyen(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
|
// Configuring Vbus sense and SOF output
|
||||||
match core_id {
|
match core_id {
|
||||||
0x0000_1200 | 0x0000_1100 | 0x0000_1000 => self.inner.config_v1(),
|
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_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
|
||||||
0x0000_5000 => self.inner.config_v5(),
|
0x0000_5000 | 0x0000_6100 => self.inner.config_v5(),
|
||||||
_ => unimplemented!("Unknown USB core id {:X}", core_id),
|
_ => unimplemented!("Unknown USB core id {:X}", core_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use defmt_rtt as _; // global logger
|
|||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_stm32::rcc::{PllSource, PllPreDiv, PllMul, PllDiv};
|
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::usb::{Driver, Instance};
|
||||||
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
|
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
|
||||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||||
@ -25,26 +25,28 @@ async fn main(_spawner: Spawner) {
|
|||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
|
|
||||||
// External HSE (32 MHz) setup
|
// External HSE (32 MHz) setup
|
||||||
config.rcc.hse = Some(Hse {
|
// config.rcc.hse = Some(Hse {
|
||||||
prescaler: HsePrescaler::DIV2,
|
// prescaler: HsePrescaler::DIV2,
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
|
||||||
// Fine-tune PLL1 dividers/multipliers
|
// Fine-tune PLL1 dividers/multipliers
|
||||||
config.rcc.pll1 = Some(embassy_stm32::rcc::Pll {
|
config.rcc.pll1 = Some(embassy_stm32::rcc::Pll {
|
||||||
source: PllSource::HSE,
|
source: PllSource::HSI,
|
||||||
prediv: PllPreDiv::DIV2, // PLLM = 2 → HSE / 2 = 8 MHz
|
prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz
|
||||||
mul: PllMul::MUL60, // PLLN = 60 → 8 MHz * 60 = 480 MHz VCO
|
mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO
|
||||||
divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
|
divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk)
|
||||||
divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (USB)
|
// divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED)
|
||||||
divp: Some(PllDiv::DIV15), // PLLP = 15 → 32 MHz (USBOTG)
|
divq: None,
|
||||||
frac: Some(4096), // Fractional part (enabled)
|
divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG)
|
||||||
|
frac: Some(0), // Fractional part (enabled)
|
||||||
});
|
});
|
||||||
|
|
||||||
config.rcc.ahb_pre = AHBPrescaler::DIV1;
|
config.rcc.ahb_pre = AHBPrescaler::DIV1;
|
||||||
config.rcc.apb1_pre = APBPrescaler::DIV1;
|
config.rcc.apb1_pre = APBPrescaler::DIV1;
|
||||||
config.rcc.apb2_pre = APBPrescaler::DIV1;
|
config.rcc.apb2_pre = APBPrescaler::DIV1;
|
||||||
config.rcc.apb7_pre = APBPrescaler::DIV1;
|
config.rcc.apb7_pre = APBPrescaler::DIV1;
|
||||||
|
config.rcc.ahb5_pre = AHB5Prescaler::DIV4;
|
||||||
|
|
||||||
// voltage scale for max performance
|
// voltage scale for max performance
|
||||||
config.rcc.voltage_scale = VoltageScale::RANGE1;
|
config.rcc.voltage_scale = VoltageScale::RANGE1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user