Skip to content
Snippets Groups Projects
Commit b39f3f3a authored by Samuel Tardieu's avatar Samuel Tardieu
Browse files

Separate watchdog code into a module

parent 5afddae6
No related branches found
No related tags found
No related merge requests found
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] => {
......
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);
});
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment