From 8acfa59d92d0654cba21ca2c09059f68b32b35db Mon Sep 17 00:00:00 2001 From: Jean Pierre Dudey Date: Sat, 22 Feb 2020 21:22:03 -0500 Subject: [PATCH] Add rtc_clk module This code gathers the CPU frequency configuration from the ESP32 registers. This code is based on top of the ESP-IDF `rtc_clk_cpu_freq_get_config`. This _might_ be needed to calculate I2C clock speeds and such. Signed-off-by: Jean Pierre Dudey --- src/lib.rs | 1 + src/rtc_clk.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 src/rtc_clk.rs diff --git a/src/lib.rs b/src/lib.rs index a03995d..043f7e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,3 +5,4 @@ pub use esp32 as pac; pub mod gpio; pub mod prelude; +pub mod rtc_clk; diff --git a/src/rtc_clk.rs b/src/rtc_clk.rs new file mode 100644 index 0000000..2c40a09 --- /dev/null +++ b/src/rtc_clk.rs @@ -0,0 +1,134 @@ +use { + crate::pac::{ + dport::cpu_per_conf::CPUPERIOD_SEL_A, + rtccntl::clk_conf::SOC_CLK_SEL_A, + generic::Variant::*, + APB_CTRL, + DPORT, + RTCCNTL, + }, +}; + +/// Disable logging from the ROM code. +pub const RTC_DISABLE_ROM_LOG: u32 = ((1 << 0) | (1 << 16)); + +/// RTC PLL 320 MHz frequency +pub const RTC_PLL_FREQ_320M: u32 = 320; + +/// RTC PLL 480 MHz frequency +pub const RTC_PLL_FREQ_480M: u32 = 480; + +/// RTC Clock errors +pub enum Error { + /// Unsupported frequency configuration + UnsupportedFreqConfig, +} + +/// CPU frequency source +pub enum CpuFreqSource { + /// XTAL + Xtal, + /// PLL + Pll, + /// 8M + Src8M, +} + +/// CPU frequency configuration +pub struct CpuFreqConfig { + /// CPU Frequency Source + pub source: CpuFreqSource, + /// CPU Source Frequency in MHz + pub source_freq_mhz: u32, + /// Frequency divider + pub div: u32, + /// CPU Frequency in MHz + pub freq_mhz: u32, +} + +impl CpuFreqConfig { + /// Read `CpuFreqConfig` from the ESP32 registers + pub fn read( + rtccntl: &RTCCNTL, + apb_ctrl: &APB_CTRL, + dport: &DPORT, + ) -> Result { + match rtccntl.clk_conf.read().soc_clk_sel().variant() { + SOC_CLK_SEL_A::XTAL => { + let mut config = CpuFreqConfig { + source: CpuFreqSource::Xtal, + source_freq_mhz: 0, + div: 0, + freq_mhz: 0, + }; + config.div = (apb_ctrl.sysclk_conf.read().pre_div_cnt().bits() + 1).into(); + config.source_freq_mhz = xtal_freq_get(rtccntl); + config.freq_mhz = config.source_freq_mhz / config.div; + Ok(config) + } + SOC_CLK_SEL_A::PLL => { + let mut config = CpuFreqConfig { + source: CpuFreqSource::Pll, + source_freq_mhz: 0, + div: 0, + freq_mhz: 0, + }; + match dport.cpu_per_conf.read().cpuperiod_sel().variant() { + Val(CPUPERIOD_SEL_A::SEL_80) => { + config.source_freq_mhz = RTC_PLL_FREQ_320M; + config.div = 4; + config.freq_mhz = 80; + } + Val(CPUPERIOD_SEL_A::SEL_160) => { + config.source_freq_mhz = RTC_PLL_FREQ_320M; + config.div = 2; + config.freq_mhz = 160; + } + Val(CPUPERIOD_SEL_A::SEL_240) => { + config.source_freq_mhz = RTC_PLL_FREQ_480M; + config.div = 2; + config.freq_mhz = 240; + } + Res(_) => { + return Err(Error::UnsupportedFreqConfig); + } + } + Ok(config) + } + SOC_CLK_SEL_A::CK8M => { + Ok(CpuFreqConfig { + source: CpuFreqSource::Src8M, + source_freq_mhz: 8, + div: 1, + freq_mhz: 8, + }) + } + SOC_CLK_SEL_A::APLL => { + Err(Error::UnsupportedFreqConfig) + } + } + } +} + +/// Get XTAL frequency +pub fn xtal_freq_get(rtccntl: &RTCCNTL) -> u32 { + // We may have already written XTAL value into RTC_XTAL_FREQ_REG + let xtal_freq_reg = rtccntl.store4.read().scratch4().bits(); + if !clk_val_is_valid(xtal_freq_reg) { + return 0; + } + + reg_val_to_clk_val(xtal_freq_reg & (!RTC_DISABLE_ROM_LOG)) +} + +/// Check if a value from RTC_XTAL_FREQ_REG or RTC_APB_FREQ_REG are valid clocks +#[inline(always)] +fn clk_val_is_valid(val: u32) -> bool { + (val & 0xffff) == ((val >> 16) & 0xffff) && val != 0 && val != u32::max_value() +} + +/// Convert a value from RTC_XTAL_FREQ_REG or RTC_APB_FREQ_REG to a clock value +#[inline(always)] +fn reg_val_to_clk_val(val: u32) -> u32 { + val & u16::max_value() as u32 +}