aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-macros/src/lib.rs6
-rw-r--r--embassy-stm32/src/dbgmcu/mod.rs13
-rw-r--r--embassy-stm32/src/lib.rs12
-rw-r--r--embassy-stm32/src/pwr/f3.rs1
-rw-r--r--embassy-stm32/src/pwr/f4.rs1
-rw-r--r--embassy-stm32/src/pwr/f7.rs1
-rw-r--r--embassy-stm32/src/pwr/g0.rs1
-rw-r--r--embassy-stm32/src/pwr/g4.rs1
-rw-r--r--embassy-stm32/src/pwr/h7.rs78
-rw-r--r--embassy-stm32/src/pwr/l1.rs1
-rw-r--r--embassy-stm32/src/pwr/mod.rs12
-rw-r--r--embassy-stm32/src/pwr/u5.rs32
-rw-r--r--embassy-stm32/src/pwr/wl5.rs1
-rw-r--r--embassy-stm32/src/rcc/f0.rs174
-rw-r--r--embassy-stm32/src/rcc/f0/mod.rs208
-rw-r--r--embassy-stm32/src/rcc/f1.rs179
-rw-r--r--embassy-stm32/src/rcc/f1/mod.rs214
-rw-r--r--embassy-stm32/src/rcc/f3.rs331
-rw-r--r--embassy-stm32/src/rcc/f3/mod.rs374
-rw-r--r--embassy-stm32/src/rcc/f4.rs288
-rw-r--r--embassy-stm32/src/rcc/f4/max.rs21
-rw-r--r--embassy-stm32/src/rcc/f4/mod.rs311
-rw-r--r--embassy-stm32/src/rcc/f7.rs321
-rw-r--r--embassy-stm32/src/rcc/f7/max.rs19
-rw-r--r--embassy-stm32/src/rcc/f7/mod.rs347
-rw-r--r--embassy-stm32/src/rcc/g0.rs183
-rw-r--r--embassy-stm32/src/rcc/g0/mod.rs234
-rw-r--r--embassy-stm32/src/rcc/g4.rs161
-rw-r--r--embassy-stm32/src/rcc/g4/mod.rs210
-rw-r--r--embassy-stm32/src/rcc/h7.rs875
-rw-r--r--embassy-stm32/src/rcc/h7/mod.rs702
-rw-r--r--embassy-stm32/src/rcc/h7/pll.rs145
-rw-r--r--embassy-stm32/src/rcc/l0.rs362
-rw-r--r--embassy-stm32/src/rcc/l0/mod.rs437
-rw-r--r--embassy-stm32/src/rcc/l1.rs321
-rw-r--r--embassy-stm32/src/rcc/l1/mod.rs261
-rw-r--r--embassy-stm32/src/rcc/l4.rs429
-rw-r--r--embassy-stm32/src/rcc/l4/mod.rs489
-rw-r--r--embassy-stm32/src/rcc/mod.rs69
-rw-r--r--embassy-stm32/src/rcc/u5.rs (renamed from embassy-stm32/src/rcc/u5/mod.rs)388
-rw-r--r--embassy-stm32/src/rcc/wb.rs167
-rw-r--r--embassy-stm32/src/rcc/wb/mod.rs213
-rw-r--r--embassy-stm32/src/rcc/wl5.rs189
-rw-r--r--embassy-stm32/src/rcc/wl5x/mod.rs236
-rw-r--r--examples/stm32l0/src/bin/button_exti.rs14
-rw-r--r--examples/stm32l0/src/bin/lorawan.rs12
-rw-r--r--examples/stm32wl55/src/bin/lorawan.rs13
-rw-r--r--examples/stm32wl55/src/bin/subghz.rs5
m---------stm32-data0
-rw-r--r--tests/stm32/link_ram.x2
50 files changed, 4208 insertions, 4856 deletions
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index cdbc25179..44a8d3b93 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -370,16 +370,14 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
370 ::core::mem::transmute(t) 370 ::core::mem::transmute(t)
371 } 371 }
372 372
373 let mut executor = #embassy_path::executor::Executor::new(); 373 #chip_setup
374 374
375 let mut executor = #embassy_path::executor::Executor::new();
375 let executor = unsafe { make_static(&mut executor) }; 376 let executor = unsafe { make_static(&mut executor) };
376 377
377 #chip_setup
378
379 executor.run(|spawner| { 378 executor.run(|spawner| {
380 spawner.must_spawn(__embassy_main(spawner, p)); 379 spawner.must_spawn(__embassy_main(spawner, p));
381 }) 380 })
382
383 } 381 }
384 }; 382 };
385 result.into() 383 result.into()
diff --git a/embassy-stm32/src/dbgmcu/mod.rs b/embassy-stm32/src/dbgmcu/mod.rs
deleted file mode 100644
index 8dc4cc53f..000000000
--- a/embassy-stm32/src/dbgmcu/mod.rs
+++ /dev/null
@@ -1,13 +0,0 @@
1pub struct Dbgmcu {}
2
3impl Dbgmcu {
4 pub unsafe fn enable_all() {
5 crate::pac::DBGMCU.cr().modify(|cr| {
6 crate::pac::dbgmcu! {
7 (cr, $fn_name:ident) => {
8 cr.$fn_name(true);
9 };
10 }
11 });
12 }
13}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index c8a0e1705..bcd9bd5c1 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -29,8 +29,6 @@ pub mod adc;
29pub mod can; 29pub mod can;
30#[cfg(dac)] 30#[cfg(dac)]
31pub mod dac; 31pub mod dac;
32#[cfg(dbgmcu)]
33pub mod dbgmcu;
34#[cfg(dcmi)] 32#[cfg(dcmi)]
35pub mod dcmi; 33pub mod dcmi;
36#[cfg(all(eth, feature = "net"))] 34#[cfg(all(eth, feature = "net"))]
@@ -43,8 +41,6 @@ pub mod i2c;
43#[cfg(crc)] 41#[cfg(crc)]
44pub mod crc; 42pub mod crc;
45pub mod pwm; 43pub mod pwm;
46#[cfg(pwr)]
47pub mod pwr;
48#[cfg(rng)] 44#[cfg(rng)]
49pub mod rng; 45pub mod rng;
50#[cfg(sdmmc)] 46#[cfg(sdmmc)]
@@ -92,7 +88,13 @@ pub fn init(config: Config) -> Peripherals {
92 88
93 unsafe { 89 unsafe {
94 if config.enable_debug_during_sleep { 90 if config.enable_debug_during_sleep {
95 dbgmcu::Dbgmcu::enable_all(); 91 crate::pac::DBGMCU.cr().modify(|cr| {
92 crate::pac::dbgmcu! {
93 (cr, $fn_name:ident) => {
94 cr.$fn_name(true);
95 };
96 }
97 });
96 } 98 }
97 99
98 gpio::init(); 100 gpio::init();
diff --git a/embassy-stm32/src/pwr/f3.rs b/embassy-stm32/src/pwr/f3.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/f3.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/pwr/f4.rs b/embassy-stm32/src/pwr/f4.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/f4.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/pwr/f7.rs b/embassy-stm32/src/pwr/f7.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/f7.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/pwr/g0.rs b/embassy-stm32/src/pwr/g0.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/g0.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/pwr/g4.rs b/embassy-stm32/src/pwr/g4.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/g4.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/pwr/h7.rs b/embassy-stm32/src/pwr/h7.rs
deleted file mode 100644
index 37b049a85..000000000
--- a/embassy-stm32/src/pwr/h7.rs
+++ /dev/null
@@ -1,78 +0,0 @@
1use crate::pac::{PWR, RCC, SYSCFG};
2use crate::peripherals;
3
4/// Voltage Scale
5///
6/// Represents the voltage range feeding the CPU core. The maximum core
7/// clock frequency depends on this value.
8#[derive(Copy, Clone, PartialEq)]
9pub enum VoltageScale {
10 /// VOS 0 range VCORE 1.26V - 1.40V
11 Scale0,
12 /// VOS 1 range VCORE 1.15V - 1.26V
13 Scale1,
14 /// VOS 2 range VCORE 1.05V - 1.15V
15 Scale2,
16 /// VOS 3 range VCORE 0.95V - 1.05V
17 Scale3,
18}
19
20/// Power Configuration
21///
22/// Generated when the PWR peripheral is frozen. The existence of this
23/// value indicates that the voltage scaling configuration can no
24/// longer be changed.
25pub struct Power {
26 pub(crate) vos: VoltageScale,
27}
28
29impl Power {
30 pub fn new(_peri: peripherals::PWR, enable_overdrive: bool) -> Self {
31 // NOTE(unsafe) we have the PWR singleton
32 unsafe {
33 // NB. The lower bytes of CR3 can only be written once after
34 // POR, and must be written with a valid combination. Refer to
35 // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
36 // `self` at the end of this method, but of course we cannot
37 // know what happened between the previous POR and here.
38 #[cfg(pwr_h7)]
39 PWR.cr3().modify(|w| {
40 w.set_scuen(true);
41 w.set_ldoen(true);
42 w.set_bypass(false);
43 });
44
45 #[cfg(pwr_h7smps)]
46 PWR.cr3().modify(|w| {
47 // hardcode "Direct SPMS" for now, this is what works on nucleos with the
48 // default solderbridge configuration.
49 w.set_sden(true);
50 w.set_ldoen(false);
51 });
52
53 // Validate the supply configuration. If you are stuck here, it is
54 // because the voltages on your board do not match those specified
55 // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
56 // VOS = Scale 3, so check that the voltage on the VCAP pins =
57 // 1.0V.
58 while !PWR.csr1().read().actvosrdy() {}
59
60 // Go to Scale 1
61 PWR.d3cr().modify(|w| w.set_vos(0b11));
62 while !PWR.d3cr().read().vosrdy() {}
63
64 let vos = if !enable_overdrive {
65 VoltageScale::Scale1
66 } else {
67 critical_section::with(|_| {
68 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
69
70 SYSCFG.pwrcr().modify(|w| w.set_oden(1));
71 });
72 while !PWR.d3cr().read().vosrdy() {}
73 VoltageScale::Scale0
74 };
75 Self { vos }
76 }
77 }
78}
diff --git a/embassy-stm32/src/pwr/l1.rs b/embassy-stm32/src/pwr/l1.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/l1.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/pwr/mod.rs b/embassy-stm32/src/pwr/mod.rs
deleted file mode 100644
index 18f462bd2..000000000
--- a/embassy-stm32/src/pwr/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
1#[cfg_attr(any(pwr_h7, pwr_h7smps), path = "h7.rs")]
2#[cfg_attr(pwr_f3, path = "f3.rs")]
3#[cfg_attr(pwr_f4, path = "f4.rs")]
4#[cfg_attr(pwr_f7, path = "f7.rs")]
5#[cfg_attr(pwr_wl5, path = "wl5.rs")]
6#[cfg_attr(pwr_g0, path = "g0.rs")]
7#[cfg_attr(pwr_g4, path = "g4.rs")]
8#[cfg_attr(pwr_l1, path = "l1.rs")]
9#[cfg_attr(pwr_u5, path = "u5.rs")]
10mod _version;
11
12pub use _version::*;
diff --git a/embassy-stm32/src/pwr/u5.rs b/embassy-stm32/src/pwr/u5.rs
deleted file mode 100644
index a90659d9c..000000000
--- a/embassy-stm32/src/pwr/u5.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1use crate::peripherals;
2
3/// Voltage Scale
4///
5/// Represents the voltage range feeding the CPU core. The maximum core
6/// clock frequency depends on this value.
7#[derive(Copy, Clone, PartialEq)]
8pub enum VoltageScale {
9 // Highest frequency
10 Range1,
11 Range2,
12 Range3,
13 // Lowest power
14 Range4,
15}
16
17/// Power Configuration
18///
19/// Generated when the PWR peripheral is frozen. The existence of this
20/// value indicates that the voltage scaling configuration can no
21/// longer be changed.
22pub struct Power {
23 pub(crate) vos: VoltageScale,
24}
25
26impl Power {
27 pub fn new(_peri: peripherals::PWR) -> Self {
28 Self {
29 vos: VoltageScale::Range4,
30 }
31 }
32}
diff --git a/embassy-stm32/src/pwr/wl5.rs b/embassy-stm32/src/pwr/wl5.rs
deleted file mode 100644
index 8b1378917..000000000
--- a/embassy-stm32/src/pwr/wl5.rs
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
new file mode 100644
index 000000000..1527afa05
--- /dev/null
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -0,0 +1,174 @@
1use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
2use crate::pac::{FLASH, RCC};
3use crate::time::Hertz;
4
5use super::{set_freqs, Clocks};
6
7const HSI: u32 = 8_000_000;
8
9/// Configuration of the clocks
10///
11/// hse takes precedence over hsi48 if both are enabled
12#[non_exhaustive]
13#[derive(Default)]
14pub struct Config {
15 pub hse: Option<Hertz>,
16 pub bypass_hse: bool,
17 pub usb_pll: bool,
18
19 #[cfg(rcc_f0)]
20 pub hsi48: bool,
21
22 pub sys_ck: Option<Hertz>,
23 pub hclk: Option<Hertz>,
24 pub pclk: Option<Hertz>,
25}
26
27pub(crate) unsafe fn init(config: Config) {
28 let sysclk = config.sys_ck.map(|v| v.0).unwrap_or(HSI);
29
30 let (src_clk, use_hsi48) = config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
31 #[cfg(rcc_f0)]
32 if config.hsi48 {
33 return (48_000_000, true);
34 }
35 (HSI, false)
36 });
37
38 let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
39 (None, sysclk)
40 } else {
41 let prediv = if config.hse.is_some() { 1 } else { 2 };
42 let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
43 let pllmul = pllmul.max(2).min(16);
44
45 let pllmul_bits = pllmul as u8 - 2;
46 let real_sysclk = pllmul * src_clk / prediv;
47 (Some(pllmul_bits), real_sysclk)
48 };
49
50 let hpre_bits = config
51 .hclk
52 .map(|hclk| match real_sysclk / hclk.0 {
53 0 => unreachable!(),
54 1 => 0b0111,
55 2 => 0b1000,
56 3..=5 => 0b1001,
57 6..=11 => 0b1010,
58 12..=39 => 0b1011,
59 40..=95 => 0b1100,
60 96..=191 => 0b1101,
61 192..=383 => 0b1110,
62 _ => 0b1111,
63 })
64 .unwrap_or(0b0111);
65 let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
66
67 let ppre_bits = config
68 .pclk
69 .map(|pclk| match hclk / pclk.0 {
70 0 => unreachable!(),
71 1 => 0b011,
72 2 => 0b100,
73 3..=5 => 0b101,
74 6..=11 => 0b110,
75 _ => 0b111,
76 })
77 .unwrap_or(0b011);
78
79 let ppre: u8 = 1 << (ppre_bits - 0b011);
80 let pclk = hclk / u32::from(ppre);
81
82 let timer_mul = if ppre == 1 { 1 } else { 2 };
83
84 FLASH.acr().write(|w| {
85 let latency = if real_sysclk <= 24_000_000 {
86 0
87 } else if real_sysclk <= 48_000_000 {
88 1
89 } else {
90 2
91 };
92 w.latency().0 = latency;
93 });
94
95 match (config.hse.is_some(), use_hsi48) {
96 (true, _) => {
97 RCC.cr().modify(|w| {
98 w.set_csson(true);
99 w.set_hseon(true);
100
101 if config.bypass_hse {
102 w.set_hsebyp(Hsebyp::BYPASSED);
103 }
104 });
105 while !RCC.cr().read().hserdy() {}
106
107 if pllmul_bits.is_some() {
108 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
109 }
110 }
111 (false, true) => {
112 // use_hsi48 will always be false for rcc_f0x0
113 #[cfg(rcc_f0)]
114 RCC.cr2().modify(|w| w.set_hsi48on(true));
115 #[cfg(rcc_f0)]
116 while !RCC.cr2().read().hsi48rdy() {}
117
118 #[cfg(rcc_f0)]
119 if pllmul_bits.is_some() {
120 RCC.cfgr()
121 .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
122 }
123 }
124 _ => {
125 RCC.cr().modify(|w| w.set_hsion(true));
126 while !RCC.cr().read().hsirdy() {}
127
128 if pllmul_bits.is_some() {
129 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
130 }
131 }
132 }
133
134 if config.usb_pll {
135 RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
136 }
137 // TODO: Option to use CRS (Clock Recovery)
138
139 if let Some(pllmul_bits) = pllmul_bits {
140 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
141
142 RCC.cr().modify(|w| w.set_pllon(true));
143 while !RCC.cr().read().pllrdy() {}
144
145 RCC.cfgr().modify(|w| {
146 w.set_ppre(Ppre(ppre_bits));
147 w.set_hpre(Hpre(hpre_bits));
148 w.set_sw(Sw::PLL)
149 });
150 } else {
151 RCC.cfgr().modify(|w| {
152 w.set_ppre(Ppre(ppre_bits));
153 w.set_hpre(Hpre(hpre_bits));
154
155 if config.hse.is_some() {
156 w.set_sw(Sw::HSE);
157 } else if use_hsi48 {
158 #[cfg(rcc_f0)]
159 w.set_sw(Sw::HSI48);
160 } else {
161 w.set_sw(Sw::HSI)
162 }
163 })
164 }
165
166 set_freqs(Clocks {
167 sys: Hertz(real_sysclk),
168 apb1: Hertz(pclk),
169 apb2: Hertz(pclk),
170 apb1_tim: Hertz(pclk * timer_mul),
171 apb2_tim: Hertz(pclk * timer_mul),
172 ahb: Hertz(hclk),
173 });
174}
diff --git a/embassy-stm32/src/rcc/f0/mod.rs b/embassy-stm32/src/rcc/f0/mod.rs
deleted file mode 100644
index 916ed39fc..000000000
--- a/embassy-stm32/src/rcc/f0/mod.rs
+++ /dev/null
@@ -1,208 +0,0 @@
1use core::marker::PhantomData;
2
3use embassy::util::Unborrow;
4
5use crate::pac::{FLASH, RCC};
6use crate::peripherals;
7use crate::time::Hertz;
8
9use super::{set_freqs, Clocks};
10
11const HSI: u32 = 8_000_000;
12
13/// Configuration of the clocks
14///
15/// hse takes precedence over hsi48 if both are enabled
16#[non_exhaustive]
17#[derive(Default)]
18pub struct Config {
19 pub hse: Option<Hertz>,
20 pub bypass_hse: bool,
21 pub usb_pll: bool,
22
23 #[cfg(rcc_f0)]
24 pub hsi48: bool,
25
26 pub sys_ck: Option<Hertz>,
27 pub hclk: Option<Hertz>,
28 pub pclk: Option<Hertz>,
29}
30
31pub struct Rcc<'d> {
32 inner: PhantomData<&'d ()>,
33 config: Config,
34}
35
36impl<'d> Rcc<'d> {
37 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
38 Self {
39 inner: PhantomData,
40 config,
41 }
42 }
43
44 pub fn freeze(self) -> Clocks {
45 use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
46
47 let sysclk = self.config.sys_ck.map(|v| v.0).unwrap_or(HSI);
48
49 let (src_clk, use_hsi48) = self.config.hse.map(|v| (v.0, false)).unwrap_or_else(|| {
50 #[cfg(rcc_f0)]
51 if self.config.hsi48 {
52 return (48_000_000, true);
53 }
54 (HSI, false)
55 });
56
57 let (pllmul_bits, real_sysclk) = if sysclk == src_clk {
58 (None, sysclk)
59 } else {
60 let prediv = if self.config.hse.is_some() { 1 } else { 2 };
61 let pllmul = (2 * prediv * sysclk + src_clk) / src_clk / 2;
62 let pllmul = pllmul.max(2).min(16);
63
64 let pllmul_bits = pllmul as u8 - 2;
65 let real_sysclk = pllmul * src_clk / prediv;
66 (Some(pllmul_bits), real_sysclk)
67 };
68
69 let hpre_bits = self
70 .config
71 .hclk
72 .map(|hclk| match real_sysclk / hclk.0 {
73 0 => unreachable!(),
74 1 => 0b0111,
75 2 => 0b1000,
76 3..=5 => 0b1001,
77 6..=11 => 0b1010,
78 12..=39 => 0b1011,
79 40..=95 => 0b1100,
80 96..=191 => 0b1101,
81 192..=383 => 0b1110,
82 _ => 0b1111,
83 })
84 .unwrap_or(0b0111);
85 let hclk = real_sysclk / (1 << (hpre_bits - 0b0111));
86
87 let ppre_bits = self
88 .config
89 .pclk
90 .map(|pclk| match hclk / pclk.0 {
91 0 => unreachable!(),
92 1 => 0b011,
93 2 => 0b100,
94 3..=5 => 0b101,
95 6..=11 => 0b110,
96 _ => 0b111,
97 })
98 .unwrap_or(0b011);
99
100 let ppre: u8 = 1 << (ppre_bits - 0b011);
101 let pclk = hclk / u32::from(ppre);
102
103 let timer_mul = if ppre == 1 { 1 } else { 2 };
104
105 // NOTE(safety) Atomic write
106 unsafe {
107 FLASH.acr().write(|w| {
108 let latency = if real_sysclk <= 24_000_000 {
109 0
110 } else if real_sysclk <= 48_000_000 {
111 1
112 } else {
113 2
114 };
115 w.latency().0 = latency;
116 });
117 }
118
119 // NOTE(unsafe) We have exclusive access to the RCC
120 unsafe {
121 match (self.config.hse.is_some(), use_hsi48) {
122 (true, _) => {
123 RCC.cr().modify(|w| {
124 w.set_csson(true);
125 w.set_hseon(true);
126
127 if self.config.bypass_hse {
128 w.set_hsebyp(Hsebyp::BYPASSED);
129 }
130 });
131 while !RCC.cr().read().hserdy() {}
132
133 if pllmul_bits.is_some() {
134 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSE_DIV_PREDIV))
135 }
136 }
137 (false, true) => {
138 // use_hsi48 will always be false for rcc_f0x0
139 #[cfg(rcc_f0)]
140 RCC.cr2().modify(|w| w.set_hsi48on(true));
141 #[cfg(rcc_f0)]
142 while !RCC.cr2().read().hsi48rdy() {}
143
144 #[cfg(rcc_f0)]
145 if pllmul_bits.is_some() {
146 RCC.cfgr()
147 .modify(|w| w.set_pllsrc(Pllsrc::HSI48_DIV_PREDIV))
148 }
149 }
150 _ => {
151 RCC.cr().modify(|w| w.set_hsion(true));
152 while !RCC.cr().read().hsirdy() {}
153
154 if pllmul_bits.is_some() {
155 RCC.cfgr().modify(|w| w.set_pllsrc(Pllsrc::HSI_DIV2))
156 }
157 }
158 }
159
160 if self.config.usb_pll {
161 RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
162 }
163 // TODO: Option to use CRS (Clock Recovery)
164
165 if let Some(pllmul_bits) = pllmul_bits {
166 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
167
168 RCC.cr().modify(|w| w.set_pllon(true));
169 while !RCC.cr().read().pllrdy() {}
170
171 RCC.cfgr().modify(|w| {
172 w.set_ppre(Ppre(ppre_bits));
173 w.set_hpre(Hpre(hpre_bits));
174 w.set_sw(Sw::PLL)
175 });
176 } else {
177 RCC.cfgr().modify(|w| {
178 w.set_ppre(Ppre(ppre_bits));
179 w.set_hpre(Hpre(hpre_bits));
180
181 if self.config.hse.is_some() {
182 w.set_sw(Sw::HSE);
183 } else if use_hsi48 {
184 #[cfg(rcc_f0)]
185 w.set_sw(Sw::HSI48);
186 } else {
187 w.set_sw(Sw::HSI)
188 }
189 })
190 }
191 }
192
193 Clocks {
194 sys: Hertz(real_sysclk),
195 apb1: Hertz(pclk),
196 apb2: Hertz(pclk),
197 apb1_tim: Hertz(pclk * timer_mul),
198 apb2_tim: Hertz(pclk * timer_mul),
199 ahb: Hertz(hclk),
200 }
201 }
202}
203
204pub unsafe fn init(config: Config) {
205 let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
206 let clocks = rcc.freeze();
207 set_freqs(clocks);
208}
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
new file mode 100644
index 000000000..d44544d28
--- /dev/null
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -0,0 +1,179 @@
1use core::convert::TryFrom;
2
3use super::{set_freqs, Clocks};
4use crate::pac::flash::vals::Latency;
5use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre};
6use crate::pac::{FLASH, RCC};
7use crate::time::Hertz;
8
9const HSI: u32 = 8_000_000;
10
11/// Configuration of the clocks
12///
13#[non_exhaustive]
14#[derive(Default)]
15pub struct Config {
16 pub hse: Option<Hertz>,
17
18 pub sys_ck: Option<Hertz>,
19 pub hclk: Option<Hertz>,
20 pub pclk1: Option<Hertz>,
21 pub pclk2: Option<Hertz>,
22 pub adcclk: Option<Hertz>,
23}
24
25pub(crate) unsafe fn init(config: Config) {
26 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI / 2);
27 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
28 let pllmul = sysclk / pllsrcclk;
29
30 let (pllmul_bits, real_sysclk) = if pllmul == 1 {
31 (None, config.hse.map(|hse| hse.0).unwrap_or(HSI))
32 } else {
33 let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
34 (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
35 };
36
37 assert!(real_sysclk <= 72_000_000);
38
39 let hpre_bits = config
40 .hclk
41 .map(|hclk| match real_sysclk / hclk.0 {
42 0 => unreachable!(),
43 1 => 0b0111,
44 2 => 0b1000,
45 3..=5 => 0b1001,
46 6..=11 => 0b1010,
47 12..=39 => 0b1011,
48 40..=95 => 0b1100,
49 96..=191 => 0b1101,
50 192..=383 => 0b1110,
51 _ => 0b1111,
52 })
53 .unwrap_or(0b0111);
54
55 let hclk = if hpre_bits >= 0b1100 {
56 real_sysclk / (1 << (hpre_bits - 0b0110))
57 } else {
58 real_sysclk / (1 << (hpre_bits - 0b0111))
59 };
60
61 assert!(hclk <= 72_000_000);
62
63 let ppre1_bits = config
64 .pclk1
65 .map(|pclk1| match hclk / pclk1.0 {
66 0 => unreachable!(),
67 1 => 0b011,
68 2 => 0b100,
69 3..=5 => 0b101,
70 6..=11 => 0b110,
71 _ => 0b111,
72 })
73 .unwrap_or(0b011);
74
75 let ppre1 = 1 << (ppre1_bits - 0b011);
76 let pclk1 = hclk / u32::try_from(ppre1).unwrap();
77 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
78
79 assert!(pclk1 <= 36_000_000);
80
81 let ppre2_bits = config
82 .pclk2
83 .map(|pclk2| match hclk / pclk2.0 {
84 0 => unreachable!(),
85 1 => 0b011,
86 2 => 0b100,
87 3..=5 => 0b101,
88 6..=11 => 0b110,
89 _ => 0b111,
90 })
91 .unwrap_or(0b011);
92
93 let ppre2 = 1 << (ppre2_bits - 0b011);
94 let pclk2 = hclk / u32::try_from(ppre2).unwrap();
95 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
96
97 assert!(pclk2 <= 72_000_000);
98
99 // Only needed for stm32f103?
100 FLASH.acr().write(|w| {
101 w.set_latency(if real_sysclk <= 24_000_000 {
102 Latency(0b000)
103 } else if real_sysclk <= 48_000_000 {
104 Latency(0b001)
105 } else {
106 Latency(0b010)
107 });
108 });
109
110 // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
111 // PLL output frequency is a supported one.
112 // usbpre == false: divide clock by 1.5, otherwise no division
113 let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) {
114 (Some(_), Some(_), 72_000_000) => (false, true),
115 (Some(_), Some(_), 48_000_000) => (true, true),
116 _ => (true, false),
117 };
118
119 let apre_bits: u8 = config
120 .adcclk
121 .map(|adcclk| match pclk2 / adcclk.0 {
122 0..=2 => 0b00,
123 3..=4 => 0b01,
124 5..=7 => 0b10,
125 _ => 0b11,
126 })
127 .unwrap_or(0b11);
128
129 let apre = (apre_bits + 1) << 1;
130 let adcclk = pclk2 / unwrap!(u32::try_from(apre));
131
132 assert!(adcclk <= 14_000_000);
133
134 if config.hse.is_some() {
135 // enable HSE and wait for it to be ready
136 RCC.cr().modify(|w| w.set_hseon(true));
137 while !RCC.cr().read().hserdy() {}
138 }
139
140 if let Some(pllmul_bits) = pllmul_bits {
141 // enable PLL and wait for it to be ready
142 RCC.cfgr().modify(|w| {
143 w.set_pllmul(Pllmul(pllmul_bits));
144 w.set_pllsrc(Pllsrc(config.hse.is_some() as u8));
145 });
146
147 RCC.cr().modify(|w| w.set_pllon(true));
148 while !RCC.cr().read().pllrdy() {}
149 }
150
151 // Only needed for stm32f103?
152 RCC.cfgr().modify(|w| {
153 w.set_adcpre(Adcpre(apre_bits));
154 w.set_ppre2(Ppre1(ppre2_bits));
155 w.set_ppre1(Ppre1(ppre1_bits));
156 w.set_hpre(Hpre(hpre_bits));
157 w.set_usbpre(Usbpre(usbpre as u8));
158 w.set_sw(Sw(if pllmul_bits.is_some() {
159 // PLL
160 0b10
161 } else if config.hse.is_some() {
162 // HSE
163 0b1
164 } else {
165 // HSI
166 0b0
167 }));
168 });
169
170 set_freqs(Clocks {
171 sys: Hertz(real_sysclk),
172 apb1: Hertz(pclk1),
173 apb2: Hertz(pclk2),
174 apb1_tim: Hertz(pclk1 * timer_mul1),
175 apb2_tim: Hertz(pclk2 * timer_mul2),
176 ahb: Hertz(hclk),
177 adc: Hertz(adcclk),
178 });
179}
diff --git a/embassy-stm32/src/rcc/f1/mod.rs b/embassy-stm32/src/rcc/f1/mod.rs
deleted file mode 100644
index d613f5a2f..000000000
--- a/embassy-stm32/src/rcc/f1/mod.rs
+++ /dev/null
@@ -1,214 +0,0 @@
1use core::convert::TryFrom;
2use core::marker::PhantomData;
3
4use embassy::util::Unborrow;
5
6use crate::pac::flash::vals::Latency;
7use crate::pac::{FLASH, RCC};
8use crate::peripherals;
9use crate::time::Hertz;
10
11use super::{set_freqs, Clocks};
12
13const HSI: u32 = 8_000_000;
14
15/// Configuration of the clocks
16///
17#[non_exhaustive]
18#[derive(Default)]
19pub struct Config {
20 pub hse: Option<Hertz>,
21
22 pub sys_ck: Option<Hertz>,
23 pub hclk: Option<Hertz>,
24 pub pclk1: Option<Hertz>,
25 pub pclk2: Option<Hertz>,
26 pub adcclk: Option<Hertz>,
27}
28
29pub struct Rcc<'d> {
30 inner: PhantomData<&'d ()>,
31 config: Config,
32}
33
34impl<'d> Rcc<'d> {
35 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
36 Self {
37 inner: PhantomData,
38 config,
39 }
40 }
41
42 pub fn freeze(self) -> Clocks {
43 use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre};
44
45 let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI / 2);
46 let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
47 let pllmul = sysclk / pllsrcclk;
48
49 let (pllmul_bits, real_sysclk) = if pllmul == 1 {
50 (None, self.config.hse.map(|hse| hse.0).unwrap_or(HSI))
51 } else {
52 let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16);
53 (Some(pllmul as u8 - 2), pllsrcclk * pllmul)
54 };
55
56 assert!(real_sysclk <= 72_000_000);
57
58 let hpre_bits = self
59 .config
60 .hclk
61 .map(|hclk| match real_sysclk / hclk.0 {
62 0 => unreachable!(),
63 1 => 0b0111,
64 2 => 0b1000,
65 3..=5 => 0b1001,
66 6..=11 => 0b1010,
67 12..=39 => 0b1011,
68 40..=95 => 0b1100,
69 96..=191 => 0b1101,
70 192..=383 => 0b1110,
71 _ => 0b1111,
72 })
73 .unwrap_or(0b0111);
74
75 let hclk = if hpre_bits >= 0b1100 {
76 real_sysclk / (1 << (hpre_bits - 0b0110))
77 } else {
78 real_sysclk / (1 << (hpre_bits - 0b0111))
79 };
80
81 assert!(hclk <= 72_000_000);
82
83 let ppre1_bits = self
84 .config
85 .pclk1
86 .map(|pclk1| match hclk / pclk1.0 {
87 0 => unreachable!(),
88 1 => 0b011,
89 2 => 0b100,
90 3..=5 => 0b101,
91 6..=11 => 0b110,
92 _ => 0b111,
93 })
94 .unwrap_or(0b011);
95
96 let ppre1 = 1 << (ppre1_bits - 0b011);
97 let pclk1 = hclk / u32::try_from(ppre1).unwrap();
98 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
99
100 assert!(pclk1 <= 36_000_000);
101
102 let ppre2_bits = self
103 .config
104 .pclk2
105 .map(|pclk2| match hclk / pclk2.0 {
106 0 => unreachable!(),
107 1 => 0b011,
108 2 => 0b100,
109 3..=5 => 0b101,
110 6..=11 => 0b110,
111 _ => 0b111,
112 })
113 .unwrap_or(0b011);
114
115 let ppre2 = 1 << (ppre2_bits - 0b011);
116 let pclk2 = hclk / u32::try_from(ppre2).unwrap();
117 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
118
119 assert!(pclk2 <= 72_000_000);
120
121 // Only needed for stm32f103?
122 // NOTE(safety) Atomic write
123 unsafe {
124 FLASH.acr().write(|w| {
125 w.set_latency(if real_sysclk <= 24_000_000 {
126 Latency(0b000)
127 } else if real_sysclk <= 48_000_000 {
128 Latency(0b001)
129 } else {
130 Latency(0b010)
131 });
132 })
133 }
134
135 // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
136 // PLL output frequency is a supported one.
137 // usbpre == false: divide clock by 1.5, otherwise no division
138 let (usbpre, _usbclk_valid) = match (self.config.hse, pllmul_bits, real_sysclk) {
139 (Some(_), Some(_), 72_000_000) => (false, true),
140 (Some(_), Some(_), 48_000_000) => (true, true),
141 _ => (true, false),
142 };
143
144 let apre_bits: u8 = self
145 .config
146 .adcclk
147 .map(|adcclk| match pclk2 / adcclk.0 {
148 0..=2 => 0b00,
149 3..=4 => 0b01,
150 5..=7 => 0b10,
151 _ => 0b11,
152 })
153 .unwrap_or(0b11);
154
155 let apre = (apre_bits + 1) << 1;
156 let adcclk = pclk2 / unwrap!(u32::try_from(apre));
157
158 assert!(adcclk <= 14_000_000);
159
160 unsafe {
161 if self.config.hse.is_some() {
162 // enable HSE and wait for it to be ready
163 RCC.cr().modify(|w| w.set_hseon(true));
164 while !RCC.cr().read().hserdy() {}
165 }
166
167 if let Some(pllmul_bits) = pllmul_bits {
168 // enable PLL and wait for it to be ready
169 RCC.cfgr().modify(|w| {
170 w.set_pllmul(Pllmul(pllmul_bits));
171 w.set_pllsrc(Pllsrc(self.config.hse.is_some() as u8));
172 });
173
174 RCC.cr().modify(|w| w.set_pllon(true));
175 while !RCC.cr().read().pllrdy() {}
176 }
177
178 // Only needed for stm32f103?
179 RCC.cfgr().modify(|w| {
180 w.set_adcpre(Adcpre(apre_bits));
181 w.set_ppre2(Ppre1(ppre2_bits));
182 w.set_ppre1(Ppre1(ppre1_bits));
183 w.set_hpre(Hpre(hpre_bits));
184 w.set_usbpre(Usbpre(usbpre as u8));
185 w.set_sw(Sw(if pllmul_bits.is_some() {
186 // PLL
187 0b10
188 } else if self.config.hse.is_some() {
189 // HSE
190 0b1
191 } else {
192 // HSI
193 0b0
194 }));
195 });
196 }
197
198 Clocks {
199 sys: Hertz(real_sysclk),
200 apb1: Hertz(pclk1),
201 apb2: Hertz(pclk2),
202 apb1_tim: Hertz(pclk1 * timer_mul1),
203 apb2_tim: Hertz(pclk2 * timer_mul2),
204 ahb: Hertz(hclk),
205 adc: Hertz(adcclk),
206 }
207 }
208}
209
210pub unsafe fn init(config: Config) {
211 let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
212 let clocks = rcc.freeze();
213 set_freqs(clocks);
214}
diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs
new file mode 100644
index 000000000..e16e1e499
--- /dev/null
+++ b/embassy-stm32/src/rcc/f3.rs
@@ -0,0 +1,331 @@
1use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
3use crate::pac::{FLASH, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz;
6
7const HSI: u32 = 8_000_000;
8
9/// Clocks configutation
10#[non_exhaustive]
11#[derive(Default)]
12pub struct Config {
13 /// Frequency of HSE oscillator
14 /// 4MHz to 32MHz
15 pub hse: Option<Hertz>,
16 /// Bypass HSE for an external clock
17 pub bypass_hse: bool,
18 /// Frequency of the System Clock
19 pub sysclk: Option<Hertz>,
20 /// Frequency of AHB bus
21 pub hclk: Option<Hertz>,
22 /// Frequency of APB1 bus
23 /// - Max frequency 36MHz
24 pub pclk1: Option<Hertz>,
25 /// Frequency of APB2 bus
26 /// - Max frequency with HSE is 72MHz
27 /// - Max frequency without HSE is 64MHz
28 pub pclk2: Option<Hertz>,
29 /// USB clock setup
30 /// It is valid only when,
31 /// - HSE is enabled,
32 /// - The System clock frequency is either 48MHz or 72MHz
33 /// - APB1 clock has a minimum frequency of 10MHz
34 pub pll48: bool,
35}
36
37// Information required to setup the PLL clock
38struct PllConfig {
39 pll_src: Pllsrc,
40 pll_mul: Pllmul,
41 pll_div: Option<Prediv>,
42}
43
44/// Initialize and Set the clock frequencies
45pub(crate) unsafe fn init(config: Config) {
46 // Calculate the real System clock, and PLL configuration if applicable
47 let (Hertz(sysclk), pll_config) = get_sysclk(&config);
48 assert!(sysclk <= 72_000_000);
49
50 // Calculate real AHB clock
51 let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
52 let (hpre_bits, hpre_div) = match sysclk / hclk {
53 0 => unreachable!(),
54 1 => (Hpre::DIV1, 1),
55 2 => (Hpre::DIV2, 2),
56 3..=5 => (Hpre::DIV4, 4),
57 6..=11 => (Hpre::DIV8, 8),
58 12..=39 => (Hpre::DIV16, 16),
59 40..=95 => (Hpre::DIV64, 64),
60 96..=191 => (Hpre::DIV128, 128),
61 192..=383 => (Hpre::DIV256, 256),
62 _ => (Hpre::DIV512, 512),
63 };
64 let hclk = sysclk / hpre_div;
65 assert!(hclk <= 72_000_000);
66
67 // Calculate real APB1 clock
68 let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk);
69 let (ppre1_bits, ppre1) = match hclk / pclk1 {
70 0 => unreachable!(),
71 1 => (Ppre::DIV1, 1),
72 2 => (Ppre::DIV2, 2),
73 3..=5 => (Ppre::DIV4, 4),
74 6..=11 => (Ppre::DIV8, 8),
75 _ => (Ppre::DIV16, 16),
76 };
77 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
78 let pclk1 = hclk / ppre1;
79 assert!(pclk1 <= 36_000_000);
80
81 // Calculate real APB2 clock
82 let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk);
83 let (ppre2_bits, ppre2) = match hclk / pclk2 {
84 0 => unreachable!(),
85 1 => (Ppre::DIV1, 1),
86 2 => (Ppre::DIV2, 2),
87 3..=5 => (Ppre::DIV4, 4),
88 6..=11 => (Ppre::DIV8, 8),
89 _ => (Ppre::DIV16, 16),
90 };
91 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
92 let pclk2 = hclk / ppre2;
93 assert!(pclk2 <= 72_000_000);
94
95 // Set latency based on HCLK frquency
96 FLASH.acr().write(|w| {
97 w.set_latency(if hclk <= 24_000_000 {
98 Latency::WS0
99 } else if hclk <= 48_000_000 {
100 Latency::WS1
101 } else {
102 Latency::WS2
103 });
104 });
105
106 // Enable HSE
107 if config.hse.is_some() {
108 RCC.cr().write(|w| {
109 w.set_hsebyp(if config.bypass_hse {
110 Hsebyp::BYPASSED
111 } else {
112 Hsebyp::NOTBYPASSED
113 });
114 // We turn on clock security to switch to HSI when HSE fails
115 w.set_csson(true);
116 w.set_hseon(true);
117 });
118 while !RCC.cr().read().hserdy() {}
119 }
120
121 // Enable PLL
122 if let Some(ref pll_config) = pll_config {
123 RCC.cfgr().write(|w| {
124 w.set_pllmul(pll_config.pll_mul);
125 w.set_pllsrc(pll_config.pll_src);
126 });
127 if let Some(pll_div) = pll_config.pll_div {
128 RCC.cfgr2().write(|w| w.set_prediv(pll_div));
129 }
130 RCC.cr().modify(|w| w.set_pllon(true));
131 while !RCC.cr().read().pllrdy() {}
132 }
133
134 if config.pll48 {
135 let usb_pre = get_usb_pre(&config, sysclk, pclk1, &pll_config);
136 RCC.cfgr().write(|w| {
137 w.set_usbpre(usb_pre);
138 });
139 }
140
141 // Set prescalers
142 RCC.cfgr().write(|w| {
143 w.set_ppre2(ppre2_bits);
144 w.set_ppre1(ppre1_bits);
145 w.set_hpre(hpre_bits);
146 });
147
148 // Wait for the new prescalers to kick in
149 // "The clocks are divided with the new prescaler factor from
150 // 1 to 16 AHB cycles after write"
151 cortex_m::asm::delay(16);
152
153 RCC.cfgr().write(|w| {
154 w.set_sw(match (pll_config, config.hse) {
155 (Some(_), _) => Sw::PLL,
156 (None, Some(_)) => Sw::HSE,
157 (None, None) => Sw::HSI,
158 })
159 });
160
161 set_freqs(Clocks {
162 sys: Hertz(sysclk),
163 apb1: Hertz(pclk1),
164 apb2: Hertz(pclk2),
165 apb1_tim: Hertz(pclk1 * timer_mul1),
166 apb2_tim: Hertz(pclk2 * timer_mul2),
167 ahb: Hertz(hclk),
168 });
169}
170
171#[inline]
172fn get_sysclk(config: &Config) -> (Hertz, Option<PllConfig>) {
173 match (config.sysclk, config.hse) {
174 (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
175 (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None),
176 // If the user selected System clock is different from HSI or HSE
177 // we will have to setup PLL clock source
178 (Some(sysclk), _) => {
179 let (sysclk, pll_config) = calc_pll(config, sysclk);
180 (sysclk, Some(pll_config))
181 }
182 (None, Some(hse)) => (hse, None),
183 (None, None) => (Hertz(HSI), None),
184 }
185}
186
187#[inline]
188fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
189 // Calculates the Multiplier and the Divisor to arrive at
190 // the required System clock from PLL source frequency
191 let get_mul_div = |sysclk, pllsrcclk| {
192 let common_div = gcd(sysclk, pllsrcclk);
193 let mut multiplier = sysclk / common_div;
194 let mut divisor = pllsrcclk / common_div;
195 // Minimum PLL multiplier is two
196 if multiplier == 1 {
197 multiplier *= 2;
198 divisor *= 2;
199 }
200 assert!(multiplier <= 16);
201 assert!(divisor <= 16);
202 (multiplier, divisor)
203 };
204 // Based on the source of Pll, we calculate the actual system clock
205 // frequency, PLL's source identifier, multiplier and divisor
206 let (act_sysclk, pll_src, pll_mul, pll_div) = match config.hse {
207 Some(Hertz(hse)) => {
208 let (multiplier, divisor) = get_mul_div(sysclk, hse);
209 (
210 Hertz((hse / divisor) * multiplier),
211 Pllsrc::HSE_DIV_PREDIV,
212 into_pll_mul(multiplier),
213 Some(into_pre_div(divisor)),
214 )
215 }
216 None => {
217 cfg_if::cfg_if! {
218 // For some chips PREDIV is always two, and cannot be changed
219 if #[cfg(any(
220 feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd",
221 feature="stm32f303xe", feature="stm32f398xe"
222 ))] {
223 let (multiplier, divisor) = get_mul_div(sysclk, HSI);
224 (
225 Hertz((hse / divisor) * multiplier),
226 Pllsrc::HSI_DIV_PREDIV,
227 into_pll_mul(multiplier),
228 Some(into_pre_div(divisor)),
229 )
230 } else {
231 let pllsrcclk = HSI / 2;
232 let multiplier = sysclk / pllsrcclk;
233 assert!(multiplier <= 16);
234 (
235 Hertz(pllsrcclk * multiplier),
236 Pllsrc::HSI_DIV2,
237 into_pll_mul(multiplier),
238 None,
239 )
240 }
241 }
242 }
243 };
244 (
245 act_sysclk,
246 PllConfig {
247 pll_src,
248 pll_mul,
249 pll_div,
250 },
251 )
252}
253
254#[inline]
255fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre {
256 cfg_if::cfg_if! {
257 // Some chips do not have USB
258 if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
259 panic!("USB clock not supported by the chip");
260 } else {
261 let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000);
262 match (usb_ok, sysclk) {
263 (true, 72_000_000) => Usbpre::DIV1_5,
264 (true, 48_000_000) => Usbpre::DIV1,
265 _ => panic!(
266 "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
267 ),
268 }
269 }
270 }
271}
272
273// This function assumes cases when multiplier is one and it
274// being greater than 16 is made impossible
275#[inline]
276fn into_pll_mul(multiplier: u32) -> Pllmul {
277 match multiplier {
278 2 => Pllmul::MUL2,
279 3 => Pllmul::MUL3,
280 4 => Pllmul::MUL4,
281 5 => Pllmul::MUL5,
282 6 => Pllmul::MUL6,
283 7 => Pllmul::MUL7,
284 8 => Pllmul::MUL8,
285 9 => Pllmul::MUL9,
286 10 => Pllmul::MUL10,
287 11 => Pllmul::MUL11,
288 12 => Pllmul::MUL12,
289 13 => Pllmul::MUL13,
290 14 => Pllmul::MUL14,
291 15 => Pllmul::MUL15,
292 16 => Pllmul::MUL16,
293 _ => unreachable!(),
294 }
295}
296
297// This function assumes the incoming divisor cannot be greater
298// than 16
299#[inline]
300fn into_pre_div(divisor: u32) -> Prediv {
301 match divisor {
302 1 => Prediv::DIV1,
303 2 => Prediv::DIV2,
304 3 => Prediv::DIV3,
305 4 => Prediv::DIV4,
306 5 => Prediv::DIV5,
307 6 => Prediv::DIV6,
308 7 => Prediv::DIV7,
309 8 => Prediv::DIV8,
310 9 => Prediv::DIV9,
311 10 => Prediv::DIV10,
312 11 => Prediv::DIV11,
313 12 => Prediv::DIV12,
314 13 => Prediv::DIV13,
315 14 => Prediv::DIV14,
316 15 => Prediv::DIV15,
317 16 => Prediv::DIV16,
318 _ => unreachable!(),
319 }
320}
321
322// Determine GCD using Euclidean algorithm
323#[inline]
324fn gcd(mut a: u32, mut b: u32) -> u32 {
325 while b != 0 {
326 let r = a % b;
327 a = b;
328 b = r;
329 }
330 a
331}
diff --git a/embassy-stm32/src/rcc/f3/mod.rs b/embassy-stm32/src/rcc/f3/mod.rs
deleted file mode 100644
index ab1bd7607..000000000
--- a/embassy-stm32/src/rcc/f3/mod.rs
+++ /dev/null
@@ -1,374 +0,0 @@
1use core::marker::PhantomData;
2use embassy::util::Unborrow;
3
4use crate::pac::{
5 flash::vals::Latency,
6 rcc::vals::{Hpre, Hsebyp, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre},
7 FLASH, RCC,
8};
9use crate::peripherals;
10use crate::rcc::{set_freqs, Clocks};
11use crate::time::Hertz;
12
13const HSI: u32 = 8_000_000;
14
15/// RCC peripheral
16pub struct Rcc<'d> {
17 config: Config,
18 phantom: PhantomData<&'d mut peripherals::RCC>,
19}
20
21/// Clocks configutation
22#[non_exhaustive]
23#[derive(Default)]
24pub struct Config {
25 /// Frequency of HSE oscillator
26 /// 4MHz to 32MHz
27 pub hse: Option<Hertz>,
28 /// Bypass HSE for an external clock
29 pub bypass_hse: bool,
30 /// Frequency of the System Clock
31 pub sysclk: Option<Hertz>,
32 /// Frequency of AHB bus
33 pub hclk: Option<Hertz>,
34 /// Frequency of APB1 bus
35 /// - Max frequency 36MHz
36 pub pclk1: Option<Hertz>,
37 /// Frequency of APB2 bus
38 /// - Max frequency with HSE is 72MHz
39 /// - Max frequency without HSE is 64MHz
40 pub pclk2: Option<Hertz>,
41 /// USB clock setup
42 /// It is valid only when,
43 /// - HSE is enabled,
44 /// - The System clock frequency is either 48MHz or 72MHz
45 /// - APB1 clock has a minimum frequency of 10MHz
46 pub pll48: bool,
47}
48
49// Information required to setup the PLL clock
50struct PllConfig {
51 pll_src: Pllsrc,
52 pll_mul: Pllmul,
53 pll_div: Option<Prediv>,
54}
55
56/// Initialize and Set the clock frequencies
57pub unsafe fn init(config: Config) {
58 let r = <peripherals::RCC as embassy::util::Steal>::steal();
59 let clocks = Rcc::new(r, config).freeze();
60 set_freqs(clocks);
61}
62
63impl<'d> Rcc<'d> {
64 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
65 Self {
66 config,
67 phantom: PhantomData,
68 }
69 }
70
71 fn freeze(self) -> Clocks {
72 // Calculate the real System clock, and PLL configuration if applicable
73 let (Hertz(sysclk), pll_config) = self.get_sysclk();
74 assert!(sysclk <= 72_000_000);
75
76 // Calculate real AHB clock
77 let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
78 let (hpre_bits, hpre_div) = match sysclk / hclk {
79 0 => unreachable!(),
80 1 => (Hpre::DIV1, 1),
81 2 => (Hpre::DIV2, 2),
82 3..=5 => (Hpre::DIV4, 4),
83 6..=11 => (Hpre::DIV8, 8),
84 12..=39 => (Hpre::DIV16, 16),
85 40..=95 => (Hpre::DIV64, 64),
86 96..=191 => (Hpre::DIV128, 128),
87 192..=383 => (Hpre::DIV256, 256),
88 _ => (Hpre::DIV512, 512),
89 };
90 let hclk = sysclk / hpre_div;
91 assert!(hclk <= 72_000_000);
92
93 // Calculate real APB1 clock
94 let pclk1 = self.config.pclk1.map(|p| p.0).unwrap_or(hclk);
95 let (ppre1_bits, ppre1) = match hclk / pclk1 {
96 0 => unreachable!(),
97 1 => (Ppre::DIV1, 1),
98 2 => (Ppre::DIV2, 2),
99 3..=5 => (Ppre::DIV4, 4),
100 6..=11 => (Ppre::DIV8, 8),
101 _ => (Ppre::DIV16, 16),
102 };
103 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
104 let pclk1 = hclk / ppre1;
105 assert!(pclk1 <= 36_000_000);
106
107 // Calculate real APB2 clock
108 let pclk2 = self.config.pclk2.map(|p| p.0).unwrap_or(hclk);
109 let (ppre2_bits, ppre2) = match hclk / pclk2 {
110 0 => unreachable!(),
111 1 => (Ppre::DIV1, 1),
112 2 => (Ppre::DIV2, 2),
113 3..=5 => (Ppre::DIV4, 4),
114 6..=11 => (Ppre::DIV8, 8),
115 _ => (Ppre::DIV16, 16),
116 };
117 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
118 let pclk2 = hclk / ppre2;
119 assert!(pclk2 <= 72_000_000);
120
121 // Set latency based on HCLK frquency
122 // NOTE(safety) Atomic write
123 unsafe {
124 FLASH.acr().write(|w| {
125 w.set_latency(if hclk <= 24_000_000 {
126 Latency::WS0
127 } else if hclk <= 48_000_000 {
128 Latency::WS1
129 } else {
130 Latency::WS2
131 });
132 })
133 }
134
135 // Enable HSE
136 if self.config.hse.is_some() {
137 // NOTE(unsafe) We own the peripheral block
138 unsafe {
139 RCC.cr().write(|w| {
140 w.set_hsebyp(if self.config.bypass_hse {
141 Hsebyp::BYPASSED
142 } else {
143 Hsebyp::NOTBYPASSED
144 });
145 // We turn on clock security to switch to HSI when HSE fails
146 w.set_csson(true);
147 w.set_hseon(true);
148 });
149 while !RCC.cr().read().hserdy() {}
150 }
151 }
152
153 // Enable PLL
154 if let Some(ref pll_config) = pll_config {
155 // NOTE(unsafe) We own the peripheral block
156 unsafe {
157 RCC.cfgr().write(|w| {
158 w.set_pllmul(pll_config.pll_mul);
159 w.set_pllsrc(pll_config.pll_src);
160 });
161 if let Some(pll_div) = pll_config.pll_div {
162 RCC.cfgr2().write(|w| w.set_prediv(pll_div));
163 }
164 RCC.cr().modify(|w| w.set_pllon(true));
165 while !RCC.cr().read().pllrdy() {}
166 }
167 }
168
169 if self.config.pll48 {
170 let usb_pre = self.get_usb_pre(sysclk, pclk1, &pll_config);
171 // NOTE(unsafe) We own the peripheral block
172 unsafe {
173 RCC.cfgr().write(|w| {
174 w.set_usbpre(usb_pre);
175 });
176 }
177 }
178
179 // Set prescalers
180 unsafe {
181 // NOTE(unsafe) We own the peripheral block
182 RCC.cfgr().write(|w| {
183 w.set_ppre2(ppre2_bits);
184 w.set_ppre1(ppre1_bits);
185 w.set_hpre(hpre_bits);
186 });
187
188 // Wait for the new prescalers to kick in
189 // "The clocks are divided with the new prescaler factor from
190 // 1 to 16 AHB cycles after write"
191 cortex_m::asm::delay(16);
192
193 // NOTE(unsafe) We own the peripheral block
194 RCC.cfgr().write(|w| {
195 w.set_sw(match (pll_config, self.config.hse) {
196 (Some(_), _) => Sw::PLL,
197 (None, Some(_)) => Sw::HSE,
198 (None, None) => Sw::HSI,
199 })
200 });
201 }
202
203 Clocks {
204 sys: Hertz(sysclk),
205 apb1: Hertz(pclk1),
206 apb2: Hertz(pclk2),
207 apb1_tim: Hertz(pclk1 * timer_mul1),
208 apb2_tim: Hertz(pclk2 * timer_mul2),
209 ahb: Hertz(hclk),
210 }
211 }
212
213 #[inline]
214 fn get_sysclk(&self) -> (Hertz, Option<PllConfig>) {
215 match (self.config.sysclk, self.config.hse) {
216 (Some(sysclk), Some(hse)) if sysclk == hse => (hse, None),
217 (Some(sysclk), None) if sysclk.0 == HSI => (Hertz(HSI), None),
218 // If the user selected System clock is different from HSI or HSE
219 // we will have to setup PLL clock source
220 (Some(sysclk), _) => {
221 let (sysclk, pll_config) = self.calc_pll(sysclk);
222 (sysclk, Some(pll_config))
223 }
224 (None, Some(hse)) => (hse, None),
225 (None, None) => (Hertz(HSI), None),
226 }
227 }
228
229 #[inline]
230 fn calc_pll(&self, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
231 // Calculates the Multiplier and the Divisor to arrive at
232 // the required System clock from PLL source frequency
233 let get_mul_div = |sysclk, pllsrcclk| {
234 let common_div = gcd(sysclk, pllsrcclk);
235 let mut multiplier = sysclk / common_div;
236 let mut divisor = pllsrcclk / common_div;
237 // Minimum PLL multiplier is two
238 if multiplier == 1 {
239 multiplier *= 2;
240 divisor *= 2;
241 }
242 assert!(multiplier <= 16);
243 assert!(divisor <= 16);
244 (multiplier, divisor)
245 };
246 // Based on the source of Pll, we calculate the actual system clock
247 // frequency, PLL's source identifier, multiplier and divisor
248 let (act_sysclk, pll_src, pll_mul, pll_div) = match self.config.hse {
249 Some(Hertz(hse)) => {
250 let (multiplier, divisor) = get_mul_div(sysclk, hse);
251 (
252 Hertz((hse / divisor) * multiplier),
253 Pllsrc::HSE_DIV_PREDIV,
254 into_pll_mul(multiplier),
255 Some(into_pre_div(divisor)),
256 )
257 }
258 None => {
259 cfg_if::cfg_if! {
260 // For some chips PREDIV is always two, and cannot be changed
261 if #[cfg(any(
262 feature="stm32f302xd", feature="stm32f302xe", feature="stm32f303xd",
263 feature="stm32f303xe", feature="stm32f398xe"
264 ))] {
265 let (multiplier, divisor) = get_mul_div(sysclk, HSI);
266 (
267 Hertz((hse / divisor) * multiplier),
268 Pllsrc::HSI_DIV_PREDIV,
269 into_pll_mul(multiplier),
270 Some(into_pre_div(divisor)),
271 )
272 } else {
273 let pllsrcclk = HSI / 2;
274 let multiplier = sysclk / pllsrcclk;
275 assert!(multiplier <= 16);
276 (
277 Hertz(pllsrcclk * multiplier),
278 Pllsrc::HSI_DIV2,
279 into_pll_mul(multiplier),
280 None,
281 )
282 }
283 }
284 }
285 };
286 (
287 act_sysclk,
288 PllConfig {
289 pll_src,
290 pll_mul,
291 pll_div,
292 },
293 )
294 }
295
296 #[inline]
297 fn get_usb_pre(&self, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre {
298 cfg_if::cfg_if! {
299 // Some chips do not have USB
300 if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
301 panic!("USB clock not supported by the chip");
302 } else {
303 let usb_ok = self.config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000);
304 match (usb_ok, sysclk) {
305 (true, 72_000_000) => Usbpre::DIV1_5,
306 (true, 48_000_000) => Usbpre::DIV1,
307 _ => panic!(
308 "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
309 ),
310 }
311 }
312 }
313 }
314}
315
316// This function assumes cases when multiplier is one and it
317// being greater than 16 is made impossible
318#[inline]
319fn into_pll_mul(multiplier: u32) -> Pllmul {
320 match multiplier {
321 2 => Pllmul::MUL2,
322 3 => Pllmul::MUL3,
323 4 => Pllmul::MUL4,
324 5 => Pllmul::MUL5,
325 6 => Pllmul::MUL6,
326 7 => Pllmul::MUL7,
327 8 => Pllmul::MUL8,
328 9 => Pllmul::MUL9,
329 10 => Pllmul::MUL10,
330 11 => Pllmul::MUL11,
331 12 => Pllmul::MUL12,
332 13 => Pllmul::MUL13,
333 14 => Pllmul::MUL14,
334 15 => Pllmul::MUL15,
335 16 => Pllmul::MUL16,
336 _ => unreachable!(),
337 }
338}
339
340// This function assumes the incoming divisor cannot be greater
341// than 16
342#[inline]
343fn into_pre_div(divisor: u32) -> Prediv {
344 match divisor {
345 1 => Prediv::DIV1,
346 2 => Prediv::DIV2,
347 3 => Prediv::DIV3,
348 4 => Prediv::DIV4,
349 5 => Prediv::DIV5,
350 6 => Prediv::DIV6,
351 7 => Prediv::DIV7,
352 8 => Prediv::DIV8,
353 9 => Prediv::DIV9,
354 10 => Prediv::DIV10,
355 11 => Prediv::DIV11,
356 12 => Prediv::DIV12,
357 13 => Prediv::DIV13,
358 14 => Prediv::DIV14,
359 15 => Prediv::DIV15,
360 16 => Prediv::DIV16,
361 _ => unreachable!(),
362 }
363}
364
365// Determine GCD using Euclidean algorithm
366#[inline]
367fn gcd(mut a: u32, mut b: u32) -> u32 {
368 while b != 0 {
369 let r = a % b;
370 a = b;
371 b = r;
372 }
373 a
374}
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
new file mode 100644
index 000000000..aba8fc0ef
--- /dev/null
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -0,0 +1,288 @@
1use super::sealed::RccPeripheral;
2use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
3use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz;
6
7const HSI: u32 = 16_000_000;
8
9/// Clocks configuration
10#[non_exhaustive]
11#[derive(Default)]
12pub struct Config {
13 pub hse: Option<Hertz>,
14 pub bypass_hse: bool,
15 pub hclk: Option<Hertz>,
16 pub sys_ck: Option<Hertz>,
17 pub pclk1: Option<Hertz>,
18 pub pclk2: Option<Hertz>,
19
20 pub pll48: bool,
21}
22
23unsafe fn setup_pll(
24 pllsrcclk: u32,
25 use_hse: bool,
26 pllsysclk: Option<u32>,
27 pll48clk: bool,
28) -> PllResults {
29 use crate::pac::rcc::vals::{Pllp, Pllsrc};
30
31 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
32 if pllsysclk.is_none() && !pll48clk {
33 RCC.pllcfgr()
34 .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
35
36 return PllResults {
37 use_pll: false,
38 pllsysclk: None,
39 pll48clk: None,
40 };
41 }
42 // Input divisor from PLL source clock, must result to frequency in
43 // the range from 1 to 2 MHz
44 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
45 let pllm_max = pllsrcclk / 1_000_000;
46
47 // Sysclk output divisor must be one of 2, 4, 6 or 8
48 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
49
50 let target_freq = if pll48clk {
51 48_000_000
52 } else {
53 sysclk * sysclk_div
54 };
55
56 // Find the lowest pllm value that minimize the difference between
57 // target frequency and the real vco_out frequency.
58 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
59 let vco_in = pllsrcclk / pllm;
60 let plln = target_freq / vco_in;
61 target_freq - vco_in * plln
62 }));
63
64 let vco_in = pllsrcclk / pllm;
65 assert!((1_000_000..=2_000_000).contains(&vco_in));
66
67 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
68 // and <= 432MHz, min 50, max 432
69 let plln = if pll48clk {
70 // try the different valid pllq according to the valid
71 // main scaller values, and take the best
72 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
73 let plln = 48_000_000 * pllq / vco_in;
74 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
75 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
76 (pll48_diff, sysclk_diff)
77 }));
78 48_000_000 * pllq / vco_in
79 } else {
80 sysclk * sysclk_div / vco_in
81 };
82
83 let pllp = (sysclk_div / 2) - 1;
84
85 let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
86 let real_pll48clk = vco_in * plln / pllq;
87
88 RCC.pllcfgr().modify(|w| {
89 w.set_pllm(pllm as u8);
90 w.set_plln(plln as u16);
91 w.set_pllp(Pllp(pllp as u8));
92 w.set_pllq(pllq as u8);
93 w.set_pllsrc(Pllsrc(use_hse as u8));
94 });
95
96 let real_pllsysclk = vco_in * plln / sysclk_div;
97
98 PllResults {
99 use_pll: true,
100 pllsysclk: Some(real_pllsysclk),
101 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
102 }
103}
104
105unsafe fn flash_setup(sysclk: u32) {
106 use crate::pac::flash::vals::Latency;
107
108 // Be conservative with voltage ranges
109 const FLASH_LATENCY_STEP: u32 = 30_000_000;
110
111 critical_section::with(|_| {
112 FLASH
113 .acr()
114 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
115 });
116}
117
118pub(crate) unsafe fn init(config: Config) {
119 crate::peripherals::PWR::enable();
120
121 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI);
122 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
123 let sysclk_on_pll = sysclk != pllsrcclk;
124
125 let plls = setup_pll(
126 pllsrcclk,
127 config.hse.is_some(),
128 if sysclk_on_pll { Some(sysclk) } else { None },
129 config.pll48,
130 );
131
132 if config.pll48 {
133 let freq = unwrap!(plls.pll48clk);
134
135 assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
136 }
137
138 let sysclk = if sysclk_on_pll {
139 unwrap!(plls.pllsysclk)
140 } else {
141 sysclk
142 };
143
144 // AHB prescaler
145 let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
146 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
147 0 => unreachable!(),
148 1 => (Hpre::DIV1, 1),
149 2 => (Hpre::DIV2, 2),
150 3..=5 => (Hpre::DIV4, 4),
151 6..=11 => (Hpre::DIV8, 8),
152 12..=39 => (Hpre::DIV16, 16),
153 40..=95 => (Hpre::DIV64, 64),
154 96..=191 => (Hpre::DIV128, 128),
155 192..=383 => (Hpre::DIV256, 256),
156 _ => (Hpre::DIV512, 512),
157 };
158
159 // Calculate real AHB clock
160 let hclk = sysclk / hpre_div;
161
162 let pclk1 = config
163 .pclk1
164 .map(|p| p.0)
165 .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
166
167 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
168 0 => unreachable!(),
169 1 => (0b000, 1),
170 2 => (0b100, 2),
171 3..=5 => (0b101, 4),
172 6..=11 => (0b110, 8),
173 _ => (0b111, 16),
174 };
175 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
176
177 // Calculate real APB1 clock
178 let pclk1 = hclk / ppre1;
179 assert!(pclk1 <= max::PCLK1_MAX);
180
181 let pclk2 = config
182 .pclk2
183 .map(|p| p.0)
184 .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
185 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
186 0 => unreachable!(),
187 1 => (0b000, 1),
188 2 => (0b100, 2),
189 3..=5 => (0b101, 4),
190 6..=11 => (0b110, 8),
191 _ => (0b111, 16),
192 };
193 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
194
195 // Calculate real APB2 clock
196 let pclk2 = hclk / ppre2;
197 assert!(pclk2 <= max::PCLK2_MAX);
198
199 flash_setup(sysclk);
200
201 if config.hse.is_some() {
202 RCC.cr().modify(|w| {
203 w.set_hsebyp(Hsebyp(config.bypass_hse as u8));
204 w.set_hseon(true);
205 });
206 while !RCC.cr().read().hserdy() {}
207 }
208
209 if plls.use_pll {
210 RCC.cr().modify(|w| w.set_pllon(true));
211
212 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
213 PWR.cr1().modify(|w| w.set_oden(true));
214 while !PWR.csr1().read().odrdy() {}
215
216 PWR.cr1().modify(|w| w.set_odswen(true));
217 while !PWR.csr1().read().odswrdy() {}
218 }
219
220 while !RCC.cr().read().pllrdy() {}
221 }
222
223 RCC.cfgr().modify(|w| {
224 w.set_ppre2(Ppre(ppre2_bits));
225 w.set_ppre1(Ppre(ppre1_bits));
226 w.set_hpre(hpre_bits);
227 });
228
229 // Wait for the new prescalers to kick in
230 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
231 cortex_m::asm::delay(16);
232
233 RCC.cfgr().modify(|w| {
234 w.set_sw(if sysclk_on_pll {
235 Sw::PLL
236 } else if config.hse.is_some() {
237 Sw::HSE
238 } else {
239 Sw::HSI
240 })
241 });
242
243 set_freqs(Clocks {
244 sys: Hertz(sysclk),
245 apb1: Hertz(pclk1),
246 apb2: Hertz(pclk2),
247
248 apb1_tim: Hertz(pclk1 * timer_mul1),
249 apb2_tim: Hertz(pclk2 * timer_mul2),
250
251 ahb1: Hertz(hclk),
252 ahb2: Hertz(hclk),
253 ahb3: Hertz(hclk),
254
255 pll48: plls.pll48clk.map(Hertz),
256 });
257}
258
259struct PllResults {
260 use_pll: bool,
261 pllsysclk: Option<u32>,
262 pll48clk: Option<u32>,
263}
264
265mod max {
266 #[cfg(stm32f401)]
267 pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
268 #[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
269 pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
270 #[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
271 pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
272 #[cfg(any(
273 stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
274 ))]
275 pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
276
277 pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 168_000_000;
278
279 pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
280
281 #[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
282 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
283 #[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
284 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
285
286 pub(crate) const PLL_48_CLK: u32 = 48_000_000;
287 pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
288}
diff --git a/embassy-stm32/src/rcc/f4/max.rs b/embassy-stm32/src/rcc/f4/max.rs
deleted file mode 100644
index dd8de3da9..000000000
--- a/embassy-stm32/src/rcc/f4/max.rs
+++ /dev/null
@@ -1,21 +0,0 @@
1#[cfg(stm32f401)]
2pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
3
4#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
5pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
6
7#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
8pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
9
10#[cfg(any(
11 stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,
12))]
13pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
14
15#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
16pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
17
18#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
19pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
20
21pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
diff --git a/embassy-stm32/src/rcc/f4/mod.rs b/embassy-stm32/src/rcc/f4/mod.rs
deleted file mode 100644
index 04083dfa1..000000000
--- a/embassy-stm32/src/rcc/f4/mod.rs
+++ /dev/null
@@ -1,311 +0,0 @@
1use crate::pac::{FLASH, PWR, RCC};
2use crate::peripherals;
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use core::marker::PhantomData;
6use embassy::util::Unborrow;
7
8mod max;
9use max::{PCLK1_MAX, PCLK2_MAX};
10
11const HSI: u32 = 16_000_000;
12
13/// Clocks configutation
14#[non_exhaustive]
15#[derive(Default)]
16pub struct Config {
17 pub hse: Option<Hertz>,
18 pub bypass_hse: bool,
19 pub pll48: bool,
20 pub sys_ck: Option<Hertz>,
21 pub hclk: Option<Hertz>,
22 pub pclk1: Option<Hertz>,
23 pub pclk2: Option<Hertz>,
24}
25
26/// RCC peripheral
27pub struct Rcc<'d> {
28 config: Config,
29 phantom: PhantomData<&'d mut peripherals::RCC>,
30}
31
32impl<'d> Rcc<'d> {
33 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
34 Self {
35 config,
36 phantom: PhantomData,
37 }
38 }
39
40 fn freeze(mut self) -> Clocks {
41 use super::sealed::RccPeripheral;
42 use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
43
44 let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
45 let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
46 let sysclk_on_pll = sysclk != pllsrcclk;
47
48 let plls = self.setup_pll(
49 pllsrcclk,
50 self.config.hse.is_some(),
51 if sysclk_on_pll { Some(sysclk) } else { None },
52 self.config.pll48,
53 );
54
55 if self.config.pll48 {
56 assert!(
57 // USB specification allows +-0.25%
58 plls.pll48clk
59 .map(|freq| (48_000_000 - freq as i32).abs() <= 120_000)
60 .unwrap_or(false)
61 );
62 }
63
64 let sysclk = if sysclk_on_pll {
65 unwrap!(plls.pllsysclk)
66 } else {
67 sysclk
68 };
69
70 let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
71 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
72 0 => unreachable!(),
73 1 => (Hpre::DIV1, 1),
74 2 => (Hpre::DIV2, 2),
75 3..=5 => (Hpre::DIV4, 4),
76 6..=11 => (Hpre::DIV8, 8),
77 12..=39 => (Hpre::DIV16, 16),
78 40..=95 => (Hpre::DIV64, 64),
79 96..=191 => (Hpre::DIV128, 128),
80 192..=383 => (Hpre::DIV256, 256),
81 _ => (Hpre::DIV512, 512),
82 };
83
84 // Calculate real AHB clock
85 let hclk = sysclk / hpre_div;
86
87 let pclk1 = self
88 .config
89 .pclk1
90 .map(|p| p.0)
91 .unwrap_or_else(|| core::cmp::min(PCLK1_MAX, hclk));
92 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
93 0 => unreachable!(),
94 1 => (0b000, 1),
95 2 => (0b100, 2),
96 3..=5 => (0b101, 4),
97 6..=11 => (0b110, 8),
98 _ => (0b111, 16),
99 };
100 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
101
102 // Calculate real APB1 clock
103 let pclk1 = hclk / ppre1;
104 assert!(pclk1 <= PCLK1_MAX);
105
106 let pclk2 = self
107 .config
108 .pclk2
109 .map(|p| p.0)
110 .unwrap_or_else(|| core::cmp::min(PCLK2_MAX, hclk));
111 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
112 0 => unreachable!(),
113 1 => (0b000, 1),
114 2 => (0b100, 2),
115 3..=5 => (0b101, 4),
116 6..=11 => (0b110, 8),
117 _ => (0b111, 16),
118 };
119 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
120
121 // Calculate real APB2 clock
122 let pclk2 = hclk / ppre2;
123 assert!(pclk2 <= PCLK2_MAX);
124
125 Self::flash_setup(sysclk);
126
127 if self.config.hse.is_some() {
128 // NOTE(unsafe) We own the peripheral block
129 unsafe {
130 RCC.cr().modify(|w| {
131 w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8));
132 w.set_hseon(true);
133 });
134 while !RCC.cr().read().hserdy() {}
135 }
136 }
137
138 if plls.use_pll {
139 unsafe {
140 RCC.cr().modify(|w| w.set_pllon(true));
141
142 if hclk > 168_000_000 {
143 peripherals::PWR::enable();
144
145 PWR.cr().modify(|w| w.set_oden(true));
146 while !PWR.csr().read().odrdy() {}
147
148 PWR.cr().modify(|w| w.set_odswen(true));
149 while !PWR.csr().read().odswrdy() {}
150 }
151
152 while !RCC.cr().read().pllrdy() {}
153 }
154 }
155
156 unsafe {
157 RCC.cfgr().modify(|w| {
158 w.set_ppre2(Ppre(ppre2_bits));
159 w.set_ppre1(Ppre(ppre1_bits));
160 w.set_hpre(hpre_bits);
161 });
162
163 // Wait for the new prescalers to kick in
164 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
165 cortex_m::asm::delay(16);
166
167 RCC.cfgr().modify(|w| {
168 w.set_sw(if sysclk_on_pll {
169 Sw::PLL
170 } else if self.config.hse.is_some() {
171 Sw::HSE
172 } else {
173 Sw::HSI
174 })
175 });
176 }
177
178 Clocks {
179 sys: Hertz(sysclk),
180 apb1: Hertz(pclk1),
181 apb2: Hertz(pclk2),
182
183 apb1_tim: Hertz(pclk1 * timer_mul1),
184 apb2_tim: Hertz(pclk2 * timer_mul2),
185
186 ahb1: Hertz(hclk),
187 ahb2: Hertz(hclk),
188 ahb3: Hertz(hclk),
189
190 pll48: plls.pll48clk.map(Hertz),
191 }
192 }
193
194 // Safety: RCC init must have been called
195 pub fn clocks(&self) -> &'static Clocks {
196 unsafe { get_freqs() }
197 }
198
199 fn setup_pll(
200 &mut self,
201 pllsrcclk: u32,
202 use_hse: bool,
203 pllsysclk: Option<u32>,
204 pll48clk: bool,
205 ) -> PllResults {
206 use crate::pac::rcc::vals::{Pllp, Pllsrc};
207
208 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
209 if pllsysclk.is_none() && !pll48clk {
210 // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock
211 unsafe {
212 RCC.pllcfgr()
213 .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
214 }
215
216 return PllResults {
217 use_pll: false,
218 pllsysclk: None,
219 pll48clk: None,
220 };
221 }
222 // Input divisor from PLL source clock, must result to frequency in
223 // the range from 1 to 2 MHz
224 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
225 let pllm_max = pllsrcclk / 1_000_000;
226
227 // Sysclk output divisor must be one of 2, 4, 6 or 8
228 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
229
230 let target_freq = if pll48clk {
231 48_000_000
232 } else {
233 sysclk * sysclk_div
234 };
235
236 // Find the lowest pllm value that minimize the difference between
237 // target frequency and the real vco_out frequency.
238 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
239 let vco_in = pllsrcclk / pllm;
240 let plln = target_freq / vco_in;
241 target_freq - vco_in * plln
242 }));
243
244 let vco_in = pllsrcclk / pllm;
245 assert!((1_000_000..=2_000_000).contains(&vco_in));
246
247 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
248 // and <= 432MHz, min 50, max 432
249 let plln = if pll48clk {
250 // try the different valid pllq according to the valid
251 // main scaller values, and take the best
252 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
253 let plln = 48_000_000 * pllq / vco_in;
254 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
255 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
256 (pll48_diff, sysclk_diff)
257 }));
258 48_000_000 * pllq / vco_in
259 } else {
260 sysclk * sysclk_div / vco_in
261 };
262
263 let pllp = (sysclk_div / 2) - 1;
264
265 let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
266 let real_pll48clk = vco_in * plln / pllq;
267
268 unsafe {
269 RCC.pllcfgr().modify(|w| {
270 w.set_pllm(pllm as u8);
271 w.set_plln(plln as u16);
272 w.set_pllp(Pllp(pllp as u8));
273 w.set_pllq(pllq as u8);
274 w.set_pllsrc(Pllsrc(use_hse as u8));
275 });
276 }
277
278 let real_pllsysclk = vco_in * plln / sysclk_div;
279
280 PllResults {
281 use_pll: true,
282 pllsysclk: Some(real_pllsysclk),
283 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
284 }
285 }
286
287 fn flash_setup(sysclk: u32) {
288 use crate::pac::flash::vals::Latency;
289
290 // Be conservative with voltage ranges
291 const FLASH_LATENCY_STEP: u32 = 30_000_000;
292
293 critical_section::with(|_| unsafe {
294 FLASH
295 .acr()
296 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
297 });
298 }
299}
300
301pub unsafe fn init(config: Config) {
302 let r = <peripherals::RCC as embassy::util::Steal>::steal();
303 let clocks = Rcc::new(r, config).freeze();
304 set_freqs(clocks);
305}
306
307struct PllResults {
308 use_pll: bool,
309 pllsysclk: Option<u32>,
310 pll48clk: Option<u32>,
311}
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
new file mode 100644
index 000000000..1a0530296
--- /dev/null
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -0,0 +1,321 @@
1use super::sealed::RccPeripheral;
2use crate::pac::pwr::vals::Vos;
3use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
4use crate::pac::{FLASH, PWR, RCC};
5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz;
7
8const HSI: u32 = 16_000_000;
9
10/// Clocks configuration
11#[non_exhaustive]
12#[derive(Default)]
13pub struct Config {
14 pub hse: Option<Hertz>,
15 pub bypass_hse: bool,
16 pub hclk: Option<Hertz>,
17 pub sys_ck: Option<Hertz>,
18 pub pclk1: Option<Hertz>,
19 pub pclk2: Option<Hertz>,
20
21 pub pll48: bool,
22}
23
24unsafe fn setup_pll(
25 pllsrcclk: u32,
26 use_hse: bool,
27 pllsysclk: Option<u32>,
28 pll48clk: bool,
29) -> PllResults {
30 use crate::pac::rcc::vals::{Pllp, Pllsrc};
31
32 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
33 if pllsysclk.is_none() && !pll48clk {
34 RCC.pllcfgr()
35 .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
36
37 return PllResults {
38 use_pll: false,
39 pllsysclk: None,
40 pll48clk: None,
41 };
42 }
43 // Input divisor from PLL source clock, must result to frequency in
44 // the range from 1 to 2 MHz
45 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
46 let pllm_max = pllsrcclk / 1_000_000;
47
48 // Sysclk output divisor must be one of 2, 4, 6 or 8
49 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
50
51 let target_freq = if pll48clk {
52 48_000_000
53 } else {
54 sysclk * sysclk_div
55 };
56
57 // Find the lowest pllm value that minimize the difference between
58 // target frequency and the real vco_out frequency.
59 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
60 let vco_in = pllsrcclk / pllm;
61 let plln = target_freq / vco_in;
62 target_freq - vco_in * plln
63 }));
64
65 let vco_in = pllsrcclk / pllm;
66 assert!((1_000_000..=2_000_000).contains(&vco_in));
67
68 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
69 // and <= 432MHz, min 50, max 432
70 let plln = if pll48clk {
71 // try the different valid pllq according to the valid
72 // main scaller values, and take the best
73 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
74 let plln = 48_000_000 * pllq / vco_in;
75 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
76 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
77 (pll48_diff, sysclk_diff)
78 }));
79 48_000_000 * pllq / vco_in
80 } else {
81 sysclk * sysclk_div / vco_in
82 };
83
84 let pllp = (sysclk_div / 2) - 1;
85
86 let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
87 let real_pll48clk = vco_in * plln / pllq;
88
89 RCC.pllcfgr().modify(|w| {
90 w.set_pllm(pllm as u8);
91 w.set_plln(plln as u16);
92 w.set_pllp(Pllp(pllp as u8));
93 w.set_pllq(pllq as u8);
94 w.set_pllsrc(Pllsrc(use_hse as u8));
95 });
96
97 let real_pllsysclk = vco_in * plln / sysclk_div;
98
99 PllResults {
100 use_pll: true,
101 pllsysclk: Some(real_pllsysclk),
102 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
103 }
104}
105
106unsafe fn flash_setup(sysclk: u32) {
107 use crate::pac::flash::vals::Latency;
108
109 // Be conservative with voltage ranges
110 const FLASH_LATENCY_STEP: u32 = 30_000_000;
111
112 critical_section::with(|_| {
113 FLASH
114 .acr()
115 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
116 });
117}
118
119pub(crate) unsafe fn init(config: Config) {
120 crate::peripherals::PWR::enable();
121
122 if let Some(hse) = config.hse {
123 if config.bypass_hse {
124 assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
125 } else {
126 assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
127 }
128 }
129
130 let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI);
131 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
132 let sysclk_on_pll = sysclk != pllsrcclk;
133
134 assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
135
136 let plls = setup_pll(
137 pllsrcclk,
138 config.hse.is_some(),
139 if sysclk_on_pll { Some(sysclk) } else { None },
140 config.pll48,
141 );
142
143 if config.pll48 {
144 let freq = unwrap!(plls.pll48clk);
145
146 assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
147 }
148
149 let sysclk = if sysclk_on_pll {
150 unwrap!(plls.pllsysclk)
151 } else {
152 sysclk
153 };
154
155 // AHB prescaler
156 let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
157 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
158 0 => unreachable!(),
159 1 => (Hpre::DIV1, 1),
160 2 => (Hpre::DIV2, 2),
161 3..=5 => (Hpre::DIV4, 4),
162 6..=11 => (Hpre::DIV8, 8),
163 12..=39 => (Hpre::DIV16, 16),
164 40..=95 => (Hpre::DIV64, 64),
165 96..=191 => (Hpre::DIV128, 128),
166 192..=383 => (Hpre::DIV256, 256),
167 _ => (Hpre::DIV512, 512),
168 };
169
170 // Calculate real AHB clock
171 let hclk = sysclk / hpre_div;
172
173 assert!(hclk < max::HCLK_MAX);
174
175 let pclk1 = config
176 .pclk1
177 .map(|p| p.0)
178 .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
179
180 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
181 0 => unreachable!(),
182 1 => (0b000, 1),
183 2 => (0b100, 2),
184 3..=5 => (0b101, 4),
185 6..=11 => (0b110, 8),
186 _ => (0b111, 16),
187 };
188 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
189
190 // Calculate real APB1 clock
191 let pclk1 = hclk / ppre1;
192 assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
193
194 let pclk2 = config
195 .pclk2
196 .map(|p| p.0)
197 .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
198 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
199 0 => unreachable!(),
200 1 => (0b000, 1),
201 2 => (0b100, 2),
202 3..=5 => (0b101, 4),
203 6..=11 => (0b110, 8),
204 _ => (0b111, 16),
205 };
206 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
207
208 // Calculate real APB2 clock
209 let pclk2 = hclk / ppre2;
210 assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
211
212 flash_setup(sysclk);
213
214 if config.hse.is_some() {
215 RCC.cr().modify(|w| {
216 w.set_hsebyp(Hsebyp(config.bypass_hse as u8));
217 w.set_hseon(true);
218 });
219 while !RCC.cr().read().hserdy() {}
220 }
221
222 if plls.use_pll {
223 RCC.cr().modify(|w| w.set_pllon(false));
224
225 // enable PWR and setup VOSScale
226
227 RCC.apb1enr().modify(|w| w.set_pwren(true));
228
229 let vos_scale = if sysclk <= 144_000_000 {
230 3
231 } else if sysclk <= 168_000_000 {
232 2
233 } else {
234 1
235 };
236 PWR.cr1().modify(|w| {
237 w.set_vos(match vos_scale {
238 3 => Vos::SCALE3,
239 2 => Vos::SCALE2,
240 1 => Vos::SCALE1,
241 _ => panic!("Invalid VOS Scale."),
242 })
243 });
244
245 RCC.cr().modify(|w| w.set_pllon(true));
246
247 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
248 PWR.cr1().modify(|w| w.set_oden(true));
249 while !PWR.csr1().read().odrdy() {}
250
251 PWR.cr1().modify(|w| w.set_odswen(true));
252 while !PWR.csr1().read().odswrdy() {}
253 }
254
255 while !RCC.cr().read().pllrdy() {}
256 }
257
258 RCC.cfgr().modify(|w| {
259 w.set_ppre2(Ppre(ppre2_bits));
260 w.set_ppre1(Ppre(ppre1_bits));
261 w.set_hpre(hpre_bits);
262 });
263
264 // Wait for the new prescalers to kick in
265 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
266 cortex_m::asm::delay(16);
267
268 RCC.cfgr().modify(|w| {
269 w.set_sw(if sysclk_on_pll {
270 Sw::PLL
271 } else if config.hse.is_some() {
272 Sw::HSE
273 } else {
274 Sw::HSI
275 })
276 });
277
278 set_freqs(Clocks {
279 sys: Hertz(sysclk),
280 apb1: Hertz(pclk1),
281 apb2: Hertz(pclk2),
282
283 apb1_tim: Hertz(pclk1 * timer_mul1),
284 apb2_tim: Hertz(pclk2 * timer_mul2),
285
286 ahb1: Hertz(hclk),
287 ahb2: Hertz(hclk),
288 ahb3: Hertz(hclk),
289
290 pll48: plls.pll48clk.map(Hertz),
291 });
292}
293
294struct PllResults {
295 use_pll: bool,
296 pllsysclk: Option<u32>,
297 pll48clk: Option<u32>,
298}
299
300mod max {
301 pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
302 pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
303 pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
304 pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
305
306 pub(crate) const HCLK_MAX: u32 = 216_000_000;
307 pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
308
309 pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
310 pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
311
312 pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
313 pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
314
315 pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
316 pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
317
318 // USB specification allows +-0.25%
319 pub(crate) const PLL_48_CLK: u32 = 48_000_000;
320 pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
321}
diff --git a/embassy-stm32/src/rcc/f7/max.rs b/embassy-stm32/src/rcc/f7/max.rs
deleted file mode 100644
index db00fdf3e..000000000
--- a/embassy-stm32/src/rcc/f7/max.rs
+++ /dev/null
@@ -1,19 +0,0 @@
1pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
2pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
3pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
4pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
5
6pub(crate) const HCLK_MAX: u32 = 216_000_000;
7pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
8
9pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
10pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
11
12pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
13pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
14
15pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
16pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
17
18pub(crate) const PLL_48_CLK: u32 = 48_000_000;
19pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
diff --git a/embassy-stm32/src/rcc/f7/mod.rs b/embassy-stm32/src/rcc/f7/mod.rs
deleted file mode 100644
index c13e20167..000000000
--- a/embassy-stm32/src/rcc/f7/mod.rs
+++ /dev/null
@@ -1,347 +0,0 @@
1mod max;
2
3use crate::pac::{FLASH, PWR, RCC};
4use crate::peripherals;
5use crate::rcc::{get_freqs, set_freqs, Clocks};
6use crate::time::Hertz;
7use core::marker::PhantomData;
8use embassy::util::Unborrow;
9
10const HSI: u32 = 16_000_000;
11
12#[non_exhaustive]
13#[derive(Default)]
14pub struct Config {
15 pub hse: Option<Hertz>,
16 pub bypass_hse: bool,
17 pub hclk: Option<Hertz>,
18 pub sys_ck: Option<Hertz>,
19 pub pclk1: Option<Hertz>,
20 pub pclk2: Option<Hertz>,
21
22 pub pll48: bool,
23}
24
25/// RCC peripheral
26pub struct Rcc<'d> {
27 config: Config,
28 phantom: PhantomData<&'d mut peripherals::RCC>,
29}
30
31impl<'d> Rcc<'d> {
32 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
33 if let Some(hse) = config.hse {
34 if config.bypass_hse {
35 assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
36 } else {
37 assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
38 }
39 }
40 Self {
41 config,
42 phantom: PhantomData,
43 }
44 }
45
46 fn freeze(mut self) -> Clocks {
47 use super::sealed::RccPeripheral;
48 use crate::pac::pwr::vals::Vos;
49 use crate::pac::rcc::vals::{Hpre, Hsebyp, Ppre, Sw};
50
51 let base_clock = self.config.hse.map(|hse| hse.0).unwrap_or(HSI);
52 let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(base_clock);
53 let sysclk_on_pll = sysclk != base_clock;
54
55 assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
56
57 let plls = self.setup_pll(
58 base_clock,
59 self.config.hse.is_some(),
60 if sysclk_on_pll { Some(sysclk) } else { None },
61 self.config.pll48,
62 );
63
64 if self.config.pll48 {
65 assert!(
66 // USB specification allows +-0.25%
67 plls.pll48clk
68 .map(|freq| (max::PLL_48_CLK as i32 - freq as i32).abs()
69 <= max::PLL_48_TOLERANCE as i32)
70 .unwrap_or(false)
71 );
72 }
73
74 let sysclk = if sysclk_on_pll {
75 unwrap!(plls.pllsysclk)
76 } else {
77 sysclk
78 };
79
80 // AHB prescaler
81 let hclk = self.config.hclk.map(|h| h.0).unwrap_or(sysclk);
82 let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
83 0 => unreachable!(),
84 1 => (Hpre::DIV1, 1),
85 2 => (Hpre::DIV2, 2),
86 3..=5 => (Hpre::DIV4, 4),
87 6..=11 => (Hpre::DIV8, 8),
88 12..=39 => (Hpre::DIV16, 16),
89 40..=95 => (Hpre::DIV64, 64),
90 96..=191 => (Hpre::DIV128, 128),
91 192..=383 => (Hpre::DIV256, 256),
92 _ => (Hpre::DIV512, 512),
93 };
94
95 // Calculate real AHB clock
96 let hclk = sysclk / hpre_div;
97
98 assert!(hclk < max::HCLK_MAX);
99
100 let pclk1 = self
101 .config
102 .pclk1
103 .map(|p| p.0)
104 .unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
105
106 let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
107 0 => unreachable!(),
108 1 => (0b000, 1),
109 2 => (0b100, 2),
110 3..=5 => (0b101, 4),
111 6..=11 => (0b110, 8),
112 _ => (0b111, 16),
113 };
114 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
115
116 // Calculate real APB1 clock
117 let pclk1 = hclk / ppre1;
118 assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
119
120 let pclk2 = self
121 .config
122 .pclk2
123 .map(|p| p.0)
124 .unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
125 let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
126 0 => unreachable!(),
127 1 => (0b000, 1),
128 2 => (0b100, 2),
129 3..=5 => (0b101, 4),
130 6..=11 => (0b110, 8),
131 _ => (0b111, 16),
132 };
133 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
134
135 // Calculate real APB2 clock
136 let pclk2 = hclk / ppre2;
137 assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
138
139 Self::flash_setup(sysclk);
140
141 if self.config.hse.is_some() {
142 // NOTE(unsafe) We own the peripheral block
143 unsafe {
144 RCC.cr().modify(|w| {
145 w.set_hsebyp(Hsebyp(self.config.bypass_hse as u8));
146 w.set_hseon(true);
147 });
148 while !RCC.cr().read().hserdy() {}
149 }
150 }
151
152 if plls.use_pll {
153 unsafe {
154 RCC.cr().modify(|w| w.set_pllon(false));
155
156 // enable PWR and setup VOSScale
157
158 RCC.apb1enr().modify(|w| w.set_pwren(true));
159
160 let vos_scale = if sysclk <= 144_000_000 {
161 3
162 } else if sysclk <= 168_000_000 {
163 2
164 } else {
165 1
166 };
167 PWR.cr1().modify(|w| {
168 w.set_vos(match vos_scale {
169 3 => Vos::SCALE3,
170 2 => Vos::SCALE2,
171 1 => Vos::SCALE1,
172 _ => panic!("Invalid VOS Scale."),
173 })
174 });
175
176 RCC.cr().modify(|w| w.set_pllon(true));
177
178 while !RCC.cr().read().pllrdy() {}
179
180 if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
181 peripherals::PWR::enable();
182
183 PWR.cr1().modify(|w| w.set_oden(true));
184 while !PWR.csr1().read().odrdy() {}
185
186 PWR.cr1().modify(|w| w.set_odswen(true));
187 while !PWR.csr1().read().odswrdy() {}
188 }
189
190 while !RCC.cr().read().pllrdy() {}
191 }
192 }
193
194 unsafe {
195 RCC.cfgr().modify(|w| {
196 w.set_ppre2(Ppre(ppre2_bits));
197 w.set_ppre1(Ppre(ppre1_bits));
198 w.set_hpre(hpre_bits);
199 });
200
201 // Wait for the new prescalers to kick in
202 // "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
203 cortex_m::asm::delay(16);
204
205 RCC.cfgr().modify(|w| {
206 w.set_sw(if sysclk_on_pll {
207 Sw::PLL
208 } else if self.config.hse.is_some() {
209 Sw::HSE
210 } else {
211 Sw::HSI
212 })
213 });
214 }
215
216 Clocks {
217 sys: Hertz(sysclk),
218 apb1: Hertz(pclk1),
219 apb2: Hertz(pclk2),
220
221 apb1_tim: Hertz(pclk1 * timer_mul1),
222 apb2_tim: Hertz(pclk2 * timer_mul2),
223
224 ahb1: Hertz(hclk),
225 ahb2: Hertz(hclk),
226 ahb3: Hertz(hclk),
227 }
228 }
229
230 // Safety: RCC init must have been called
231 pub fn clocks(&self) -> &'static Clocks {
232 unsafe { get_freqs() }
233 }
234
235 fn setup_pll(
236 &mut self,
237 pllsrcclk: u32,
238 use_hse: bool,
239 pllsysclk: Option<u32>,
240 pll48clk: bool,
241 ) -> PllResults {
242 use crate::pac::rcc::vals::{Pllp, Pllsrc};
243
244 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
245 if pllsysclk.is_none() && !pll48clk {
246 // NOTE(unsafe) We have a mutable borrow to the owner of the RegBlock
247 unsafe {
248 RCC.pllcfgr()
249 .modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
250 }
251
252 return PllResults {
253 use_pll: false,
254 pllsysclk: None,
255 pll48clk: None,
256 };
257 }
258 // Input divisor from PLL source clock, must result to frequency in
259 // the range from 1 to 2 MHz
260 let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
261 let pllm_max = pllsrcclk / 1_000_000;
262
263 // Sysclk output divisor must be one of 2, 4, 6 or 8
264 let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
265
266 let target_freq = if pll48clk {
267 48_000_000
268 } else {
269 sysclk * sysclk_div
270 };
271
272 // Find the lowest pllm value that minimize the difference between
273 // target frequency and the real vco_out frequency.
274 let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
275 let vco_in = pllsrcclk / pllm;
276 let plln = target_freq / vco_in;
277 target_freq - vco_in * plln
278 }));
279
280 let vco_in = pllsrcclk / pllm;
281 assert!((1_000_000..=2_000_000).contains(&vco_in));
282
283 // Main scaler, must result in >= 100MHz (>= 192MHz for F401)
284 // and <= 432MHz, min 50, max 432
285 let plln = if pll48clk {
286 // try the different valid pllq according to the valid
287 // main scaller values, and take the best
288 let pllq = unwrap!((4..=9).min_by_key(|pllq| {
289 let plln = 48_000_000 * pllq / vco_in;
290 let pll48_diff = 48_000_000 - vco_in * plln / pllq;
291 let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
292 (pll48_diff, sysclk_diff)
293 }));
294 48_000_000 * pllq / vco_in
295 } else {
296 sysclk * sysclk_div / vco_in
297 };
298
299 let pllp = (sysclk_div / 2) - 1;
300
301 let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
302 let real_pll48clk = vco_in * plln / pllq;
303
304 unsafe {
305 RCC.pllcfgr().modify(|w| {
306 w.set_pllm(pllm as u8);
307 w.set_plln(plln as u16);
308 w.set_pllp(Pllp(pllp as u8));
309 w.set_pllq(pllq as u8);
310 w.set_pllsrc(Pllsrc(use_hse as u8));
311 });
312 }
313
314 let real_pllsysclk = vco_in * plln / sysclk_div;
315
316 PllResults {
317 use_pll: true,
318 pllsysclk: Some(real_pllsysclk),
319 pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
320 }
321 }
322
323 fn flash_setup(sysclk: u32) {
324 use crate::pac::flash::vals::Latency;
325
326 // Be conservative with voltage ranges
327 const FLASH_LATENCY_STEP: u32 = 30_000_000;
328
329 critical_section::with(|_| unsafe {
330 FLASH
331 .acr()
332 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
333 });
334 }
335}
336
337pub unsafe fn init(config: Config) {
338 let r = <peripherals::RCC as embassy::util::Steal>::steal();
339 let clocks = Rcc::new(r, config).freeze();
340 set_freqs(clocks);
341}
342
343struct PllResults {
344 use_pll: bool,
345 pllsysclk: Option<u32>,
346 pll48clk: Option<u32>,
347}
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
new file mode 100644
index 000000000..a3a4c197f
--- /dev/null
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -0,0 +1,183 @@
1use crate::pac::{PWR, RCC};
2use crate::rcc::{set_freqs, Clocks};
3use crate::time::Hertz;
4use crate::time::U32Ext;
5
6/// HSI speed
7pub const HSI_FREQ: u32 = 16_000_000;
8
9/// LSI speed
10pub const LSI_FREQ: u32 = 32_000;
11
12/// System clock mux source
13#[derive(Clone, Copy)]
14pub enum ClockSrc {
15 HSE(Hertz),
16 HSI16(HSI16Prescaler),
17 LSI,
18}
19
20#[derive(Clone, Copy)]
21pub enum HSI16Prescaler {
22 NotDivided,
23 Div2,
24 Div4,
25 Div8,
26 Div16,
27 Div32,
28 Div64,
29 Div128,
30}
31
32impl Into<u8> for HSI16Prescaler {
33 fn into(self) -> u8 {
34 match self {
35 HSI16Prescaler::NotDivided => 0x00,
36 HSI16Prescaler::Div2 => 0x01,
37 HSI16Prescaler::Div4 => 0x02,
38 HSI16Prescaler::Div8 => 0x03,
39 HSI16Prescaler::Div16 => 0x04,
40 HSI16Prescaler::Div32 => 0x05,
41 HSI16Prescaler::Div64 => 0x06,
42 HSI16Prescaler::Div128 => 0x07,
43 }
44 }
45}
46
47/// AHB prescaler
48#[derive(Clone, Copy, PartialEq)]
49pub enum AHBPrescaler {
50 NotDivided,
51 Div2,
52 Div4,
53 Div8,
54 Div16,
55 Div64,
56 Div128,
57 Div256,
58 Div512,
59}
60
61/// APB prescaler
62#[derive(Clone, Copy)]
63pub enum APBPrescaler {
64 NotDivided,
65 Div2,
66 Div4,
67 Div8,
68 Div16,
69}
70
71impl Into<u8> for APBPrescaler {
72 fn into(self) -> u8 {
73 match self {
74 APBPrescaler::NotDivided => 1,
75 APBPrescaler::Div2 => 0x04,
76 APBPrescaler::Div4 => 0x05,
77 APBPrescaler::Div8 => 0x06,
78 APBPrescaler::Div16 => 0x07,
79 }
80 }
81}
82
83impl Into<u8> for AHBPrescaler {
84 fn into(self) -> u8 {
85 match self {
86 AHBPrescaler::NotDivided => 1,
87 AHBPrescaler::Div2 => 0x08,
88 AHBPrescaler::Div4 => 0x09,
89 AHBPrescaler::Div8 => 0x0a,
90 AHBPrescaler::Div16 => 0x0b,
91 AHBPrescaler::Div64 => 0x0c,
92 AHBPrescaler::Div128 => 0x0d,
93 AHBPrescaler::Div256 => 0x0e,
94 AHBPrescaler::Div512 => 0x0f,
95 }
96 }
97}
98
99/// Clocks configutation
100pub struct Config {
101 pub mux: ClockSrc,
102 pub ahb_pre: AHBPrescaler,
103 pub apb_pre: APBPrescaler,
104 pub low_power_run: bool,
105}
106
107impl Default for Config {
108 #[inline]
109 fn default() -> Config {
110 Config {
111 mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
112 ahb_pre: AHBPrescaler::NotDivided,
113 apb_pre: APBPrescaler::NotDivided,
114 low_power_run: false,
115 }
116 }
117}
118
119pub(crate) unsafe fn init(config: Config) {
120 let (sys_clk, sw) = match config.mux {
121 ClockSrc::HSI16(div) => {
122 // Enable HSI16
123 let div: u8 = div.into();
124 RCC.cr().write(|w| {
125 w.set_hsidiv(div);
126 w.set_hsion(true)
127 });
128 while !RCC.cr().read().hsirdy() {}
129
130 (HSI_FREQ >> div, 0x00)
131 }
132 ClockSrc::HSE(freq) => {
133 // Enable HSE
134 RCC.cr().write(|w| w.set_hseon(true));
135 while !RCC.cr().read().hserdy() {}
136
137 (freq.0, 0x01)
138 }
139 ClockSrc::LSI => {
140 // Enable LSI
141 RCC.csr().write(|w| w.set_lsion(true));
142 while !RCC.csr().read().lsirdy() {}
143 (LSI_FREQ, 0x03)
144 }
145 };
146
147 RCC.cfgr().modify(|w| {
148 w.set_sw(sw.into());
149 w.set_hpre(config.ahb_pre.into());
150 w.set_ppre(config.apb_pre.into());
151 });
152
153 let ahb_freq: u32 = match config.ahb_pre {
154 AHBPrescaler::NotDivided => sys_clk,
155 pre => {
156 let pre: u8 = pre.into();
157 let pre = 1 << (pre as u32 - 7);
158 sys_clk / pre
159 }
160 };
161
162 let (apb_freq, apb_tim_freq) = match config.apb_pre {
163 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
164 pre => {
165 let pre: u8 = pre.into();
166 let pre: u8 = 1 << (pre - 3);
167 let freq = ahb_freq / pre as u32;
168 (freq, freq * 2)
169 }
170 };
171
172 if config.low_power_run {
173 assert!(sys_clk.hz() <= 2_000_000.hz());
174 PWR.cr1().modify(|w| w.set_lpr(true));
175 }
176
177 set_freqs(Clocks {
178 sys: sys_clk.hz(),
179 ahb: ahb_freq.hz(),
180 apb: apb_freq.hz(),
181 apb_tim: apb_tim_freq.hz(),
182 });
183}
diff --git a/embassy-stm32/src/rcc/g0/mod.rs b/embassy-stm32/src/rcc/g0/mod.rs
deleted file mode 100644
index 7f7af2fc9..000000000
--- a/embassy-stm32/src/rcc/g0/mod.rs
+++ /dev/null
@@ -1,234 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9
10/// HSI speed
11pub const HSI_FREQ: u32 = 16_000_000;
12
13/// LSI speed
14pub const LSI_FREQ: u32 = 32_000;
15
16/// System clock mux source
17#[derive(Clone, Copy)]
18pub enum ClockSrc {
19 HSE(Hertz),
20 HSI16(HSI16Prescaler),
21 LSI,
22}
23
24#[derive(Clone, Copy)]
25pub enum HSI16Prescaler {
26 NotDivided,
27 Div2,
28 Div4,
29 Div8,
30 Div16,
31 Div32,
32 Div64,
33 Div128,
34}
35
36impl Into<u8> for HSI16Prescaler {
37 fn into(self) -> u8 {
38 match self {
39 HSI16Prescaler::NotDivided => 0x00,
40 HSI16Prescaler::Div2 => 0x01,
41 HSI16Prescaler::Div4 => 0x02,
42 HSI16Prescaler::Div8 => 0x03,
43 HSI16Prescaler::Div16 => 0x04,
44 HSI16Prescaler::Div32 => 0x05,
45 HSI16Prescaler::Div64 => 0x06,
46 HSI16Prescaler::Div128 => 0x07,
47 }
48 }
49}
50
51/// AHB prescaler
52#[derive(Clone, Copy, PartialEq)]
53pub enum AHBPrescaler {
54 NotDivided,
55 Div2,
56 Div4,
57 Div8,
58 Div16,
59 Div64,
60 Div128,
61 Div256,
62 Div512,
63}
64
65/// APB prescaler
66#[derive(Clone, Copy)]
67pub enum APBPrescaler {
68 NotDivided,
69 Div2,
70 Div4,
71 Div8,
72 Div16,
73}
74
75impl Into<u8> for APBPrescaler {
76 fn into(self) -> u8 {
77 match self {
78 APBPrescaler::NotDivided => 1,
79 APBPrescaler::Div2 => 0x04,
80 APBPrescaler::Div4 => 0x05,
81 APBPrescaler::Div8 => 0x06,
82 APBPrescaler::Div16 => 0x07,
83 }
84 }
85}
86
87impl Into<u8> for AHBPrescaler {
88 fn into(self) -> u8 {
89 match self {
90 AHBPrescaler::NotDivided => 1,
91 AHBPrescaler::Div2 => 0x08,
92 AHBPrescaler::Div4 => 0x09,
93 AHBPrescaler::Div8 => 0x0a,
94 AHBPrescaler::Div16 => 0x0b,
95 AHBPrescaler::Div64 => 0x0c,
96 AHBPrescaler::Div128 => 0x0d,
97 AHBPrescaler::Div256 => 0x0e,
98 AHBPrescaler::Div512 => 0x0f,
99 }
100 }
101}
102
103/// Clocks configutation
104pub struct Config {
105 pub mux: ClockSrc,
106 pub ahb_pre: AHBPrescaler,
107 pub apb_pre: APBPrescaler,
108 pub low_power_run: bool,
109}
110
111impl Default for Config {
112 #[inline]
113 fn default() -> Config {
114 Config {
115 mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
116 ahb_pre: AHBPrescaler::NotDivided,
117 apb_pre: APBPrescaler::NotDivided,
118 low_power_run: false,
119 }
120 }
121}
122
123/// RCC peripheral
124pub struct Rcc<'d> {
125 _rb: peripherals::RCC,
126 phantom: PhantomData<&'d mut peripherals::RCC>,
127}
128
129impl<'d> Rcc<'d> {
130 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
131 unborrow!(rcc);
132 Self {
133 _rb: rcc,
134 phantom: PhantomData,
135 }
136 }
137
138 // Safety: RCC init must have been called
139 pub fn clocks(&self) -> &'static Clocks {
140 unsafe { get_freqs() }
141 }
142}
143
144/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
145pub trait RccExt {
146 fn freeze(self, config: Config) -> Clocks;
147}
148
149impl RccExt for RCC {
150 #[inline]
151 fn freeze(self, cfgr: Config) -> Clocks {
152 let rcc = pac::RCC;
153 let (sys_clk, sw) = match cfgr.mux {
154 ClockSrc::HSI16(div) => {
155 // Enable HSI16
156 let div: u8 = div.into();
157 unsafe {
158 rcc.cr().write(|w| {
159 w.set_hsidiv(div);
160 w.set_hsion(true)
161 });
162 while !rcc.cr().read().hsirdy() {}
163 }
164
165 (HSI_FREQ >> div, 0x00)
166 }
167 ClockSrc::HSE(freq) => {
168 // Enable HSE
169 unsafe {
170 rcc.cr().write(|w| w.set_hseon(true));
171 while !rcc.cr().read().hserdy() {}
172 }
173
174 (freq.0, 0x01)
175 }
176 ClockSrc::LSI => {
177 // Enable LSI
178 unsafe {
179 rcc.csr().write(|w| w.set_lsion(true));
180 while !rcc.csr().read().lsirdy() {}
181 }
182 (LSI_FREQ, 0x03)
183 }
184 };
185
186 unsafe {
187 rcc.cfgr().modify(|w| {
188 w.set_sw(sw.into());
189 w.set_hpre(cfgr.ahb_pre.into());
190 w.set_ppre(cfgr.apb_pre.into());
191 });
192 }
193
194 let ahb_freq: u32 = match cfgr.ahb_pre {
195 AHBPrescaler::NotDivided => sys_clk,
196 pre => {
197 let pre: u8 = pre.into();
198 let pre = 1 << (pre as u32 - 7);
199 sys_clk / pre
200 }
201 };
202
203 let (apb_freq, apb_tim_freq) = match cfgr.apb_pre {
204 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
205 pre => {
206 let pre: u8 = pre.into();
207 let pre: u8 = 1 << (pre - 3);
208 let freq = ahb_freq / pre as u32;
209 (freq, freq * 2)
210 }
211 };
212
213 let pwr = pac::PWR;
214 if cfgr.low_power_run {
215 assert!(sys_clk.hz() <= 2_000_000.hz());
216 unsafe {
217 pwr.cr1().modify(|w| w.set_lpr(true));
218 }
219 }
220
221 Clocks {
222 sys: sys_clk.hz(),
223 ahb: ahb_freq.hz(),
224 apb: apb_freq.hz(),
225 apb_tim: apb_tim_freq.hz(),
226 }
227 }
228}
229
230pub unsafe fn init(config: Config) {
231 let r = <peripherals::RCC as embassy::util::Steal>::steal();
232 let clocks = r.freeze(config);
233 set_freqs(clocks);
234}
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
new file mode 100644
index 000000000..ce8cca45d
--- /dev/null
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -0,0 +1,161 @@
1use crate::pac::{PWR, RCC};
2use crate::rcc::{set_freqs, Clocks};
3use crate::time::Hertz;
4use crate::time::U32Ext;
5
6/// HSI speed
7pub const HSI_FREQ: u32 = 16_000_000;
8
9/// LSI speed
10pub const LSI_FREQ: u32 = 32_000;
11
12/// System clock mux source
13#[derive(Clone, Copy)]
14pub enum ClockSrc {
15 HSE(Hertz),
16 HSI16,
17}
18
19/// AHB prescaler
20#[derive(Clone, Copy, PartialEq)]
21pub enum AHBPrescaler {
22 NotDivided,
23 Div2,
24 Div4,
25 Div8,
26 Div16,
27 Div64,
28 Div128,
29 Div256,
30 Div512,
31}
32
33/// APB prescaler
34#[derive(Clone, Copy)]
35pub enum APBPrescaler {
36 NotDivided,
37 Div2,
38 Div4,
39 Div8,
40 Div16,
41}
42
43impl Into<u8> for APBPrescaler {
44 fn into(self) -> u8 {
45 match self {
46 APBPrescaler::NotDivided => 1,
47 APBPrescaler::Div2 => 0x04,
48 APBPrescaler::Div4 => 0x05,
49 APBPrescaler::Div8 => 0x06,
50 APBPrescaler::Div16 => 0x07,
51 }
52 }
53}
54
55impl Into<u8> for AHBPrescaler {
56 fn into(self) -> u8 {
57 match self {
58 AHBPrescaler::NotDivided => 1,
59 AHBPrescaler::Div2 => 0x08,
60 AHBPrescaler::Div4 => 0x09,
61 AHBPrescaler::Div8 => 0x0a,
62 AHBPrescaler::Div16 => 0x0b,
63 AHBPrescaler::Div64 => 0x0c,
64 AHBPrescaler::Div128 => 0x0d,
65 AHBPrescaler::Div256 => 0x0e,
66 AHBPrescaler::Div512 => 0x0f,
67 }
68 }
69}
70
71/// Clocks configutation
72pub struct Config {
73 pub mux: ClockSrc,
74 pub ahb_pre: AHBPrescaler,
75 pub apb1_pre: APBPrescaler,
76 pub apb2_pre: APBPrescaler,
77 pub low_power_run: bool,
78}
79
80impl Default for Config {
81 #[inline]
82 fn default() -> Config {
83 Config {
84 mux: ClockSrc::HSI16,
85 ahb_pre: AHBPrescaler::NotDivided,
86 apb1_pre: APBPrescaler::NotDivided,
87 apb2_pre: APBPrescaler::NotDivided,
88 low_power_run: false,
89 }
90 }
91}
92
93pub(crate) unsafe fn init(config: Config) {
94 let (sys_clk, sw) = match config.mux {
95 ClockSrc::HSI16 => {
96 // Enable HSI16
97 RCC.cr().write(|w| w.set_hsion(true));
98 while !RCC.cr().read().hsirdy() {}
99
100 (HSI_FREQ, 0x01)
101 }
102 ClockSrc::HSE(freq) => {
103 // Enable HSE
104 RCC.cr().write(|w| w.set_hseon(true));
105 while !RCC.cr().read().hserdy() {}
106
107 (freq.0, 0x02)
108 }
109 };
110
111 RCC.cfgr().modify(|w| {
112 w.set_sw(sw.into());
113 w.set_hpre(config.ahb_pre.into());
114 w.set_ppre1(config.apb1_pre.into());
115 w.set_ppre2(config.apb2_pre.into());
116 });
117
118 let ahb_freq: u32 = match config.ahb_pre {
119 AHBPrescaler::NotDivided => sys_clk,
120 pre => {
121 let pre: u8 = pre.into();
122 let pre = 1 << (pre as u32 - 7);
123 sys_clk / pre
124 }
125 };
126
127 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
128 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
129 pre => {
130 let pre: u8 = pre.into();
131 let pre: u8 = 1 << (pre - 3);
132 let freq = ahb_freq / pre as u32;
133 (freq, freq * 2)
134 }
135 };
136
137 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
138 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
139 pre => {
140 let pre: u8 = pre.into();
141 let pre: u8 = 1 << (pre - 3);
142 let freq = ahb_freq / pre as u32;
143 (freq, freq * 2)
144 }
145 };
146
147 if config.low_power_run {
148 assert!(sys_clk.hz() <= 2_000_000.hz());
149 PWR.cr1().modify(|w| w.set_lpr(true));
150 }
151
152 set_freqs(Clocks {
153 sys: sys_clk.hz(),
154 ahb1: ahb_freq.hz(),
155 ahb2: ahb_freq.hz(),
156 apb1: apb1_freq.hz(),
157 apb1_tim: apb1_tim_freq.hz(),
158 apb2: apb2_freq.hz(),
159 apb2_tim: apb2_tim_freq.hz(),
160 });
161}
diff --git a/embassy-stm32/src/rcc/g4/mod.rs b/embassy-stm32/src/rcc/g4/mod.rs
deleted file mode 100644
index 8a75b2e03..000000000
--- a/embassy-stm32/src/rcc/g4/mod.rs
+++ /dev/null
@@ -1,210 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9
10/// HSI speed
11pub const HSI_FREQ: u32 = 16_000_000;
12
13/// LSI speed
14pub const LSI_FREQ: u32 = 32_000;
15
16/// System clock mux source
17#[derive(Clone, Copy)]
18pub enum ClockSrc {
19 HSE(Hertz),
20 HSI16,
21}
22
23/// AHB prescaler
24#[derive(Clone, Copy, PartialEq)]
25pub enum AHBPrescaler {
26 NotDivided,
27 Div2,
28 Div4,
29 Div8,
30 Div16,
31 Div64,
32 Div128,
33 Div256,
34 Div512,
35}
36
37/// APB prescaler
38#[derive(Clone, Copy)]
39pub enum APBPrescaler {
40 NotDivided,
41 Div2,
42 Div4,
43 Div8,
44 Div16,
45}
46
47impl Into<u8> for APBPrescaler {
48 fn into(self) -> u8 {
49 match self {
50 APBPrescaler::NotDivided => 1,
51 APBPrescaler::Div2 => 0x04,
52 APBPrescaler::Div4 => 0x05,
53 APBPrescaler::Div8 => 0x06,
54 APBPrescaler::Div16 => 0x07,
55 }
56 }
57}
58
59impl Into<u8> for AHBPrescaler {
60 fn into(self) -> u8 {
61 match self {
62 AHBPrescaler::NotDivided => 1,
63 AHBPrescaler::Div2 => 0x08,
64 AHBPrescaler::Div4 => 0x09,
65 AHBPrescaler::Div8 => 0x0a,
66 AHBPrescaler::Div16 => 0x0b,
67 AHBPrescaler::Div64 => 0x0c,
68 AHBPrescaler::Div128 => 0x0d,
69 AHBPrescaler::Div256 => 0x0e,
70 AHBPrescaler::Div512 => 0x0f,
71 }
72 }
73}
74
75/// Clocks configutation
76pub struct Config {
77 pub mux: ClockSrc,
78 pub ahb_pre: AHBPrescaler,
79 pub apb1_pre: APBPrescaler,
80 pub apb2_pre: APBPrescaler,
81 pub low_power_run: bool,
82}
83
84impl Default for Config {
85 #[inline]
86 fn default() -> Config {
87 Config {
88 mux: ClockSrc::HSI16,
89 ahb_pre: AHBPrescaler::NotDivided,
90 apb1_pre: APBPrescaler::NotDivided,
91 apb2_pre: APBPrescaler::NotDivided,
92 low_power_run: false,
93 }
94 }
95}
96
97/// RCC peripheral
98pub struct Rcc<'d> {
99 _rb: peripherals::RCC,
100 phantom: PhantomData<&'d mut peripherals::RCC>,
101}
102
103impl<'d> Rcc<'d> {
104 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
105 unborrow!(rcc);
106 Self {
107 _rb: rcc,
108 phantom: PhantomData,
109 }
110 }
111
112 // Safety: RCC init must have been called
113 pub fn clocks(&self) -> &'static Clocks {
114 unsafe { get_freqs() }
115 }
116}
117
118/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
119pub trait RccExt {
120 fn freeze(self, config: Config) -> Clocks;
121}
122
123impl RccExt for RCC {
124 #[inline]
125 fn freeze(self, cfgr: Config) -> Clocks {
126 let rcc = pac::RCC;
127 let (sys_clk, sw) = match cfgr.mux {
128 ClockSrc::HSI16 => {
129 // Enable HSI16
130 unsafe {
131 rcc.cr().write(|w| w.set_hsion(true));
132 while !rcc.cr().read().hsirdy() {}
133 }
134
135 (HSI_FREQ, 0x01)
136 }
137 ClockSrc::HSE(freq) => {
138 // Enable HSE
139 unsafe {
140 rcc.cr().write(|w| w.set_hseon(true));
141 while !rcc.cr().read().hserdy() {}
142 }
143
144 (freq.0, 0x02)
145 }
146 };
147
148 unsafe {
149 rcc.cfgr().modify(|w| {
150 w.set_sw(sw.into());
151 w.set_hpre(cfgr.ahb_pre.into());
152 w.set_ppre1(cfgr.apb1_pre.into());
153 w.set_ppre2(cfgr.apb2_pre.into());
154 });
155 }
156
157 let ahb_freq: u32 = match cfgr.ahb_pre {
158 AHBPrescaler::NotDivided => sys_clk,
159 pre => {
160 let pre: u8 = pre.into();
161 let pre = 1 << (pre as u32 - 7);
162 sys_clk / pre
163 }
164 };
165
166 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
167 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
168 pre => {
169 let pre: u8 = pre.into();
170 let pre: u8 = 1 << (pre - 3);
171 let freq = ahb_freq / pre as u32;
172 (freq, freq * 2)
173 }
174 };
175
176 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
177 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
178 pre => {
179 let pre: u8 = pre.into();
180 let pre: u8 = 1 << (pre - 3);
181 let freq = ahb_freq / pre as u32;
182 (freq, freq * 2)
183 }
184 };
185
186 let pwr = pac::PWR;
187 if cfgr.low_power_run {
188 assert!(sys_clk.hz() <= 2_000_000.hz());
189 unsafe {
190 pwr.cr1().modify(|w| w.set_lpr(true));
191 }
192 }
193
194 Clocks {
195 sys: sys_clk.hz(),
196 ahb1: ahb_freq.hz(),
197 ahb2: ahb_freq.hz(),
198 apb1: apb1_freq.hz(),
199 apb1_tim: apb1_tim_freq.hz(),
200 apb2: apb2_freq.hz(),
201 apb2_tim: apb2_tim_freq.hz(),
202 }
203 }
204}
205
206pub unsafe fn init(config: Config) {
207 let r = <peripherals::RCC as embassy::util::Steal>::steal();
208 let clocks = r.freeze(config);
209 set_freqs(clocks);
210}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
new file mode 100644
index 000000000..55ddf073a
--- /dev/null
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -0,0 +1,875 @@
1use core::marker::PhantomData;
2
3use embassy::util::Unborrow;
4use embassy_hal_common::unborrow;
5use stm32_metapac::rcc::vals::{Mco1, Mco2};
6
7use crate::gpio::sealed::Pin as __GpioPin;
8use crate::gpio::Pin;
9use crate::pac::rcc::vals::Timpre;
10use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw};
11use crate::pac::{PWR, RCC, SYSCFG};
12use crate::peripherals;
13use crate::rcc::{set_freqs, Clocks};
14use crate::time::Hertz;
15
16pub use pll::PllConfig;
17
18const HSI: Hertz = Hertz(64_000_000);
19const CSI: Hertz = Hertz(4_000_000);
20const HSI48: Hertz = Hertz(48_000_000);
21const LSI: Hertz = Hertz(32_000);
22
23/// Voltage Scale
24///
25/// Represents the voltage range feeding the CPU core. The maximum core
26/// clock frequency depends on this value.
27#[derive(Copy, Clone, PartialEq)]
28pub enum VoltageScale {
29 /// VOS 0 range VCORE 1.26V - 1.40V
30 Scale0,
31 /// VOS 1 range VCORE 1.15V - 1.26V
32 Scale1,
33 /// VOS 2 range VCORE 1.05V - 1.15V
34 Scale2,
35 /// VOS 3 range VCORE 0.95V - 1.05V
36 Scale3,
37}
38
39/// Core clock frequencies
40#[derive(Clone, Copy)]
41pub struct CoreClocks {
42 pub hclk: Hertz,
43 pub pclk1: Hertz,
44 pub pclk2: Hertz,
45 pub pclk3: Hertz,
46 pub pclk4: Hertz,
47 pub ppre1: u8,
48 pub ppre2: u8,
49 pub ppre3: u8,
50 pub ppre4: u8,
51 pub csi_ck: Option<Hertz>,
52 pub hsi_ck: Option<Hertz>,
53 pub hsi48_ck: Option<Hertz>,
54 pub lsi_ck: Option<Hertz>,
55 pub per_ck: Option<Hertz>,
56 pub hse_ck: Option<Hertz>,
57 pub pll1_p_ck: Option<Hertz>,
58 pub pll1_q_ck: Option<Hertz>,
59 pub pll1_r_ck: Option<Hertz>,
60 pub pll2_p_ck: Option<Hertz>,
61 pub pll2_q_ck: Option<Hertz>,
62 pub pll2_r_ck: Option<Hertz>,
63 pub pll3_p_ck: Option<Hertz>,
64 pub pll3_q_ck: Option<Hertz>,
65 pub pll3_r_ck: Option<Hertz>,
66 pub timx_ker_ck: Option<Hertz>,
67 pub timy_ker_ck: Option<Hertz>,
68 pub sys_ck: Hertz,
69 pub c_ck: Hertz,
70}
71
72/// Configuration of the core clocks
73#[non_exhaustive]
74#[derive(Default)]
75pub struct Config {
76 pub hse: Option<Hertz>,
77 pub bypass_hse: bool,
78 pub sys_ck: Option<Hertz>,
79 pub per_ck: Option<Hertz>,
80 rcc_hclk: Option<Hertz>,
81 pub hclk: Option<Hertz>,
82 pub pclk1: Option<Hertz>,
83 pub pclk2: Option<Hertz>,
84 pub pclk3: Option<Hertz>,
85 pub pclk4: Option<Hertz>,
86 pub pll1: PllConfig,
87 pub pll2: PllConfig,
88 pub pll3: PllConfig,
89}
90
91/// Setup traceclk
92/// Returns a pll1_r_ck
93fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
94 let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
95 // pll1_p_ck selected as system clock but pll1_r_ck not
96 // set. The traceclk mux is synchronous with the system
97 // clock mux, but has pll1_r_ck as an input. In order to
98 // keep traceclk running, we force a pll1_r_ck.
99 (true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
100
101 // Either pll1 not selected as system clock, free choice
102 // of pll1_r_ck. Or pll1 is selected, assume user has set
103 // a suitable pll1_r_ck frequency.
104 _ => config.pll1.r_ck,
105 };
106 config.pll1.r_ck = pll1_r_ck;
107}
108
109/// Divider calculator for pclk 1 - 4
110///
111/// Returns real pclk, bits, ppre and the timer kernel clock
112fn ppre_calculate(
113 requested_pclk: u32,
114 hclk: u32,
115 max_pclk: u32,
116 tim_pre: Option<Timpre>,
117) -> (u32, u8, u8, Option<u32>) {
118 let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
119 0 => panic!(),
120 1 => (0b000, 1),
121 2 => (0b100, 2),
122 3..=5 => (0b101, 4),
123 6..=11 => (0b110, 8),
124 _ => (0b111, 16),
125 };
126 let real_pclk = hclk / u32::from(ppre);
127 assert!(real_pclk <= max_pclk);
128
129 let tim_ker_clk = if let Some(tim_pre) = tim_pre {
130 let clk = match (bits, tim_pre) {
131 (0b101, Timpre::DEFAULTX2) => hclk / 2,
132 (0b110, Timpre::DEFAULTX4) => hclk / 2,
133 (0b110, Timpre::DEFAULTX2) => hclk / 4,
134 (0b111, Timpre::DEFAULTX4) => hclk / 4,
135 (0b111, Timpre::DEFAULTX2) => hclk / 8,
136 _ => hclk,
137 };
138 Some(clk)
139 } else {
140 None
141 };
142 (real_pclk, bits, ppre, tim_ker_clk)
143}
144
145/// Setup sys_ck
146/// Returns sys_ck frequency, and a pll1_p_ck
147fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
148 // Compare available with wanted clocks
149 let sys_ck = config.sys_ck.unwrap_or(srcclk);
150
151 if sys_ck != srcclk {
152 // The requested system clock is not the immediately available
153 // HSE/HSI clock. Perhaps there are other ways of obtaining
154 // the requested system clock (such as `HSIDIV`) but we will
155 // ignore those for now.
156 //
157 // Therefore we must use pll1_p_ck
158 let pll1_p_ck = match config.pll1.p_ck {
159 Some(p_ck) => {
160 assert!(p_ck == sys_ck,
161 "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck");
162 Some(p_ck)
163 }
164 None => Some(sys_ck),
165 };
166 config.pll1.p_ck = pll1_p_ck;
167
168 (sys_ck, true)
169 } else {
170 // sys_ck is derived directly from a source clock
171 // (HSE/HSI). pll1_p_ck can be as requested
172 (sys_ck, false)
173 }
174}
175
176fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
177 use crate::pac::FLASH;
178
179 // ACLK in MHz, round down and subtract 1 from integers. eg.
180 // 61_999_999 -> 61MHz
181 // 62_000_000 -> 61MHz
182 // 62_000_001 -> 62MHz
183 let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
184
185 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
186 // states and programming delay
187 let (wait_states, progr_delay) = match vos {
188 // VOS 0 range VCORE 1.26V - 1.40V
189 VoltageScale::Scale0 => match rcc_aclk_mhz {
190 0..=69 => (0, 0),
191 70..=139 => (1, 1),
192 140..=184 => (2, 1),
193 185..=209 => (2, 2),
194 210..=224 => (3, 2),
195 225..=239 => (4, 2),
196 _ => (7, 3),
197 },
198 // VOS 1 range VCORE 1.15V - 1.26V
199 VoltageScale::Scale1 => match rcc_aclk_mhz {
200 0..=69 => (0, 0),
201 70..=139 => (1, 1),
202 140..=184 => (2, 1),
203 185..=209 => (2, 2),
204 210..=224 => (3, 2),
205 _ => (7, 3),
206 },
207 // VOS 2 range VCORE 1.05V - 1.15V
208 VoltageScale::Scale2 => match rcc_aclk_mhz {
209 0..=54 => (0, 0),
210 55..=109 => (1, 1),
211 110..=164 => (2, 1),
212 165..=224 => (3, 2),
213 _ => (7, 3),
214 },
215 // VOS 3 range VCORE 0.95V - 1.05V
216 VoltageScale::Scale3 => match rcc_aclk_mhz {
217 0..=44 => (0, 0),
218 45..=89 => (1, 1),
219 90..=134 => (2, 1),
220 135..=179 => (3, 2),
221 180..=224 => (4, 2),
222 _ => (7, 3),
223 },
224 };
225
226 // NOTE(unsafe) Atomic write
227 unsafe {
228 FLASH.acr().write(|w| {
229 w.set_wrhighfreq(progr_delay);
230 w.set_latency(wait_states)
231 });
232 while FLASH.acr().read().latency() != wait_states {}
233 }
234}
235
236pub enum McoClock {
237 Disabled,
238 Bypassed,
239 Divided(u8),
240}
241
242impl McoClock {
243 fn into_raw(&self) -> u8 {
244 match self {
245 McoClock::Disabled => 0,
246 McoClock::Bypassed => 1,
247 McoClock::Divided(divisor) => {
248 if *divisor > 15 {
249 panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
250 }
251 *divisor
252 }
253 }
254 }
255}
256
257#[derive(Copy, Clone)]
258pub enum Mco1Source {
259 Hsi,
260 Lse,
261 Hse,
262 Pll1Q,
263 Hsi48,
264}
265
266impl Default for Mco1Source {
267 fn default() -> Self {
268 Self::Hsi
269 }
270}
271
272pub trait McoSource {
273 type Raw;
274
275 fn into_raw(&self) -> Self::Raw;
276}
277
278impl McoSource for Mco1Source {
279 type Raw = Mco1;
280 fn into_raw(&self) -> Self::Raw {
281 match self {
282 Mco1Source::Hsi => Mco1::HSI,
283 Mco1Source::Lse => Mco1::LSE,
284 Mco1Source::Hse => Mco1::HSE,
285 Mco1Source::Pll1Q => Mco1::PLL1_Q,
286 Mco1Source::Hsi48 => Mco1::HSI48,
287 }
288 }
289}
290
291#[derive(Copy, Clone)]
292pub enum Mco2Source {
293 SysClk,
294 Pll2Q,
295 Hse,
296 Pll1Q,
297 Csi,
298 Lsi,
299}
300
301impl Default for Mco2Source {
302 fn default() -> Self {
303 Self::SysClk
304 }
305}
306
307impl McoSource for Mco2Source {
308 type Raw = Mco2;
309 fn into_raw(&self) -> Self::Raw {
310 match self {
311 Mco2Source::SysClk => Mco2::SYSCLK,
312 Mco2Source::Pll2Q => Mco2::PLL2_P,
313 Mco2Source::Hse => Mco2::HSE,
314 Mco2Source::Pll1Q => Mco2::PLL1_P,
315 Mco2Source::Csi => Mco2::CSI,
316 Mco2Source::Lsi => Mco2::LSI,
317 }
318 }
319}
320
321pub(crate) mod sealed {
322 use super::*;
323
324 pub trait McoInstance {
325 type Source;
326 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
327 }
328
329 pub trait McoPin<T: McoInstance>: Pin {
330 fn configure(&mut self);
331 }
332}
333
334pub trait McoInstance: sealed::McoInstance + 'static {}
335
336pub trait McoPin<T: McoInstance>: sealed::McoPin<T> + 'static {}
337
338macro_rules! impl_peri {
339 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
340 impl sealed::McoInstance for peripherals::$peri {
341 type Source = $source;
342
343 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
344 RCC.cfgr().modify(|w| {
345 w.$set_source(source);
346 w.$set_prescaler(prescaler);
347 });
348 }
349 }
350
351 impl McoInstance for peripherals::$peri {}
352 };
353}
354
355impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
356impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
357
358macro_rules! impl_pin {
359 ($peri:ident, $pin:ident, $af:expr) => {
360 impl McoPin<peripherals::$peri> for peripherals::$pin {}
361
362 impl sealed::McoPin<peripherals::$peri> for peripherals::$pin {
363 fn configure(&mut self) {
364 critical_section::with(|_| unsafe {
365 self.set_as_af($af, crate::gpio::sealed::AFType::OutputPushPull);
366 self.block().ospeedr().modify(|w| {
367 w.set_ospeedr(
368 self.pin() as usize,
369 crate::pac::gpio::vals::Ospeedr::VERYHIGHSPEED,
370 )
371 });
372 })
373 }
374 }
375 };
376}
377
378crate::pac::peripheral_pins!(
379 ($inst:ident, rcc, RCC, $pin:ident, MCO_1, $af:expr) => {
380 impl_pin!(MCO1, $pin, $af);
381 };
382 ($inst:ident, rcc, RCC, $pin:ident, MCO_2, $af:expr) => {
383 impl_pin!(MCO2, $pin, $af);
384 };
385);
386
387pub struct Mco<'d, T: McoInstance> {
388 phantom: PhantomData<&'d mut T>,
389}
390
391impl<'d, T: McoInstance> Mco<'d, T> {
392 pub fn new(
393 _peri: impl Unborrow<Target = T> + 'd,
394 pin: impl Unborrow<Target = impl McoPin<T>> + 'd,
395 source: impl McoSource<Raw = T::Source>,
396 prescaler: McoClock,
397 ) -> Self {
398 unborrow!(pin);
399
400 unsafe {
401 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
402 }
403
404 pin.configure();
405
406 Self {
407 phantom: PhantomData,
408 }
409 }
410}
411
412pub(crate) unsafe fn init(mut config: Config) {
413 // TODO make configurable?
414 let enable_overdrive = false;
415
416 // NB. The lower bytes of CR3 can only be written once after
417 // POR, and must be written with a valid combination. Refer to
418 // RM0433 Rev 7 6.8.4. This is partially enforced by dropping
419 // `self` at the end of this method, but of course we cannot
420 // know what happened between the previous POR and here.
421 #[cfg(pwr_h7)]
422 PWR.cr3().modify(|w| {
423 w.set_scuen(true);
424 w.set_ldoen(true);
425 w.set_bypass(false);
426 });
427
428 #[cfg(pwr_h7smps)]
429 PWR.cr3().modify(|w| {
430 // hardcode "Direct SPMS" for now, this is what works on nucleos with the
431 // default solderbridge configuration.
432 w.set_sden(true);
433 w.set_ldoen(false);
434 });
435
436 // Validate the supply configuration. If you are stuck here, it is
437 // because the voltages on your board do not match those specified
438 // in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
439 // VOS = Scale 3, so check that the voltage on the VCAP pins =
440 // 1.0V.
441 while !PWR.csr1().read().actvosrdy() {}
442
443 // Go to Scale 1
444 PWR.d3cr().modify(|w| w.set_vos(0b11));
445 while !PWR.d3cr().read().vosrdy() {}
446
447 let pwr_vos = if !enable_overdrive {
448 VoltageScale::Scale1
449 } else {
450 critical_section::with(|_| {
451 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
452
453 SYSCFG.pwrcr().modify(|w| w.set_oden(1));
454 });
455 while !PWR.d3cr().read().vosrdy() {}
456 VoltageScale::Scale0
457 };
458
459 // Freeze the core clocks, returning a Core Clocks Distribution
460 // and Reset (CCDR) structure. The actual frequency of the clocks
461 // configured is returned in the `clocks` member of the CCDR
462 // structure.
463 //
464 // Note that `freeze` will never result in a clock _faster_ than
465 // that specified. It may result in a clock that is a factor of [1,
466 // 2) slower.
467 //
468 // `syscfg` is required to enable the I/O compensation cell.
469 //
470 // # Panics
471 //
472 // If a clock specification cannot be achieved within the
473 // hardware specification then this function will panic. This
474 // function may also panic if a clock specification can be
475 // achieved, but the mechanism for doing so is not yet
476 // implemented here.
477
478 let srcclk = config.hse.unwrap_or(HSI); // Available clocks
479 let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
480
481 // Configure traceclk from PLL if needed
482 traceclk_setup(&mut config, sys_use_pll1_p);
483
484 // NOTE(unsafe) We have exclusive access to the RCC
485 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
486 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
487 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
488
489 let sys_ck = if sys_use_pll1_p {
490 Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
491 } else {
492 sys_ck
493 };
494
495 // This routine does not support HSIDIV != 1. To
496 // do so it would need to ensure all PLLxON bits are clear
497 // before changing the value of HSIDIV
498 let cr = RCC.cr().read();
499 assert!(cr.hsion());
500 assert!(cr.hsidiv() == Hsidiv::DIV1);
501
502 RCC.csr().modify(|w| w.set_lsion(true));
503 while !RCC.csr().read().lsirdy() {}
504
505 // per_ck from HSI by default
506 let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
507 (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
508 (_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI
509 _ => (HSI, Ckpersel::HSI), // HSI
510 };
511
512 // D1 Core Prescaler
513 // Set to 1
514 let d1cpre_bits = 0;
515 let d1cpre_div = 1;
516 let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
517
518 // Refer to part datasheet "General operating conditions"
519 // table for (rev V). We do not assert checks for earlier
520 // revisions which may have lower limits.
521 let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
522 VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
523 VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
524 VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
525 _ => (200_000_000, 100_000_000, 50_000_000),
526 };
527 assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
528
529 let rcc_hclk = config.rcc_hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
530 assert!(rcc_hclk <= rcc_hclk_max);
531
532 // Estimate divisor
533 let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
534 0 => panic!(),
535 1 => (Hpre::DIV1, 1),
536 2 => (Hpre::DIV2, 2),
537 3..=5 => (Hpre::DIV4, 4),
538 6..=11 => (Hpre::DIV8, 8),
539 12..=39 => (Hpre::DIV16, 16),
540 40..=95 => (Hpre::DIV64, 64),
541 96..=191 => (Hpre::DIV128, 128),
542 192..=383 => (Hpre::DIV256, 256),
543 _ => (Hpre::DIV512, 512),
544 };
545 // Calculate real AXI and AHB clock
546 let rcc_hclk = sys_d1cpre_ck / hpre_div;
547 assert!(rcc_hclk <= rcc_hclk_max);
548 let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
549 // Timer prescaler selection
550 let timpre = Timpre::DEFAULTX2;
551
552 let requested_pclk1 = config
553 .pclk1
554 .map(|v| v.0)
555 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
556 let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
557 ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
558
559 let requested_pclk2 = config
560 .pclk2
561 .map(|v| v.0)
562 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
563 let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
564 ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
565
566 let requested_pclk3 = config
567 .pclk3
568 .map(|v| v.0)
569 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
570 let (rcc_pclk3, ppre3_bits, ppre3, _) =
571 ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
572
573 let requested_pclk4 = config
574 .pclk4
575 .map(|v| v.0)
576 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
577 let (rcc_pclk4, ppre4_bits, ppre4, _) =
578 ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
579
580 flash_setup(rcc_aclk, pwr_vos);
581
582 // Start switching clocks -------------------
583
584 // Ensure CSI is on and stable
585 RCC.cr().modify(|w| w.set_csion(true));
586 while !RCC.cr().read().csirdy() {}
587
588 // Ensure HSI48 is on and stable
589 RCC.cr().modify(|w| w.set_hsi48on(true));
590 while !RCC.cr().read().hsi48on() {}
591
592 // XXX: support MCO ?
593
594 let hse_ck = match config.hse {
595 Some(hse) => {
596 // Ensure HSE is on and stable
597 RCC.cr().modify(|w| {
598 w.set_hseon(true);
599 w.set_hsebyp(if config.bypass_hse {
600 Hsebyp::BYPASSED
601 } else {
602 Hsebyp::NOTBYPASSED
603 });
604 });
605 while !RCC.cr().read().hserdy() {}
606 Some(hse)
607 }
608 None => None,
609 };
610
611 let pllsrc = if config.hse.is_some() {
612 Pllsrc::HSE
613 } else {
614 Pllsrc::HSI
615 };
616 RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
617
618 let enable_pll = |pll| {
619 RCC.cr().modify(|w| w.set_pllon(pll, true));
620 while !RCC.cr().read().pllrdy(pll) {}
621 };
622
623 if pll1_p_ck.is_some() {
624 enable_pll(0);
625 }
626
627 if pll2_p_ck.is_some() {
628 enable_pll(1);
629 }
630
631 if pll3_p_ck.is_some() {
632 enable_pll(2);
633 }
634
635 // Core Prescaler / AHB Prescaler / APB3 Prescaler
636 RCC.d1cfgr().modify(|w| {
637 w.set_d1cpre(Hpre(d1cpre_bits));
638 w.set_d1ppre(Dppre(ppre3_bits));
639 w.set_hpre(hpre_bits)
640 });
641 // Ensure core prescaler value is valid before future lower
642 // core voltage
643 while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
644
645 // APB1 / APB2 Prescaler
646 RCC.d2cfgr().modify(|w| {
647 w.set_d2ppre1(Dppre(ppre1_bits));
648 w.set_d2ppre2(Dppre(ppre2_bits));
649 });
650
651 // APB4 Prescaler
652 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
653
654 // Peripheral Clock (per_ck)
655 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
656
657 // Set timer clocks prescaler setting
658 RCC.cfgr().modify(|w| w.set_timpre(timpre));
659
660 // Select system clock source
661 let sw = match (sys_use_pll1_p, config.hse.is_some()) {
662 (true, _) => Sw::PLL1,
663 (false, true) => Sw::HSE,
664 _ => Sw::HSI,
665 };
666 RCC.cfgr().modify(|w| w.set_sw(sw));
667 while RCC.cfgr().read().sws() != sw.0 {}
668
669 // IO compensation cell - Requires CSI clock and SYSCFG
670 assert!(RCC.cr().read().csirdy());
671 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
672
673 // Enable the compensation cell, using back-bias voltage code
674 // provide by the cell.
675 critical_section::with(|_| {
676 SYSCFG.cccsr().modify(|w| {
677 w.set_en(true);
678 w.set_cs(false);
679 w.set_hslv(false);
680 })
681 });
682 while !SYSCFG.cccsr().read().ready() {}
683
684 let core_clocks = CoreClocks {
685 hclk: Hertz(rcc_hclk),
686 pclk1: Hertz(rcc_pclk1),
687 pclk2: Hertz(rcc_pclk2),
688 pclk3: Hertz(rcc_pclk3),
689 pclk4: Hertz(rcc_pclk4),
690 ppre1,
691 ppre2,
692 ppre3,
693 ppre4,
694 csi_ck: Some(CSI),
695 hsi_ck: Some(HSI),
696 hsi48_ck: Some(HSI48),
697 lsi_ck: Some(LSI),
698 per_ck: Some(per_ck),
699 hse_ck,
700 pll1_p_ck: pll1_p_ck.map(Hertz),
701 pll1_q_ck: pll1_q_ck.map(Hertz),
702 pll1_r_ck: pll1_r_ck.map(Hertz),
703 pll2_p_ck: pll2_p_ck.map(Hertz),
704 pll2_q_ck: pll2_q_ck.map(Hertz),
705 pll2_r_ck: pll2_r_ck.map(Hertz),
706 pll3_p_ck: pll3_p_ck.map(Hertz),
707 pll3_q_ck: pll3_q_ck.map(Hertz),
708 pll3_r_ck: pll3_r_ck.map(Hertz),
709 timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
710 timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
711 sys_ck,
712 c_ck: Hertz(sys_d1cpre_ck),
713 };
714
715 set_freqs(Clocks {
716 sys: core_clocks.c_ck,
717 ahb1: core_clocks.hclk,
718 ahb2: core_clocks.hclk,
719 ahb3: core_clocks.hclk,
720 ahb4: core_clocks.hclk,
721 apb1: core_clocks.pclk1,
722 apb2: core_clocks.pclk2,
723 apb4: core_clocks.pclk4,
724 apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
725 apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
726 });
727}
728
729mod pll {
730 use super::{Hertz, RCC};
731
732 const VCO_MIN: u32 = 150_000_000;
733 const VCO_MAX: u32 = 420_000_000;
734
735 #[derive(Default)]
736 pub struct PllConfig {
737 pub p_ck: Option<Hertz>,
738 pub q_ck: Option<Hertz>,
739 pub r_ck: Option<Hertz>,
740 }
741
742 pub(super) struct PllConfigResults {
743 pub ref_x_ck: u32,
744 pub pll_x_m: u32,
745 pub pll_x_p: u32,
746 pub vco_ck_target: u32,
747 }
748
749 fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
750 let pll_x_p = if plln == 0 {
751 if output > VCO_MAX / 2 {
752 1
753 } else {
754 ((VCO_MAX / output) | 1) - 1 // Must be even or unity
755 }
756 } else {
757 // Specific to PLL2/3, will subtract 1 later
758 if output > VCO_MAX / 2 {
759 1
760 } else {
761 VCO_MAX / output
762 }
763 };
764
765 let vco_ck = output + pll_x_p;
766
767 assert!(pll_x_p < 128);
768 assert!(vco_ck >= VCO_MIN);
769 assert!(vco_ck <= VCO_MAX);
770
771 (vco_ck, pll_x_p)
772 }
773
774 /// # Safety
775 ///
776 /// Must have exclusive access to the RCC register block
777 unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
778 use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
779
780 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
781
782 // Input divisor, resulting in a reference clock in the range
783 // 1 to 2 MHz. Choose the highest reference clock (lowest m)
784 let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
785 assert!(pll_x_m < 64);
786
787 // Calculate resulting reference clock
788 let ref_x_ck = pll_src / pll_x_m;
789 assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
790
791 RCC.pllcfgr().modify(|w| {
792 w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
793 w.set_pllrge(plln, Pllrge::RANGE1);
794 });
795 PllConfigResults {
796 ref_x_ck,
797 pll_x_m,
798 pll_x_p,
799 vco_ck_target,
800 }
801 }
802
803 /// # Safety
804 ///
805 /// Must have exclusive access to the RCC register block
806 pub(super) unsafe fn pll_setup(
807 pll_src: u32,
808 config: &PllConfig,
809 plln: usize,
810 ) -> (Option<u32>, Option<u32>, Option<u32>) {
811 use crate::pac::rcc::vals::Divp;
812
813 match config.p_ck {
814 Some(requested_output) => {
815 let config_results = vco_setup(pll_src, requested_output.0, plln);
816 let PllConfigResults {
817 ref_x_ck,
818 pll_x_m,
819 pll_x_p,
820 vco_ck_target,
821 } = config_results;
822
823 RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
824
825 // Feedback divider. Integer only
826 let pll_x_n = vco_ck_target / ref_x_ck;
827 assert!(pll_x_n >= 4);
828 assert!(pll_x_n <= 512);
829 RCC.plldivr(plln)
830 .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
831
832 // No FRACN
833 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
834 let vco_ck = ref_x_ck * pll_x_n;
835
836 RCC.plldivr(plln)
837 .modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
838 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
839
840 // Calulate additional output dividers
841 let q_ck = match config.q_ck {
842 Some(Hertz(ck)) if ck > 0 => {
843 let div = (vco_ck + ck - 1) / ck;
844 RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
845 RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
846 Some(vco_ck / div)
847 }
848 _ => None,
849 };
850 let r_ck = match config.r_ck {
851 Some(Hertz(ck)) if ck > 0 => {
852 let div = (vco_ck + ck - 1) / ck;
853 RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
854 RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
855 Some(vco_ck / div)
856 }
857 _ => None,
858 };
859
860 (Some(vco_ck / pll_x_p), q_ck, r_ck)
861 }
862 None => {
863 assert!(
864 config.q_ck.is_none(),
865 "Must set PLL P clock for Q clock to take effect!"
866 );
867 assert!(
868 config.r_ck.is_none(),
869 "Must set PLL P clock for R clock to take effect!"
870 );
871 (None, None, None)
872 }
873 }
874 }
875}
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs
deleted file mode 100644
index cd493a80a..000000000
--- a/embassy-stm32/src/rcc/h7/mod.rs
+++ /dev/null
@@ -1,702 +0,0 @@
1use core::marker::PhantomData;
2
3use embassy::util::Unborrow;
4use embassy_hal_common::unborrow;
5use stm32_metapac::rcc::vals::{Mco1, Mco2};
6
7use crate::gpio::sealed::Pin as __GpioPin;
8use crate::gpio::Pin;
9use crate::pac::rcc::vals::Timpre;
10use crate::pac::{RCC, SYSCFG};
11use crate::peripherals;
12use crate::pwr::{Power, VoltageScale};
13use crate::rcc::{set_freqs, Clocks};
14use crate::time::Hertz;
15
16mod pll;
17use pll::pll_setup;
18pub use pll::PllConfig;
19
20const HSI: Hertz = Hertz(64_000_000);
21const CSI: Hertz = Hertz(4_000_000);
22const HSI48: Hertz = Hertz(48_000_000);
23const LSI: Hertz = Hertz(32_000);
24
25/// Core clock frequencies
26#[derive(Clone, Copy)]
27pub struct CoreClocks {
28 pub hclk: Hertz,
29 pub pclk1: Hertz,
30 pub pclk2: Hertz,
31 pub pclk3: Hertz,
32 pub pclk4: Hertz,
33 pub ppre1: u8,
34 pub ppre2: u8,
35 pub ppre3: u8,
36 pub ppre4: u8,
37 pub csi_ck: Option<Hertz>,
38 pub hsi_ck: Option<Hertz>,
39 pub hsi48_ck: Option<Hertz>,
40 pub lsi_ck: Option<Hertz>,
41 pub per_ck: Option<Hertz>,
42 pub hse_ck: Option<Hertz>,
43 pub pll1_p_ck: Option<Hertz>,
44 pub pll1_q_ck: Option<Hertz>,
45 pub pll1_r_ck: Option<Hertz>,
46 pub pll2_p_ck: Option<Hertz>,
47 pub pll2_q_ck: Option<Hertz>,
48 pub pll2_r_ck: Option<Hertz>,
49 pub pll3_p_ck: Option<Hertz>,
50 pub pll3_q_ck: Option<Hertz>,
51 pub pll3_r_ck: Option<Hertz>,
52 pub timx_ker_ck: Option<Hertz>,
53 pub timy_ker_ck: Option<Hertz>,
54 pub sys_ck: Hertz,
55 pub c_ck: Hertz,
56}
57
58/// Configuration of the core clocks
59#[non_exhaustive]
60#[derive(Default)]
61pub struct Config {
62 pub hse: Option<Hertz>,
63 pub bypass_hse: bool,
64 pub sys_ck: Option<Hertz>,
65 pub per_ck: Option<Hertz>,
66 rcc_hclk: Option<Hertz>,
67 pub hclk: Option<Hertz>,
68 pub pclk1: Option<Hertz>,
69 pub pclk2: Option<Hertz>,
70 pub pclk3: Option<Hertz>,
71 pub pclk4: Option<Hertz>,
72 pub pll1: PllConfig,
73 pub pll2: PllConfig,
74 pub pll3: PllConfig,
75}
76
77pub struct Rcc<'d> {
78 inner: PhantomData<&'d ()>,
79 config: Config,
80}
81
82impl<'d> Rcc<'d> {
83 pub fn new(_rcc: impl Unborrow<Target = peripherals::RCC> + 'd, config: Config) -> Self {
84 Self {
85 inner: PhantomData,
86 config,
87 }
88 }
89
90 /// Freeze the core clocks, returning a Core Clocks Distribution
91 /// and Reset (CCDR) structure. The actual frequency of the clocks
92 /// configured is returned in the `clocks` member of the CCDR
93 /// structure.
94 ///
95 /// Note that `freeze` will never result in a clock _faster_ than
96 /// that specified. It may result in a clock that is a factor of [1,
97 /// 2) slower.
98 ///
99 /// `syscfg` is required to enable the I/O compensation cell.
100 ///
101 /// # Panics
102 ///
103 /// If a clock specification cannot be achieved within the
104 /// hardware specification then this function will panic. This
105 /// function may also panic if a clock specification can be
106 /// achieved, but the mechanism for doing so is not yet
107 /// implemented here.
108 pub fn freeze(mut self, pwr: &Power) -> CoreClocks {
109 use crate::pac::rcc::vals::{Ckpersel, Dppre, Hpre, Hsebyp, Hsidiv, Pllsrc, Sw};
110
111 let srcclk = self.config.hse.unwrap_or(HSI); // Available clocks
112 let (sys_ck, sys_use_pll1_p) = self.sys_ck_setup(srcclk);
113
114 // Configure traceclk from PLL if needed
115 self.traceclk_setup(sys_use_pll1_p);
116
117 // NOTE(unsafe) We have exclusive access to the RCC
118 let (pll1_p_ck, pll1_q_ck, pll1_r_ck) =
119 unsafe { pll_setup(srcclk.0, &self.config.pll1, 0) };
120 let (pll2_p_ck, pll2_q_ck, pll2_r_ck) =
121 unsafe { pll_setup(srcclk.0, &self.config.pll2, 1) };
122 let (pll3_p_ck, pll3_q_ck, pll3_r_ck) =
123 unsafe { pll_setup(srcclk.0, &self.config.pll3, 2) };
124
125 let sys_ck = if sys_use_pll1_p {
126 Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
127 } else {
128 sys_ck
129 };
130
131 // NOTE(unsafe) We own the regblock
132 unsafe {
133 // This routine does not support HSIDIV != 1. To
134 // do so it would need to ensure all PLLxON bits are clear
135 // before changing the value of HSIDIV
136 let cr = RCC.cr().read();
137 assert!(cr.hsion());
138 assert!(cr.hsidiv() == Hsidiv::DIV1);
139
140 RCC.csr().modify(|w| w.set_lsion(true));
141 while !RCC.csr().read().lsirdy() {}
142 }
143
144 // per_ck from HSI by default
145 let (per_ck, ckpersel) = match (self.config.per_ck == self.config.hse, self.config.per_ck) {
146 (true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
147 (_, Some(CSI)) => (CSI, Ckpersel::CSI), // CSI
148 _ => (HSI, Ckpersel::HSI), // HSI
149 };
150
151 // D1 Core Prescaler
152 // Set to 1
153 let d1cpre_bits = 0;
154 let d1cpre_div = 1;
155 let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
156
157 // Refer to part datasheet "General operating conditions"
158 // table for (rev V). We do not assert checks for earlier
159 // revisions which may have lower limits.
160 let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr.vos {
161 VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
162 VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
163 VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
164 _ => (200_000_000, 100_000_000, 50_000_000),
165 };
166 assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
167
168 let rcc_hclk = self
169 .config
170 .rcc_hclk
171 .map(|v| v.0)
172 .unwrap_or(sys_d1cpre_ck / 2);
173 assert!(rcc_hclk <= rcc_hclk_max);
174
175 // Estimate divisor
176 let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
177 0 => panic!(),
178 1 => (Hpre::DIV1, 1),
179 2 => (Hpre::DIV2, 2),
180 3..=5 => (Hpre::DIV4, 4),
181 6..=11 => (Hpre::DIV8, 8),
182 12..=39 => (Hpre::DIV16, 16),
183 40..=95 => (Hpre::DIV64, 64),
184 96..=191 => (Hpre::DIV128, 128),
185 192..=383 => (Hpre::DIV256, 256),
186 _ => (Hpre::DIV512, 512),
187 };
188 // Calculate real AXI and AHB clock
189 let rcc_hclk = sys_d1cpre_ck / hpre_div;
190 assert!(rcc_hclk <= rcc_hclk_max);
191 let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
192 // Timer prescaler selection
193 let timpre = Timpre::DEFAULTX2;
194
195 let requested_pclk1 = self
196 .config
197 .pclk1
198 .map(|v| v.0)
199 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
200 let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
201 Self::ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
202
203 let requested_pclk2 = self
204 .config
205 .pclk2
206 .map(|v| v.0)
207 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
208 let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
209 Self::ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
210
211 let requested_pclk3 = self
212 .config
213 .pclk3
214 .map(|v| v.0)
215 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
216 let (rcc_pclk3, ppre3_bits, ppre3, _) =
217 Self::ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
218
219 let requested_pclk4 = self
220 .config
221 .pclk4
222 .map(|v| v.0)
223 .unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
224 let (rcc_pclk4, ppre4_bits, ppre4, _) =
225 Self::ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
226
227 Self::flash_setup(rcc_aclk, pwr.vos);
228
229 // Start switching clocks -------------------
230 // NOTE(unsafe) We have the RCC singleton
231 unsafe {
232 // Ensure CSI is on and stable
233 RCC.cr().modify(|w| w.set_csion(true));
234 while !RCC.cr().read().csirdy() {}
235
236 // Ensure HSI48 is on and stable
237 RCC.cr().modify(|w| w.set_hsi48on(true));
238 while !RCC.cr().read().hsi48on() {}
239
240 // XXX: support MCO ?
241
242 let hse_ck = match self.config.hse {
243 Some(hse) => {
244 // Ensure HSE is on and stable
245 RCC.cr().modify(|w| {
246 w.set_hseon(true);
247 w.set_hsebyp(if self.config.bypass_hse {
248 Hsebyp::BYPASSED
249 } else {
250 Hsebyp::NOTBYPASSED
251 });
252 });
253 while !RCC.cr().read().hserdy() {}
254 Some(hse)
255 }
256 None => None,
257 };
258
259 let pllsrc = if self.config.hse.is_some() {
260 Pllsrc::HSE
261 } else {
262 Pllsrc::HSI
263 };
264 RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
265
266 let enable_pll = |pll| {
267 RCC.cr().modify(|w| w.set_pllon(pll, true));
268 while !RCC.cr().read().pllrdy(pll) {}
269 };
270
271 if pll1_p_ck.is_some() {
272 enable_pll(0);
273 }
274
275 if pll2_p_ck.is_some() {
276 enable_pll(1);
277 }
278
279 if pll3_p_ck.is_some() {
280 enable_pll(2);
281 }
282
283 // Core Prescaler / AHB Prescaler / APB3 Prescaler
284 RCC.d1cfgr().modify(|w| {
285 w.set_d1cpre(Hpre(d1cpre_bits));
286 w.set_d1ppre(Dppre(ppre3_bits));
287 w.set_hpre(hpre_bits)
288 });
289 // Ensure core prescaler value is valid before future lower
290 // core voltage
291 while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
292
293 // APB1 / APB2 Prescaler
294 RCC.d2cfgr().modify(|w| {
295 w.set_d2ppre1(Dppre(ppre1_bits));
296 w.set_d2ppre2(Dppre(ppre2_bits));
297 });
298
299 // APB4 Prescaler
300 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
301
302 // Peripheral Clock (per_ck)
303 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
304
305 // Set timer clocks prescaler setting
306 RCC.cfgr().modify(|w| w.set_timpre(timpre));
307
308 // Select system clock source
309 let sw = match (sys_use_pll1_p, self.config.hse.is_some()) {
310 (true, _) => Sw::PLL1,
311 (false, true) => Sw::HSE,
312 _ => Sw::HSI,
313 };
314 RCC.cfgr().modify(|w| w.set_sw(sw));
315 while RCC.cfgr().read().sws() != sw.0 {}
316
317 // IO compensation cell - Requires CSI clock and SYSCFG
318 assert!(RCC.cr().read().csirdy());
319 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
320
321 // Enable the compensation cell, using back-bias voltage code
322 // provide by the cell.
323 critical_section::with(|_| {
324 SYSCFG.cccsr().modify(|w| {
325 w.set_en(true);
326 w.set_cs(false);
327 w.set_hslv(false);
328 })
329 });
330 while !SYSCFG.cccsr().read().ready() {}
331
332 CoreClocks {
333 hclk: Hertz(rcc_hclk),
334 pclk1: Hertz(rcc_pclk1),
335 pclk2: Hertz(rcc_pclk2),
336 pclk3: Hertz(rcc_pclk3),
337 pclk4: Hertz(rcc_pclk4),
338 ppre1,
339 ppre2,
340 ppre3,
341 ppre4,
342 csi_ck: Some(CSI),
343 hsi_ck: Some(HSI),
344 hsi48_ck: Some(HSI48),
345 lsi_ck: Some(LSI),
346 per_ck: Some(per_ck),
347 hse_ck,
348 pll1_p_ck: pll1_p_ck.map(Hertz),
349 pll1_q_ck: pll1_q_ck.map(Hertz),
350 pll1_r_ck: pll1_r_ck.map(Hertz),
351 pll2_p_ck: pll2_p_ck.map(Hertz),
352 pll2_q_ck: pll2_q_ck.map(Hertz),
353 pll2_r_ck: pll2_r_ck.map(Hertz),
354 pll3_p_ck: pll3_p_ck.map(Hertz),
355 pll3_q_ck: pll3_q_ck.map(Hertz),
356 pll3_r_ck: pll3_r_ck.map(Hertz),
357 timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
358 timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
359 sys_ck,
360 c_ck: Hertz(sys_d1cpre_ck),
361 }
362 }
363 }
364
365 /// Setup traceclk
366 /// Returns a pll1_r_ck
367 fn traceclk_setup(&mut self, sys_use_pll1_p: bool) {
368 let pll1_r_ck = match (sys_use_pll1_p, self.config.pll1.r_ck) {
369 // pll1_p_ck selected as system clock but pll1_r_ck not
370 // set. The traceclk mux is synchronous with the system
371 // clock mux, but has pll1_r_ck as an input. In order to
372 // keep traceclk running, we force a pll1_r_ck.
373 (true, None) => Some(Hertz(unwrap!(self.config.pll1.p_ck).0 / 2)),
374
375 // Either pll1 not selected as system clock, free choice
376 // of pll1_r_ck. Or pll1 is selected, assume user has set
377 // a suitable pll1_r_ck frequency.
378 _ => self.config.pll1.r_ck,
379 };
380 self.config.pll1.r_ck = pll1_r_ck;
381 }
382
383 /// Divider calculator for pclk 1 - 4
384 ///
385 /// Returns real pclk, bits, ppre and the timer kernel clock
386 fn ppre_calculate(
387 requested_pclk: u32,
388 hclk: u32,
389 max_pclk: u32,
390 tim_pre: Option<Timpre>,
391 ) -> (u32, u8, u8, Option<u32>) {
392 let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
393 0 => panic!(),
394 1 => (0b000, 1),
395 2 => (0b100, 2),
396 3..=5 => (0b101, 4),
397 6..=11 => (0b110, 8),
398 _ => (0b111, 16),
399 };
400 let real_pclk = hclk / u32::from(ppre);
401 assert!(real_pclk <= max_pclk);
402
403 let tim_ker_clk = if let Some(tim_pre) = tim_pre {
404 let clk = match (bits, tim_pre) {
405 (0b101, Timpre::DEFAULTX2) => hclk / 2,
406 (0b110, Timpre::DEFAULTX4) => hclk / 2,
407 (0b110, Timpre::DEFAULTX2) => hclk / 4,
408 (0b111, Timpre::DEFAULTX4) => hclk / 4,
409 (0b111, Timpre::DEFAULTX2) => hclk / 8,
410 _ => hclk,
411 };
412 Some(clk)
413 } else {
414 None
415 };
416 (real_pclk, bits, ppre, tim_ker_clk)
417 }
418
419 /// Setup sys_ck
420 /// Returns sys_ck frequency, and a pll1_p_ck
421 fn sys_ck_setup(&mut self, srcclk: Hertz) -> (Hertz, bool) {
422 // Compare available with wanted clocks
423 let sys_ck = self.config.sys_ck.unwrap_or(srcclk);
424
425 if sys_ck != srcclk {
426 // The requested system clock is not the immediately available
427 // HSE/HSI clock. Perhaps there are other ways of obtaining
428 // the requested system clock (such as `HSIDIV`) but we will
429 // ignore those for now.
430 //
431 // Therefore we must use pll1_p_ck
432 let pll1_p_ck = match self.config.pll1.p_ck {
433 Some(p_ck) => {
434 assert!(p_ck == sys_ck,
435 "Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck");
436 Some(p_ck)
437 }
438 None => Some(sys_ck),
439 };
440 self.config.pll1.p_ck = pll1_p_ck;
441
442 (sys_ck, true)
443 } else {
444 // sys_ck is derived directly from a source clock
445 // (HSE/HSI). pll1_p_ck can be as requested
446 (sys_ck, false)
447 }
448 }
449
450 fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
451 use crate::pac::FLASH;
452
453 // ACLK in MHz, round down and subtract 1 from integers. eg.
454 // 61_999_999 -> 61MHz
455 // 62_000_000 -> 61MHz
456 // 62_000_001 -> 62MHz
457 let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
458
459 // See RM0433 Rev 7 Table 17. FLASH recommended number of wait
460 // states and programming delay
461 let (wait_states, progr_delay) = match vos {
462 // VOS 0 range VCORE 1.26V - 1.40V
463 VoltageScale::Scale0 => match rcc_aclk_mhz {
464 0..=69 => (0, 0),
465 70..=139 => (1, 1),
466 140..=184 => (2, 1),
467 185..=209 => (2, 2),
468 210..=224 => (3, 2),
469 225..=239 => (4, 2),
470 _ => (7, 3),
471 },
472 // VOS 1 range VCORE 1.15V - 1.26V
473 VoltageScale::Scale1 => match rcc_aclk_mhz {
474 0..=69 => (0, 0),
475 70..=139 => (1, 1),
476 140..=184 => (2, 1),
477 185..=209 => (2, 2),
478 210..=224 => (3, 2),
479 _ => (7, 3),
480 },
481 // VOS 2 range VCORE 1.05V - 1.15V
482 VoltageScale::Scale2 => match rcc_aclk_mhz {
483 0..=54 => (0, 0),
484 55..=109 => (1, 1),
485 110..=164 => (2, 1),
486 165..=224 => (3, 2),
487 _ => (7, 3),
488 },
489 // VOS 3 range VCORE 0.95V - 1.05V
490 VoltageScale::Scale3 => match rcc_aclk_mhz {
491 0..=44 => (0, 0),
492 45..=89 => (1, 1),
493 90..=134 => (2, 1),
494 135..=179 => (3, 2),
495 180..=224 => (4, 2),
496 _ => (7, 3),
497 },
498 };
499
500 // NOTE(unsafe) Atomic write
501 unsafe {
502 FLASH.acr().write(|w| {
503 w.set_wrhighfreq(progr_delay);
504 w.set_latency(wait_states)
505 });
506 while FLASH.acr().read().latency() != wait_states {}
507 }
508 }
509}
510pub enum McoClock {
511 Disabled,
512 Bypassed,
513 Divided(u8),
514}
515
516impl McoClock {
517 fn into_raw(&self) -> u8 {
518 match self {
519 McoClock::Disabled => 0,
520 McoClock::Bypassed => 1,
521 McoClock::Divided(divisor) => {
522 if *divisor > 15 {
523 panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
524 }
525 *divisor
526 }
527 }
528 }
529}
530
531#[derive(Copy, Clone)]
532pub enum Mco1Source {
533 Hsi,
534 Lse,
535 Hse,
536 Pll1Q,
537 Hsi48,
538}
539
540impl Default for Mco1Source {
541 fn default() -> Self {
542 Self::Hsi
543 }
544}
545
546pub trait McoSource {
547 type Raw;
548
549 fn into_raw(&self) -> Self::Raw;
550}
551
552impl McoSource for Mco1Source {
553 type Raw = Mco1;
554 fn into_raw(&self) -> Self::Raw {
555 match self {
556 Mco1Source::Hsi => Mco1::HSI,
557 Mco1Source::Lse => Mco1::LSE,
558 Mco1Source::Hse => Mco1::HSE,
559 Mco1Source::Pll1Q => Mco1::PLL1_Q,
560 Mco1Source::Hsi48 => Mco1::HSI48,
561 }
562 }
563}
564
565#[derive(Copy, Clone)]
566pub enum Mco2Source {
567 SysClk,
568 Pll2Q,
569 Hse,
570 Pll1Q,
571 Csi,
572 Lsi,
573}
574
575impl Default for Mco2Source {
576 fn default() -> Self {
577 Self::SysClk
578 }
579}
580
581impl McoSource for Mco2Source {
582 type Raw = Mco2;
583 fn into_raw(&self) -> Self::Raw {
584 match self {
585 Mco2Source::SysClk => Mco2::SYSCLK,
586 Mco2Source::Pll2Q => Mco2::PLL2_P,
587 Mco2Source::Hse => Mco2::HSE,
588 Mco2Source::Pll1Q => Mco2::PLL1_P,
589 Mco2Source::Csi => Mco2::CSI,
590 Mco2Source::Lsi => Mco2::LSI,
591 }
592 }
593}
594
595pub(crate) mod sealed {
596 use super::*;
597
598 pub trait McoInstance {
599 type Source;
600 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
601 }
602
603 pub trait McoPin<T: McoInstance>: Pin {
604 fn configure(&mut self);
605 }
606}
607
608pub trait McoInstance: sealed::McoInstance + 'static {}
609
610pub trait McoPin<T: McoInstance>: sealed::McoPin<T> + 'static {}
611
612macro_rules! impl_peri {
613 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
614 impl sealed::McoInstance for peripherals::$peri {
615 type Source = $source;
616
617 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
618 RCC.cfgr().modify(|w| {
619 w.$set_source(source);
620 w.$set_prescaler(prescaler);
621 });
622 }
623 }
624
625 impl McoInstance for peripherals::$peri {}
626 };
627}
628
629impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
630impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
631
632macro_rules! impl_pin {
633 ($peri:ident, $pin:ident, $af:expr) => {
634 impl McoPin<peripherals::$peri> for peripherals::$pin {}
635
636 impl sealed::McoPin<peripherals::$peri> for peripherals::$pin {
637 fn configure(&mut self) {
638 critical_section::with(|_| unsafe {
639 self.set_as_af($af, crate::gpio::sealed::AFType::OutputPushPull);
640 self.block().ospeedr().modify(|w| {
641 w.set_ospeedr(
642 self.pin() as usize,
643 crate::pac::gpio::vals::Ospeedr::VERYHIGHSPEED,
644 )
645 });
646 })
647 }
648 }
649 };
650}
651
652crate::pac::peripheral_pins!(
653 ($inst:ident, rcc, RCC, $pin:ident, MCO_1, $af:expr) => {
654 impl_pin!(MCO1, $pin, $af);
655 };
656 ($inst:ident, rcc, RCC, $pin:ident, MCO_2, $af:expr) => {
657 impl_pin!(MCO2, $pin, $af);
658 };
659);
660
661pub struct Mco<'d, T: McoInstance> {
662 phantom: PhantomData<&'d mut T>,
663}
664
665impl<'d, T: McoInstance> Mco<'d, T> {
666 pub fn new(
667 _peri: impl Unborrow<Target = T> + 'd,
668 pin: impl Unborrow<Target = impl McoPin<T>> + 'd,
669 source: impl McoSource<Raw = T::Source>,
670 prescaler: McoClock,
671 ) -> Self {
672 unborrow!(pin);
673
674 unsafe {
675 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
676 }
677
678 pin.configure();
679
680 Self {
681 phantom: PhantomData,
682 }
683 }
684}
685
686pub unsafe fn init(config: Config) {
687 let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
688 let rcc = Rcc::new(<peripherals::RCC as embassy::util::Steal>::steal(), config);
689 let core_clocks = rcc.freeze(&mut power);
690 set_freqs(Clocks {
691 sys: core_clocks.c_ck,
692 ahb1: core_clocks.hclk,
693 ahb2: core_clocks.hclk,
694 ahb3: core_clocks.hclk,
695 ahb4: core_clocks.hclk,
696 apb1: core_clocks.pclk1,
697 apb2: core_clocks.pclk2,
698 apb4: core_clocks.pclk4,
699 apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
700 apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
701 });
702}
diff --git a/embassy-stm32/src/rcc/h7/pll.rs b/embassy-stm32/src/rcc/h7/pll.rs
deleted file mode 100644
index d3709378b..000000000
--- a/embassy-stm32/src/rcc/h7/pll.rs
+++ /dev/null
@@ -1,145 +0,0 @@
1use super::{Hertz, RCC};
2
3const VCO_MIN: u32 = 150_000_000;
4const VCO_MAX: u32 = 420_000_000;
5
6#[derive(Default)]
7pub struct PllConfig {
8 pub p_ck: Option<Hertz>,
9 pub q_ck: Option<Hertz>,
10 pub r_ck: Option<Hertz>,
11}
12
13pub(super) struct PllConfigResults {
14 pub ref_x_ck: u32,
15 pub pll_x_m: u32,
16 pub pll_x_p: u32,
17 pub vco_ck_target: u32,
18}
19
20fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
21 let pll_x_p = if plln == 0 {
22 if output > VCO_MAX / 2 {
23 1
24 } else {
25 ((VCO_MAX / output) | 1) - 1 // Must be even or unity
26 }
27 } else {
28 // Specific to PLL2/3, will subtract 1 later
29 if output > VCO_MAX / 2 {
30 1
31 } else {
32 VCO_MAX / output
33 }
34 };
35
36 let vco_ck = output + pll_x_p;
37
38 assert!(pll_x_p < 128);
39 assert!(vco_ck >= VCO_MIN);
40 assert!(vco_ck <= VCO_MAX);
41
42 (vco_ck, pll_x_p)
43}
44
45/// # Safety
46///
47/// Must have exclusive access to the RCC register block
48unsafe fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
49 use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
50
51 let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
52
53 // Input divisor, resulting in a reference clock in the range
54 // 1 to 2 MHz. Choose the highest reference clock (lowest m)
55 let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
56 assert!(pll_x_m < 64);
57
58 // Calculate resulting reference clock
59 let ref_x_ck = pll_src / pll_x_m;
60 assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
61
62 RCC.pllcfgr().modify(|w| {
63 w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
64 w.set_pllrge(plln, Pllrge::RANGE1);
65 });
66 PllConfigResults {
67 ref_x_ck,
68 pll_x_m,
69 pll_x_p,
70 vco_ck_target,
71 }
72}
73
74/// # Safety
75///
76/// Must have exclusive access to the RCC register block
77pub(super) unsafe fn pll_setup(
78 pll_src: u32,
79 config: &PllConfig,
80 plln: usize,
81) -> (Option<u32>, Option<u32>, Option<u32>) {
82 use crate::pac::rcc::vals::Divp;
83
84 match config.p_ck {
85 Some(requested_output) => {
86 let config_results = vco_setup(pll_src, requested_output.0, plln);
87 let PllConfigResults {
88 ref_x_ck,
89 pll_x_m,
90 pll_x_p,
91 vco_ck_target,
92 } = config_results;
93
94 RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
95
96 // Feedback divider. Integer only
97 let pll_x_n = vco_ck_target / ref_x_ck;
98 assert!(pll_x_n >= 4);
99 assert!(pll_x_n <= 512);
100 RCC.plldivr(plln)
101 .modify(|w| w.set_divn1((pll_x_n - 1) as u16));
102
103 // No FRACN
104 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
105 let vco_ck = ref_x_ck * pll_x_n;
106
107 RCC.plldivr(plln)
108 .modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
109 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
110
111 // Calulate additional output dividers
112 let q_ck = match config.q_ck {
113 Some(Hertz(ck)) if ck > 0 => {
114 let div = (vco_ck + ck - 1) / ck;
115 RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
116 RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
117 Some(vco_ck / div)
118 }
119 _ => None,
120 };
121 let r_ck = match config.r_ck {
122 Some(Hertz(ck)) if ck > 0 => {
123 let div = (vco_ck + ck - 1) / ck;
124 RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
125 RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
126 Some(vco_ck / div)
127 }
128 _ => None,
129 };
130
131 (Some(vco_ck / pll_x_p), q_ck, r_ck)
132 }
133 None => {
134 assert!(
135 config.q_ck.is_none(),
136 "Must set PLL P clock for Q clock to take effect!"
137 );
138 assert!(
139 config.r_ck.is_none(),
140 "Must set PLL P clock for R clock to take effect!"
141 );
142 (None, None, None)
143 }
144 }
145}
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
new file mode 100644
index 000000000..25daeedf0
--- /dev/null
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -0,0 +1,362 @@
1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
2use crate::pac::{CRS, RCC, SYSCFG};
3use crate::rcc::{set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6
7/// HSI16 speed
8pub const HSI16_FREQ: u32 = 16_000_000;
9
10/// System clock mux source
11#[derive(Clone, Copy)]
12pub enum ClockSrc {
13 MSI(MSIRange),
14 PLL(PLLSource, PLLMul, PLLDiv),
15 HSE(Hertz),
16 HSI16,
17}
18
19/// MSI Clock Range
20///
21/// These ranges control the frequency of the MSI. Internally, these ranges map
22/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
23#[derive(Clone, Copy)]
24pub enum MSIRange {
25 /// Around 65.536 kHz
26 Range0,
27 /// Around 131.072 kHz
28 Range1,
29 /// Around 262.144 kHz
30 Range2,
31 /// Around 524.288 kHz
32 Range3,
33 /// Around 1.048 MHz
34 Range4,
35 /// Around 2.097 MHz (reset value)
36 Range5,
37 /// Around 4.194 MHz
38 Range6,
39}
40
41impl Default for MSIRange {
42 fn default() -> MSIRange {
43 MSIRange::Range5
44 }
45}
46
47/// PLL divider
48#[derive(Clone, Copy)]
49pub enum PLLDiv {
50 Div2,
51 Div3,
52 Div4,
53}
54
55/// PLL multiplier
56#[derive(Clone, Copy)]
57pub enum PLLMul {
58 Mul3,
59 Mul4,
60 Mul6,
61 Mul8,
62 Mul12,
63 Mul16,
64 Mul24,
65 Mul32,
66 Mul48,
67}
68
69/// AHB prescaler
70#[derive(Clone, Copy, PartialEq)]
71pub enum AHBPrescaler {
72 NotDivided,
73 Div2,
74 Div4,
75 Div8,
76 Div16,
77 Div64,
78 Div128,
79 Div256,
80 Div512,
81}
82
83/// APB prescaler
84#[derive(Clone, Copy)]
85pub enum APBPrescaler {
86 NotDivided,
87 Div2,
88 Div4,
89 Div8,
90 Div16,
91}
92
93/// PLL clock input source
94#[derive(Clone, Copy)]
95pub enum PLLSource {
96 HSI16,
97 HSE(Hertz),
98}
99
100impl From<PLLMul> for Pllmul {
101 fn from(val: PLLMul) -> Pllmul {
102 match val {
103 PLLMul::Mul3 => Pllmul::MUL3,
104 PLLMul::Mul4 => Pllmul::MUL4,
105 PLLMul::Mul6 => Pllmul::MUL6,
106 PLLMul::Mul8 => Pllmul::MUL8,
107 PLLMul::Mul12 => Pllmul::MUL12,
108 PLLMul::Mul16 => Pllmul::MUL16,
109 PLLMul::Mul24 => Pllmul::MUL24,
110 PLLMul::Mul32 => Pllmul::MUL32,
111 PLLMul::Mul48 => Pllmul::MUL48,
112 }
113 }
114}
115
116impl From<PLLDiv> for Plldiv {
117 fn from(val: PLLDiv) -> Plldiv {
118 match val {
119 PLLDiv::Div2 => Plldiv::DIV2,
120 PLLDiv::Div3 => Plldiv::DIV3,
121 PLLDiv::Div4 => Plldiv::DIV4,
122 }
123 }
124}
125
126impl From<PLLSource> for Pllsrc {
127 fn from(val: PLLSource) -> Pllsrc {
128 match val {
129 PLLSource::HSI16 => Pllsrc::HSI16,
130 PLLSource::HSE(_) => Pllsrc::HSE,
131 }
132 }
133}
134
135impl From<APBPrescaler> for Ppre {
136 fn from(val: APBPrescaler) -> Ppre {
137 match val {
138 APBPrescaler::NotDivided => Ppre::DIV1,
139 APBPrescaler::Div2 => Ppre::DIV2,
140 APBPrescaler::Div4 => Ppre::DIV4,
141 APBPrescaler::Div8 => Ppre::DIV8,
142 APBPrescaler::Div16 => Ppre::DIV16,
143 }
144 }
145}
146
147impl From<AHBPrescaler> for Hpre {
148 fn from(val: AHBPrescaler) -> Hpre {
149 match val {
150 AHBPrescaler::NotDivided => Hpre::DIV1,
151 AHBPrescaler::Div2 => Hpre::DIV2,
152 AHBPrescaler::Div4 => Hpre::DIV4,
153 AHBPrescaler::Div8 => Hpre::DIV8,
154 AHBPrescaler::Div16 => Hpre::DIV16,
155 AHBPrescaler::Div64 => Hpre::DIV64,
156 AHBPrescaler::Div128 => Hpre::DIV128,
157 AHBPrescaler::Div256 => Hpre::DIV256,
158 AHBPrescaler::Div512 => Hpre::DIV512,
159 }
160 }
161}
162
163impl From<MSIRange> for Msirange {
164 fn from(val: MSIRange) -> Msirange {
165 match val {
166 MSIRange::Range0 => Msirange::RANGE0,
167 MSIRange::Range1 => Msirange::RANGE1,
168 MSIRange::Range2 => Msirange::RANGE2,
169 MSIRange::Range3 => Msirange::RANGE3,
170 MSIRange::Range4 => Msirange::RANGE4,
171 MSIRange::Range5 => Msirange::RANGE5,
172 MSIRange::Range6 => Msirange::RANGE6,
173 }
174 }
175}
176
177/// Clocks configutation
178pub struct Config {
179 pub mux: ClockSrc,
180 pub ahb_pre: AHBPrescaler,
181 pub apb1_pre: APBPrescaler,
182 pub apb2_pre: APBPrescaler,
183 pub enable_hsi48: bool,
184}
185
186impl Default for Config {
187 #[inline]
188 fn default() -> Config {
189 Config {
190 mux: ClockSrc::MSI(MSIRange::default()),
191 ahb_pre: AHBPrescaler::NotDivided,
192 apb1_pre: APBPrescaler::NotDivided,
193 apb2_pre: APBPrescaler::NotDivided,
194 enable_hsi48: false,
195 }
196 }
197}
198
199pub(crate) unsafe fn init(config: Config) {
200 let (sys_clk, sw) = match config.mux {
201 ClockSrc::MSI(range) => {
202 // Set MSI range
203 RCC.icscr().write(|w| w.set_msirange(range.into()));
204
205 // Enable MSI
206 RCC.cr().write(|w| w.set_msion(true));
207 while !RCC.cr().read().msirdy() {}
208
209 let freq = 32_768 * (1 << (range as u8 + 1));
210 (freq, Sw::MSI)
211 }
212 ClockSrc::HSI16 => {
213 // Enable HSI16
214 RCC.cr().write(|w| w.set_hsi16on(true));
215 while !RCC.cr().read().hsi16rdyf() {}
216
217 (HSI16_FREQ, Sw::HSI16)
218 }
219 ClockSrc::HSE(freq) => {
220 // Enable HSE
221 RCC.cr().write(|w| w.set_hseon(true));
222 while !RCC.cr().read().hserdy() {}
223
224 (freq.0, Sw::HSE)
225 }
226 ClockSrc::PLL(src, mul, div) => {
227 let freq = match src {
228 PLLSource::HSE(freq) => {
229 // Enable HSE
230 RCC.cr().write(|w| w.set_hseon(true));
231 while !RCC.cr().read().hserdy() {}
232 freq.0
233 }
234 PLLSource::HSI16 => {
235 // Enable HSI
236 RCC.cr().write(|w| w.set_hsi16on(true));
237 while !RCC.cr().read().hsi16rdyf() {}
238 HSI16_FREQ
239 }
240 };
241
242 // Disable PLL
243 RCC.cr().modify(|w| w.set_pllon(false));
244 while RCC.cr().read().pllrdy() {}
245
246 let freq = match mul {
247 PLLMul::Mul3 => freq * 3,
248 PLLMul::Mul4 => freq * 4,
249 PLLMul::Mul6 => freq * 6,
250 PLLMul::Mul8 => freq * 8,
251 PLLMul::Mul12 => freq * 12,
252 PLLMul::Mul16 => freq * 16,
253 PLLMul::Mul24 => freq * 24,
254 PLLMul::Mul32 => freq * 32,
255 PLLMul::Mul48 => freq * 48,
256 };
257
258 let freq = match div {
259 PLLDiv::Div2 => freq / 2,
260 PLLDiv::Div3 => freq / 3,
261 PLLDiv::Div4 => freq / 4,
262 };
263 assert!(freq <= 32_u32.mhz().0);
264
265 RCC.cfgr().write(move |w| {
266 w.set_pllmul(mul.into());
267 w.set_plldiv(div.into());
268 w.set_pllsrc(src.into());
269 });
270
271 // Enable PLL
272 RCC.cr().modify(|w| w.set_pllon(true));
273 while !RCC.cr().read().pllrdy() {}
274
275 (freq, Sw::PLL)
276 }
277 };
278
279 RCC.cfgr().modify(|w| {
280 w.set_sw(sw);
281 w.set_hpre(config.ahb_pre.into());
282 w.set_ppre1(config.apb1_pre.into());
283 w.set_ppre2(config.apb2_pre.into());
284 });
285
286 let ahb_freq: u32 = match config.ahb_pre {
287 AHBPrescaler::NotDivided => sys_clk,
288 pre => {
289 let pre: Hpre = pre.into();
290 let pre = 1 << (pre.0 as u32 - 7);
291 sys_clk / pre
292 }
293 };
294
295 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
296 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
297 pre => {
298 let pre: Ppre = pre.into();
299 let pre: u8 = 1 << (pre.0 - 3);
300 let freq = ahb_freq / pre as u32;
301 (freq, freq * 2)
302 }
303 };
304
305 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
306 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
307 pre => {
308 let pre: Ppre = pre.into();
309 let pre: u8 = 1 << (pre.0 - 3);
310 let freq = ahb_freq / (1 << (pre as u8 - 3));
311 (freq, freq * 2)
312 }
313 };
314
315 if config.enable_hsi48 {
316 // Reset SYSCFG peripheral
317 RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
318 RCC.apb2rstr().modify(|w| w.set_syscfgrst(false));
319
320 // Enable SYSCFG peripheral
321 RCC.apb2enr().modify(|w| w.set_syscfgen(true));
322
323 // Reset CRS peripheral
324 RCC.apb1rstr().modify(|w| w.set_crsrst(true));
325 RCC.apb1rstr().modify(|w| w.set_crsrst(false));
326
327 // Enable CRS peripheral
328 RCC.apb1enr().modify(|w| w.set_crsen(true));
329
330 // Initialize CRS
331 CRS.cfgr().write(|w|
332
333 // Select LSE as synchronization source
334 w.set_syncsrc(0b01));
335 CRS.cr().modify(|w| {
336 w.set_autotrimen(true);
337 w.set_cen(true);
338 });
339
340 // Enable VREFINT reference for HSI48 oscillator
341 SYSCFG.cfgr3().modify(|w| {
342 w.set_enref_hsi48(true);
343 w.set_en_vrefint(true);
344 });
345
346 // Select HSI48 as USB clock
347 RCC.ccipr().modify(|w| w.set_hsi48msel(true));
348
349 // Enable dedicated USB clock
350 RCC.crrcr().modify(|w| w.set_hsi48on(true));
351 while !RCC.crrcr().read().hsi48rdy() {}
352 }
353
354 set_freqs(Clocks {
355 sys: sys_clk.hz(),
356 ahb: ahb_freq.hz(),
357 apb1: apb1_freq.hz(),
358 apb2: apb2_freq.hz(),
359 apb1_tim: apb1_tim_freq.hz(),
360 apb2_tim: apb2_tim_freq.hz(),
361 });
362}
diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs
deleted file mode 100644
index fd84f09c5..000000000
--- a/embassy-stm32/src/rcc/l0/mod.rs
+++ /dev/null
@@ -1,437 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, CRS, RCC, SYSCFG};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9use pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
10
11/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
12/// and with the addition of the init function to configure a system clock.
13
14/// HSI speed
15pub const HSI_FREQ: u32 = 16_000_000;
16
17/// System clock mux source
18#[derive(Clone, Copy)]
19pub enum ClockSrc {
20 MSI(MSIRange),
21 PLL(PLLSource, PLLMul, PLLDiv),
22 HSE(Hertz),
23 HSI16,
24}
25
26/// MSI Clock Range
27///
28/// These ranges control the frequency of the MSI. Internally, these ranges map
29/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
30#[derive(Clone, Copy)]
31pub enum MSIRange {
32 /// Around 65.536 kHz
33 Range0,
34 /// Around 131.072 kHz
35 Range1,
36 /// Around 262.144 kHz
37 Range2,
38 /// Around 524.288 kHz
39 Range3,
40 /// Around 1.048 MHz
41 Range4,
42 /// Around 2.097 MHz (reset value)
43 Range5,
44 /// Around 4.194 MHz
45 Range6,
46}
47
48impl Default for MSIRange {
49 fn default() -> MSIRange {
50 MSIRange::Range5
51 }
52}
53
54/// PLL divider
55#[derive(Clone, Copy)]
56pub enum PLLDiv {
57 Div2,
58 Div3,
59 Div4,
60}
61
62/// PLL multiplier
63#[derive(Clone, Copy)]
64pub enum PLLMul {
65 Mul3,
66 Mul4,
67 Mul6,
68 Mul8,
69 Mul12,
70 Mul16,
71 Mul24,
72 Mul32,
73 Mul48,
74}
75
76/// AHB prescaler
77#[derive(Clone, Copy, PartialEq)]
78pub enum AHBPrescaler {
79 NotDivided,
80 Div2,
81 Div4,
82 Div8,
83 Div16,
84 Div64,
85 Div128,
86 Div256,
87 Div512,
88}
89
90/// APB prescaler
91#[derive(Clone, Copy)]
92pub enum APBPrescaler {
93 NotDivided,
94 Div2,
95 Div4,
96 Div8,
97 Div16,
98}
99
100/// PLL clock input source
101#[derive(Clone, Copy)]
102pub enum PLLSource {
103 HSI16,
104 HSE(Hertz),
105}
106
107impl Into<Pllmul> for PLLMul {
108 fn into(self) -> Pllmul {
109 match self {
110 PLLMul::Mul3 => Pllmul::MUL3,
111 PLLMul::Mul4 => Pllmul::MUL4,
112 PLLMul::Mul6 => Pllmul::MUL6,
113 PLLMul::Mul8 => Pllmul::MUL8,
114 PLLMul::Mul12 => Pllmul::MUL12,
115 PLLMul::Mul16 => Pllmul::MUL16,
116 PLLMul::Mul24 => Pllmul::MUL24,
117 PLLMul::Mul32 => Pllmul::MUL32,
118 PLLMul::Mul48 => Pllmul::MUL48,
119 }
120 }
121}
122
123impl Into<Plldiv> for PLLDiv {
124 fn into(self) -> Plldiv {
125 match self {
126 PLLDiv::Div2 => Plldiv::DIV2,
127 PLLDiv::Div3 => Plldiv::DIV3,
128 PLLDiv::Div4 => Plldiv::DIV4,
129 }
130 }
131}
132
133impl Into<Pllsrc> for PLLSource {
134 fn into(self) -> Pllsrc {
135 match self {
136 PLLSource::HSI16 => Pllsrc::HSI16,
137 PLLSource::HSE(_) => Pllsrc::HSE,
138 }
139 }
140}
141
142impl Into<Ppre> for APBPrescaler {
143 fn into(self) -> Ppre {
144 match self {
145 APBPrescaler::NotDivided => Ppre::DIV1,
146 APBPrescaler::Div2 => Ppre::DIV2,
147 APBPrescaler::Div4 => Ppre::DIV4,
148 APBPrescaler::Div8 => Ppre::DIV8,
149 APBPrescaler::Div16 => Ppre::DIV16,
150 }
151 }
152}
153
154impl Into<Hpre> for AHBPrescaler {
155 fn into(self) -> Hpre {
156 match self {
157 AHBPrescaler::NotDivided => Hpre::DIV1,
158 AHBPrescaler::Div2 => Hpre::DIV2,
159 AHBPrescaler::Div4 => Hpre::DIV4,
160 AHBPrescaler::Div8 => Hpre::DIV8,
161 AHBPrescaler::Div16 => Hpre::DIV16,
162 AHBPrescaler::Div64 => Hpre::DIV64,
163 AHBPrescaler::Div128 => Hpre::DIV128,
164 AHBPrescaler::Div256 => Hpre::DIV256,
165 AHBPrescaler::Div512 => Hpre::DIV512,
166 }
167 }
168}
169
170impl Into<Msirange> for MSIRange {
171 fn into(self) -> Msirange {
172 match self {
173 MSIRange::Range0 => Msirange::RANGE0,
174 MSIRange::Range1 => Msirange::RANGE1,
175 MSIRange::Range2 => Msirange::RANGE2,
176 MSIRange::Range3 => Msirange::RANGE3,
177 MSIRange::Range4 => Msirange::RANGE4,
178 MSIRange::Range5 => Msirange::RANGE5,
179 MSIRange::Range6 => Msirange::RANGE6,
180 }
181 }
182}
183
184/// Clocks configutation
185pub struct Config {
186 pub mux: ClockSrc,
187 pub ahb_pre: AHBPrescaler,
188 pub apb1_pre: APBPrescaler,
189 pub apb2_pre: APBPrescaler,
190}
191
192impl Default for Config {
193 #[inline]
194 fn default() -> Config {
195 Config {
196 mux: ClockSrc::MSI(MSIRange::default()),
197 ahb_pre: AHBPrescaler::NotDivided,
198 apb1_pre: APBPrescaler::NotDivided,
199 apb2_pre: APBPrescaler::NotDivided,
200 }
201 }
202}
203
204/// RCC peripheral
205pub struct Rcc<'d> {
206 _rb: peripherals::RCC,
207 phantom: PhantomData<&'d mut peripherals::RCC>,
208}
209
210impl<'d> Rcc<'d> {
211 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
212 unborrow!(rcc);
213 Self {
214 _rb: rcc,
215 phantom: PhantomData,
216 }
217 }
218
219 // Safety: RCC init must have been called
220 pub fn clocks(&self) -> &'static Clocks {
221 unsafe { get_freqs() }
222 }
223
224 pub fn enable_hsi48(&mut self, _syscfg: &mut SYSCFG, _crs: CRS) -> HSI48 {
225 let rcc = pac::RCC;
226 unsafe {
227 // Reset SYSCFG peripheral
228 rcc.apb2rstr().modify(|w| w.set_syscfgrst(true));
229 rcc.apb2rstr().modify(|w| w.set_syscfgrst(false));
230
231 // Enable SYSCFG peripheral
232 rcc.apb2enr().modify(|w| w.set_syscfgen(true));
233
234 // Reset CRS peripheral
235 rcc.apb1rstr().modify(|w| w.set_crsrst(true));
236 rcc.apb1rstr().modify(|w| w.set_crsrst(false));
237
238 // Enable CRS peripheral
239 rcc.apb1enr().modify(|w| w.set_crsen(true));
240
241 // Initialize CRS
242 let crs = pac::CRS;
243 crs.cfgr().write(|w|
244
245 // Select LSE as synchronization source
246 w.set_syncsrc(0b01));
247 crs.cr().modify(|w| {
248 w.set_autotrimen(true);
249 w.set_cen(true);
250 });
251
252 // Enable VREFINT reference for HSI48 oscillator
253 let syscfg = pac::SYSCFG;
254 syscfg.cfgr3().modify(|w| {
255 w.set_enref_hsi48(true);
256 w.set_en_vrefint(true);
257 });
258
259 // Select HSI48 as USB clock
260 rcc.ccipr().modify(|w| w.set_hsi48msel(true));
261
262 // Enable dedicated USB clock
263 rcc.crrcr().modify(|w| w.set_hsi48on(true));
264 while !rcc.crrcr().read().hsi48rdy() {}
265 }
266
267 HSI48(())
268 }
269}
270
271/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
272pub trait RccExt {
273 fn freeze(self, config: Config) -> Clocks;
274}
275
276impl RccExt for RCC {
277 // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by
278 // marking this function and all `Config` constructors and setters as `#[inline]`.
279 // This saves ~900 Bytes for the `pwr.rs` example.
280 #[inline]
281 fn freeze(self, cfgr: Config) -> Clocks {
282 let rcc = pac::RCC;
283 let (sys_clk, sw) = match cfgr.mux {
284 ClockSrc::MSI(range) => {
285 // Set MSI range
286 unsafe {
287 rcc.icscr().write(|w| w.set_msirange(range.into()));
288 }
289
290 // Enable MSI
291 unsafe {
292 rcc.cr().write(|w| w.set_msion(true));
293 while !rcc.cr().read().msirdy() {}
294 }
295
296 let freq = 32_768 * (1 << (range as u8 + 1));
297 (freq, Sw::MSI)
298 }
299 ClockSrc::HSI16 => {
300 // Enable HSI16
301 unsafe {
302 rcc.cr().write(|w| w.set_hsi16on(true));
303 while !rcc.cr().read().hsi16rdyf() {}
304 }
305
306 (HSI_FREQ, Sw::HSI16)
307 }
308 ClockSrc::HSE(freq) => {
309 // Enable HSE
310 unsafe {
311 rcc.cr().write(|w| w.set_hseon(true));
312 while !rcc.cr().read().hserdy() {}
313 }
314
315 (freq.0, Sw::HSE)
316 }
317 ClockSrc::PLL(src, mul, div) => {
318 let freq = match src {
319 PLLSource::HSE(freq) => {
320 // Enable HSE
321 unsafe {
322 rcc.cr().write(|w| w.set_hseon(true));
323 while !rcc.cr().read().hserdy() {}
324 }
325 freq.0
326 }
327 PLLSource::HSI16 => {
328 // Enable HSI
329 unsafe {
330 rcc.cr().write(|w| w.set_hsi16on(true));
331 while !rcc.cr().read().hsi16rdyf() {}
332 }
333 HSI_FREQ
334 }
335 };
336
337 // Disable PLL
338 unsafe {
339 rcc.cr().modify(|w| w.set_pllon(false));
340 while rcc.cr().read().pllrdy() {}
341 }
342
343 let freq = match mul {
344 PLLMul::Mul3 => freq * 3,
345 PLLMul::Mul4 => freq * 4,
346 PLLMul::Mul6 => freq * 6,
347 PLLMul::Mul8 => freq * 8,
348 PLLMul::Mul12 => freq * 12,
349 PLLMul::Mul16 => freq * 16,
350 PLLMul::Mul24 => freq * 24,
351 PLLMul::Mul32 => freq * 32,
352 PLLMul::Mul48 => freq * 48,
353 };
354
355 let freq = match div {
356 PLLDiv::Div2 => freq / 2,
357 PLLDiv::Div3 => freq / 3,
358 PLLDiv::Div4 => freq / 4,
359 };
360 assert!(freq <= 32_u32.mhz().0);
361
362 unsafe {
363 rcc.cfgr().write(move |w| {
364 w.set_pllmul(mul.into());
365 w.set_plldiv(div.into());
366 w.set_pllsrc(src.into());
367 });
368
369 // Enable PLL
370 rcc.cr().modify(|w| w.set_pllon(true));
371 while !rcc.cr().read().pllrdy() {}
372 }
373
374 (freq, Sw::PLL)
375 }
376 };
377
378 unsafe {
379 rcc.cfgr().modify(|w| {
380 w.set_sw(sw.into());
381 w.set_hpre(cfgr.ahb_pre.into());
382 w.set_ppre1(cfgr.apb1_pre.into());
383 w.set_ppre2(cfgr.apb2_pre.into());
384 });
385 }
386
387 let ahb_freq: u32 = match cfgr.ahb_pre {
388 AHBPrescaler::NotDivided => sys_clk,
389 pre => {
390 let pre: Hpre = pre.into();
391 let pre = 1 << (pre.0 as u32 - 7);
392 sys_clk / pre
393 }
394 };
395
396 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
397 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
398 pre => {
399 let pre: Ppre = pre.into();
400 let pre: u8 = 1 << (pre.0 - 3);
401 let freq = ahb_freq / pre as u32;
402 (freq, freq * 2)
403 }
404 };
405
406 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
407 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
408 pre => {
409 let pre: Ppre = pre.into();
410 let pre: u8 = 1 << (pre.0 - 3);
411 let freq = ahb_freq / (1 << (pre as u8 - 3));
412 (freq, freq * 2)
413 }
414 };
415
416 Clocks {
417 sys: sys_clk.hz(),
418 ahb: ahb_freq.hz(),
419 apb1: apb1_freq.hz(),
420 apb2: apb2_freq.hz(),
421 apb1_tim: apb1_tim_freq.hz(),
422 apb2_tim: apb2_tim_freq.hz(),
423 }
424 }
425}
426
427/// Token that exists only, if the HSI48 clock has been enabled
428///
429/// You can get an instance of this struct by calling [`Rcc::enable_hsi48`].
430#[derive(Clone, Copy)]
431pub struct HSI48(());
432
433pub unsafe fn init(config: Config) {
434 let r = <peripherals::RCC as embassy::util::Steal>::steal();
435 let clocks = r.freeze(config);
436 set_freqs(clocks);
437}
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs
new file mode 100644
index 000000000..517869ca4
--- /dev/null
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -0,0 +1,321 @@
1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
2use crate::pac::RCC;
3use crate::rcc::{set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6
7/// HSI speed
8pub const HSI_FREQ: u32 = 16_000_000;
9
10/// System clock mux source
11#[derive(Clone, Copy)]
12pub enum ClockSrc {
13 MSI(MSIRange),
14 PLL(PLLSource, PLLMul, PLLDiv),
15 HSE(Hertz),
16 HSI,
17}
18
19/// MSI Clock Range
20///
21/// These ranges control the frequency of the MSI. Internally, these ranges map
22/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
23#[derive(Clone, Copy)]
24pub enum MSIRange {
25 /// Around 65.536 kHz
26 Range0,
27 /// Around 131.072 kHz
28 Range1,
29 /// Around 262.144 kHz
30 Range2,
31 /// Around 524.288 kHz
32 Range3,
33 /// Around 1.048 MHz
34 Range4,
35 /// Around 2.097 MHz (reset value)
36 Range5,
37 /// Around 4.194 MHz
38 Range6,
39}
40
41impl Default for MSIRange {
42 fn default() -> MSIRange {
43 MSIRange::Range5
44 }
45}
46
47/// PLL divider
48#[derive(Clone, Copy)]
49pub enum PLLDiv {
50 Div2,
51 Div3,
52 Div4,
53}
54
55/// PLL multiplier
56#[derive(Clone, Copy)]
57pub enum PLLMul {
58 Mul3,
59 Mul4,
60 Mul6,
61 Mul8,
62 Mul12,
63 Mul16,
64 Mul24,
65 Mul32,
66 Mul48,
67}
68
69/// AHB prescaler
70#[derive(Clone, Copy, PartialEq)]
71pub enum AHBPrescaler {
72 NotDivided,
73 Div2,
74 Div4,
75 Div8,
76 Div16,
77 Div64,
78 Div128,
79 Div256,
80 Div512,
81}
82
83/// APB prescaler
84#[derive(Clone, Copy)]
85pub enum APBPrescaler {
86 NotDivided,
87 Div2,
88 Div4,
89 Div8,
90 Div16,
91}
92
93/// PLL clock input source
94#[derive(Clone, Copy)]
95pub enum PLLSource {
96 HSI,
97 HSE(Hertz),
98}
99
100impl From<PLLMul> for Pllmul {
101 fn from(val: PLLMul) -> Pllmul {
102 match val {
103 PLLMul::Mul3 => Pllmul::MUL3,
104 PLLMul::Mul4 => Pllmul::MUL4,
105 PLLMul::Mul6 => Pllmul::MUL6,
106 PLLMul::Mul8 => Pllmul::MUL8,
107 PLLMul::Mul12 => Pllmul::MUL12,
108 PLLMul::Mul16 => Pllmul::MUL16,
109 PLLMul::Mul24 => Pllmul::MUL24,
110 PLLMul::Mul32 => Pllmul::MUL32,
111 PLLMul::Mul48 => Pllmul::MUL48,
112 }
113 }
114}
115
116impl From<PLLDiv> for Plldiv {
117 fn from(val: PLLDiv) -> Plldiv {
118 match val {
119 PLLDiv::Div2 => Plldiv::DIV2,
120 PLLDiv::Div3 => Plldiv::DIV3,
121 PLLDiv::Div4 => Plldiv::DIV4,
122 }
123 }
124}
125
126impl From<PLLSource> for Pllsrc {
127 fn from(val: PLLSource) -> Pllsrc {
128 match val {
129 PLLSource::HSI => Pllsrc::HSI,
130 PLLSource::HSE(_) => Pllsrc::HSE,
131 }
132 }
133}
134
135impl From<APBPrescaler> for Ppre {
136 fn from(val: APBPrescaler) -> Ppre {
137 match val {
138 APBPrescaler::NotDivided => Ppre::DIV1,
139 APBPrescaler::Div2 => Ppre::DIV2,
140 APBPrescaler::Div4 => Ppre::DIV4,
141 APBPrescaler::Div8 => Ppre::DIV8,
142 APBPrescaler::Div16 => Ppre::DIV16,
143 }
144 }
145}
146
147impl From<AHBPrescaler> for Hpre {
148 fn from(val: AHBPrescaler) -> Hpre {
149 match val {
150 AHBPrescaler::NotDivided => Hpre::DIV1,
151 AHBPrescaler::Div2 => Hpre::DIV2,
152 AHBPrescaler::Div4 => Hpre::DIV4,
153 AHBPrescaler::Div8 => Hpre::DIV8,
154 AHBPrescaler::Div16 => Hpre::DIV16,
155 AHBPrescaler::Div64 => Hpre::DIV64,
156 AHBPrescaler::Div128 => Hpre::DIV128,
157 AHBPrescaler::Div256 => Hpre::DIV256,
158 AHBPrescaler::Div512 => Hpre::DIV512,
159 }
160 }
161}
162
163impl From<MSIRange> for Msirange {
164 fn from(val: MSIRange) -> Msirange {
165 match val {
166 MSIRange::Range0 => Msirange::RANGE0,
167 MSIRange::Range1 => Msirange::RANGE1,
168 MSIRange::Range2 => Msirange::RANGE2,
169 MSIRange::Range3 => Msirange::RANGE3,
170 MSIRange::Range4 => Msirange::RANGE4,
171 MSIRange::Range5 => Msirange::RANGE5,
172 MSIRange::Range6 => Msirange::RANGE6,
173 }
174 }
175}
176
177/// Clocks configutation
178pub struct Config {
179 pub mux: ClockSrc,
180 pub ahb_pre: AHBPrescaler,
181 pub apb1_pre: APBPrescaler,
182 pub apb2_pre: APBPrescaler,
183}
184
185impl Default for Config {
186 #[inline]
187 fn default() -> Config {
188 Config {
189 mux: ClockSrc::MSI(MSIRange::default()),
190 ahb_pre: AHBPrescaler::NotDivided,
191 apb1_pre: APBPrescaler::NotDivided,
192 apb2_pre: APBPrescaler::NotDivided,
193 }
194 }
195}
196
197pub(crate) unsafe fn init(config: Config) {
198 let (sys_clk, sw) = match config.mux {
199 ClockSrc::MSI(range) => {
200 // Set MSI range
201 RCC.icscr().write(|w| w.set_msirange(range.into()));
202
203 // Enable MSI
204 RCC.cr().write(|w| w.set_msion(true));
205 while !RCC.cr().read().msirdy() {}
206
207 let freq = 32_768 * (1 << (range as u8 + 1));
208 (freq, Sw::MSI)
209 }
210 ClockSrc::HSI => {
211 // Enable HSI
212 RCC.cr().write(|w| w.set_hsion(true));
213 while !RCC.cr().read().hsirdy() {}
214
215 (HSI_FREQ, Sw::HSI)
216 }
217 ClockSrc::HSE(freq) => {
218 // Enable HSE
219 RCC.cr().write(|w| w.set_hseon(true));
220 while !RCC.cr().read().hserdy() {}
221
222 (freq.0, Sw::HSE)
223 }
224 ClockSrc::PLL(src, mul, div) => {
225 let freq = match src {
226 PLLSource::HSE(freq) => {
227 // Enable HSE
228 RCC.cr().write(|w| w.set_hseon(true));
229 while !RCC.cr().read().hserdy() {}
230 freq.0
231 }
232 PLLSource::HSI => {
233 // Enable HSI
234 RCC.cr().write(|w| w.set_hsion(true));
235 while !RCC.cr().read().hsirdy() {}
236 HSI_FREQ
237 }
238 };
239
240 // Disable PLL
241 RCC.cr().modify(|w| w.set_pllon(false));
242 while RCC.cr().read().pllrdy() {}
243
244 let freq = match mul {
245 PLLMul::Mul3 => freq * 3,
246 PLLMul::Mul4 => freq * 4,
247 PLLMul::Mul6 => freq * 6,
248 PLLMul::Mul8 => freq * 8,
249 PLLMul::Mul12 => freq * 12,
250 PLLMul::Mul16 => freq * 16,
251 PLLMul::Mul24 => freq * 24,
252 PLLMul::Mul32 => freq * 32,
253 PLLMul::Mul48 => freq * 48,
254 };
255
256 let freq = match div {
257 PLLDiv::Div2 => freq / 2,
258 PLLDiv::Div3 => freq / 3,
259 PLLDiv::Div4 => freq / 4,
260 };
261 assert!(freq <= 32_u32.mhz().0);
262
263 RCC.cfgr().write(move |w| {
264 w.set_pllmul(mul.into());
265 w.set_plldiv(div.into());
266 w.set_pllsrc(src.into());
267 });
268
269 // Enable PLL
270 RCC.cr().modify(|w| w.set_pllon(true));
271 while !RCC.cr().read().pllrdy() {}
272
273 (freq, Sw::PLL)
274 }
275 };
276
277 RCC.cfgr().modify(|w| {
278 w.set_sw(sw);
279 w.set_hpre(config.ahb_pre.into());
280 w.set_ppre1(config.apb1_pre.into());
281 w.set_ppre2(config.apb2_pre.into());
282 });
283
284 let ahb_freq: u32 = match config.ahb_pre {
285 AHBPrescaler::NotDivided => sys_clk,
286 pre => {
287 let pre: Hpre = pre.into();
288 let pre = 1 << (pre.0 as u32 - 7);
289 sys_clk / pre
290 }
291 };
292
293 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
294 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
295 pre => {
296 let pre: Ppre = pre.into();
297 let pre: u8 = 1 << (pre.0 - 3);
298 let freq = ahb_freq / pre as u32;
299 (freq, freq * 2)
300 }
301 };
302
303 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
304 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
305 pre => {
306 let pre: Ppre = pre.into();
307 let pre: u8 = 1 << (pre.0 - 3);
308 let freq = ahb_freq / (1 << (pre as u8 - 3));
309 (freq, freq * 2)
310 }
311 };
312
313 set_freqs(Clocks {
314 sys: sys_clk.hz(),
315 ahb: ahb_freq.hz(),
316 apb1: apb1_freq.hz(),
317 apb2: apb2_freq.hz(),
318 apb1_tim: apb1_tim_freq.hz(),
319 apb2_tim: apb2_tim_freq.hz(),
320 });
321}
diff --git a/embassy-stm32/src/rcc/l1/mod.rs b/embassy-stm32/src/rcc/l1/mod.rs
deleted file mode 100644
index e46bee323..000000000
--- a/embassy-stm32/src/rcc/l1/mod.rs
+++ /dev/null
@@ -1,261 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9
10/// Most of clock setup is copied from rcc/l0
11
12/// HSI speed
13pub const HSI_FREQ: u32 = 16_000_000;
14
15/// System clock mux source
16#[derive(Clone, Copy)]
17pub enum ClockSrc {
18 MSI(MSIRange),
19 HSE(Hertz),
20 HSI,
21}
22
23/// MSI Clock Range
24///
25/// These ranges control the frequency of the MSI. Internally, these ranges map
26/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
27#[derive(Clone, Copy)]
28pub enum MSIRange {
29 /// Around 65.536 kHz
30 Range0,
31 /// Around 131.072 kHz
32 Range1,
33 /// Around 262.144 kHz
34 Range2,
35 /// Around 524.288 kHz
36 Range3,
37 /// Around 1.048 MHz
38 Range4,
39 /// Around 2.097 MHz (reset value)
40 Range5,
41 /// Around 4.194 MHz
42 Range6,
43}
44
45impl Default for MSIRange {
46 fn default() -> MSIRange {
47 MSIRange::Range5
48 }
49}
50
51/// AHB prescaler
52#[derive(Clone, Copy, PartialEq)]
53pub enum AHBPrescaler {
54 NotDivided,
55 Div2,
56 Div4,
57 Div8,
58 Div16,
59 Div64,
60 Div128,
61 Div256,
62 Div512,
63}
64
65/// APB prescaler
66#[derive(Clone, Copy)]
67pub enum APBPrescaler {
68 NotDivided,
69 Div2,
70 Div4,
71 Div8,
72 Div16,
73}
74
75type Ppre = u8;
76impl Into<Ppre> for APBPrescaler {
77 fn into(self) -> Ppre {
78 match self {
79 APBPrescaler::NotDivided => 0b000,
80 APBPrescaler::Div2 => 0b100,
81 APBPrescaler::Div4 => 0b101,
82 APBPrescaler::Div8 => 0b110,
83 APBPrescaler::Div16 => 0b111,
84 }
85 }
86}
87
88type Hpre = u8;
89impl Into<Hpre> for AHBPrescaler {
90 fn into(self) -> Hpre {
91 match self {
92 AHBPrescaler::NotDivided => 0b0000,
93 AHBPrescaler::Div2 => 0b1000,
94 AHBPrescaler::Div4 => 0b1001,
95 AHBPrescaler::Div8 => 0b1010,
96 AHBPrescaler::Div16 => 0b1011,
97 AHBPrescaler::Div64 => 0b1100,
98 AHBPrescaler::Div128 => 0b1101,
99 AHBPrescaler::Div256 => 0b1110,
100 AHBPrescaler::Div512 => 0b1111,
101 }
102 }
103}
104
105impl Into<u8> for MSIRange {
106 fn into(self) -> u8 {
107 match self {
108 MSIRange::Range0 => 0b000,
109 MSIRange::Range1 => 0b001,
110 MSIRange::Range2 => 0b010,
111 MSIRange::Range3 => 0b011,
112 MSIRange::Range4 => 0b100,
113 MSIRange::Range5 => 0b101,
114 MSIRange::Range6 => 0b110,
115 }
116 }
117}
118
119/// Clocks configutation
120pub struct Config {
121 pub mux: ClockSrc,
122 pub ahb_pre: AHBPrescaler,
123 pub apb1_pre: APBPrescaler,
124 pub apb2_pre: APBPrescaler,
125}
126
127impl Default for Config {
128 #[inline]
129 fn default() -> Config {
130 Config {
131 mux: ClockSrc::MSI(MSIRange::default()),
132 ahb_pre: AHBPrescaler::NotDivided,
133 apb1_pre: APBPrescaler::NotDivided,
134 apb2_pre: APBPrescaler::NotDivided,
135 }
136 }
137}
138
139/// RCC peripheral
140pub struct Rcc<'d> {
141 _rb: peripherals::RCC,
142 phantom: PhantomData<&'d mut peripherals::RCC>,
143}
144
145impl<'d> Rcc<'d> {
146 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
147 unborrow!(rcc);
148 Self {
149 _rb: rcc,
150 phantom: PhantomData,
151 }
152 }
153
154 // Safety: RCC init must have been called
155 pub fn clocks(&self) -> &'static Clocks {
156 unsafe { get_freqs() }
157 }
158}
159
160/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
161pub trait RccExt {
162 fn freeze(self, config: Config) -> Clocks;
163}
164
165impl RccExt for RCC {
166 // `cfgr` is almost always a constant, so make sure it can be constant-propagated properly by
167 // marking this function and all `Config` constructors and setters as `#[inline]`.
168 // This saves ~900 Bytes for the `pwr.rs` example.
169 #[inline]
170 fn freeze(self, cfgr: Config) -> Clocks {
171 let rcc = pac::RCC;
172 let (sys_clk, sw) = match cfgr.mux {
173 ClockSrc::MSI(range) => {
174 // Set MSI range
175 unsafe {
176 rcc.icscr().write(|w| w.set_msirange(range.into()));
177 }
178
179 // Enable MSI
180 unsafe {
181 rcc.cr().write(|w| w.set_msion(true));
182 while !rcc.cr().read().msirdy() {}
183 }
184
185 let freq = 32_768 * (1 << (range as u8 + 1));
186 (freq, 0b00)
187 }
188 ClockSrc::HSI => {
189 // Enable HSI
190 unsafe {
191 rcc.cr().write(|w| w.set_hsion(true));
192 while !rcc.cr().read().hsirdy() {}
193 }
194
195 (HSI_FREQ, 0b01)
196 }
197 ClockSrc::HSE(freq) => {
198 // Enable HSE
199 unsafe {
200 rcc.cr().write(|w| w.set_hseon(true));
201 while !rcc.cr().read().hserdy() {}
202 }
203
204 (freq.0, 0b10)
205 }
206 };
207
208 unsafe {
209 rcc.cfgr().modify(|w| {
210 w.set_sw(sw.into());
211 w.set_hpre(cfgr.ahb_pre.into());
212 w.set_ppre1(cfgr.apb1_pre.into());
213 w.set_ppre2(cfgr.apb2_pre.into());
214 });
215 }
216
217 let ahb_freq: u32 = match cfgr.ahb_pre {
218 AHBPrescaler::NotDivided => sys_clk,
219 pre => {
220 let pre: Hpre = pre.into();
221 let pre = 1 << (pre as u32 - 7);
222 sys_clk / pre
223 }
224 };
225
226 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
227 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
228 pre => {
229 let pre: Ppre = pre.into();
230 let pre: u8 = 1 << (pre - 3);
231 let freq = ahb_freq / pre as u32;
232 (freq, freq * 2)
233 }
234 };
235
236 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
237 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
238 pre => {
239 let pre: Ppre = pre.into();
240 let pre: u8 = 1 << (pre - 3);
241 let freq = ahb_freq / (1 << (pre as u8 - 3));
242 (freq, freq * 2)
243 }
244 };
245
246 Clocks {
247 sys: sys_clk.hz(),
248 ahb: ahb_freq.hz(),
249 apb1: apb1_freq.hz(),
250 apb2: apb2_freq.hz(),
251 apb1_tim: apb1_tim_freq.hz(),
252 apb2_tim: apb2_tim_freq.hz(),
253 }
254 }
255}
256
257pub unsafe fn init(config: Config) {
258 let r = <peripherals::RCC as embassy::util::Steal>::steal();
259 let clocks = r.freeze(config);
260 set_freqs(clocks);
261}
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
new file mode 100644
index 000000000..68b960d7c
--- /dev/null
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -0,0 +1,429 @@
1use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
2use crate::pac::{FLASH, RCC};
3use crate::rcc::{set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6
7/// HSI16 speed
8pub const HSI16_FREQ: u32 = 16_000_000;
9
10/// System clock mux source
11#[derive(Clone, Copy)]
12pub enum ClockSrc {
13 MSI(MSIRange),
14 PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
15 HSE(Hertz),
16 HSI16,
17}
18
19/// MSI Clock Range
20///
21/// These ranges control the frequency of the MSI. Internally, these ranges map
22/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
23#[derive(Clone, Copy)]
24pub enum MSIRange {
25 /// Around 100 kHz
26 Range0,
27 /// Around 200 kHz
28 Range1,
29 /// Around 400 kHz
30 Range2,
31 /// Around 800 kHz
32 Range3,
33 /// Around 1 MHz
34 Range4,
35 /// Around 2 MHz
36 Range5,
37 /// Around 4 MHz (reset value)
38 Range6,
39 /// Around 8 MHz
40 Range7,
41 /// Around 16 MHz
42 Range8,
43 /// Around 24 MHz
44 Range9,
45 /// Around 32 MHz
46 Range10,
47 /// Around 48 MHz
48 Range11,
49}
50
51impl Default for MSIRange {
52 fn default() -> MSIRange {
53 MSIRange::Range6
54 }
55}
56
57pub type PLL48Div = PLLClkDiv;
58
59/// PLL divider
60#[derive(Clone, Copy)]
61pub enum PLLDiv {
62 Div2,
63 Div3,
64 Div4,
65}
66
67/// AHB prescaler
68#[derive(Clone, Copy, PartialEq)]
69pub enum AHBPrescaler {
70 NotDivided,
71 Div2,
72 Div4,
73 Div8,
74 Div16,
75 Div64,
76 Div128,
77 Div256,
78 Div512,
79}
80
81/// APB prescaler
82#[derive(Clone, Copy)]
83pub enum APBPrescaler {
84 NotDivided,
85 Div2,
86 Div4,
87 Div8,
88 Div16,
89}
90
91/// PLL clock input source
92#[derive(Clone, Copy)]
93pub enum PLLSource {
94 HSI16,
95 HSE(Hertz),
96}
97
98seq_macro::seq!(N in 8..=86 {
99 #[derive(Clone, Copy)]
100 pub enum PLLMul {
101 #(
102 Mul#N,
103 )*
104 }
105
106 impl From<PLLMul> for u8 {
107 fn from(val: PLLMul) -> u8 {
108 match val {
109 #(
110 PLLMul::Mul#N => N,
111 )*
112 }
113 }
114 }
115
116 impl PLLMul {
117 pub fn to_mul(self) -> u32 {
118 match self {
119 #(
120 PLLMul::Mul#N => N,
121 )*
122 }
123 }
124 }
125});
126
127#[derive(Clone, Copy)]
128pub enum PLLClkDiv {
129 Div2,
130 Div4,
131 Div6,
132 Div8,
133}
134
135impl PLLClkDiv {
136 pub fn to_div(self) -> u32 {
137 let val: u8 = self.into();
138 (val as u32 + 1) * 2
139 }
140}
141
142impl From<PLLClkDiv> for u8 {
143 fn from(val: PLLClkDiv) -> u8 {
144 match val {
145 PLLClkDiv::Div2 => 0b00,
146 PLLClkDiv::Div4 => 0b01,
147 PLLClkDiv::Div6 => 0b10,
148 PLLClkDiv::Div8 => 0b11,
149 }
150 }
151}
152
153#[derive(Clone, Copy)]
154pub enum PLLSrcDiv {
155 Div1,
156 Div2,
157 Div3,
158 Div4,
159 Div5,
160 Div6,
161 Div7,
162 Div8,
163}
164
165impl PLLSrcDiv {
166 pub fn to_div(self) -> u32 {
167 let val: u8 = self.into();
168 val as u32 + 1
169 }
170}
171
172impl From<PLLSrcDiv> for u8 {
173 fn from(val: PLLSrcDiv) -> u8 {
174 match val {
175 PLLSrcDiv::Div1 => 0b000,
176 PLLSrcDiv::Div2 => 0b001,
177 PLLSrcDiv::Div3 => 0b010,
178 PLLSrcDiv::Div4 => 0b011,
179 PLLSrcDiv::Div5 => 0b100,
180 PLLSrcDiv::Div6 => 0b101,
181 PLLSrcDiv::Div7 => 0b110,
182 PLLSrcDiv::Div8 => 0b111,
183 }
184 }
185}
186
187impl From<PLLSource> for Pllsrc {
188 fn from(val: PLLSource) -> Pllsrc {
189 match val {
190 PLLSource::HSI16 => Pllsrc::HSI16,
191 PLLSource::HSE(_) => Pllsrc::HSE,
192 }
193 }
194}
195
196impl From<APBPrescaler> for Ppre {
197 fn from(val: APBPrescaler) -> Ppre {
198 match val {
199 APBPrescaler::NotDivided => Ppre::DIV1,
200 APBPrescaler::Div2 => Ppre::DIV2,
201 APBPrescaler::Div4 => Ppre::DIV4,
202 APBPrescaler::Div8 => Ppre::DIV8,
203 APBPrescaler::Div16 => Ppre::DIV16,
204 }
205 }
206}
207
208impl From<AHBPrescaler> for Hpre {
209 fn from(val: AHBPrescaler) -> Hpre {
210 match val {
211 AHBPrescaler::NotDivided => Hpre::DIV1,
212 AHBPrescaler::Div2 => Hpre::DIV2,
213 AHBPrescaler::Div4 => Hpre::DIV4,
214 AHBPrescaler::Div8 => Hpre::DIV8,
215 AHBPrescaler::Div16 => Hpre::DIV16,
216 AHBPrescaler::Div64 => Hpre::DIV64,
217 AHBPrescaler::Div128 => Hpre::DIV128,
218 AHBPrescaler::Div256 => Hpre::DIV256,
219 AHBPrescaler::Div512 => Hpre::DIV512,
220 }
221 }
222}
223
224impl From<MSIRange> for Msirange {
225 fn from(val: MSIRange) -> Msirange {
226 match val {
227 MSIRange::Range0 => Msirange::RANGE100K,
228 MSIRange::Range1 => Msirange::RANGE200K,
229 MSIRange::Range2 => Msirange::RANGE400K,
230 MSIRange::Range3 => Msirange::RANGE800K,
231 MSIRange::Range4 => Msirange::RANGE1M,
232 MSIRange::Range5 => Msirange::RANGE2M,
233 MSIRange::Range6 => Msirange::RANGE4M,
234 MSIRange::Range7 => Msirange::RANGE8M,
235 MSIRange::Range8 => Msirange::RANGE16M,
236 MSIRange::Range9 => Msirange::RANGE24M,
237 MSIRange::Range10 => Msirange::RANGE32M,
238 MSIRange::Range11 => Msirange::RANGE48M,
239 }
240 }
241}
242
243impl From<MSIRange> for u32 {
244 fn from(val: MSIRange) -> u32 {
245 match val {
246 MSIRange::Range0 => 100_000,
247 MSIRange::Range1 => 200_000,
248 MSIRange::Range2 => 400_000,
249 MSIRange::Range3 => 800_000,
250 MSIRange::Range4 => 1_000_000,
251 MSIRange::Range5 => 2_000_000,
252 MSIRange::Range6 => 4_000_000,
253 MSIRange::Range7 => 8_000_000,
254 MSIRange::Range8 => 16_000_000,
255 MSIRange::Range9 => 24_000_000,
256 MSIRange::Range10 => 32_000_000,
257 MSIRange::Range11 => 48_000_000,
258 }
259 }
260}
261
262/// Clocks configutation
263pub struct Config {
264 pub mux: ClockSrc,
265 pub ahb_pre: AHBPrescaler,
266 pub apb1_pre: APBPrescaler,
267 pub apb2_pre: APBPrescaler,
268}
269
270impl Default for Config {
271 #[inline]
272 fn default() -> Config {
273 Config {
274 mux: ClockSrc::MSI(MSIRange::Range6),
275 ahb_pre: AHBPrescaler::NotDivided,
276 apb1_pre: APBPrescaler::NotDivided,
277 apb2_pre: APBPrescaler::NotDivided,
278 }
279 }
280}
281
282pub(crate) unsafe fn init(config: Config) {
283 let (sys_clk, sw) = match config.mux {
284 ClockSrc::MSI(range) => {
285 // Enable MSI
286 RCC.cr().write(|w| {
287 let bits: Msirange = range.into();
288 w.set_msirange(bits);
289 w.set_msipllen(false);
290 w.set_msirgsel(true);
291 w.set_msion(true);
292 });
293 while !RCC.cr().read().msirdy() {}
294
295 // Enable as clock source for USB, RNG if running at 48 MHz
296 if let MSIRange::Range11 = range {
297 RCC.ccipr().modify(|w| {
298 w.set_clk48sel(0b11);
299 });
300 }
301 (range.into(), Sw::MSI)
302 }
303 ClockSrc::HSI16 => {
304 // Enable HSI16
305 RCC.cr().write(|w| w.set_hsion(true));
306 while !RCC.cr().read().hsirdy() {}
307
308 (HSI16_FREQ, Sw::HSI16)
309 }
310 ClockSrc::HSE(freq) => {
311 // Enable HSE
312 RCC.cr().write(|w| w.set_hseon(true));
313 while !RCC.cr().read().hserdy() {}
314
315 (freq.0, Sw::HSE)
316 }
317 ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
318 let freq = match src {
319 PLLSource::HSE(freq) => {
320 // Enable HSE
321 RCC.cr().write(|w| w.set_hseon(true));
322 while !RCC.cr().read().hserdy() {}
323 freq.0
324 }
325 PLLSource::HSI16 => {
326 // Enable HSI
327 RCC.cr().write(|w| w.set_hsion(true));
328 while !RCC.cr().read().hsirdy() {}
329 HSI16_FREQ
330 }
331 };
332
333 // Disable PLL
334 RCC.cr().modify(|w| w.set_pllon(false));
335 while RCC.cr().read().pllrdy() {}
336
337 let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div();
338
339 assert!(freq <= 80_000_000);
340
341 RCC.pllcfgr().write(move |w| {
342 w.set_plln(mul.into());
343 w.set_pllm(prediv.into());
344 w.set_pllr(div.into());
345 if let Some(pll48div) = pll48div {
346 w.set_pllq(pll48div.into());
347 w.set_pllqen(true);
348 }
349 w.set_pllsrc(src.into());
350 });
351
352 // Enable as clock source for USB, RNG if PLL48 divisor is provided
353 if pll48div.is_some() {
354 RCC.ccipr().modify(|w| {
355 w.set_clk48sel(0b10);
356 });
357 }
358
359 // Enable PLL
360 RCC.cr().modify(|w| w.set_pllon(true));
361 while !RCC.cr().read().pllrdy() {}
362 RCC.pllcfgr().modify(|w| w.set_pllren(true));
363
364 (freq, Sw::PLL)
365 }
366 };
367
368 // Set flash wait states
369 FLASH.acr().modify(|w| {
370 w.set_latency(if sys_clk <= 16_000_000 {
371 0b000
372 } else if sys_clk <= 32_000_000 {
373 0b001
374 } else if sys_clk <= 48_000_000 {
375 0b010
376 } else if sys_clk <= 64_000_000 {
377 0b011
378 } else {
379 0b100
380 });
381 });
382
383 RCC.cfgr().modify(|w| {
384 w.set_sw(sw);
385 w.set_hpre(config.ahb_pre.into());
386 w.set_ppre1(config.apb1_pre.into());
387 w.set_ppre2(config.apb2_pre.into());
388 });
389
390 let ahb_freq: u32 = match config.ahb_pre {
391 AHBPrescaler::NotDivided => sys_clk,
392 pre => {
393 let pre: Hpre = pre.into();
394 let pre = 1 << (pre.0 as u32 - 7);
395 sys_clk / pre
396 }
397 };
398
399 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
400 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
401 pre => {
402 let pre: Ppre = pre.into();
403 let pre: u8 = 1 << (pre.0 - 3);
404 let freq = ahb_freq / pre as u32;
405 (freq, freq * 2)
406 }
407 };
408
409 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
410 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
411 pre => {
412 let pre: Ppre = pre.into();
413 let pre: u8 = 1 << (pre.0 - 3);
414 let freq = ahb_freq / (1 << (pre as u8 - 3));
415 (freq, freq * 2)
416 }
417 };
418
419 set_freqs(Clocks {
420 sys: sys_clk.hz(),
421 ahb1: ahb_freq.hz(),
422 ahb2: ahb_freq.hz(),
423 ahb3: ahb_freq.hz(),
424 apb1: apb1_freq.hz(),
425 apb2: apb2_freq.hz(),
426 apb1_tim: apb1_tim_freq.hz(),
427 apb2_tim: apb2_tim_freq.hz(),
428 });
429}
diff --git a/embassy-stm32/src/rcc/l4/mod.rs b/embassy-stm32/src/rcc/l4/mod.rs
deleted file mode 100644
index a0eedf0b6..000000000
--- a/embassy-stm32/src/rcc/l4/mod.rs
+++ /dev/null
@@ -1,489 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9use stm32_metapac::rcc::vals::Msirange;
10
11/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
12/// and with the addition of the init function to configure a system clock.
13
14/// Only the basic setup using the HSE and HSI clocks are supported as of now.
15
16/// HSI16 speed
17pub const HSI16_FREQ: u32 = 16_000_000;
18
19/// System clock mux source
20#[derive(Clone, Copy)]
21pub enum ClockSrc {
22 PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
23 MSI(MSIRange),
24 HSE(Hertz),
25 HSI16,
26}
27
28/// MSI Clock Range
29///
30/// These ranges control the frequency of the MSI. Internally, these ranges map
31/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
32#[derive(Clone, Copy)]
33pub enum MSIRange {
34 /// Around 100 kHz
35 Range0,
36 /// Around 200 kHz
37 Range1,
38 /// Around 400 kHz
39 Range2,
40 /// Around 800 kHz
41 Range3,
42 /// Around 1 MHz
43 Range4,
44 /// Around 2 MHz
45 Range5,
46 /// Around 4 MHz (reset value)
47 Range6,
48 /// Around 8 MHz
49 Range7,
50 /// Around 16 MHz
51 Range8,
52 /// Around 24 MHz
53 Range9,
54 /// Around 32 MHz
55 Range10,
56 /// Around 48 MHz
57 Range11,
58}
59
60impl Into<u32> for MSIRange {
61 fn into(self) -> u32 {
62 match self {
63 MSIRange::Range0 => 100_000,
64 MSIRange::Range1 => 200_000,
65 MSIRange::Range2 => 400_000,
66 MSIRange::Range3 => 800_000,
67 MSIRange::Range4 => 1_000_000,
68 MSIRange::Range5 => 2_000_000,
69 MSIRange::Range6 => 4_000_000,
70 MSIRange::Range7 => 8_000_000,
71 MSIRange::Range8 => 16_000_000,
72 MSIRange::Range9 => 24_000_000,
73 MSIRange::Range10 => 32_000_000,
74 MSIRange::Range11 => 48_000_000,
75 }
76 }
77}
78
79impl Default for MSIRange {
80 fn default() -> MSIRange {
81 MSIRange::Range6
82 }
83}
84
85pub type PLL48Div = PLLClkDiv;
86
87/// PLL divider
88#[derive(Clone, Copy)]
89pub enum PLLDiv {
90 Div2,
91 Div3,
92 Div4,
93}
94
95/// AHB prescaler
96#[derive(Clone, Copy, PartialEq)]
97pub enum AHBPrescaler {
98 NotDivided,
99 Div2,
100 Div4,
101 Div8,
102 Div16,
103 Div64,
104 Div128,
105 Div256,
106 Div512,
107}
108
109/// APB prescaler
110#[derive(Clone, Copy)]
111pub enum APBPrescaler {
112 NotDivided,
113 Div2,
114 Div4,
115 Div8,
116 Div16,
117}
118
119/// PLL clock input source
120#[derive(Clone, Copy)]
121pub enum PLLSource {
122 HSI16,
123 HSE(Hertz),
124}
125
126seq_macro::seq!(N in 8..=86 {
127 #[derive(Clone, Copy)]
128 pub enum PLLMul {
129 #(
130 Mul#N,
131 )*
132 }
133
134 impl Into<u8> for PLLMul {
135 fn into(self) -> u8 {
136 match self {
137 #(
138 PLLMul::Mul#N => N,
139 )*
140 }
141 }
142 }
143
144 impl PLLMul {
145 pub fn to_mul(self) -> u32 {
146 match self {
147 #(
148 PLLMul::Mul#N => N,
149 )*
150 }
151 }
152 }
153});
154
155#[derive(Clone, Copy)]
156pub enum PLLClkDiv {
157 Div2,
158 Div4,
159 Div6,
160 Div8,
161}
162
163impl PLLClkDiv {
164 pub fn to_div(self) -> u32 {
165 let val: u8 = self.into();
166 val as u32 + 1 * 2
167 }
168}
169
170impl Into<u8> for PLLClkDiv {
171 fn into(self) -> u8 {
172 match self {
173 PLLClkDiv::Div2 => 0b00,
174 PLLClkDiv::Div4 => 0b01,
175 PLLClkDiv::Div6 => 0b10,
176 PLLClkDiv::Div8 => 0b11,
177 }
178 }
179}
180
181#[derive(Clone, Copy)]
182pub enum PLLSrcDiv {
183 Div1,
184 Div2,
185 Div3,
186 Div4,
187 Div5,
188 Div6,
189 Div7,
190 Div8,
191}
192
193impl PLLSrcDiv {
194 pub fn to_div(self) -> u32 {
195 let val: u8 = self.into();
196 val as u32 + 1
197 }
198}
199
200impl Into<u8> for PLLSrcDiv {
201 fn into(self) -> u8 {
202 match self {
203 PLLSrcDiv::Div1 => 0b000,
204 PLLSrcDiv::Div2 => 0b001,
205 PLLSrcDiv::Div3 => 0b010,
206 PLLSrcDiv::Div4 => 0b011,
207 PLLSrcDiv::Div5 => 0b100,
208 PLLSrcDiv::Div6 => 0b101,
209 PLLSrcDiv::Div7 => 0b110,
210 PLLSrcDiv::Div8 => 0b111,
211 }
212 }
213}
214
215impl Into<u8> for PLLSource {
216 fn into(self) -> u8 {
217 match self {
218 PLLSource::HSI16 => 0b10,
219 PLLSource::HSE(_) => 0b11,
220 }
221 }
222}
223
224impl Into<Msirange> for MSIRange {
225 fn into(self) -> Msirange {
226 match self {
227 MSIRange::Range0 => Msirange::RANGE100K,
228 MSIRange::Range1 => Msirange::RANGE200K,
229 MSIRange::Range2 => Msirange::RANGE400K,
230 MSIRange::Range3 => Msirange::RANGE800K,
231 MSIRange::Range4 => Msirange::RANGE1M,
232 MSIRange::Range5 => Msirange::RANGE2M,
233 MSIRange::Range6 => Msirange::RANGE4M,
234 MSIRange::Range7 => Msirange::RANGE8M,
235 MSIRange::Range8 => Msirange::RANGE16M,
236 MSIRange::Range9 => Msirange::RANGE24M,
237 MSIRange::Range10 => Msirange::RANGE32M,
238 MSIRange::Range11 => Msirange::RANGE48M,
239 }
240 }
241}
242impl Into<u8> for APBPrescaler {
243 fn into(self) -> u8 {
244 match self {
245 APBPrescaler::NotDivided => 1,
246 APBPrescaler::Div2 => 0x04,
247 APBPrescaler::Div4 => 0x05,
248 APBPrescaler::Div8 => 0x06,
249 APBPrescaler::Div16 => 0x07,
250 }
251 }
252}
253
254impl Into<u8> for AHBPrescaler {
255 fn into(self) -> u8 {
256 match self {
257 AHBPrescaler::NotDivided => 1,
258 AHBPrescaler::Div2 => 0x08,
259 AHBPrescaler::Div4 => 0x09,
260 AHBPrescaler::Div8 => 0x0a,
261 AHBPrescaler::Div16 => 0x0b,
262 AHBPrescaler::Div64 => 0x0c,
263 AHBPrescaler::Div128 => 0x0d,
264 AHBPrescaler::Div256 => 0x0e,
265 AHBPrescaler::Div512 => 0x0f,
266 }
267 }
268}
269
270/// Clocks configutation
271pub struct Config {
272 pub mux: ClockSrc,
273 pub ahb_pre: AHBPrescaler,
274 pub apb1_pre: APBPrescaler,
275 pub apb2_pre: APBPrescaler,
276}
277
278impl Default for Config {
279 #[inline]
280 fn default() -> Config {
281 Config {
282 mux: ClockSrc::MSI(MSIRange::Range6),
283 ahb_pre: AHBPrescaler::NotDivided,
284 apb1_pre: APBPrescaler::NotDivided,
285 apb2_pre: APBPrescaler::NotDivided,
286 }
287 }
288}
289
290/// RCC peripheral
291pub struct Rcc<'d> {
292 _rb: peripherals::RCC,
293 phantom: PhantomData<&'d mut peripherals::RCC>,
294}
295
296impl<'d> Rcc<'d> {
297 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
298 unborrow!(rcc);
299 Self {
300 _rb: rcc,
301 phantom: PhantomData,
302 }
303 }
304
305 // Safety: RCC init must have been called
306 pub fn clocks(&self) -> &'static Clocks {
307 unsafe { get_freqs() }
308 }
309}
310
311/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
312pub trait RccExt {
313 fn freeze(self, config: Config) -> Clocks;
314}
315
316impl RccExt for RCC {
317 #[inline]
318 fn freeze(self, cfgr: Config) -> Clocks {
319 let rcc = pac::RCC;
320 let (sys_clk, sw) = match cfgr.mux {
321 ClockSrc::HSI16 => {
322 // Enable HSI16
323 unsafe {
324 rcc.cr().write(|w| w.set_hsion(true));
325 while !rcc.cr().read().hsirdy() {}
326 }
327
328 (HSI16_FREQ, 0b01)
329 }
330 ClockSrc::HSE(freq) => {
331 // Enable HSE
332 unsafe {
333 rcc.cr().write(|w| w.set_hseon(true));
334 while !rcc.cr().read().hserdy() {}
335 }
336
337 (freq.0, 0b10)
338 }
339 ClockSrc::MSI(range) => {
340 // Enable MSI
341 unsafe {
342 rcc.cr().write(|w| {
343 let bits: Msirange = range.into();
344 w.set_msirange(bits);
345 w.set_msipllen(false);
346 w.set_msirgsel(true);
347 w.set_msion(true);
348 });
349 while !rcc.cr().read().msirdy() {}
350
351 // Enable as clock source for USB, RNG if running at 48 MHz
352 if let MSIRange::Range11 = range {
353 rcc.ccipr().modify(|w| {
354 w.set_clk48sel(0b11);
355 });
356 }
357 }
358 (range.into(), 0b00)
359 }
360 ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
361 let freq = match src {
362 PLLSource::HSE(freq) => {
363 // Enable HSE
364 unsafe {
365 rcc.cr().write(|w| w.set_hseon(true));
366 while !rcc.cr().read().hserdy() {}
367 }
368 freq.0
369 }
370 PLLSource::HSI16 => {
371 // Enable HSI
372 unsafe {
373 rcc.cr().write(|w| w.set_hsion(true));
374 while !rcc.cr().read().hsirdy() {}
375 }
376 HSI16_FREQ
377 }
378 };
379
380 // Disable PLL
381 unsafe {
382 rcc.cr().modify(|w| w.set_pllon(false));
383 while rcc.cr().read().pllrdy() {}
384 }
385
386 let freq = (freq / prediv.to_div() * mul.to_mul()) / div.to_div();
387
388 assert!(freq <= 80_000_000);
389
390 unsafe {
391 rcc.pllcfgr().write(move |w| {
392 w.set_plln(mul.into());
393 w.set_pllm(prediv.into());
394 w.set_pllr(div.into());
395 if let Some(pll48div) = pll48div {
396 w.set_pllq(pll48div.into());
397 w.set_pllqen(true);
398 }
399 w.set_pllsrc(src.into());
400 });
401
402 // Enable as clock source for USB, RNG if PLL48 divisor is provided
403 if pll48div.is_some() {
404 rcc.ccipr().modify(|w| {
405 w.set_clk48sel(0b10);
406 });
407 }
408
409 // Enable PLL
410 rcc.cr().modify(|w| w.set_pllon(true));
411 while !rcc.cr().read().pllrdy() {}
412 rcc.pllcfgr().modify(|w| w.set_pllren(true));
413 }
414 (freq, 0b11)
415 }
416 };
417
418 unsafe {
419 // Set flash wait states
420 pac::FLASH.acr().modify(|w| {
421 w.set_latency(if sys_clk <= 16_000_000 {
422 0b000
423 } else if sys_clk <= 32_000_000 {
424 0b001
425 } else if sys_clk <= 48_000_000 {
426 0b010
427 } else if sys_clk <= 64_000_000 {
428 0b011
429 } else {
430 0b100
431 });
432 });
433
434 // Switch active clocks to new clock source
435 rcc.cfgr().modify(|w| {
436 w.set_sw(sw.into());
437 w.set_hpre(cfgr.ahb_pre.into());
438 w.set_ppre1(cfgr.apb1_pre.into());
439 w.set_ppre2(cfgr.apb2_pre.into());
440 });
441 }
442
443 let ahb_freq: u32 = match cfgr.ahb_pre {
444 AHBPrescaler::NotDivided => sys_clk,
445 pre => {
446 let pre: u8 = pre.into();
447 let pre = 1 << (pre as u32 - 7);
448 sys_clk / pre
449 }
450 };
451
452 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
453 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
454 pre => {
455 let pre: u8 = pre.into();
456 let pre: u8 = 1 << (pre - 3);
457 let freq = ahb_freq / pre as u32;
458 (freq, freq * 2)
459 }
460 };
461
462 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
463 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
464 pre => {
465 let pre: u8 = pre.into();
466 let pre: u8 = 1 << (pre - 3);
467 let freq = ahb_freq / (1 << (pre as u8 - 3));
468 (freq, freq * 2)
469 }
470 };
471
472 Clocks {
473 sys: sys_clk.hz(),
474 ahb1: ahb_freq.hz(),
475 ahb2: ahb_freq.hz(),
476 ahb3: ahb_freq.hz(),
477 apb1: apb1_freq.hz(),
478 apb2: apb2_freq.hz(),
479 apb1_tim: apb1_tim_freq.hz(),
480 apb2_tim: apb2_tim_freq.hz(),
481 }
482 }
483}
484
485pub unsafe fn init(config: Config) {
486 let r = <peripherals::RCC as embassy::util::Steal>::steal();
487 let clocks = r.freeze(config);
488 set_freqs(clocks);
489}
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 0a7edb37a..d0b6e5a18 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -4,6 +4,23 @@ use crate::peripherals;
4use crate::time::Hertz; 4use crate::time::Hertz;
5use core::mem::MaybeUninit; 5use core::mem::MaybeUninit;
6 6
7#[cfg_attr(any(rcc_f0, rcc_f0x0), path = "f0.rs")]
8#[cfg_attr(rcc_f1, path = "f1.rs")]
9#[cfg_attr(rcc_f3, path = "f3.rs")]
10#[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")]
11#[cfg_attr(rcc_f7, path = "f7.rs")]
12#[cfg_attr(rcc_g0, path = "g0.rs")]
13#[cfg_attr(rcc_g4, path = "g4.rs")]
14#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
15#[cfg_attr(rcc_l0, path = "l0.rs")]
16#[cfg_attr(rcc_l1, path = "l1.rs")]
17#[cfg_attr(rcc_l4, path = "l4.rs")]
18#[cfg_attr(rcc_u5, path = "u5.rs")]
19#[cfg_attr(rcc_wb, path = "wb.rs")]
20#[cfg_attr(rcc_wl5, path = "wl5.rs")]
21mod _version;
22pub use _version::*;
23
7#[derive(Clone, Copy)] 24#[derive(Clone, Copy)]
8pub struct Clocks { 25pub struct Clocks {
9 pub sys: Hertz, 26 pub sys: Hertz,
@@ -44,7 +61,7 @@ pub struct Clocks {
44 #[cfg(any(rcc_h7))] 61 #[cfg(any(rcc_h7))]
45 pub apb4: Hertz, 62 pub apb4: Hertz,
46 63
47 #[cfg(rcc_f4)] 64 #[cfg(any(rcc_f4, rcc_f7))]
48 pub pll48: Option<Hertz>, 65 pub pll48: Option<Hertz>,
49 66
50 #[cfg(rcc_f1)] 67 #[cfg(rcc_f1)]
@@ -59,61 +76,15 @@ static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
59/// Sets the clock frequencies 76/// Sets the clock frequencies
60/// 77///
61/// Safety: Sets a mutable global. 78/// Safety: Sets a mutable global.
62pub unsafe fn set_freqs(freqs: Clocks) { 79pub(crate) unsafe fn set_freqs(freqs: Clocks) {
63 CLOCK_FREQS.as_mut_ptr().write(freqs); 80 CLOCK_FREQS.as_mut_ptr().write(freqs);
64} 81}
65 82
66/// Safety: Reads a mutable global. 83/// Safety: Reads a mutable global.
67pub unsafe fn get_freqs() -> &'static Clocks { 84pub(crate) unsafe fn get_freqs() -> &'static Clocks {
68 &*CLOCK_FREQS.as_ptr() 85 &*CLOCK_FREQS.as_ptr()
69} 86}
70 87
71cfg_if::cfg_if! {
72 if #[cfg(rcc_h7)] {
73 mod h7;
74 pub use h7::*;
75 } else if #[cfg(rcc_l0)] {
76 mod l0;
77 pub use l0::*;
78 } else if #[cfg(rcc_l1)] {
79 mod l1;
80 pub use l1::*;
81 } else if #[cfg(rcc_l4)] {
82 mod l4;
83 pub use l4::*;
84 } else if #[cfg(rcc_f1)] {
85 mod f1;
86 pub use f1::*;
87 } else if #[cfg(rcc_f3)] {
88 mod f3;
89 pub use f3::*;
90 } else if #[cfg(rcc_f4)] {
91 mod f4;
92 pub use f4::*;
93 } else if #[cfg(rcc_f7)] {
94 mod f7;
95 pub use f7::*;
96 } else if #[cfg(rcc_wb)] {
97 mod wb;
98 pub use wb::*;
99 } else if #[cfg(rcc_wl5)] {
100 mod wl5x;
101 pub use wl5x::*;
102 } else if #[cfg(any(rcc_f0, rcc_f0x0))] {
103 mod f0;
104 pub use f0::*;
105 } else if #[cfg(any(rcc_g0))] {
106 mod g0;
107 pub use g0::*;
108 } else if #[cfg(any(rcc_g4))] {
109 mod g4;
110 pub use g4::*;
111 } else if #[cfg(any(rcc_u5))] {
112 mod u5;
113 pub use u5::*;
114 }
115}
116
117pub(crate) mod sealed { 88pub(crate) mod sealed {
118 pub trait RccPeripheral { 89 pub trait RccPeripheral {
119 fn frequency() -> crate::time::Hertz; 90 fn frequency() -> crate::time::Hertz;
diff --git a/embassy-stm32/src/rcc/u5/mod.rs b/embassy-stm32/src/rcc/u5.rs
index a3df3a02d..ac1cd06c8 100644
--- a/embassy-stm32/src/rcc/u5/mod.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -1,6 +1,4 @@
1use crate::pac; 1use crate::pac::{FLASH, RCC};
2use crate::peripherals::{self, RCC};
3use crate::pwr::{Power, VoltageScale};
4use crate::rcc::{set_freqs, Clocks}; 2use crate::rcc::{set_freqs, Clocks};
5use crate::time::{Hertz, U32Ext}; 3use crate::time::{Hertz, U32Ext};
6use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}; 4use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw};
@@ -8,6 +6,20 @@ use stm32_metapac::rcc::vals::{Hpre, Msirange, Msirgsel, Pllm, Pllsrc, Ppre, Sw}
8/// HSI16 speed 6/// HSI16 speed
9pub const HSI16_FREQ: u32 = 16_000_000; 7pub const HSI16_FREQ: u32 = 16_000_000;
10 8
9/// Voltage Scale
10///
11/// Represents the voltage range feeding the CPU core. The maximum core
12/// clock frequency depends on this value.
13#[derive(Copy, Clone, PartialEq)]
14pub enum VoltageScale {
15 // Highest frequency
16 Range1,
17 Range2,
18 Range3,
19 // Lowest power
20 Range4,
21}
22
11#[derive(Copy, Clone)] 23#[derive(Copy, Clone)]
12pub enum ClockSrc { 24pub enum ClockSrc {
13 MSI(MSIRange), 25 MSI(MSIRange),
@@ -293,218 +305,188 @@ impl Default for Config {
293 } 305 }
294} 306}
295 307
296/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration 308pub(crate) unsafe fn init(config: Config) {
297pub trait RccExt { 309 let sys_clk = match config.mux {
298 fn freeze(self, config: Config, power: &Power) -> Clocks; 310 ClockSrc::MSI(range) => {
299} 311 RCC.icscr1().modify(|w| {
300 312 let bits: Msirange = range.into();
301impl RccExt for RCC { 313 w.set_msisrange(bits);
302 #[inline] 314 w.set_msirgsel(Msirgsel::RCC_ICSCR1);
303 fn freeze(self, cfgr: Config, power: &Power) -> Clocks { 315 });
304 let rcc = pac::RCC; 316 RCC.cr().write(|w| {
305 317 w.set_msipllen(false);
306 let sys_clk = match cfgr.mux { 318 w.set_msison(true);
307 ClockSrc::MSI(range) => { 319 w.set_msison(true);
308 unsafe { 320 });
309 rcc.icscr1().modify(|w| { 321 while !RCC.cr().read().msisrdy() {}
310 let bits: Msirange = range.into();
311 w.set_msisrange(bits);
312 w.set_msirgsel(Msirgsel::RCC_ICSCR1);
313 });
314 rcc.cr().write(|w| {
315 w.set_msipllen(false);
316 w.set_msison(true);
317 w.set_msison(true);
318 });
319 while !rcc.cr().read().msisrdy() {}
320 }
321
322 range.into()
323 }
324 ClockSrc::HSE(freq) => {
325 unsafe {
326 rcc.cr().write(|w| w.set_hseon(true));
327 while !rcc.cr().read().hserdy() {}
328 }
329
330 freq.0
331 }
332 ClockSrc::HSI16 => {
333 unsafe {
334 rcc.cr().write(|w| w.set_hsion(true));
335 while !rcc.cr().read().hsirdy() {}
336 }
337 322
338 HSI16_FREQ 323 range.into()
339 } 324 }
340 ClockSrc::PLL1R(src, m, n, div) => { 325 ClockSrc::HSE(freq) => {
341 let freq = match src { 326 RCC.cr().write(|w| w.set_hseon(true));
342 PllSrc::MSI(_) => MSIRange::default().into(), 327 while !RCC.cr().read().hserdy() {}
343 PllSrc::HSE(hertz) => hertz.0,
344 PllSrc::HSI16 => HSI16_FREQ,
345 };
346
347 // disable
348 unsafe {
349 rcc.cr().modify(|w| w.set_pllon(0, false));
350 while rcc.cr().read().pllrdy(0) {}
351 }
352
353 let vco = freq * n as u8 as u32;
354 let pll_ck = vco / (div as u8 as u32 + 1);
355
356 unsafe {
357 rcc.pll1cfgr().write(|w| {
358 w.set_pllm(m.into());
359 w.set_pllsrc(src.into());
360 });
361
362 rcc.pll1divr().modify(|w| {
363 w.set_pllr(div.to_div());
364 w.set_plln(n.to_mul());
365 });
366
367 // Enable PLL
368 rcc.cr().modify(|w| w.set_pllon(0, true));
369 while !rcc.cr().read().pllrdy(0) {}
370 rcc.pll1cfgr().modify(|w| w.set_pllren(true));
371 }
372
373 unsafe {
374 rcc.cr().write(|w| w.set_pllon(0, true));
375 while !rcc.cr().read().pllrdy(0) {}
376 }
377
378 pll_ck
379 }
380 };
381
382 // states and programming delay
383 let wait_states = match power.vos {
384 // VOS 0 range VCORE 1.26V - 1.40V
385 VoltageScale::Range1 => {
386 if sys_clk < 32_000_000 {
387 0
388 } else if sys_clk < 64_000_000 {
389 1
390 } else if sys_clk < 96_000_000 {
391 2
392 } else if sys_clk < 128_000_000 {
393 3
394 } else {
395 4
396 }
397 }
398 // VOS 1 range VCORE 1.15V - 1.26V
399 VoltageScale::Range2 => {
400 if sys_clk < 30_000_000 {
401 0
402 } else if sys_clk < 60_000_000 {
403 1
404 } else if sys_clk < 90_000_000 {
405 2
406 } else {
407 3
408 }
409 }
410 // VOS 2 range VCORE 1.05V - 1.15V
411 VoltageScale::Range3 => {
412 if sys_clk < 24_000_000 {
413 0
414 } else if sys_clk < 48_000_000 {
415 1
416 } else {
417 2
418 }
419 }
420 // VOS 3 range VCORE 0.95V - 1.05V
421 VoltageScale::Range4 => {
422 if sys_clk < 12_000_000 {
423 0
424 } else {
425 1
426 }
427 }
428 };
429 328
430 unsafe { 329 freq.0
431 pac::FLASH.acr().modify(|w| {
432 w.set_latency(wait_states);
433 })
434 } 330 }
331 ClockSrc::HSI16 => {
332 RCC.cr().write(|w| w.set_hsion(true));
333 while !RCC.cr().read().hsirdy() {}
435 334
436 unsafe { 335 HSI16_FREQ
437 rcc.cfgr1().modify(|w| { 336 }
438 w.set_sw(cfgr.mux.into()); 337 ClockSrc::PLL1R(src, m, n, div) => {
338 let freq = match src {
339 PllSrc::MSI(_) => MSIRange::default().into(),
340 PllSrc::HSE(hertz) => hertz.0,
341 PllSrc::HSI16 => HSI16_FREQ,
342 };
343
344 // disable
345 RCC.cr().modify(|w| w.set_pllon(0, false));
346 while RCC.cr().read().pllrdy(0) {}
347
348 let vco = freq * n as u8 as u32;
349 let pll_ck = vco / (div as u8 as u32 + 1);
350
351 RCC.pll1cfgr().write(|w| {
352 w.set_pllm(m.into());
353 w.set_pllsrc(src.into());
439 }); 354 });
440 355
441 rcc.cfgr2().modify(|w| { 356 RCC.pll1divr().modify(|w| {
442 w.set_hpre(cfgr.ahb_pre.into()); 357 w.set_pllr(div.to_div());
443 w.set_ppre1(cfgr.apb1_pre.into()); 358 w.set_plln(n.to_mul());
444 w.set_ppre2(cfgr.apb2_pre.into());
445 }); 359 });
446 360
447 rcc.cfgr3().modify(|w| { 361 // Enable PLL
448 w.set_ppre3(cfgr.apb3_pre.into()); 362 RCC.cr().modify(|w| w.set_pllon(0, true));
449 }); 363 while !RCC.cr().read().pllrdy(0) {}
450 } 364 RCC.pll1cfgr().modify(|w| w.set_pllren(true));
365
366 RCC.cr().write(|w| w.set_pllon(0, true));
367 while !RCC.cr().read().pllrdy(0) {}
451 368
452 let ahb_freq: u32 = match cfgr.ahb_pre { 369 pll_ck
453 AHBPrescaler::NotDivided => sys_clk, 370 }
454 pre => { 371 };
455 let pre: u8 = pre.into(); 372
456 let pre = 1 << (pre as u32 - 7); 373 // TODO make configurable
457 sys_clk / pre 374 let power_vos = VoltageScale::Range4;
375
376 // states and programming delay
377 let wait_states = match power_vos {
378 // VOS 0 range VCORE 1.26V - 1.40V
379 VoltageScale::Range1 => {
380 if sys_clk < 32_000_000 {
381 0
382 } else if sys_clk < 64_000_000 {
383 1
384 } else if sys_clk < 96_000_000 {
385 2
386 } else if sys_clk < 128_000_000 {
387 3
388 } else {
389 4
458 } 390 }
459 }; 391 }
460 392 // VOS 1 range VCORE 1.15V - 1.26V
461 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre { 393 VoltageScale::Range2 => {
462 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 394 if sys_clk < 30_000_000 {
463 pre => { 395 0
464 let pre: u8 = pre.into(); 396 } else if sys_clk < 60_000_000 {
465 let pre: u8 = 1 << (pre - 3); 397 1
466 let freq = ahb_freq / pre as u32; 398 } else if sys_clk < 90_000_000 {
467 (freq, freq * 2) 399 2
400 } else {
401 3
468 } 402 }
469 }; 403 }
470 404 // VOS 2 range VCORE 1.05V - 1.15V
471 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre { 405 VoltageScale::Range3 => {
472 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 406 if sys_clk < 24_000_000 {
473 pre => { 407 0
474 let pre: u8 = pre.into(); 408 } else if sys_clk < 48_000_000 {
475 let pre: u8 = 1 << (pre - 3); 409 1
476 let freq = ahb_freq / (1 << (pre as u8 - 3)); 410 } else {
477 (freq, freq * 2) 411 2
478 } 412 }
479 }; 413 }
480 414 // VOS 3 range VCORE 0.95V - 1.05V
481 let (apb3_freq, _apb3_tim_freq) = match cfgr.apb3_pre { 415 VoltageScale::Range4 => {
482 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 416 if sys_clk < 12_000_000 {
483 pre => { 417 0
484 let pre: u8 = pre.into(); 418 } else {
485 let pre: u8 = 1 << (pre - 3); 419 1
486 let freq = ahb_freq / (1 << (pre as u8 - 3));
487 (freq, freq * 2)
488 } 420 }
489 };
490
491 Clocks {
492 sys: sys_clk.hz(),
493 ahb1: ahb_freq.hz(),
494 ahb2: ahb_freq.hz(),
495 ahb3: ahb_freq.hz(),
496 apb1: apb1_freq.hz(),
497 apb2: apb2_freq.hz(),
498 apb3: apb3_freq.hz(),
499 apb1_tim: apb1_tim_freq.hz(),
500 apb2_tim: apb2_tim_freq.hz(),
501 } 421 }
502 } 422 };
503} 423
504 424 FLASH.acr().modify(|w| {
505pub unsafe fn init(config: Config) { 425 w.set_latency(wait_states);
506 let r = <peripherals::RCC as embassy::util::Steal>::steal(); 426 });
507 let power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal()); 427
508 let clocks = r.freeze(config, &power); 428 RCC.cfgr1().modify(|w| {
509 set_freqs(clocks); 429 w.set_sw(config.mux.into());
430 });
431
432 RCC.cfgr2().modify(|w| {
433 w.set_hpre(config.ahb_pre.into());
434 w.set_ppre1(config.apb1_pre.into());
435 w.set_ppre2(config.apb2_pre.into());
436 });
437
438 RCC.cfgr3().modify(|w| {
439 w.set_ppre3(config.apb3_pre.into());
440 });
441
442 let ahb_freq: u32 = match config.ahb_pre {
443 AHBPrescaler::NotDivided => sys_clk,
444 pre => {
445 let pre: u8 = pre.into();
446 let pre = 1 << (pre as u32 - 7);
447 sys_clk / pre
448 }
449 };
450
451 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
452 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
453 pre => {
454 let pre: u8 = pre.into();
455 let pre: u8 = 1 << (pre - 3);
456 let freq = ahb_freq / pre as u32;
457 (freq, freq * 2)
458 }
459 };
460
461 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
462 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
463 pre => {
464 let pre: u8 = pre.into();
465 let pre: u8 = 1 << (pre - 3);
466 let freq = ahb_freq / (1 << (pre as u8 - 3));
467 (freq, freq * 2)
468 }
469 };
470
471 let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
472 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
473 pre => {
474 let pre: u8 = pre.into();
475 let pre: u8 = 1 << (pre - 3);
476 let freq = ahb_freq / (1 << (pre as u8 - 3));
477 (freq, freq * 2)
478 }
479 };
480
481 set_freqs(Clocks {
482 sys: sys_clk.hz(),
483 ahb1: ahb_freq.hz(),
484 ahb2: ahb_freq.hz(),
485 ahb3: ahb_freq.hz(),
486 apb1: apb1_freq.hz(),
487 apb2: apb2_freq.hz(),
488 apb3: apb3_freq.hz(),
489 apb1_tim: apb1_tim_freq.hz(),
490 apb2_tim: apb2_tim_freq.hz(),
491 });
510} 492}
diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs
new file mode 100644
index 000000000..eae7c9464
--- /dev/null
+++ b/embassy-stm32/src/rcc/wb.rs
@@ -0,0 +1,167 @@
1use crate::pac::RCC;
2use crate::rcc::{set_freqs, Clocks};
3use crate::time::Hertz;
4use crate::time::U32Ext;
5
6/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
7/// and with the addition of the init function to configure a system clock.
8
9/// Only the basic setup using the HSE and HSI clocks are supported as of now.
10
11/// HSI speed
12pub const HSI_FREQ: u32 = 16_000_000;
13
14/// System clock mux source
15#[derive(Clone, Copy)]
16pub enum ClockSrc {
17 HSE(Hertz),
18 HSI16,
19}
20
21/// AHB prescaler
22#[derive(Clone, Copy, PartialEq)]
23pub enum AHBPrescaler {
24 NotDivided,
25 Div2,
26 Div3,
27 Div4,
28 Div5,
29 Div6,
30 Div8,
31 Div10,
32 Div16,
33 Div32,
34 Div64,
35 Div128,
36 Div256,
37 Div512,
38}
39
40/// APB prescaler
41#[derive(Clone, Copy)]
42pub enum APBPrescaler {
43 NotDivided,
44 Div2,
45 Div4,
46 Div8,
47 Div16,
48}
49
50impl Into<u8> for APBPrescaler {
51 fn into(self) -> u8 {
52 match self {
53 APBPrescaler::NotDivided => 1,
54 APBPrescaler::Div2 => 0x04,
55 APBPrescaler::Div4 => 0x05,
56 APBPrescaler::Div8 => 0x06,
57 APBPrescaler::Div16 => 0x07,
58 }
59 }
60}
61
62impl Into<u8> for AHBPrescaler {
63 fn into(self) -> u8 {
64 match self {
65 AHBPrescaler::NotDivided => 1,
66 AHBPrescaler::Div2 => 0x08,
67 AHBPrescaler::Div3 => 0x01,
68 AHBPrescaler::Div4 => 0x09,
69 AHBPrescaler::Div5 => 0x02,
70 AHBPrescaler::Div6 => 0x05,
71 AHBPrescaler::Div8 => 0x0a,
72 AHBPrescaler::Div10 => 0x06,
73 AHBPrescaler::Div16 => 0x0b,
74 AHBPrescaler::Div32 => 0x07,
75 AHBPrescaler::Div64 => 0x0c,
76 AHBPrescaler::Div128 => 0x0d,
77 AHBPrescaler::Div256 => 0x0e,
78 AHBPrescaler::Div512 => 0x0f,
79 }
80 }
81}
82
83/// Clocks configutation
84pub struct Config {
85 pub mux: ClockSrc,
86 pub ahb_pre: AHBPrescaler,
87 pub apb1_pre: APBPrescaler,
88 pub apb2_pre: APBPrescaler,
89}
90
91impl Default for Config {
92 #[inline]
93 fn default() -> Config {
94 Config {
95 mux: ClockSrc::HSI16,
96 ahb_pre: AHBPrescaler::NotDivided,
97 apb1_pre: APBPrescaler::NotDivided,
98 apb2_pre: APBPrescaler::NotDivided,
99 }
100 }
101}
102
103pub(crate) unsafe fn init(config: Config) {
104 let (sys_clk, sw) = match config.mux {
105 ClockSrc::HSI16 => {
106 // Enable HSI16
107 RCC.cr().write(|w| w.set_hsion(true));
108 while !RCC.cr().read().hsirdy() {}
109
110 (HSI_FREQ, 0x01)
111 }
112 ClockSrc::HSE(freq) => {
113 // Enable HSE
114 RCC.cr().write(|w| w.set_hseon(true));
115 while !RCC.cr().read().hserdy() {}
116
117 (freq.0, 0x02)
118 }
119 };
120
121 RCC.cfgr().modify(|w| {
122 w.set_sw(sw.into());
123 w.set_hpre(config.ahb_pre.into());
124 w.set_ppre1(config.apb1_pre.into());
125 w.set_ppre2(config.apb2_pre.into());
126 });
127
128 let ahb_freq: u32 = match config.ahb_pre {
129 AHBPrescaler::NotDivided => sys_clk,
130 pre => {
131 let pre: u8 = pre.into();
132 let pre = 1 << (pre as u32 - 7);
133 sys_clk / pre
134 }
135 };
136
137 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
138 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
139 pre => {
140 let pre: u8 = pre.into();
141 let pre: u8 = 1 << (pre - 3);
142 let freq = ahb_freq / pre as u32;
143 (freq, freq * 2)
144 }
145 };
146
147 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
148 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
149 pre => {
150 let pre: u8 = pre.into();
151 let pre: u8 = 1 << (pre - 3);
152 let freq = ahb_freq / (1 << (pre as u8 - 3));
153 (freq, freq * 2)
154 }
155 };
156
157 set_freqs(Clocks {
158 sys: sys_clk.hz(),
159 ahb1: ahb_freq.hz(),
160 ahb2: ahb_freq.hz(),
161 ahb3: ahb_freq.hz(),
162 apb1: apb1_freq.hz(),
163 apb2: apb2_freq.hz(),
164 apb1_tim: apb1_tim_freq.hz(),
165 apb2_tim: apb2_tim_freq.hz(),
166 });
167}
diff --git a/embassy-stm32/src/rcc/wb/mod.rs b/embassy-stm32/src/rcc/wb/mod.rs
deleted file mode 100644
index 73835cacd..000000000
--- a/embassy-stm32/src/rcc/wb/mod.rs
+++ /dev/null
@@ -1,213 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::Hertz;
5use crate::time::U32Ext;
6use core::marker::PhantomData;
7use embassy::util::Unborrow;
8use embassy_hal_common::unborrow;
9
10/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
11/// and with the addition of the init function to configure a system clock.
12
13/// Only the basic setup using the HSE and HSI clocks are supported as of now.
14
15/// HSI speed
16pub const HSI_FREQ: u32 = 16_000_000;
17
18/// System clock mux source
19#[derive(Clone, Copy)]
20pub enum ClockSrc {
21 HSE(Hertz),
22 HSI16,
23}
24
25/// AHB prescaler
26#[derive(Clone, Copy, PartialEq)]
27pub enum AHBPrescaler {
28 NotDivided,
29 Div2,
30 Div3,
31 Div4,
32 Div5,
33 Div6,
34 Div8,
35 Div10,
36 Div16,
37 Div32,
38 Div64,
39 Div128,
40 Div256,
41 Div512,
42}
43
44/// APB prescaler
45#[derive(Clone, Copy)]
46pub enum APBPrescaler {
47 NotDivided,
48 Div2,
49 Div4,
50 Div8,
51 Div16,
52}
53
54impl Into<u8> for APBPrescaler {
55 fn into(self) -> u8 {
56 match self {
57 APBPrescaler::NotDivided => 1,
58 APBPrescaler::Div2 => 0x04,
59 APBPrescaler::Div4 => 0x05,
60 APBPrescaler::Div8 => 0x06,
61 APBPrescaler::Div16 => 0x07,
62 }
63 }
64}
65
66impl Into<u8> for AHBPrescaler {
67 fn into(self) -> u8 {
68 match self {
69 AHBPrescaler::NotDivided => 1,
70 AHBPrescaler::Div2 => 0x08,
71 AHBPrescaler::Div3 => 0x01,
72 AHBPrescaler::Div4 => 0x09,
73 AHBPrescaler::Div5 => 0x02,
74 AHBPrescaler::Div6 => 0x05,
75 AHBPrescaler::Div8 => 0x0a,
76 AHBPrescaler::Div10 => 0x06,
77 AHBPrescaler::Div16 => 0x0b,
78 AHBPrescaler::Div32 => 0x07,
79 AHBPrescaler::Div64 => 0x0c,
80 AHBPrescaler::Div128 => 0x0d,
81 AHBPrescaler::Div256 => 0x0e,
82 AHBPrescaler::Div512 => 0x0f,
83 }
84 }
85}
86
87/// Clocks configutation
88pub struct Config {
89 pub mux: ClockSrc,
90 pub ahb_pre: AHBPrescaler,
91 pub apb1_pre: APBPrescaler,
92 pub apb2_pre: APBPrescaler,
93}
94
95impl Default for Config {
96 #[inline]
97 fn default() -> Config {
98 Config {
99 mux: ClockSrc::HSI16,
100 ahb_pre: AHBPrescaler::NotDivided,
101 apb1_pre: APBPrescaler::NotDivided,
102 apb2_pre: APBPrescaler::NotDivided,
103 }
104 }
105}
106
107/// RCC peripheral
108pub struct Rcc<'d> {
109 _rb: peripherals::RCC,
110 phantom: PhantomData<&'d mut peripherals::RCC>,
111}
112
113impl<'d> Rcc<'d> {
114 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
115 unborrow!(rcc);
116 Self {
117 _rb: rcc,
118 phantom: PhantomData,
119 }
120 }
121
122 // Safety: RCC init must have been called
123 pub fn clocks(&self) -> &'static Clocks {
124 unsafe { get_freqs() }
125 }
126}
127
128/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
129pub trait RccExt {
130 fn freeze(self, config: Config) -> Clocks;
131}
132
133impl RccExt for RCC {
134 #[inline]
135 fn freeze(self, cfgr: Config) -> Clocks {
136 let rcc = pac::RCC;
137 let (sys_clk, sw) = match cfgr.mux {
138 ClockSrc::HSI16 => {
139 // Enable HSI16
140 unsafe {
141 rcc.cr().write(|w| w.set_hsion(true));
142 while !rcc.cr().read().hsirdy() {}
143 }
144
145 (HSI_FREQ, 0x01)
146 }
147 ClockSrc::HSE(freq) => {
148 // Enable HSE
149 unsafe {
150 rcc.cr().write(|w| w.set_hseon(true));
151 while !rcc.cr().read().hserdy() {}
152 }
153
154 (freq.0, 0x02)
155 }
156 };
157
158 unsafe {
159 rcc.cfgr().modify(|w| {
160 w.set_sw(sw.into());
161 w.set_hpre(cfgr.ahb_pre.into());
162 w.set_ppre1(cfgr.apb1_pre.into());
163 w.set_ppre2(cfgr.apb2_pre.into());
164 });
165 }
166
167 let ahb_freq: u32 = match cfgr.ahb_pre {
168 AHBPrescaler::NotDivided => sys_clk,
169 pre => {
170 let pre: u8 = pre.into();
171 let pre = 1 << (pre as u32 - 7);
172 sys_clk / pre
173 }
174 };
175
176 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
177 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
178 pre => {
179 let pre: u8 = pre.into();
180 let pre: u8 = 1 << (pre - 3);
181 let freq = ahb_freq / pre as u32;
182 (freq, freq * 2)
183 }
184 };
185
186 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
187 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
188 pre => {
189 let pre: u8 = pre.into();
190 let pre: u8 = 1 << (pre - 3);
191 let freq = ahb_freq / (1 << (pre as u8 - 3));
192 (freq, freq * 2)
193 }
194 };
195
196 Clocks {
197 sys: sys_clk.hz(),
198 ahb1: ahb_freq.hz(),
199 ahb2: ahb_freq.hz(),
200 ahb3: ahb_freq.hz(),
201 apb1: apb1_freq.hz(),
202 apb2: apb2_freq.hz(),
203 apb1_tim: apb1_tim_freq.hz(),
204 apb2_tim: apb2_tim_freq.hz(),
205 }
206 }
207}
208
209pub unsafe fn init(config: Config) {
210 let r = <peripherals::RCC as embassy::util::Steal>::steal();
211 let clocks = r.freeze(config);
212 set_freqs(clocks);
213}
diff --git a/embassy-stm32/src/rcc/wl5.rs b/embassy-stm32/src/rcc/wl5.rs
new file mode 100644
index 000000000..fb2dd9986
--- /dev/null
+++ b/embassy-stm32/src/rcc/wl5.rs
@@ -0,0 +1,189 @@
1use crate::pac::RCC;
2use crate::rcc::{set_freqs, Clocks};
3use crate::time::U32Ext;
4
5/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
6/// and with the addition of the init function to configure a system clock.
7
8/// Only the basic setup using the HSE and HSI clocks are supported as of now.
9
10/// HSI speed
11pub const HSI_FREQ: u32 = 16_000_000;
12
13pub const HSE32_FREQ: u32 = 32_000_000;
14
15/// System clock mux source
16#[derive(Clone, Copy)]
17pub enum ClockSrc {
18 HSE32,
19 HSI16,
20}
21
22/// AHB prescaler
23#[derive(Clone, Copy, PartialEq)]
24pub enum AHBPrescaler {
25 NotDivided,
26 Div2,
27 Div3,
28 Div4,
29 Div5,
30 Div6,
31 Div8,
32 Div10,
33 Div16,
34 Div32,
35 Div64,
36 Div128,
37 Div256,
38 Div512,
39}
40
41/// APB prescaler
42#[derive(Clone, Copy)]
43pub enum APBPrescaler {
44 NotDivided,
45 Div2,
46 Div4,
47 Div8,
48 Div16,
49}
50
51impl Into<u8> for APBPrescaler {
52 fn into(self) -> u8 {
53 match self {
54 APBPrescaler::NotDivided => 1,
55 APBPrescaler::Div2 => 0x04,
56 APBPrescaler::Div4 => 0x05,
57 APBPrescaler::Div8 => 0x06,
58 APBPrescaler::Div16 => 0x07,
59 }
60 }
61}
62
63impl Into<u8> for AHBPrescaler {
64 fn into(self) -> u8 {
65 match self {
66 AHBPrescaler::NotDivided => 1,
67 AHBPrescaler::Div2 => 0x08,
68 AHBPrescaler::Div3 => 0x01,
69 AHBPrescaler::Div4 => 0x09,
70 AHBPrescaler::Div5 => 0x02,
71 AHBPrescaler::Div6 => 0x05,
72 AHBPrescaler::Div8 => 0x0a,
73 AHBPrescaler::Div10 => 0x06,
74 AHBPrescaler::Div16 => 0x0b,
75 AHBPrescaler::Div32 => 0x07,
76 AHBPrescaler::Div64 => 0x0c,
77 AHBPrescaler::Div128 => 0x0d,
78 AHBPrescaler::Div256 => 0x0e,
79 AHBPrescaler::Div512 => 0x0f,
80 }
81 }
82}
83
84/// Clocks configutation
85pub struct Config {
86 pub mux: ClockSrc,
87 pub ahb_pre: AHBPrescaler,
88 pub apb1_pre: APBPrescaler,
89 pub apb2_pre: APBPrescaler,
90 pub enable_lsi: bool,
91}
92
93impl Default for Config {
94 #[inline]
95 fn default() -> Config {
96 Config {
97 mux: ClockSrc::HSI16,
98 ahb_pre: AHBPrescaler::NotDivided,
99 apb1_pre: APBPrescaler::NotDivided,
100 apb2_pre: APBPrescaler::NotDivided,
101 enable_lsi: false,
102 }
103 }
104}
105
106pub(crate) unsafe fn init(config: Config) {
107 let (sys_clk, sw) = match config.mux {
108 ClockSrc::HSI16 => {
109 // Enable HSI16
110 RCC.cr().write(|w| w.set_hsion(true));
111 while !RCC.cr().read().hsirdy() {}
112
113 (HSI_FREQ, 0x01)
114 }
115 ClockSrc::HSE32 => {
116 // Enable HSE32
117 RCC.cr().write(|w| {
118 w.set_hsebyppwr(true);
119 w.set_hseon(true);
120 });
121 while !RCC.cr().read().hserdy() {}
122
123 (HSE32_FREQ, 0x02)
124 }
125 };
126
127 RCC.cfgr().modify(|w| {
128 w.set_sw(sw.into());
129 if config.ahb_pre == AHBPrescaler::NotDivided {
130 w.set_hpre(0);
131 } else {
132 w.set_hpre(config.ahb_pre.into());
133 }
134 w.set_ppre1(config.apb1_pre.into());
135 w.set_ppre2(config.apb2_pre.into());
136 });
137
138 let ahb_freq: u32 = match config.ahb_pre {
139 AHBPrescaler::NotDivided => sys_clk,
140 pre => {
141 let pre: u8 = pre.into();
142 let pre = 1 << (pre as u32 - 7);
143 sys_clk / pre
144 }
145 };
146
147 let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
148 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
149 pre => {
150 let pre: u8 = pre.into();
151 let pre: u8 = 1 << (pre - 3);
152 let freq = ahb_freq / pre as u32;
153 (freq, freq * 2)
154 }
155 };
156
157 let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
158 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
159 pre => {
160 let pre: u8 = pre.into();
161 let pre: u8 = 1 << (pre - 3);
162 let freq = ahb_freq / (1 << (pre as u8 - 3));
163 (freq, freq * 2)
164 }
165 };
166
167 // TODO: completely untested
168 let apb3_freq = ahb_freq;
169
170 if config.enable_lsi {
171 let csr = RCC.csr().read();
172 if !csr.lsion() {
173 RCC.csr().modify(|w| w.set_lsion(true));
174 while !RCC.csr().read().lsirdy() {}
175 }
176 }
177
178 set_freqs(Clocks {
179 sys: sys_clk.hz(),
180 ahb1: ahb_freq.hz(),
181 ahb2: ahb_freq.hz(),
182 ahb3: ahb_freq.hz(),
183 apb1: apb1_freq.hz(),
184 apb2: apb2_freq.hz(),
185 apb3: apb3_freq.hz(),
186 apb1_tim: apb1_tim_freq.hz(),
187 apb2_tim: apb2_tim_freq.hz(),
188 });
189}
diff --git a/embassy-stm32/src/rcc/wl5x/mod.rs b/embassy-stm32/src/rcc/wl5x/mod.rs
deleted file mode 100644
index edf603ee6..000000000
--- a/embassy-stm32/src/rcc/wl5x/mod.rs
+++ /dev/null
@@ -1,236 +0,0 @@
1use crate::pac;
2use crate::peripherals::{self, RCC};
3use crate::rcc::{get_freqs, set_freqs, Clocks};
4use crate::time::U32Ext;
5use core::marker::PhantomData;
6use embassy::util::Unborrow;
7use embassy_hal_common::unborrow;
8
9/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
10/// and with the addition of the init function to configure a system clock.
11
12/// Only the basic setup using the HSE and HSI clocks are supported as of now.
13
14/// HSI speed
15pub const HSI_FREQ: u32 = 16_000_000;
16
17pub const HSE32_FREQ: u32 = 32_000_000;
18
19/// System clock mux source
20#[derive(Clone, Copy)]
21pub enum ClockSrc {
22 HSE32,
23 HSI16,
24}
25
26/// AHB prescaler
27#[derive(Clone, Copy, PartialEq)]
28pub enum AHBPrescaler {
29 NotDivided,
30 Div2,
31 Div3,
32 Div4,
33 Div5,
34 Div6,
35 Div8,
36 Div10,
37 Div16,
38 Div32,
39 Div64,
40 Div128,
41 Div256,
42 Div512,
43}
44
45/// APB prescaler
46#[derive(Clone, Copy)]
47pub enum APBPrescaler {
48 NotDivided,
49 Div2,
50 Div4,
51 Div8,
52 Div16,
53}
54
55impl Into<u8> for APBPrescaler {
56 fn into(self) -> u8 {
57 match self {
58 APBPrescaler::NotDivided => 1,
59 APBPrescaler::Div2 => 0x04,
60 APBPrescaler::Div4 => 0x05,
61 APBPrescaler::Div8 => 0x06,
62 APBPrescaler::Div16 => 0x07,
63 }
64 }
65}
66
67impl Into<u8> for AHBPrescaler {
68 fn into(self) -> u8 {
69 match self {
70 AHBPrescaler::NotDivided => 1,
71 AHBPrescaler::Div2 => 0x08,
72 AHBPrescaler::Div3 => 0x01,
73 AHBPrescaler::Div4 => 0x09,
74 AHBPrescaler::Div5 => 0x02,
75 AHBPrescaler::Div6 => 0x05,
76 AHBPrescaler::Div8 => 0x0a,
77 AHBPrescaler::Div10 => 0x06,
78 AHBPrescaler::Div16 => 0x0b,
79 AHBPrescaler::Div32 => 0x07,
80 AHBPrescaler::Div64 => 0x0c,
81 AHBPrescaler::Div128 => 0x0d,
82 AHBPrescaler::Div256 => 0x0e,
83 AHBPrescaler::Div512 => 0x0f,
84 }
85 }
86}
87
88/// Clocks configutation
89pub struct Config {
90 pub mux: ClockSrc,
91 pub ahb_pre: AHBPrescaler,
92 pub apb1_pre: APBPrescaler,
93 pub apb2_pre: APBPrescaler,
94}
95
96impl Default for Config {
97 #[inline]
98 fn default() -> Config {
99 Config {
100 mux: ClockSrc::HSI16,
101 ahb_pre: AHBPrescaler::NotDivided,
102 apb1_pre: APBPrescaler::NotDivided,
103 apb2_pre: APBPrescaler::NotDivided,
104 }
105 }
106}
107
108/// RCC peripheral
109pub struct Rcc<'d> {
110 _rb: peripherals::RCC,
111 phantom: PhantomData<&'d mut peripherals::RCC>,
112}
113
114impl<'d> Rcc<'d> {
115 pub fn new(rcc: impl Unborrow<Target = peripherals::RCC> + 'd) -> Self {
116 unborrow!(rcc);
117 Self {
118 _rb: rcc,
119 phantom: PhantomData,
120 }
121 }
122
123 pub fn enable_lsi(&mut self) {
124 let rcc = pac::RCC;
125 unsafe {
126 let csr = rcc.csr().read();
127 if !csr.lsion() {
128 rcc.csr().modify(|w| w.set_lsion(true));
129 while !rcc.csr().read().lsirdy() {}
130 }
131 }
132 }
133
134 // Safety: RCC init must have been called
135 pub fn clocks(&self) -> &'static Clocks {
136 unsafe { get_freqs() }
137 }
138}
139
140/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
141pub trait RccExt {
142 fn freeze(self, config: Config) -> Clocks;
143}
144
145impl RccExt for RCC {
146 #[inline]
147 fn freeze(self, cfgr: Config) -> Clocks {
148 let rcc = pac::RCC;
149 let (sys_clk, sw) = match cfgr.mux {
150 ClockSrc::HSI16 => {
151 // Enable HSI16
152 unsafe {
153 rcc.cr().write(|w| w.set_hsion(true));
154 while !rcc.cr().read().hsirdy() {}
155 }
156
157 (HSI_FREQ, 0x01)
158 }
159 ClockSrc::HSE32 => {
160 // Enable HSE32
161 unsafe {
162 rcc.cr().write(|w| {
163 w.set_hsebyppwr(true);
164 w.set_hseon(true);
165 });
166 while !rcc.cr().read().hserdy() {}
167 }
168
169 (HSE32_FREQ, 0x02)
170 }
171 };
172
173 unsafe {
174 rcc.cfgr().modify(|w| {
175 w.set_sw(sw.into());
176 if cfgr.ahb_pre == AHBPrescaler::NotDivided {
177 w.set_hpre(0);
178 } else {
179 w.set_hpre(cfgr.ahb_pre.into());
180 }
181 w.set_ppre1(cfgr.apb1_pre.into());
182 w.set_ppre2(cfgr.apb2_pre.into());
183 });
184 }
185
186 let ahb_freq: u32 = match cfgr.ahb_pre {
187 AHBPrescaler::NotDivided => sys_clk,
188 pre => {
189 let pre: u8 = pre.into();
190 let pre = 1 << (pre as u32 - 7);
191 sys_clk / pre
192 }
193 };
194
195 let (apb1_freq, apb1_tim_freq) = match cfgr.apb1_pre {
196 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
197 pre => {
198 let pre: u8 = pre.into();
199 let pre: u8 = 1 << (pre - 3);
200 let freq = ahb_freq / pre as u32;
201 (freq, freq * 2)
202 }
203 };
204
205 let (apb2_freq, apb2_tim_freq) = match cfgr.apb2_pre {
206 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
207 pre => {
208 let pre: u8 = pre.into();
209 let pre: u8 = 1 << (pre - 3);
210 let freq = ahb_freq / (1 << (pre as u8 - 3));
211 (freq, freq * 2)
212 }
213 };
214
215 // TODO: completely untested
216 let apb3_freq = ahb_freq;
217
218 Clocks {
219 sys: sys_clk.hz(),
220 ahb1: ahb_freq.hz(),
221 ahb2: ahb_freq.hz(),
222 ahb3: ahb_freq.hz(),
223 apb1: apb1_freq.hz(),
224 apb2: apb2_freq.hz(),
225 apb3: apb3_freq.hz(),
226 apb1_tim: apb1_tim_freq.hz(),
227 apb2_tim: apb2_tim_freq.hz(),
228 }
229 }
230}
231
232pub unsafe fn init(config: Config) {
233 let r = <peripherals::RCC as embassy::util::Steal>::steal();
234 let clocks = r.freeze(config);
235 set_freqs(clocks);
236}
diff --git a/examples/stm32l0/src/bin/button_exti.rs b/examples/stm32l0/src/bin/button_exti.rs
index 20d6f5555..88c75ce6d 100644
--- a/examples/stm32l0/src/bin/button_exti.rs
+++ b/examples/stm32l0/src/bin/button_exti.rs
@@ -8,16 +8,18 @@ mod example_common;
8use embassy::executor::Spawner; 8use embassy::executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::gpio::{Input, Pull}; 10use embassy_stm32::gpio::{Input, Pull};
11use embassy_stm32::{rcc, Peripherals}; 11use embassy_stm32::Peripherals;
12use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; 12use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
13use example_common::*; 13use example_common::*;
14 14
15#[embassy::main] 15fn config() -> embassy_stm32::Config {
16async fn main(_spawner: Spawner, mut p: Peripherals) { 16 let mut config = embassy_stm32::Config::default();
17 let mut rcc = rcc::Rcc::new(p.RCC); 17 config.rcc.enable_hsi48 = true;
18 // Enables SYSCFG 18 config
19 let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS); 19}
20 20
21#[embassy::main(config = "config()")]
22async fn main(_spawner: Spawner, p: Peripherals) {
21 let button = Input::new(p.PB2, Pull::Up); 23 let button = Input::new(p.PB2, Pull::Up);
22 let mut button = ExtiInput::new(button, p.EXTI2); 24 let mut button = ExtiInput::new(button, p.EXTI2);
23 25
diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs
index 7ce859a8d..df08ba18c 100644
--- a/examples/stm32l0/src/bin/lorawan.rs
+++ b/examples/stm32l0/src/bin/lorawan.rs
@@ -11,10 +11,8 @@ mod example_common;
11 11
12use embassy_lora::{sx127x::*, LoraTimer}; 12use embassy_lora::{sx127x::*, LoraTimer};
13use embassy_stm32::{ 13use embassy_stm32::{
14 dbgmcu::Dbgmcu,
15 exti::ExtiInput, 14 exti::ExtiInput,
16 gpio::{Input, Level, Output, Pull, Speed}, 15 gpio::{Input, Level, Output, Pull, Speed},
17 rcc,
18 rng::Rng, 16 rng::Rng,
19 spi, 17 spi,
20 time::U32Ext, 18 time::U32Ext,
@@ -26,18 +24,12 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto;
26fn config() -> embassy_stm32::Config { 24fn config() -> embassy_stm32::Config {
27 let mut config = embassy_stm32::Config::default(); 25 let mut config = embassy_stm32::Config::default();
28 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; 26 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
27 config.rcc.enable_hsi48 = true;
29 config 28 config
30} 29}
31 30
32#[embassy::main(config = "config()")] 31#[embassy::main(config = "config()")]
33async fn main(_spawner: embassy::executor::Spawner, mut p: Peripherals) { 32async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
34 unsafe {
35 Dbgmcu::enable_all();
36 }
37
38 let mut rcc = rcc::Rcc::new(p.RCC);
39 let _ = rcc.enable_hsi48(&mut p.SYSCFG, p.CRS);
40
41 // SPI for sx127x 33 // SPI for sx127x
42 let spi = spi::Spi::new( 34 let spi = spi::Spi::new(
43 p.SPI1, 35 p.SPI1,
diff --git a/examples/stm32wl55/src/bin/lorawan.rs b/examples/stm32wl55/src/bin/lorawan.rs
index 7048a5814..5d26dead2 100644
--- a/examples/stm32wl55/src/bin/lorawan.rs
+++ b/examples/stm32wl55/src/bin/lorawan.rs
@@ -10,10 +10,9 @@ mod example_common;
10 10
11use embassy_lora::{stm32wl::*, LoraTimer}; 11use embassy_lora::{stm32wl::*, LoraTimer};
12use embassy_stm32::{ 12use embassy_stm32::{
13 dbgmcu::Dbgmcu,
14 dma::NoDma, 13 dma::NoDma,
15 gpio::{Level, Output, Pin, Speed}, 14 gpio::{Level, Output, Pin, Speed},
16 interrupt, pac, rcc, 15 interrupt, pac,
17 rng::Rng, 16 rng::Rng,
18 subghz::*, 17 subghz::*,
19 Peripherals, 18 Peripherals,
@@ -24,19 +23,13 @@ use lorawan_encoding::default_crypto::DefaultFactory as Crypto;
24fn config() -> embassy_stm32::Config { 23fn config() -> embassy_stm32::Config {
25 let mut config = embassy_stm32::Config::default(); 24 let mut config = embassy_stm32::Config::default();
26 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16; 25 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
26 config.rcc.enable_lsi = true;
27 config 27 config
28} 28}
29 29
30#[embassy::main(config = "config()")] 30#[embassy::main(config = "config()")]
31async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { 31async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
32 unsafe { 32 unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) }
33 Dbgmcu::enable_all();
34 let mut rcc = rcc::Rcc::new(p.RCC);
35 rcc.enable_lsi();
36 pac::RCC.ccipr().modify(|w| {
37 w.set_rngsel(0b01);
38 });
39 }
40 33
41 let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High); 34 let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
42 let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High); 35 let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High);
diff --git a/examples/stm32wl55/src/bin/subghz.rs b/examples/stm32wl55/src/bin/subghz.rs
index a73c361c2..52fe6e9fa 100644
--- a/examples/stm32wl55/src/bin/subghz.rs
+++ b/examples/stm32wl55/src/bin/subghz.rs
@@ -11,7 +11,6 @@ mod example_common;
11use embassy::channel::signal::Signal; 11use embassy::channel::signal::Signal;
12use embassy::interrupt::{Interrupt, InterruptExt}; 12use embassy::interrupt::{Interrupt, InterruptExt};
13use embassy::traits::gpio::WaitForRisingEdge; 13use embassy::traits::gpio::WaitForRisingEdge;
14use embassy_stm32::dbgmcu::Dbgmcu;
15use embassy_stm32::dma::NoDma; 14use embassy_stm32::dma::NoDma;
16use embassy_stm32::exti::ExtiInput; 15use embassy_stm32::exti::ExtiInput;
17use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 16use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
@@ -72,10 +71,6 @@ fn config() -> embassy_stm32::Config {
72 71
73#[embassy::main(config = "config()")] 72#[embassy::main(config = "config()")]
74async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) { 73async fn main(_spawner: embassy::executor::Spawner, p: Peripherals) {
75 unsafe {
76 Dbgmcu::enable_all();
77 }
78
79 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); 74 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
80 let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low); 75 let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low);
81 let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low); 76 let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low);
diff --git a/stm32-data b/stm32-data
Subproject 27f9d6dc2c5afaa5003ce9afc06def9b16d30ad Subproject 3fa97966f07d43a28c0031175591e1c2ff5d083
diff --git a/tests/stm32/link_ram.x b/tests/stm32/link_ram.x
index d23ffc747..26da86baa 100644
--- a/tests/stm32/link_ram.x
+++ b/tests/stm32/link_ram.x
@@ -125,6 +125,7 @@ SECTIONS
125 { 125 {
126 . = ALIGN(4); 126 . = ALIGN(4);
127 __sdata = .; 127 __sdata = .;
128 __edata = .;
128 *(.data .data.*); 129 *(.data .data.*);
129 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ 130 . = ALIGN(4); /* 4-byte align the end (VMA) of this section */
130 } > RAM 131 } > RAM
@@ -132,7 +133,6 @@ SECTIONS
132 * use the .data loading mechanism by pushing __edata. Note: do not change 133 * use the .data loading mechanism by pushing __edata. Note: do not change
133 * output region or load region in those user sections! */ 134 * output region or load region in those user sections! */
134 . = ALIGN(4); 135 . = ALIGN(4);
135 __edata = .;
136 136
137 /* LMA of .data */ 137 /* LMA of .data */
138 __sidata = LOADADDR(.data); 138 __sidata = LOADADDR(.data);