#![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 } } #[unsafe(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::SharedData; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_time::Timer; use shared::SHARED_LED_STATE; use {defmt_rtt as _, panic_probe as _}; #[unsafe(link_section = ".ram_d3")] static SHARED_DATA: MaybeUninit = 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 spawner.spawn(unwrap!(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; } }