aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32h755cm7/src/bin/intercore.rs
diff options
context:
space:
mode:
authorleftger <[email protected]>2025-07-27 09:38:38 -0700
committerGitHub <[email protected]>2025-07-27 09:38:38 -0700
commitb9e643d5c2d7192143e91db83b9e8377f0fbcacc (patch)
tree86a695a05ccb70be67613ea742b14094a7aca362 /examples/stm32h755cm7/src/bin/intercore.rs
parent1b3674b30ac2b7deb8e19b132d5ba15351cb8ebd (diff)
parent77a8bc27e9c34e363f321132ebb9e8d8ff684a9f (diff)
Merge branch 'main' into feat/stm32wba-rcc-pll-support
Diffstat (limited to 'examples/stm32h755cm7/src/bin/intercore.rs')
-rw-r--r--examples/stm32h755cm7/src/bin/intercore.rs228
1 files changed, 228 insertions, 0 deletions
diff --git a/examples/stm32h755cm7/src/bin/intercore.rs b/examples/stm32h755cm7/src/bin/intercore.rs
new file mode 100644
index 000000000..a4e1b5ff4
--- /dev/null
+++ b/examples/stm32h755cm7/src/bin/intercore.rs
@@ -0,0 +1,228 @@
1#![no_std]
2#![no_main]
3
4//! STM32H7 Primary Core (CM7) Intercore Communication Example
5//!
6//! This example demonstrates reliable communication between the Cortex-M7 and
7//! Cortex-M4 cores using a shared memory region configured as non-cacheable
8//! via MPU settings.
9//!
10//! The CM7 core handles:
11//! - MPU configuration to make shared memory non-cacheable
12//! - Clock initialization
13//! - Toggling LED states in shared memory
14//!
15//! Usage:
16//! 1. Flash the CM4 (secondary) core binary first
17//! 2. Then flash this CM7 (primary) core binary
18//! 3. The system will start with CM7 toggling LED states and CM4 responding by
19//! physically toggling the LEDs
20
21use core::mem::MaybeUninit;
22
23use cortex_m::asm;
24use cortex_m::peripheral::MPU;
25use defmt::*;
26use embassy_executor::Spawner;
27use embassy_stm32::{Config, SharedData};
28use embassy_time::Timer;
29use shared::{SHARED_LED_STATE, SRAM4_BASE_ADDRESS, SRAM4_REGION_NUMBER, SRAM4_SIZE_LOG2};
30use {defmt_rtt as _, panic_probe as _};
31
32/// Module providing shared memory constructs for intercore communication
33mod shared {
34 use core::sync::atomic::{AtomicU32, Ordering};
35
36 /// State shared between CM7 and CM4 cores for LED control
37 #[repr(C, align(4))]
38 pub struct SharedLedState {
39 pub magic: AtomicU32,
40 pub counter: AtomicU32,
41 pub led_states: AtomicU32,
42 }
43
44 // Bit positions in led_states
45 pub const GREEN_LED_BIT: u32 = 0;
46 pub const YELLOW_LED_BIT: u32 = 1;
47
48 impl SharedLedState {
49 pub const fn new() -> Self {
50 Self {
51 magic: AtomicU32::new(0xDEADBEEF),
52 counter: AtomicU32::new(0),
53 led_states: AtomicU32::new(0),
54 }
55 }
56
57 /// Set LED state by manipulating the appropriate bit in the led_states field
58 #[inline(never)]
59 pub fn set_led(&self, is_green: bool, state: bool) {
60 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
61 let current = self.led_states.load(Ordering::SeqCst);
62
63 let new_value = if state {
64 current | (1 << bit) // Set bit
65 } else {
66 current & !(1 << bit) // Clear bit
67 };
68
69 self.led_states.store(new_value, Ordering::SeqCst);
70 }
71
72 /// Get current LED state
73 #[inline(never)]
74 #[allow(dead_code)]
75 pub fn get_led(&self, is_green: bool) -> bool {
76 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
77
78 let value = self.led_states.load(Ordering::SeqCst);
79 (value & (1 << bit)) != 0
80 }
81
82 /// Increment counter and return new value
83 #[inline(never)]
84 pub fn increment_counter(&self) -> u32 {
85 let current = self.counter.load(Ordering::SeqCst);
86 let new_value = current.wrapping_add(1);
87 self.counter.store(new_value, Ordering::SeqCst);
88 new_value
89 }
90
91 /// Get current counter value
92 #[inline(never)]
93 #[allow(dead_code)]
94 pub fn get_counter(&self) -> u32 {
95 let value = self.counter.load(Ordering::SeqCst);
96 value
97 }
98 }
99
100 #[link_section = ".ram_d3"]
101 pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new();
102
103 // Memory region constants for MPU configuration
104 pub const SRAM4_BASE_ADDRESS: u32 = 0x38000000;
105 pub const SRAM4_SIZE_LOG2: u32 = 15; // 64KB = 2^(15+1)
106 pub const SRAM4_REGION_NUMBER: u8 = 0;
107}
108
109#[link_section = ".ram_d3"]
110static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
111
112/// Configure MPU to make SRAM4 region non-cacheable
113fn configure_mpu_non_cacheable(mpu: &mut MPU) {
114 asm::dmb();
115 unsafe {
116 // Disable MPU
117 mpu.ctrl.write(0);
118
119 // Configure SRAM4 as non-cacheable
120 mpu.rnr.write(SRAM4_REGION_NUMBER as u32);
121
122 // Set base address with region number
123 mpu.rbar.write(SRAM4_BASE_ADDRESS | (1 << 4));
124
125 // Configure region attributes
126 let rasr_value: u32 = (SRAM4_SIZE_LOG2 << 1) | // SIZE=15 (64KB)
127 (1 << 0) | // ENABLE=1
128 (3 << 24) | // AP=3 (Full access)
129 (1 << 19) | // TEX=1
130 (1 << 18); // S=1 (Shareable)
131
132 mpu.rasr.write(rasr_value);
133
134 // Enable MPU with default memory map as background
135 mpu.ctrl.write(1 | (1 << 2)); // MPU_ENABLE | PRIVDEFENA
136 }
137
138 asm::dsb();
139 asm::isb();
140
141 info!("MPU configured - SRAM4 set as non-cacheable");
142}
143
144#[embassy_executor::main]
145async fn main(_spawner: Spawner) -> ! {
146 // Set up MPU and cache configuration
147 {
148 let mut cp = cortex_m::Peripherals::take().unwrap();
149 let scb = &mut cp.SCB;
150
151 // First disable caches
152 scb.disable_icache();
153 scb.disable_dcache(&mut cp.CPUID);
154
155 // Configure MPU
156 configure_mpu_non_cacheable(&mut cp.MPU);
157
158 // Re-enable caches
159 scb.enable_icache();
160 scb.enable_dcache(&mut cp.CPUID);
161 asm::dsb();
162 asm::isb();
163 }
164
165 // Configure the clock system
166 let mut config = Config::default();
167 {
168 use embassy_stm32::rcc::*;
169 config.rcc.hsi = Some(HSIPrescaler::DIV1);
170 config.rcc.csi = true;
171 config.rcc.hsi48 = Some(Default::default());
172 config.rcc.pll1 = Some(Pll {
173 source: PllSource::HSI,
174 prediv: PllPreDiv::DIV4,
175 mul: PllMul::MUL50,
176 divp: Some(PllDiv::DIV2),
177 divq: Some(PllDiv::DIV8),
178 divr: None,
179 });
180 config.rcc.sys = Sysclk::PLL1_P;
181 config.rcc.ahb_pre = AHBPrescaler::DIV2;
182 config.rcc.apb1_pre = APBPrescaler::DIV2;
183 config.rcc.apb2_pre = APBPrescaler::DIV2;
184 config.rcc.apb3_pre = APBPrescaler::DIV2;
185 config.rcc.apb4_pre = APBPrescaler::DIV2;
186 config.rcc.voltage_scale = VoltageScale::Scale1;
187 config.rcc.supply_config = SupplyConfig::DirectSMPS;
188 }
189
190 // Initialize the CM7 core
191 let _p = embassy_stm32::init_primary(config, &SHARED_DATA);
192 info!("CM7 core initialized with non-cacheable SRAM4!");
193
194 // Verify shared memory is accessible
195 let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
196 info!("CM7: Magic value = 0x{:X}", magic);
197
198 // Initialize LED states
199 SHARED_LED_STATE.set_led(true, false); // Green LED off
200 SHARED_LED_STATE.set_led(false, false); // Yellow LED off
201
202 // Main loop - periodically toggle LED states
203 let mut green_state = false;
204 let mut yellow_state = false;
205 let mut loop_count = 0;
206
207 info!("CM7: Starting main loop");
208 loop {
209 loop_count += 1;
210 let counter = SHARED_LED_STATE.increment_counter();
211
212 // Toggle green LED every second
213 if loop_count % 10 == 0 {
214 green_state = !green_state;
215 SHARED_LED_STATE.set_led(true, green_state);
216 info!("CM7: Counter = {}, Set green LED to {}", counter, green_state);
217 }
218
219 // Toggle yellow LED every 3 seconds
220 if loop_count % 30 == 0 {
221 yellow_state = !yellow_state;
222 SHARED_LED_STATE.set_led(false, yellow_state);
223 info!("CM7: Counter = {}, Set yellow LED to {}", counter, yellow_state);
224 }
225
226 Timer::after_millis(100).await;
227 }
228}