diff options
| author | everdrone <[email protected]> | 2025-09-24 14:02:34 +0200 |
|---|---|---|
| committer | everdrone <[email protected]> | 2025-09-24 14:02:34 +0200 |
| commit | bbb2a1ca5359f4a31c91aed9fe5fa347bef4d3f1 (patch) | |
| tree | dd0dbbb6be3930526c3a01e6281a91aa78eb2447 /embassy-stm32 | |
| parent | ea4e7bc3d23c3deb44fa6029f70ddcd72dfa4d35 (diff) | |
Add clock initialization to N6
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/rcc/n6.rs | 222 |
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 @@ | |||
| 1 | use stm32_metapac::rcc::vals::{Cpusws, Hseext, Hsitrim, Pllsel, Syssws}; | ||
| 2 | pub use stm32_metapac::rcc::vals::{Hsidiv as HsiPrescaler, Hsitrim as HsiCalibration, Syssw as Sysclk}; | ||
| 3 | |||
| 4 | use crate::pac::{PWR, RCC, SYSCFG}; | ||
| 5 | use crate::time::Hertz; | ||
| 6 | |||
| 7 | pub const HSI_FREQ: Hertz = Hertz(64_000_000); | ||
| 8 | |||
| 9 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 10 | pub 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)] | ||
| 20 | pub 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)] | ||
| 28 | pub struct Hsi { | ||
| 29 | pub pre: HsiPrescaler, | ||
| 30 | pub calib: Hsitrim, | ||
| 31 | } | ||
| 32 | |||
| 33 | #[derive(Clone, Copy, PartialEq)] | ||
| 34 | pub 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)] |
| 4 | pub struct Config {} | 42 | pub 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 | ||
| 6 | impl Config { | 50 | impl 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 | ||
| 68 | fn 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 | |||
| 81 | fn 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 | |||
| 18 | pub(crate) unsafe fn init(config: Config) { | 173 | pub(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 | } |
