1use crate::fmc::Fmc;
20use crate::pac;
21use crate::time::Hertz;
22
23const IRC8M: u32 = 8_000_000;
24const IRC28M: u32 = 28_000_000;
25const LXTAL: u32 = 32_768;
26const PLL_SRC: u32 = IRC8M / 2;
27pub(crate) const IRC40K: u32 = 40_000;
28
29const IRC28MDIV_DIV1: bool = true;
30const IRC28MDIV_DIV2: bool = false;
31const ADCSEL_IRC28M: bool = false;
32const ADCSEL_PRESCALED: bool = true;
33const ADCPSC_MSB_APB2: bool = false;
34const ADCPSC_MSB_AHB: bool = true;
35
36#[derive(Clone, Copy, PartialEq, Eq)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39#[allow(missing_docs)]
40pub enum PllFreq {
41 Mhz8 = 8_000_000,
42 Mhz12 = 12_000_000,
43 Mhz16 = 16_000_000,
44 Mhz20 = 20_000_000,
45 Mhz24 = 24_000_000,
46 Mhz28 = 28_000_000,
47 Mhz32 = 32_000_000,
48 Mhz36 = 36_000_000,
49 Mhz40 = 40_000_000,
50 Mhz44 = 44_000_000,
51 Mhz48 = 48_000_000,
52 Mhz52 = 52_000_000,
53 Mhz56 = 56_000_000,
54 Mhz60 = 60_000_000,
55 Mhz64 = 64_000_000,
56 Mhz68 = 68_000_000,
57 Mhz72 = 72_000_000,
58}
59
60#[derive(Clone, Copy, PartialEq, Eq)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66pub enum SysClk {
67 Irc8m,
69 Pll(PllFreq),
71}
72
73#[derive(Clone, Copy, PartialEq, Eq)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76#[allow(missing_docs)]
77pub enum AhbPsc {
78 Div1 = 1,
79 Div2 = 2,
80 Div4 = 4,
81 Div8 = 8,
82 Div16 = 16,
83 Div64 = 64,
84 Div128 = 128,
85 Div256 = 256,
86 Div512 = 512,
87}
88
89#[derive(Clone, Copy, PartialEq, Eq)]
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92#[allow(missing_docs)]
93pub enum ApbPsc {
94 Div1 = 1,
95 Div2 = 2,
96 Div4 = 4,
97 Div8 = 8,
98 Div16 = 16,
99}
100
101#[derive(Clone, Copy, PartialEq, Eq)]
103#[cfg_attr(feature = "defmt", derive(defmt::Format))]
104#[allow(missing_docs)]
105pub enum AdcPsc {
106 Apb2Div2,
107 Apb2Div4,
108 Apb2Div6,
109 Apb2Div8,
110 AhbDiv3,
111 AhbDiv5,
112 AhbDiv7,
113 AhbDiv9,
114}
115
116#[derive(Clone, Copy, PartialEq, Eq)]
118#[cfg_attr(feature = "defmt", derive(defmt::Format))]
119#[allow(missing_docs)]
120pub enum Irc28mDiv {
121 Div1,
122 Div2,
123}
124
125#[derive(Clone, Copy, PartialEq, Eq)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128pub enum AdcSel {
129 Off,
132 Irc28m(Irc28mDiv),
134 Prescaled(AdcPsc),
136}
137
138#[derive(Clone, Copy, PartialEq, Eq)]
140#[cfg_attr(feature = "defmt", derive(defmt::Format))]
141pub enum Usart0Sel {
142 Apb2,
144 Sysclk,
146 Lxtal,
151 Irc8m,
153}
154
155#[derive(Clone, Copy, PartialEq, Eq)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158pub struct Clocks {
159 hclk: Hertz,
160 pclk1: Hertz,
161 pclk2: Hertz,
162 sysclk: Hertz,
163 usart0: Hertz,
164 ck_adc: Hertz,
165 pclk1_tim: Hertz,
166 pclk2_tim: Hertz,
167}
168
169impl Clocks {
170 #[inline]
172 pub fn hclk(&self) -> Hertz {
173 self.hclk
174 }
175 #[inline]
177 pub fn pclk1(&self) -> Hertz {
178 self.pclk1
179 }
180 #[inline]
182 pub fn pclk2(&self) -> Hertz {
183 self.pclk2
184 }
185 #[inline]
187 pub fn sysclk(&self) -> Hertz {
188 self.sysclk
189 }
190 #[inline]
192 pub fn usart0(&self) -> Hertz {
193 self.usart0
194 }
195 #[inline]
197 pub fn ck_adc(&self) -> Hertz {
198 self.ck_adc
199 }
200 #[inline]
206 pub fn pclk1_tim(&self) -> Hertz {
207 self.pclk1_tim
208 }
209 #[inline]
213 pub fn pclk2_tim(&self) -> Hertz {
214 self.pclk2_tim
215 }
216}
217
218#[derive(Clone, Copy, PartialEq, Eq)]
224#[cfg_attr(feature = "defmt", derive(defmt::Format))]
225#[must_use]
226pub struct ClockConfig {
227 hclk: AhbPsc,
228 pclk1: ApbPsc,
229 pclk2: ApbPsc,
230 sysclk: SysClk,
231 usart0_sel: Usart0Sel,
232 adc_sel: AdcSel,
233}
234
235impl Default for ClockConfig {
236 fn default() -> Self {
237 Self {
238 hclk: AhbPsc::Div1,
239 pclk1: ApbPsc::Div1,
240 pclk2: ApbPsc::Div1,
241 sysclk: SysClk::Irc8m,
242 usart0_sel: Usart0Sel::Apb2,
243 adc_sel: AdcSel::Off,
244 }
245 }
246}
247
248impl ClockConfig {
249 const fn pll_mul(desired: PllFreq) -> u32 {
250 (desired as u32) / PLL_SRC
251 }
252
253 pub const fn hclk(mut self, psc: AhbPsc) -> Self {
255 self.hclk = psc;
256 self
257 }
258 pub const fn pclk1(mut self, psc: ApbPsc) -> Self {
260 self.pclk1 = psc;
261 self
262 }
263 pub const fn pclk2(mut self, psc: ApbPsc) -> Self {
265 self.pclk2 = psc;
266 self
267 }
268 pub const fn sysclk(mut self, src: SysClk) -> Self {
270 self.sysclk = src;
271 self
272 }
273 pub const fn usart0_sel(mut self, src: Usart0Sel) -> Self {
275 self.usart0_sel = src;
276 self
277 }
278 pub const fn adc_sel(mut self, sel: AdcSel) -> Self {
283 self.adc_sel = sel;
284 self
285 }
286}
287
288pub struct UnfrozenRcu {
290 rcu: pac::Rcu,
291}
292
293impl UnfrozenRcu {
294 #[allow(clippy::too_many_lines)]
299 pub fn freeze(self, fmc: &mut Fmc, config: ClockConfig) -> Rcu {
300 let sysclk = match config.sysclk {
301 SysClk::Irc8m => IRC8M,
302 SysClk::Pll(desired) => {
303 let mul = ClockConfig::pll_mul(desired);
304 self.rcu.cfg0().modify(|_, w| {
305 let w = w.pllsel().irc8m_2();
306 match mul {
307 2 => w.pllmf().mul2().pllmf_msb().none(),
308 3 => w.pllmf().mul3().pllmf_msb().none(),
309 4 => w.pllmf().mul4().pllmf_msb().none(),
310 5 => w.pllmf().mul5().pllmf_msb().none(),
311 6 => w.pllmf().mul6().pllmf_msb().none(),
312 7 => w.pllmf().mul7().pllmf_msb().none(),
313 8 => w.pllmf().mul8().pllmf_msb().none(),
314 9 => w.pllmf().mul9().pllmf_msb().none(),
315 10 => w.pllmf().mul10().pllmf_msb().none(),
316 11 => w.pllmf().mul11().pllmf_msb().none(),
317 12 => w.pllmf().mul12().pllmf_msb().none(),
318 13 => w.pllmf().mul13().pllmf_msb().none(),
319 14 => w.pllmf().mul14().pllmf_msb().none(),
320 15 => w.pllmf().mul15().pllmf_msb().none(),
321 16 => w.pllmf().mul16().pllmf_msb().none(),
322 17 => w.pllmf().mul2().pllmf_msb().plus15(),
323 18 => w.pllmf().mul3().pllmf_msb().plus15(),
324 _ => unreachable!(),
325 }
326 });
327 self.rcu.ctl0().modify(|_, w| w.pllen().on());
328 while self.rcu.ctl0().read().pllstb().is_not_ready() {}
329 desired as u32
330 }
331 };
332
333 let ahb_psc = config.hclk;
334 let hclk = sysclk / (ahb_psc as u32);
335 let apb1_psc = config.pclk1;
336 let pclk1 = hclk / (apb1_psc as u32);
337 let apb2_psc = config.pclk2;
338 let pclk2 = hclk / (apb2_psc as u32);
339
340 let usart0_sel = config.usart0_sel;
341 let usart0 = match usart0_sel {
342 Usart0Sel::Apb2 => pclk2,
343 Usart0Sel::Sysclk => sysclk,
344 Usart0Sel::Lxtal => LXTAL,
345 Usart0Sel::Irc8m => IRC8M,
346 };
347 self.rcu.cfg2().modify(|_, w| match usart0_sel {
348 Usart0Sel::Apb2 => w.usart0sel().apb2(),
349 Usart0Sel::Sysclk => w.usart0sel().sys(),
350 Usart0Sel::Lxtal => w.usart0sel().lxtal(),
351 Usart0Sel::Irc8m => w.usart0sel().irc8m(),
352 });
353
354 let ck_adc = match config.adc_sel {
355 AdcSel::Off => 0,
356 AdcSel::Irc28m(div) => {
357 self.rcu.ctl1().modify(|_, w| w.irc28men().on());
358 while self.rcu.ctl1().read().irc28mstb().is_not_ready() {}
359 self.rcu.cfg2().modify(|_, w| {
360 let w = match div {
361 Irc28mDiv::Div1 => w.irc28mdiv().bit(IRC28MDIV_DIV1),
362 Irc28mDiv::Div2 => w.irc28mdiv().bit(IRC28MDIV_DIV2),
363 };
364 w.adcsel().bit(ADCSEL_IRC28M)
365 });
366 match div {
367 Irc28mDiv::Div1 => IRC28M,
368 Irc28mDiv::Div2 => IRC28M / 2,
369 }
370 }
371 AdcSel::Prescaled(psc) => {
372 self.rcu.cfg0().modify(|_, w| match psc {
374 AdcPsc::Apb2Div2 | AdcPsc::AhbDiv3 => w.adcpsc().div2(),
375 AdcPsc::Apb2Div4 | AdcPsc::AhbDiv5 => w.adcpsc().div4(),
376 AdcPsc::Apb2Div6 | AdcPsc::AhbDiv7 => w.adcpsc().div6(),
377 AdcPsc::Apb2Div8 | AdcPsc::AhbDiv9 => w.adcpsc().div8(),
378 });
379 self.rcu.cfg2().modify(|_, w| {
380 let w = match psc {
381 AdcPsc::Apb2Div2
382 | AdcPsc::Apb2Div4
383 | AdcPsc::Apb2Div6
384 | AdcPsc::Apb2Div8 => w.adcpsc().bit(ADCPSC_MSB_APB2),
385 AdcPsc::AhbDiv3 | AdcPsc::AhbDiv5 | AdcPsc::AhbDiv7 | AdcPsc::AhbDiv9 => {
386 w.adcpsc().bit(ADCPSC_MSB_AHB)
387 }
388 };
389 w.adcsel().bit(ADCSEL_PRESCALED)
390 });
391 match psc {
392 AdcPsc::Apb2Div2 => pclk2 / 2,
393 AdcPsc::Apb2Div4 => pclk2 / 4,
394 AdcPsc::Apb2Div6 => pclk2 / 6,
395 AdcPsc::Apb2Div8 => pclk2 / 8,
396 AdcPsc::AhbDiv3 => hclk / 3,
397 AdcPsc::AhbDiv5 => hclk / 5,
398 AdcPsc::AhbDiv7 => hclk / 7,
399 AdcPsc::AhbDiv9 => hclk / 9,
400 }
401 }
402 };
403
404 fmc.set_ws(hclk);
405
406 self.rcu.cfg0().modify(|_, w| {
407 let w = match ahb_psc {
408 AhbPsc::Div1 => w.ahbpsc().div1(),
409 AhbPsc::Div2 => w.ahbpsc().div2(),
410 AhbPsc::Div4 => w.ahbpsc().div4(),
411 AhbPsc::Div8 => w.ahbpsc().div8(),
412 AhbPsc::Div16 => w.ahbpsc().div16(),
413 AhbPsc::Div64 => w.ahbpsc().div64(),
414 AhbPsc::Div128 => w.ahbpsc().div128(),
415 AhbPsc::Div256 => w.ahbpsc().div256(),
416 AhbPsc::Div512 => w.ahbpsc().div512(),
417 };
418 let w = match apb1_psc {
419 ApbPsc::Div1 => w.apb1psc().div1(),
420 ApbPsc::Div2 => w.apb1psc().div2(),
421 ApbPsc::Div4 => w.apb1psc().div4(),
422 ApbPsc::Div8 => w.apb1psc().div8(),
423 ApbPsc::Div16 => w.apb1psc().div16(),
424 };
425 let w = match apb2_psc {
426 ApbPsc::Div1 => w.apb2psc().div1(),
427 ApbPsc::Div2 => w.apb2psc().div2(),
428 ApbPsc::Div4 => w.apb2psc().div4(),
429 ApbPsc::Div8 => w.apb2psc().div8(),
430 ApbPsc::Div16 => w.apb2psc().div16(),
431 };
432 match config.sysclk {
433 SysClk::Pll(_) => w.scs().pll(),
434 SysClk::Irc8m => w,
437 }
438 });
439 let clocks = Clocks {
440 hclk: Hertz::from_raw(hclk),
441 pclk1: Hertz::from_raw(pclk1),
442 pclk2: Hertz::from_raw(pclk2),
443 sysclk: Hertz::from_raw(sysclk),
444 usart0: Hertz::from_raw(usart0),
445 ck_adc: Hertz::from_raw(ck_adc),
446 pclk1_tim: Hertz::from_raw(match apb1_psc {
447 ApbPsc::Div1 => hclk, _ => hclk / (apb1_psc as u32 / 2), }),
450 pclk2_tim: Hertz::from_raw(match apb2_psc {
451 ApbPsc::Div1 => hclk, _ => hclk / (apb2_psc as u32 / 2), }),
454 };
455 Rcu {
456 rcu: self.rcu,
457 clocks,
458 }
459 }
460}
461
462#[derive(Clone, Copy, PartialEq, Eq)]
464#[cfg_attr(feature = "defmt", derive(defmt::Format))]
465#[allow(missing_docs)]
466pub enum PllDiv {
467 Div1,
468 Div2,
469}
470
471#[derive(Clone, Copy, PartialEq, Eq)]
475#[cfg_attr(feature = "defmt", derive(defmt::Format))]
476pub enum CkOutSrc {
477 None,
479 Irc14m,
481 Lsi40k,
483 Lxtal,
485 Sysclk,
487 Irc8m,
489 Hxtal,
491 Pll(PllDiv),
493}
494
495#[derive(Clone, Copy, PartialEq, Eq)]
497#[cfg_attr(feature = "defmt", derive(defmt::Format))]
498#[allow(missing_docs)]
499pub enum CkOutDiv {
500 Div1,
501 Div2,
502 Div4,
503 Div8,
504 Div16,
505 Div32,
506 Div64,
507 Div128,
508}
509
510#[derive(Clone, Copy, PartialEq, Eq)]
515#[cfg_attr(feature = "defmt", derive(defmt::Format))]
516pub enum ResetFlag {
517 LowPower,
519 WindowWatchdog,
521 FreeWatchdog,
523 Software,
525 Power,
527 ExternalPin,
529 OptionByteLoader,
531}
532
533pub struct Rcu {
536 rcu: pac::Rcu,
537 clocks: Clocks,
538}
539
540impl Rcu {
541 pub fn clocks(&self) -> Clocks {
543 self.clocks
544 }
545
546 pub fn ck_out(&mut self, src: CkOutSrc, div: CkOutDiv) {
551 self.rcu.cfg0().modify(|_, w| {
552 let w = match div {
553 CkOutDiv::Div1 => w.ckoutdiv().div1(),
554 CkOutDiv::Div2 => w.ckoutdiv().div2(),
555 CkOutDiv::Div4 => w.ckoutdiv().div4(),
556 CkOutDiv::Div8 => w.ckoutdiv().div8(),
557 CkOutDiv::Div16 => w.ckoutdiv().div16(),
558 CkOutDiv::Div32 => w.ckoutdiv().div32(),
559 CkOutDiv::Div64 => w.ckoutdiv().div64(),
560 CkOutDiv::Div128 => w.ckoutdiv().div128(),
561 };
562 match src {
563 CkOutSrc::None => w.ckoutsel().none(),
564 CkOutSrc::Irc14m => w.ckoutsel().irc14m(),
565 CkOutSrc::Lsi40k => w.ckoutsel().lsi40k(),
566 CkOutSrc::Lxtal => w.ckoutsel().lxtal(),
567 CkOutSrc::Sysclk => w.ckoutsel().sysclk(),
568 CkOutSrc::Irc8m => w.ckoutsel().irc8m(),
569 CkOutSrc::Hxtal => w.ckoutsel().hxtal(),
570 CkOutSrc::Pll(d) => {
571 let w = w.ckoutsel().pll();
572 match d {
573 PllDiv::Div1 => w.plldv().div1(),
574 PllDiv::Div2 => w.plldv().div2(),
575 }
576 }
577 }
578 });
579 }
580
581 pub fn enable_irc40k(&mut self) {
583 self.rcu.rstsck().modify(|_, w| w.irc40ken().on());
584 while self.rcu.rstsck().read().irc40kstb().is_not_ready() {}
585 }
586 pub fn disable_irc40k(&mut self) {
590 self.rcu.rstsck().modify(|_, w| w.irc40ken().off());
591 }
592
593 pub fn enable_cfgcmp(&mut self) {
597 self.rcu.apb2en().modify(|_, w| w.cfgcmpen().enabled());
598 }
599 pub fn disable_cfgcmp(&mut self) {
603 self.rcu.apb2en().modify(|_, w| w.cfgcmpen().disabled());
604 }
605 pub fn reset_cfgcmp(&mut self) {
610 self.rcu.apb2rst().modify(|_, w| w.cfgcmprst().reset());
611 self.rcu.apb2rst().modify(|_, w| w.cfgcmprst().clear_bit());
612 }
613
614 pub fn reset_flag(&self, flag: ResetFlag) -> bool {
618 let rstsck = self.rcu.rstsck().read();
619 match flag {
620 ResetFlag::LowPower => rstsck.lprstf().is_reset(),
621 ResetFlag::WindowWatchdog => rstsck.wwdgtrstf().is_reset(),
622 ResetFlag::FreeWatchdog => rstsck.fwdgtrstf().is_reset(),
623 ResetFlag::Software => rstsck.swrstf().is_reset(),
624 ResetFlag::Power => rstsck.porrstf().is_reset(),
625 ResetFlag::ExternalPin => rstsck.eprstf().is_reset(),
626 ResetFlag::OptionByteLoader => rstsck.oblrstf().is_reset(),
627 }
628 }
629 pub fn clear_reset_flags(&mut self) {
634 self.rcu.rstsck().modify(|_, w| w.rstfc().clear());
635 }
636}
637
638pub trait RcuExt {
640 fn constrain(self) -> UnfrozenRcu;
643}
644
645impl RcuExt for pac::Rcu {
646 fn constrain(self) -> UnfrozenRcu {
647 UnfrozenRcu { rcu: self }
648 }
649}
650
651pub trait Enable {
653 fn enable(rcu: &mut Rcu);
655 fn disable(rcu: &mut Rcu);
657}
658
659pub trait Reset {
661 fn reset(rcu: &mut Rcu);
663}
664
665macro_rules! bus_en {
666 ($($Periph:ty => $en_reg:ident, $en_bit:ident,)+) => {
667 $(
668 impl Enable for $Periph {
669 fn enable(rcu: &mut Rcu) {
670 rcu.rcu.$en_reg().modify(|_, w| w.$en_bit().enabled());
671 }
672 fn disable(rcu: &mut Rcu) {
673 rcu.rcu.$en_reg().modify(|_, w| w.$en_bit().disabled());
674 }
675 }
676 )+
677 };
678}
679
680macro_rules! bus_rst {
681 ($($Periph:ty => $rst_reg:ident, $rst_bit:ident,)+) => {
682 $(
683 impl Reset for $Periph {
684 fn reset(rcu: &mut Rcu) {
685 rcu.rcu.$rst_reg().modify(|_, w| w.$rst_bit().reset());
686 rcu.rcu.$rst_reg().modify(|_, w| w.$rst_bit().clear_bit());
687 }
688 }
689 )+
690 };
691}
692
693bus_en! {
694 pac::Gpioa => ahben, paen,
695 pac::Gpiob => ahben, pben,
696 pac::Gpiof => ahben, pfen,
697 pac::Dma => ahben, dmaen,
698 pac::Crc => ahben, crcen,
699 pac::Usart1 => apb1en, usart1en,
700 pac::Spi1 => apb1en, spi1en,
701 pac::Timer2 => apb1en, timer2en,
702 pac::Timer5 => apb1en, timer5en,
703 pac::Timer13 => apb1en, timer13en,
704 pac::I2c0 => apb1en, i2c0en,
705 pac::I2c1 => apb1en, i2c1en,
706 pac::Wwdgt => apb1en, wwdgten,
707 pac::Usart0 => apb2en, usart0en,
708 pac::Adc => apb2en, adcen,
709 pac::Spi0 => apb2en, spi0en,
710 pac::Timer0 => apb2en, timer0en,
711 pac::Timer15 => apb2en, timer15en,
712 pac::Timer16 => apb2en, timer16en,
713}
714
715#[cfg(has_timer14)]
718bus_en! {
719 pac::Timer14 => apb2en, timer14en,
720}
721
722#[cfg(pads_ge_48)]
724bus_en! {
725 pac::Gpioc => ahben, pcen,
726}
727
728bus_rst! {
729 pac::Gpioa => ahbrst, parst,
730 pac::Gpiob => ahbrst, pbrst,
731 pac::Gpiof => ahbrst, pfrst,
732 pac::Usart1 => apb1rst, usart1rst,
733 pac::Spi1 => apb1rst, spi1rst,
734 pac::Timer2 => apb1rst, timer2rst,
735 pac::Timer5 => apb1rst, timer5rst,
736 pac::Timer13 => apb1rst, timer13rst,
737 pac::I2c0 => apb1rst, i2c0rst,
738 pac::I2c1 => apb1rst, i2c1rst,
739 pac::Wwdgt => apb1rst, wwdgtrst,
740 pac::Usart0 => apb2rst, usart0rst,
741 pac::Adc => apb2rst, adcrst,
742 pac::Spi0 => apb2rst, spi0rst,
743 pac::Timer0 => apb2rst, timer0rst,
744 pac::Timer15 => apb2rst, timer15rst,
745 pac::Timer16 => apb2rst, timer16rst,
746}
747
748#[cfg(has_timer14)]
749bus_rst! {
750 pac::Timer14 => apb2rst, timer14rst,
751}
752
753#[cfg(pads_ge_48)]
754bus_rst! {
755 pac::Gpioc => ahbrst, pcrst,
756}