5 Commits

Author SHA1 Message Date
Priec
3ebbd97760 improvements to semestralka 2 2025-12-03 20:20:34 +01:00
Priec
68d13ebbbc sram2 standby working 2025-12-03 18:33:07 +01:00
Priec
434e2b3d21 shutdown added 2025-12-03 17:57:10 +01:00
Priec
33543099c2 split the wakeup now, properly working 2025-12-03 16:52:30 +01:00
Priec
9be1d514fb ready for feature based split 2025-12-03 13:36:56 +01:00
9 changed files with 148 additions and 39 deletions

View File

@@ -13,12 +13,12 @@ async fn main(_spawner: Spawner) {
let p = init(Config::default()); let p = init(Config::default());
let mut output_pin = Output::new(p.PA3, Level::Low, Speed::Low); let mut output_pin = Output::new(p.PA3, Level::Low, Speed::Low);
let mut artificial_ground = Output::new(p.PB0, Level::Low, Speed::Low); let mut _artificial_ground = Output::new(p.PB0, Level::Low, Speed::Low);
loop { loop {
output_pin.set_high(); output_pin.set_high();
Timer::after(Duration::from_millis(500)).await; Timer::after(Duration::from_millis(500)).await;
output_pin.set_low(); // output_pin.set_low();
Timer::after(Duration::from_millis(500)).await; Timer::after(Duration::from_millis(500)).await;
} }
} }

View File

@@ -3,7 +3,6 @@
#![no_main] #![no_main]
use defmt::*; use defmt::*;
use core::ptr::addr_of_mut;
use embassy_stm32::pac; use embassy_stm32::pac;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::yield_now; use embassy_futures::yield_now;
@@ -12,7 +11,6 @@ use embassy_stm32::peripherals;
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_stm32::usart::{BufferedUart, Config as UsartConfig, BufferedInterruptHandler}; use embassy_stm32::usart::{BufferedUart, Config as UsartConfig, BufferedInterruptHandler};
use embassy_stm32::gpio::{Output, Level, Speed}; use embassy_stm32::gpio::{Output, Level, Speed};
use embassy_stm32::wdg::IndependentWatchdog;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use static_cell::StaticCell; use static_cell::StaticCell;
@@ -20,38 +18,27 @@ use dma_gpio::config::{
BAUD, PIPE_HW_RX, PIPE_HW_TX, BAUD, PIPE_HW_RX, PIPE_HW_TX,
}; };
use dma_gpio::hw_uart_pc::{driver::uart_task, usart1}; use dma_gpio::hw_uart_pc::{driver::uart_task, usart1};
use dma_gpio::wakeup::iwdg::{clear_wakeup_flags, init_watchdog};
use dma_gpio::sleep::shutdown::enter_shutdown;
use dma_gpio::sleep::standby;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs { bind_interrupts!(struct Irqs {
USART1 => BufferedInterruptHandler<peripherals::USART1>; USART1 => BufferedInterruptHandler<peripherals::USART1>;
}); });
unsafe extern "C" {
fn HAL_PWR_EnterSTANDBYMode();
}
const PWR_FLAG_SBF: u32 = 1 << 1;
#[embassy_executor::main] #[embassy_executor::main]
async fn main(spawner: Spawner) { async fn main(spawner: Spawner) {
info!("boot"); info!("boot");
let mut config = Config::default(); let p = embassy_stm32::init(Config::default());
config.enable_debug_during_sleep = true;
let p = embassy_stm32::init(config);
let mut led = Output::new(p.PA3, Level::Low, Speed::Low); let mut led = Output::new(p.PA3, Level::Low, Speed::Low);
let _led_ground = Output::new(p.PB0, Level::Low, Speed::Low); let _led_ground = Output::new(p.PB0, Level::Low, Speed::Low);
info!("init m8"); info!("init m8");
// Clearing after the wakeup clear_wakeup_flags();
let rcc = pac::RCC;
rcc.csr().write(|w| w.set_rmvf(true)); led.set_high();
info!("LED ON (MCU awake)");
// Check wake source
let pwr = pac::PWR;
if pwr.sr().read().sbf() {
info!("Woke from Standby via watchdog");
pwr.sr().write(|w| w.set_sbf(true));
}
// HARDWARE UART to the PC // HARDWARE UART to the PC
let mut cfg = UsartConfig::default(); let mut cfg = UsartConfig::default();
@@ -76,27 +63,17 @@ async fn main(spawner: Spawner) {
info!("DBGMCU CR: dbg_stop={}, dbg_standby={}", cr.dbg_stop(), cr.dbg_standby()); info!("DBGMCU CR: dbg_stop={}, dbg_standby={}", cr.dbg_stop(), cr.dbg_standby());
// MAIN LOOP // MAIN LOOP
info!("tick start");
led.set_high();
info!("LED IS HIGH");
Timer::after(Duration::from_millis(500)).await; Timer::after(Duration::from_millis(500)).await;
led.set_low();
info!("LED IS LOW");
Timer::after(Duration::from_millis(500)).await;
led.set_high();
info!("LED IS HIGH");
info!("Iwdg init"); init_watchdog(p.IWDG).await;
let mut watchdog = IndependentWatchdog::new(p.IWDG, 2_000_000); // 2 seconds
watchdog.unleash();
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(10)).await;
unsafe {
info!("Standby...");
HAL_PWR_EnterSTANDBYMode();
}
loop { loop {
info!("entering shutdown");
// enter_shutdown();
info!("shutdown");
standby::enter_standby_with_sram2_full();
cortex_m::asm::wfi(); cortex_m::asm::wfi();
yield_now().await;
} }
} }

View File

@@ -6,5 +6,7 @@ pub const BAUD: u32 = 9_600;
pub const PIPE_HW_TX_SIZE: usize = 1024; pub const PIPE_HW_TX_SIZE: usize = 1024;
pub const PIPE_HW_RX_SIZE: usize = 1024; pub const PIPE_HW_RX_SIZE: usize = 1024;
pub const WATCHDOG_TIMEOUT_US: u32 = 2_000_000; // 2 seconds
pub static PIPE_HW_TX: Pipe<CriticalSectionRawMutex, PIPE_HW_TX_SIZE> = Pipe::new(); pub static PIPE_HW_TX: Pipe<CriticalSectionRawMutex, PIPE_HW_TX_SIZE> = Pipe::new();
pub static PIPE_HW_RX: Pipe<CriticalSectionRawMutex, PIPE_HW_RX_SIZE> = Pipe::new(); pub static PIPE_HW_RX: Pipe<CriticalSectionRawMutex, PIPE_HW_RX_SIZE> = Pipe::new();

View File

@@ -4,3 +4,5 @@
// pub use low_power::*; // pub use low_power::*;
pub mod hw_uart_pc; pub mod hw_uart_pc;
pub mod config; pub mod config;
pub mod sleep;
pub mod wakeup;

View File

@@ -0,0 +1,4 @@
// src/sleep/mod.rs
pub mod standby;
pub mod shutdown;

View File

@@ -0,0 +1,13 @@
// src/sleep/standby.rs
pub fn enter_shutdown() -> ! {
unsafe extern "C" {
fn HAL_PWREx_EnterSHUTDOWNMode();
}
unsafe {
HAL_PWREx_EnterSHUTDOWNMode();
}
cortex_m::asm::udf(); //panic
}

View File

@@ -0,0 +1,58 @@
// src/sleep/standby.rs
pub fn enter_standby() -> ! {
unsafe extern "C" {
fn HAL_PWR_EnterSTANDBYMode();
}
unsafe {
HAL_PWR_EnterSTANDBYMode();
}
cortex_m::asm::udf(); // never happen marker
}
pub fn enter_standby_with_sram2_8kb() -> ! {
sram2_8kb_retention();
enter_standby();
}
pub fn enter_standby_with_sram2_full() -> ! {
sram2_full_retention();
enter_standby();
}
pub fn sram2_full_retention() {
unsafe extern "C" {
fn HAL_PWREx_EnableSRAM2ContentStandbyRetention(sram2_pages: u32);
}
unsafe {
// 0x60 = PWR_SRAM2_FULL_STANDBY = PWR_CR1_RRSB1 | PWR_CR1_RRSB2
// See: STM32U5xx HAL: stm32u5xx_hal_pwr_ex.h line 227
// PWR_CR1_RRSB1=0x20, PWR_CR1_RRSB2=0x40
HAL_PWREx_EnableSRAM2ContentStandbyRetention(0x60);
}
}
pub fn sram2_8kb_retention() {
unsafe extern "C" {
fn HAL_PWREx_EnableSRAM2ContentStandbyRetention(sram2_pages: u32);
}
unsafe {
// 0x40 = PWR_SRAM2_PAGE1_STANDBY = PWR_CR1_RRSB2
// 8KB retention only
HAL_PWREx_EnableSRAM2ContentStandbyRetention(0x40);
}
}
pub fn disable_sram2_full_retention() {
unsafe extern "C" {
fn HAL_PWREx_DisableSRAM2ContentStandbyRetention(sram2_pages: u32);
}
unsafe {
HAL_PWREx_DisableSRAM2ContentStandbyRetention(0x60);
}
}

View File

@@ -0,0 +1,50 @@
// src/wakeup/iwdg.rs
use defmt::info;
use embassy_stm32::peripherals;
use embassy_stm32::wdg::IndependentWatchdog;
use embassy_stm32::Peri;
use embassy_time::{Duration, Timer};
use embassy_stm32::pac;
use crate::sleep::standby;
use crate::config::WATCHDOG_TIMEOUT_US;
/// Clears system reset and standby flags after wakeup.
///
/// Call early in startup to:
/// - Clear reset flags by setting `RMVF` in `RCC_CSR`.
/// - If `SBF` in `PWR_SR` is set (woke from Standby), clear it.
///
/// # Registers
/// - `RCC_CSR` — Reset and Clock Control / Status
/// - `PWR_SR` — Power Control / Status
pub fn clear_wakeup_flags() {
info!("Clearing wakeup flags...");
standby::disable_sram2_full_retention();
// Clear reset flags
// let rcc = unsafe { &*pac::RCC::ptr() };
let rcc = pac::RCC;
rcc.csr().write(|w| w.set_rmvf(true));
// Check and clear Standby wakeup flag
// let pwr = unsafe { &*pac::PWR::ptr() };
let pwr = pac::PWR;
if pwr.sr().read().sbf() {
info!("Woke from Standby mode");
pwr.sr().write(|w| w.set_sbf(true));
}
}
/// Initializes the Independent Watchdog (IWDG) timer.
/// Wakeup source: Can wake the system from Standby mode on timeout
///
/// # Timing
/// - Timeout value is configured in `WATCHDOG_TIMEOUT_US` from config.rs
pub async fn init_watchdog(iwdg: Peri<'_, peripherals::IWDG>) {
info!("Initializing watchdog after watchdog wake...");
let mut watchdog = IndependentWatchdog::new(iwdg, WATCHDOG_TIMEOUT_US);
watchdog.unleash();
Timer::after(Duration::from_millis(10)).await;
}

View File

@@ -0,0 +1,3 @@
// src/wakeup/mod.rs
pub mod iwdg;