-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Ragarnoy
wants to merge
11
commits into
embassy-rs:main
Choose a base branch
from
Ragarnoy:stm32h755-intercore
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
90404a8
Add intercore communication examples for STM32H755CM4 and CM7, does n…
Ragarnoy cf60b11
rustfmt
Ragarnoy 65f6769
Add #[allow(dead_code] attributes and rename spawner variable
Ragarnoy 6b84bf5
formatting
Ragarnoy f52c776
formatting again
Ragarnoy d9befca
dead code, formatting, ci, we're good
Ragarnoy 04c0bd8
fix release mode that was broken by lto and codegen units (there are …
Ragarnoy f28934c
Rewrite documentation and generally improve it
Ragarnoy ddcf13b
nightly rustfmt really do be my bane rn
Ragarnoy d5c9d1a
Remove unnecessary atomic fences from intercore examples
Ragarnoy a4676f8
Merge branch 'embassy-rs:main' into stm32h755-intercore
Ragarnoy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
#![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); | ||
core::sync::atomic::fence(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); | ||
core::sync::atomic::fence(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); | ||
core::sync::atomic::fence(Ordering::SeqCst); | ||
new_value | ||
} | ||
|
||
/// Get current counter value | ||
#[inline(never)] | ||
pub fn get_counter(&self) -> u32 { | ||
let value = self.counter.load(Ordering::SeqCst); | ||
core::sync::atomic::fence(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; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a bunch of places you do this fence after an atomic operation. I don't think this is necessary (though I could be wrong)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed them, it still works