aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-03-04 00:03:07 +0100
committerDario Nieuwenhuis <[email protected]>2024-03-04 00:08:14 +0100
commitae266f3bf528c334c4712cd37305d2bcb71c0936 (patch)
tree66fa6a524c6ce25b0f883639c40dc1a64c24a047
parentc8c4b0b701ecfbb146c6f651bebd43f053f55ac2 (diff)
stm32/rcc: port 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--tests/stm32/src/common.rs11
3 files changed, 142 insertions, 97 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/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 1587a6fb4..3297ea7e2 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -260,6 +260,17 @@ 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
263 #[cfg(feature = "stm32g071rb")] 274 #[cfg(feature = "stm32g071rb")]
264 { 275 {
265 config.rcc.hsi = true; 276 config.rcc.hsi = true;