12 Commits

Author SHA1 Message Date
Priec
c60f8db3c8 moves 2025-12-16 00:39:51 +01:00
Priec
4c7d9af29a moved handler 2025-12-15 16:46:10 +01:00
Priec
88341314dd cleaning up 2025-12-15 16:16:46 +01:00
Priec
053cba171d sleep 2025-12-14 15:16:24 +01:00
Priec
20dfdbc335 wake up pin working for the wake up 2025-12-14 14:33:01 +01:00
Priec
f4ca3071f0 exti gpio wake up 2025-12-14 12:50:21 +01:00
Priec
bbddc7cf9c detection of the stop0-2 2025-12-14 12:01:19 +01:00
Priec
49cc8dcc71 stop0 working 2025-12-14 11:56:09 +01:00
Priec
58561ec392 dumb changes didnt do anything 2025-12-13 22:31:49 +01:00
Priec
f36a9fd9e2 scuffed uart print 2025-12-13 00:55:30 +01:00
Priec
2c9433cb84 implementation of stops and reorganization of the codebase 2025-12-12 22:25:36 +01:00
Filipriec
72a731abef stop3 working properly well 2025-12-09 16:02:09 +01:00
18 changed files with 343 additions and 99 deletions

View File

@@ -16,7 +16,7 @@ embassy-sync = { git = "https://github.com/embassy-rs/embassy.git", branch =
embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["tick-hz-32_768"] } embassy-time = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["tick-hz-32_768"] }
embassy-hal-internal = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } embassy-hal-internal = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-usb = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" } embassy-usb = { git = "https://github.com/embassy-rs/embassy.git", branch = "main" }
embassy-stm32 = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["unstable-pac", "stm32u575zi", "time-driver-tim2", "memory-x", "defmt"] } embassy-stm32 = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", features = ["unstable-pac", "stm32u575zi", "time-driver-tim2", "memory-x", "defmt", "exti"] }
embedded-hal = "1.0.0" embedded-hal = "1.0.0"
embedded-graphics = "0.8.1" embedded-graphics = "0.8.1"

View File

@@ -37,6 +37,8 @@ fn main() {
build.file(hal_driver.join("Src").join(src)); build.file(hal_driver.join("Src").join(src));
} }
build.file("src/c_ll/stop0_ll.c");
build build
.include(hal_driver.join("Inc")) .include(hal_driver.join("Inc"))
.include(device.join("Include")) .include(device.join("Include"))

View File

@@ -4,16 +4,17 @@
use defmt::*; use defmt::*;
use embassy_stm32::pac; use embassy_stm32::pac;
use embassy_executor::Spawner; use embassy_executor::{Spawner, task};
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_stm32::gpio::{Output, Level, Speed}; use embassy_stm32::gpio::{Output, Level, Speed};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use dma_gpio::config::BAUD; use dma_gpio::config::BAUD;
use dma_gpio::wakeup::iwdg::{clear_wakeup_flags, init_watchdog_reset}; use dma_gpio::wakeup::iwdg::clear_wakeup_flags;
use dma_gpio::sleep::shutdown; use dma_gpio::wakeup::gpio::gpio_wakeup;
use dma_gpio::sleep::standby; use dma_gpio::logic::handler::execute_low_power;
use dma_gpio::hw_uart_pc::init::{init_hw_uart_to_pc, LowPowerCmd, CMD_CH}; use dma_gpio::hw_uart_pc::init::init_hw_uart_to_pc;
use dma_gpio::logic::uart_cmd::CMD_CH;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
@@ -29,6 +30,9 @@ async fn main(spawner: Spawner) {
led.set_high(); led.set_high();
info!("LED ON (MCU awake)"); info!("LED ON (MCU awake)");
// LED BLINK
// spawner.spawn(led_blink(led).unwrap());
// INIT HW UART // INIT HW UART
init_hw_uart_to_pc(p.USART1, p.PA10, p.PA9, &spawner); init_hw_uart_to_pc(p.USART1, p.PA10, p.PA9, &spawner);
@@ -45,7 +49,8 @@ async fn main(spawner: Spawner) {
[1] Standby + 8 KB SRAM2 retention\n\ [1] Standby + 8 KB SRAM2 retention\n\
[2] Standby + full SRAM2 retention\n\ [2] Standby + full SRAM2 retention\n\
[3] Standby — minimal power, SRAM2 lost\n\ [3] Standby — minimal power, SRAM2 lost\n\
[4] Shutdown — lowest power, full reset on wake", [4] Shutdown — lowest power, full reset on wake\n\
[5] STOP mode (then choose: 0-3 for mode, 1-3 for entry method)",
BAUD, WATCHDOG_TIMEOUT_US / 1_000_000 BAUD, WATCHDOG_TIMEOUT_US / 1_000_000
); );
@@ -60,28 +65,19 @@ async fn main(spawner: Spawner) {
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(10)).await;
info!("ready for uart"); info!("ready for uart");
let mut iwdg = Some(p.IWDG);
spawner.spawn(gpio_wakeup(p.PA0, p.EXTI0).unwrap()); // exti wake up
loop { loop {
let cmd = CMD_CH.receive().await; let cmd = CMD_CH.receive().await;
match cmd { execute_low_power(cmd, &mut iwdg).await;
LowPowerCmd::Standby8k => { }
init_watchdog_reset(p.IWDG).await; // watchdog reset at configurated time }
Timer::after(Duration::from_millis(10)).await; // let UART flush
standby::enter_standby_with_sram2_8kb(); #[task]
} async fn led_blink(mut led: Output<'static>) {
LowPowerCmd::StandbyFull => { loop {
init_watchdog_reset(p.IWDG).await; led.toggle();
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(300)).await;
standby::enter_standby_with_sram2_full();
}
LowPowerCmd::Standby => {
init_watchdog_reset(p.IWDG).await;
Timer::after(Duration::from_millis(10)).await;
standby::enter_standby();
}
LowPowerCmd::Shutdown => {
Timer::after(Duration::from_millis(10)).await;
shutdown::enter_shutdown();
}
}
} }
} }

View File

@@ -0,0 +1,8 @@
#include "stm32u5xx_ll_pwr.h"
void rust_LL_PWR_SetPowerMode(unsigned int mode)
{
// Configure STOP0
LL_PWR_SetPowerMode(mode);
}

View File

@@ -33,7 +33,7 @@ pub async fn uart_task(
} }
// Outgoing data waiting in TX pipe // Outgoing data waiting in TX pipe
Either::Second(n) => { Either::Second(n) => {
unwrap!(uart.write(&tx_buf[..n]).await); unwrap!(uart.write_all(&tx_buf[..n]).await);
} }
} }
yield_now().await; yield_now().await;

View File

@@ -1,12 +1,8 @@
// src/hw_uart_pc/init.rs // src/hw_uart_pc/init.rs
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use embassy_futures::yield_now;
// UART HW init
use crate::config::{BAUD, PIPE_HW_TX, PIPE_HW_RX}; use crate::config::{BAUD, PIPE_HW_TX, PIPE_HW_RX};
use crate::hw_uart_pc::driver::uart_task; use crate::hw_uart_pc::driver::uart_task;
use crate::logic::uart_cmd::uart_cmd_task;
use static_cell::StaticCell; use static_cell::StaticCell;
use embassy_stm32::usart::BufferedInterruptHandler; use embassy_stm32::usart::BufferedInterruptHandler;
use embassy_stm32::usart::{BufferedUart, Config as UsartConfig}; use embassy_stm32::usart::{BufferedUart, Config as UsartConfig};
@@ -21,53 +17,6 @@ bind_interrupts!(struct Irqs {
USART1 => BufferedInterruptHandler<peripherals::USART1>; USART1 => BufferedInterruptHandler<peripherals::USART1>;
}); });
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LowPowerCmd {
Standby8k, // 1
StandbyFull, // 2
Standby, // 3
Shutdown, // 4
}
pub static CMD_CH: Channel<CriticalSectionRawMutex, LowPowerCmd, 1> = Channel::new();
#[embassy_executor::task]
pub async fn uart_cmd_task() {
// Prompt once
let _ = PIPE_HW_TX
.write(b"Modes: 1=SB8, 2=SBfull, 3=SB, 4=SD\r\n")
.await;
let mut b = [0u8; 1];
loop {
let n = PIPE_HW_RX.read(&mut b).await;
if n == 0 {
continue;
}
match b[0] {
b'1' => {
let _ = PIPE_HW_TX.write(b"ACK 1: standby 8KB\r\n").await;
CMD_CH.send(LowPowerCmd::Standby8k).await;
}
b'2' => {
let _ = PIPE_HW_TX.write(b"ACK 2: standby full\r\n").await;
CMD_CH.send(LowPowerCmd::StandbyFull).await;
}
b'3' => {
let _ = PIPE_HW_TX.write(b"ACK 3: standby\r\n").await;
CMD_CH.send(LowPowerCmd::Standby).await;
}
b'4' => {
let _ = PIPE_HW_TX.write(b"ACK 4: shutdown\r\n").await;
CMD_CH.send(LowPowerCmd::Shutdown).await;
}
b'\r' | b'\n' | b' ' => {}
_ => { let _ = PIPE_HW_TX.write(b"ERR: use 1|2|3|4\r\n").await; }
}
yield_now().await;
}
}
pub fn init_hw_uart_to_pc( pub fn init_hw_uart_to_pc(
usart1: Peri<'static, USART1>, usart1: Peri<'static, USART1>,
pa10: Peri<'static, PA10>, pa10: Peri<'static, PA10>,

View File

@@ -1,4 +1,5 @@
// src/hw_uart_pc/mod.rs // src/hw_uart_pc/mod.rs
pub mod driver; pub mod driver;
pub mod usart1; pub mod usart1;
pub mod safety; pub mod safety;

View File

@@ -6,3 +6,4 @@ pub mod hw_uart_pc;
pub mod config; pub mod config;
pub mod sleep; pub mod sleep;
pub mod wakeup; pub mod wakeup;
pub mod logic;

View File

@@ -0,0 +1,67 @@
// src/logic/handler.rs
use embassy_time::{Duration, Timer};
use embassy_stm32::peripherals;
use embassy_stm32::Peri;
use crate::sleep::stop::{enter_stop0, enter_stop1, enter_stop2, enter_stop3};
use crate::sleep::sleep::{enter_sleep_mode, SleepEntry};
use crate::sleep::{standby, shutdown};
use crate::wakeup::iwdg::init_watchdog_reset;
use crate::logic::uart_cmd::{LowPowerCmd, StopMode, StopModeConfig};
use defmt::info;
pub async fn execute_low_power(
cmd: LowPowerCmd,
iwdg: &mut Option<Peri<'static, peripherals::IWDG>>
) {
Timer::after(Duration::from_millis(10)).await;
match cmd {
LowPowerCmd::Standby8k => {
info!("Entering Standby with 8KB SRAM2 retention");
if let Some(wdg) = iwdg.take() {
init_watchdog_reset(wdg).await;
}
standby::enter_standby_with_sram2_8kb();
}
LowPowerCmd::StandbyFull => {
info!("Entering Standby with full SRAM2 retention");
if let Some(wdg) = iwdg.take() {
init_watchdog_reset(wdg).await;
}
standby::enter_standby_with_sram2_full();
}
LowPowerCmd::Standby => {
info!("Entering minimal Standby");
if let Some(wdg) = iwdg.take() {
init_watchdog_reset(wdg).await;
}
standby::enter_standby();
}
LowPowerCmd::Shutdown => {
info!("Entering Shutdown mode");
shutdown::enter_shutdown();
}
LowPowerCmd::StopMode(StopModeConfig { mode, entry }) => {
info!("Entering {:?} with {:?}", mode, entry);
match mode {
StopMode::Stop0 => enter_stop0(),
StopMode::Stop1 => enter_stop1(entry),
StopMode::Stop2 => enter_stop2(entry),
StopMode::Stop3 => {
if let Some(wdg) = iwdg.take() {
init_watchdog_reset(wdg).await;
}
enter_stop3(entry);
}
}
}
LowPowerCmd::Sleep => {
info!("Entering Sleep mode (WFI)...");
enter_sleep_mode(SleepEntry::Wfi);
info!("Woke up from Sleep mode.");
}
}
}

View File

@@ -0,0 +1,4 @@
// src/logic/mod.rs
pub mod handler;
pub mod uart_cmd;

View File

@@ -0,0 +1,106 @@
// src/logic/uart_cmd.rs
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
// UART HW init
use crate::config::{PIPE_HW_TX, PIPE_HW_RX};
use crate::sleep::StopEntry;
pub static CMD_CH: Channel<CriticalSectionRawMutex, LowPowerCmd, 1> = Channel::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
pub enum LowPowerCmd {
Standby8k, // 1
StandbyFull, // 2
Standby, // 3
Shutdown, // 4
StopMode(StopModeConfig),
Sleep,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
pub struct StopModeConfig {
pub mode: StopMode,
pub entry: StopEntry,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
pub enum StopMode {
Stop0,
Stop1,
Stop2,
Stop3,
}
#[embassy_executor::task]
pub async fn uart_cmd_task() {
async fn print_menu() {
while PIPE_HW_TX.len() > 0 {
embassy_time::Timer::after(embassy_time::Duration::from_millis(8)).await;
}
let _ = PIPE_HW_TX.write(
b"\x1B[2J\x1B[H\r\n\
Modes:\r\n\
[1] Standby + 8 KB SRAM2 retention\r\n\
[2] Standby + full SRAM2 retention\r\n\
[3] Standby minimal\r\n\
[4] Shutdown\r\n\
[5] Stop mode (0-3)\r\n\
[6] Sleep mode (WFI or WFE)\r\n\
"
).await;
embassy_time::Timer::after(embassy_time::Duration::from_millis(8)).await;
}
print_menu().await;
let mut b = [0u8; 2];
loop {
b.fill(0);
let n = PIPE_HW_RX.read(&mut b).await;
if n == 0 { continue; }
match b[0] {
b'1' => CMD_CH.send(LowPowerCmd::Standby8k).await,
b'2' => CMD_CH.send(LowPowerCmd::StandbyFull).await,
b'3' => CMD_CH.send(LowPowerCmd::Standby).await,
b'4' => CMD_CH.send(LowPowerCmd::Shutdown).await,
b'5' => {
let _ = PIPE_HW_TX.write(b"Enter Stop mode number (0-3): ").await;
b.fill(0);
let n = PIPE_HW_RX.read(&mut b).await;
if n == 0 { print_menu().await; continue; }
let stop_mode = match b[0] {
b'0' => StopMode::Stop0,
b'1' => StopMode::Stop1,
b'2' => StopMode::Stop2,
b'3' => StopMode::Stop3,
_ => { print_menu().await; continue; }
};
if matches!(stop_mode, StopMode::Stop0) {
CMD_CH.send(LowPowerCmd::StopMode(StopModeConfig {
mode: stop_mode,
entry: StopEntry::Wfi, // to tu je, lebo nejdem prepisovat kod, kvoli
// pos**temu halu co si nevie urobit konzistentnost
})).await;
continue;
}
let _ = PIPE_HW_TX.write(b"Enter entry method (1=WFI,2=WFE,3=WFE no clear): ").await;
b.fill(0);
let n = PIPE_HW_RX.read(&mut b).await;
if n == 0 { print_menu().await; continue; }
let entry = match b[0] {
b'1' => StopEntry::Wfi,
b'2' => StopEntry::Wfe,
b'3' => StopEntry::WfeNoEventClear,
_ => { print_menu().await; continue; }
};
CMD_CH.send(LowPowerCmd::StopMode(StopModeConfig { mode: stop_mode, entry })).await;
},
b'6' => CMD_CH.send(LowPowerCmd::Sleep).await,
_ => { print_menu().await; continue; }
}
}
}

View File

@@ -2,3 +2,7 @@
pub mod standby; pub mod standby;
pub mod shutdown; pub mod shutdown;
pub mod stop;
pub mod sleep;
pub use stop::StopEntry;

View File

@@ -0,0 +1,19 @@
// src/sleep/sleep.rs
use cortex_m::Peripherals;
#[derive(Clone, Copy, Debug, defmt::Format)]
pub enum SleepEntry {
Wfi,
Wfe,
}
pub fn enter_sleep_mode(entry: SleepEntry) {
let mut core = unsafe { Peripherals::steal() };
core.SCB.clear_sleepdeep();
match entry {
SleepEntry::Wfi => cortex_m::asm::wfi(),
SleepEntry::Wfe => cortex_m::asm::wfe(),
}
}

View File

@@ -9,7 +9,7 @@ pub fn enter_standby() -> ! {
HAL_PWR_EnterSTANDBYMode(); HAL_PWR_EnterSTANDBYMode();
} }
cortex_m::asm::udf(); // never happen marker cortex_m::asm::udf();
} }
pub fn enter_standby_with_sram2_8kb() -> ! { pub fn enter_standby_with_sram2_8kb() -> ! {

View File

@@ -0,0 +1,69 @@
// src/sleep/stop.rs
use cortex_m::Peripherals;
use cortex_m::asm;
/// Enter STOPx mode parameter
#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
pub enum StopEntry {
Wfi,
Wfe,
WfeNoEventClear,
}
impl From<StopEntry> for u8 {
fn from(value: StopEntry) -> Self {
match value {
StopEntry::Wfi => 0x01,
StopEntry::Wfe => 0x02,
StopEntry::WfeNoEventClear => 0x03,
}
}
}
pub fn enter_stop0() {
unsafe extern "C" {
fn rust_LL_PWR_SetPowerMode(mode: u32);
}
const LL_PWR_STOP0_MODE: u32 = 0; //stm32u5xx_ll_pwr.h
unsafe {
rust_LL_PWR_SetPowerMode(LL_PWR_STOP0_MODE);
let mut core = Peripherals::steal();
core.SCB.set_sleepdeep();
asm::wfi();
core.SCB.clear_sleepdeep();
}
}
pub fn enter_stop1(entry: StopEntry) {
unsafe extern "C" {
fn HAL_PWREx_EnterSTOP1Mode(entry: u8);
}
unsafe {
HAL_PWREx_EnterSTOP1Mode(entry.into());
}
}
pub fn enter_stop2(entry: StopEntry) {
unsafe extern "C" {
fn HAL_PWREx_EnterSTOP2Mode(entry: u8);
}
unsafe {
HAL_PWREx_EnterSTOP2Mode(entry.into());
}
}
pub fn enter_stop3(entry: StopEntry) {
unsafe extern "C" {
fn HAL_PWREx_EnterSTOP3Mode(entry: u8);
}
unsafe {
HAL_PWREx_EnterSTOP3Mode(entry.into());
}
}

View File

@@ -0,0 +1,25 @@
// src/wakeup/gpio.rs
use defmt::info;
use embassy_stm32::exti::ExtiInput;
use embassy_stm32::gpio::Pull;
use embassy_stm32::peripherals;
use embassy_time::{Duration, Timer};
use embassy_hal_internal::Peri;
/// GPIO pin as an EXTI wake-up source.
#[embassy_executor::task]
pub async fn gpio_wakeup(
pin: Peri<'static, peripherals::PA0>,
ch: Peri<'static, peripherals::EXTI0>
) {
info!("EXTI wake input on PA0");
let mut btn = ExtiInput::new(pin, ch, Pull::Up);
loop {
info!("Waiting for falling edge on PA0");
btn.wait_for_falling_edge().await;
info!("GPIO wake-up");
Timer::after(Duration::from_millis(50)).await;
}
}

View File

@@ -10,13 +10,8 @@ use crate::sleep::standby;
use crate::config::WATCHDOG_TIMEOUT_US; use crate::config::WATCHDOG_TIMEOUT_US;
/// Clears system reset and standby flags after wakeup. /// Call early in startup
/// ///
/// 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 /// - `RCC_CSR` — Reset and Clock Control / Status
/// - `PWR_SR` — Power Control / Status /// - `PWR_SR` — Power Control / Status
pub fn clear_wakeup_flags() { pub fn clear_wakeup_flags() {
@@ -37,13 +32,10 @@ pub fn clear_wakeup_flags() {
} }
} }
/// Initializes the Independent Watchdog (IWDG) timer. /// Init Independent Watchdog (IWDG) timer.
/// Wakeup source: Can wake the system from Standby mode on timeout /// Timeout value is configured in `WATCHDOG_TIMEOUT_US` from config.rs
/// pub async fn init_watchdog_reset(iwdg: Peri<'static, peripherals::IWDG>) {
/// # Timing info!("Init watchdog after watchdog wake...");
/// - Timeout value is configured in `WATCHDOG_TIMEOUT_US` from config.rs
pub async fn init_watchdog_reset(iwdg: Peri<'_, peripherals::IWDG>) {
info!("Initializing watchdog after watchdog wake...");
let mut watchdog = IndependentWatchdog::new(iwdg, WATCHDOG_TIMEOUT_US); let mut watchdog = IndependentWatchdog::new(iwdg, WATCHDOG_TIMEOUT_US);
watchdog.unleash(); watchdog.unleash();
Timer::after(Duration::from_millis(10)).await; Timer::after(Duration::from_millis(10)).await;

View File

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