stm32: use PAC enums for VOS.

This commit is contained in:
Dario Nieuwenhuis 2023-09-18 03:00:59 +02:00
parent 0da793e5de
commit 4bfbcd6c72
11 changed files with 156 additions and 106 deletions

2
ci.sh
View file

@ -85,6 +85,8 @@ cargo batch \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \

View file

@ -67,24 +67,20 @@ where
self.board_type = board_type;
}
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
let pwr = pac::PWR;
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
pac::PWR.subghzspicr().modify(|w| w.set_nss(false));
Ok(())
}
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
let pwr = pac::PWR;
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
pac::PWR.subghzspicr().modify(|w| w.set_nss(true));
Ok(())
}
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
let rcc = pac::RCC;
rcc.csr().modify(|w| w.set_rfrst(true));
rcc.csr().modify(|w| w.set_rfrst(false));
pac::RCC.csr().modify(|w| w.set_rfrst(true));
pac::RCC.csr().modify(|w| w.set_rfrst(false));
Ok(())
}
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
let pwr = pac::PWR;
while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
while pac::PWR.sr2().read().rfbusys() {}
Ok(())
}

View file

@ -59,7 +59,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
atomic-polyfill = "1.0.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-907dd82c848bc912252c61509944e85c2a48c919" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-907dd82c848bc912252c61509944e85c2a48c919", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2dba1f1ddee697e616aff2a4db57a6ffaf1b29b7", default-features = false, features = ["metadata"]}
[features]
default = ["rt"]

View file

@ -5,22 +5,6 @@ use crate::pac::rcc;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
use crate::time::Hertz;
/// Voltage Scale
///
/// Represents the voltage range feeding the CPU core. The maximum core
/// clock frequency depends on this value.
///
/// Scale0 represents the highest voltage range
#[derive(Copy, Clone, PartialEq)]
pub enum VoltageScale {
Scale0,
Scale1,
#[cfg(not(any(rcc_wl5, rcc_wle)))]
Scale2,
#[cfg(not(any(rcc_wl5, rcc_wle)))]
Scale3,
}
impl Div<AHBPrescaler> for Hertz {
type Output = Hertz;

View file

@ -203,7 +203,20 @@ pub struct PLLClocks {
pub pll48_freq: Hertz,
}
pub use super::bus::VoltageScale;
/// Voltage range of the power supply used.
///
/// Used to calculate flash waitstates. See
/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
pub enum VoltageScale {
/// 2.7v to 4.6v
Range0,
/// 2.4v to 2.7v
Range1,
/// 2.1v to 2.4v
Range2,
/// 1.8v to 2.1v
Range3,
}
impl VoltageScale {
const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
@ -211,7 +224,7 @@ impl VoltageScale {
// Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
// frequency
match self {
VoltageScale::Scale3 => {
VoltageScale::Range3 => {
if ahb_freq <= 16_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 32_000_000 {
@ -232,7 +245,7 @@ impl VoltageScale {
None
}
}
VoltageScale::Scale2 => {
VoltageScale::Range2 => {
if ahb_freq <= 18_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 36_000_000 {
@ -251,7 +264,7 @@ impl VoltageScale {
None
}
}
VoltageScale::Scale1 => {
VoltageScale::Range1 => {
if ahb_freq <= 24_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 48_000_000 {
@ -266,7 +279,7 @@ impl VoltageScale {
None
}
}
VoltageScale::Scale0 => {
VoltageScale::Range0 => {
if ahb_freq <= 30_000_000 {
Some(Latency::WS0)
} else if ahb_freq <= 60_000_000 {
@ -307,7 +320,7 @@ impl Default for Config {
hsi: true,
pll_mux: PLLSrc::HSI,
pll: PLLConfig::default(),
voltage: VoltageScale::Scale3,
voltage: VoltageScale::Range3,
mux: ClockSrc::HSI,
rtc: None,
lsi: false,

View file

@ -2,7 +2,6 @@ use core::marker::PhantomData;
use stm32_metapac::rcc::vals::Timpre;
use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
@ -26,7 +25,8 @@ const VCO_MAX: u32 = 420_000_000;
const VCO_WIDE_MIN: u32 = 128_000_000;
const VCO_WIDE_MAX: u32 = 560_000_000;
pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale};
pub use super::bus::{AHBPrescaler, APBPrescaler};
pub use crate::pac::pwr::vals::Vos as VoltageScale;
pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0)
@ -171,7 +171,7 @@ impl Default for Config {
apb3_pre: APBPrescaler::DIV1,
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale3,
voltage_scale: VoltageScale::SCALE3,
}
}
}
@ -222,15 +222,15 @@ impl<'d, T: McoInstance> Mco<'d, T> {
}
pub(crate) unsafe fn init(config: Config) {
let (vos, max_clk) = match config.voltage_scale {
VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)),
VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)),
VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)),
VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)),
let max_clk = match config.voltage_scale {
VoltageScale::SCALE0 => Hertz(250_000_000),
VoltageScale::SCALE1 => Hertz(200_000_000),
VoltageScale::SCALE2 => Hertz(150_000_000),
VoltageScale::SCALE3 => Hertz(100_000_000),
};
// Configure voltage scale.
PWR.voscr().modify(|w| w.set_vos(vos));
PWR.voscr().modify(|w| w.set_vos(config.voltage_scale));
while !PWR.vossr().read().vosrdy() {}
// Configure HSI
@ -472,36 +472,36 @@ fn flash_setup(clk: Hertz, vos: VoltageScale) {
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
// states and programming delay
let (latency, wrhighfreq) = match (vos, clk.0) {
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
(VoltageScale::Scale0, ..=250_000_000) => (5, 2),
(VoltageScale::SCALE0, ..=42_000_000) => (0, 0),
(VoltageScale::SCALE0, ..=84_000_000) => (1, 0),
(VoltageScale::SCALE0, ..=126_000_000) => (2, 1),
(VoltageScale::SCALE0, ..=168_000_000) => (3, 1),
(VoltageScale::SCALE0, ..=210_000_000) => (4, 2),
(VoltageScale::SCALE0, ..=250_000_000) => (5, 2),
(VoltageScale::Scale1, ..=34_000_000) => (0, 0),
(VoltageScale::Scale1, ..=68_000_000) => (1, 0),
(VoltageScale::Scale1, ..=102_000_000) => (2, 1),
(VoltageScale::Scale1, ..=136_000_000) => (3, 1),
(VoltageScale::Scale1, ..=170_000_000) => (4, 2),
(VoltageScale::Scale1, ..=200_000_000) => (5, 2),
(VoltageScale::SCALE1, ..=34_000_000) => (0, 0),
(VoltageScale::SCALE1, ..=68_000_000) => (1, 0),
(VoltageScale::SCALE1, ..=102_000_000) => (2, 1),
(VoltageScale::SCALE1, ..=136_000_000) => (3, 1),
(VoltageScale::SCALE1, ..=170_000_000) => (4, 2),
(VoltageScale::SCALE1, ..=200_000_000) => (5, 2),
(VoltageScale::Scale2, ..=30_000_000) => (0, 0),
(VoltageScale::Scale2, ..=60_000_000) => (1, 0),
(VoltageScale::Scale2, ..=90_000_000) => (2, 1),
(VoltageScale::Scale2, ..=120_000_000) => (3, 1),
(VoltageScale::Scale2, ..=150_000_000) => (4, 2),
(VoltageScale::SCALE2, ..=30_000_000) => (0, 0),
(VoltageScale::SCALE2, ..=60_000_000) => (1, 0),
(VoltageScale::SCALE2, ..=90_000_000) => (2, 1),
(VoltageScale::SCALE2, ..=120_000_000) => (3, 1),
(VoltageScale::SCALE2, ..=150_000_000) => (4, 2),
(VoltageScale::Scale3, ..=20_000_000) => (0, 0),
(VoltageScale::Scale3, ..=40_000_000) => (1, 0),
(VoltageScale::Scale3, ..=60_000_000) => (2, 1),
(VoltageScale::Scale3, ..=80_000_000) => (3, 1),
(VoltageScale::Scale3, ..=100_000_000) => (4, 2),
(VoltageScale::SCALE3, ..=20_000_000) => (0, 0),
(VoltageScale::SCALE3, ..=40_000_000) => (1, 0),
(VoltageScale::SCALE3, ..=60_000_000) => (2, 1),
(VoltageScale::SCALE3, ..=80_000_000) => (3, 1),
(VoltageScale::SCALE3, ..=100_000_000) => (4, 2),
_ => unreachable!(),
};
defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
FLASH.acr().write(|w| {
w.set_wrhighfreq(wrhighfreq);

View file

@ -1,9 +1,10 @@
use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
pub use pll::PllConfig;
use stm32_metapac::pwr::vals::Vos;
use stm32_metapac::rcc::vals::{Mco1, Mco2};
pub use self::pll::PllConfig;
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Adcsel, Ckpersel, Hpre, Hsidiv, Pllsrc, Ppre, Sw, Timpre};
@ -24,7 +25,13 @@ pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
pub use super::bus::VoltageScale;
#[derive(Clone, Copy)]
pub enum VoltageScale {
Scale0,
Scale1,
Scale2,
Scale3,
}
#[derive(Clone, Copy)]
pub enum AdcClockSource {
@ -85,7 +92,6 @@ pub struct CoreClocks {
/// Configuration of the core clocks
#[non_exhaustive]
#[derive(Default)]
pub struct Config {
pub hse: Option<Hertz>,
pub bypass_hse: bool,
@ -100,6 +106,28 @@ pub struct Config {
pub pll2: PllConfig,
pub pll3: PllConfig,
pub adc_clock_source: AdcClockSource,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
fn default() -> Self {
Self {
hse: None,
bypass_hse: false,
sys_ck: None,
per_ck: None,
hclk: None,
pclk1: None,
pclk2: None,
pclk3: None,
pclk4: None,
pll1: Default::default(),
pll2: Default::default(),
pll3: Default::default(),
adc_clock_source: Default::default(),
voltage_scale: VoltageScale::Scale1,
}
}
}
/// Setup traceclk
@ -431,9 +459,6 @@ impl<'d, T: McoInstance> Mco<'d, T> {
}
pub(crate) unsafe fn init(mut config: Config) {
// TODO make configurable?
let enable_overdrive = false;
// NB. The lower bytes of CR3 can only be written once after
// POR, and must be written with a valid combination. Refer to
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
@ -461,21 +486,49 @@ pub(crate) unsafe fn init(mut config: Config) {
// 1.0V.
while !PWR.csr1().read().actvosrdy() {}
// Go to Scale 1
PWR.d3cr().modify(|w| w.set_vos(0b11));
while !PWR.d3cr().read().vosrdy() {}
let pwr_vos = if !enable_overdrive {
VoltageScale::Scale1
} else {
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
SYSCFG.pwrcr().modify(|w| w.set_oden(1));
#[cfg(syscfg_h7)]
{
// in chips without the overdrive bit, we can go from any scale to any scale directly.
PWR.d3cr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => Vos::SCALE0,
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.d3cr().read().vosrdy() {}
VoltageScale::Scale0
};
}
#[cfg(syscfg_h7od)]
{
match config.voltage_scale {
VoltageScale::Scale0 => {
// to go to scale0, we must go to Scale1 first...
PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
while !PWR.d3cr().read().vosrdy() {}
// Then enable overdrive.
critical_section::with(|_| {
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
SYSCFG.pwrcr().modify(|w| w.set_oden(1));
});
while !PWR.d3cr().read().vosrdy() {}
}
_ => {
// for all other scales, we can go directly.
PWR.d3cr().modify(|w| {
w.set_vos(match config.voltage_scale {
VoltageScale::Scale0 => unreachable!(),
VoltageScale::Scale1 => Vos::SCALE1,
VoltageScale::Scale2 => Vos::SCALE2,
VoltageScale::Scale3 => Vos::SCALE3,
})
});
while !PWR.d3cr().read().vosrdy() {}
}
}
}
// Freeze the core clocks, returning a Core Clocks Distribution
// and Reset (CCDR) structure. The actual frequency of the clocks
@ -538,11 +591,11 @@ pub(crate) unsafe fn init(mut config: Config) {
// Refer to part datasheet "General operating conditions"
// table for (rev V). We do not assert checks for earlier
// revisions which may have lower limits.
let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
_ => (200_000_000, 100_000_000, 50_000_000),
VoltageScale::Scale3 => (200_000_000, 100_000_000, 50_000_000),
};
assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
@ -638,7 +691,7 @@ pub(crate) unsafe fn init(mut config: Config) {
// core voltage
while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
flash_setup(rcc_aclk, pwr_vos);
flash_setup(rcc_aclk, config.voltage_scale);
// APB1 / APB2 Prescaler
RCC.d2cfgr().modify(|w| {

View file

@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
pub use super::bus::VoltageScale;
pub use crate::pac::pwr::vals::Vos as VoltageScale;
#[derive(Copy, Clone)]
pub enum ClockSrc {
@ -286,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) {
}
// TODO make configurable
let power_vos = VoltageScale::Scale3;
let power_vos = VoltageScale::RANGE3;
// states and programming delay
let wait_states = match power_vos {
// VOS 0 range VCORE 1.26V - 1.40V
VoltageScale::Scale0 => {
// VOS 1 range VCORE 1.26V - 1.40V
VoltageScale::RANGE1 => {
if sys_clk < 32_000_000 {
0
} else if sys_clk < 64_000_000 {
@ -304,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) {
4
}
}
// VOS 1 range VCORE 1.15V - 1.26V
VoltageScale::Scale1 => {
// VOS 2 range VCORE 1.15V - 1.26V
VoltageScale::RANGE2 => {
if sys_clk < 30_000_000 {
0
} else if sys_clk < 60_000_000 {
@ -316,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) {
3
}
}
// VOS 2 range VCORE 1.05V - 1.15V
VoltageScale::Scale2 => {
// VOS 3 range VCORE 1.05V - 1.15V
VoltageScale::RANGE3 => {
if sys_clk < 24_000_000 {
0
} else if sys_clk < 48_000_000 {
@ -326,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) {
2
}
}
// VOS 3 range VCORE 0.95V - 1.05V
VoltageScale::Scale3 => {
// VOS 4 range VCORE 0.95V - 1.05V
VoltageScale::RANGE4 => {
if sys_clk < 12_000_000 {
0
} else {

View file

@ -1,4 +1,5 @@
pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale};
pub use super::bus::{AHBPrescaler, APBPrescaler};
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::Adcsel;
use crate::pac::{FLASH, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
@ -75,9 +76,9 @@ impl MSIRange {
fn vos(&self) -> VoltageScale {
if self > &MSIRange::Range8 {
VoltageScale::Scale0
VoltageScale::RANGE1
} else {
VoltageScale::Scale1
VoltageScale::RANGE2
}
}
}
@ -170,8 +171,8 @@ pub enum Lsedrv {
pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw, vos) = match config.mux {
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1),
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0),
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2),
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1),
ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
};
@ -216,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) {
// Adjust flash latency
let flash_clk_src_freq: u32 = shd_ahb_freq;
let ws = match vos {
VoltageScale::Scale0 => match flash_clk_src_freq {
VoltageScale::RANGE1 => match flash_clk_src_freq {
0..=18_000_000 => 0b000,
18_000_001..=36_000_000 => 0b001,
_ => 0b010,
},
VoltageScale::Scale1 => match flash_clk_src_freq {
VoltageScale::RANGE2 => match flash_clk_src_freq {
0..=6_000_000 => 0b000,
6_000_001..=12_000_000 => 0b001,
_ => 0b010,
},
_ => unreachable!(),
};
FLASH.acr().modify(|w| {

View file

@ -53,7 +53,7 @@ async fn main(spawner: Spawner) -> ! {
config.rcc.apb2_pre = APBPrescaler::DIV1;
config.rcc.apb3_pre = APBPrescaler::DIV1;
config.rcc.sys = Sysclk::Pll1P;
config.rcc.voltage_scale = VoltageScale::Scale0;
config.rcc.voltage_scale = VoltageScale::SCALE0;
let p = embassy_stm32::init(config);
info!("Hello World!");

View file

@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
config.rcc.apb2_pre = APBPrescaler::DIV2;
config.rcc.apb3_pre = APBPrescaler::DIV4;
config.rcc.sys = Sysclk::Pll1P;
config.rcc.voltage_scale = VoltageScale::Scale0;
config.rcc.voltage_scale = VoltageScale::SCALE0;
let p = embassy_stm32::init(config);
info!("Hello World!");