|
| 1 | +use super::Error; |
| 2 | +use crate::prelude::*; |
| 3 | +use core::fmt; |
| 4 | + |
| 5 | +use super::{ |
| 6 | + dfs, CPUSource, ClockControlConfig, FastRTCSource, SlowRTCSource, CLOCK_CONTROL, |
| 7 | + CLOCK_CONTROL_MUTEX, |
| 8 | +}; |
| 9 | + |
| 10 | +impl<'a> super::ClockControlConfig { |
| 11 | + // All the single word reads of frequencies and sources are thread and interrupt safe |
| 12 | + // as these are atomic. |
| 13 | + |
| 14 | + /// The current CPU frequency |
| 15 | + pub fn cpu_frequency(&self) -> Hertz { |
| 16 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().cpu_frequency } |
| 17 | + } |
| 18 | + |
| 19 | + /// The current APB frequency |
| 20 | + pub fn apb_frequency(&self) -> Hertz { |
| 21 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().apb_frequency } |
| 22 | + } |
| 23 | + |
| 24 | + /// The CPU frequency in the default state |
| 25 | + pub fn cpu_frequency_default(&self) -> Hertz { |
| 26 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().cpu_frequency_default } |
| 27 | + } |
| 28 | + |
| 29 | + /// The CPU frequency in the CPU lock state |
| 30 | + pub fn cpu_frequency_locked(&self) -> Hertz { |
| 31 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().cpu_frequency_locked } |
| 32 | + } |
| 33 | + |
| 34 | + /// The CPU frequency in the APB lock state |
| 35 | + pub fn cpu_frequency_apb_locked(&self) -> Hertz { |
| 36 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().cpu_frequency_apb_locked } |
| 37 | + } |
| 38 | + |
| 39 | + /// The APB frequency in the APB lock state |
| 40 | + pub fn apb_frequency_apb_locked(&self) -> Hertz { |
| 41 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().apb_frequency_apb_locked } |
| 42 | + } |
| 43 | + |
| 44 | + /// Is the reference clock 1MHz under all clock conditions |
| 45 | + pub fn is_ref_clock_stable(&self) -> bool { |
| 46 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().ref_clock_stable } |
| 47 | + } |
| 48 | + |
| 49 | + /// The current reference frequency |
| 50 | + pub fn ref_frequency(&self) -> Hertz { |
| 51 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().ref_frequency } |
| 52 | + } |
| 53 | + |
| 54 | + /// The current slow RTC frequency |
| 55 | + pub fn slow_rtc_frequency(&self) -> Hertz { |
| 56 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().slow_rtc_frequency } |
| 57 | + } |
| 58 | + |
| 59 | + /// The current fast RTC frequency |
| 60 | + pub fn fast_rtc_frequency(&self) -> Hertz { |
| 61 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().fast_rtc_frequency } |
| 62 | + } |
| 63 | + |
| 64 | + /// The current APLL frequency |
| 65 | + pub fn apll_frequency(&self) -> Hertz { |
| 66 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().apll_frequency } |
| 67 | + } |
| 68 | + |
| 69 | + /// The current PLL/2 frequency |
| 70 | + pub fn pll_d2_frequency(&self) -> Hertz { |
| 71 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().pll_d2_frequency } |
| 72 | + } |
| 73 | + |
| 74 | + /// The Xtal frequency |
| 75 | + pub fn xtal_frequency(&self) -> Hertz { |
| 76 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().xtal_frequency } |
| 77 | + } |
| 78 | + |
| 79 | + /// The 32kHz Xtal frequency |
| 80 | + pub fn xtal32k_frequency(&self) -> Hertz { |
| 81 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().xtal32k_frequency } |
| 82 | + } |
| 83 | + |
| 84 | + /// The current PLL frequency |
| 85 | + pub fn pll_frequency(&self) -> Hertz { |
| 86 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().pll_frequency } |
| 87 | + } |
| 88 | + |
| 89 | + /// The current 8MHz oscillator frequency |
| 90 | + pub fn rtc8m_frequency(&self) -> Hertz { |
| 91 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().rtc8m_frequency } |
| 92 | + } |
| 93 | + |
| 94 | + /// The current 8MHz oscillator frequency / 256 |
| 95 | + pub fn rtc8md256_frequency(&self) -> Hertz { |
| 96 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().rtc8md256_frequency } |
| 97 | + } |
| 98 | + |
| 99 | + /// The current 150kHz oscillator frequency |
| 100 | + pub fn rtc_frequency(&self) -> Hertz { |
| 101 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().rtc_frequency } |
| 102 | + } |
| 103 | + |
| 104 | + /// The current source for the CPU and APB frequencies |
| 105 | + pub fn cpu_source(&self) -> CPUSource { |
| 106 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().cpu_source } |
| 107 | + } |
| 108 | + |
| 109 | + /// The current source for the slow RTC frequency |
| 110 | + pub fn slow_rtc_source(&self) -> SlowRTCSource { |
| 111 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().slow_rtc_source } |
| 112 | + } |
| 113 | + |
| 114 | + /// The current source for the fast RTC frequency |
| 115 | + pub fn fast_rtc_source(&self) -> FastRTCSource { |
| 116 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().fast_rtc_source } |
| 117 | + } |
| 118 | + |
| 119 | + // The lock and unlock calls are thread and interrupt safe because this is handled inside |
| 120 | + // the DFS routines |
| 121 | + |
| 122 | + /// Obtain a RAII lock to use the high CPU frequency |
| 123 | + pub fn lock_cpu_frequency(&self) -> dfs::LockCPU { |
| 124 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().lock_cpu_frequency() } |
| 125 | + } |
| 126 | + |
| 127 | + /// Obtain a RAII lock to use the APB CPU frequency |
| 128 | + pub fn lock_apb_frequency(&self) -> dfs::LockAPB { |
| 129 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().lock_apb_frequency() } |
| 130 | + } |
| 131 | + |
| 132 | + /// Obtain a RAII lock to keep the CPU from sleeping |
| 133 | + pub fn lock_awake(&self) -> dfs::LockAwake { |
| 134 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().lock_awake() } |
| 135 | + } |
| 136 | + |
| 137 | + /// Obtain a RAII lock to keep the PLL/2 from being turned off |
| 138 | + pub fn lock_plld2(&self) -> dfs::LockPllD2 { |
| 139 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().lock_plld2() } |
| 140 | + } |
| 141 | + |
| 142 | + /// Add callback which will be called when clock speeds are changed. |
| 143 | + /// |
| 144 | + /// NOTE: these callbacks are called in an interrupt free environment, |
| 145 | + /// so should be as short as possible |
| 146 | + // TODO: at the moment only static lifetime callbacks are allow |
| 147 | + pub fn add_callback<F>(&self, f: &'static F) -> Result<(), Error> |
| 148 | + where |
| 149 | + F: Fn(), |
| 150 | + { |
| 151 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().add_callback(f) } |
| 152 | + } |
| 153 | + |
| 154 | + /// Get the current count of the PCU, APB, Awake and PLL/2 locks |
| 155 | + pub fn get_lock_count(&self) -> dfs::Locks { |
| 156 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().get_lock_count() } |
| 157 | + } |
| 158 | + |
| 159 | + // The following routines are made thread and interrupt safe here |
| 160 | + |
| 161 | + /// Halt the designated core |
| 162 | + pub unsafe fn park_core(&mut self, core: crate::Core) { |
| 163 | + interrupt::free(|_| { |
| 164 | + CLOCK_CONTROL_MUTEX.lock(); |
| 165 | + CLOCK_CONTROL.as_mut().unwrap().park_core(core); |
| 166 | + }) |
| 167 | + } |
| 168 | + |
| 169 | + /// Start the APP (second) core |
| 170 | + /// |
| 171 | + /// The second core will start running with the function `entry`. |
| 172 | + pub fn unpark_core(&mut self, core: crate::Core) { |
| 173 | + interrupt::free(|_| { |
| 174 | + CLOCK_CONTROL_MUTEX.lock(); |
| 175 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().unpark_core(core) } |
| 176 | + }) |
| 177 | + } |
| 178 | + |
| 179 | + /// Start the APP (second) core |
| 180 | + /// |
| 181 | + /// The second core will start running with the function `entry`. |
| 182 | + pub fn start_app_core(&mut self, entry: fn() -> !) -> Result<(), Error> { |
| 183 | + interrupt::free(|_| { |
| 184 | + CLOCK_CONTROL_MUTEX.lock(); |
| 185 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().start_app_core(entry) } |
| 186 | + }) |
| 187 | + } |
| 188 | + |
| 189 | + // The following routines handle thread and interrupt safety themselves |
| 190 | + |
| 191 | + /// Get RTC tick count since boot |
| 192 | + /// |
| 193 | + /// *Note: this function takes up to one slow RTC clock cycle (can be up to 300us) and |
| 194 | + /// interrupts are blocked during this time.* |
| 195 | + pub fn rtc_tick_count(&self) -> TicksU64 { |
| 196 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().rtc_tick_count() } |
| 197 | + } |
| 198 | + |
| 199 | + /// Get nanoseconds since boot based on RTC tick count |
| 200 | + /// |
| 201 | + /// *Note: this function takes up to one slow RTC clock cycle (can be up to 300us) and |
| 202 | + /// interrupts are blocked during this time.* |
| 203 | + pub fn rtc_nanoseconds(&self) -> NanoSecondsU64 { |
| 204 | + unsafe { CLOCK_CONTROL.as_mut().unwrap().rtc_nanoseconds() } |
| 205 | + } |
| 206 | +} |
| 207 | + |
| 208 | +impl fmt::Debug for ClockControlConfig { |
| 209 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 210 | + unsafe { CLOCK_CONTROL.as_ref().unwrap().fmt(f) } |
| 211 | + } |
| 212 | +} |
0 commit comments