Compare commits
2 Commits
72a731abef
...
f36a9fd9e2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f36a9fd9e2 | ||
|
|
2c9433cb84 |
@@ -11,9 +11,7 @@ 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, init_watchdog_reset};
|
||||||
use dma_gpio::sleep::shutdown;
|
use dma_gpio::sleep::handler::execute_low_power;
|
||||||
use dma_gpio::sleep::standby;
|
|
||||||
use dma_gpio::sleep::stop3;
|
|
||||||
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, LowPowerCmd, CMD_CH};
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@@ -43,14 +41,12 @@ async fn main(spawner: Spawner) {
|
|||||||
"Baud: {} bps | Watchdog: {}s\n\
|
"Baud: {} bps | Watchdog: {}s\n\
|
||||||
UART1 TX=PA9 RX=PA10\n\
|
UART1 TX=PA9 RX=PA10\n\
|
||||||
Modes via UART input:\n\
|
Modes via UART input:\n\
|
||||||
[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\n\
|
[4] Shutdown — lowest power, full reset on wake\n\
|
||||||
[5] STOP3 mode with WFI\n\
|
[5] STOP mode (then choose: 0-3 for mode, 1-3 for entry method)",
|
||||||
[6] STOP3 mode with WFE\n\
|
BAUD, WATCHDOG_TIMEOUT_US / 1_000_000
|
||||||
[7] STOP3 mode with WFE (no event clear)",
|
|
||||||
BAUD, WATCHDOG_TIMEOUT_US / 1_000_000
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// disabling st-link debug
|
// disabling st-link debug
|
||||||
@@ -64,43 +60,10 @@ 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);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
LowPowerCmd::StandbyFull => {
|
|
||||||
init_watchdog_reset(p.IWDG).await;
|
|
||||||
Timer::after(Duration::from_millis(10)).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();
|
|
||||||
}
|
|
||||||
LowPowerCmd::Stop3Wfi => {
|
|
||||||
init_watchdog_reset(p.IWDG).await;
|
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
|
||||||
stop3::enter_stop3(stop3::StopEntry::Wfi);
|
|
||||||
}
|
|
||||||
LowPowerCmd::Stop3Wfe => {
|
|
||||||
init_watchdog_reset(p.IWDG).await;
|
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
|
||||||
stop3::enter_stop3(stop3::StopEntry::Wfe);
|
|
||||||
}
|
|
||||||
LowPowerCmd::Stop3WfeNoClear => {
|
|
||||||
init_watchdog_reset(p.IWDG).await;
|
|
||||||
Timer::after(Duration::from_millis(10)).await;
|
|
||||||
stop3::enter_stop3(stop3::StopEntry::WfeNoEventClear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use embassy_futures::yield_now;
|
|||||||
// UART HW init
|
// 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::sleep::StopEntry;
|
||||||
|
use crate::sleep::handler::execute_low_power;
|
||||||
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,67 +23,88 @@ bind_interrupts!(struct Irqs {
|
|||||||
USART1 => BufferedInterruptHandler<peripherals::USART1>;
|
USART1 => BufferedInterruptHandler<peripherals::USART1>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
|
||||||
pub enum LowPowerCmd {
|
pub enum LowPowerCmd {
|
||||||
Standby8k, // 1
|
Standby8k, // 1
|
||||||
StandbyFull, // 2
|
StandbyFull, // 2
|
||||||
Standby, // 3
|
Standby, // 3
|
||||||
Shutdown, // 4
|
Shutdown, // 4
|
||||||
Stop3Wfi,
|
StopMode(StopModeConfig),
|
||||||
Stop3Wfe,
|
}
|
||||||
Stop3WfeNoClear,
|
|
||||||
|
#[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 {
|
||||||
|
Stop1,
|
||||||
|
Stop2,
|
||||||
|
Stop3,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static CMD_CH: Channel<CriticalSectionRawMutex, LowPowerCmd, 1> = Channel::new();
|
pub static CMD_CH: Channel<CriticalSectionRawMutex, LowPowerCmd, 1> = Channel::new();
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
pub async fn uart_cmd_task() {
|
pub async fn uart_cmd_task() {
|
||||||
// Prompt once
|
async fn print_menu() {
|
||||||
let _ = PIPE_HW_TX
|
while PIPE_HW_TX.len() > 0 {
|
||||||
.write(b"Modes: 1=SB8, 2=SBfull, 3=SB, 4=SD, 5=STOP3(WFI), 6=STOP3(WFE), 7=STOP3(WFE no clear)\r\n")
|
embassy_time::Timer::after(embassy_time::Duration::from_millis(2)).await;
|
||||||
.await;
|
}
|
||||||
|
let _ = PIPE_HW_TX.write(b"\x1B[2J\x1B[H").await;
|
||||||
|
let _ = PIPE_HW_TX.write(
|
||||||
|
b"\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\
|
||||||
|
"
|
||||||
|
).await;
|
||||||
|
}
|
||||||
|
|
||||||
let mut b = [0u8; 1];
|
print_menu().await;
|
||||||
|
|
||||||
|
let mut b = [0u8; 2];
|
||||||
loop {
|
loop {
|
||||||
|
b.fill(0);
|
||||||
let n = PIPE_HW_RX.read(&mut b).await;
|
let n = PIPE_HW_RX.read(&mut b).await;
|
||||||
if n == 0 {
|
if n == 0 { continue; }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
match b[0] {
|
match b[0] {
|
||||||
b'1' => {
|
b'1' => CMD_CH.send(LowPowerCmd::Standby8k).await,
|
||||||
let _ = PIPE_HW_TX.write(b"ACK 1: standby 8KB\r\n").await;
|
b'2' => CMD_CH.send(LowPowerCmd::StandbyFull).await,
|
||||||
CMD_CH.send(LowPowerCmd::Standby8k).await;
|
b'3' => CMD_CH.send(LowPowerCmd::Standby).await,
|
||||||
}
|
b'4' => CMD_CH.send(LowPowerCmd::Shutdown).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'5' => {
|
b'5' => {
|
||||||
let _ = PIPE_HW_TX.write(b"ACK 5: STOP3 with WFI\r\n").await;
|
let _ = PIPE_HW_TX.write(b"Enter Stop mode number (1-3): ").await;
|
||||||
CMD_CH.send(LowPowerCmd::Stop3Wfi).await;
|
b.fill(0);
|
||||||
}
|
let n = PIPE_HW_RX.read(&mut b).await;
|
||||||
b'6' => {
|
if n == 0 { print_menu().await; continue; }
|
||||||
let _ = PIPE_HW_TX.write(b"ACK 6: STOP3 with WFE\r\n").await;
|
let stop_mode = match b[0] {
|
||||||
CMD_CH.send(LowPowerCmd::Stop3Wfe).await;
|
b'1' => StopMode::Stop1,
|
||||||
}
|
b'2' => StopMode::Stop2,
|
||||||
b'7' => {
|
b'3' => StopMode::Stop3,
|
||||||
let _ = PIPE_HW_TX.write(b"ACK 7: STOP3 with WFE (no event clear)\r\n").await;
|
_ => { print_menu().await; continue; }
|
||||||
CMD_CH.send(LowPowerCmd::Stop3WfeNoClear).await;
|
};
|
||||||
}
|
|
||||||
b'\r' | b'\n' | b' ' => {}
|
let _ = PIPE_HW_TX.write(b"Enter entry method (1=WFI,2=WFE,3=WFE no clear): ").await;
|
||||||
_ => {
|
b.fill(0);
|
||||||
let _ = PIPE_HW_TX.write(b"ERR: use 1|2|3|4|5|6|7\r\n").await;
|
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;
|
||||||
}
|
}
|
||||||
|
_ => { print_menu().await; continue; }
|
||||||
}
|
}
|
||||||
yield_now().await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
58
semestralka_2_uart/src/sleep/handler.rs
Normal file
58
semestralka_2_uart/src/sleep/handler.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// src/sleep/handler.rs
|
||||||
|
|
||||||
|
use embassy_time::{Duration, Timer};
|
||||||
|
use embassy_stm32::peripherals;
|
||||||
|
use embassy_stm32::Peri;
|
||||||
|
|
||||||
|
use crate::sleep::stop::StopEntry;
|
||||||
|
use crate::sleep::stop::*;
|
||||||
|
use crate::wakeup::iwdg::init_watchdog_reset;
|
||||||
|
use crate::hw_uart_pc::init::{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;
|
||||||
|
}
|
||||||
|
super::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;
|
||||||
|
}
|
||||||
|
super::standby::enter_standby_with_sram2_full();
|
||||||
|
}
|
||||||
|
LowPowerCmd::Standby => {
|
||||||
|
info!("Entering minimal Standby");
|
||||||
|
if let Some(wdg) = iwdg.take() {
|
||||||
|
init_watchdog_reset(wdg).await;
|
||||||
|
}
|
||||||
|
super::standby::enter_standby();
|
||||||
|
}
|
||||||
|
LowPowerCmd::Shutdown => {
|
||||||
|
info!("Entering Shutdown mode");
|
||||||
|
super::shutdown::enter_shutdown();
|
||||||
|
}
|
||||||
|
LowPowerCmd::StopMode(StopModeConfig { mode, entry }) => {
|
||||||
|
info!("Entering {:?} with {:?}", mode, entry);
|
||||||
|
if let Some(wdg) = iwdg.take() {
|
||||||
|
init_watchdog_reset(wdg).await;
|
||||||
|
}
|
||||||
|
match mode {
|
||||||
|
StopMode::Stop1 => enter_stop1(entry),
|
||||||
|
StopMode::Stop2 => enter_stop2(entry),
|
||||||
|
StopMode::Stop3 => enter_stop3(entry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,7 @@
|
|||||||
|
|
||||||
pub mod standby;
|
pub mod standby;
|
||||||
pub mod shutdown;
|
pub mod shutdown;
|
||||||
pub mod stop3;
|
pub mod stop;
|
||||||
|
pub mod handler;
|
||||||
|
|
||||||
|
pub use stop::StopEntry;
|
||||||
|
|||||||
55
semestralka_2_uart/src/sleep/stop.rs
Normal file
55
semestralka_2_uart/src/sleep/stop.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// src/sleep/stop.rs
|
||||||
|
|
||||||
|
/// How to enter STOPx mode (STOP0–STOP3)
|
||||||
|
#[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_stop1(entry: StopEntry) -> ! {
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn HAL_PWREx_EnterSTOP1Mode(entry: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
HAL_PWREx_EnterSTOP1Mode(entry.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
cortex_m::asm::udf()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enter_stop2(entry: StopEntry) -> ! {
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn HAL_PWREx_EnterSTOP2Mode(entry: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
HAL_PWREx_EnterSTOP2Mode(entry.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
cortex_m::asm::udf()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enter_stop3(entry: StopEntry) -> ! {
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn HAL_PWREx_EnterSTOP3Mode(entry: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
HAL_PWREx_EnterSTOP3Mode(entry.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
cortex_m::asm::udf()
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// src/sleep/stop3.rs
|
|
||||||
|
|
||||||
// #define PWR_STOPENTRY_WFI (0x01U) //*!< Wait For Interruption instruction to enter Stop mode */
|
|
||||||
// #define PWR_STOPENTRY_WFE (0x02U) //*!< Wait For Event instruction to enter Stop mode */
|
|
||||||
// #define PWR_STOPENTRY_WFE_NO_EVT_CLEAR (0x03U)
|
|
||||||
|
|
||||||
/// How to enter STOP3 mode
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
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_stop3(stop_entry: StopEntry) -> ! {
|
|
||||||
unsafe extern "C" {
|
|
||||||
fn HAL_PWREx_EnterSTOP3Mode(stop_entry: u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
HAL_PWREx_EnterSTOP3Mode(stop_entry.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
cortex_m::asm::udf(); //panic
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example usage:
|
|
||||||
// enter_stop3(StopEntry::Wfi);
|
|
||||||
// enter_stop3(StopEntry::Wfe);
|
|
||||||
// enter_stop3(StopEntry::WfeNoEventClear);
|
|
||||||
@@ -42,7 +42,7 @@ pub fn clear_wakeup_flags() {
|
|||||||
///
|
///
|
||||||
/// # Timing
|
/// # Timing
|
||||||
/// - Timeout value is configured in `WATCHDOG_TIMEOUT_US` from config.rs
|
/// - Timeout value is configured in `WATCHDOG_TIMEOUT_US` from config.rs
|
||||||
pub async fn init_watchdog_reset(iwdg: Peri<'_, peripherals::IWDG>) {
|
pub async fn init_watchdog_reset(iwdg: Peri<'static, peripherals::IWDG>) {
|
||||||
info!("Initializing watchdog after watchdog wake...");
|
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();
|
||||||
|
|||||||
Reference in New Issue
Block a user