aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs17
-rw-r--r--embassy-stm32/src/rcc/f4.rs165
-rw-r--r--embassy-stm32/src/rcc/l4.rs133
-rw-r--r--examples/stm32f4/src/bin/mco.rs31
-rw-r--r--examples/stm32l4/src/bin/mco.rs27
5 files changed, 371 insertions, 2 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 3780c5a40..481fec677 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -50,10 +50,13 @@ fn main() {
50 // We *shouldn't* have singletons for these, but the HAL currently requires 50 // We *shouldn't* have singletons for these, but the HAL currently requires
51 // singletons, for using with RccPeripheral to enable/disable clocks to them. 51 // singletons, for using with RccPeripheral to enable/disable clocks to them.
52 "rcc" => { 52 "rcc" => {
53 if r.version.starts_with("h7") { 53 if r.version.starts_with("h7") || r.version.starts_with("f4") {
54 singletons.push("MCO1".to_string()); 54 singletons.push("MCO1".to_string());
55 singletons.push("MCO2".to_string()); 55 singletons.push("MCO2".to_string());
56 } 56 }
57 if r.version.starts_with("l4") {
58 singletons.push("MCO".to_string());
59 }
57 singletons.push(p.name.to_string()); 60 singletons.push(p.name.to_string());
58 } 61 }
59 //"dbgmcu" => {} 62 //"dbgmcu" => {}
@@ -258,6 +261,7 @@ fn main() {
258 (("i2c", "SCL"), quote!(crate::i2c::SclPin)), 261 (("i2c", "SCL"), quote!(crate::i2c::SclPin)),
259 (("rcc", "MCO_1"), quote!(crate::rcc::McoPin)), 262 (("rcc", "MCO_1"), quote!(crate::rcc::McoPin)),
260 (("rcc", "MCO_2"), quote!(crate::rcc::McoPin)), 263 (("rcc", "MCO_2"), quote!(crate::rcc::McoPin)),
264 (("rcc", "MCO"), quote!(crate::rcc::McoPin)),
261 (("dcmi", "D0"), quote!(crate::dcmi::D0Pin)), 265 (("dcmi", "D0"), quote!(crate::dcmi::D0Pin)),
262 (("dcmi", "D1"), quote!(crate::dcmi::D1Pin)), 266 (("dcmi", "D1"), quote!(crate::dcmi::D1Pin)),
263 (("dcmi", "D2"), quote!(crate::dcmi::D2Pin)), 267 (("dcmi", "D2"), quote!(crate::dcmi::D2Pin)),
@@ -447,13 +451,22 @@ fn main() {
447 // MCO is special 451 // MCO is special
448 if pin.signal.starts_with("MCO_") { 452 if pin.signal.starts_with("MCO_") {
449 // Supported in H7 only for now 453 // Supported in H7 only for now
450 if regs.version.starts_with("h7") { 454 if regs.version.starts_with("h7") || regs.version.starts_with("f4") {
451 peri = format_ident!("{}", pin.signal.replace("_", "")); 455 peri = format_ident!("{}", pin.signal.replace("_", ""));
452 } else { 456 } else {
453 continue; 457 continue;
454 } 458 }
455 } 459 }
456 460
461 if pin.signal == "MCO" {
462 // Supported in H7 only for now
463 if regs.version.starts_with("l4") {
464 peri = format_ident!("MCO");
465 } else {
466 continue;
467 }
468 }
469
457 g.extend(quote! { 470 g.extend(quote! {
458 pin_trait_impl!(#tr, #peri, #pin_name, #af); 471 pin_trait_impl!(#tr, #peri, #pin_name, #af);
459 }) 472 })
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index 200bcce9c..d0e0d585a 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -1,8 +1,16 @@
1use core::marker::PhantomData;
2
3use embassy_hal_common::into_ref;
4use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
5
1use super::sealed::RccPeripheral; 6use super::sealed::RccPeripheral;
7use crate::gpio::sealed::AFType;
8use crate::gpio::Speed;
2use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; 9use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
3use crate::pac::{FLASH, PWR, RCC}; 10use crate::pac::{FLASH, PWR, RCC};
4use crate::rcc::{set_freqs, Clocks}; 11use crate::rcc::{set_freqs, Clocks};
5use crate::time::Hertz; 12use crate::time::Hertz;
13use crate::{peripherals, Peripheral};
6 14
7/// HSI speed 15/// HSI speed
8pub const HSI_FREQ: Hertz = Hertz(16_000_000); 16pub const HSI_FREQ: Hertz = Hertz(16_000_000);
@@ -96,6 +104,163 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48
96 } 104 }
97} 105}
98 106
107pub enum McoClock {
108 DIV1,
109 DIV2,
110 DIV3,
111 DIV4,
112 DIV5,
113}
114
115impl McoClock {
116 fn into_raw(&self) -> Mcopre {
117 match self {
118 McoClock::DIV1 => Mcopre::DIV1,
119 McoClock::DIV2 => Mcopre::DIV2,
120 McoClock::DIV3 => Mcopre::DIV3,
121 McoClock::DIV4 => Mcopre::DIV4,
122 McoClock::DIV5 => Mcopre::DIV5,
123 }
124 }
125}
126
127#[derive(Copy, Clone)]
128pub enum Mco1Source {
129 Hsi,
130 Lse,
131 Hse,
132 Pll,
133}
134
135impl Default for Mco1Source {
136 fn default() -> Self {
137 Self::Hsi
138 }
139}
140
141pub trait McoSource {
142 type Raw;
143
144 fn into_raw(&self) -> Self::Raw;
145}
146
147impl McoSource for Mco1Source {
148 type Raw = Mco1;
149 fn into_raw(&self) -> Self::Raw {
150 match self {
151 Mco1Source::Hsi => Mco1::HSI,
152 Mco1Source::Lse => Mco1::LSE,
153 Mco1Source::Hse => Mco1::HSE,
154 Mco1Source::Pll => Mco1::PLL,
155 }
156 }
157}
158
159#[derive(Copy, Clone)]
160pub enum Mco2Source {
161 SysClk,
162 Plli2s,
163 Hse,
164 Pll,
165}
166
167impl Default for Mco2Source {
168 fn default() -> Self {
169 Self::SysClk
170 }
171}
172
173impl McoSource for Mco2Source {
174 type Raw = Mco2;
175 fn into_raw(&self) -> Self::Raw {
176 match self {
177 Mco2Source::SysClk => Mco2::SYSCLK,
178 Mco2Source::Plli2s => Mco2::PLLI2S,
179 Mco2Source::Hse => Mco2::HSE,
180 Mco2Source::Pll => Mco2::PLL,
181 }
182 }
183}
184
185pub(crate) mod sealed {
186 use stm32_metapac::rcc::vals::Mcopre;
187 pub trait McoInstance {
188 type Source;
189 unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre);
190 }
191}
192
193pub trait McoInstance: sealed::McoInstance + 'static {}
194
195pin_trait!(McoPin, McoInstance);
196
197impl sealed::McoInstance for peripherals::MCO1 {
198 type Source = Mco1;
199 unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
200 RCC.cfgr().modify(|w| {
201 w.set_mco1(source);
202 w.set_mco1pre(prescaler);
203 });
204 match source {
205 Mco1::PLL => {
206 RCC.cr().modify(|w| w.set_pllon(true));
207 while !RCC.cr().read().pllrdy() {}
208 }
209 Mco1::HSI => {
210 RCC.cr().modify(|w| w.set_hsion(true));
211 while !RCC.cr().read().hsirdy() {}
212 }
213 _ => {}
214 }
215 }
216}
217impl McoInstance for peripherals::MCO1 {}
218
219impl sealed::McoInstance for peripherals::MCO2 {
220 type Source = Mco2;
221 unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
222 RCC.cfgr().modify(|w| {
223 w.set_mco2(source);
224 w.set_mco2pre(prescaler);
225 });
226 match source {
227 Mco2::PLL => {
228 RCC.cr().modify(|w| w.set_pllon(true));
229 while !RCC.cr().read().pllrdy() {}
230 }
231 Mco2::PLLI2S => {
232 RCC.cr().modify(|w| w.set_plli2son(true));
233 while !RCC.cr().read().plli2srdy() {}
234 }
235 _ => {}
236 }
237 }
238}
239impl McoInstance for peripherals::MCO2 {}
240
241pub struct Mco<'d, T: McoInstance> {
242 phantom: PhantomData<&'d mut T>,
243}
244
245impl<'d, T: McoInstance> Mco<'d, T> {
246 pub fn new(
247 _peri: impl Peripheral<P = T> + 'd,
248 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
249 source: impl McoSource<Raw = T::Source>,
250 prescaler: McoClock,
251 ) -> Self {
252 into_ref!(pin);
253
254 critical_section::with(|_| unsafe {
255 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
256 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
257 pin.set_speed(Speed::VeryHigh);
258 });
259
260 Self { phantom: PhantomData }
261 }
262}
263
99unsafe fn flash_setup(sysclk: u32) { 264unsafe fn flash_setup(sysclk: u32) {
100 use crate::pac::flash::vals::Latency; 265 use crate::pac::flash::vals::Latency;
101 266
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index e650490fe..c1bf7d0cd 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -1,7 +1,15 @@
1use core::marker::PhantomData;
2
3use embassy_hal_common::into_ref;
4use stm32_metapac::rcc::vals::{Mcopre, Mcosel};
5
6use crate::gpio::sealed::AFType;
7use crate::gpio::Speed;
1use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; 8use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
2use crate::pac::{FLASH, RCC}; 9use crate::pac::{FLASH, RCC};
3use crate::rcc::{set_freqs, Clocks}; 10use crate::rcc::{set_freqs, Clocks};
4use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::{peripherals, Peripheral};
5 13
6/// HSI speed 14/// HSI speed
7pub const HSI_FREQ: Hertz = Hertz(16_000_000); 15pub const HSI_FREQ: Hertz = Hertz(16_000_000);
@@ -298,6 +306,131 @@ impl Default for Config {
298 } 306 }
299} 307}
300 308
309pub enum McoClock {
310 DIV1,
311 DIV2,
312 DIV4,
313 DIV8,
314 DIV16,
315}
316
317impl McoClock {
318 fn into_raw(&self) -> Mcopre {
319 match self {
320 McoClock::DIV1 => Mcopre::DIV1,
321 McoClock::DIV2 => Mcopre::DIV2,
322 McoClock::DIV4 => Mcopre::DIV4,
323 McoClock::DIV8 => Mcopre::DIV8,
324 McoClock::DIV16 => Mcopre::DIV16,
325 }
326 }
327}
328
329#[derive(Copy, Clone)]
330pub enum Mco1Source {
331 Disabled,
332 Lse,
333 Lsi,
334 Hse,
335 Hsi16,
336 PllClk,
337 SysClk,
338 Msi,
339 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
340 Hsi48,
341}
342
343impl Default for Mco1Source {
344 fn default() -> Self {
345 Self::Hsi16
346 }
347}
348
349pub trait McoSource {
350 type Raw;
351
352 fn into_raw(&self) -> Self::Raw;
353}
354
355impl McoSource for Mco1Source {
356 type Raw = Mcosel;
357 fn into_raw(&self) -> Self::Raw {
358 match self {
359 Mco1Source::Disabled => Mcosel::NOCLOCK,
360 Mco1Source::Lse => Mcosel::LSE,
361 Mco1Source::Lsi => Mcosel::LSI,
362 Mco1Source::Hse => Mcosel::HSE,
363 Mco1Source::Hsi16 => Mcosel::HSI16,
364 Mco1Source::PllClk => Mcosel::PLL,
365 Mco1Source::SysClk => Mcosel::SYSCLK,
366 Mco1Source::Msi => Mcosel::MSI,
367 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
368 Mco1Source::Hsi48 => Mcosel::HSI48,
369 }
370 }
371}
372
373pub(crate) mod sealed {
374 use stm32_metapac::rcc::vals::Mcopre;
375 pub trait McoInstance {
376 type Source;
377 unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre);
378 }
379}
380
381pub trait McoInstance: sealed::McoInstance + 'static {}
382
383pin_trait!(McoPin, McoInstance);
384
385impl sealed::McoInstance for peripherals::MCO {
386 type Source = Mcosel;
387
388 unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
389 RCC.cfgr().modify(|w| {
390 w.set_mcosel(source);
391 w.set_mcopre(prescaler);
392 });
393
394 match source {
395 Mcosel::HSI16 => {
396 RCC.cr().modify(|w| w.set_hsion(true));
397 while !RCC.cr().read().hsirdy() {}
398 }
399 #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
400 Mcosel::HSI48 => {
401 RCC.crrcr().modify(|w| w.set_hsi48on(true));
402 while !RCC.crrcr().read().hsi48rdy() {}
403 }
404 _ => {}
405 }
406 }
407}
408
409impl McoInstance for peripherals::MCO {}
410
411pub struct Mco<'d, T: McoInstance> {
412 phantom: PhantomData<&'d mut T>,
413}
414
415impl<'d, T: McoInstance> Mco<'d, T> {
416 pub fn new(
417 _peri: impl Peripheral<P = T> + 'd,
418 pin: impl Peripheral<P = impl McoPin<T>> + 'd,
419 source: impl McoSource<Raw = T::Source>,
420 prescaler: McoClock,
421 ) -> Self {
422 into_ref!(pin);
423
424 critical_section::with(|_| unsafe {
425 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
426 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
427 pin.set_speed(Speed::VeryHigh);
428 });
429
430 Self { phantom: PhantomData }
431 }
432}
433
301pub(crate) unsafe fn init(config: Config) { 434pub(crate) unsafe fn init(config: Config) {
302 let (sys_clk, sw) = match config.mux { 435 let (sys_clk, sw) = match config.mux {
303 ClockSrc::MSI(range) => { 436 ClockSrc::MSI(range) => {
diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs
new file mode 100644
index 000000000..5d780f94d
--- /dev/null
+++ b/examples/stm32f4/src/bin/mco.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoClock};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default());
15 info!("Hello World!");
16
17
18 let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::DIV1);
19 let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::Pll, McoClock::DIV4);
20 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
21
22 loop {
23 info!("high");
24 led.set_high();
25 Timer::after(Duration::from_millis(300)).await;
26
27 info!("low");
28 led.set_low();
29 Timer::after(Duration::from_millis(300)).await;
30 }
31}
diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs
new file mode 100644
index 000000000..dea0c66e0
--- /dev/null
+++ b/examples/stm32l4/src/bin/mco.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::rcc::{Mco, Mco1Source, McoClock};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default());
15 info!("Hello World!");
16
17 let _mco = Mco::new(p.MCO, p.PA8, Mco1Source::Hsi16, McoClock::DIV1);
18
19 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
20
21 loop {
22 led.set_high();
23 Timer::after(Duration::from_millis(300)).await;
24 led.set_low();
25 Timer::after(Duration::from_millis(300)).await;
26 }
27}