mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 04:10:25 +00:00
Merge branch 'main' into feat/stm32wba-rcc-pll-support
This commit is contained in:
commit
b9e643d5c2
2
.github/ci/book.sh
vendored
2
.github/ci/book.sh
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
## on push branch=main
|
||||
## priority -9
|
||||
## priority -100
|
||||
## dedup dequeue
|
||||
|
||||
set -euxo pipefail
|
||||
|
2
.github/ci/doc.sh
vendored
2
.github/ci/doc.sh
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
## on push branch=main
|
||||
## priority -10
|
||||
## priority -100
|
||||
## dedup dequeue
|
||||
|
||||
set -euxo pipefail
|
||||
|
@ -24,7 +24,7 @@ features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6",
|
||||
|
||||
[features]
|
||||
## Enable defmt
|
||||
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03", "defmt?/ip_in_core"]
|
||||
defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"]
|
||||
|
||||
## Trace all raw received and transmitted packets using defmt or log.
|
||||
packet-trace = []
|
||||
|
@ -106,6 +106,7 @@ impl<const SOCK: usize> StackResources<SOCK> {
|
||||
/// Static IP address configuration.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct StaticConfigV4 {
|
||||
/// IP address and subnet mask.
|
||||
pub address: Ipv4Cidr,
|
||||
@ -118,6 +119,7 @@ pub struct StaticConfigV4 {
|
||||
/// Static IPv6 address configuration
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct StaticConfigV6 {
|
||||
/// IP address and subnet mask.
|
||||
pub address: Ipv6Cidr,
|
||||
@ -130,6 +132,7 @@ pub struct StaticConfigV6 {
|
||||
/// DHCP configuration.
|
||||
#[cfg(feature = "dhcpv4")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub struct DhcpConfig {
|
||||
/// Maximum lease duration.
|
||||
@ -169,6 +172,7 @@ impl Default for DhcpConfig {
|
||||
|
||||
/// Network stack configuration.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub struct Config {
|
||||
/// IPv4 configuration
|
||||
@ -220,6 +224,7 @@ impl Config {
|
||||
/// Network stack IPv4 configuration.
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ConfigV4 {
|
||||
/// Do not configure IPv4.
|
||||
#[default]
|
||||
@ -234,6 +239,7 @@ pub enum ConfigV4 {
|
||||
/// Network stack IPv6 configuration.
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ConfigV6 {
|
||||
/// Do not configure IPv6.
|
||||
#[default]
|
||||
|
@ -1599,7 +1599,7 @@ fn main() {
|
||||
for e in rcc_registers.ir.enums {
|
||||
fn is_rcc_name(e: &str) -> bool {
|
||||
match e {
|
||||
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true,
|
||||
"Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true,
|
||||
"Timpre" | "Pllrclkpre" => false,
|
||||
e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
|
||||
_ => false,
|
||||
|
@ -95,6 +95,18 @@ cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Number of samples used for averaging.
|
||||
pub enum Averaging {
|
||||
Disabled,
|
||||
Samples2,
|
||||
Samples4,
|
||||
Samples8,
|
||||
Samples16,
|
||||
Samples32,
|
||||
Samples64,
|
||||
Samples128,
|
||||
Samples256,
|
||||
}
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: Peri<'d, T>) -> Self {
|
||||
rcc::enable_and_reset::<T>();
|
||||
@ -225,6 +237,30 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
||||
}
|
||||
|
||||
pub fn set_averaging(&mut self, averaging: Averaging) {
|
||||
let (enable, samples, right_shift) = match averaging {
|
||||
Averaging::Disabled => (false, 0, 0),
|
||||
Averaging::Samples2 => (true, 0, 1),
|
||||
Averaging::Samples4 => (true, 1, 2),
|
||||
Averaging::Samples8 => (true, 2, 3),
|
||||
Averaging::Samples16 => (true, 3, 4),
|
||||
Averaging::Samples32 => (true, 4, 5),
|
||||
Averaging::Samples64 => (true, 5, 6),
|
||||
Averaging::Samples128 => (true, 6, 7),
|
||||
Averaging::Samples256 => (true, 7, 8),
|
||||
};
|
||||
T::regs().cfgr2().modify(|reg| {
|
||||
#[cfg(not(any(adc_g0, adc_u0)))]
|
||||
reg.set_rovse(enable);
|
||||
#[cfg(any(adc_g0, adc_u0))]
|
||||
reg.set_ovse(enable);
|
||||
#[cfg(any(adc_h5, adc_h7rs))]
|
||||
reg.set_ovsr(samples.into());
|
||||
#[cfg(not(any(adc_h5, adc_h7rs)))]
|
||||
reg.set_ovsr(samples.into());
|
||||
reg.set_ovss(right_shift.into());
|
||||
})
|
||||
}
|
||||
/*
|
||||
/// Convert a raw sample from the `Temperature` to deg C
|
||||
pub fn to_degrees_centigrade(sample: u16) -> f32 {
|
||||
|
@ -1,5 +1,8 @@
|
||||
use core::ops::RangeInclusive;
|
||||
|
||||
#[cfg(stm32h7rs)]
|
||||
use stm32_metapac::rcc::vals::Plldivst;
|
||||
|
||||
use crate::pac;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
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 {
|
||||
pub divq: Option<PllDiv>,
|
||||
/// PLL R division factor. If None, PLL R output is disabled.
|
||||
pub divr: Option<PllDiv>,
|
||||
#[cfg(stm32h7rs)]
|
||||
/// PLL S division factor. If None, PLL S output is disabled.
|
||||
pub divs: Option<Plldivst>,
|
||||
#[cfg(stm32h7rs)]
|
||||
/// PLL T division factor. If None, PLL T output is disabled.
|
||||
pub divt: Option<Plldivst>,
|
||||
}
|
||||
|
||||
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
|
||||
@ -749,6 +758,12 @@ struct PllOutput {
|
||||
q: Option<Hertz>,
|
||||
#[allow(dead_code)]
|
||||
r: Option<Hertz>,
|
||||
#[cfg(stm32h7rs)]
|
||||
#[allow(dead_code)]
|
||||
s: Option<Hertz>,
|
||||
#[cfg(stm32h7rs)]
|
||||
#[allow(dead_code)]
|
||||
t: Option<Hertz>,
|
||||
}
|
||||
|
||||
fn 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 {
|
||||
p: None,
|
||||
q: None,
|
||||
r: None,
|
||||
#[cfg(stm32h7rs)]
|
||||
s: None,
|
||||
#[cfg(stm32h7rs)]
|
||||
t: None,
|
||||
};
|
||||
};
|
||||
|
||||
@ -814,6 +833,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||
});
|
||||
let q = config.divq.map(|div| vco_clk / div);
|
||||
let r = config.divr.map(|div| vco_clk / div);
|
||||
#[cfg(stm32h7rs)]
|
||||
let s = config.divs.map(|div| vco_clk / div);
|
||||
#[cfg(stm32h7rs)]
|
||||
let t = config.divt.map(|div| vco_clk / div);
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
RCC.pllcfgr(num).write(|w| {
|
||||
@ -840,6 +863,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||
w.set_divpen(num, p.is_some());
|
||||
w.set_divqen(num, q.is_some());
|
||||
w.set_divren(num, r.is_some());
|
||||
#[cfg(stm32h7rs)]
|
||||
w.set_divsen(num, s.is_some());
|
||||
#[cfg(stm32h7rs)]
|
||||
w.set_divten(num, t.is_some());
|
||||
});
|
||||
}
|
||||
|
||||
@ -850,10 +877,24 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||
w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2));
|
||||
});
|
||||
|
||||
#[cfg(stm32h7rs)]
|
||||
RCC.plldivr2(num).write(|w| {
|
||||
w.set_plls(config.divs.unwrap_or(Plldivst::DIV2));
|
||||
w.set_pllt(config.divt.unwrap_or(Plldivst::DIV2));
|
||||
});
|
||||
|
||||
RCC.cr().modify(|w| w.set_pllon(num, true));
|
||||
while !RCC.cr().read().pllrdy(num) {}
|
||||
|
||||
PllOutput { p, q, r }
|
||||
PllOutput {
|
||||
p,
|
||||
q,
|
||||
r,
|
||||
#[cfg(stm32h7rs)]
|
||||
s,
|
||||
#[cfg(stm32h7rs)]
|
||||
t,
|
||||
}
|
||||
}
|
||||
|
||||
fn flash_setup(clk: Hertz, vos: VoltageScale) {
|
||||
|
@ -36,13 +36,6 @@ chrono = { version = "^0.4", default-features = false }
|
||||
grounded = "0.2.0"
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
@ -55,11 +48,10 @@ overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
codegen-units = 16
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
|
182
examples/stm32h755cm4/src/bin/intercore.rs
Normal file
182
examples/stm32h755cm4/src/bin/intercore.rs
Normal file
@ -0,0 +1,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;
|
||||
}
|
||||
}
|
@ -35,15 +35,6 @@ static_cell = "2"
|
||||
chrono = { version = "^0.4", default-features = false }
|
||||
grounded = "0.2.0"
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
@ -55,11 +46,10 @@ overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
codegen-units = 16
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
|
228
examples/stm32h755cm7/src/bin/intercore.rs
Normal file
228
examples/stm32h755cm7/src/bin/intercore.rs
Normal file
@ -0,0 +1,228 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
//! STM32H7 Primary Core (CM7) Intercore Communication Example
|
||||
//!
|
||||
//! This example demonstrates reliable communication between the Cortex-M7 and
|
||||
//! Cortex-M4 cores using a shared memory region configured as non-cacheable
|
||||
//! via MPU settings.
|
||||
//!
|
||||
//! The CM7 core handles:
|
||||
//! - MPU configuration to make shared memory non-cacheable
|
||||
//! - Clock initialization
|
||||
//! - Toggling LED states in shared memory
|
||||
//!
|
||||
//! Usage:
|
||||
//! 1. Flash the CM4 (secondary) core binary first
|
||||
//! 2. Then flash this CM7 (primary) core binary
|
||||
//! 3. The system will start with CM7 toggling LED states and CM4 responding by
|
||||
//! physically toggling the LEDs
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use cortex_m::asm;
|
||||
use cortex_m::peripheral::MPU;
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::{Config, SharedData};
|
||||
use embassy_time::Timer;
|
||||
use shared::{SHARED_LED_STATE, SRAM4_BASE_ADDRESS, SRAM4_REGION_NUMBER, SRAM4_SIZE_LOG2};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
/// 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)]
|
||||
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)]
|
||||
#[allow(dead_code)]
|
||||
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)]
|
||||
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)]
|
||||
#[allow(dead_code)]
|
||||
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();
|
||||
|
||||
// Memory region constants for MPU configuration
|
||||
pub const SRAM4_BASE_ADDRESS: u32 = 0x38000000;
|
||||
pub const SRAM4_SIZE_LOG2: u32 = 15; // 64KB = 2^(15+1)
|
||||
pub const SRAM4_REGION_NUMBER: u8 = 0;
|
||||
}
|
||||
|
||||
#[link_section = ".ram_d3"]
|
||||
static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
|
||||
|
||||
/// Configure MPU to make SRAM4 region non-cacheable
|
||||
fn configure_mpu_non_cacheable(mpu: &mut MPU) {
|
||||
asm::dmb();
|
||||
unsafe {
|
||||
// Disable MPU
|
||||
mpu.ctrl.write(0);
|
||||
|
||||
// Configure SRAM4 as non-cacheable
|
||||
mpu.rnr.write(SRAM4_REGION_NUMBER as u32);
|
||||
|
||||
// Set base address with region number
|
||||
mpu.rbar.write(SRAM4_BASE_ADDRESS | (1 << 4));
|
||||
|
||||
// Configure region attributes
|
||||
let rasr_value: u32 = (SRAM4_SIZE_LOG2 << 1) | // SIZE=15 (64KB)
|
||||
(1 << 0) | // ENABLE=1
|
||||
(3 << 24) | // AP=3 (Full access)
|
||||
(1 << 19) | // TEX=1
|
||||
(1 << 18); // S=1 (Shareable)
|
||||
|
||||
mpu.rasr.write(rasr_value);
|
||||
|
||||
// Enable MPU with default memory map as background
|
||||
mpu.ctrl.write(1 | (1 << 2)); // MPU_ENABLE | PRIVDEFENA
|
||||
}
|
||||
|
||||
asm::dsb();
|
||||
asm::isb();
|
||||
|
||||
info!("MPU configured - SRAM4 set as non-cacheable");
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
// Set up MPU and cache configuration
|
||||
{
|
||||
let mut cp = cortex_m::Peripherals::take().unwrap();
|
||||
let scb = &mut cp.SCB;
|
||||
|
||||
// First disable caches
|
||||
scb.disable_icache();
|
||||
scb.disable_dcache(&mut cp.CPUID);
|
||||
|
||||
// Configure MPU
|
||||
configure_mpu_non_cacheable(&mut cp.MPU);
|
||||
|
||||
// Re-enable caches
|
||||
scb.enable_icache();
|
||||
scb.enable_dcache(&mut cp.CPUID);
|
||||
asm::dsb();
|
||||
asm::isb();
|
||||
}
|
||||
|
||||
// Configure the clock system
|
||||
let mut config = Config::default();
|
||||
{
|
||||
use embassy_stm32::rcc::*;
|
||||
config.rcc.hsi = Some(HSIPrescaler::DIV1);
|
||||
config.rcc.csi = true;
|
||||
config.rcc.hsi48 = Some(Default::default());
|
||||
config.rcc.pll1 = Some(Pll {
|
||||
source: PllSource::HSI,
|
||||
prediv: PllPreDiv::DIV4,
|
||||
mul: PllMul::MUL50,
|
||||
divp: Some(PllDiv::DIV2),
|
||||
divq: Some(PllDiv::DIV8),
|
||||
divr: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P;
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2;
|
||||
config.rcc.apb1_pre = APBPrescaler::DIV2;
|
||||
config.rcc.apb2_pre = APBPrescaler::DIV2;
|
||||
config.rcc.apb3_pre = APBPrescaler::DIV2;
|
||||
config.rcc.apb4_pre = APBPrescaler::DIV2;
|
||||
config.rcc.voltage_scale = VoltageScale::Scale1;
|
||||
config.rcc.supply_config = SupplyConfig::DirectSMPS;
|
||||
}
|
||||
|
||||
// Initialize the CM7 core
|
||||
let _p = embassy_stm32::init_primary(config, &SHARED_DATA);
|
||||
info!("CM7 core initialized with non-cacheable SRAM4!");
|
||||
|
||||
// Verify shared memory is accessible
|
||||
let magic = SHARED_LED_STATE.magic.load(core::sync::atomic::Ordering::SeqCst);
|
||||
info!("CM7: Magic value = 0x{:X}", magic);
|
||||
|
||||
// Initialize LED states
|
||||
SHARED_LED_STATE.set_led(true, false); // Green LED off
|
||||
SHARED_LED_STATE.set_led(false, false); // Yellow LED off
|
||||
|
||||
// Main loop - periodically toggle LED states
|
||||
let mut green_state = false;
|
||||
let mut yellow_state = false;
|
||||
let mut loop_count = 0;
|
||||
|
||||
info!("CM7: Starting main loop");
|
||||
loop {
|
||||
loop_count += 1;
|
||||
let counter = SHARED_LED_STATE.increment_counter();
|
||||
|
||||
// Toggle green LED every second
|
||||
if loop_count % 10 == 0 {
|
||||
green_state = !green_state;
|
||||
SHARED_LED_STATE.set_led(true, green_state);
|
||||
info!("CM7: Counter = {}, Set green LED to {}", counter, green_state);
|
||||
}
|
||||
|
||||
// Toggle yellow LED every 3 seconds
|
||||
if loop_count % 30 == 0 {
|
||||
yellow_state = !yellow_state;
|
||||
SHARED_LED_STATE.set_led(false, yellow_state);
|
||||
info!("CM7: Counter = {}, Set yellow LED to {}", counter, yellow_state);
|
||||
}
|
||||
|
||||
Timer::after_millis(100).await;
|
||||
}
|
||||
}
|
@ -25,6 +25,8 @@ async fn main(_spawner: Spawner) {
|
||||
divp: Some(PllDiv::DIV2),
|
||||
divq: None,
|
||||
divr: None,
|
||||
divs: None,
|
||||
divt: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
|
||||
|
@ -41,6 +41,8 @@ async fn main(spawner: Spawner) -> ! {
|
||||
divp: Some(PllDiv::DIV2),
|
||||
divq: None,
|
||||
divr: None,
|
||||
divs: None,
|
||||
divt: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
|
||||
|
@ -40,6 +40,8 @@ async fn main(_spawner: Spawner) {
|
||||
divp: Some(PllDiv::DIV1), //600 MHz
|
||||
divq: Some(PllDiv::DIV2), // 300 MHz
|
||||
divr: Some(PllDiv::DIV2), // 300 MHz
|
||||
divs: None,
|
||||
divt: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 600 MHz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz
|
||||
|
@ -36,6 +36,8 @@ async fn main(_spawner: Spawner) {
|
||||
divp: Some(PllDiv::DIV2),
|
||||
divq: None,
|
||||
divr: None,
|
||||
divs: None,
|
||||
divt: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
|
||||
|
@ -681,6 +681,8 @@ pub fn config() -> Config {
|
||||
divp: Some(PllDiv::DIV2), // 600Mhz
|
||||
divq: Some(PllDiv::DIV25), // 48Mhz
|
||||
divr: None,
|
||||
divs: None,
|
||||
divt: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz
|
||||
|
Loading…
x
Reference in New Issue
Block a user