aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreverdrone <[email protected]>2025-09-24 14:02:34 +0200
committereverdrone <[email protected]>2025-09-24 14:02:34 +0200
commitbbb2a1ca5359f4a31c91aed9fe5fa347bef4d3f1 (patch)
treedd0dbbb6be3930526c3a01e6281a91aa78eb2447
parentea4e7bc3d23c3deb44fa6029f70ddcd72dfa4d35 (diff)
Add clock initialization to N6
-rw-r--r--embassy-stm32/src/rcc/n6.rs222
1 files changed, 219 insertions, 3 deletions
diff --git a/embassy-stm32/src/rcc/n6.rs b/embassy-stm32/src/rcc/n6.rs
index 68627edfd..c8dae6303 100644
--- a/embassy-stm32/src/rcc/n6.rs
+++ b/embassy-stm32/src/rcc/n6.rs
@@ -1,11 +1,61 @@
1use stm32_metapac::rcc::vals::{Cpusws, Hseext, Hsitrim, Pllsel, Syssws};
2pub use stm32_metapac::rcc::vals::{Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Syssw as Sysclk};
3
4use crate::pac::{PWR, RCC, SYSCFG};
5use crate::time::Hertz;
6
7pub const HSI_FREQ: Hertz = Hertz(64_000_000);
8
9#[derive(Clone, Copy, Eq, PartialEq)]
10pub enum HseMode {
11 /// crystal/ceramic oscillator
12 Oscillator,
13 /// oscillator bypassed with external clock (analog)
14 Bypass,
15 /// oscillator bypassed with external digital clock
16 BypassDigital,
17}
18
19#[derive(Clone, Copy, Eq, PartialEq)]
20pub struct Hse {
21 /// HSE frequency.
22 pub freq: Hertz,
23 /// HSE oscillator mode.
24 pub mode: HseMode,
25}
26
27#[derive(Clone, Copy, Eq, PartialEq)]
28pub struct Hsi {
29 pub pre: HsiPrescaler,
30 pub calib: Hsitrim,
31}
32
33#[derive(Clone, Copy, PartialEq)]
34pub enum SupplyConfig {
35 Smps,
36 External,
37}
38
1/// Configuration of the core clocks 39/// Configuration of the core clocks
2#[non_exhaustive] 40#[non_exhaustive]
3#[derive(Clone, Copy)] 41#[derive(Clone, Copy)]
4pub struct Config {} 42pub struct Config {
43 pub hsi: Option<Hsi>,
44 pub hse: Option<Hse>,
45 pub sys: Sysclk,
46
47 pub supply_config: SupplyConfig,
48}
5 49
6impl Config { 50impl Config {
7 pub const fn new() -> Self { 51 pub const fn new() -> Self {
8 Self {} 52 Self {
53 hsi: None,
54 hse: None,
55 sys: Sysclk::HSI,
56
57 supply_config: SupplyConfig::Smps,
58 }
9 } 59 }
10} 60}
11 61
@@ -15,6 +65,172 @@ impl Default for Config {
15 } 65 }
16} 66}
17 67
68fn power_supply_config(supply_config: SupplyConfig) {
69 // power supply config
70 PWR.cr1().modify(|w| {
71 w.set_sden(match supply_config {
72 SupplyConfig::External => false,
73 SupplyConfig::Smps => true,
74 });
75 });
76
77 // Validate supply configuration
78 while !PWR.voscr().read().actvosrdy() {}
79}
80
81fn osc_config(config: Config) -> (Option<Hertz>, Option<Hertz>) {
82 let (cpu_clk_src, sys_clk_src) = {
83 let cfgr = RCC.cfgr().read();
84 (cfgr.cpusws(), cfgr.syssws())
85 };
86 let pll1_clk_src = RCC.pll1cfgr1().read().pllsel();
87 let pll2_clk_src = RCC.pll2cfgr1().read().pllsel();
88 let pll3_clk_src = RCC.pll3cfgr1().read().pllsel();
89 let pll4_clk_src = RCC.pll4cfgr1().read().pllsel();
90 let sr = RCC.sr().read();
91
92 let hsi = match config.hsi {
93 None => {
94 if (cpu_clk_src == Cpusws::HSI || sys_clk_src == Syssws::HSI)
95 || (pll1_clk_src == Pllsel::HSI && sr.pllrdy(0))
96 || (pll2_clk_src == Pllsel::HSI && sr.pllrdy(1))
97 || (pll3_clk_src == Pllsel::HSI && sr.pllrdy(2))
98 || (pll4_clk_src == Pllsel::HSI && sr.pllrdy(3))
99 {
100 if config.hse.is_none() {
101 panic!("When the HSI is used as CPU or system bus clock source, it is not allowed to be disabled");
102 }
103 } else {
104 // disable the HSI
105 RCC.ccr().write(|w| w.set_hsionc(true));
106 // wait until HSI is disabled
107 while RCC.sr().read().hsirdy() {}
108 }
109
110 None
111 }
112 Some(hsi_config) => {
113 RCC.hsicfgr().modify(|w| {
114 w.set_hsidiv(hsi_config.pre);
115 w.set_hsitrim(hsi_config.calib);
116 });
117 Some(HSI_FREQ / hsi_config.pre)
118 }
119 };
120
121 let hse = match config.hse {
122 None => {
123 if ((cpu_clk_src == Cpusws::HSE || sys_clk_src == Syssws::HSE)
124 || (pll1_clk_src == Pllsel::HSE && sr.pllrdy(0))
125 || (pll2_clk_src == Pllsel::HSE && sr.pllrdy(1))
126 || (pll3_clk_src == Pllsel::HSE && sr.pllrdy(2))
127 || (pll4_clk_src == Pllsel::HSE && sr.pllrdy(3)))
128 && config.hse.is_none()
129 {
130 panic!("When the HSE is used as CPU or system bus clock source, it is not allowed to be disabled");
131 }
132
133 // hse off
134 RCC.csr().modify(|w| w.set_hseons(false));
135 RCC.hsecfgr().modify(|w| {
136 w.set_hseext(Hseext::ANALOG);
137 w.set_hsebyp(false);
138 });
139
140 // wait until hse is off
141 while RCC.sr().read().hserdy() {}
142
143 None
144 }
145 Some(hse_config) => {
146 match hse_config.mode {
147 HseMode::Oscillator => RCC.csr().modify(|w| w.set_hseons(true)),
148 HseMode::Bypass => {
149 RCC.hsecfgr().modify(|w| {
150 w.set_hsebyp(true);
151 w.set_hseext(Hseext::ANALOG);
152 });
153 RCC.csr().modify(|w| w.set_hseons(true));
154 }
155 HseMode::BypassDigital => {
156 RCC.hsecfgr().modify(|w| {
157 w.set_hsebyp(true);
158 w.set_hseext(Hseext::DIGITAL)
159 });
160 }
161 };
162
163 // wait until the hse is ready
164 while !RCC.sr().read().hserdy() {}
165
166 Some(hse_config.freq)
167 }
168 };
169
170 (hsi, hse)
171}
172
18pub(crate) unsafe fn init(config: Config) { 173pub(crate) unsafe fn init(config: Config) {
19 todo!() 174 // system configuration setup
175 RCC.apb4hensr().write(|w| w.set_syscfgens(true));
176 // delay after RCC peripheral clock enabling
177 core::ptr::read_volatile(RCC.apb4hensr().as_ptr());
178
179 let vtor = unsafe {
180 let p = cortex_m::Peripherals::steal();
181 p.SCB.vtor.read()
182 };
183
184 // set default vector table location after reset or standby
185 SYSCFG.initsvtorcr().write(|w| w.set_svtor_addr(vtor));
186 // read back the value to ensure it is written before deactivating SYSCFG
187 core::ptr::read_volatile(SYSCFG.initsvtorcr().as_ptr());
188
189 // deactivate SYSCFG
190 RCC.apb4hensr().write(|w| w.set_syscfgens(false));
191
192 // enable fpu
193 unsafe {
194 let p = cortex_m::Peripherals::steal();
195 p.SCB.cpacr.modify(|w| w | (3 << 20) | (3 << 22));
196 }
197
198 power_supply_config(config.supply_config);
199
200 let (hsi, hse) = osc_config(config);
201
202 let sys = match config.sys {
203 Sysclk::HSE => unwrap!(hse),
204 Sysclk::HSI => unwrap!(hsi),
205 Sysclk::MSI => todo!(),
206 Sysclk::IC2 => todo!(),
207 };
208
209 // TODO: sysb, sysc, sysd must have the same clock source
210
211 set_clocks!(
212 sys: Some(sys),
213 hsi: hsi,
214 hsi_div: None,
215 hse: hse,
216 hclk1: None,
217 hclk2: None,
218 hclk3: None,
219 hclk4: None,
220 hclk5: None,
221 pclk1: None,
222 pclk2: None,
223 pclk2_tim: None,
224 pclk4: None,
225 pclk5: None,
226 per: None,
227 rtc: None,
228 msi: None,
229 i2s_ckin: None,
230 ic8: None,
231 ic9: None,
232 ic14: None,
233 ic17: None,
234 ic20: None,
235 );
20} 236}