Skip to content

Add intercore communication example for STM32H755CM4 and CM7 #4184

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
10 changes: 1 addition & 9 deletions examples/stm32h755cm4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ chrono = { version = "^0.4", default-features = false }
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
[profile.test]
Expand All @@ -55,11 +48,10 @@ overflow-checks = true # <-

# cargo build/run --release
[profile.release]
codegen-units = 1
codegen-units = 16
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-

Expand Down
182 changes: 182 additions & 0 deletions examples/stm32h755cm4/src/bin/intercore.rs
Original file line number Diff line number Diff line change
@@ -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;
}
}
12 changes: 1 addition & 11 deletions examples/stm32h755cm7/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,6 @@ static_cell = "2"
chrono = { version = "^0.4", default-features = false }
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
[profile.test]
codegen-units = 1
Expand All @@ -55,11 +46,10 @@ overflow-checks = true # <-

# cargo build/run --release
[profile.release]
codegen-units = 1
codegen-units = 16
debug = 2
debug-assertions = false # <-
incremental = false
lto = 'fat'
opt-level = 3 # <-
overflow-checks = false # <-

Expand Down
Loading