1use crate::clock::Hertz;
14
15use mik32_pac::pm::ahb_mux::{AhbClkMux, ForceMux};
16use mik32_pac::pm::cpu_rtc_clk_mux::CpuRtcClkMux;
17use mik32_pac::wake_up::clocks_bu::RtcClkMux;
18use mik32_pac::wake_up::clocks_sys::Force32kClk;
19use mik32_pac::{Peripherals, Pm, WakeUp};
20
21pub const HSI32M_FREQ: Hertz = Hertz(32_000_000);
22pub const OSC32M_FREQ: Hertz = Hertz(32_000_000);
23pub const LSI32K_FREQ: Hertz = Hertz(32_768);
24pub const OSC32K_FREQ: Hertz = Hertz(32_768);
25
26const CLOCKSWITCH_TIMEOUT_VALUE: u32 = 500_000;
27const SWITCH_SETTLE_CYCLES: u32 = 100;
28const LSI32K_CALIBRATION_MAX: u8 = 15;
29
30#[derive(Debug, Clone, Copy)]
36pub struct Clocks {
37 sys: Hertz,
39 ahb: Hertz,
41 apb_m: Hertz,
43 apb_p: Hertz,
45 ahb_div: u32,
47 apb_m_div: u32,
49 apb_p_div: u32,
51}
52
53impl Clocks {
54 pub const fn new(sys: Hertz, ahb_div: u32) -> Self {
59 Self::from_config(sys, ahb_div, 0, 0)
60 }
61
62 pub const fn from_config(sys: Hertz, ahb_div: u32, apb_m_div: u32, apb_p_div: u32) -> Self {
64 let ahb = Hertz(sys.0 / (ahb_div + 1));
65 Self {
66 sys,
67 ahb,
68 apb_m: Hertz(ahb.0 / (apb_m_div + 1)),
69 apb_p: Hertz(ahb.0 / (apb_p_div + 1)),
70 ahb_div,
71 apb_m_div,
72 apb_p_div,
73 }
74 }
75
76 pub fn sysclk(&self) -> Hertz {
78 self.sys
79 }
80
81 pub fn ahbclk(&self) -> Hertz {
83 self.ahb
84 }
85
86 pub fn apb_m_clk(&self) -> Hertz {
88 self.apb_m
89 }
90
91 pub fn apb_p_clk(&self) -> Hertz {
93 self.apb_p
94 }
95
96 pub fn ahb_div_clk(&self) -> u32 {
98 self.ahb_div
99 }
100
101 pub fn apb_m_div_clk(&self) -> u32 {
103 self.apb_m_div
104 }
105
106 pub fn apb_p_div_clk(&self) -> u32 {
108 self.apb_p_div
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum ClockSource {
115 Hsi32m,
117 Osc32m,
119 Lsi32k,
121 Osc32k,
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub enum ClockSwitchStage {
128 FreqMonitorRef,
130 SystemClock,
132 RtcClock,
134 CpuRtcClock,
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum Error {
141 DisabledClockSelected(ClockSource),
143 No32kClockEnabled,
146 ClockNotReady {
149 stage: ClockSwitchStage,
151 source: ClockSource,
153 },
154 InvalidCalibration {
156 source: ClockSource,
158 value: u8,
160 },
161}
162
163pub struct FreqMonitor {
165 pub sys: AhbClkMux,
167 pub force_osc_sys: ForceMux,
170 pub force32k_clk: Force32kClk,
172}
173
174impl Default for FreqMonitor {
175 fn default() -> Self {
176 Self {
177 sys: AhbClkMux::Osc32m,
178 force_osc_sys: ForceMux::Unfixed,
179 force32k_clk: Force32kClk::Automatic,
180 }
181 }
182}
183
184pub struct RCC {
191 pub hsi32m: bool,
193 pub osc32m: bool,
195 pub lsi32k: bool,
197 pub osc32k: bool,
199 pub freq_monitor: FreqMonitor,
201 pub ahb_div: u8,
203 pub apb_m_div: u8,
205 pub apb_p_div: u8,
207 pub hsi32m_calibration_value: u8,
209 pub lsi32k_calibration_value: u8,
211 pub rtcclk: RtcClkMux,
213 pub rtccpuclk: CpuRtcClkMux,
215 pub clocks: Clocks,
218}
219
220impl Default for RCC {
221 fn default() -> Self {
222 Self {
223 hsi32m: true,
224 osc32m: true,
225 lsi32k: true,
226 osc32k: true,
227 freq_monitor: FreqMonitor::default(),
228 ahb_div: 0,
229 apb_m_div: 0,
230 apb_p_div: 0,
231 hsi32m_calibration_value: 128,
232 lsi32k_calibration_value: 8,
233 rtcclk: RtcClkMux::Automatic,
234 rtccpuclk: CpuRtcClkMux::Osc32k,
235 clocks: Clocks::from_config(OSC32M_FREQ, 0, 0, 0),
236 }
237 }
238}
239
240impl RCC {
241 pub fn init(config: &RCC) -> Result<Clocks, Error> {
247 Self::validate(config)?;
248
249 let wu = unsafe { WakeUp::steal() };
250 let pm = unsafe { Pm::steal() };
251 let mut first_error = None;
252
253 wu.clocks_sys()
256 .modify(|_, w| w.hsi32m_en().enable().osc32m_en().enable());
257
258 wu.clocks_bu()
259 .modify(|_, w| w.lsi32k_en().enable().osc32k_en().enable());
260
261 wu.clocks_sys()
264 .modify(|_, w| unsafe { w.adj_hsi32m().bits(config.hsi32m_calibration_value) });
265
266 wu.clocks_bu()
267 .modify(|_, w| unsafe { w.adj_lsi32k().bits(config.lsi32k_calibration_value) });
268
269 match config.freq_monitor.force32k_clk {
274 Force32kClk::Automatic => {
275 wu.clocks_sys().modify(|_, w| w.force_32k_clk().automatic());
276 }
277 Force32kClk::Lsi32k => {
278 if Self::wait_freq_status(&pm, ClockSource::Lsi32k) {
279 wu.clocks_sys().modify(|_, w| w.force_32k_clk().lsi32k());
280 Self::switch_settle_delay();
281 } else {
282 Self::record_error(
283 &mut first_error,
284 Error::ClockNotReady {
285 stage: ClockSwitchStage::FreqMonitorRef,
286 source: ClockSource::Lsi32k,
287 },
288 );
289 }
290 }
291 Force32kClk::Osc32k => {
292 if Self::wait_freq_status(&pm, ClockSource::Osc32k) {
293 wu.clocks_sys().modify(|_, w| w.force_32k_clk().osc32k());
294 Self::switch_settle_delay();
295 } else {
296 Self::record_error(
297 &mut first_error,
298 Error::ClockNotReady {
299 stage: ClockSwitchStage::FreqMonitorRef,
300 source: ClockSource::Osc32k,
301 },
302 );
303 }
304 }
305 }
306
307 let system_source = Self::source_for_ahb(config.freq_monitor.sys);
312 if Self::wait_freq_status(&pm, system_source) {
313 pm.ahb_mux().modify(|_, w| {
314 let w = match config.freq_monitor.sys {
315 AhbClkMux::Osc32m => w.ahb_clk_mux().osc32m(),
316 AhbClkMux::Hsi32m => w.ahb_clk_mux().hsi32m(),
317 AhbClkMux::Osc32k => w.ahb_clk_mux().osc32k(),
318 AhbClkMux::Lsi32k => w.ahb_clk_mux().lsi32k(),
319 };
320
321 match config.freq_monitor.force_osc_sys {
322 ForceMux::Unfixed => w.force_mux().unfixed(),
323 ForceMux::Fixed => w.force_mux().fixed(),
324 }
325 });
326 Self::switch_settle_delay();
327 } else {
328 pm.ahb_mux().modify(|_, w| match config.freq_monitor.sys {
329 AhbClkMux::Osc32m => w.ahb_clk_mux().osc32m().force_mux().unfixed(),
330 AhbClkMux::Hsi32m => w.ahb_clk_mux().hsi32m().force_mux().unfixed(),
331 AhbClkMux::Osc32k => w.ahb_clk_mux().osc32k().force_mux().unfixed(),
332 AhbClkMux::Lsi32k => w.ahb_clk_mux().lsi32k().force_mux().unfixed(),
333 });
334 Self::record_error(
335 &mut first_error,
336 Error::ClockNotReady {
337 stage: ClockSwitchStage::SystemClock,
338 source: system_source,
339 },
340 );
341 }
342
343 pm.div_ahb()
344 .modify(|_, w| unsafe { w.bits(config.ahb_div as u32) });
345
346 pm.div_apb_m()
347 .modify(|_, w| unsafe { w.bits(config.apb_m_div as u32) });
348
349 pm.div_apb_p()
350 .modify(|_, w| unsafe { w.bits(config.apb_p_div as u32) });
351
352 match config.rtcclk {
358 RtcClkMux::Automatic => {
359 wu.clocks_bu().modify(|_, w| w.rtc_clk_mux().automatic());
360 }
361 RtcClkMux::Lsi32k => {
362 if Self::wait_freq_status(&pm, ClockSource::Lsi32k) {
363 wu.clocks_bu().modify(|_, w| w.rtc_clk_mux().lsi32k());
364 Self::pulse_rtc_reset(&wu);
365 Self::switch_settle_delay();
366 } else {
367 Self::record_error(
368 &mut first_error,
369 Error::ClockNotReady {
370 stage: ClockSwitchStage::RtcClock,
371 source: ClockSource::Lsi32k,
372 },
373 );
374 }
375 }
376 RtcClkMux::Osc32k => {
377 if Self::wait_freq_status(&pm, ClockSource::Osc32k) {
378 wu.clocks_bu().modify(|_, w| w.rtc_clk_mux().osc32k());
379 Self::pulse_rtc_reset(&wu);
380 Self::switch_settle_delay();
381 } else {
382 Self::record_error(
383 &mut first_error,
384 Error::ClockNotReady {
385 stage: ClockSwitchStage::RtcClock,
386 source: ClockSource::Osc32k,
387 },
388 );
389 }
390 }
391 }
392
393 let cpu_rtc_source = Self::source_for_cpu_rtc(config.rtccpuclk);
394 if Self::wait_freq_status(&pm, cpu_rtc_source) {
395 pm.cpu_rtc_clk_mux().modify(|_, w| match config.rtccpuclk {
396 CpuRtcClkMux::Osc32k => w.cpu_rtc_clk_mux().osc32k(),
397 CpuRtcClkMux::Lsi32k => w.cpu_rtc_clk_mux().lsi32k(),
398 });
399 Self::switch_settle_delay();
400 } else {
401 Self::record_error(
402 &mut first_error,
403 Error::ClockNotReady {
404 stage: ClockSwitchStage::CpuRtcClock,
405 source: cpu_rtc_source,
406 },
407 );
408 }
409
410 if !config.osc32m {
413 wu.clocks_sys().modify(|_, w| w.osc32m_en().disable());
414 }
415
416 if !config.hsi32m {
417 wu.clocks_sys().modify(|_, w| w.hsi32m_en().disable());
418 }
419
420 if !config.osc32k {
421 wu.clocks_bu().modify(|_, w| w.osc32k_en().disable());
422 }
423
424 if !config.lsi32k {
425 wu.clocks_bu().modify(|_, w| w.lsi32k_en().disable());
426 }
427
428 if let Some(error) = first_error {
429 Err(error)
430 } else {
431 Ok(Self::clocks(config))
432 }
433 }
434
435 pub fn clocks(config: &RCC) -> Clocks {
437 Clocks::from_config(
438 Self::sysclk_for(config.freq_monitor.sys),
439 config.ahb_div as u32,
440 config.apb_m_div as u32,
441 config.apb_p_div as u32,
442 )
443 }
444
445 fn validate(config: &RCC) -> Result<(), Error> {
447 if config.lsi32k_calibration_value > LSI32K_CALIBRATION_MAX {
448 return Err(Error::InvalidCalibration {
449 source: ClockSource::Lsi32k,
450 value: config.lsi32k_calibration_value,
451 });
452 }
453
454 Self::ensure_enabled(config, Self::source_for_ahb(config.freq_monitor.sys))?;
455
456 match config.freq_monitor.force32k_clk {
457 Force32kClk::Automatic => Self::ensure_any_32k_enabled(config)?,
458 Force32kClk::Lsi32k => Self::ensure_enabled(config, ClockSource::Lsi32k)?,
459 Force32kClk::Osc32k => Self::ensure_enabled(config, ClockSource::Osc32k)?,
460 }
461
462 match config.rtcclk {
463 RtcClkMux::Automatic => Self::ensure_any_32k_enabled(config)?,
464 RtcClkMux::Lsi32k => Self::ensure_enabled(config, ClockSource::Lsi32k)?,
465 RtcClkMux::Osc32k => Self::ensure_enabled(config, ClockSource::Osc32k)?,
466 }
467
468 match config.rtccpuclk {
469 CpuRtcClkMux::Osc32k => Self::ensure_enabled(config, ClockSource::Osc32k)?,
470 CpuRtcClkMux::Lsi32k => Self::ensure_enabled(config, ClockSource::Lsi32k)?,
471 }
472
473 Ok(())
474 }
475
476 fn ensure_any_32k_enabled(config: &RCC) -> Result<(), Error> {
477 if config.lsi32k || config.osc32k {
478 Ok(())
479 } else {
480 Err(Error::No32kClockEnabled)
481 }
482 }
483
484 fn ensure_enabled(config: &RCC, source: ClockSource) -> Result<(), Error> {
485 let enabled = match source {
486 ClockSource::Hsi32m => config.hsi32m,
487 ClockSource::Osc32m => config.osc32m,
488 ClockSource::Lsi32k => config.lsi32k,
489 ClockSource::Osc32k => config.osc32k,
490 };
491
492 if enabled {
493 Ok(())
494 } else {
495 Err(Error::DisabledClockSelected(source))
496 }
497 }
498
499 fn source_for_ahb(source: AhbClkMux) -> ClockSource {
500 match source {
501 AhbClkMux::Osc32m => ClockSource::Osc32m,
502 AhbClkMux::Hsi32m => ClockSource::Hsi32m,
503 AhbClkMux::Osc32k => ClockSource::Osc32k,
504 AhbClkMux::Lsi32k => ClockSource::Lsi32k,
505 }
506 }
507
508 fn source_for_cpu_rtc(source: CpuRtcClkMux) -> ClockSource {
509 match source {
510 CpuRtcClkMux::Osc32k => ClockSource::Osc32k,
511 CpuRtcClkMux::Lsi32k => ClockSource::Lsi32k,
512 }
513 }
514
515 fn wait_freq_status(pm: &Pm, source: ClockSource) -> bool {
516 for _ in 0..CLOCKSWITCH_TIMEOUT_VALUE {
517 if Self::freq_status_ready(pm, source) {
518 return true;
519 }
520 }
521
522 false
523 }
524
525 fn freq_status_ready(pm: &Pm, source: ClockSource) -> bool {
526 let status = pm.freq_status().read();
527
528 match source {
529 ClockSource::Hsi32m => status.mask_hsi32m().bit_is_set(),
530 ClockSource::Osc32m => status.mask_osc32m().bit_is_set(),
531 ClockSource::Lsi32k => status.mask_lsi32k().bit_is_set(),
532 ClockSource::Osc32k => status.mask_osc32k().bit_is_set(),
533 }
534 }
535
536 fn pulse_rtc_reset(wu: &WakeUp) {
537 wu.rtc_control().write(|w| unsafe { w.bits(1) });
538 wu.rtc_control().write(|w| unsafe { w.bits(0) });
539 }
540
541 fn switch_settle_delay() {
542 for _ in 0..SWITCH_SETTLE_CYCLES {
543 core::hint::spin_loop();
544 }
545 }
546
547 fn record_error(slot: &mut Option<Error>, error: Error) {
548 if slot.is_none() {
549 *slot = Some(error);
550 }
551 }
552
553 fn sysclk_for(source: AhbClkMux) -> Hertz {
554 match source {
555 AhbClkMux::Osc32m => OSC32M_FREQ,
556 AhbClkMux::Hsi32m => HSI32M_FREQ,
557 AhbClkMux::Osc32k => OSC32K_FREQ,
558 AhbClkMux::Lsi32k => LSI32K_FREQ,
559 }
560 }
561}
562
563pub fn system_clock() -> Hertz {
565 let p = unsafe { Peripherals::steal() };
566
567 match p.pm.ahb_mux().read().ahb_clk_mux().variant() {
568 AhbClkMux::Osc32m => OSC32M_FREQ,
569 AhbClkMux::Hsi32m => HSI32M_FREQ,
570 AhbClkMux::Osc32k => OSC32K_FREQ,
571 AhbClkMux::Lsi32k => LSI32K_FREQ,
572 }
573}
574
575pub fn clocks() -> Clocks {
577 let p = unsafe { Peripherals::steal() };
578
579 Clocks::from_config(
580 system_clock(),
581 p.pm.div_ahb().read().bits(),
582 p.pm.div_apb_m().read().bits(),
583 p.pm.div_apb_p().read().bits(),
584 )
585}