From b39f3f3ada9ca12906377a75387e41665316875e Mon Sep 17 00:00:00 2001 From: Samuel Tardieu <sam@rfc1149.net> Date: Wed, 17 Jul 2024 00:47:56 +0200 Subject: [PATCH] Separate watchdog code into a module --- controller/src/logic/mod.rs | 63 +++----------------------------- controller/src/logic/watchdog.rs | 61 +++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 57 deletions(-) create mode 100644 controller/src/logic/watchdog.rs diff --git a/controller/src/logic/mod.rs b/controller/src/logic/mod.rs index 00ee9fc..3ed0269 100644 --- a/controller/src/logic/mod.rs +++ b/controller/src/logic/mod.rs @@ -1,20 +1,12 @@ use crate::{encoders::Encoders, tb6612fng::Tb6612fng}; -use core::sync::atomic::{AtomicU8, Ordering}; use embassy_executor::Spawner; -use embassy_stm32::{ - pac::{self, wwdg::vals::Wdgtb}, - peripherals::WWDG, - time::hz, -}; -use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}; -use embassy_time::{Duration, Instant, Ticker}; +use embassy_stm32::{peripherals::WWDG, time::hz}; use futures::FutureExt; use heapless::Deque; use i2c2_target::{I2C2, MESSAGE_SIZE}; mod motor_control; - -static WATCHDOG_TICKS: AtomicU8 = AtomicU8::new(5); +mod watchdog; struct State { i2c: I2C2, @@ -32,28 +24,6 @@ impl State { static mut STATE: Option<State> = None; -fn wwdg_configure() { - // Enable WWDG clock - pac::RCC.apb1enr().modify(|w| w.set_wwdgen(true)); - // With PCLK1 at 36MHz, 63 as a timeout value with wdgtb at /8 - // means ~58ms. Comparing with a value of 45 means that at - // least ~42ms must have passed before the watchdog can be - // petted, so we have 8ms on each side. - pac::WWDG.cfr().write(|w| { - w.set_wdgtb(Wdgtb::DIV8); - w.set_w((1 << 6) | 31); - }); - wwdg_pet(); -} - -fn wwdg_pet() { - // Reset watchdog and start it if not started yet - pac::WWDG.cr().write(|w| { - w.set_t((1 << 6) | 63); - w.set_wdga(true); - }); -} - #[allow(clippy::needless_pass_by_value, clippy::used_underscore_binding)] // Clippy bug pub fn start_i2c_target( spawner: Spawner, @@ -66,36 +36,15 @@ pub fn start_i2c_target( STATE = Some(State::new(i2c2, encoders)); STATE.as_mut().unwrap().i2c.start(&i2c_callback); } - spawner.spawn(watchdog()).unwrap(); + spawner.spawn(watchdog::watchdog()).unwrap(); spawner.spawn(motor_control::motor_control(motors)).unwrap(); } -static WATCHDOG_PING: Signal<CriticalSectionRawMutex, Instant> = Signal::new(); - -#[embassy_executor::task] -async fn watchdog() { - wwdg_configure(); - let mut ticker = Ticker::every(Duration::from_millis(50)); - let mut watchdog_expiration: Instant = Instant::now(); - loop { - ticker.next().await; - wwdg_pet(); - if let Some(ping) = WATCHDOG_PING.try_take() { - watchdog_expiration = ping - + Duration::from_millis(100 * u64::from(WATCHDOG_TICKS.load(Ordering::Relaxed))); - } - if motor_control::is_moving() && Instant::now() >= watchdog_expiration { - defmt::debug!("stopping motors after watchdog has expired"); - motor_control::standby().await; - } - } -} - fn i2c_callback(command: &[u8], response: &mut Deque<u8, MESSAGE_SIZE>) { #[allow(static_mut_refs)] let state = unsafe { STATE.as_mut().unwrap() }; if process_command(state, command, response) { - WATCHDOG_PING.signal(Instant::now()); + watchdog::ping(); } else { // If this does not succeed, this will reset due to // a lack of petting the window watchdog. @@ -180,7 +129,7 @@ fn process_command( } &[CMD_MOTOR_SHUTDOWN_TIMEOUT, ticks] => { if (1..=100).contains(&ticks) { - WATCHDOG_TICKS.store(ticks, Ordering::Relaxed); + watchdog::set_shutdown_timeout(ticks); } else { defmt::warn!("ticks out of range: {}", ticks); return false; @@ -188,7 +137,7 @@ fn process_command( } [CMD_MOTOR_SHUTDOWN_TIMEOUT] => { response - .push_back(WATCHDOG_TICKS.load(Ordering::Relaxed)) + .push_back(watchdog::get_shutdown_timeout()) .unwrap(); } [CMD_ENCODER_TICKS] => { diff --git a/controller/src/logic/watchdog.rs b/controller/src/logic/watchdog.rs new file mode 100644 index 0000000..a31917e --- /dev/null +++ b/controller/src/logic/watchdog.rs @@ -0,0 +1,61 @@ +use super::motor_control; +use core::sync::atomic::{AtomicU8, Ordering}; +use embassy_stm32::pac::{self, wwdg::vals::Wdgtb}; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}; +use embassy_time::{Duration, Instant, Ticker}; + +static WATCHDOG_PING: Signal<CriticalSectionRawMutex, Instant> = Signal::new(); +static WATCHDOG_TICKS: AtomicU8 = AtomicU8::new(5); + +pub fn ping() { + WATCHDOG_PING.signal(Instant::now()); +} + +pub fn set_shutdown_timeout(ticks: u8) { + WATCHDOG_TICKS.store(ticks, Ordering::Relaxed); +} + +pub fn get_shutdown_timeout() -> u8 { + WATCHDOG_TICKS.load(Ordering::Relaxed) +} + +#[embassy_executor::task] +pub async fn watchdog() { + wwdg_configure(); + let mut ticker = Ticker::every(Duration::from_millis(50)); + let mut watchdog_expiration: Instant = Instant::now(); + loop { + ticker.next().await; + wwdg_pet(); + if let Some(ping) = WATCHDOG_PING.try_take() { + watchdog_expiration = ping + + Duration::from_millis(100 * u64::from(WATCHDOG_TICKS.load(Ordering::Relaxed))); + } + if motor_control::is_moving() && Instant::now() >= watchdog_expiration { + defmt::debug!("stopping motors after watchdog has expired"); + motor_control::standby().await; + } + } +} + +fn wwdg_configure() { + // Enable WWDG clock + pac::RCC.apb1enr().modify(|w| w.set_wwdgen(true)); + // With PCLK1 at 36MHz, 63 as a timeout value with wdgtb at /8 + // means ~58ms. Comparing with a value of 45 means that at + // least ~42ms must have passed before the watchdog can be + // petted, so we have 8ms on each side. + pac::WWDG.cfr().write(|w| { + w.set_wdgtb(Wdgtb::DIV8); + w.set_w((1 << 6) | 31); + }); + wwdg_pet(); +} + +fn wwdg_pet() { + // Reset watchdog and start it if not started yet + pac::WWDG.cr().write(|w| { + w.set_t((1 << 6) | 63); + w.set_wdga(true); + }); +} -- GitLab