Skip to content

Fix SysCfg hardfault, Add I2C Fast Mode Plus enable method #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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"]

Expand All @@ -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 = []
Expand Down
2 changes: 2 additions & 0 deletions Embed.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[default.rtt]
enabled = true
15 changes: 10 additions & 5 deletions examples/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ use stm32g4xx_hal::{
//delay::{DelayExt, SYSTDelayExt},
gpio::{self, ExtiPin, GpioExt, Input, SignalEdge},
rcc::RccExt,
stm32,
stm32::{interrupt, Interrupt},
stm32::{self, interrupt, Interrupt},
syscfg::SysCfgExt,
};

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<Input>;
Expand Down Expand Up @@ -52,8 +51,14 @@ fn main() -> ! {
utils::logger::init();

let mut dp = stm32::Peripherals::take().expect("cannot take peripherals");

let mut rcc = dp.RCC.constrain();
let mut syscfg = dp.SYSCFG.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());

let mut syscfg = dp.SYSCFG.constrain(&mut rcc);

println!("Led Init");
// Configure PA5 pin to blink LED
Expand All @@ -80,7 +85,7 @@ fn main() -> ! {

println!("Start Loop");
loop {
wfi();
cortex_m::asm::wfi();
println!("Check");

if G_LED_ON.load(Ordering::Relaxed) {
Expand Down
92 changes: 92 additions & 0 deletions examples/i2c-fmp-as5600.rs
Original file line number Diff line number Diff line change
@@ -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 i2c-fmp-as5600 --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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would make sense and be possible to use the HSI so as not to require an external clock source?

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the user figure out if they should pass a 1 here or something else?


// 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"),
},
}
}
}
39 changes: 25 additions & 14 deletions src/syscfg.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
use crate::bb;
use crate::stm32::{RCC, SYSCFG};
use crate::rcc::{Enable, Rcc, Reset};
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 {
SYSCFG::enable(rcc);
SYSCFG::reset(rcc);

SysCfg(self)
}
Expand All @@ -35,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 ignored and overridden.
///
pub fn i2c_fmp_enable<const BUS: u8>(&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"),
};
}
}
Loading