aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/rcc/f1.rs372
-rw-r--r--examples/stm32f1/src/bin/hello.rs4
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs20
-rw-r--r--tests/stm32/.cargo/config.toml4
-rw-r--r--tests/stm32/src/common.rs18
5 files changed, 257 insertions, 161 deletions
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index 7f0adab27..9fdd4c11c 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -1,191 +1,257 @@
1use core::convert::TryFrom;
2
3use crate::pac::flash::vals::Latency; 1use crate::pac::flash::vals::Latency;
4use crate::pac::rcc::vals::*; 2use crate::pac::rcc::vals::Pllsrc;
3#[cfg(any(rcc_f1, rcc_f1cl))]
4use crate::pac::rcc::vals::Usbpre;
5pub use crate::pac::rcc::vals::{
6 Adcpre as ADCPrescaler, Hpre as AHBPrescaler, Pllmul as PllMul, Pllxtpre as PllPreDiv, Ppre as APBPrescaler,
7 Sw as Sysclk,
8};
5use crate::pac::{FLASH, RCC}; 9use crate::pac::{FLASH, RCC};
6use crate::time::Hertz; 10use crate::time::Hertz;
7 11
8/// HSI speed 12/// HSI speed
9pub const HSI_FREQ: Hertz = Hertz(8_000_000); 13pub const HSI_FREQ: Hertz = Hertz(8_000_000);
10 14
11/// Configuration of the clocks 15#[derive(Clone, Copy, Eq, PartialEq)]
12/// 16pub enum HseMode {
17 /// crystal/ceramic oscillator (HSEBYP=0)
18 Oscillator,
19 /// external analog clock (low swing) (HSEBYP=1)
20 Bypass,
21}
22
23#[derive(Clone, Copy, Eq, PartialEq)]
24pub struct Hse {
25 /// HSE frequency.
26 pub freq: Hertz,
27 /// HSE mode.
28 pub mode: HseMode,
29}
30
31#[derive(Clone, Copy, Eq, PartialEq)]
32pub enum PllSource {
33 HSE,
34 HSI,
35}
36
37#[derive(Clone, Copy)]
38pub struct Pll {
39 pub src: PllSource,
40
41 /// PLL pre-divider.
42 ///
43 /// On some F3 chips, this must be 2 if `src == HSI`. Init will panic if this is not the case.
44 pub prediv: PllPreDiv,
45
46 /// PLL multiplication factor.
47 pub mul: PllMul,
48}
49
50/// Clocks configutation
13#[non_exhaustive] 51#[non_exhaustive]
14#[derive(Default)]
15pub struct Config { 52pub struct Config {
16 pub hse: Option<Hertz>, 53 pub hsi: bool,
54 pub hse: Option<Hse>,
55 pub sys: Sysclk,
17 56
18 pub sys_ck: Option<Hertz>, 57 pub pll: Option<Pll>,
19 pub hclk: Option<Hertz>, 58
20 pub pclk1: Option<Hertz>, 59 pub ahb_pre: AHBPrescaler,
21 pub pclk2: Option<Hertz>, 60 pub apb1_pre: APBPrescaler,
22 pub adcclk: Option<Hertz>, 61 pub apb2_pre: APBPrescaler,
23 pub pllxtpre: bool, 62
63 pub adc_pre: ADCPrescaler,
24 64
25 pub ls: super::LsConfig, 65 pub ls: super::LsConfig,
26} 66}
27 67
28pub(crate) unsafe fn init(config: Config) { 68impl Default for Config {
29 let pllxtpre_div = if config.pllxtpre { 2 } else { 1 }; 69 fn default() -> Self {
30 let pllsrcclk = config.hse.map(|hse| hse.0 / pllxtpre_div).unwrap_or(HSI_FREQ.0 / 2); 70 Self {
71 hsi: true,
72 hse: None,
73 sys: Sysclk::HSI,
74 pll: None,
75 ahb_pre: AHBPrescaler::DIV1,
76 apb1_pre: APBPrescaler::DIV1,
77 apb2_pre: APBPrescaler::DIV1,
78 ls: Default::default(),
31 79
32 let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); 80 // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz)
33 let pllmul = sysclk / pllsrcclk; 81 adc_pre: ADCPrescaler::DIV6,
82 }
83 }
84}
34 85
35 let (pllmul_bits, real_sysclk) = if pllmul == 1 { 86/// Initialize and Set the clock frequencies
36 (None, config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0)) 87pub(crate) unsafe fn init(config: Config) {
37 } else { 88 // Configure HSI
38 let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); 89 let hsi = match config.hsi {
39 (Some(pllmul as u8 - 2), pllsrcclk * pllmul) 90 false => {
91 RCC.cr().modify(|w| w.set_hsion(false));
92 None
93 }
94 true => {
95 RCC.cr().modify(|w| w.set_hsion(true));
96 while !RCC.cr().read().hsirdy() {}
97 Some(HSI_FREQ)
98 }
40 }; 99 };
41 100
42 assert!(real_sysclk <= 72_000_000); 101 // Configure HSE
43 102 let hse = match config.hse {
44 let hpre_bits = config 103 None => {
45 .hclk 104 RCC.cr().modify(|w| w.set_hseon(false));
46 .map(|hclk| match real_sysclk / hclk.0 { 105 None
47 0 => unreachable!(), 106 }
48 1 => 0b0111, 107 Some(hse) => {
49 2 => 0b1000, 108 match hse.mode {
50 3..=5 => 0b1001, 109 HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
51 6..=11 => 0b1010, 110 HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
52 12..=39 => 0b1011, 111 }
53 40..=95 => 0b1100, 112
54 96..=191 => 0b1101, 113 RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
55 192..=383 => 0b1110, 114 RCC.cr().modify(|w| w.set_hseon(true));
56 _ => 0b1111, 115 while !RCC.cr().read().hserdy() {}
57 }) 116 Some(hse.freq)
58 .unwrap_or(0b0111); 117 }
59
60 let hclk = if hpre_bits >= 0b1100 {
61 real_sysclk / (1 << (hpre_bits - 0b0110))
62 } else {
63 real_sysclk / (1 << (hpre_bits - 0b0111))
64 }; 118 };
65 119
66 assert!(hclk <= 72_000_000); 120 // Enable PLL
67 121 let pll = config.pll.map(|pll| {
68 let ppre1_bits = config 122 let (src_val, src_freq) = match pll.src {
69 .pclk1 123 PllSource::HSI => {
70 .map(|pclk1| match hclk / pclk1.0 { 124 if pll.prediv != PllPreDiv::DIV2 {
71 0 => unreachable!(), 125 panic!("if PLL source is HSI, PLL prediv must be 2.");
72 1 => 0b011, 126 }
73 2 => 0b100, 127 (Pllsrc::HSI_DIV2, unwrap!(hsi))
74 3..=5 => 0b101, 128 }
75 6..=11 => 0b110, 129 PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)),
76 _ => 0b111, 130 };
77 }) 131 let in_freq = src_freq / pll.prediv;
78 .unwrap_or(0b011); 132 assert!(max::PLL_IN.contains(&in_freq));
79 133 let out_freq = in_freq * pll.mul;
80 let ppre1 = 1 << (ppre1_bits - 0b011); 134 assert!(max::PLL_OUT.contains(&out_freq));
81 let pclk1 = hclk / u32::try_from(ppre1).unwrap(); 135
82 let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; 136 RCC.cfgr().modify(|w| {
83 137 w.set_pllmul(pll.mul);
84 assert!(pclk1 <= 36_000_000); 138 w.set_pllsrc(src_val);
85 139 w.set_pllxtpre(pll.prediv);
86 let ppre2_bits = config
87 .pclk2
88 .map(|pclk2| match hclk / pclk2.0 {
89 0 => unreachable!(),
90 1 => 0b011,
91 2 => 0b100,
92 3..=5 => 0b101,
93 6..=11 => 0b110,
94 _ => 0b111,
95 })
96 .unwrap_or(0b011);
97
98 let ppre2 = 1 << (ppre2_bits - 0b011);
99 let pclk2 = hclk / u32::try_from(ppre2).unwrap();
100 let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
101
102 assert!(pclk2 <= 72_000_000);
103
104 FLASH.acr().write(|w| {
105 w.set_latency(if real_sysclk <= 24_000_000 {
106 Latency::WS0
107 } else if real_sysclk <= 48_000_000 {
108 Latency::WS1
109 } else {
110 Latency::WS2
111 }); 140 });
112 // the prefetch buffer is enabled by default, let's keep it enabled 141 RCC.cr().modify(|w| w.set_pllon(true));
113 w.set_prftbe(true); 142 while !RCC.cr().read().pllrdy() {}
143
144 out_freq
114 }); 145 });
115 146
116 // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the 147 #[cfg(any(rcc_f1, rcc_f1cl))]
117 // PLL output frequency is a supported one. 148 let usb = match pll {
118 // usbpre == false: divide clock by 1.5, otherwise no division 149 Some(Hertz(72_000_000)) => {
119 #[cfg(not(rcc_f100))] 150 RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1_5));
120 let (usbpre, _usbclk_valid) = match (config.hse, pllmul_bits, real_sysclk) { 151 Some(Hertz(48_000_000))
121 (Some(_), Some(_), 72_000_000) => (false, true), 152 }
122 (Some(_), Some(_), 48_000_000) => (true, true), 153 Some(Hertz(48_000_000)) => {
123 _ => (true, false), 154 RCC.cfgr().modify(|w| w.set_usbpre(Usbpre::DIV1));
155 Some(Hertz(48_000_000))
156 }
157 _ => None,
124 }; 158 };
125 159
126 let apre_bits: u8 = config 160 // Configure sysclk
127 .adcclk 161 let sys = match config.sys {
128 .map(|adcclk| match pclk2 / adcclk.0 { 162 Sysclk::HSI => unwrap!(hsi),
129 0..=2 => 0b00, 163 Sysclk::HSE => unwrap!(hse),
130 3..=4 => 0b01, 164 Sysclk::PLL1_P => unwrap!(pll),
131 5..=7 => 0b10, 165 _ => unreachable!(),
132 _ => 0b11, 166 };
133 })
134 .unwrap_or(0b11);
135
136 let apre = (apre_bits + 1) << 1;
137 let adcclk = pclk2 / unwrap!(u32::try_from(apre));
138
139 assert!(adcclk <= 14_000_000);
140
141 if config.hse.is_some() {
142 // enable HSE and wait for it to be ready
143 RCC.cr().modify(|w| w.set_hseon(true));
144 while !RCC.cr().read().hserdy() {}
145 }
146 167
147 if let Some(pllmul_bits) = pllmul_bits { 168 let hclk = sys / config.ahb_pre;
148 let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 }; 169 let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
149 RCC.cfgr() 170 let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
150 .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag)));
151 171
152 // enable PLL and wait for it to be ready 172 assert!(max::HCLK.contains(&hclk));
153 RCC.cfgr().modify(|w| { 173 assert!(max::PCLK1.contains(&pclk1));
154 w.set_pllmul(Pllmul::from_bits(pllmul_bits)); 174 assert!(max::PCLK2.contains(&pclk2));
155 w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8));
156 });
157 175
158 RCC.cr().modify(|w| w.set_pllon(true)); 176 let adc = pclk2 / config.adc_pre;
159 while !RCC.cr().read().pllrdy() {} 177 assert!(max::ADC.contains(&adc));
160 } 178
179 // Set latency based on HCLK frquency
180 let latency = match hclk.0 {
181 ..=24_000_000 => Latency::WS0,
182 ..=48_000_000 => Latency::WS1,
183 _ => Latency::WS2,
184 };
185 FLASH.acr().modify(|w| {
186 w.set_latency(latency);
187 // RM0316: "The prefetch buffer must be kept on when using a prescaler
188 // different from 1 on the AHB clock.", "Half-cycle access cannot be
189 // used when there is a prescaler different from 1 on the AHB clock"
190 if config.ahb_pre != AHBPrescaler::DIV1 {
191 w.set_hlfcya(false);
192 w.set_prftbe(true);
193 }
194 });
161 195
162 // Only needed for stm32f103? 196 // Set prescalers
197 // CFGR has been written before (PLL, PLL48) don't overwrite these settings
163 RCC.cfgr().modify(|w| { 198 RCC.cfgr().modify(|w| {
164 w.set_adcpre(Adcpre::from_bits(apre_bits)); 199 w.set_ppre1(config.apb1_pre);
165 w.set_ppre2(Ppre::from_bits(ppre2_bits)); 200 w.set_ppre2(config.apb2_pre);
166 w.set_ppre1(Ppre::from_bits(ppre1_bits)); 201 w.set_hpre(config.ahb_pre);
167 w.set_hpre(Hpre::from_bits(hpre_bits)); 202 w.set_adcpre(config.adc_pre);
168 #[cfg(not(rcc_f100))]
169 w.set_usbpre(Usbpre::from_bits(usbpre as u8));
170 w.set_sw(if pllmul_bits.is_some() {
171 Sw::PLL1_P
172 } else if config.hse.is_some() {
173 Sw::HSE
174 } else {
175 Sw::HSI
176 });
177 }); 203 });
178 204
205 // Wait for the new prescalers to kick in
206 // "The clocks are divided with the new prescaler factor from
207 // 1 to 16 AHB cycles after write"
208 cortex_m::asm::delay(16);
209
210 // CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings
211 RCC.cfgr().modify(|w| w.set_sw(config.sys));
212 while RCC.cfgr().read().sws() != config.sys {}
213
179 let rtc = config.ls.init(); 214 let rtc = config.ls.init();
180 215
181 set_clocks!( 216 set_clocks!(
182 sys: Some(Hertz(real_sysclk)), 217 hsi: hsi,
183 pclk1: Some(Hertz(pclk1)), 218 hse: hse,
184 pclk2: Some(Hertz(pclk2)), 219 pll1_p: pll,
185 pclk1_tim: Some(Hertz(pclk1 * timer_mul1)), 220 sys: Some(sys),
186 pclk2_tim: Some(Hertz(pclk2 * timer_mul2)), 221 pclk1: Some(pclk1),
187 hclk1: Some(Hertz(hclk)), 222 pclk2: Some(pclk2),
188 adc: Some(Hertz(adcclk)), 223 pclk1_tim: Some(pclk1_tim),
224 pclk2_tim: Some(pclk2_tim),
225 hclk1: Some(hclk),
226 adc: Some(adc),
189 rtc: rtc, 227 rtc: rtc,
228 #[cfg(any(rcc_f1, rcc_f1cl))]
229 usb: usb,
230 lse: None,
190 ); 231 );
191} 232}
233
234mod max {
235 use core::ops::RangeInclusive;
236
237 use crate::time::Hertz;
238
239 #[cfg(not(rcc_f1cl))]
240 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(16_000_000);
241 #[cfg(not(rcc_f1cl))]
242 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(25_000_000);
243
244 #[cfg(rcc_f1cl)]
245 pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(3_000_000)..=Hertz(25_000_000);
246 #[cfg(rcc_f1cl)]
247 pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
248
249 pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000);
250 pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(36_000_000);
251 pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(72_000_000);
252
253 pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(25_000_000);
254 pub(crate) const PLL_OUT: RangeInclusive<Hertz> = Hertz(16_000_000)..=Hertz(72_000_000);
255
256 pub(crate) const ADC: RangeInclusive<Hertz> = Hertz(0)..=Hertz(14_000_000);
257}
diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs
index 7b761ecc1..3c295612c 100644
--- a/examples/stm32f1/src/bin/hello.rs
+++ b/examples/stm32f1/src/bin/hello.rs
@@ -3,15 +3,13 @@
3 3
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::time::Hertz;
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 _};
10 9
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 config = Config::default();
14 config.rcc.sys_ck = Some(Hertz(36_000_000));
15 let _p = embassy_stm32::init(config); 13 let _p = embassy_stm32::init(config);
16 14
17 loop { 15 loop {
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index e28381893..1ae6c1dee 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -21,9 +21,23 @@ bind_interrupts!(struct Irqs {
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 config.rcc.hse = Some(Hertz(8_000_000)); 24 {
25 config.rcc.sys_ck = Some(Hertz(48_000_000)); 25 use embassy_stm32::rcc::*;
26 config.rcc.pclk1 = Some(Hertz(24_000_000)); 26 config.rcc.hse = Some(Hse {
27 freq: Hertz(8_000_000),
28 // Oscillator for bluepill, Bypass for nucleos.
29 mode: HseMode::Oscillator,
30 });
31 config.rcc.pll = Some(Pll {
32 src: PllSource::HSE,
33 prediv: PllPreDiv::DIV1,
34 mul: PllMul::MUL9,
35 });
36 config.rcc.sys = Sysclk::PLL1_P;
37 config.rcc.ahb_pre = AHBPrescaler::DIV1;
38 config.rcc.apb1_pre = APBPrescaler::DIV2;
39 config.rcc.apb2_pre = APBPrescaler::DIV1;
40 }
27 let mut p = embassy_stm32::init(config); 41 let mut p = embassy_stm32::init(config);
28 42
29 info!("Hello World!"); 43 info!("Hello World!");
diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml
index 8e32b4cee..528bd3451 100644
--- a/tests/stm32/.cargo/config.toml
+++ b/tests/stm32/.cargo/config.toml
@@ -14,9 +14,9 @@ rustflags = [
14] 14]
15 15
16[build] 16[build]
17target = "thumbv6m-none-eabi" 17#target = "thumbv6m-none-eabi"
18#target = "thumbv7m-none-eabi" 18#target = "thumbv7m-none-eabi"
19#target = "thumbv7em-none-eabi" 19target = "thumbv7em-none-eabi"
20#target = "thumbv8m.main-none-eabihf" 20#target = "thumbv8m.main-none-eabihf"
21 21
22[env] 22[env]
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 36fe8a235..182ad6298 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -247,6 +247,24 @@ pub fn config() -> Config {
247 config.rcc = embassy_stm32::rcc::WPAN_DEFAULT; 247 config.rcc = embassy_stm32::rcc::WPAN_DEFAULT;
248 } 248 }
249 249
250 #[cfg(feature = "stm32f103c8")]
251 {
252 use embassy_stm32::rcc::*;
253 config.rcc.hse = Some(Hse {
254 freq: Hertz(8_000_000),
255 mode: HseMode::Oscillator,
256 });
257 config.rcc.pll = Some(Pll {
258 src: PllSource::HSE,
259 prediv: PllPreDiv::DIV1,
260 mul: PllMul::MUL9,
261 });
262 config.rcc.sys = Sysclk::PLL1_P;
263 config.rcc.ahb_pre = AHBPrescaler::DIV1;
264 config.rcc.apb1_pre = APBPrescaler::DIV2;
265 config.rcc.apb2_pre = APBPrescaler::DIV1;
266 }
267
250 #[cfg(feature = "stm32f207zg")] 268 #[cfg(feature = "stm32f207zg")]
251 { 269 {
252 use embassy_stm32::rcc::*; 270 use embassy_stm32::rcc::*;