aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-03-04 00:26:21 +0100
committerGitHub <[email protected]>2024-03-04 00:26:21 +0100
commit02a0a15976ca815924a3780f80a7f28b90717a2b (patch)
tree66fa6a524c6ce25b0f883639c40dc1a64c24a047
parent20760ff4f7dcbca8b1654957462df4551883932d (diff)
parentae266f3bf528c334c4712cd37305d2bcb71c0936 (diff)
Merge pull request #2656 from embassy-rs/rcc-gc0
stm32/rcc: port g0, c0 to new api. Add c0 HSIKER/HSISYS support.
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/rcc/c0.rs224
-rw-r--r--embassy-stm32/src/rcc/g0.rs482
-rw-r--r--embassy-stm32/src/rcc/g4.rs218
-rw-r--r--examples/stm32g0/src/bin/hf_timer.rs15
-rw-r--r--examples/stm32g4/src/bin/adc.rs2
-rw-r--r--examples/stm32g4/src/bin/can.rs2
-rw-r--r--examples/stm32g4/src/bin/pll.rs29
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs2
-rw-r--r--tests/stm32/src/common.rs26
10 files changed, 520 insertions, 484 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 4bbd43c47..b326c26fd 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,7 @@ rand_core = "0.6.3"
70sdio-host = "0.5.0" 70sdio-host = "0.5.0"
71critical-section = "1.1" 71critical-section = "1.1"
72#stm32-metapac = { version = "15" } 72#stm32-metapac = { version = "15" }
73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085" }
74vcell = "0.1.3" 74vcell = "0.1.3"
75bxcan = "0.7.0" 75bxcan = "0.7.0"
76nb = "1.0.0" 76nb = "1.0.0"
@@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
94proc-macro2 = "1.0.36" 94proc-macro2 = "1.0.36"
95quote = "1.0.15" 95quote = "1.0.15"
96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]} 97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e7f91751fbbf856e0cb30e50ae6db79f0409b085", default-features = false, features = ["metadata"]}
98 98
99 99
100[features] 100[features]
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 1946c5a15..7ca737bf0 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -1,25 +1,56 @@
1use crate::pac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::Sw; 2pub use crate::pac::rcc::vals::{
3pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler}; 3 Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Hsikerdiv as HsiKerDiv, Ppre as APBPrescaler, Sw as Sysclk,
4};
4use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
5use crate::time::Hertz; 6use crate::time::Hertz;
6 7
7/// HSI speed 8/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(48_000_000); 9pub const HSI_FREQ: Hertz = Hertz(16_000_000);
9 10
10/// System clock mux source 11/// HSE Mode
11#[derive(Clone, Copy)] 12#[derive(Clone, Copy, Eq, PartialEq)]
12pub enum Sysclk { 13pub enum HseMode {
13 HSE(Hertz), 14 /// crystal/ceramic oscillator (HSEBYP=0)
14 HSI(HSIPrescaler), 15 Oscillator,
15 LSI, 16 /// external analog clock (low swing) (HSEBYP=1)
17 Bypass,
18}
19
20/// HSE Configuration
21#[derive(Clone, Copy, Eq, PartialEq)]
22pub struct Hse {
23 /// HSE frequency.
24 pub freq: Hertz,
25 /// HSE mode.
26 pub mode: HseMode,
27}
28
29/// HSI Configuration
30#[derive(Clone, Copy, Eq, PartialEq)]
31pub struct Hsi {
32 /// Division factor for HSISYS clock. Default is 4.
33 pub sys_div: HsiSysDiv,
34 /// Division factor for HSIKER clock. Default is 3.
35 pub ker_div: HsiKerDiv,
16} 36}
17 37
18/// Clocks configutation 38/// Clocks configutation
39#[non_exhaustive]
19pub struct Config { 40pub struct Config {
41 /// HSI Configuration
42 pub hsi: Option<Hsi>,
43
44 /// HSE Configuration
45 pub hse: Option<Hse>,
46
47 /// System Clock Configuration
20 pub sys: Sysclk, 48 pub sys: Sysclk,
49
21 pub ahb_pre: AHBPrescaler, 50 pub ahb_pre: AHBPrescaler,
22 pub apb_pre: APBPrescaler, 51 pub apb1_pre: APBPrescaler,
52
53 /// Low-Speed Clock Configuration
23 pub ls: super::LsConfig, 54 pub ls: super::LsConfig,
24 55
25 /// Per-peripheral kernel clock selection muxes 56 /// Per-peripheral kernel clock selection muxes
@@ -30,9 +61,14 @@ impl Default for Config {
30 #[inline] 61 #[inline]
31 fn default() -> Config { 62 fn default() -> Config {
32 Config { 63 Config {
33 sys: Sysclk::HSI(HSIPrescaler::DIV1), 64 hsi: Some(Hsi {
65 sys_div: HsiSysDiv::DIV4,
66 ker_div: HsiKerDiv::DIV3,
67 }),
68 hse: None,
69 sys: Sysclk::HSISYS,
34 ahb_pre: AHBPrescaler::DIV1, 70 ahb_pre: AHBPrescaler::DIV1,
35 apb_pre: APBPrescaler::DIV1, 71 apb1_pre: APBPrescaler::DIV1,
36 ls: Default::default(), 72 ls: Default::default(),
37 mux: Default::default(), 73 mux: Default::default(),
38 } 74 }
@@ -40,111 +76,109 @@ impl Default for Config {
40} 76}
41 77
42pub(crate) unsafe fn init(config: Config) { 78pub(crate) unsafe fn init(config: Config) {
43 let (sys_clk, sw) = match config.sys { 79 // Configure HSI
44 Sysclk::HSI(div) => { 80 let (hsi, hsisys, hsiker) = match config.hsi {
45 // Enable HSI 81 None => {
46 RCC.cr().write(|w| { 82 RCC.cr().modify(|w| w.set_hsion(false));
47 w.set_hsidiv(div); 83 (None, None, None)
48 w.set_hsion(true) 84 }
85 Some(hsi) => {
86 RCC.cr().modify(|w| {
87 w.set_hsidiv(hsi.sys_div);
88 w.set_hsikerdiv(hsi.ker_div);
89 w.set_hsion(true);
49 }); 90 });
50 while !RCC.cr().read().hsirdy() {} 91 while !RCC.cr().read().hsirdy() {}
51 92 (
52 (HSI_FREQ / div, Sw::HSI) 93 Some(HSI_FREQ),
94 Some(HSI_FREQ / hsi.sys_div),
95 Some(HSI_FREQ / hsi.ker_div),
96 )
53 } 97 }
54 Sysclk::HSE(freq) => { 98 };
55 // Enable HSE
56 RCC.cr().write(|w| w.set_hseon(true));
57 while !RCC.cr().read().hserdy() {}
58 99
59 (freq, Sw::HSE) 100 // Configure HSE
101 let hse = match config.hse {
102 None => {
103 RCC.cr().modify(|w| w.set_hseon(false));
104 None
60 } 105 }
61 Sysclk::LSI => { 106 Some(hse) => {
62 // Enable LSI 107 match hse.mode {
63 RCC.csr2().write(|w| w.set_lsion(true)); 108 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
64 while !RCC.csr2().read().lsirdy() {} 109 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
65 (super::LSI_FREQ, Sw::LSI) 110 }
111
112 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
113 RCC.cr().modify(|w| w.set_hseon(true));
114 while !RCC.cr().read().hserdy() {}
115 Some(hse.freq)
66 } 116 }
67 }; 117 };
68 118
69 let rtc = config.ls.init(); 119 let sys = match config.sys {
120 Sysclk::HSISYS => unwrap!(hsisys),
121 Sysclk::HSE => unwrap!(hse),
122 _ => unreachable!(),
123 };
70 124
71 // Determine the flash latency implied by the target clock speed 125 assert!(max::SYSCLK.contains(&sys));
72 // RM0454 § 3.3.4: 126
73 let target_flash_latency = if sys_clk <= Hertz(24_000_000) { 127 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
74 Latency::WS0 128 let hclk = sys / config.ahb_pre;
75 } else { 129 assert!(max::HCLK.contains(&hclk));
76 Latency::WS1 130
131 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
132 assert!(max::PCLK.contains(&pclk1));
133
134 let latency = match hclk.0 {
135 ..=24_000_000 => Latency::WS0,
136 _ => Latency::WS1,
77 }; 137 };
78 138
79 // Increase the number of cycles we wait for flash if the new value is higher 139 // Configure flash read access latency based on voltage scale and frequency
80 // There's no harm in waiting a little too much before the clock change, but we'll
81 // crash immediately if we don't wait enough after the clock change
82 let mut set_flash_latency_after = false;
83 FLASH.acr().modify(|w| { 140 FLASH.acr().modify(|w| {
84 // Is the current flash latency less than what we need at the new SYSCLK? 141 w.set_latency(latency);
85 if w.latency().to_bits() <= target_flash_latency.to_bits() {
86 // We must increase the number of wait states now
87 w.set_latency(target_flash_latency)
88 } else {
89 // We may decrease the number of wait states later
90 set_flash_latency_after = true;
91 }
92
93 // RM0490 § 3.3.4:
94 // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register
95 // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the
96 // > Flash memory.
97 //
98 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
99 w.set_prften(target_flash_latency.to_bits() > 0);
100 }); 142 });
101 143
102 if !set_flash_latency_after { 144 // Spin until the effective flash latency is set.
103 // Spin until the effective flash latency is compatible with the clock change 145 while FLASH.acr().read().latency() != latency {}
104 while FLASH.acr().read().latency() < target_flash_latency {}
105 }
106 146
107 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 147 // Now that boost mode and flash read access latency are configured, set up SYSCLK
108 RCC.cfgr().modify(|w| { 148 RCC.cfgr().modify(|w| {
109 w.set_sw(sw); 149 w.set_sw(config.sys);
110 w.set_hpre(config.ahb_pre); 150 w.set_hpre(config.ahb_pre);
111 w.set_ppre(config.apb_pre); 151 w.set_ppre(config.apb1_pre);
112 }); 152 });
113 // Spin until the SYSCLK changes have taken effect
114 loop {
115 let cfgr = RCC.cfgr().read();
116 if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre {
117 break;
118 }
119 }
120 153
121 // Set the flash latency to require fewer wait states 154 let rtc = config.ls.init();
122 if set_flash_latency_after {
123 FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
124 }
125
126 let ahb_freq = sys_clk / config.ahb_pre;
127
128 let (apb_freq, apb_tim_freq) = match config.apb_pre {
129 APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
130 pre => {
131 let freq = ahb_freq / pre;
132 (freq, freq * 2u32)
133 }
134 };
135 155
136 config.mux.init(); 156 config.mux.init();
137 157
138 // without this, the ringbuffered uart test fails.
139 cortex_m::asm::dsb();
140
141 set_clocks!( 158 set_clocks!(
142 hsi: None, 159 sys: Some(sys),
143 lse: None, 160 hclk1: Some(hclk),
144 sys: Some(sys_clk), 161 pclk1: Some(pclk1),
145 hclk1: Some(ahb_freq), 162 pclk1_tim: Some(pclk1_tim),
146 pclk1: Some(apb_freq), 163 hsi: hsi,
147 pclk1_tim: Some(apb_tim_freq), 164 hsiker: hsiker,
165 hse: hse,
148 rtc: rtc, 166 rtc: rtc,
167
168 // TODO
169 lsi: None,
170 lse: None,
149 ); 171 );
150} 172}
173
174mod max {
175 use core::ops::RangeInclusive;
176
177 use crate::time::Hertz;
178
179 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(48_000_000);
180 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
181 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
182 pub(crate) const PCLK: RangeInclusive<Hertz> = Hertz(8)..=Hertz(48_000_000);
183 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
184}
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index 5cfe9953b..ea4422ccc 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -1,7 +1,8 @@
1use crate::pac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use crate::pac::rcc::vals::{self, Sw}; 2pub use crate::pac::pwr::vals::Vos as VoltageRange;
3pub use crate::pac::rcc::vals::{ 3pub use crate::pac::rcc::vals::{
4 Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler, 4 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
5 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
5}; 6};
6use crate::pac::{FLASH, PWR, RCC}; 7use crate::pac::{FLASH, PWR, RCC};
7use crate::time::Hertz; 8use crate::time::Hertz;
@@ -9,6 +10,7 @@ use crate::time::Hertz;
9/// HSI speed 10/// HSI speed
10pub const HSI_FREQ: Hertz = Hertz(16_000_000); 11pub const HSI_FREQ: Hertz = Hertz(16_000_000);
11 12
13/// HSE Mode
12#[derive(Clone, Copy, Eq, PartialEq)] 14#[derive(Clone, Copy, Eq, PartialEq)]
13pub enum HseMode { 15pub enum HseMode {
14 /// crystal/ceramic oscillator (HSEBYP=0) 16 /// crystal/ceramic oscillator (HSEBYP=0)
@@ -17,69 +19,71 @@ pub enum HseMode {
17 Bypass, 19 Bypass,
18} 20}
19 21
20/// System clock mux source 22/// HSE Configuration
21#[derive(Clone, Copy)] 23#[derive(Clone, Copy, Eq, PartialEq)]
22pub enum Sysclk { 24pub struct Hse {
23 HSE(Hertz, HseMode), 25 /// HSE frequency.
24 HSI(HSIPrescaler), 26 pub freq: Hertz,
25 PLL(PllConfig), 27 /// HSE mode.
26 LSI, 28 pub mode: HseMode,
27} 29}
28 30
29/// The PLL configuration. 31/// PLL Configuration
30/// 32///
31/// * `VCOCLK = source / m * n` 33/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
32/// * `PLLRCLK = VCOCLK / r` 34/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
33/// * `PLLQCLK = VCOCLK / q` 35/// frequency ranges for each of these settings.
34/// * `PLLPCLK = VCOCLK / p` 36pub struct Pll {
35#[derive(Clone, Copy)] 37 /// PLL Source clock selection.
36pub struct PllConfig {
37 /// The source from which the PLL receives a clock signal
38 pub source: PllSource, 38 pub source: PllSource,
39 /// The initial divisor of that clock signal
40 pub m: Pllm,
41 /// The PLL VCO multiplier, which must be in the range `8..=86`.
42 pub n: Plln,
43 /// The final divisor for `PLLRCLK` output which drives the system clock
44 pub r: Pllr,
45
46 /// The divisor for the `PLLQCLK` output, if desired
47 pub q: Option<Pllq>,
48
49 /// The divisor for the `PLLPCLK` output, if desired
50 pub p: Option<Pllp>,
51}
52 39
53impl Default for PllConfig { 40 /// PLL pre-divider
54 #[inline] 41 pub prediv: PllPreDiv,
55 fn default() -> PllConfig {
56 // HSI / 1 * 8 / 2 = 64 MHz
57 PllConfig {
58 source: PllSource::HSI,
59 m: Pllm::DIV1,
60 n: Plln::MUL8,
61 r: Pllr::DIV2,
62 q: None,
63 p: None,
64 }
65 }
66}
67 42
68#[derive(Clone, Copy, Eq, PartialEq)] 43 /// PLL multiplication factor for VCO
69pub enum PllSource { 44 pub mul: PllMul,
70 HSI, 45
71 HSE(Hertz, HseMode), 46 /// PLL division factor for P clock (ADC Clock)
47 pub divp: Option<PllPDiv>,
48
49 /// PLL division factor for Q clock (USB, I2S23, SAI1, FDCAN, QSPI)
50 pub divq: Option<PllQDiv>,
51
52 /// PLL division factor for R clock (SYSCLK)
53 pub divr: Option<PllRDiv>,
72} 54}
73 55
74/// Clocks configutation 56/// Clocks configutation
57#[non_exhaustive]
75pub struct Config { 58pub struct Config {
59 /// HSI Enable
60 pub hsi: bool,
61
62 /// HSE Configuration
63 pub hse: Option<Hse>,
64
65 /// System Clock Configuration
76 pub sys: Sysclk, 66 pub sys: Sysclk,
77 pub ahb_pre: AHBPrescaler, 67
78 pub apb_pre: APBPrescaler, 68 /// HSI48 Configuration
79 pub low_power_run: bool,
80 pub ls: super::LsConfig,
81 #[cfg(crs)] 69 #[cfg(crs)]
82 pub hsi48: Option<super::Hsi48Config>, 70 pub hsi48: Option<super::Hsi48Config>,
71
72 /// PLL Configuration
73 pub pll: Option<Pll>,
74
75 /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration
76 /// MUST turn on the PLLR output.
77 pub ahb_pre: AHBPrescaler,
78 pub apb1_pre: APBPrescaler,
79
80 /// Low-Speed Clock Configuration
81 pub ls: super::LsConfig,
82
83 pub low_power_run: bool,
84
85 pub voltage_range: VoltageRange,
86
83 /// Per-peripheral kernel clock selection muxes 87 /// Per-peripheral kernel clock selection muxes
84 pub mux: super::mux::ClockMux, 88 pub mux: super::mux::ClockMux,
85} 89}
@@ -88,248 +92,218 @@ impl Default for Config {
88 #[inline] 92 #[inline]
89 fn default() -> Config { 93 fn default() -> Config {
90 Config { 94 Config {
91 sys: Sysclk::HSI(HSIPrescaler::DIV1), 95 hsi: true,
96 hse: None,
97 sys: Sysclk::HSI,
98 #[cfg(crs)]
99 hsi48: Some(Default::default()),
100 pll: None,
92 ahb_pre: AHBPrescaler::DIV1, 101 ahb_pre: AHBPrescaler::DIV1,
93 apb_pre: APBPrescaler::DIV1, 102 apb1_pre: APBPrescaler::DIV1,
94 low_power_run: false, 103 low_power_run: false,
95 ls: Default::default(), 104 ls: Default::default(),
96 #[cfg(crs)] 105 voltage_range: VoltageRange::RANGE1,
97 hsi48: Some(Default::default()),
98 mux: Default::default(), 106 mux: Default::default(),
99 } 107 }
100 } 108 }
101} 109}
102 110
103impl PllConfig { 111#[derive(Default)]
104 pub(crate) fn init(self) -> (Hertz, Option<Hertz>, Option<Hertz>) { 112pub struct PllFreq {
105 let (src, input_freq) = match self.source { 113 pub pll_p: Option<Hertz>,
106 PllSource::HSI => (vals::Pllsrc::HSI, HSI_FREQ), 114 pub pll_q: Option<Hertz>,
107 PllSource::HSE(freq, _) => (vals::Pllsrc::HSE, freq), 115 pub pll_r: Option<Hertz>,
108 };
109
110 let m_freq = input_freq / self.m;
111 // RM0454 § 5.4.4:
112 // > Caution: The software must set these bits so that the PLL input frequency after the
113 // > /M divider is between 2.66 and 16 MHz.
114 debug_assert!(m_freq.0 >= 2_660_000 && m_freq.0 <= 16_000_000);
115
116 let n_freq = m_freq * self.n as u32;
117 // RM0454 § 5.4.4:
118 // > Caution: The software must set these bits so that the VCO output frequency is between
119 // > 64 and 344 MHz.
120 debug_assert!(n_freq.0 >= 64_000_000 && n_freq.0 <= 344_000_000);
121
122 let r_freq = n_freq / self.r;
123 // RM0454 § 5.4.4:
124 // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock.
125 debug_assert!(r_freq.0 <= 64_000_000);
126
127 let q_freq = self.q.map(|q| n_freq / q);
128 let p_freq = self.p.map(|p| n_freq / p);
129
130 // RM0454 § 5.2.3:
131 // > To modify the PLL configuration, proceed as follows:
132 // > 1. Disable the PLL by setting PLLON to 0 in Clock control register (RCC_CR).
133 RCC.cr().modify(|w| w.set_pllon(false));
134
135 // > 2. Wait until PLLRDY is cleared. The PLL is now fully stopped.
136 while RCC.cr().read().pllrdy() {}
137
138 // > 3. Change the desired parameter.
139 // Enable whichever clock source we're using, and wait for it to become ready
140 match self.source {
141 PllSource::HSI => {
142 RCC.cr().write(|w| w.set_hsion(true));
143 while !RCC.cr().read().hsirdy() {}
144 }
145 PllSource::HSE(_, mode) => {
146 RCC.cr().write(|w| {
147 w.set_hsebyp(mode != HseMode::Oscillator);
148 w.set_hseon(true);
149 });
150 while !RCC.cr().read().hserdy() {}
151 }
152 }
153
154 // Configure PLLCFGR
155 RCC.pllcfgr().modify(|w| {
156 w.set_pllr(self.r);
157 w.set_pllren(false);
158 w.set_pllq(self.q.unwrap_or(Pllq::DIV2));
159 w.set_pllqen(false);
160 w.set_pllp(self.p.unwrap_or(Pllp::DIV2));
161 w.set_pllpen(false);
162 w.set_plln(self.n);
163 w.set_pllm(self.m);
164 w.set_pllsrc(src)
165 });
166
167 // > 4. Enable the PLL again by setting PLLON to 1.
168 RCC.cr().modify(|w| w.set_pllon(true));
169
170 // Wait for the PLL to become ready
171 while !RCC.cr().read().pllrdy() {}
172
173 // > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL
174 // > configuration register (RCC_PLLCFGR).
175 RCC.pllcfgr().modify(|w| {
176 // We'll use R for system clock, so enable that unconditionally
177 w.set_pllren(true);
178
179 // We may also use Q or P
180 w.set_pllqen(self.q.is_some());
181 w.set_pllpen(self.p.is_some());
182 });
183
184 (r_freq, q_freq, p_freq)
185 }
186} 116}
187 117
188pub(crate) unsafe fn init(config: Config) { 118pub(crate) unsafe fn init(config: Config) {
189 let mut pll1_q_freq = None; 119 // Configure HSI
190 let mut pll1_p_freq = None; 120 let hsi = match config.hsi {
191 121 false => {
192 let (sys_clk, sw) = match config.sys { 122 RCC.cr().modify(|w| w.set_hsion(false));
193 Sysclk::HSI(div) => { 123 None
194 // Enable HSI 124 }
195 RCC.cr().write(|w| { 125 true => {
196 w.set_hsidiv(div); 126 RCC.cr().modify(|w| w.set_hsion(true));
197 w.set_hsion(true)
198 });
199 while !RCC.cr().read().hsirdy() {} 127 while !RCC.cr().read().hsirdy() {}
200 128 Some(HSI_FREQ)
201 (HSI_FREQ / div, Sw::HSI)
202 } 129 }
203 Sysclk::HSE(freq, mode) => { 130 };
204 // Enable HSE
205 RCC.cr().write(|w| {
206 w.set_hseon(true);
207 w.set_hsebyp(mode != HseMode::Oscillator);
208 });
209 while !RCC.cr().read().hserdy() {}
210 131
211 (freq, Sw::HSE) 132 // Configure HSE
133 let hse = match config.hse {
134 None => {
135 RCC.cr().modify(|w| w.set_hseon(false));
136 None
212 } 137 }
213 Sysclk::PLL(pll) => { 138 Some(hse) => {
214 let (r_freq, q_freq, p_freq) = pll.init(); 139 match hse.mode {
215 140 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
216 pll1_q_freq = q_freq; 141 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
217 pll1_p_freq = p_freq; 142 }
218 143
219 (r_freq, Sw::PLL1_R) 144 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
220 } 145 RCC.cr().modify(|w| w.set_hseon(true));
221 Sysclk::LSI => { 146 while !RCC.cr().read().hserdy() {}
222 // Enable LSI 147 Some(hse.freq)
223 RCC.csr().write(|w| w.set_lsion(true));
224 while !RCC.csr().read().lsirdy() {}
225 (super::LSI_FREQ, Sw::LSI)
226 } 148 }
227 }; 149 };
228 150
229 // Determine the flash latency implied by the target clock speed 151 // Configure HSI48 if required
230 // RM0454 § 3.3.4: 152 #[cfg(crs)]
231 let target_flash_latency = if sys_clk.0 <= 24_000_000 { 153 let hsi48 = config.hsi48.map(super::init_hsi48);
232 Latency::WS0
233 } else if sys_clk.0 <= 48_000_000 {
234 Latency::WS1
235 } else {
236 Latency::WS2
237 };
238 154
239 // Increase the number of cycles we wait for flash if the new value is higher 155 let pll = config
240 // There's no harm in waiting a little too much before the clock change, but we'll 156 .pll
241 // crash immediately if we don't wait enough after the clock change 157 .map(|pll_config| {
242 let mut set_flash_latency_after = false; 158 let src_freq = match pll_config.source {
243 FLASH.acr().modify(|w| { 159 PllSource::HSI => unwrap!(hsi),
244 // Is the current flash latency less than what we need at the new SYSCLK? 160 PllSource::HSE => unwrap!(hse),
245 if w.latency().to_bits() <= target_flash_latency.to_bits() { 161 _ => unreachable!(),
246 // We must increase the number of wait states now 162 };
247 w.set_latency(target_flash_latency) 163
248 } else { 164 // Disable PLL before configuration
249 // We may decrease the number of wait states later 165 RCC.cr().modify(|w| w.set_pllon(false));
250 set_flash_latency_after = true; 166 while RCC.cr().read().pllrdy() {}
251 } 167
168 let in_freq = src_freq / pll_config.prediv;
169 assert!(max::PLL_IN.contains(&in_freq));
170 let internal_freq = in_freq * pll_config.mul;
171
172 assert!(max::PLL_VCO.contains(&internal_freq));
173
174 RCC.pllcfgr().write(|w| {
175 w.set_plln(pll_config.mul);
176 w.set_pllm(pll_config.prediv);
177 w.set_pllsrc(pll_config.source.into());
178 });
252 179
253 // RM0454 § 3.3.5: 180 let pll_p_freq = pll_config.divp.map(|div_p| {
254 // > Prefetch is enabled by setting the PRFTEN bit of the FLASH access control register 181 RCC.pllcfgr().modify(|w| {
255 // > (FLASH_ACR). This feature is useful if at least one wait state is needed to access the 182 w.set_pllp(div_p);
256 // > Flash memory. 183 w.set_pllpen(true);
257 // 184 });
258 // Enable flash prefetching if we have at least one wait state, and disable it otherwise. 185 let freq = internal_freq / div_p;
259 w.set_prften(target_flash_latency.to_bits() > 0); 186 assert!(max::PLL_P.contains(&freq));
260 }); 187 freq
188 });
261 189
262 if !set_flash_latency_after { 190 let pll_q_freq = pll_config.divq.map(|div_q| {
263 // Spin until the effective flash latency is compatible with the clock change 191 RCC.pllcfgr().modify(|w| {
264 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} 192 w.set_pllq(div_q);
265 } 193 w.set_pllqen(true);
194 });
195 let freq = internal_freq / div_q;
196 assert!(max::PLL_Q.contains(&freq));
197 freq
198 });
266 199
267 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 200 let pll_r_freq = pll_config.divr.map(|div_r| {
268 let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); 201 RCC.pllcfgr().modify(|w| {
269 RCC.cfgr().modify(|w| { 202 w.set_pllr(div_r);
270 w.set_sw(sw); 203 w.set_pllren(true);
271 w.set_hpre(hpre); 204 });
272 w.set_ppre(ppre); 205 let freq = internal_freq / div_r;
273 }); 206 assert!(max::PLL_R.contains(&freq));
207 freq
208 });
274 209
275 if set_flash_latency_after { 210 // Enable the PLL
276 // We can make the flash require fewer wait states 211 RCC.cr().modify(|w| w.set_pllon(true));
277 // Spin until the SYSCLK changes have taken effect 212 while !RCC.cr().read().pllrdy() {}
278 loop { 213
279 let cfgr = RCC.cfgr().read(); 214 PllFreq {
280 if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre { 215 pll_p: pll_p_freq,
281 break; 216 pll_q: pll_q_freq,
217 pll_r: pll_r_freq,
282 } 218 }
283 } 219 })
220 .unwrap_or_default();
221
222 let sys = match config.sys {
223 Sysclk::HSI => unwrap!(hsi),
224 Sysclk::HSE => unwrap!(hse),
225 Sysclk::PLL1_R => unwrap!(pll.pll_r),
226 _ => unreachable!(),
227 };
284 228
285 // Set the flash latency to require fewer wait states 229 assert!(max::SYSCLK.contains(&sys));
286 FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
287 }
288 230
289 let ahb_freq = sys_clk / config.ahb_pre; 231 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
232 let hclk = sys / config.ahb_pre;
233 assert!(max::HCLK.contains(&hclk));
290 234
291 let (apb_freq, apb_tim_freq) = match config.apb_pre { 235 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
292 APBPrescaler::DIV1 => (ahb_freq, ahb_freq), 236 assert!(max::PCLK.contains(&pclk1));
293 pre => { 237
294 let freq = ahb_freq / pre; 238 let latency = match (config.voltage_range, hclk.0) {
295 (freq, freq * 2u32) 239 (VoltageRange::RANGE1, ..=24_000_000) => Latency::WS0,
296 } 240 (VoltageRange::RANGE1, ..=48_000_000) => Latency::WS1,
241 (VoltageRange::RANGE1, _) => Latency::WS2,
242 (VoltageRange::RANGE2, ..=8_000_000) => Latency::WS0,
243 (VoltageRange::RANGE2, ..=16_000_000) => Latency::WS1,
244 (VoltageRange::RANGE2, _) => Latency::WS2,
245 _ => unreachable!(),
297 }; 246 };
298 247
248 // Configure flash read access latency based on voltage scale and frequency (RM0444 3.3.4)
249 FLASH.acr().modify(|w| {
250 w.set_latency(latency);
251 });
252
253 // Spin until the effective flash latency is set.
254 while FLASH.acr().read().latency() != latency {}
255
256 // Now that boost mode and flash read access latency are configured, set up SYSCLK
257 RCC.cfgr().modify(|w| {
258 w.set_sw(config.sys);
259 w.set_hpre(config.ahb_pre);
260 w.set_ppre(config.apb1_pre);
261 });
262
299 if config.low_power_run { 263 if config.low_power_run {
300 assert!(sys_clk.0 <= 2_000_000); 264 assert!(sys <= Hertz(2_000_000));
301 PWR.cr1().modify(|w| w.set_lpr(true)); 265 PWR.cr1().modify(|w| w.set_lpr(true));
302 } 266 }
303 267
304 let rtc = config.ls.init(); 268 let rtc = config.ls.init();
305 let lse_freq = config.ls.lse.map(|lse| lse.frequency);
306
307 let hsi_freq = (sw == Sw::HSI).then_some(HSI_FREQ);
308 let hsi_div_8_freq = hsi_freq.map(|f| f / 8u32);
309 let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ);
310 let hse_freq = (sw == Sw::HSE).then_some(sys_clk);
311
312 #[cfg(crs)]
313 let hsi48 = config.hsi48.map(super::init_hsi48);
314 #[cfg(not(crs))]
315 let hsi48: Option<Hertz> = None;
316 269
317 config.mux.init(); 270 config.mux.init();
318 271
319 set_clocks!( 272 set_clocks!(
320 sys: Some(sys_clk), 273 sys: Some(sys),
321 hclk1: Some(ahb_freq), 274 hclk1: Some(hclk),
322 pclk1: Some(apb_freq), 275 pclk1: Some(pclk1),
323 pclk1_tim: Some(apb_tim_freq), 276 pclk1_tim: Some(pclk1_tim),
324 hsi: hsi_freq, 277 pll1_p: pll.pll_p,
278 pll1_q: pll.pll_q,
279 pll1_r: pll.pll_r,
280 hsi: hsi,
281 hse: hse,
282 #[cfg(crs)]
325 hsi48: hsi48, 283 hsi48: hsi48,
326 hsi_div_8: hsi_div_8_freq,
327 hse: hse_freq,
328 lse: lse_freq,
329 lsi: lsi_freq,
330 pll1_q: pll1_q_freq,
331 pll1_p: pll1_p_freq,
332 rtc: rtc, 284 rtc: rtc,
333 hsi_div_488: None, 285 hsi_div_8: hsi.map(|h| h / 8u32),
286 hsi_div_488: hsi.map(|h| h / 488u32),
287
288 // TODO
289 lsi: None,
290 lse: None,
334 ); 291 );
335} 292}
293
294mod max {
295 use core::ops::RangeInclusive;
296
297 use crate::time::Hertz;
298
299 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(48_000_000);
300 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(0)..=Hertz(48_000_000);
301 pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(64_000_000);
302 pub(crate) const PCLK: RangeInclusive<Hertz> = Hertz(8)..=Hertz(64_000_000);
303 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(64_000_000);
304 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(2_660_000)..=Hertz(16_000_000);
305 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000);
306 pub(crate) const PLL_P: RangeInclusive<Hertz> = Hertz(3_090_000)..=Hertz(122_000_000);
307 pub(crate) const PLL_Q: RangeInclusive<Hertz> = Hertz(12_000_000)..=Hertz(128_000_000);
308 pub(crate) const PLL_R: RangeInclusive<Hertz> = Hertz(12_000_000)..=Hertz(64_000_000);
309}
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 79bdbeb77..cd2d2a8a2 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -1,12 +1,9 @@
1use stm32_metapac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
2use stm32_metapac::rcc::vals::Sw;
3use stm32_metapac::FLASH;
4
5pub use crate::pac::rcc::vals::{ 2pub use crate::pac::rcc::vals::{
6 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, 3 Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv,
7 Ppre as APBPrescaler, Sw as Sysclk, 4 Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk,
8}; 5};
9use crate::pac::{PWR, RCC}; 6use crate::pac::{FLASH, PWR, RCC};
10use crate::time::Hertz; 7use crate::time::Hertz;
11 8
12/// HSI speed 9/// HSI speed
@@ -37,7 +34,7 @@ pub struct Hse {
37/// frequency ranges for each of these settings. 34/// frequency ranges for each of these settings.
38pub struct Pll { 35pub struct Pll {
39 /// PLL Source clock selection. 36 /// PLL Source clock selection.
40 pub source: Pllsrc, 37 pub source: PllSource,
41 38
42 /// PLL pre-divider 39 /// PLL pre-divider
43 pub prediv: PllPreDiv, 40 pub prediv: PllPreDiv,
@@ -73,7 +70,7 @@ pub struct Config {
73 /// PLL Configuration 70 /// PLL Configuration
74 pub pll: Option<Pll>, 71 pub pll: Option<Pll>,
75 72
76 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration 73 /// If PLL is requested as the main clock source in the `sys` field then the PLL configuration
77 /// MUST turn on the PLLR output. 74 /// MUST turn on the PLLR output.
78 pub ahb_pre: AHBPrescaler, 75 pub ahb_pre: AHBPrescaler,
79 pub apb1_pre: APBPrescaler, 76 pub apb1_pre: APBPrescaler,
@@ -112,6 +109,7 @@ impl Default for Config {
112 } 109 }
113} 110}
114 111
112#[derive(Default)]
115pub struct PllFreq { 113pub struct PllFreq {
116 pub pll_p: Option<Hertz>, 114 pub pll_p: Option<Hertz>,
117 pub pll_q: Option<Hertz>, 115 pub pll_q: Option<Hertz>,
@@ -154,91 +152,91 @@ pub(crate) unsafe fn init(config: Config) {
154 // Configure HSI48 if required 152 // Configure HSI48 if required
155 let hsi48 = config.hsi48.map(super::init_hsi48); 153 let hsi48 = config.hsi48.map(super::init_hsi48);
156 154
157 let pll_freq = config.pll.map(|pll_config| { 155 let pll = config
158 let src_freq = match pll_config.source { 156 .pll
159 Pllsrc::HSI => unwrap!(hsi), 157 .map(|pll_config| {
160 Pllsrc::HSE => unwrap!(hse), 158 let src_freq = match pll_config.source {
161 _ => unreachable!(), 159 PllSource::HSI => unwrap!(hsi),
162 }; 160 PllSource::HSE => unwrap!(hse),
163 161 _ => unreachable!(),
164 // Disable PLL before configuration 162 };
165 RCC.cr().modify(|w| w.set_pllon(false)); 163
166 while RCC.cr().read().pllrdy() {} 164 // Disable PLL before configuration
167 165 RCC.cr().modify(|w| w.set_pllon(false));
168 let in_freq = src_freq / pll_config.prediv; 166 while RCC.cr().read().pllrdy() {}
169 assert!(max::PLL_IN.contains(&in_freq)); 167
170 let internal_freq = in_freq * pll_config.mul; 168 let in_freq = src_freq / pll_config.prediv;
171 169 assert!(max::PLL_IN.contains(&in_freq));
172 assert!(max::PLL_VCO.contains(&internal_freq)); 170 let internal_freq = in_freq * pll_config.mul;
173 171
174 RCC.pllcfgr().write(|w| { 172 assert!(max::PLL_VCO.contains(&internal_freq));
175 w.set_plln(pll_config.mul); 173
176 w.set_pllm(pll_config.prediv); 174 RCC.pllcfgr().write(|w| {
177 w.set_pllsrc(pll_config.source.into()); 175 w.set_plln(pll_config.mul);
178 }); 176 w.set_pllm(pll_config.prediv);
179 177 w.set_pllsrc(pll_config.source.into());
180 let pll_p_freq = pll_config.divp.map(|div_p| {
181 RCC.pllcfgr().modify(|w| {
182 w.set_pllp(div_p);
183 w.set_pllpen(true);
184 }); 178 });
185 let freq = internal_freq / div_p; 179
186 assert!(max::PCLK.contains(&freq)); 180 let pll_p_freq = pll_config.divp.map(|div_p| {
187 freq 181 RCC.pllcfgr().modify(|w| {
188 }); 182 w.set_pllp(div_p);
189 183 w.set_pllpen(true);
190 let pll_q_freq = pll_config.divq.map(|div_q| { 184 });
191 RCC.pllcfgr().modify(|w| { 185 let freq = internal_freq / div_p;
192 w.set_pllq(div_q); 186 assert!(max::PLL_P.contains(&freq));
193 w.set_pllqen(true); 187 freq
194 }); 188 });
195 let freq = internal_freq / div_q; 189
196 assert!(max::PCLK.contains(&freq)); 190 let pll_q_freq = pll_config.divq.map(|div_q| {
197 freq 191 RCC.pllcfgr().modify(|w| {
198 }); 192 w.set_pllq(div_q);
199 193 w.set_pllqen(true);
200 let pll_r_freq = pll_config.divr.map(|div_r| { 194 });
201 RCC.pllcfgr().modify(|w| { 195 let freq = internal_freq / div_q;
202 w.set_pllr(div_r); 196 assert!(max::PLL_Q.contains(&freq));
203 w.set_pllren(true); 197 freq
204 }); 198 });
205 let freq = internal_freq / div_r;
206 assert!(max::PCLK.contains(&freq));
207 freq
208 });
209
210 // Enable the PLL
211 RCC.cr().modify(|w| w.set_pllon(true));
212 while !RCC.cr().read().pllrdy() {}
213
214 PllFreq {
215 pll_p: pll_p_freq,
216 pll_q: pll_q_freq,
217 pll_r: pll_r_freq,
218 }
219 });
220 199
221 let (sys_clk, sw) = match config.sys { 200 let pll_r_freq = pll_config.divr.map(|div_r| {
222 Sysclk::HSI => (HSI_FREQ, Sw::HSI), 201 RCC.pllcfgr().modify(|w| {
223 Sysclk::HSE => (unwrap!(hse), Sw::HSE), 202 w.set_pllr(div_r);
224 Sysclk::PLL1_R => { 203 w.set_pllren(true);
225 assert!(pll_freq.is_some()); 204 });
226 assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); 205 let freq = internal_freq / div_r;
206 assert!(max::PLL_R.contains(&freq));
207 freq
208 });
227 209
228 let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; 210 // Enable the PLL
211 RCC.cr().modify(|w| w.set_pllon(true));
212 while !RCC.cr().read().pllrdy() {}
229 213
230 assert!(max::SYSCLK.contains(&Hertz(freq))); 214 PllFreq {
215 pll_p: pll_p_freq,
216 pll_q: pll_q_freq,
217 pll_r: pll_r_freq,
218 }
219 })
220 .unwrap_or_default();
231 221
232 (Hertz(freq), Sw::PLL1_R) 222 let sys = match config.sys {
233 } 223 Sysclk::HSI => unwrap!(hsi),
224 Sysclk::HSE => unwrap!(hse),
225 Sysclk::PLL1_R => unwrap!(pll.pll_r),
234 _ => unreachable!(), 226 _ => unreachable!(),
235 }; 227 };
236 228
237 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. 229 assert!(max::SYSCLK.contains(&sys));
238 let hclk = sys_clk / config.ahb_pre;
239 230
231 // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency.
232 let hclk = sys / config.ahb_pre;
240 assert!(max::HCLK.contains(&hclk)); 233 assert!(max::HCLK.contains(&hclk));
241 234
235 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
236 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
237 assert!(max::PCLK.contains(&pclk2));
238 assert!(max::PCLK.contains(&pclk2));
239
242 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) 240 // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!)
243 if config.boost { 241 if config.boost {
244 // RM0440 p235 242 // RM0440 p235
@@ -253,23 +251,28 @@ pub(crate) unsafe fn init(config: Config) {
253 // 4. Configure and switch to new frequency 251 // 4. Configure and switch to new frequency
254 } 252 }
255 253
254 let latency = match (config.boost, hclk.0) {
255 (true, ..=34_000_000) => Latency::WS0,
256 (true, ..=68_000_000) => Latency::WS1,
257 (true, ..=102_000_000) => Latency::WS2,
258 (true, ..=136_000_000) => Latency::WS3,
259 (true, _) => Latency::WS4,
260
261 (false, ..=36_000_000) => Latency::WS0,
262 (false, ..=60_000_000) => Latency::WS1,
263 (false, ..=90_000_000) => Latency::WS2,
264 (false, ..=120_000_000) => Latency::WS3,
265 (false, _) => Latency::WS4,
266 };
267
256 // Configure flash read access latency based on boost mode and frequency (RM0440 p98) 268 // Configure flash read access latency based on boost mode and frequency (RM0440 p98)
257 FLASH.acr().modify(|w| { 269 FLASH.acr().modify(|w| {
258 w.set_latency(match (config.boost, hclk.0) { 270 w.set_latency(latency);
259 (true, ..=34_000_000) => Latency::WS0,
260 (true, ..=68_000_000) => Latency::WS1,
261 (true, ..=102_000_000) => Latency::WS2,
262 (true, ..=136_000_000) => Latency::WS3,
263 (true, _) => Latency::WS4,
264
265 (false, ..=36_000_000) => Latency::WS0,
266 (false, ..=60_000_000) => Latency::WS1,
267 (false, ..=90_000_000) => Latency::WS2,
268 (false, ..=120_000_000) => Latency::WS3,
269 (false, _) => Latency::WS4,
270 })
271 }); 271 });
272 272
273 // Spin until the effective flash latency is set.
274 while FLASH.acr().read().latency() != latency {}
275
273 if config.boost { 276 if config.boost {
274 // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency. 277 // 5. Wait for at least 1us and then reconfigure the AHB prescaler to get the needed HCLK clock frequency.
275 cortex_m::asm::delay(16); 278 cortex_m::asm::delay(16);
@@ -277,17 +280,14 @@ pub(crate) unsafe fn init(config: Config) {
277 280
278 // Now that boost mode and flash read access latency are configured, set up SYSCLK 281 // Now that boost mode and flash read access latency are configured, set up SYSCLK
279 RCC.cfgr().modify(|w| { 282 RCC.cfgr().modify(|w| {
280 w.set_sw(sw); 283 w.set_sw(config.sys);
281 w.set_hpre(config.ahb_pre); 284 w.set_hpre(config.ahb_pre);
282 w.set_ppre1(config.apb1_pre); 285 w.set_ppre1(config.apb1_pre);
283 w.set_ppre2(config.apb2_pre); 286 w.set_ppre2(config.apb2_pre);
284 }); 287 });
285 288
286 let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
287 let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
288
289 if config.low_power_run { 289 if config.low_power_run {
290 assert!(sys_clk <= Hertz(2_000_000)); 290 assert!(sys <= Hertz(2_000_000));
291 PWR.cr1().modify(|w| w.set_lpr(true)); 291 PWR.cr1().modify(|w| w.set_lpr(true));
292 } 292 }
293 293
@@ -296,17 +296,18 @@ pub(crate) unsafe fn init(config: Config) {
296 config.mux.init(); 296 config.mux.init();
297 297
298 set_clocks!( 298 set_clocks!(
299 sys: Some(sys_clk), 299 sys: Some(sys),
300 hclk1: Some(hclk), 300 hclk1: Some(hclk),
301 hclk2: Some(hclk), 301 hclk2: Some(hclk),
302 hclk3: Some(hclk), 302 hclk3: Some(hclk),
303 pclk1: Some(apb1_freq), 303 pclk1: Some(pclk1),
304 pclk1_tim: Some(apb1_tim_freq), 304 pclk1_tim: Some(pclk1_tim),
305 pclk2: Some(apb2_freq), 305 pclk2: Some(pclk2),
306 pclk2_tim: Some(apb2_tim_freq), 306 pclk2_tim: Some(pclk2_tim),
307 pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p), 307 pll1_p: pll.pll_p,
308 pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q), 308 pll1_q: pll.pll_q,
309 pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r), 309 pll1_r: pll.pll_r,
310 hsi: hsi,
310 hse: hse, 311 hse: hse,
311 hsi48: hsi48, 312 hsi48: hsi48,
312 rtc: rtc, 313 rtc: rtc,
@@ -342,4 +343,7 @@ mod max {
342 343
343 /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46) 344 /// PLL VCO (internal) Frequency Range (STM32G474 Datasheet p123, Table 46)
344 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000); 345 pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(96_000_000)..=Hertz(344_000_000);
346 pub(crate) const PLL_P: RangeInclusive<Hertz> = Hertz(2_064_500)..=Hertz(170_000_000);
347 pub(crate) const PLL_Q: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
348 pub(crate) const PLL_R: RangeInclusive<Hertz> = Hertz(8_000_000)..=Hertz(170_000_000);
345} 349}
diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs
index 647ff0419..3ea06cdee 100644
--- a/examples/stm32g0/src/bin/hf_timer.rs
+++ b/examples/stm32g0/src/bin/hf_timer.rs
@@ -16,15 +16,16 @@ async fn main(_spawner: Spawner) {
16 let mut config = PeripheralConfig::default(); 16 let mut config = PeripheralConfig::default();
17 { 17 {
18 use embassy_stm32::rcc::*; 18 use embassy_stm32::rcc::*;
19 19 config.rcc.hsi = true;
20 config.rcc.sys = Sysclk::PLL(PllConfig { 20 config.rcc.pll = Some(Pll {
21 source: PllSource::HSI, 21 source: PllSource::HSI,
22 m: Pllm::DIV1, 22 prediv: PllPreDiv::DIV1,
23 n: Plln::MUL16, 23 mul: PllMul::MUL16,
24 r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz) 24 divp: None,
25 q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz) 25 divq: Some(PllQDiv::DIV2), // 16 / 1 * 16 / 2 = 128 Mhz
26 p: None, 26 divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz
27 }); 27 });
28 config.rcc.sys = Sysclk::PLL1_R;
28 29
29 // configure TIM1 mux to select PLLQ as clock source 30 // configure TIM1 mux to select PLLQ as clock source
30 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 31 // https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs
index f81335f93..ae64bc8e4 100644
--- a/examples/stm32g4/src/bin/adc.rs
+++ b/examples/stm32g4/src/bin/adc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 { 14 {
15 use embassy_stm32::rcc::*; 15 use embassy_stm32::rcc::*;
16 config.rcc.pll = Some(Pll { 16 config.rcc.pll = Some(Pll {
17 source: Pllsrc::HSI, 17 source: PllSource::HSI,
18 prediv: PllPreDiv::DIV4, 18 prediv: PllPreDiv::DIV4,
19 mul: PllMul::MUL85, 19 mul: PllMul::MUL85,
20 divp: None, 20 divp: None,
diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs
index 93b206de8..4373a89a8 100644
--- a/examples/stm32g4/src/bin/can.rs
+++ b/examples/stm32g4/src/bin/can.rs
@@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
24 mode: HseMode::Oscillator, 24 mode: HseMode::Oscillator,
25 }); 25 });
26 config.rcc.pll = Some(Pll { 26 config.rcc.pll = Some(Pll {
27 source: Pllsrc::HSE, 27 source: PllSource::HSE,
28 prediv: PllPreDiv::DIV6, 28 prediv: PllPreDiv::DIV6,
29 mul: PllMul::MUL85, 29 mul: PllMul::MUL85,
30 divp: None, 30 divp: None,
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
index 2609abfa2..08ed95b34 100644
--- a/examples/stm32g4/src/bin/pll.rs
+++ b/examples/stm32g4/src/bin/pll.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::rcc::{Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
7use embassy_stm32::Config; 6use embassy_stm32::Config;
8use embassy_time::Timer; 7use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
@@ -11,20 +10,20 @@ use {defmt_rtt as _, panic_probe as _};
11#[embassy_executor::main] 10#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
13 let mut config = Config::default(); 12 let mut config = Config::default();
14 13 {
15 config.rcc.hsi = true; 14 use embassy_stm32::rcc::*;
16 config.rcc.pll = Some(Pll { 15 config.rcc.hsi = true;
17 source: Pllsrc::HSI, 16 config.rcc.pll = Some(Pll {
18 prediv: PllPreDiv::DIV4, 17 source: PllSource::HSI,
19 mul: PllMul::MUL85, 18 prediv: PllPreDiv::DIV4,
20 divp: None, 19 mul: PllMul::MUL85,
21 divq: None, 20 divp: None,
22 // Main system clock at 170 MHz 21 divq: None,
23 divr: Some(PllRDiv::DIV2), 22 // Main system clock at 170 MHz
24 }); 23 divr: Some(PllRDiv::DIV2),
25 24 });
26 config.rcc.sys = Sysclk::PLL1_R; 25 config.rcc.sys = Sysclk::PLL1_R;
27 26 }
28 let _p = embassy_stm32::init(config); 27 let _p = embassy_stm32::init(config);
29 info!("Hello World!"); 28 info!("Hello World!");
30 29
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 90caaae14..dc95aa6e5 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 mode: HseMode::Oscillator, 28 mode: HseMode::Oscillator,
29 }); 29 });
30 config.rcc.pll = Some(Pll { 30 config.rcc.pll = Some(Pll {
31 source: Pllsrc::HSE, 31 source: PllSource::HSE,
32 prediv: PllPreDiv::DIV2, 32 prediv: PllPreDiv::DIV2,
33 mul: PllMul::MUL72, 33 mul: PllMul::MUL72,
34 divp: None, 34 divp: None,
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index cf3e04a4b..3297ea7e2 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -260,6 +260,30 @@ pub fn config() -> Config {
260 #[allow(unused_mut)] 260 #[allow(unused_mut)]
261 let mut config = Config::default(); 261 let mut config = Config::default();
262 262
263 #[cfg(feature = "stm32c031c6")]
264 {
265 config.rcc.hsi = Some(Hsi {
266 sys_div: HsiSysDiv::DIV1, // 48Mhz
267 ker_div: HsiKerDiv::DIV3, // 16Mhz
268 });
269 config.rcc.sys = Sysclk::HSISYS;
270 config.rcc.ahb_pre = AHBPrescaler::DIV1;
271 config.rcc.apb1_pre = APBPrescaler::DIV1;
272 }
273
274 #[cfg(feature = "stm32g071rb")]
275 {
276 config.rcc.hsi = true;
277 config.rcc.pll = Some(Pll {
278 source: PllSource::HSI,
279 prediv: PllPreDiv::DIV1,
280 mul: PllMul::MUL16,
281 divp: None,
282 divq: None,
283 divr: Some(PllRDiv::DIV4), // 16 / 1 * 16 / 4 = 64 Mhz
284 });
285 config.rcc.sys = Sysclk::PLL1_R;
286 }
263 #[cfg(feature = "stm32wb55rg")] 287 #[cfg(feature = "stm32wb55rg")]
264 { 288 {
265 config.rcc = embassy_stm32::rcc::WPAN_DEFAULT; 289 config.rcc = embassy_stm32::rcc::WPAN_DEFAULT;
@@ -456,7 +480,7 @@ pub fn config() -> Config {
456 mode: HseMode::Oscillator, 480 mode: HseMode::Oscillator,
457 }); 481 });
458 config.rcc.pll = Some(Pll { 482 config.rcc.pll = Some(Pll {
459 source: Pllsrc::HSE, 483 source: PllSource::HSE,
460 prediv: PllPreDiv::DIV6, 484 prediv: PllPreDiv::DIV6,
461 mul: PllMul::MUL85, 485 mul: PllMul::MUL85,
462 divp: None, 486 divp: None,