1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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;
}
}
|