diff --git a/CHANGELOG.md b/CHANGELOG.md index 871be621..6830dfc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [breaking-change] ADC2 and ADC3 no longer allow access to VREF, VBAT, or the internal temperature measurement (ADC2 and ADC3 do not have an internal connection for these channels) - Improved Serial baudrate calculation to be correct for higher baudrates or lower PCLKs +- Added `SysCfg` wrapper to enforce clock enable for `SYSCFG` +- [breaking-change] gpio::ExtiPin now uses `SysCfg` wrapper instead of `SYSCFG` ### Added diff --git a/examples/analog-stopwatch-with-spi-ssd1306.rs b/examples/analog-stopwatch-with-spi-ssd1306.rs index 4b8507d4..d2221460 100644 --- a/examples/analog-stopwatch-with-spi-ssd1306.rs +++ b/examples/analog-stopwatch-with-spi-ssd1306.rs @@ -13,7 +13,7 @@ extern crate panic_semihosting; extern crate stm32f4xx_hal as hal; use crate::hal::{ - gpio::{gpioa::PA0, Edge, ExtiPin, Input, PullDown}, + gpio::{gpioa::PA0, Edge, Input, PullDown}, interrupt, pac, prelude::*, rcc::{Clocks, Rcc}, @@ -79,11 +79,13 @@ fn main() -> ! { let clocks = setup_clocks(rcc); + let mut syscfg = dp.SYSCFG.constrain(); + let gpioa = dp.GPIOA.split(); let gpioe = dp.GPIOE.split(); let mut board_btn = gpioa.pa0.into_pull_down_input(); - board_btn.make_interrupt_source(&mut dp.SYSCFG); + board_btn.make_interrupt_source(&mut syscfg); board_btn.enable_interrupt(&mut dp.EXTI); board_btn.trigger_on_edge(&mut dp.EXTI, Edge::FALLING); diff --git a/examples/stopwatch-with-ssd1306-and-interrupts.rs b/examples/stopwatch-with-ssd1306-and-interrupts.rs index 1819f1c8..9ef5657d 100644 --- a/examples/stopwatch-with-ssd1306-and-interrupts.rs +++ b/examples/stopwatch-with-ssd1306-and-interrupts.rs @@ -22,7 +22,7 @@ extern crate stm32f4xx_hal as hal; use crate::hal::{ delay::Delay, - gpio::{gpioc::PC13, Edge, ExtiPin, Input, PullUp}, + gpio::{gpioc::PC13, Edge, Input, PullUp}, i2c::I2c, interrupt, prelude::*, @@ -60,8 +60,6 @@ enum StopwatchState { #[entry] fn main() -> ! { if let (Some(mut dp), Some(cp)) = (stm32::Peripherals::take(), cortex_m::Peripherals::take()) { - dp.RCC.apb2enr.write(|w| w.syscfgen().enabled()); - let rcc = dp.RCC.constrain(); let clocks = setup_clocks(rcc); let gpiob = dp.GPIOB.split(); @@ -75,10 +73,12 @@ fn main() -> ! { clocks, ); + let mut syscfg = dp.SYSCFG.constrain(); + // Create a button input with an interrupt let gpioc = dp.GPIOC.split(); let mut board_btn = gpioc.pc13.into_pull_up_input(); - board_btn.make_interrupt_source(&mut dp.SYSCFG); + board_btn.make_interrupt_source(&mut syscfg); board_btn.enable_interrupt(&mut dp.EXTI); board_btn.trigger_on_edge(&mut dp.EXTI, Edge::FALLING); diff --git a/src/gpio.rs b/src/gpio.rs index ee63ed83..7ee14d97 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -2,7 +2,8 @@ use core::marker::PhantomData; -use crate::pac::{EXTI, SYSCFG}; +use crate::pac::EXTI; +use crate::syscfg::SysCfg; /// Extension trait to split a GPIO peripheral in independent pins and registers pub trait GpioExt { @@ -85,7 +86,7 @@ pub enum Edge { /// External Interrupt Pin pub trait ExtiPin { - fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG); + fn make_interrupt_source(&mut self, syscfg: &mut SysCfg); fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge); fn enable_interrupt(&mut self, exti: &mut EXTI); fn disable_interrupt(&mut self, exti: &mut EXTI); @@ -97,7 +98,7 @@ macro_rules! exti_erased { ($PIN:ty, $extigpionr:expr) => { impl ExtiPin for $PIN { /// Make corresponding EXTI line sensitive to this pin - fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG) { + fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) { let offset = 4 * (self.i % 4); match self.i { 0..=3 => { @@ -177,7 +178,7 @@ macro_rules! exti { ($PIN:ty, $extigpionr:expr, $i:expr, $exticri:ident) => { impl ExtiPin for $PIN { /// Configure EXTI Line $i to trigger from this pin. - fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG) { + fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) { let offset = 4 * ($i % 4); syscfg.$exticri.modify(|r, w| unsafe { let mut exticr = r.bits(); @@ -247,7 +248,7 @@ macro_rules! gpio { use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, toggleable}; use crate::pac::$GPIOX; - use crate::{pac::{RCC, EXTI, SYSCFG}, bb}; + use crate::{pac::{RCC, EXTI}, bb, syscfg::SysCfg}; use super::{ Alternate, AlternateOD, Floating, GpioExt, Input, OpenDrain, Output, Speed, PullDown, PullUp, PushPull, AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7, AF8, AF9, AF10, diff --git a/src/lib.rs b/src/lib.rs index 6cdfc9e3..3eaecf6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -178,6 +178,8 @@ pub mod signature; #[cfg(feature = "device-selected")] pub mod spi; #[cfg(feature = "device-selected")] +pub mod syscfg; +#[cfg(feature = "device-selected")] pub mod time; #[cfg(feature = "device-selected")] pub mod timer; diff --git a/src/prelude.rs b/src/prelude.rs index f4dd80fc..89730d9b 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,6 +9,7 @@ pub use embedded_hal::prelude::*; not(any(feature = "stm32f411", feature = "stm32f412", feature = "stm32f401",)) ))] pub use crate::dac::DacExt as _stm32f4xx_hal_dac_DacExt; +pub use crate::gpio::ExtiPin as _stm32f4xx_hal_gpio_ExtiPin; pub use crate::gpio::GpioExt as _stm32f4xx_hal_gpio_GpioExt; pub use crate::i2c::Pins as _stm32f4xx_hal_i2c_Pins; pub use crate::rcc::RccExt as _stm32f4xx_hal_rcc_RccExt; @@ -22,4 +23,5 @@ pub use crate::rcc::RccExt as _stm32f4xx_hal_rcc_RccExt; )) ))] pub use crate::rng::RngExt as _stm32f4xx_hal_rng_RngExt; +pub use crate::syscfg::SysCfgExt as _stm32f4xx_hal_syscfg_SysCfgExt; pub use crate::time::U32Ext as _stm32f4xx_hal_time_U32Ext; diff --git a/src/syscfg.rs b/src/syscfg.rs new file mode 100644 index 00000000..c4a02504 --- /dev/null +++ b/src/syscfg.rs @@ -0,0 +1,34 @@ +use crate::bb; +use crate::stm32::{RCC, SYSCFG}; +use core::ops::Deref; + +/// Extension trait that constrains the `SYSCFG` peripheral +pub trait SysCfgExt { + /// Constrains the `SYSCFG` peripheral so it plays nicely with the other abstractions + fn constrain(self) -> SysCfg; +} + +impl SysCfgExt for SYSCFG { + fn constrain(self) -> SysCfg { + unsafe { + // NOTE(unsafe) this reference will only be used for atomic writes with no side effects. + let rcc = &(*RCC::ptr()); + + // Enable clock. + bb::set(&rcc.apb2enr, 14); + } + + SysCfg(self) + } +} + +pub struct SysCfg(SYSCFG); + +impl Deref for SysCfg { + type Target = SYSCFG; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +}