Merge pull request #241 from lulf/get-clock-frequencies

Provide a way for a peripheral to query its clock frequency
This commit is contained in:
Dario Nieuwenhuis 2021-06-14 16:22:14 +02:00 committed by GitHub
commit 0dafd8f763
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 805 additions and 172 deletions

View file

@ -17,9 +17,7 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream
); );
let clock = unsafe { make_static(&mut c) }; let clock = unsafe { make_static(&mut c) };
// TODO: Is TIM2 always APB1? clock.start();
let timer_freq = unsafe { #embassy_stm32_path::rcc::get_freqs().apb1_clk };
clock.start(timer_freq);
let mut alarm = clock.alarm1(); let mut alarm = clock.alarm1();
unsafe { #embassy_path::time::set_clock(clock) }; unsafe { #embassy_path::time::set_clock(clock) };

View file

@ -77,12 +77,14 @@ impl<T: Instance> Clock<T> {
} }
} }
pub fn start(&'static self, timer_freq: Hertz) { pub fn start(&'static self) {
let inner = T::inner(); let inner = T::inner();
T::enable(); T::enable();
T::reset(); T::reset();
let timer_freq = T::frequency();
// NOTE(unsafe) Critical section to use the unsafe methods // NOTE(unsafe) Critical section to use the unsafe methods
critical_section::with(|_| { critical_section::with(|_| {
unsafe { unsafe {

View file

@ -0,0 +1,205 @@
pub use super::types::*;
use crate::pac;
use crate::peripherals::{self, RCC};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz;
use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_extras::unborrow;
use pac::rcc::vals::{Hpre, Ppre, Sw};
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed
pub const HSI_FREQ: u32 = 16_000_000;
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSI16,
}
impl Into<Ppre> for APBPrescaler {
fn into(self) -> Ppre {
match self {
APBPrescaler::NotDivided => Ppre::DIV1,
APBPrescaler::Div2 => Ppre::DIV2,
APBPrescaler::Div4 => Ppre::DIV4,
APBPrescaler::Div8 => Ppre::DIV8,
APBPrescaler::Div16 => Ppre::DIV16,
}
}
}
impl Into<Hpre> for AHBPrescaler {
fn into(self) -> Hpre {
match self {
AHBPrescaler::NotDivided => Hpre::DIV1,
AHBPrescaler::Div2 => Hpre::DIV2,
AHBPrescaler::Div4 => Hpre::DIV4,
AHBPrescaler::Div8 => Hpre::DIV8,
AHBPrescaler::Div16 => Hpre::DIV16,
AHBPrescaler::Div64 => Hpre::DIV64,
AHBPrescaler::Div128 => Hpre::DIV128,
AHBPrescaler::Div256 => Hpre::DIV256,
AHBPrescaler::Div512 => Hpre::DIV512,
}
}
}
/// Clocks configutation
pub struct Config {
mux: ClockSrc,
ahb_pre: AHBPrescaler,
apb1_pre: APBPrescaler,
apb2_pre: APBPrescaler,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
}
impl Config {
#[inline]
pub fn clock_src(mut self, mux: ClockSrc) -> Self {
self.mux = mux;
self
}
#[inline]
pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self {
self.ahb_pre = pre;
self
}
#[inline]
pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self {
self.apb1_pre = pre;
self
}
#[inline]
pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self {
self.apb2_pre = pre;
self
}
}
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, Sw::HSE)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.0 as u32 - 7);
sys_clk / pre
}
};
let apb1_freq = match cfgr.apb1_pre {
APBPrescaler::NotDivided => ahb_freq,
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32;
freq
}
};
let apb2_freq = match cfgr.apb2_pre {
APBPrescaler::NotDivided => ahb_freq,
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
freq
}
};
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
}
}
}
pub unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal();
let clocks = r.freeze(config);
set_freqs(clocks);
}

View file

@ -6,6 +6,7 @@ use crate::pac::rcc::vals::Timpre;
use crate::pac::{DBGMCU, RCC, SYSCFG}; use crate::pac::{DBGMCU, RCC, SYSCFG};
use crate::peripherals; use crate::peripherals;
use crate::pwr::{Power, VoltageScale}; use crate::pwr::{Power, VoltageScale};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
mod pll; mod pll;
@ -522,5 +523,17 @@ impl<'d> Rcc<'d> {
} }
} }
// TODO pub unsafe fn init(config: Config) {
pub unsafe fn init(_config: Config) {} let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
let core_clocks = rcc.freeze(&mut power);
set_freqs(Clocks {
sys: core_clocks.c_ck,
ahb1: core_clocks.hclk,
ahb2: core_clocks.hclk,
ahb3: core_clocks.hclk,
apb1: core_clocks.pclk1,
apb2: core_clocks.pclk2,
apb4: core_clocks.pclk4,
});
}

View file

@ -1,3 +1,4 @@
pub use super::types::*;
use crate::pac; use crate::pac;
use crate::peripherals::{self, CRS, RCC, SYSCFG}; use crate::peripherals::{self, CRS, RCC, SYSCFG};
use crate::rcc::{get_freqs, set_freqs, Clocks}; use crate::rcc::{get_freqs, set_freqs, Clocks};
@ -12,6 +13,9 @@ use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock. /// and with the addition of the init function to configure a system clock.
/// HSI speed
pub const HSI_FREQ: u32 = 16_000_000;
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -21,90 +25,6 @@ pub enum ClockSrc {
HSI16, HSI16,
} }
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// AHB prescaler
#[derive(Clone, Copy)]
pub enum AHBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div64,
Div128,
Div256,
Div512,
}
/// APB prescaler
#[derive(Clone, Copy)]
pub enum APBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI16,
HSE(Hertz),
}
/// HSI speed
pub const HSI_FREQ: u32 = 16_000_000;
impl Into<Pllmul> for PLLMul { impl Into<Pllmul> for PLLMul {
fn into(self) -> Pllmul { fn into(self) -> Pllmul {
match self { match self {
@ -248,18 +168,6 @@ impl<'d> Rcc<'d> {
unsafe { get_freqs() } unsafe { get_freqs() }
} }
/*
pub fn enable_lse(&mut self, _: &PWR) -> LSE {
self.rb.csr.modify(|_, w| {
// Enable LSE clock
w.lseon().set_bit()
});
while self.rb.csr.read().lserdy().bit_is_clear() {}
LSE(())
}
}
*/
pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) {
// NOTE(unsafe) We have exclusive access to the RCC and DBGMCU // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU
unsafe { unsafe {
@ -319,30 +227,6 @@ impl<'d> Rcc<'d> {
HSI48(()) HSI48(())
} }
} }
/*
impl Rcc {
/// Configure MCO (Microcontroller Clock Output).
pub fn configure_mco<P>(
&mut self,
source: MCOSEL_A,
prescaler: MCOPRE_A,
output_pin: P,
) -> MCOEnabled
where
P: mco::Pin,
{
output_pin.into_mco();
self.rb.cfgr.modify(|_, w| {
w.mcosel().variant(source);
w.mcopre().variant(prescaler)
});
MCOEnabled(())
}
}
*/
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration /// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt { pub trait RccExt {
@ -469,35 +353,31 @@ impl RccExt for RCC {
} }
}; };
let (apb1_freq, apb1_tim_freq, apb1_pre) = match cfgr.apb1_pre { let apb1_freq = match cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), APBPrescaler::NotDivided => ahb_freq,
pre => { pre => {
let pre: Ppre = pre.into(); let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3); let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32; let freq = ahb_freq / pre as u32;
(freq, freq * 2, pre as u8) freq
} }
}; };
let (apb2_freq, apb2_tim_freq, apb2_pre) = match cfgr.apb2_pre { let apb2_freq = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), APBPrescaler::NotDivided => ahb_freq,
pre => { pre => {
let pre: Ppre = pre.into(); let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3); let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3)); let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2, pre as u8) freq
} }
}; };
Clocks { Clocks {
sys_clk: sys_clk.hz(), sys: sys_clk.hz(),
ahb_clk: ahb_freq.hz(), ahb: ahb_freq.hz(),
apb1_clk: apb1_freq.hz(), apb1: apb1_freq.hz(),
apb2_clk: apb2_freq.hz(), apb2: apb2_freq.hz(),
apb1_tim_clk: apb1_tim_freq.hz(),
apb2_tim_clk: apb2_tim_freq.hz(),
apb1_pre,
apb2_pre,
} }
} }
} }
@ -508,18 +388,6 @@ impl RccExt for RCC {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct HSI48(()); pub struct HSI48(());
/// Token that exists only if MCO (Microcontroller Clock Out) has been enabled.
///
/// You can get an instance of this struct by calling [`Rcc::configure_mco`].
#[derive(Clone, Copy)]
pub struct MCOEnabled(());
/// Token that exists only, if the LSE clock has been enabled
///
/// You can get an instance of this struct by calling [`Rcc::enable_lse`].
#[derive(Clone, Copy)]
pub struct LSE(());
pub unsafe fn init(config: Config) { pub unsafe fn init(config: Config) {
let rcc = pac::RCC; let rcc = pac::RCC;
rcc.iopenr().write(|w| { rcc.iopenr().write(|w| {

View file

@ -0,0 +1,204 @@
pub use super::types::*;
use crate::pac;
use crate::peripherals::{self, RCC};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz;
use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_extras::unborrow;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed
pub const HSI_FREQ: u32 = 16_000_000;
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSI16,
}
impl Into<u8> for APBPrescaler {
fn into(self) -> u8 {
match self {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 0x04,
APBPrescaler::Div4 => 0x05,
APBPrescaler::Div8 => 0x06,
APBPrescaler::Div16 => 0x07,
}
}
}
impl Into<u8> for AHBPrescaler {
fn into(self) -> u8 {
match self {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 0x08,
AHBPrescaler::Div4 => 0x09,
AHBPrescaler::Div8 => 0x0a,
AHBPrescaler::Div16 => 0x0b,
AHBPrescaler::Div64 => 0x0c,
AHBPrescaler::Div128 => 0x0d,
AHBPrescaler::Div256 => 0x0e,
AHBPrescaler::Div512 => 0x0f,
}
}
}
/// Clocks configutation
pub struct Config {
mux: ClockSrc,
ahb_pre: AHBPrescaler,
apb1_pre: APBPrescaler,
apb2_pre: APBPrescaler,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
}
impl Config {
#[inline]
pub fn clock_src(mut self, mux: ClockSrc) -> Self {
self.mux = mux;
self
}
#[inline]
pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self {
self.ahb_pre = pre;
self
}
#[inline]
pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self {
self.apb1_pre = pre;
self
}
#[inline]
pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self {
self.apb2_pre = pre;
self
}
}
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0x02)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let apb1_freq = match cfgr.apb1_pre {
APBPrescaler::NotDivided => ahb_freq,
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
freq
}
};
let apb2_freq = match cfgr.apb2_pre {
APBPrescaler::NotDivided => ahb_freq,
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
freq
}
};
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
}
}
}
pub unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal();
let clocks = r.freeze(config);
set_freqs(clocks);
}

View file

@ -3,22 +3,33 @@
use crate::peripherals; use crate::peripherals;
use crate::time::Hertz; use crate::time::Hertz;
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
mod types;
#[derive(Clone, Copy)]
pub struct Clocks {
pub sys: Hertz,
pub apb1: Hertz,
pub apb2: Hertz,
#[cfg(any(rcc_l0))]
pub ahb: Hertz,
#[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55))]
pub ahb1: Hertz,
#[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55))]
pub ahb2: Hertz,
#[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55))]
pub ahb3: Hertz,
#[cfg(any(rcc_h7))]
pub apb4: Hertz,
}
/// Frozen clock frequencies /// Frozen clock frequencies
/// ///
/// The existence of this value indicates that the clock configuration can no longer be changed /// The existence of this value indicates that the clock configuration can no longer be changed
#[derive(Clone, Copy)]
pub struct Clocks {
pub sys_clk: Hertz,
pub ahb_clk: Hertz,
pub apb1_clk: Hertz,
pub apb1_tim_clk: Hertz,
pub apb2_clk: Hertz,
pub apb2_tim_clk: Hertz,
pub apb1_pre: u8,
pub apb2_pre: u8,
}
static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
/// Sets the clock frequencies /// Sets the clock frequencies
@ -40,6 +51,15 @@ cfg_if::cfg_if! {
} else if #[cfg(rcc_l0)] { } else if #[cfg(rcc_l0)] {
mod l0; mod l0;
pub use l0::*; pub use l0::*;
} else if #[cfg(rcc_l4)] {
mod l4;
pub use l4::*;
} else if #[cfg(rcc_f4)] {
mod f4;
pub use f4::*;
} else if #[cfg(rcc_wb55)] {
mod wb55;
pub use wb55::*;
} else { } else {
#[derive(Default)] #[derive(Default)]
pub struct Config {} pub struct Config {}
@ -50,6 +70,7 @@ cfg_if::cfg_if! {
pub(crate) mod sealed { pub(crate) mod sealed {
pub trait RccPeripheral { pub trait RccPeripheral {
fn frequency() -> crate::time::Hertz;
fn reset(); fn reset();
fn enable(); fn enable();
fn disable(); fn disable();
@ -59,8 +80,16 @@ pub(crate) mod sealed {
pub trait RccPeripheral: sealed::RccPeripheral + 'static {} pub trait RccPeripheral: sealed::RccPeripheral + 'static {}
crate::pac::peripheral_rcc!( crate::pac::peripheral_rcc!(
($inst:ident, $enable:ident, $reset:ident, $perien:ident, $perirst:ident) => { ($inst:ident, $clk:ident, $enable:ident, $reset:ident, $perien:ident, $perirst:ident) => {
impl sealed::RccPeripheral for peripherals::$inst { impl sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
unsafe {
let freqs = get_freqs();
freqs.$clk
}
})
}
fn enable() { fn enable() {
critical_section::with(|_| { critical_section::with(|_| {
unsafe { unsafe {

View file

@ -0,0 +1,94 @@
#![allow(dead_code)]
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
use crate::time::Hertz;
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16,
}
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// AHB prescaler
#[derive(Clone, Copy)]
pub enum AHBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div64,
Div128,
Div256,
Div512,
}
/// APB prescaler
#[derive(Clone, Copy)]
pub enum APBPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI16,
HSE(Hertz),
}

View file

@ -0,0 +1,204 @@
pub use super::types::*;
use crate::pac;
use crate::peripherals::{self, RCC};
use crate::rcc::{get_freqs, set_freqs, Clocks};
use crate::time::Hertz;
use crate::time::U32Ext;
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_extras::unborrow;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed
pub const HSI_FREQ: u32 = 16_000_000;
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSI16,
}
impl Into<u8> for APBPrescaler {
fn into(self) -> u8 {
match self {
APBPrescaler::NotDivided => 1,
APBPrescaler::Div2 => 0x04,
APBPrescaler::Div4 => 0x05,
APBPrescaler::Div8 => 0x06,
APBPrescaler::Div16 => 0x07,
}
}
}
impl Into<u8> for AHBPrescaler {
fn into(self) -> u8 {
match self {
AHBPrescaler::NotDivided => 1,
AHBPrescaler::Div2 => 0x08,
AHBPrescaler::Div4 => 0x09,
AHBPrescaler::Div8 => 0x0a,
AHBPrescaler::Div16 => 0x0b,
AHBPrescaler::Div64 => 0x0c,
AHBPrescaler::Div128 => 0x0d,
AHBPrescaler::Div256 => 0x0e,
AHBPrescaler::Div512 => 0x0f,
}
}
}
/// Clocks configutation
pub struct Config {
mux: ClockSrc,
ahb_pre: AHBPrescaler,
apb1_pre: APBPrescaler,
apb2_pre: APBPrescaler,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::NotDivided,
apb1_pre: APBPrescaler::NotDivided,
apb2_pre: APBPrescaler::NotDivided,
}
}
}
impl Config {
#[inline]
pub fn clock_src(mut self, mux: ClockSrc) -> Self {
self.mux = mux;
self
}
#[inline]
pub fn ahb_pre(mut self, pre: AHBPrescaler) -> Self {
self.ahb_pre = pre;
self
}
#[inline]
pub fn apb1_pre(mut self, pre: APBPrescaler) -> Self {
self.apb1_pre = pre;
self
}
#[inline]
pub fn apb2_pre(mut self, pre: APBPrescaler) -> Self {
self.apb2_pre = pre;
self
}
}
/// RCC peripheral
pub struct Rcc<'d> {
_rb: peripherals::RCC,
phantom: PhantomData<&'d mut peripherals::RCC>,
}
impl<'d> Rcc<'d> {
pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
unborrow!(rcc);
Self {
_rb: rcc,
phantom: PhantomData,
}
}
// Safety: RCC init must have been called
pub fn clocks(&self) -> &'static Clocks {
unsafe { get_freqs() }
}
}
/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Clocks;
}
impl RccExt for RCC {
#[inline]
fn freeze(self, cfgr: Config) -> Clocks {
let rcc = pac::RCC;
let (sys_clk, sw) = match cfgr.mux {
ClockSrc::HSI16 => {
// Enable HSI16
unsafe {
rcc.cr().write(|w| w.set_hsion(true));
while !rcc.cr().read().hsirdy() {}
}
(HSI_FREQ, 0x01)
}
ClockSrc::HSE(freq) => {
// Enable HSE
unsafe {
rcc.cr().write(|w| w.set_hseon(true));
while !rcc.cr().read().hserdy() {}
}
(freq.0, 0x02)
}
};
unsafe {
rcc.cfgr().modify(|w| {
w.set_sw(sw.into());
w.set_hpre(cfgr.ahb_pre.into());
w.set_ppre1(cfgr.apb1_pre.into());
w.set_ppre2(cfgr.apb2_pre.into());
});
}
let ahb_freq: u32 = match cfgr.ahb_pre {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let apb1_freq = match cfgr.apb1_pre {
APBPrescaler::NotDivided => ahb_freq,
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
freq
}
};
let apb2_freq = match cfgr.apb2_pre {
APBPrescaler::NotDivided => ahb_freq,
pre => {
let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3));
freq
}
};
Clocks {
sys: sys_clk.hz(),
ahb1: ahb_freq.hz(),
ahb2: ahb_freq.hz(),
ahb3: ahb_freq.hz(),
apb1: apb1_freq.hz(),
apb2: apb2_freq.hz(),
}
}
}
pub unsafe fn init(config: Config) {
let r = <peripherals::RCC as embassy::util::Steal>::steal();
let clocks = r.freeze(config);
set_freqs(clocks);
}

View file

@ -29,7 +29,6 @@ pub struct Spi<'d, T: Instance> {
impl<'d, T: Instance> Spi<'d, T> { impl<'d, T: Instance> Spi<'d, T> {
pub fn new<F>( pub fn new<F>(
pclk: Hertz,
_peri: impl Unborrow<Target = T> + 'd, _peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>>, sck: impl Unborrow<Target = impl SckPin<T>>,
mosi: impl Unborrow<Target = impl MosiPin<T>>, mosi: impl Unborrow<Target = impl MosiPin<T>>,
@ -58,6 +57,7 @@ impl<'d, T: Instance> Spi<'d, T> {
}); });
} }
let pclk = T::frequency();
let br = Self::compute_baud_rate(pclk, freq.into()); let br = Self::compute_baud_rate(pclk, freq.into());
unsafe { unsafe {

View file

@ -37,7 +37,6 @@ pub struct Spi<'d, T: Instance> {
impl<'d, T: Instance> Spi<'d, T> { impl<'d, T: Instance> Spi<'d, T> {
pub fn new<F>( pub fn new<F>(
pclk: Hertz,
_peri: impl Unborrow<Target = T> + 'd, _peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>>, sck: impl Unborrow<Target = impl SckPin<T>>,
mosi: impl Unborrow<Target = impl MosiPin<T>>, mosi: impl Unborrow<Target = impl MosiPin<T>>,
@ -60,6 +59,7 @@ impl<'d, T: Instance> Spi<'d, T> {
let mosi = mosi.degrade(); let mosi = mosi.degrade();
let miso = miso.degrade(); let miso = miso.degrade();
let pclk = T::frequency();
let br = Self::compute_baud_rate(pclk, freq.into()); let br = Self::compute_baud_rate(pclk, freq.into());
unsafe { unsafe {

View file

@ -37,7 +37,6 @@ pub struct Spi<'d, T: Instance> {
impl<'d, T: Instance> Spi<'d, T> { impl<'d, T: Instance> Spi<'d, T> {
pub fn new<F>( pub fn new<F>(
pclk: Hertz,
_peri: impl Unborrow<Target = T> + 'd, _peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>>, sck: impl Unborrow<Target = impl SckPin<T>>,
mosi: impl Unborrow<Target = impl MosiPin<T>>, mosi: impl Unborrow<Target = impl MosiPin<T>>,
@ -62,6 +61,7 @@ impl<'d, T: Instance> Spi<'d, T> {
let mosi = mosi.degrade(); let mosi = mosi.degrade();
let miso = miso.degrade(); let miso = miso.degrade();
let pclk = T::frequency();
let br = Self::compute_baud_rate(pclk, freq.into()); let br = Self::compute_baud_rate(pclk, freq.into());
unsafe { unsafe {
T::enable(); T::enable();

View file

@ -50,7 +50,6 @@ fn main() -> ! {
let p = embassy_stm32::init(Default::default()); let p = embassy_stm32::init(Default::default());
let mut spi = Spi::new( let mut spi = Spi::new(
Hertz(16_000_000),
p.SPI3, p.SPI3,
p.PC10, p.PC10,
p.PC12, p.PC12,

View file

@ -28,7 +28,6 @@ fn main() -> ! {
rcc.enable_debug_wfe(&mut p.DBGMCU, true); rcc.enable_debug_wfe(&mut p.DBGMCU, true);
let mut spi = Spi::new( let mut spi = Spi::new(
Hertz(16_000_000),
p.SPI1, p.SPI1,
p.PB3, p.PB3,
p.PA7, p.PA7,

View file

@ -44,7 +44,6 @@ fn main() -> ! {
let p = embassy_stm32::init(Default::default()); let p = embassy_stm32::init(Default::default());
let mut spi = Spi::new( let mut spi = Spi::new(
Hertz(16_000_000),
p.SPI3, p.SPI3,
p.PC10, p.PC10,
p.PC12, p.PC12,

View file

@ -84,7 +84,11 @@ fn find_reg_for_field<'c>(
field_name: &str, field_name: &str,
) -> Option<(&'c str, &'c str)> { ) -> Option<(&'c str, &'c str)> {
rcc.fieldsets.iter().find_map(|(name, fieldset)| { rcc.fieldsets.iter().find_map(|(name, fieldset)| {
if name.starts_with(reg_prefix) { // Workaround for some families that prefix register aliases with C1_, which does
// not help matching for clock name.
if name.starts_with("C1") || name.starts_with("C2") {
None
} else if name.starts_with(reg_prefix) {
fieldset fieldset
.fields .fields
.iter() .iter()
@ -287,8 +291,23 @@ pub fn gen(options: Options) {
match (en, rst) { match (en, rst) {
(Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => {
let clock = if clock_prefix == "" {
let re = Regex::new("([A-Z]+\\d*).*").unwrap();
if !re.is_match(enable_reg) {
panic!(
"unable to derive clock name from register name {}",
enable_reg
);
} else {
let caps = re.captures(enable_reg).unwrap();
caps.get(1).unwrap().as_str()
}
} else {
clock_prefix
};
peripheral_rcc_table.push(vec![ peripheral_rcc_table.push(vec![
name.clone(), name.clone(),
clock.to_ascii_lowercase(),
enable_reg.to_ascii_lowercase(), enable_reg.to_ascii_lowercase(),
reset_reg.to_ascii_lowercase(), reset_reg.to_ascii_lowercase(),
format!("set_{}", enable_field.to_ascii_lowercase()), format!("set_{}", enable_field.to_ascii_lowercase()),