Merge branch 'main' into feat/stm32wba-rcc-pll-support

This commit is contained in:
leftger 2025-07-27 09:38:38 -07:00 committed by GitHub
commit b9e643d5c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 510 additions and 25 deletions

2
.github/ci/book.sh vendored
View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
## on push branch=main ## on push branch=main
## priority -9 ## priority -100
## dedup dequeue ## dedup dequeue
set -euxo pipefail set -euxo pipefail

2
.github/ci/doc.sh vendored
View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
## on push branch=main ## on push branch=main
## priority -10 ## priority -100
## dedup dequeue ## dedup dequeue
set -euxo pipefail set -euxo pipefail

View File

@ -24,7 +24,7 @@ features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6",
[features] [features]
## Enable defmt ## Enable defmt
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03", "defmt?/ip_in_core"] defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"]
## Trace all raw received and transmitted packets using defmt or log. ## Trace all raw received and transmitted packets using defmt or log.
packet-trace = [] packet-trace = []

View File

@ -106,6 +106,7 @@ impl<const SOCK: usize> StackResources<SOCK> {
/// Static IP address configuration. /// Static IP address configuration.
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StaticConfigV4 { pub struct StaticConfigV4 {
/// IP address and subnet mask. /// IP address and subnet mask.
pub address: Ipv4Cidr, pub address: Ipv4Cidr,
@ -118,6 +119,7 @@ pub struct StaticConfigV4 {
/// Static IPv6 address configuration /// Static IPv6 address configuration
#[cfg(feature = "proto-ipv6")] #[cfg(feature = "proto-ipv6")]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct StaticConfigV6 { pub struct StaticConfigV6 {
/// IP address and subnet mask. /// IP address and subnet mask.
pub address: Ipv6Cidr, pub address: Ipv6Cidr,
@ -130,6 +132,7 @@ pub struct StaticConfigV6 {
/// DHCP configuration. /// DHCP configuration.
#[cfg(feature = "dhcpv4")] #[cfg(feature = "dhcpv4")]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub struct DhcpConfig { pub struct DhcpConfig {
/// Maximum lease duration. /// Maximum lease duration.
@ -169,6 +172,7 @@ impl Default for DhcpConfig {
/// Network stack configuration. /// Network stack configuration.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub struct Config { pub struct Config {
/// IPv4 configuration /// IPv4 configuration
@ -220,6 +224,7 @@ impl Config {
/// Network stack IPv4 configuration. /// Network stack IPv4 configuration.
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigV4 { pub enum ConfigV4 {
/// Do not configure IPv4. /// Do not configure IPv4.
#[default] #[default]
@ -234,6 +239,7 @@ pub enum ConfigV4 {
/// Network stack IPv6 configuration. /// Network stack IPv6 configuration.
#[cfg(feature = "proto-ipv6")] #[cfg(feature = "proto-ipv6")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigV6 { pub enum ConfigV6 {
/// Do not configure IPv6. /// Do not configure IPv6.
#[default] #[default]

View File

@ -1599,7 +1599,7 @@ fn main() {
for e in rcc_registers.ir.enums { for e in rcc_registers.ir.enums {
fn is_rcc_name(e: &str) -> bool { fn is_rcc_name(e: &str) -> bool {
match e { match e {
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true, "Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true,
"Timpre" | "Pllrclkpre" => false, "Timpre" | "Pllrclkpre" => false,
e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
_ => false, _ => false,

View File

@ -95,6 +95,18 @@ cfg_if! {
} }
} }
/// Number of samples used for averaging.
pub enum Averaging {
Disabled,
Samples2,
Samples4,
Samples8,
Samples16,
Samples32,
Samples64,
Samples128,
Samples256,
}
impl<'d, T: Instance> Adc<'d, T> { impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: Peri<'d, T>) -> Self { pub fn new(adc: Peri<'d, T>) -> Self {
rcc::enable_and_reset::<T>(); rcc::enable_and_reset::<T>();
@ -225,6 +237,30 @@ impl<'d, T: Instance> Adc<'d, T> {
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
} }
pub fn set_averaging(&mut self, averaging: Averaging) {
let (enable, samples, right_shift) = match averaging {
Averaging::Disabled => (false, 0, 0),
Averaging::Samples2 => (true, 0, 1),
Averaging::Samples4 => (true, 1, 2),
Averaging::Samples8 => (true, 2, 3),
Averaging::Samples16 => (true, 3, 4),
Averaging::Samples32 => (true, 4, 5),
Averaging::Samples64 => (true, 5, 6),
Averaging::Samples128 => (true, 6, 7),
Averaging::Samples256 => (true, 7, 8),
};
T::regs().cfgr2().modify(|reg| {
#[cfg(not(any(adc_g0, adc_u0)))]
reg.set_rovse(enable);
#[cfg(any(adc_g0, adc_u0))]
reg.set_ovse(enable);
#[cfg(any(adc_h5, adc_h7rs))]
reg.set_ovsr(samples.into());
#[cfg(not(any(adc_h5, adc_h7rs)))]
reg.set_ovsr(samples.into());
reg.set_ovss(right_shift.into());
})
}
/* /*
/// Convert a raw sample from the `Temperature` to deg C /// Convert a raw sample from the `Temperature` to deg C
pub fn to_degrees_centigrade(sample: u16) -> f32 { pub fn to_degrees_centigrade(sample: u16) -> f32 {

View File

@ -1,5 +1,8 @@
use core::ops::RangeInclusive; use core::ops::RangeInclusive;
#[cfg(stm32h7rs)]
use stm32_metapac::rcc::vals::Plldivst;
use crate::pac; use crate::pac;
pub use crate::pac::rcc::vals::{ pub use crate::pac::rcc::vals::{
Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
@ -78,6 +81,12 @@ pub struct Pll {
pub divq: Option<PllDiv>, pub divq: Option<PllDiv>,
/// PLL R division factor. If None, PLL R output is disabled. /// PLL R division factor. If None, PLL R output is disabled.
pub divr: Option<PllDiv>, pub divr: Option<PllDiv>,
#[cfg(stm32h7rs)]
/// PLL S division factor. If None, PLL S output is disabled.
pub divs: Option<Plldivst>,
#[cfg(stm32h7rs)]
/// PLL T division factor. If None, PLL T output is disabled.
pub divt: Option<Plldivst>,
} }
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
@ -749,6 +758,12 @@ struct PllOutput {
q: Option<Hertz>, q: Option<Hertz>,
#[allow(dead_code)] #[allow(dead_code)]
r: Option<Hertz>, r: Option<Hertz>,
#[cfg(stm32h7rs)]
#[allow(dead_code)]
s: Option<Hertz>,
#[cfg(stm32h7rs)]
#[allow(dead_code)]
t: Option<Hertz>,
} }
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
@ -767,6 +782,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
p: None, p: None,
q: None, q: None,
r: None, r: None,
#[cfg(stm32h7rs)]
s: None,
#[cfg(stm32h7rs)]
t: None,
}; };
}; };
@ -814,6 +833,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
}); });
let q = config.divq.map(|div| vco_clk / div); let q = config.divq.map(|div| vco_clk / div);
let r = config.divr.map(|div| vco_clk / div); let r = config.divr.map(|div| vco_clk / div);
#[cfg(stm32h7rs)]
let s = config.divs.map(|div| vco_clk / div);
#[cfg(stm32h7rs)]
let t = config.divt.map(|div| vco_clk / div);
#[cfg(stm32h5)] #[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| { RCC.pllcfgr(num).write(|w| {
@ -840,6 +863,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
w.set_divpen(num, p.is_some()); w.set_divpen(num, p.is_some());
w.set_divqen(num, q.is_some()); w.set_divqen(num, q.is_some());
w.set_divren(num, r.is_some()); w.set_divren(num, r.is_some());
#[cfg(stm32h7rs)]
w.set_divsen(num, s.is_some());
#[cfg(stm32h7rs)]
w.set_divten(num, t.is_some());
}); });
} }
@ -850,10 +877,24 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2)); w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2));
}); });
#[cfg(stm32h7rs)]
RCC.plldivr2(num).write(|w| {
w.set_plls(config.divs.unwrap_or(Plldivst::DIV2));
w.set_pllt(config.divt.unwrap_or(Plldivst::DIV2));
});
RCC.cr().modify(|w| w.set_pllon(num, true)); RCC.cr().modify(|w| w.set_pllon(num, true));
while !RCC.cr().read().pllrdy(num) {} while !RCC.cr().read().pllrdy(num) {}
PllOutput { p, q, r } PllOutput {
p,
q,
r,
#[cfg(stm32h7rs)]
s,
#[cfg(stm32h7rs)]
t,
}
} }
fn flash_setup(clk: Hertz, vos: VoltageScale) { fn flash_setup(clk: Hertz, vos: VoltageScale) {

View File

@ -36,13 +36,6 @@ chrono = { version = "^0.4", default-features = false }
grounded = "0.2.0" grounded = "0.2.0"
# cargo build/run # cargo build/run
[profile.dev]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = 3 # <-
overflow-checks = true # <-
# cargo test # cargo test
[profile.test] [profile.test]
@ -55,11 +48,10 @@ overflow-checks = true # <-
# cargo build/run --release # cargo build/run --release
[profile.release] [profile.release]
codegen-units = 1 codegen-units = 16
debug = 2 debug = 2
debug-assertions = false # <- debug-assertions = false # <-
incremental = false incremental = false
lto = 'fat'
opt-level = 3 # <- opt-level = 3 # <-
overflow-checks = false # <- overflow-checks = false # <-

View File

@ -0,0 +1,182 @@
#![no_std]
#![no_main]
//! STM32H7 Secondary Core (CM4) Intercore Communication Example
//!
//! This example demonstrates reliable communication between the Cortex-M7 and
//! Cortex-M4 cores. This secondary core monitors shared memory for LED state
//! changes and updates the physical LEDs accordingly.
//!
//! The CM4 core handles:
//! - Responding to state changes from CM7
//! - Controlling the physical green and yellow LEDs
//! - Providing visual feedback via a heartbeat on the red LED
//!
//! Usage:
//! 1. Flash this CM4 (secondary) core binary first
//! 2. Then flash the CM7 (primary) core binary
//! 3. The red LED should blink continuously as a heartbeat
//! 4. Green and yellow LEDs should toggle according to CM7 core signals
/// Module providing shared memory constructs for intercore communication
mod shared {
use core::sync::atomic::{AtomicU32, Ordering};
/// State shared between CM7 and CM4 cores for LED control
#[repr(C, align(4))]
pub struct SharedLedState {
pub magic: AtomicU32,
pub counter: AtomicU32,
pub led_states: AtomicU32,
}
// Bit positions in led_states
pub const GREEN_LED_BIT: u32 = 0;
pub const YELLOW_LED_BIT: u32 = 1;
impl SharedLedState {
pub const fn new() -> Self {
Self {
magic: AtomicU32::new(0xDEADBEEF),
counter: AtomicU32::new(0),
led_states: AtomicU32::new(0),
}
}
/// Set LED state by manipulating the appropriate bit in the led_states field
#[inline(never)]
#[allow(dead_code)]
pub fn set_led(&self, is_green: bool, state: bool) {
let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
let current = self.led_states.load(Ordering::SeqCst);
let new_value = if state {
current | (1 << bit) // Set bit
} else {
current & !(1 << bit) // Clear bit
};
self.led_states.store(new_value, Ordering::SeqCst);
}
/// Get current LED state
#[inline(never)]
pub fn get_led(&self, is_green: bool) -> bool {
let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
let value = self.led_states.load(Ordering::SeqCst);
(value & (1 << bit)) != 0
}
/// Increment counter and return new value
#[inline(never)]
#[allow(dead_code)]
pub fn increment_counter(&self) -> u32 {
let current = self.counter.load(Ordering::SeqCst);
let new_value = current.wrapping_add(1);
self.counter.store(new_value, Ordering::SeqCst);
new_value
}
/// Get current counter value
#[inline(never)]
pub fn get_counter(&self) -> u32 {
let value = self.counter.load(Ordering::SeqCst);
value
}
}
#[link_section = ".ram_d3"]
pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new();
}
use core::mem::MaybeUninit;
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::SharedData;
use embassy_time::Timer;
use shared::SHARED_LED_STATE;
use {defmt_rtt as _, panic_probe as _};
#[link_section = ".ram_d3"]
static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
/// Task that continuously blinks the red LED as a heartbeat indicator
#[embassy_executor::task]
async fn blink_heartbeat(mut led: Output<'static>) {
loop {
led.toggle();
info!("CM4 heartbeat");
Timer::after_millis(500).await;
}
}
#[embassy_executor::main]
async fn main(spawner: Spawner) -> ! {
// Initialize the secondary core
let p = embassy_stm32::init_secondary(&SHARED_DATA);
info!("CM4 core initialized!");
// Verify shared memory is accessible
let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
info!("CM4: Magic value = 0x{:X}", magic);
// Set up LEDs
let mut green_led = Output::new(p.PB0, Level::Low, Speed::Low); // LD1
let mut yellow_led = Output::new(p.PE1, Level::Low, Speed::Low); // LD2
let red_led = Output::new(p.PB14, Level::Low, Speed::Low); // LD3 (heartbeat)
// Start heartbeat task
unwrap!(spawner.spawn(blink_heartbeat(red_led)));
// Track previous values to detect changes
let mut prev_green = false;
let mut prev_yellow = false;
let mut prev_counter = 0;
info!("CM4: Starting main loop");
loop {
// Read current values from shared memory
let green_state = SHARED_LED_STATE.get_led(true);
let yellow_state = SHARED_LED_STATE.get_led(false);
let counter = SHARED_LED_STATE.get_counter();
// Detect changes
let green_changed = green_state != prev_green;
let yellow_changed = yellow_state != prev_yellow;
let counter_changed = counter != prev_counter;
// Update LEDs and logs when values change
if green_changed || yellow_changed || counter_changed {
if counter_changed {
info!("CM4: Counter = {}", counter);
prev_counter = counter;
}
if green_changed {
if green_state {
green_led.set_high();
info!("CM4: Green LED ON");
} else {
green_led.set_low();
info!("CM4: Green LED OFF");
}
prev_green = green_state;
}
if yellow_changed {
if yellow_state {
yellow_led.set_high();
info!("CM4: Yellow LED ON");
} else {
yellow_led.set_low();
info!("CM4: Yellow LED OFF");
}
prev_yellow = yellow_state;
}
}
Timer::after_millis(10).await;
}
}

View File

@ -35,15 +35,6 @@ static_cell = "2"
chrono = { version = "^0.4", default-features = false } chrono = { version = "^0.4", default-features = false }
grounded = "0.2.0" grounded = "0.2.0"
# cargo build/run
[profile.dev]
codegen-units = 1
debug = 2
debug-assertions = true # <-
incremental = false
opt-level = 3 # <-
overflow-checks = true # <-
# cargo test # cargo test
[profile.test] [profile.test]
codegen-units = 1 codegen-units = 1
@ -55,11 +46,10 @@ overflow-checks = true # <-
# cargo build/run --release # cargo build/run --release
[profile.release] [profile.release]
codegen-units = 1 codegen-units = 16
debug = 2 debug = 2
debug-assertions = false # <- debug-assertions = false # <-
incremental = false incremental = false
lto = 'fat'
opt-level = 3 # <- opt-level = 3 # <-
overflow-checks = false # <- overflow-checks = false # <-

View File

@ -0,0 +1,228 @@
#![no_std]
#![no_main]
//! STM32H7 Primary Core (CM7) Intercore Communication Example
//!
//! This example demonstrates reliable communication between the Cortex-M7 and
//! Cortex-M4 cores using a shared memory region configured as non-cacheable
//! via MPU settings.
//!
//! The CM7 core handles:
//! - MPU configuration to make shared memory non-cacheable
//! - Clock initialization
//! - Toggling LED states in shared memory
//!
//! Usage:
//! 1. Flash the CM4 (secondary) core binary first
//! 2. Then flash this CM7 (primary) core binary
//! 3. The system will start with CM7 toggling LED states and CM4 responding by
//! physically toggling the LEDs
use core::mem::MaybeUninit;
use cortex_m::asm;
use cortex_m::peripheral::MPU;
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::{Config, SharedData};
use embassy_time::Timer;
use shared::{SHARED_LED_STATE, SRAM4_BASE_ADDRESS, SRAM4_REGION_NUMBER, SRAM4_SIZE_LOG2};
use {defmt_rtt as _, panic_probe as _};
/// Module providing shared memory constructs for intercore communication
mod shared {
use core::sync::atomic::{AtomicU32, Ordering};
/// State shared between CM7 and CM4 cores for LED control
#[repr(C, align(4))]
pub struct SharedLedState {
pub magic: AtomicU32,
pub counter: AtomicU32,
pub led_states: AtomicU32,
}
// Bit positions in led_states
pub const GREEN_LED_BIT: u32 = 0;
pub const YELLOW_LED_BIT: u32 = 1;
impl SharedLedState {
pub const fn new() -> Self {
Self {
magic: AtomicU32::new(0xDEADBEEF),
counter: AtomicU32::new(0),
led_states: AtomicU32::new(0),
}
}
/// Set LED state by manipulating the appropriate bit in the led_states field
#[inline(never)]
pub fn set_led(&self, is_green: bool, state: bool) {
let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
let current = self.led_states.load(Ordering::SeqCst);
let new_value = if state {
current | (1 << bit) // Set bit
} else {
current & !(1 << bit) // Clear bit
};
self.led_states.store(new_value, Ordering::SeqCst);
}
/// Get current LED state
#[inline(never)]
#[allow(dead_code)]
pub fn get_led(&self, is_green: bool) -> bool {
let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
let value = self.led_states.load(Ordering::SeqCst);
(value & (1 << bit)) != 0
}
/// Increment counter and return new value
#[inline(never)]
pub fn increment_counter(&self) -> u32 {
let current = self.counter.load(Ordering::SeqCst);
let new_value = current.wrapping_add(1);
self.counter.store(new_value, Ordering::SeqCst);
new_value
}
/// Get current counter value
#[inline(never)]
#[allow(dead_code)]
pub fn get_counter(&self) -> u32 {
let value = self.counter.load(Ordering::SeqCst);
value
}
}
#[link_section = ".ram_d3"]
pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new();
// Memory region constants for MPU configuration
pub const SRAM4_BASE_ADDRESS: u32 = 0x38000000;
pub const SRAM4_SIZE_LOG2: u32 = 15; // 64KB = 2^(15+1)
pub const SRAM4_REGION_NUMBER: u8 = 0;
}
#[link_section = ".ram_d3"]
static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
/// Configure MPU to make SRAM4 region non-cacheable
fn configure_mpu_non_cacheable(mpu: &mut MPU) {
asm::dmb();
unsafe {
// Disable MPU
mpu.ctrl.write(0);
// Configure SRAM4 as non-cacheable
mpu.rnr.write(SRAM4_REGION_NUMBER as u32);
// Set base address with region number
mpu.rbar.write(SRAM4_BASE_ADDRESS | (1 << 4));
// Configure region attributes
let rasr_value: u32 = (SRAM4_SIZE_LOG2 << 1) | // SIZE=15 (64KB)
(1 << 0) | // ENABLE=1
(3 << 24) | // AP=3 (Full access)
(1 << 19) | // TEX=1
(1 << 18); // S=1 (Shareable)
mpu.rasr.write(rasr_value);
// Enable MPU with default memory map as background
mpu.ctrl.write(1 | (1 << 2)); // MPU_ENABLE | PRIVDEFENA
}
asm::dsb();
asm::isb();
info!("MPU configured - SRAM4 set as non-cacheable");
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) -> ! {
// Set up MPU and cache configuration
{
let mut cp = cortex_m::Peripherals::take().unwrap();
let scb = &mut cp.SCB;
// First disable caches
scb.disable_icache();
scb.disable_dcache(&mut cp.CPUID);
// Configure MPU
configure_mpu_non_cacheable(&mut cp.MPU);
// Re-enable caches
scb.enable_icache();
scb.enable_dcache(&mut cp.CPUID);
asm::dsb();
asm::isb();
}
// Configure the clock system
let mut config = Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = Some(Default::default());
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI,
prediv: PllPreDiv::DIV4,
mul: PllMul::MUL50,
divp: Some(PllDiv::DIV2),
divq: Some(PllDiv::DIV8),
divr: None,
});
config.rcc.sys = Sysclk::PLL1_P;
config.rcc.ahb_pre = AHBPrescaler::DIV2;
config.rcc.apb1_pre = APBPrescaler::DIV2;
config.rcc.apb2_pre = APBPrescaler::DIV2;
config.rcc.apb3_pre = APBPrescaler::DIV2;
config.rcc.apb4_pre = APBPrescaler::DIV2;
config.rcc.voltage_scale = VoltageScale::Scale1;
config.rcc.supply_config = SupplyConfig::DirectSMPS;
}
// Initialize the CM7 core
let _p = embassy_stm32::init_primary(config, &SHARED_DATA);
info!("CM7 core initialized with non-cacheable SRAM4!");
// Verify shared memory is accessible
let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
info!("CM7: Magic value = 0x{:X}", magic);
// Initialize LED states
SHARED_LED_STATE.set_led(true, false); // Green LED off
SHARED_LED_STATE.set_led(false, false); // Yellow LED off
// Main loop - periodically toggle LED states
let mut green_state = false;
let mut yellow_state = false;
let mut loop_count = 0;
info!("CM7: Starting main loop");
loop {
loop_count += 1;
let counter = SHARED_LED_STATE.increment_counter();
// Toggle green LED every second
if loop_count % 10 == 0 {
green_state = !green_state;
SHARED_LED_STATE.set_led(true, green_state);
info!("CM7: Counter = {}, Set green LED to {}", counter, green_state);
}
// Toggle yellow LED every 3 seconds
if loop_count % 30 == 0 {
yellow_state = !yellow_state;
SHARED_LED_STATE.set_led(false, yellow_state);
info!("CM7: Counter = {}, Set yellow LED to {}", counter, yellow_state);
}
Timer::after_millis(100).await;
}
}

View File

@ -25,6 +25,8 @@ async fn main(_spawner: Spawner) {
divp: Some(PllDiv::DIV2), divp: Some(PllDiv::DIV2),
divq: None, divq: None,
divr: None, divr: None,
divs: None,
divt: None,
}); });
config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz

View File

@ -41,6 +41,8 @@ async fn main(spawner: Spawner) -> ! {
divp: Some(PllDiv::DIV2), divp: Some(PllDiv::DIV2),
divq: None, divq: None,
divr: None, divr: None,
divs: None,
divt: None,
}); });
config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz

View File

@ -40,6 +40,8 @@ async fn main(_spawner: Spawner) {
divp: Some(PllDiv::DIV1), //600 MHz divp: Some(PllDiv::DIV1), //600 MHz
divq: Some(PllDiv::DIV2), // 300 MHz divq: Some(PllDiv::DIV2), // 300 MHz
divr: Some(PllDiv::DIV2), // 300 MHz divr: Some(PllDiv::DIV2), // 300 MHz
divs: None,
divt: None,
}); });
config.rcc.sys = Sysclk::PLL1_P; // 600 MHz config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz

View File

@ -36,6 +36,8 @@ async fn main(_spawner: Spawner) {
divp: Some(PllDiv::DIV2), divp: Some(PllDiv::DIV2),
divq: None, divq: None,
divr: None, divr: None,
divs: None,
divt: None,
}); });
config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz

View File

@ -681,6 +681,8 @@ pub fn config() -> Config {
divp: Some(PllDiv::DIV2), // 600Mhz divp: Some(PllDiv::DIV2), // 600Mhz
divq: Some(PllDiv::DIV25), // 48Mhz divq: Some(PllDiv::DIV25), // 48Mhz
divr: None, divr: None,
divs: None,
divt: None,
}); });
config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz