aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs27
-rw-r--r--embassy-stm32/src/rcc/h7/mod.rs179
-rw-r--r--examples/stm32h7/src/bin/mco.rs32
3 files changed, 230 insertions, 8 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 32115f9a8..517ee57ba 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1,3 +1,4 @@
1use std::collections::HashMap;
1use std::env; 2use std::env;
2use std::fs; 3use std::fs;
3use std::path::PathBuf; 4use std::path::PathBuf;
@@ -14,14 +15,25 @@ fn main() {
14 struct Peripheral { 15 struct Peripheral {
15 kind: String, 16 kind: String,
16 name: String, 17 name: String,
18 version: String,
17 } 19 }
18 20
21 let mut peripheral_version_mapping = HashMap::<String, String>::new();
22 stm32_metapac::peripheral_versions!(
23 ($peri:ident, $version:ident) => {
24 peripheral_version_mapping.insert(stringify!($peri).to_string(), stringify!($version).to_string());
25 println!("cargo:rustc-cfg={}", stringify!($peri));
26 println!("cargo:rustc-cfg={}_{}", stringify!($peri), stringify!($version));
27 };
28 );
29
19 let mut peripherals: Vec<Peripheral> = Vec::new(); 30 let mut peripherals: Vec<Peripheral> = Vec::new();
20 stm32_metapac::peripherals!( 31 stm32_metapac::peripherals!(
21 ($kind:ident, $name:ident) => { 32 ($kind:ident, $name:ident) => {
22 peripherals.push(Peripheral{ 33 peripherals.push(Peripheral{
23 kind: stringify!($kind).to_string(), 34 kind: stringify!($kind).to_string(),
24 name: stringify!($name).to_string(), 35 name: stringify!($name).to_string(),
36 version: peripheral_version_mapping[&stringify!($kind).to_ascii_lowercase()].clone()
25 }); 37 });
26 }; 38 };
27 ); 39 );
@@ -43,7 +55,13 @@ fn main() {
43 55
44 // We *shouldn't* have singletons for these, but the HAL currently requires 56 // We *shouldn't* have singletons for these, but the HAL currently requires
45 // singletons, for using with RccPeripheral to enable/disable clocks to them. 57 // singletons, for using with RccPeripheral to enable/disable clocks to them.
46 //"rcc" => {} 58 "rcc" => {
59 if p.version == "h7" {
60 singletons.push("MCO1".to_string());
61 singletons.push("MCO2".to_string());
62 }
63 singletons.push(p.name.clone());
64 }
47 //"dbgmcu" => {} 65 //"dbgmcu" => {}
48 //"syscfg" => {} 66 //"syscfg" => {}
49 //"dma" => {} 67 //"dma" => {}
@@ -78,13 +96,6 @@ fn main() {
78 ) 96 )
79 .unwrap(); 97 .unwrap();
80 98
81 stm32_metapac::peripheral_versions!(
82 ($peri:ident, $version:ident) => {
83 println!("cargo:rustc-cfg={}", stringify!($peri));
84 println!("cargo:rustc-cfg={}_{}", stringify!($peri), stringify!($version));
85 };
86 );
87
88 let mut s = chip_name.split('_'); 99 let mut s = chip_name.split('_');
89 let mut chip_name: String = s.next().unwrap().to_string(); 100 let mut chip_name: String = s.next().unwrap().to_string();
90 let core_name = if let Some(c) = s.next() { 101 let core_name = if let Some(c) = s.next() {
diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs
index 5567a478b..dc458a8a3 100644
--- a/embassy-stm32/src/rcc/h7/mod.rs
+++ b/embassy-stm32/src/rcc/h7/mod.rs
@@ -1,7 +1,11 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy::util::Unborrow; 3use embassy::util::Unborrow;
4use embassy_hal_common::unborrow;
5use stm32_metapac::rcc::vals::{Mco1, Mco2};
4 6
7use crate::gpio::sealed::Pin as __GpioPin;
8use crate::gpio::Pin;
5use crate::pac::rcc::vals::Timpre; 9use crate::pac::rcc::vals::Timpre;
6use crate::pac::{RCC, SYSCFG}; 10use crate::pac::{RCC, SYSCFG};
7use crate::peripherals; 11use crate::peripherals;
@@ -508,6 +512,181 @@ impl<'d> Rcc<'d> {
508 } 512 }
509 } 513 }
510} 514}
515pub enum McoClock {
516 Disabled,
517 Bypassed,
518 Divided(u8),
519}
520
521impl McoClock {
522 fn into_raw(&self) -> u8 {
523 match self {
524 McoClock::Disabled => 0,
525 McoClock::Bypassed => 1,
526 McoClock::Divided(divisor) => {
527 if *divisor > 15 {
528 panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
529 }
530 *divisor
531 }
532 }
533 }
534}
535
536#[derive(Copy, Clone)]
537pub enum Mco1Source {
538 Hsi,
539 Lse,
540 Hse,
541 Pll1Q,
542 Hsi48,
543}
544
545impl Default for Mco1Source {
546 fn default() -> Self {
547 Self::Hsi
548 }
549}
550
551pub trait McoSource {
552 type Raw;
553
554 fn into_raw(&self) -> Self::Raw;
555}
556
557impl McoSource for Mco1Source {
558 type Raw = Mco1;
559 fn into_raw(&self) -> Self::Raw {
560 match self {
561 Mco1Source::Hsi => Mco1::HSI,
562 Mco1Source::Lse => Mco1::LSE,
563 Mco1Source::Hse => Mco1::HSE,
564 Mco1Source::Pll1Q => Mco1::PLL1_Q,
565 Mco1Source::Hsi48 => Mco1::HSI48,
566 }
567 }
568}
569
570#[derive(Copy, Clone)]
571pub enum Mco2Source {
572 SysClk,
573 Pll2Q,
574 Hse,
575 Pll1Q,
576 Csi,
577 Lsi,
578}
579
580impl Default for Mco2Source {
581 fn default() -> Self {
582 Self::SysClk
583 }
584}
585
586impl McoSource for Mco2Source {
587 type Raw = Mco2;
588 fn into_raw(&self) -> Self::Raw {
589 match self {
590 Mco2Source::SysClk => Mco2::SYSCLK,
591 Mco2Source::Pll2Q => Mco2::PLL2_P,
592 Mco2Source::Hse => Mco2::HSE,
593 Mco2Source::Pll1Q => Mco2::PLL1_P,
594 Mco2Source::Csi => Mco2::CSI,
595 Mco2Source::Lsi => Mco2::LSI,
596 }
597 }
598}
599
600pub(crate) mod sealed {
601 use super::*;
602
603 pub trait McoInstance {
604 type Source;
605 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
606 }
607
608 pub trait McoPin<T: McoInstance>: Pin {
609 fn configure(&mut self);
610 }
611}
612
613pub trait McoInstance: sealed::McoInstance + 'static {}
614
615pub trait McoPin<T: McoInstance>: sealed::McoPin<T> + 'static {}
616
617macro_rules! impl_peri {
618 ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
619 impl sealed::McoInstance for peripherals::$peri {
620 type Source = $source;
621
622 unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
623 RCC.cfgr().modify(|w| {
624 w.$set_source(source);
625 w.$set_prescaler(prescaler);
626 });
627 }
628 }
629
630 impl McoInstance for peripherals::$peri {}
631 };
632}
633
634impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
635impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
636
637macro_rules! impl_pin {
638 ($peri:ident, $pin:ident, $af:expr) => {
639 impl McoPin<peripherals::$peri> for peripherals::$pin {}
640
641 impl sealed::McoPin<peripherals::$peri> for peripherals::$pin {
642 fn configure(&mut self) {
643 critical_section::with(|_| unsafe {
644 self.set_as_af($af, crate::gpio::sealed::AFType::OutputPushPull);
645 self.block().ospeedr().modify(|w| {
646 w.set_ospeedr(
647 self.pin() as usize,
648 crate::pac::gpio::vals::Ospeedr::VERYHIGHSPEED,
649 )
650 });
651 })
652 }
653 }
654 };
655}
656
657crate::pac::peripheral_pins!(
658 ($inst:ident, rcc, RCC, $pin:ident, MCO_1, $af:expr) => {
659 impl_pin!(MCO1, $pin, $af);
660 };
661 ($inst:ident, rcc, RCC, $pin:ident, MCO_2, $af:expr) => {
662 impl_pin!(MCO2, $pin, $af);
663 };
664);
665
666pub struct Mco<'d, T: McoInstance> {
667 phantom: PhantomData<&'d mut T>,
668}
669
670impl<'d, T: McoInstance> Mco<'d, T> {
671 pub fn new(
672 _peri: impl Unborrow<Target = T> + 'd,
673 pin: impl Unborrow<Target = impl McoPin<T>> + 'd,
674 source: impl McoSource<Raw = T::Source>,
675 prescaler: McoClock,
676 ) -> Self {
677 unborrow!(pin);
678
679 unsafe {
680 T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
681 }
682
683 pin.configure();
684
685 Self {
686 phantom: PhantomData,
687 }
688 }
689}
511 690
512pub unsafe fn init(config: Config) { 691pub unsafe fn init(config: Config) {
513 let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false); 692 let mut power = Power::new(<peripherals::PWR as embassy::util::Steal>::steal(), false);
diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs
new file mode 100644
index 000000000..4cecd9b04
--- /dev/null
+++ b/examples/stm32h7/src/bin/mco.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5#[path = "../example_common.rs"]
6mod example_common;
7use embassy::executor::Spawner;
8use embassy::time::{Duration, Timer};
9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::rcc::{Mco, Mco1Source, McoClock};
11use embassy_stm32::Peripherals;
12use embedded_hal::digital::v2::OutputPin;
13use example_common::*;
14
15#[embassy::main]
16async fn main(_spawner: Spawner, p: Peripherals) {
17 info!("Hello World!");
18
19 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
20
21 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(8));
22
23 loop {
24 info!("high");
25 unwrap!(led.set_high());
26 Timer::after(Duration::from_millis(500)).await;
27
28 info!("low");
29 unwrap!(led.set_low());
30 Timer::after(Duration::from_millis(500)).await;
31 }
32}