Skip to content

Commit

Permalink
rcc: Add basic structure of RCC module
Browse files Browse the repository at this point in the history
  • Loading branch information
astapleton committed Aug 12, 2024
1 parent 2b401a5 commit 6aad4bc
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 3 deletions.
186 changes: 186 additions & 0 deletions src/rcc.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,188 @@
//! Reset and Clock Control
//!
use crate::stm32::RCC;
use crate::time::Hertz;

#[cfg(feature = "log")]
use log::debug;

mod core_clocks;
mod reset_reason;

pub use core_clocks::CoreClocks;
pub use reset_reason::ResetReason;

/// Configuration of the core clocks
pub struct Config {
hse: Option<u32>,
bypass_hse: bool,
lse: Option<u32>,
sys_ck: Option<u32>,
per_ck: Option<u32>,
audio_ck: Option<u32>,
rcc_hclk: Option<u32>,
rcc_pclk1: Option<u32>,
rcc_pclk2: Option<u32>,
rcc_pclk3: Option<u32>,
#[cfg(feature = "rm0481")]
rcc_pclk4: Option<u32>,
}

/// Extension trait that constrains the `RCC` peripheral
pub trait RccExt {
/// Constrains the `RCC` peripheral so it plays nicely with the
/// other abstractions
fn constrain(self) -> Rcc;
}

impl RccExt for RCC {
fn constrain(self) -> Rcc {
Rcc {
config: Config {
hse: None,
bypass_hse: false,
lse: None,
sys_ck: None,
per_ck: None,
audio_ck: None,
rcc_hclk: None,
rcc_pclk1: None,
rcc_pclk2: None,
rcc_pclk3: None,
#[cfg(feature = "rm0481")]
rcc_pclk4: None,
},
rb: self,
}
}
}

/// Constrained RCC peripheral
///
/// Generated by calling `constrain` on the PAC's RCC peripheral.
///
/// ```rust
/// let dp = stm32::Peripherals::take().unwrap();
/// let rcc = dp.RCC.constrain();
/// ```
pub struct Rcc {
config: Config,
pub(crate) rb: RCC,
}

impl Rcc {
/// Gets and clears the reason of why the mcu was reset
pub fn get_reset_reason(&mut self) -> ResetReason {
reset_reason::get_reset_reason(&mut self.rb)
}
}

/// Core Clock Distribution and Reset (CCDR)
///
/// Generated when the RCC is frozen. The configuration of the Sys_Ck `sys_ck`,
/// AHB clocks `hclk`, APB clocks `pclkN` and PLL outputs `pllN_X_ck` are
/// frozen. However the distribution of some clocks may still be modified and
/// peripherals enabled / reset by passing this object to other implementations
/// in this stack.
pub struct Ccdr {
/// A record of the frozen core clock frequencies
pub clocks: CoreClocks,
}

const MAX_SYSCLK_FREQ_HZ: u32 = 250_000_000;

/// Setter defintion for pclk 1 - 4
macro_rules! pclk_setter {
($($name:ident: $pclk:ident,)+) => {
$(
/// Set the peripheral clock frequency for APB
/// peripherals.
#[must_use]
pub fn $name(mut self, freq: Hertz) -> Self {
assert!(freq.raw() <= MAX_SYSCLK_FREQ_HZ,
"Max frequency is {MAX_SYSCLK_FREQ_HZ}Hz");
self.config.$pclk = Some(freq.raw());
self
}
)+
};
}

impl Rcc {
/// Uses HSE (external oscillator) instead of HSI (internal RC
/// oscillator) as the clock source. Will result in a hang if an
/// external oscillator is not connected or it fails to start.
#[must_use]
pub fn use_hse(mut self, freq: Hertz) -> Self {
self.config.hse = Some(freq.raw());
self
}

/// Use an external clock signal rather than a crystal oscillator,
/// bypassing the XTAL driver.
#[must_use]
pub fn bypass_hse(mut self) -> Self {
self.config.bypass_hse = true;
self
}

/// Set SYSCLK frequency
#[must_use]
pub fn sys_ck(mut self, freq: Hertz) -> Self {
assert!(
freq.raw() <= MAX_SYSCLK_FREQ_HZ,
"Max frequency is {MAX_SYSCLK_FREQ_HZ}Hz"
);
self.config.sys_ck = Some(freq.raw());
self
}

/// Set SYSCLK frequency - ALIAS
#[must_use]
pub fn sysclk(self, freq: Hertz) -> Self {
self.sys_ck(freq)
}

/// Set peripheral clock frequency
#[must_use]
pub fn per_ck(mut self, freq: Hertz) -> Self {
self.config.per_ck = Some(freq.raw());
self
}

/// Set low speed external clock frequency
pub fn lse_ck(mut self, freq: Hertz) -> Self {
self.config.lse = Some(freq.raw());
self
}

/// Set external AUDIOCLK frequency
#[must_use]
pub fn audio_ck(mut self, freq: Hertz) -> Self {
self.config.audio_ck = Some(freq.raw());
self
}

/// Set the peripheral clock frequency for AHB peripherals.
#[must_use]
pub fn hclk(mut self, freq: Hertz) -> Self {
assert!(
freq.raw() <= MAX_SYSCLK_FREQ_HZ,
"Max frequency is {MAX_SYSCLK_FREQ_HZ}Hz"
);
self.config.rcc_hclk = Some(freq.raw());
self
}

pclk_setter! {
pclk1: rcc_pclk1,
pclk2: rcc_pclk2,
pclk3: rcc_pclk3,
}

#[cfg(feature = "rm0481")]
pclk_setter! {
pclk4: rcc_pclk4,
}
}
1 change: 0 additions & 1 deletion src/rcc/core_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ macro_rules! pll_getter {
};
}

#[allow(dead_code)]
impl CoreClocks {
/// Returns the frequency of AHB1,2,3 busses
pub fn hclk(&self) -> Hertz {
Expand Down
2 changes: 0 additions & 2 deletions src/rcc/reset_reason.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use core::fmt::Display;

/// Gets and clears the reason of why the mcu was reset
#[rustfmt::skip]
#[allow(dead_code)]
pub fn get_reset_reason(rcc: &mut crate::stm32::RCC) -> ResetReason {
let reset_reason = rcc.rsr().read();

Expand Down Expand Up @@ -55,7 +54,6 @@ pub fn get_reset_reason(rcc: &mut crate::stm32::RCC) -> ResetReason {

/// Gives the reason why the mcu was reset
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
pub enum ResetReason {
/// The mcu went from not having power to having power and resetting
PowerOnReset,
Expand Down

0 comments on commit 6aad4bc

Please sign in to comment.