diff options
| author | Matous Hybl <[email protected]> | 2021-11-08 23:43:03 +0100 |
|---|---|---|
| committer | Matous Hybl <[email protected]> | 2021-11-11 11:34:09 +0100 |
| commit | c14642cffcd7f6171ecfb107dbbd8a29ec5e2540 (patch) | |
| tree | e40d81aad3aa3abd11c74485b4b71f83e9f47555 | |
| parent | db889da0446833ff219e652bd68c397af858b999 (diff) | |
Add MCO peripheral.
| -rw-r--r-- | embassy-stm32/build.rs | 27 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/h7/mod.rs | 179 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/mco.rs | 32 |
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 @@ | |||
| 1 | use std::collections::HashMap; | ||
| 1 | use std::env; | 2 | use std::env; |
| 2 | use std::fs; | 3 | use std::fs; |
| 3 | use std::path::PathBuf; | 4 | use 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 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use core::marker::PhantomData; |
| 2 | 2 | ||
| 3 | use embassy::util::Unborrow; | 3 | use embassy::util::Unborrow; |
| 4 | use embassy_hal_common::unborrow; | ||
| 5 | use stm32_metapac::rcc::vals::{Mco1, Mco2}; | ||
| 4 | 6 | ||
| 7 | use crate::gpio::sealed::Pin as __GpioPin; | ||
| 8 | use crate::gpio::Pin; | ||
| 5 | use crate::pac::rcc::vals::Timpre; | 9 | use crate::pac::rcc::vals::Timpre; |
| 6 | use crate::pac::{RCC, SYSCFG}; | 10 | use crate::pac::{RCC, SYSCFG}; |
| 7 | use crate::peripherals; | 11 | use crate::peripherals; |
| @@ -508,6 +512,181 @@ impl<'d> Rcc<'d> { | |||
| 508 | } | 512 | } |
| 509 | } | 513 | } |
| 510 | } | 514 | } |
| 515 | pub enum McoClock { | ||
| 516 | Disabled, | ||
| 517 | Bypassed, | ||
| 518 | Divided(u8), | ||
| 519 | } | ||
| 520 | |||
| 521 | impl 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)] | ||
| 537 | pub enum Mco1Source { | ||
| 538 | Hsi, | ||
| 539 | Lse, | ||
| 540 | Hse, | ||
| 541 | Pll1Q, | ||
| 542 | Hsi48, | ||
| 543 | } | ||
| 544 | |||
| 545 | impl Default for Mco1Source { | ||
| 546 | fn default() -> Self { | ||
| 547 | Self::Hsi | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | pub trait McoSource { | ||
| 552 | type Raw; | ||
| 553 | |||
| 554 | fn into_raw(&self) -> Self::Raw; | ||
| 555 | } | ||
| 556 | |||
| 557 | impl 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)] | ||
| 571 | pub enum Mco2Source { | ||
| 572 | SysClk, | ||
| 573 | Pll2Q, | ||
| 574 | Hse, | ||
| 575 | Pll1Q, | ||
| 576 | Csi, | ||
| 577 | Lsi, | ||
| 578 | } | ||
| 579 | |||
| 580 | impl Default for Mco2Source { | ||
| 581 | fn default() -> Self { | ||
| 582 | Self::SysClk | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | impl 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 | |||
| 600 | pub(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 | |||
| 613 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 614 | |||
| 615 | pub trait McoPin<T: McoInstance>: sealed::McoPin<T> + 'static {} | ||
| 616 | |||
| 617 | macro_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 | |||
| 634 | impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre); | ||
| 635 | impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre); | ||
| 636 | |||
| 637 | macro_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 | |||
| 657 | crate::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 | |||
| 666 | pub struct Mco<'d, T: McoInstance> { | ||
| 667 | phantom: PhantomData<&'d mut T>, | ||
| 668 | } | ||
| 669 | |||
| 670 | impl<'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 | ||
| 512 | pub unsafe fn init(config: Config) { | 691 | pub 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"] | ||
| 6 | mod example_common; | ||
| 7 | use embassy::executor::Spawner; | ||
| 8 | use embassy::time::{Duration, Timer}; | ||
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 10 | use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; | ||
| 11 | use embassy_stm32::Peripherals; | ||
| 12 | use embedded_hal::digital::v2::OutputPin; | ||
| 13 | use example_common::*; | ||
| 14 | |||
| 15 | #[embassy::main] | ||
| 16 | async 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 | } | ||
