aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32h755cm4
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-07-26 11:06:30 +0000
committerGitHub <[email protected]>2025-07-26 11:06:30 +0000
commitc45b6d4a5109330b6980b0a6843b06c65c8ca04c (patch)
tree232532de81a8ffe86fc502c5d7ff5dc254c0449b /examples/stm32h755cm4
parent945529282aee6a9702bb56e368c6e4d2a4dd4a3c (diff)
parenta4676f8b94db9a62752f05595a282afc0fb99288 (diff)
Merge pull request #4184 from Ragarnoy/stm32h755-intercore
Add intercore communication example for STM32H755CM4 and CM7
Diffstat (limited to 'examples/stm32h755cm4')
-rw-r--r--examples/stm32h755cm4/Cargo.toml10
-rw-r--r--examples/stm32h755cm4/src/bin/intercore.rs182
2 files changed, 183 insertions, 9 deletions
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
index eaaeb1ac0..cf324d3df 100644
--- a/examples/stm32h755cm4/Cargo.toml
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -36,13 +36,6 @@ chrono = { version = "^0.4", default-features = false }
36grounded = "0.2.0" 36grounded = "0.2.0"
37 37
38# cargo build/run 38# cargo build/run
39[profile.dev]
40codegen-units = 1
41debug = 2
42debug-assertions = true # <-
43incremental = false
44opt-level = 3 # <-
45overflow-checks = true # <-
46 39
47# cargo test 40# cargo test
48[profile.test] 41[profile.test]
@@ -55,11 +48,10 @@ overflow-checks = true # <-
55 48
56# cargo build/run --release 49# cargo build/run --release
57[profile.release] 50[profile.release]
58codegen-units = 1 51codegen-units = 16
59debug = 2 52debug = 2
60debug-assertions = false # <- 53debug-assertions = false # <-
61incremental = false 54incremental = false
62lto = 'fat'
63opt-level = 3 # <- 55opt-level = 3 # <-
64overflow-checks = false # <- 56overflow-checks = false # <-
65 57
diff --git a/examples/stm32h755cm4/src/bin/intercore.rs b/examples/stm32h755cm4/src/bin/intercore.rs
new file mode 100644
index 000000000..d5e3e7648
--- /dev/null
+++ b/examples/stm32h755cm4/src/bin/intercore.rs
@@ -0,0 +1,182 @@
1#![no_std]
2#![no_main]
3
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
22mod shared {
23 use core::sync::atomic::{AtomicU32, Ordering};
24
25 /// State shared between CM7 and CM4 cores for LED control
26 #[repr(C, align(4))]
27 pub struct SharedLedState {
28 pub magic: AtomicU32,
29 pub counter: AtomicU32,
30 pub led_states: AtomicU32,
31 }
32
33 // Bit positions in led_states
34 pub const GREEN_LED_BIT: u32 = 0;
35 pub const YELLOW_LED_BIT: u32 = 1;
36
37 impl SharedLedState {
38 pub const fn new() -> Self {
39 Self {
40 magic: AtomicU32::new(0xDEADBEEF),
41 counter: AtomicU32::new(0),
42 led_states: AtomicU32::new(0),
43 }
44 }
45
46 /// Set LED state by manipulating the appropriate bit in the led_states field
47 #[inline(never)]
48 #[allow(dead_code)]
49 pub fn set_led(&self, is_green: bool, state: bool) {
50 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
51 let current = self.led_states.load(Ordering::SeqCst);
52
53 let new_value = if state {
54 current | (1 << bit) // Set bit
55 } else {
56 current & !(1 << bit) // Clear bit
57 };
58 self.led_states.store(new_value, Ordering::SeqCst);
59 }
60
61 /// Get current LED state
62 #[inline(never)]
63 pub fn get_led(&self, is_green: bool) -> bool {
64 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
65
66 let value = self.led_states.load(Ordering::SeqCst);
67 (value & (1 << bit)) != 0
68 }
69
70 /// Increment counter and return new value
71 #[inline(never)]
72 #[allow(dead_code)]
73 pub fn increment_counter(&self) -> u32 {
74 let current = self.counter.load(Ordering::SeqCst);
75 let new_value = current.wrapping_add(1);
76 self.counter.store(new_value, Ordering::SeqCst);
77 new_value
78 }
79
80 /// Get current counter value
81 #[inline(never)]
82 pub fn get_counter(&self) -> u32 {
83 let value = self.counter.load(Ordering::SeqCst);
84 value
85 }
86 }
87
88 #[link_section = ".ram_d3"]
89 pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new();
90}
91
92use core::mem::MaybeUninit;
93
94use defmt::*;
95use embassy_executor::Spawner;
96use embassy_stm32::gpio::{Level, Output, Speed};
97use embassy_stm32::SharedData;
98use embassy_time::Timer;
99use shared::SHARED_LED_STATE;
100use {defmt_rtt as _, panic_probe as _};
101
102#[link_section = ".ram_d3"]
103static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
104
105/// Task that continuously blinks the red LED as a heartbeat indicator
106#[embassy_executor::task]
107async fn blink_heartbeat(mut led: Output<'static>) {
108 loop {
109 led.toggle();
110 info!("CM4 heartbeat");
111 Timer::after_millis(500).await;
112 }
113}
114
115#[embassy_executor::main]
116async fn main(spawner: Spawner) -> ! {
117 // Initialize the secondary core
118 let p = embassy_stm32::init_secondary(&SHARED_DATA);
119 info!("CM4 core initialized!");
120
121 // Verify shared memory is accessible
122 let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
123 info!("CM4: Magic value = 0x{:X}", magic);
124
125 // Set up LEDs
126 let mut green_led = Output::new(p.PB0, Level::Low, Speed::Low); // LD1
127 let mut yellow_led = Output::new(p.PE1, Level::Low, Speed::Low); // LD2
128 let red_led = Output::new(p.PB14, Level::Low, Speed::Low); // LD3 (heartbeat)
129
130 // Start heartbeat task
131 unwrap!(spawner.spawn(blink_heartbeat(red_led)));
132
133 // Track previous values to detect changes
134 let mut prev_green = false;
135 let mut prev_yellow = false;
136 let mut prev_counter = 0;
137
138 info!("CM4: Starting main loop");
139 loop {
140 // Read current values from shared memory
141 let green_state = SHARED_LED_STATE.get_led(true);
142 let yellow_state = SHARED_LED_STATE.get_led(false);
143 let counter = SHARED_LED_STATE.get_counter();
144
145 // Detect changes
146 let green_changed = green_state != prev_green;
147 let yellow_changed = yellow_state != prev_yellow;
148 let counter_changed = counter != prev_counter;
149
150 // Update LEDs and logs when values change
151 if green_changed || yellow_changed || counter_changed {
152 if counter_changed {
153 info!("CM4: Counter = {}", counter);
154 prev_counter = counter;
155 }
156
157 if green_changed {
158 if green_state {
159 green_led.set_high();
160 info!("CM4: Green LED ON");
161 } else {
162 green_led.set_low();
163 info!("CM4: Green LED OFF");
164 }
165 prev_green = green_state;
166 }
167
168 if yellow_changed {
169 if yellow_state {
170 yellow_led.set_high();
171 info!("CM4: Yellow LED ON");
172 } else {
173 yellow_led.set_low();
174 info!("CM4: Yellow LED OFF");
175 }
176 prev_yellow = yellow_state;
177 }
178 }
179
180 Timer::after_millis(10).await;
181 }
182}