stm32/rcc: add shared code for hsi48 with crs support.

This commit is contained in:
Dario Nieuwenhuis 2023-11-05 23:35:01 +01:00
parent c4a8b79dbc
commit 0272deb158
25 changed files with 136 additions and 161 deletions

View File

@ -58,7 +58,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73b8c37ae74fc28b247188c989fd99400611bd6b" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8381654ade324de3945c3c755d359686e957e99b" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -76,7 +76,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-73b8c37ae74fc28b247188c989fd99400611bd6b", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8381654ade324de3945c3c755d359686e957e99b", default-features = false, features = ["metadata"]}
[features]

View File

@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{
Pllr as PllR, Ppre as APBPrescaler,
};
use crate::pac::{PWR, RCC};
use crate::rcc::sealed::RccPeripheral;
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -67,23 +66,13 @@ pub struct Pll {
pub enum Clock48MhzSrc {
/// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
/// oscillator to comply with the USB specification for oscillator tolerance.
Hsi48(Option<CrsConfig>),
Hsi48(super::Hsi48Config),
/// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
/// PLL needs to be using the HSE source to comply with the USB specification for oscillator
/// tolerance.
PllQ,
}
/// Sets the sync source for the Clock Recovery System (CRS).
pub enum CrsSyncSource {
/// Use an external GPIO to sync the CRS.
Gpio,
/// Use the Low Speed External oscillator to sync the CRS.
Lse,
/// Use the USB SOF to sync the CRS.
Usb,
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
@ -102,12 +91,6 @@ pub struct Config {
pub ls: super::LsConfig,
}
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
pub struct CrsConfig {
/// Sync source for the CRS.
pub sync_src: CrsSyncSource,
}
impl Default for Config {
#[inline]
fn default() -> Config {
@ -118,7 +101,7 @@ impl Default for Config {
apb2_pre: APBPrescaler::DIV1,
low_power_run: false,
pll: None,
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(None)),
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
adc12_clock_source: Adcsel::DISABLE,
adc345_clock_source: Adcsel::DISABLE,
ls: Default::default(),
@ -288,33 +271,8 @@ pub(crate) unsafe fn init(config: Config) {
crate::pac::rcc::vals::Clk48sel::PLL1_Q
}
Clock48MhzSrc::Hsi48(crs_config) => {
// Enable HSI48
RCC.crrcr().modify(|w| w.set_hsi48on(true));
// Wait for HSI48 to turn on
while RCC.crrcr().read().hsi48rdy() == false {}
// Enable and setup CRS if needed
if let Some(crs_config) = crs_config {
crate::peripherals::CRS::enable_and_reset();
let sync_src = match crs_config.sync_src {
CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
};
crate::pac::CRS.cfgr().modify(|w| {
w.set_syncsrc(sync_src);
});
// These are the correct settings for standard USB operation. If other settings
// are needed there will need to be additional config options for the CRS.
crate::pac::CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
}
Clock48MhzSrc::Hsi48(config) => {
super::init_hsi48(config);
crate::pac::rcc::vals::Clk48sel::HSI48
}
};

View File

@ -21,9 +21,6 @@ pub const HSI_FREQ: Hertz = Hertz(64_000_000);
/// CSI speed
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
#[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
@ -126,7 +123,7 @@ pub struct Config {
pub hsi: Option<HSIPrescaler>,
pub hse: Option<Hse>,
pub csi: bool,
pub hsi48: bool,
pub hsi48: Option<super::Hsi48Config>,
pub sys: Sysclk,
pub pll1: Option<Pll>,
@ -155,7 +152,7 @@ impl Default for Config {
hsi: Some(HSIPrescaler::DIV1),
hse: None,
csi: false,
hsi48: false,
hsi48: Some(Default::default()),
sys: Sysclk::HSI,
pll1: None,
pll2: None,
@ -301,14 +298,7 @@ pub(crate) unsafe fn init(config: Config) {
};
// Configure HSI48.
RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
let _hsi48 = match config.hsi48 {
false => None,
true => {
while !RCC.cr().read().hsi48rdy() {}
Some(CSI_FREQ)
}
};
let _hsi48 = config.hsi48.map(super::init_hsi48);
// Configure CSI.
RCC.cr().modify(|w| w.set_csion(config.csi));

View File

@ -0,0 +1,62 @@
#![allow(unused)]
use crate::pac::crs::vals::Syncsrc;
use crate::pac::{CRS, RCC};
use crate::rcc::sealed::RccPeripheral;
use crate::time::Hertz;
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// Configuration for the HSI48 clock
#[derive(Clone, Copy, Debug)]
pub struct Hsi48Config {
/// Enable CRS Sync from USB Start Of Frame (SOF) events.
/// Required if HSI48 is going to be used as USB clock.
///
/// Other use cases of CRS are not supported yet.
pub sync_from_usb: bool,
}
impl Default for Hsi48Config {
fn default() -> Self {
Self { sync_from_usb: false }
}
}
pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
// Enable VREFINT reference for HSI48 oscillator
#[cfg(stm32l0)]
crate::pac::SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Enable HSI48
#[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba, stm32f0)))]
let r = RCC.crrcr();
#[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba))]
let r = RCC.cr();
#[cfg(any(stm32f0))]
let r = RCC.cr2();
r.modify(|w| w.set_hsi48on(true));
while r.read().hsi48rdy() == false {}
if config.sync_from_usb {
crate::peripherals::CRS::enable_and_reset();
CRS.cfgr().modify(|w| {
w.set_syncsrc(Syncsrc::USB);
});
// These are the correct settings for standard USB operation. If other settings
// are needed there will need to be additional config options for the CRS.
crate::pac::CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
}
HSI48_FREQ
}

View File

@ -3,8 +3,6 @@ pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Plldiv as PllDiv, Pllmul as PLLMul, Pllmul as PllMul,
Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc,
};
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -47,7 +45,7 @@ pub struct Config {
pub hsi: bool,
pub hse: Option<Hse>,
#[cfg(crs)]
pub hsi48: bool,
pub hsi48: Option<super::Hsi48Config>,
pub pll: Option<Pll>,
@ -68,7 +66,7 @@ impl Default for Config {
hse: None,
hsi: false,
#[cfg(crs)]
hsi48: false,
hsi48: Some(Default::default()),
pll: None,
@ -174,37 +172,11 @@ pub(crate) unsafe fn init(config: Config) {
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
#[cfg(crs)]
if config.hsi48 {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
let _hsi48 = config.hsi48.map(|config| {
// Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true));
// Enable dedicated USB clock
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
super::init_hsi48(config)
});
set_freqs(Clocks {
sys: sys_clk,

View File

@ -58,8 +58,8 @@ pub struct Config {
pub msi: Option<MSIRange>,
pub hsi: bool,
pub hse: Option<Hse>,
#[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))]
pub hsi48: bool,
#[cfg(crs)]
pub hsi48: Option<super::Hsi48Config>,
// pll
pub pll: Option<Pll>,
@ -108,8 +108,8 @@ impl Default for Config {
pllsai1: None,
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
pllsai2: None,
#[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))]
hsi48: true,
#[cfg(crs)]
hsi48: Some(Default::default()),
#[cfg(any(stm32l4, stm32l5, stm32wb))]
clk48_src: Clk48Src::HSI48,
ls: Default::default(),
@ -126,7 +126,8 @@ pub const WPAN_DEFAULT: Config = Config {
prescaler: HsePrescaler::DIV1,
}),
mux: ClockSrc::PLL1_R,
hsi48: true,
#[cfg(crs)]
hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
msi: None,
hsi: false,
clk48_src: Clk48Src::PLL1_Q,
@ -216,15 +217,10 @@ pub(crate) unsafe fn init(config: Config) {
hse.freq
});
#[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))]
let hsi48 = config.hsi48.then(|| {
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
Hertz(48_000_000)
});
#[cfg(any(stm32l47x, stm32l48x))]
let hsi48 = None;
#[cfg(crs)]
let _hsi48 = config.hsi48.map(super::init_hsi48);
#[cfg(not(crs))]
let _hsi48: Option<Hertz> = None;
let _plls = [
&config.pll,
@ -275,7 +271,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr1().modify(|w| w.set_clk48sel(config.clk48_src));
#[cfg(any(stm32l4, stm32l5, stm32wb))]
let _clk48 = match config.clk48_src {
Clk48Src::HSI48 => hsi48,
Clk48Src::HSI48 => _hsi48,
Clk48Src::MSI => msi,
Clk48Src::PLLSAI1_Q => pllsai1.q,
Clk48Src::PLL1_Q => pll.q,

View File

@ -9,6 +9,11 @@ mod mco;
pub use bd::*;
pub use mco::*;
#[cfg(crs)]
mod hsi48;
#[cfg(crs)]
pub use hsi48::*;
#[cfg_attr(rcc_f0, path = "f0.rs")]
#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
#[cfg_attr(rcc_f2, path = "f2.rs")]

View File

@ -115,7 +115,7 @@ pub struct Config {
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler,
pub hsi48: bool,
pub hsi48: Option<super::Hsi48Config>,
/// The voltage range influences the maximum clock frequencies for different parts of the
/// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
/// exceeding 55 MHz require at least `RANGE2`.
@ -189,7 +189,7 @@ impl Default for Config {
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1,
hsi48: true,
hsi48: Some(Default::default()),
voltage_range: VoltageScale::RANGE3,
ls: Default::default(),
}
@ -322,10 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
}
};
if config.hsi48 {
RCC.cr().modify(|w| w.set_hsi48on(true));
while !RCC.cr().read().hsi48rdy() {}
}
let _hsi48 = config.hsi48.map(super::init_hsi48);
// The clock source is ready
// Calculate and set the flash wait states

View File

@ -4,7 +4,7 @@
use defmt::{panic, *};
use embassy_executor::Spawner;
use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSrc};
use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{self, Driver, Instance};
use embassy_stm32::{bind_interrupts, peripherals, Config};
@ -41,9 +41,7 @@ async fn main(_spawner: Spawner) {
if USE_HSI48 {
// Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
sync_src: CrsSyncSource::Usb,
})));
config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true }));
} else {
config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
}

View File

@ -37,7 +37,7 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
async fn main(spawner: Spawner) -> ! {
let mut config = Config::default();
config.rcc.hsi = None;
config.rcc.hsi48 = true; // needed for rng
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::BypassDigital,

View File

@ -4,9 +4,6 @@
use defmt::{panic, *};
use embassy_executor::Spawner;
use embassy_stm32::rcc::{
AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale,
};
use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{Driver, Instance};
use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
@ -23,8 +20,10 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.hsi = None;
config.rcc.hsi48 = true; // needed for usb
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::BypassDigital,
@ -43,6 +42,7 @@ async fn main(_spawner: Spawner) {
config.rcc.apb3_pre = APBPrescaler::DIV4;
config.rcc.sys = Sysclk::PLL1_P;
config.rcc.voltage_scale = VoltageScale::Scale0;
}
let p = embassy_stm32::init(config);
info!("Hello World!");

View File

@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! {
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,

View File

@ -37,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,

View File

@ -19,7 +19,6 @@ async fn main(_spawner: Spawner) {
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,

View File

@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.rcc.hsi48 = true; // needed for RNG.
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
let p = embassy_stm32::init(config);
info!("Hello World!");

View File

@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) {
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for USB
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,

View File

@ -11,8 +11,7 @@ use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.rcc.hsi48 = true;
let config = Config::default();
let p = embassy_stm32::init(config);
let button = Input::new(p.PB2, Pull::Up);

View File

@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default();

View File

@ -33,8 +33,8 @@ const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set th
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default();

View File

@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default();

View File

@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default();

View File

@ -90,7 +90,7 @@ async fn main(spawner: Spawner) {
divq: None,
divr: Some(PllRDiv::DIV2), // sysclk 80Mhz clock (8 / 1 * 20 / 2)
});
config.rcc.hsi48 = true; // needed for rng
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
}
let dp = embassy_stm32::init(config);

View File

@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
info!("Hello World!");
let mut config = Config::default();
config.rcc.hsi48 = true;
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
config.rcc.mux = ClockSrc::PLL1_R;
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {

View File

@ -29,8 +29,7 @@ async fn main(_spawner: Spawner) {
n: Plln::MUL10,
r: Plldiv::DIV1,
});
//config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz);
config.rcc.hsi48 = true;
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
let p = embassy_stm32::init(config);

View File

@ -306,7 +306,7 @@ pub fn config() -> Config {
{
use embassy_stm32::rcc::*;
config.rcc.hsi = None;
config.rcc.hsi48 = true; // needed for rng
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::BypassDigital,
@ -332,7 +332,7 @@ pub fn config() -> Config {
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,
@ -364,7 +364,7 @@ pub fn config() -> Config {
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,