From ced789fe084cea1dc5e411064431fd1c95f57a3d Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Mon, 21 Jul 2025 18:00:15 -0700 Subject: [PATCH 1/7] Fix SysCfg hardfault The `SysCfg` peripheral used bit banding to set the APB2 peripheral clock enable bit which fails on an assertion on a G431KBT (have not tested on other chips, but I suspect they would do the same). This takes a mutable reference to `Rcc` in `SysCfg::constrain` and uses safe accessors to enable the clock. Updated and tested the button example which is all that uses SysCfg. ```[INFO ] Configuring PLL (stm32_foc stm32-foc/src/main.rs:132) [INFO ] System clock frequency: 168000000 (stm32_foc stm32-foc/src/main.rs:138) [DEBUG] Write 20007FB0 (stm32g4xx_hal stm32g4xx-hal/src/bb.rs:42) [ERROR] panicked at /Users/fuzz/wave/stm32g4xx-hal/src/bb.rs:44:5: assertion failed: (PERI_ADDRESS_START..=PERI_ADDRESS_END).contains(&addr) (panic_probe panic-probe-1.0.0/src/lib.rs:104) Firmware exited unexpectedly: Multiple Core 0 Frame 0: HardFault_ @ 0x08006394 /Users/fuzz/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cortex-m-rt-0.7.5/src/lib.rs:1103:1 Frame 1: HardFault > @ 0x08005ce2``` --- Embed.toml | 2 ++ examples/button.rs | 4 ++-- src/syscfg.rs | 20 ++++++-------------- 3 files changed, 10 insertions(+), 16 deletions(-) create mode 100644 Embed.toml diff --git a/Embed.toml b/Embed.toml new file mode 100644 index 00000000..74bc2415 --- /dev/null +++ b/Embed.toml @@ -0,0 +1,2 @@ +[default.rtt] +enabled = true diff --git a/examples/button.rs b/examples/button.rs index c3530b90..7b8f41fa 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -53,7 +53,7 @@ fn main() -> ! { let mut dp = stm32::Peripherals::take().expect("cannot take peripherals"); let mut rcc = dp.RCC.constrain(); - let mut syscfg = dp.SYSCFG.constrain(); + let mut syscfg = dp.SYSCFG.constrain(&mut rcc); println!("Led Init"); // Configure PA5 pin to blink LED @@ -80,7 +80,7 @@ fn main() -> ! { println!("Start Loop"); loop { - wfi(); + //wfi(); println!("Check"); if G_LED_ON.load(Ordering::Relaxed) { diff --git a/src/syscfg.rs b/src/syscfg.rs index b13833bb..097f6850 100644 --- a/src/syscfg.rs +++ b/src/syscfg.rs @@ -1,25 +1,17 @@ -use crate::bb; -use crate::stm32::{RCC, SYSCFG}; +use crate::rcc::Rcc; +use crate::stm32::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; + fn constrain(self, rcc: &mut Rcc) -> 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(), 0); - - // Stall the pipeline to work around erratum 2.1.13 (DM00037591) - cortex_m::asm::dsb(); - } + fn constrain(self, rcc: &mut Rcc) -> SysCfg { + // Enable SYSCFG peripheral clock in APB2ENR register + rcc.apb2enr().modify(|_, w| w.syscfgen().set_bit()); SysCfg(self) } From 557637a28aaaf2a70cffaaa5389099b15a8abddf Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Mon, 21 Jul 2025 18:36:01 -0700 Subject: [PATCH 2/7] Update button with workaround for wfi() and debug probes --- examples/button.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/examples/button.rs b/examples/button.rs index 7b8f41fa..f8d8f9f6 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -5,8 +5,7 @@ use stm32g4xx_hal::{ //delay::{DelayExt, SYSTDelayExt}, gpio::{self, ExtiPin, GpioExt, Input, SignalEdge}, rcc::RccExt, - stm32, - stm32::{interrupt, Interrupt}, + stm32::{self, interrupt, Interrupt}, syscfg::SysCfgExt, }; @@ -52,7 +51,21 @@ fn main() -> ! { utils::logger::init(); let mut dp = stm32::Peripherals::take().expect("cannot take peripherals"); + + // Workaround for RTT when using wfi instruction + // Enable the debug sleep bits in DBGMCU, + // then enable DMA peripheral clock in AHB1ENR + dp.DBGMCU.cr().modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_stop().set_bit(); + w.dbg_standby().set_bit() + }); + let mut rcc = dp.RCC.constrain(); + + // Enable an AHB peripheral clock for debug probe with wfi + rcc.ahb1enr().modify(|_, w| w.dma1en().set_bit()); + let mut syscfg = dp.SYSCFG.constrain(&mut rcc); println!("Led Init"); @@ -80,7 +93,7 @@ fn main() -> ! { println!("Start Loop"); loop { - //wfi(); + cortex_m::asm::wfi(); println!("Check"); if G_LED_ON.load(Ordering::Relaxed) { From 033b58ab6fedfb309df041094c499676254724ba Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Mon, 21 Jul 2025 18:38:21 -0700 Subject: [PATCH 3/7] Remove unused import --- examples/button.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/button.rs b/examples/button.rs index f8d8f9f6..1e5c88dd 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -11,7 +11,7 @@ use stm32g4xx_hal::{ use core::cell::RefCell; use core::sync::atomic::{AtomicBool, Ordering}; -use cortex_m::{asm::wfi, interrupt::Mutex}; +use cortex_m::interrupt::Mutex; use cortex_m_rt::entry; type ButtonPin = gpio::PC13; From bac7b62f8842994752f95a3b97270948f20aa79c Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Wed, 13 Aug 2025 13:26:40 -0700 Subject: [PATCH 4/7] Remove DBGMCU register modification from button example which is set automatically by probe-rs --- examples/button.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/examples/button.rs b/examples/button.rs index 1e5c88dd..a1c12a9d 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -52,17 +52,9 @@ fn main() -> ! { let mut dp = stm32::Peripherals::take().expect("cannot take peripherals"); - // Workaround for RTT when using wfi instruction - // Enable the debug sleep bits in DBGMCU, - // then enable DMA peripheral clock in AHB1ENR - dp.DBGMCU.cr().modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_stop().set_bit(); - w.dbg_standby().set_bit() - }); - let mut rcc = dp.RCC.constrain(); + // Workaround for RTT when using wfi instruction // Enable an AHB peripheral clock for debug probe with wfi rcc.ahb1enr().modify(|_, w| w.dma1en().set_bit()); From 15f7fab1ccde8d9a4b10204d8df0ff21667d31d9 Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Wed, 13 Aug 2025 16:37:17 -0700 Subject: [PATCH 5/7] Use rcc Enable and Reset traits rather than direct register access --- src/syscfg.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/syscfg.rs b/src/syscfg.rs index 097f6850..fff1b78d 100644 --- a/src/syscfg.rs +++ b/src/syscfg.rs @@ -1,4 +1,4 @@ -use crate::rcc::Rcc; +use crate::rcc::{Enable, Rcc, Reset}; use crate::stm32::SYSCFG; use core::ops::Deref; @@ -10,8 +10,8 @@ pub trait SysCfgExt { impl SysCfgExt for SYSCFG { fn constrain(self, rcc: &mut Rcc) -> SysCfg { - // Enable SYSCFG peripheral clock in APB2ENR register - rcc.apb2enr().modify(|_, w| w.syscfgen().set_bit()); + SYSCFG::enable(rcc); + SYSCFG::reset(rcc); SysCfg(self) } From eb3aef7144cbe89d1e9b8509a2b7202b7ed6f2ef Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Wed, 13 Aug 2025 17:36:56 -0700 Subject: [PATCH 6/7] Add I2C fast mode plus enable function to SysCfg. Added I2C fast mode plus example using an AS5600 magnetic angle sensor --- Cargo.toml | 21 +++++++-- examples/i2c-fmp-as5600.rs | 92 ++++++++++++++++++++++++++++++++++++++ src/syscfg.rs | 19 ++++++++ 3 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 examples/i2c-fmp-as5600.rs diff --git a/Cargo.toml b/Cargo.toml index 41328b51..fe5c4703 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,7 @@ embedded-sdmmc = "0.3.0" usb-device = { version = "0.3.2", features = ["defmt"] } usbd-serial = "0.2.2" rand = { version = "0.9", default-features = false } +as5600 = "0.8.0" #TODO: Separate feature sets [features] @@ -84,9 +85,23 @@ usb = ["dep:stm32-usbd"] stm32g431 = ["stm32g4/stm32g431", "cat2"] stm32g441 = ["stm32g4/stm32g441", "cat2"] stm32g473 = ["stm32g4/stm32g473", "cat3", "adc3", "adc4", "adc5"] -stm32g474 = ["stm32g4/stm32g474", "cat3", "adc3", "adc4", "adc5", "stm32-hrtim/stm32g474"] +stm32g474 = [ + "stm32g4/stm32g474", + "cat3", + "adc3", + "adc4", + "adc5", + "stm32-hrtim/stm32g474", +] stm32g483 = ["stm32g4/stm32g483", "cat3", "adc3", "adc4", "adc5"] -stm32g484 = ["stm32g4/stm32g484", "cat3", "adc3", "adc4", "adc5", "stm32-hrtim/stm32g484"] +stm32g484 = [ + "stm32g4/stm32g484", + "cat3", + "adc3", + "adc4", + "adc5", + "stm32-hrtim/stm32g484", +] stm32g491 = ["stm32g4/stm32g491", "cat4", "adc3"] stm32g4a1 = ["stm32g4/stm32g4a1", "cat4", "adc3"] @@ -108,7 +123,7 @@ defmt = [ "embedded-hal/defmt-03", "embedded-io/defmt-03", "embedded-test/defmt", - "stm32-hrtim?/defmt" + "stm32-hrtim?/defmt", ] cordic = ["dep:fixed"] adc3 = [] diff --git a/examples/i2c-fmp-as5600.rs b/examples/i2c-fmp-as5600.rs new file mode 100644 index 00000000..aa14425c --- /dev/null +++ b/examples/i2c-fmp-as5600.rs @@ -0,0 +1,92 @@ +//! I2C Fast Mode Plus example with an AS5600 magnetic angle sensor. +//! +//! This example expects the AS5600 to be connected to the I2C bus on PB7 (SDA) and PA15 (SCL), +//! and a 24MHz HSE oscillator to configure the PLL for 168MHz system clock. +//! +//! The I2C bus is configured with Fast Mode Plus (FMP) enabled in SysCfg, and a 1MHz I2C clock rate. +//! +//! ```DEFMT_LOG=debug cargo run --release --example rand --features stm32g431,defmt -- --chip STM32G431KBTx``` + +#![deny(warnings)] +#![deny(unsafe_code)] +#![no_main] +#![no_std] + +use fugit::HertzU32 as Hertz; +use hal::prelude::*; +use hal::rcc::SysClockSrc; +use hal::stm32; +use hal::time::RateExtU32; +use stm32g4xx_hal as hal; +use stm32g4xx_hal::syscfg::SysCfgExt; + +use as5600::As5600; +use cortex_m_rt::entry; + +#[macro_use] +mod utils; +use utils::logger::error; +use utils::logger::info; + +#[entry] +fn main() -> ! { + utils::logger::init(); + + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + //let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); + + let pwr_cfg = dp + .PWR + .constrain() + .vos(stm32g4xx_hal::pwr::VoltageScale::Range1 { enable_boost: true }) + .freeze(); + + let pll_cfg = hal::rcc::PllConfig { + mux: hal::rcc::PllSrc::HSE(Hertz::MHz(24)), + m: hal::rcc::PllMDiv::DIV_2, + n: hal::rcc::PllNMul::MUL_28, + r: Some(hal::rcc::PllRDiv::DIV_2), + q: None, + p: None, + }; + + info!("Configuring PLL"); + let rcc_cfg = hal::rcc::Config::new(SysClockSrc::PLL) + .boost(true) + .pll_cfg(pll_cfg); + + let mut rcc = dp.RCC.freeze(rcc_cfg, pwr_cfg); + info!("System clock frequency: {}", rcc.clocks.sys_clk.to_Hz()); + + let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); + + let sda = gpiob.pb7.into_alternate_open_drain(); + let scl = gpioa.pa15.into_alternate_open_drain(); + + let mut syscfg = dp.SYSCFG.constrain(&mut rcc); + + // Enable Fast Mode Plus for I2C1 + syscfg.i2c_fmp_enable::<1>(true); + + // Configure I2C for 1MHz + let i2c = dp.I2C1.i2c(sda, scl, 1.MHz(), &mut rcc); + + let mut as5600 = As5600::new(i2c); + + loop { + match as5600.angle() { + Ok(angle) => { + // Convert angle to degrees + let angle_degrees = angle as f32 * 360.0 / 4096.0; + info!("Angle: {}°", angle_degrees); + } + Err(e) => match e { + as5600::error::Error::Communication(_) => error!("I2C communication error"), + as5600::error::Error::Status(_error) => error!("AS5600 status error"), + as5600::error::Error::Configuration(_error) => error!("AS5600 configuration error"), + _ => error!("Other AS5600 error"), + }, + } + } +} diff --git a/src/syscfg.rs b/src/syscfg.rs index fff1b78d..2d7f60ba 100644 --- a/src/syscfg.rs +++ b/src/syscfg.rs @@ -27,3 +27,22 @@ impl Deref for SysCfg { &self.0 } } + +impl SysCfg { + /// Enable/disable I2C fast mode plus on the I2C bus index provided as a const generic parameter. + /// + /// Pins that are configured as I2C alternate functions will be configured as fast mode plus. + /// The alternate function mode of the pin must be set before FMP is enabled in SysCfg. + /// + /// When FM+ mode is activated on a pin, the GPIO speed configuration (OSPEEDR) is is ignored and overridden. + /// + pub fn i2c_fmp_enable(&mut self, en: bool) { + match BUS { + 1 => (*self).cfgr1().modify(|_, w| w.i2c1_fmp().bit(en)), + 2 => (*self).cfgr1().modify(|_, w| w.i2c2_fmp().bit(en)), + 3 => (*self).cfgr1().modify(|_, w| w.i2c3_fmp().bit(en)), + 4 => (*self).cfgr1().modify(|_, w| w.i2c4_fmp().bit(en)), + _ => panic!("Invalid I2C bus"), + }; + } +} From 18754c360ae616f137fcbacb3eed70780a9989d5 Mon Sep 17 00:00:00 2001 From: boondockenergy Date: Wed, 13 Aug 2025 17:43:27 -0700 Subject: [PATCH 7/7] Fix typos --- examples/i2c-fmp-as5600.rs | 2 +- src/syscfg.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/i2c-fmp-as5600.rs b/examples/i2c-fmp-as5600.rs index aa14425c..2031558e 100644 --- a/examples/i2c-fmp-as5600.rs +++ b/examples/i2c-fmp-as5600.rs @@ -5,7 +5,7 @@ //! //! The I2C bus is configured with Fast Mode Plus (FMP) enabled in SysCfg, and a 1MHz I2C clock rate. //! -//! ```DEFMT_LOG=debug cargo run --release --example rand --features stm32g431,defmt -- --chip STM32G431KBTx``` +//! ```DEFMT_LOG=debug cargo run --release --example i2c-fmp-as5600 --features stm32g431,defmt -- --chip STM32G431KBTx``` #![deny(warnings)] #![deny(unsafe_code)] diff --git a/src/syscfg.rs b/src/syscfg.rs index 2d7f60ba..8da543a0 100644 --- a/src/syscfg.rs +++ b/src/syscfg.rs @@ -34,7 +34,7 @@ impl SysCfg { /// Pins that are configured as I2C alternate functions will be configured as fast mode plus. /// The alternate function mode of the pin must be set before FMP is enabled in SysCfg. /// - /// When FM+ mode is activated on a pin, the GPIO speed configuration (OSPEEDR) is is ignored and overridden. + /// When FM+ mode is activated on a pin, the GPIO speed configuration (OSPEEDR) is ignored and overridden. /// pub fn i2c_fmp_enable(&mut self, en: bool) { match BUS {