aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/book.sh2
-rwxr-xr-x.github/ci/doc.sh2
-rw-r--r--embassy-net/Cargo.toml2
-rw-r--r--embassy-net/src/lib.rs6
-rw-r--r--embassy-stm32/build.rs2
-rw-r--r--embassy-stm32/src/adc/v3.rs36
-rw-r--r--embassy-stm32/src/rcc/h.rs43
-rw-r--r--examples/stm32h755cm4/Cargo.toml10
-rw-r--r--examples/stm32h755cm4/src/bin/intercore.rs182
-rw-r--r--examples/stm32h755cm7/Cargo.toml12
-rw-r--r--examples/stm32h755cm7/src/bin/intercore.rs228
-rw-r--r--examples/stm32h7rs/src/bin/blinky.rs2
-rw-r--r--examples/stm32h7rs/src/bin/eth.rs2
-rw-r--r--examples/stm32h7rs/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32h7rs/src/bin/xspi_memory_mapped.rs2
-rw-r--r--tests/stm32/src/common.rs2
16 files changed, 510 insertions, 25 deletions
diff --git a/.github/ci/book.sh b/.github/ci/book.sh
index 2466f53f5..c91d10d16 100755
--- a/.github/ci/book.sh
+++ b/.github/ci/book.sh
@@ -1,6 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2## on push branch=main 2## on push branch=main
3## priority -9 3## priority -100
4## dedup dequeue 4## dedup dequeue
5 5
6set -euxo pipefail 6set -euxo pipefail
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 9162b37ae..26971afdc 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -1,6 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2## on push branch=main 2## on push branch=main
3## priority -10 3## priority -100
4## dedup dequeue 4## dedup dequeue
5 5
6set -euxo pipefail 6set -euxo pipefail
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 526c8a4b3..a2665c770 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -24,7 +24,7 @@ features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6",
24 24
25[features] 25[features]
26## Enable defmt 26## Enable defmt
27defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03", "defmt?/ip_in_core"] 27defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"]
28 28
29## Trace all raw received and transmitted packets using defmt or log. 29## Trace all raw received and transmitted packets using defmt or log.
30packet-trace = [] 30packet-trace = []
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 693a39ed5..2b1888170 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -106,6 +106,7 @@ impl<const SOCK: usize> StackResources<SOCK> {
106/// Static IP address configuration. 106/// Static IP address configuration.
107#[cfg(feature = "proto-ipv4")] 107#[cfg(feature = "proto-ipv4")]
108#[derive(Debug, Clone, PartialEq, Eq)] 108#[derive(Debug, Clone, PartialEq, Eq)]
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
109pub struct StaticConfigV4 { 110pub struct StaticConfigV4 {
110 /// IP address and subnet mask. 111 /// IP address and subnet mask.
111 pub address: Ipv4Cidr, 112 pub address: Ipv4Cidr,
@@ -118,6 +119,7 @@ pub struct StaticConfigV4 {
118/// Static IPv6 address configuration 119/// Static IPv6 address configuration
119#[cfg(feature = "proto-ipv6")] 120#[cfg(feature = "proto-ipv6")]
120#[derive(Debug, Clone, PartialEq, Eq)] 121#[derive(Debug, Clone, PartialEq, Eq)]
122#[cfg_attr(feature = "defmt", derive(defmt::Format))]
121pub struct StaticConfigV6 { 123pub struct StaticConfigV6 {
122 /// IP address and subnet mask. 124 /// IP address and subnet mask.
123 pub address: Ipv6Cidr, 125 pub address: Ipv6Cidr,
@@ -130,6 +132,7 @@ pub struct StaticConfigV6 {
130/// DHCP configuration. 132/// DHCP configuration.
131#[cfg(feature = "dhcpv4")] 133#[cfg(feature = "dhcpv4")]
132#[derive(Debug, Clone, PartialEq, Eq)] 134#[derive(Debug, Clone, PartialEq, Eq)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133#[non_exhaustive] 136#[non_exhaustive]
134pub struct DhcpConfig { 137pub struct DhcpConfig {
135 /// Maximum lease duration. 138 /// Maximum lease duration.
@@ -169,6 +172,7 @@ impl Default for DhcpConfig {
169 172
170/// Network stack configuration. 173/// Network stack configuration.
171#[derive(Debug, Clone, Default)] 174#[derive(Debug, Clone, Default)]
175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
172#[non_exhaustive] 176#[non_exhaustive]
173pub struct Config { 177pub struct Config {
174 /// IPv4 configuration 178 /// IPv4 configuration
@@ -220,6 +224,7 @@ impl Config {
220/// Network stack IPv4 configuration. 224/// Network stack IPv4 configuration.
221#[cfg(feature = "proto-ipv4")] 225#[cfg(feature = "proto-ipv4")]
222#[derive(Debug, Clone, Default)] 226#[derive(Debug, Clone, Default)]
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
223pub enum ConfigV4 { 228pub enum ConfigV4 {
224 /// Do not configure IPv4. 229 /// Do not configure IPv4.
225 #[default] 230 #[default]
@@ -234,6 +239,7 @@ pub enum ConfigV4 {
234/// Network stack IPv6 configuration. 239/// Network stack IPv6 configuration.
235#[cfg(feature = "proto-ipv6")] 240#[cfg(feature = "proto-ipv6")]
236#[derive(Debug, Clone, Default)] 241#[derive(Debug, Clone, Default)]
242#[cfg_attr(feature = "defmt", derive(defmt::Format))]
237pub enum ConfigV6 { 243pub enum ConfigV6 {
238 /// Do not configure IPv6. 244 /// Do not configure IPv6.
239 #[default] 245 #[default]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index a4ed86bdf..deefb13c1 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -1599,7 +1599,7 @@ fn main() {
1599 for e in rcc_registers.ir.enums { 1599 for e in rcc_registers.ir.enums {
1600 fn is_rcc_name(e: &str) -> bool { 1600 fn is_rcc_name(e: &str) -> bool {
1601 match e { 1601 match e {
1602 "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true, 1602 "Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true,
1603 "Timpre" | "Pllrclkpre" => false, 1603 "Timpre" | "Pllrclkpre" => false,
1604 e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, 1604 e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
1605 _ => false, 1605 _ => false,
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index fd74d5318..a2e42fe52 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -95,6 +95,18 @@ cfg_if! {
95 } 95 }
96} 96}
97 97
98/// Number of samples used for averaging.
99pub enum Averaging {
100 Disabled,
101 Samples2,
102 Samples4,
103 Samples8,
104 Samples16,
105 Samples32,
106 Samples64,
107 Samples128,
108 Samples256,
109}
98impl<'d, T: Instance> Adc<'d, T> { 110impl<'d, T: Instance> Adc<'d, T> {
99 pub fn new(adc: Peri<'d, T>) -> Self { 111 pub fn new(adc: Peri<'d, T>) -> Self {
100 rcc::enable_and_reset::<T>(); 112 rcc::enable_and_reset::<T>();
@@ -225,6 +237,30 @@ impl<'d, T: Instance> Adc<'d, T> {
225 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); 237 T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
226 } 238 }
227 239
240 pub fn set_averaging(&mut self, averaging: Averaging) {
241 let (enable, samples, right_shift) = match averaging {
242 Averaging::Disabled => (false, 0, 0),
243 Averaging::Samples2 => (true, 0, 1),
244 Averaging::Samples4 => (true, 1, 2),
245 Averaging::Samples8 => (true, 2, 3),
246 Averaging::Samples16 => (true, 3, 4),
247 Averaging::Samples32 => (true, 4, 5),
248 Averaging::Samples64 => (true, 5, 6),
249 Averaging::Samples128 => (true, 6, 7),
250 Averaging::Samples256 => (true, 7, 8),
251 };
252 T::regs().cfgr2().modify(|reg| {
253 #[cfg(not(any(adc_g0, adc_u0)))]
254 reg.set_rovse(enable);
255 #[cfg(any(adc_g0, adc_u0))]
256 reg.set_ovse(enable);
257 #[cfg(any(adc_h5, adc_h7rs))]
258 reg.set_ovsr(samples.into());
259 #[cfg(not(any(adc_h5, adc_h7rs)))]
260 reg.set_ovsr(samples.into());
261 reg.set_ovss(right_shift.into());
262 })
263 }
228 /* 264 /*
229 /// Convert a raw sample from the `Temperature` to deg C 265 /// Convert a raw sample from the `Temperature` to deg C
230 pub fn to_degrees_centigrade(sample: u16) -> f32 { 266 pub fn to_degrees_centigrade(sample: u16) -> f32 {
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 383f48874..837210b6a 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -1,5 +1,8 @@
1use core::ops::RangeInclusive; 1use core::ops::RangeInclusive;
2 2
3#[cfg(stm32h7rs)]
4use stm32_metapac::rcc::vals::Plldivst;
5
3use crate::pac; 6use crate::pac;
4pub use crate::pac::rcc::vals::{ 7pub use crate::pac::rcc::vals::{
5 Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk, 8 Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
@@ -78,6 +81,12 @@ pub struct Pll {
78 pub divq: Option<PllDiv>, 81 pub divq: Option<PllDiv>,
79 /// PLL R division factor. If None, PLL R output is disabled. 82 /// PLL R division factor. If None, PLL R output is disabled.
80 pub divr: Option<PllDiv>, 83 pub divr: Option<PllDiv>,
84 #[cfg(stm32h7rs)]
85 /// PLL S division factor. If None, PLL S output is disabled.
86 pub divs: Option<Plldivst>,
87 #[cfg(stm32h7rs)]
88 /// PLL T division factor. If None, PLL T output is disabled.
89 pub divt: Option<Plldivst>,
81} 90}
82 91
83fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { 92fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
@@ -749,6 +758,12 @@ struct PllOutput {
749 q: Option<Hertz>, 758 q: Option<Hertz>,
750 #[allow(dead_code)] 759 #[allow(dead_code)]
751 r: Option<Hertz>, 760 r: Option<Hertz>,
761 #[cfg(stm32h7rs)]
762 #[allow(dead_code)]
763 s: Option<Hertz>,
764 #[cfg(stm32h7rs)]
765 #[allow(dead_code)]
766 t: Option<Hertz>,
752} 767}
753 768
754fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput { 769fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
@@ -767,6 +782,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
767 p: None, 782 p: None,
768 q: None, 783 q: None,
769 r: None, 784 r: None,
785 #[cfg(stm32h7rs)]
786 s: None,
787 #[cfg(stm32h7rs)]
788 t: None,
770 }; 789 };
771 }; 790 };
772 791
@@ -814,6 +833,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
814 }); 833 });
815 let q = config.divq.map(|div| vco_clk / div); 834 let q = config.divq.map(|div| vco_clk / div);
816 let r = config.divr.map(|div| vco_clk / div); 835 let r = config.divr.map(|div| vco_clk / div);
836 #[cfg(stm32h7rs)]
837 let s = config.divs.map(|div| vco_clk / div);
838 #[cfg(stm32h7rs)]
839 let t = config.divt.map(|div| vco_clk / div);
817 840
818 #[cfg(stm32h5)] 841 #[cfg(stm32h5)]
819 RCC.pllcfgr(num).write(|w| { 842 RCC.pllcfgr(num).write(|w| {
@@ -840,6 +863,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
840 w.set_divpen(num, p.is_some()); 863 w.set_divpen(num, p.is_some());
841 w.set_divqen(num, q.is_some()); 864 w.set_divqen(num, q.is_some());
842 w.set_divren(num, r.is_some()); 865 w.set_divren(num, r.is_some());
866 #[cfg(stm32h7rs)]
867 w.set_divsen(num, s.is_some());
868 #[cfg(stm32h7rs)]
869 w.set_divten(num, t.is_some());
843 }); 870 });
844 } 871 }
845 872
@@ -850,10 +877,24 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
850 w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2)); 877 w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2));
851 }); 878 });
852 879
880 #[cfg(stm32h7rs)]
881 RCC.plldivr2(num).write(|w| {
882 w.set_plls(config.divs.unwrap_or(Plldivst::DIV2));
883 w.set_pllt(config.divt.unwrap_or(Plldivst::DIV2));
884 });
885
853 RCC.cr().modify(|w| w.set_pllon(num, true)); 886 RCC.cr().modify(|w| w.set_pllon(num, true));
854 while !RCC.cr().read().pllrdy(num) {} 887 while !RCC.cr().read().pllrdy(num) {}
855 888
856 PllOutput { p, q, r } 889 PllOutput {
890 p,
891 q,
892 r,
893 #[cfg(stm32h7rs)]
894 s,
895 #[cfg(stm32h7rs)]
896 t,
897 }
857} 898}
858 899
859fn flash_setup(clk: Hertz, vos: VoltageScale) { 900fn flash_setup(clk: Hertz, vos: VoltageScale) {
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}
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
index e7fc05948..ac1429f30 100644
--- a/examples/stm32h755cm7/Cargo.toml
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -35,15 +35,6 @@ static_cell = "2"
35chrono = { version = "^0.4", default-features = false } 35chrono = { version = "^0.4", default-features = false }
36grounded = "0.2.0" 36grounded = "0.2.0"
37 37
38# cargo build/run
39[profile.dev]
40codegen-units = 1
41debug = 2
42debug-assertions = true # <-
43incremental = false
44opt-level = 3 # <-
45overflow-checks = true # <-
46
47# cargo test 38# cargo test
48[profile.test] 39[profile.test]
49codegen-units = 1 40codegen-units = 1
@@ -55,11 +46,10 @@ overflow-checks = true # <-
55 46
56# cargo build/run --release 47# cargo build/run --release
57[profile.release] 48[profile.release]
58codegen-units = 1 49codegen-units = 16
59debug = 2 50debug = 2
60debug-assertions = false # <- 51debug-assertions = false # <-
61incremental = false 52incremental = false
62lto = 'fat'
63opt-level = 3 # <- 53opt-level = 3 # <-
64overflow-checks = false # <- 54overflow-checks = false # <-
65 55
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}
diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs
index 137c585b7..5fd50fb15 100644
--- a/examples/stm32h7rs/src/bin/blinky.rs
+++ b/examples/stm32h7rs/src/bin/blinky.rs
@@ -25,6 +25,8 @@ async fn main(_spawner: Spawner) {
25 divp: Some(PllDiv::DIV2), 25 divp: Some(PllDiv::DIV2),
26 divq: None, 26 divq: None,
27 divr: None, 27 divr: None,
28 divs: None,
29 divt: None,
28 }); 30 });
29 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz 31 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
30 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz 32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs
index 6d246bb09..d8002e9ba 100644
--- a/examples/stm32h7rs/src/bin/eth.rs
+++ b/examples/stm32h7rs/src/bin/eth.rs
@@ -41,6 +41,8 @@ async fn main(spawner: Spawner) -> ! {
41 divp: Some(PllDiv::DIV2), 41 divp: Some(PllDiv::DIV2),
42 divq: None, 42 divq: None,
43 divr: None, 43 divr: None,
44 divs: None,
45 divt: None,
44 }); 46 });
45 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz 47 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
46 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz 48 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs
index 56a9884af..23abc3e2f 100644
--- a/examples/stm32h7rs/src/bin/usb_serial.rs
+++ b/examples/stm32h7rs/src/bin/usb_serial.rs
@@ -40,6 +40,8 @@ async fn main(_spawner: Spawner) {
40 divp: Some(PllDiv::DIV1), //600 MHz 40 divp: Some(PllDiv::DIV1), //600 MHz
41 divq: Some(PllDiv::DIV2), // 300 MHz 41 divq: Some(PllDiv::DIV2), // 300 MHz
42 divr: Some(PllDiv::DIV2), // 300 MHz 42 divr: Some(PllDiv::DIV2), // 300 MHz
43 divs: None,
44 divt: None,
43 }); 45 });
44 config.rcc.sys = Sysclk::PLL1_P; // 600 MHz 46 config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz 47 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz
diff --git a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
index 59045ca2e..4c1b450b4 100644
--- a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
+++ b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs
@@ -36,6 +36,8 @@ async fn main(_spawner: Spawner) {
36 divp: Some(PllDiv::DIV2), 36 divp: Some(PllDiv::DIV2),
37 divq: None, 37 divq: None,
38 divr: None, 38 divr: None,
39 divs: None,
40 divt: None,
39 }); 41 });
40 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz 42 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
41 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz 43 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index a4d8048ce..cb63b3374 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -681,6 +681,8 @@ pub fn config() -> Config {
681 divp: Some(PllDiv::DIV2), // 600Mhz 681 divp: Some(PllDiv::DIV2), // 600Mhz
682 divq: Some(PllDiv::DIV25), // 48Mhz 682 divq: Some(PllDiv::DIV25), // 48Mhz
683 divr: None, 683 divr: None,
684 divs: None,
685 divt: None,
684 }); 686 });
685 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz 687 config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
686 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz 688 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz