diff options
| author | ragarnoy <[email protected]> | 2025-05-10 10:40:35 +0200 |
|---|---|---|
| committer | ragarnoy <[email protected]> | 2025-05-10 10:40:35 +0200 |
| commit | f28934cb46bd18cf362b988471266e1b7bb9927e (patch) | |
| tree | 68f0226806987fc000dfe85f15a7dc86f6775329 /examples/stm32h755cm4/src/bin/intercore.rs | |
| parent | 04c0bd84e6043ac35d2a20f1f4a789ccf79bb316 (diff) | |
Rewrite documentation and generally improve it
Diffstat (limited to 'examples/stm32h755cm4/src/bin/intercore.rs')
| -rw-r--r-- | examples/stm32h755cm4/src/bin/intercore.rs | 53 |
1 files changed, 31 insertions, 22 deletions
diff --git a/examples/stm32h755cm4/src/bin/intercore.rs b/examples/stm32h755cm4/src/bin/intercore.rs index 3a66a1ecd..715df28d6 100644 --- a/examples/stm32h755cm4/src/bin/intercore.rs +++ b/examples/stm32h755cm4/src/bin/intercore.rs | |||
| @@ -1,18 +1,32 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | // IMPORTANT: This must match EXACTLY the definition in CM7! | 4 | //! STM32H7 Secondary Core (CM4) Intercore Communication Example |
| 5 | //! | ||
| 6 | //! This example demonstrates reliable communication between the Cortex-M7 and | ||
| 7 | //! Cortex-M4 cores. This secondary core monitors shared memory for LED state | ||
| 8 | //! changes and updates the physical LEDs accordingly. | ||
| 9 | //! | ||
| 10 | //! The CM4 core handles: | ||
| 11 | //! - Responding to state changes from CM7 | ||
| 12 | //! - Controlling the physical green and yellow LEDs | ||
| 13 | //! - Providing visual feedback via a heartbeat on the red LED | ||
| 14 | //! | ||
| 15 | //! Usage: | ||
| 16 | //! 1. Flash this CM4 (secondary) core binary first | ||
| 17 | //! 2. Then flash the CM7 (primary) core binary | ||
| 18 | //! 3. The red LED should blink continuously as a heartbeat | ||
| 19 | //! 4. Green and yellow LEDs should toggle according to CM7 core signals | ||
| 20 | |||
| 21 | /// Module providing shared memory constructs for intercore communication | ||
| 5 | mod shared { | 22 | mod shared { |
| 6 | use core::sync::atomic::{AtomicU32, Ordering}; | 23 | use core::sync::atomic::{AtomicU32, Ordering}; |
| 7 | 24 | ||
| 8 | /// Shared LED state between CM7 and CM4 cores | 25 | /// State shared between CM7 and CM4 cores for LED control |
| 9 | #[repr(C, align(4))] | 26 | #[repr(C, align(4))] |
| 10 | pub struct SharedLedState { | 27 | pub struct SharedLedState { |
| 11 | // Magic number for validation | ||
| 12 | pub magic: AtomicU32, | 28 | pub magic: AtomicU32, |
| 13 | // Counter for synchronization testing | ||
| 14 | pub counter: AtomicU32, | 29 | pub counter: AtomicU32, |
| 15 | // LED states packed into a single atomic | ||
| 16 | pub led_states: AtomicU32, | 30 | pub led_states: AtomicU32, |
| 17 | } | 31 | } |
| 18 | 32 | ||
| @@ -23,19 +37,17 @@ mod shared { | |||
| 23 | impl SharedLedState { | 37 | impl SharedLedState { |
| 24 | pub const fn new() -> Self { | 38 | pub const fn new() -> Self { |
| 25 | Self { | 39 | Self { |
| 26 | magic: AtomicU32::new(0xDEADBEEF), // Magic number | 40 | magic: AtomicU32::new(0xDEADBEEF), |
| 27 | counter: AtomicU32::new(0), | 41 | counter: AtomicU32::new(0), |
| 28 | led_states: AtomicU32::new(0), | 42 | led_states: AtomicU32::new(0), |
| 29 | } | 43 | } |
| 30 | } | 44 | } |
| 31 | 45 | ||
| 32 | /// Set LED state using safe bit operations | 46 | /// Set LED state by manipulating the appropriate bit in the led_states field |
| 33 | #[inline(never)] | 47 | #[inline(never)] |
| 34 | #[allow(dead_code)] | 48 | #[allow(dead_code)] |
| 35 | pub fn set_led(&self, is_green: bool, state: bool) { | 49 | pub fn set_led(&self, is_green: bool, state: bool) { |
| 36 | let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT }; | 50 | let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT }; |
| 37 | |||
| 38 | // Use bit operations to avoid complex atomic operations | ||
| 39 | let current = self.led_states.load(Ordering::SeqCst); | 51 | let current = self.led_states.load(Ordering::SeqCst); |
| 40 | 52 | ||
| 41 | let new_value = if state { | 53 | let new_value = if state { |
| @@ -48,7 +60,7 @@ mod shared { | |||
| 48 | core::sync::atomic::fence(Ordering::SeqCst); | 60 | core::sync::atomic::fence(Ordering::SeqCst); |
| 49 | } | 61 | } |
| 50 | 62 | ||
| 51 | /// Get LED state using safe bit operations | 63 | /// Get current LED state |
| 52 | #[inline(never)] | 64 | #[inline(never)] |
| 53 | pub fn get_led(&self, is_green: bool) -> bool { | 65 | pub fn get_led(&self, is_green: bool) -> bool { |
| 54 | let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT }; | 66 | let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT }; |
| @@ -59,7 +71,7 @@ mod shared { | |||
| 59 | (value & (1 << bit)) != 0 | 71 | (value & (1 << bit)) != 0 |
| 60 | } | 72 | } |
| 61 | 73 | ||
| 62 | /// Increment counter safely | 74 | /// Increment counter and return new value |
| 63 | #[inline(never)] | 75 | #[inline(never)] |
| 64 | #[allow(dead_code)] | 76 | #[allow(dead_code)] |
| 65 | pub fn increment_counter(&self) -> u32 { | 77 | pub fn increment_counter(&self) -> u32 { |
| @@ -70,7 +82,7 @@ mod shared { | |||
| 70 | new_value | 82 | new_value |
| 71 | } | 83 | } |
| 72 | 84 | ||
| 73 | /// Get counter without incrementing | 85 | /// Get current counter value |
| 74 | #[inline(never)] | 86 | #[inline(never)] |
| 75 | pub fn get_counter(&self) -> u32 { | 87 | pub fn get_counter(&self) -> u32 { |
| 76 | let value = self.counter.load(Ordering::SeqCst); | 88 | let value = self.counter.load(Ordering::SeqCst); |
| @@ -84,19 +96,18 @@ mod shared { | |||
| 84 | } | 96 | } |
| 85 | 97 | ||
| 86 | use core::mem::MaybeUninit; | 98 | use core::mem::MaybeUninit; |
| 87 | |||
| 88 | use defmt::*; | 99 | use defmt::*; |
| 89 | use embassy_executor::Spawner; | 100 | use embassy_executor::Spawner; |
| 90 | use embassy_stm32::gpio::{Level, Output, Speed}; | 101 | use embassy_stm32::gpio::{Level, Output, Speed}; |
| 91 | use embassy_stm32::SharedData; | 102 | use embassy_stm32::SharedData; |
| 92 | use embassy_time::Timer; | 103 | use embassy_time::Timer; |
| 93 | // Use our shared state from the module | ||
| 94 | use shared::SHARED_LED_STATE; | 104 | use shared::SHARED_LED_STATE; |
| 95 | use {defmt_rtt as _, panic_probe as _}; | 105 | use {defmt_rtt as _, panic_probe as _}; |
| 96 | 106 | ||
| 97 | #[link_section = ".ram_d3"] | 107 | #[link_section = ".ram_d3"] |
| 98 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); | 108 | static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit(); |
| 99 | 109 | ||
| 110 | /// Task that continuously blinks the red LED as a heartbeat indicator | ||
| 100 | #[embassy_executor::task] | 111 | #[embassy_executor::task] |
| 101 | async fn blink_heartbeat(mut led: Output<'static>) { | 112 | async fn blink_heartbeat(mut led: Output<'static>) { |
| 102 | loop { | 113 | loop { |
| @@ -112,11 +123,11 @@ async fn main(spawner: Spawner) -> ! { | |||
| 112 | let p = embassy_stm32::init_secondary(&SHARED_DATA); | 123 | let p = embassy_stm32::init_secondary(&SHARED_DATA); |
| 113 | info!("CM4 core initialized!"); | 124 | info!("CM4 core initialized!"); |
| 114 | 125 | ||
| 115 | // Read the magic value to ensure shared memory is accessible | 126 | // Verify shared memory is accessible |
| 116 | let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst); | 127 | let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst); |
| 117 | info!("CM4: Magic value = 0x{:X}", magic); | 128 | info!("CM4: Magic value = 0x{:X}", magic); |
| 118 | 129 | ||
| 119 | // Initialize LEDs | 130 | // Set up LEDs |
| 120 | let mut green_led = Output::new(p.PB0, Level::Low, Speed::Low); // LD1 | 131 | let mut green_led = Output::new(p.PB0, Level::Low, Speed::Low); // LD1 |
| 121 | let mut yellow_led = Output::new(p.PE1, Level::Low, Speed::Low); // LD2 | 132 | let mut yellow_led = Output::new(p.PE1, Level::Low, Speed::Low); // LD2 |
| 122 | let red_led = Output::new(p.PB14, Level::Low, Speed::Low); // LD3 (heartbeat) | 133 | let red_led = Output::new(p.PB14, Level::Low, Speed::Low); // LD3 (heartbeat) |
| @@ -124,31 +135,30 @@ async fn main(spawner: Spawner) -> ! { | |||
| 124 | // Start heartbeat task | 135 | // Start heartbeat task |
| 125 | unwrap!(spawner.spawn(blink_heartbeat(red_led))); | 136 | unwrap!(spawner.spawn(blink_heartbeat(red_led))); |
| 126 | 137 | ||
| 127 | // Previous values for detecting changes | 138 | // Track previous values to detect changes |
| 128 | let mut prev_green = false; | 139 | let mut prev_green = false; |
| 129 | let mut prev_yellow = false; | 140 | let mut prev_yellow = false; |
| 130 | let mut prev_counter = 0; | 141 | let mut prev_counter = 0; |
| 131 | 142 | ||
| 132 | info!("CM4: Starting main loop"); | 143 | info!("CM4: Starting main loop"); |
| 133 | loop { | 144 | loop { |
| 134 | // Read values from shared memory | 145 | // Read current values from shared memory |
| 135 | let green_state = SHARED_LED_STATE.get_led(true); | 146 | let green_state = SHARED_LED_STATE.get_led(true); |
| 136 | let yellow_state = SHARED_LED_STATE.get_led(false); | 147 | let yellow_state = SHARED_LED_STATE.get_led(false); |
| 137 | let counter = SHARED_LED_STATE.get_counter(); | 148 | let counter = SHARED_LED_STATE.get_counter(); |
| 138 | 149 | ||
| 139 | // Check for state changes | 150 | // Detect changes |
| 140 | let green_changed = green_state != prev_green; | 151 | let green_changed = green_state != prev_green; |
| 141 | let yellow_changed = yellow_state != prev_yellow; | 152 | let yellow_changed = yellow_state != prev_yellow; |
| 142 | let counter_changed = counter != prev_counter; | 153 | let counter_changed = counter != prev_counter; |
| 143 | 154 | ||
| 144 | // If any state changed, log it and update LEDs | 155 | // Update LEDs and logs when values change |
| 145 | if green_changed || yellow_changed || counter_changed { | 156 | if green_changed || yellow_changed || counter_changed { |
| 146 | if counter_changed { | 157 | if counter_changed { |
| 147 | info!("CM4: Counter = {}", counter); | 158 | info!("CM4: Counter = {}", counter); |
| 148 | prev_counter = counter; | 159 | prev_counter = counter; |
| 149 | } | 160 | } |
| 150 | 161 | ||
| 151 | // Update LED states | ||
| 152 | if green_changed { | 162 | if green_changed { |
| 153 | if green_state { | 163 | if green_state { |
| 154 | green_led.set_high(); | 164 | green_led.set_high(); |
| @@ -172,7 +182,6 @@ async fn main(spawner: Spawner) -> ! { | |||
| 172 | } | 182 | } |
| 173 | } | 183 | } |
| 174 | 184 | ||
| 175 | // Poll at a reasonable rate | ||
| 176 | Timer::after_millis(10).await; | 185 | Timer::after_millis(10).await; |
| 177 | } | 186 | } |
| 178 | } | 187 | } |
