aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/stm32h755cm4/Cargo.toml17
-rw-r--r--examples/stm32h755cm4/src/bin/intercore.rs181
-rw-r--r--examples/stm32h755cm7/Cargo.toml15
-rw-r--r--examples/stm32h755cm7/src/bin/intercore.rs226
4 files changed, 415 insertions, 24 deletions
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
index 7c17bc766..c6d4996f1 100644
--- a/examples/stm32h755cm4/Cargo.toml
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -15,8 +15,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm
15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
@@ -25,7 +25,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = "0.8.0" 26embedded-nal-async = "0.8.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3" 30rand_core = "0.6.3"
31critical-section = "1.1" 31critical-section = "1.1"
@@ -37,13 +37,6 @@ chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0" 37grounded = "0.2.0"
38 38
39# cargo build/run 39# cargo build/run
40[profile.dev]
41codegen-units = 1
42debug = 2
43debug-assertions = true # <-
44incremental = false
45opt-level = 3 # <-
46overflow-checks = true # <-
47 40
48# cargo test 41# cargo test
49[profile.test] 42[profile.test]
@@ -60,8 +53,8 @@ codegen-units = 1
60debug = 2 53debug = 2
61debug-assertions = false # <- 54debug-assertions = false # <-
62incremental = false 55incremental = false
63lto = 'fat' 56#lto = 'fat'
64opt-level = 3 # <- 57#opt-level = 3 # <-
65overflow-checks = false # <- 58overflow-checks = false # <-
66 59
67# cargo test --release 60# cargo test --release
diff --git a/examples/stm32h755cm4/src/bin/intercore.rs b/examples/stm32h755cm4/src/bin/intercore.rs
new file mode 100644
index 000000000..08cf6c7b9
--- /dev/null
+++ b/examples/stm32h755cm4/src/bin/intercore.rs
@@ -0,0 +1,181 @@
1#![no_std]
2#![no_main]
3
4// IMPORTANT: This must match EXACTLY the definition in CM7!
5mod shared {
6 use core::sync::atomic::{AtomicU32, Ordering};
7
8 /// Shared LED state between CM7 and CM4 cores
9 #[repr(C, align(4))]
10 pub struct SharedLedState {
11 // Magic number for validation
12 pub magic: AtomicU32,
13 // Counter for synchronization testing
14 pub counter: AtomicU32,
15 // LED states packed into a single atomic
16 pub led_states: AtomicU32,
17 }
18
19 // Bit positions in led_states
20 pub const GREEN_LED_BIT: u32 = 0;
21 pub const YELLOW_LED_BIT: u32 = 1;
22
23 impl SharedLedState {
24 pub const fn new() -> Self {
25 Self {
26 magic: AtomicU32::new(0xDEADBEEF), // Magic number
27 counter: AtomicU32::new(0),
28 led_states: AtomicU32::new(0),
29 }
30 }
31
32 /// Set LED state using safe bit operations
33 #[inline(never)]
34 pub fn set_led(&self, is_green: bool, state: bool) {
35 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
36
37 // Use bit operations to avoid complex atomic operations
38 let current = self.led_states.load(Ordering::SeqCst);
39
40 let new_value = if state {
41 current | (1 << bit) // Set bit
42 } else {
43 current & !(1 << bit) // Clear bit
44 };
45
46 self.led_states.store(new_value, Ordering::SeqCst);
47 core::sync::atomic::compiler_fence(Ordering::SeqCst);
48 }
49
50 /// Get LED state using safe bit operations
51 #[inline(never)]
52 pub fn get_led(&self, is_green: bool) -> bool {
53 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
54
55 let value = self.led_states.load(Ordering::SeqCst);
56 core::sync::atomic::compiler_fence(Ordering::SeqCst);
57
58 (value & (1 << bit)) != 0
59 }
60
61 /// Increment counter safely
62 #[inline(never)]
63 pub fn increment_counter(&self) -> u32 {
64 let current = self.counter.load(Ordering::SeqCst);
65 let new_value = current.wrapping_add(1);
66 self.counter.store(new_value, Ordering::SeqCst);
67 core::sync::atomic::compiler_fence(Ordering::SeqCst);
68 new_value
69 }
70
71 /// Get counter without incrementing
72 #[inline(never)]
73 pub fn get_counter(&self) -> u32 {
74 let value = self.counter.load(Ordering::SeqCst);
75 core::sync::atomic::compiler_fence(Ordering::SeqCst);
76 value
77 }
78 }
79
80 #[link_section = ".ram_d3"]
81 pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new();
82
83 // SRAM4 memory region constants for MPU configuration
84 pub const SRAM4_BASE_ADDRESS: u32 = 0x38000000;
85 pub const SRAM4_SIZE_LOG2: u32 = 15; // 64KB = 2^(15+1)
86 pub const SRAM4_REGION_NUMBER: u8 = 0; // MPU region number to use
87}
88
89use core::mem::MaybeUninit;
90use defmt::*;
91use embassy_executor::Spawner;
92use embassy_stm32::gpio::{Level, Output, Speed};
93use embassy_stm32::SharedData;
94use embassy_time::Timer;
95use {defmt_rtt as _, panic_probe as _};
96
97// Use our shared state from the module
98use shared::SHARED_LED_STATE;
99
100#[link_section = ".ram_d3"]
101static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
102
103#[embassy_executor::task]
104async fn blink_heartbeat(mut led: Output<'static>) {
105 loop {
106 led.toggle();
107 info!("CM4 heartbeat");
108 Timer::after_millis(500).await;
109 }
110}
111
112#[embassy_executor::main]
113async fn main(spawner: Spawner) -> ! {
114 // Initialize the secondary core
115 let p = embassy_stm32::init_secondary(&SHARED_DATA);
116 info!("CM4 core initialized!");
117
118 // Read the magic value to ensure shared memory is accessible
119 let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
120 info!("CM4: Magic value = 0x{:X}", magic);
121
122 // Initialize LEDs
123 let mut green_led = Output::new(p.PB0, Level::Low, Speed::Low); // LD1
124 let mut yellow_led = Output::new(p.PE1, Level::Low, Speed::Low); // LD2
125 let red_led = Output::new(p.PB14, Level::Low, Speed::Low); // LD3 (heartbeat)
126
127 // Start heartbeat task
128 unwrap!(spawner.spawn(blink_heartbeat(red_led)));
129
130 // Previous values for detecting changes
131 let mut prev_green = false;
132 let mut prev_yellow = false;
133 let mut prev_counter = 0;
134
135 info!("CM4: Starting main loop");
136 loop {
137 // Read values from shared memory
138 let green_state = SHARED_LED_STATE.get_led(true);
139 let yellow_state = SHARED_LED_STATE.get_led(false);
140 let counter = SHARED_LED_STATE.get_counter();
141
142 // Check for state changes
143 let green_changed = green_state != prev_green;
144 let yellow_changed = yellow_state != prev_yellow;
145 let counter_changed = counter != prev_counter;
146
147 // If any state changed, log it and update LEDs
148 if green_changed || yellow_changed || counter_changed {
149 if counter_changed {
150 info!("CM4: Counter = {}", counter);
151 prev_counter = counter;
152 }
153
154 // Update LED states
155 if green_changed {
156 if green_state {
157 green_led.set_high();
158 info!("CM4: Green LED ON");
159 } else {
160 green_led.set_low();
161 info!("CM4: Green LED OFF");
162 }
163 prev_green = green_state;
164 }
165
166 if yellow_changed {
167 if yellow_state {
168 yellow_led.set_high();
169 info!("CM4: Yellow LED ON");
170 } else {
171 yellow_led.set_low();
172 info!("CM4: Yellow LED OFF");
173 }
174 prev_yellow = yellow_state;
175 }
176 }
177
178 // Poll at a reasonable rate
179 Timer::after_millis(10).await;
180 }
181} \ No newline at end of file
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
index 3186929a8..06a3b06af 100644
--- a/examples/stm32h755cm7/Cargo.toml
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -15,8 +15,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm
15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "1.0.1"
19defmt-rtt = "0.4" 19defmt-rtt = "1.0.0"
20 20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
@@ -25,7 +25,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" } 25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = "0.8.0" 26embedded-nal-async = "0.8.0"
27embedded-io-async = { version = "0.6.1" } 27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] } 28panic-probe = { version = "1.0.0", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false } 29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3" 30rand_core = "0.6.3"
31critical-section = "1.1" 31critical-section = "1.1"
@@ -36,15 +36,6 @@ static_cell = "2"
36chrono = { version = "^0.4", default-features = false } 36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0" 37grounded = "0.2.0"
38 38
39# cargo build/run
40[profile.dev]
41codegen-units = 1
42debug = 2
43debug-assertions = true # <-
44incremental = false
45opt-level = 3 # <-
46overflow-checks = true # <-
47
48# cargo test 39# cargo test
49[profile.test] 40[profile.test]
50codegen-units = 1 41codegen-units = 1
diff --git a/examples/stm32h755cm7/src/bin/intercore.rs b/examples/stm32h755cm7/src/bin/intercore.rs
new file mode 100644
index 000000000..154b1682b
--- /dev/null
+++ b/examples/stm32h755cm7/src/bin/intercore.rs
@@ -0,0 +1,226 @@
1#![no_std]
2#![no_main]
3
4mod shared {
5 use core::sync::atomic::{AtomicU32, Ordering};
6
7 /// Shared LED state between CM7 and CM4 cores
8 #[repr(C, align(4))]
9 pub struct SharedLedState {
10 // Magic number for validation
11 pub magic: AtomicU32,
12 // Counter for synchronization testing
13 pub counter: AtomicU32,
14 // LED states packed into a single atomic
15 pub led_states: AtomicU32,
16 }
17
18 // Bit positions in led_states
19 pub const GREEN_LED_BIT: u32 = 0;
20 pub const YELLOW_LED_BIT: u32 = 1;
21
22 impl SharedLedState {
23 pub const fn new() -> Self {
24 Self {
25 magic: AtomicU32::new(0xDEADBEEF), // Magic number
26 counter: AtomicU32::new(0),
27 led_states: AtomicU32::new(0),
28 }
29 }
30
31 /// Set LED state using safe bit operations
32 #[inline(never)]
33 pub fn set_led(&self, is_green: bool, state: bool) {
34 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
35
36 // Use bit operations to avoid complex atomic operations
37 let current = self.led_states.load(Ordering::SeqCst);
38
39 let new_value = if state {
40 current | (1 << bit) // Set bit
41 } else {
42 current & !(1 << bit) // Clear bit
43 };
44
45 self.led_states.store(new_value, Ordering::SeqCst);
46 core::sync::atomic::compiler_fence(Ordering::SeqCst);
47 }
48
49 /// Get LED state using safe bit operations
50 #[inline(never)]
51 pub fn get_led(&self, is_green: bool) -> bool {
52 let bit = if is_green { GREEN_LED_BIT } else { YELLOW_LED_BIT };
53
54 let value = self.led_states.load(Ordering::SeqCst);
55 core::sync::atomic::compiler_fence(Ordering::SeqCst);
56
57 (value & (1 << bit)) != 0
58 }
59
60 /// Increment counter safely
61 #[inline(never)]
62 pub fn increment_counter(&self) -> u32 {
63 let current = self.counter.load(Ordering::SeqCst);
64 let new_value = current.wrapping_add(1);
65 self.counter.store(new_value, Ordering::SeqCst);
66 core::sync::atomic::compiler_fence(Ordering::SeqCst);
67 new_value
68 }
69
70 /// Get counter without incrementing
71 #[inline(never)]
72 pub fn get_counter(&self) -> u32 {
73 let value = self.counter.load(Ordering::SeqCst);
74 core::sync::atomic::compiler_fence(Ordering::SeqCst);
75 value
76 }
77 }
78
79 #[link_section = ".ram_d3"]
80 pub static SHARED_LED_STATE: SharedLedState = SharedLedState::new();
81
82 // SRAM4 memory region constants for MPU configuration
83 pub const SRAM4_BASE_ADDRESS: u32 = 0x38000000;
84 pub const SRAM4_SIZE_LOG2: u32 = 15; // 64KB = 2^(15+1)
85 pub const SRAM4_REGION_NUMBER: u8 = 0; // MPU region number to use
86}
87
88use core::mem::MaybeUninit;
89use defmt::*;
90use embassy_executor::Spawner;
91use embassy_stm32::{Config, SharedData};
92use embassy_time::Timer;
93use {defmt_rtt as _, panic_probe as _};
94
95// Import cortex_m for MPU configuration
96use cortex_m::peripheral::{MPU, SCB};
97use cortex_m::asm;
98
99// Use our shared state from the module
100use shared::{SHARED_LED_STATE, SRAM4_BASE_ADDRESS, SRAM4_REGION_NUMBER, SRAM4_SIZE_LOG2};
101
102#[link_section = ".ram_d3"]
103static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
104
105// Function to configure MPU with your provided settings
106fn configure_mpu_non_cacheable(mpu: &mut MPU, _scb: &mut SCB) {
107 // Ensure all operations complete before reconfiguring MPU/caches
108 asm::dmb();
109 unsafe {
110 // Disable MPU
111 mpu.ctrl.write(0);
112
113 // Configure SRAM4 as non-cacheable
114 // Set region number (0)
115 mpu.rnr.write(SRAM4_REGION_NUMBER as u32);
116
117 // Set base address (SRAM4 = 0x38000000) with VALID bit and region number
118 mpu.rbar.write(
119 SRAM4_BASE_ADDRESS |
120 (1 << 4) // Region number = 0 (explicit in RBAR)
121 );
122
123 // Configure region attributes:
124 // SIZE=15 (64KB = 2^(15+1))
125 // ENABLE=1
126 // AP=3 (Full access)
127 // TEX=1, S=1, C=0, B=0 (Normal memory, Non-cacheable, Shareable)
128 let rasr_value: u32 = (SRAM4_SIZE_LOG2 << 1) | // SIZE=15 (64KB)
129 (1 << 0) | // ENABLE=1
130 (3 << 24) | // AP=3 (Full access)
131 (1 << 19) | // TEX=1
132 (1 << 18); // S=1 (Shareable)
133
134 mpu.rasr.write(rasr_value);
135
136 // Enable MPU with default memory map as background
137 mpu.ctrl.write(1 | (1 << 2)); // MPU_ENABLE | PRIVDEFENA
138 }
139
140 // Ensure changes are committed
141 asm::dsb();
142 asm::isb();
143
144 info!("MPU configured - SRAM4 set as non-cacheable");
145}
146
147#[embassy_executor::main]
148async fn main(spawner: Spawner) -> ! {
149 // Configure MPU to make SRAM4 non-cacheable
150 {
151 let mut cp = cortex_m::Peripherals::take().unwrap();
152 let mpu = &mut cp.MPU;
153 let scb = &mut cp.SCB;
154
155 // Configure MPU without disabling caches
156 configure_mpu_non_cacheable(mpu, scb);
157 }
158
159 // Configure the clocks
160 let mut config = Config::default();
161 {
162 use embassy_stm32::rcc::*;
163 config.rcc.hsi = Some(HSIPrescaler::DIV1);
164 config.rcc.csi = true;
165 config.rcc.hsi48 = Some(Default::default());
166 config.rcc.pll1 = Some(Pll {
167 source: PllSource::HSI,
168 prediv: PllPreDiv::DIV4,
169 mul: PllMul::MUL50,
170 divp: Some(PllDiv::DIV2),
171 divq: Some(PllDiv::DIV8),
172 divr: None,
173 });
174 config.rcc.sys = Sysclk::PLL1_P;
175 config.rcc.ahb_pre = AHBPrescaler::DIV2;
176 config.rcc.apb1_pre = APBPrescaler::DIV2;
177 config.rcc.apb2_pre = APBPrescaler::DIV2;
178 config.rcc.apb3_pre = APBPrescaler::DIV2;
179 config.rcc.apb4_pre = APBPrescaler::DIV2;
180 config.rcc.voltage_scale = VoltageScale::Scale1;
181 config.rcc.supply_config = SupplyConfig::DirectSMPS;
182 }
183
184 // Initialize the CM7 core
185 let _p = embassy_stm32::init_primary(config, &SHARED_DATA);
186 info!("CM7 core initialized with non-cacheable SRAM4!");
187
188 // Read the magic value to ensure shared memory is accessible
189 let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
190 info!("CM7: Magic value = 0x{:X}", magic);
191
192 // Initialize shared memory state
193 SHARED_LED_STATE.set_led(true, false); // Green LED off
194 SHARED_LED_STATE.set_led(false, false); // Yellow LED off
195
196 // Main loop - update shared memory values
197 let mut green_state = false;
198 let mut yellow_state = false;
199 let mut loop_count = 0;
200
201 info!("CM7: Starting main loop");
202 loop {
203 // Update loop counter
204 loop_count += 1;
205
206 // Update shared counter
207 let counter = SHARED_LED_STATE.increment_counter();
208
209 // Every second, toggle green LED state
210 if loop_count % 10 == 0 {
211 green_state = !green_state;
212 SHARED_LED_STATE.set_led(true, green_state);
213 info!("CM7: Counter = {}, Set green LED to {}", counter, green_state);
214 }
215
216 // Every 3 seconds, toggle yellow LED state
217 if loop_count % 30 == 0 {
218 yellow_state = !yellow_state;
219 SHARED_LED_STATE.set_led(false, yellow_state);
220 info!("CM7: Counter = {}, Set yellow LED to {}", counter, yellow_state);
221 }
222
223 // Wait 100ms before next cycle
224 Timer::after_millis(100).await;
225 }
226} \ No newline at end of file