Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IWDT - Independent watchdog timer #82

Merged
merged 3 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions examples/independent_watchdog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Originaly from stm32h7xx-hal, adapted for stm32g4xx-hal

#![no_main]
#![no_std]

//#[macro_use]
//mod utils;
use stm32g4xx_hal::{independent_watchdog::IndependentWatchdog, prelude::*, stm32::Peripherals};

use cortex_m_rt::entry;

// TODO: Use utils instead
use defmt::Logger;
use defmt_rtt as _; // global logger
use panic_probe as _;

use defmt::info; // TODO: Use utils::logger instead

#[entry]
fn main() -> ! {
//utils::logger::init();
let dp = Peripherals::take().unwrap();

let mut watchdog = IndependentWatchdog::new(dp.IWDG);

info!("");
info!("stm32g4xx-hal example - Watchdog");
info!("");

// If the watchdog is working correctly this print should
// appear again and again as the chip gets restarted
info!("Watchdog restarted! ");

// Enable the watchdog with a limit of 32.76 seconds (which is the maximum this watchdog can do) and wait forever
// -> restart the chip
watchdog.start(32_760.ms());

// Alternatively, there's also a windowed option where if the watchdog is fed before the window time, it will reset the chip as well
// watchdog.start_windowed(100.millis(), 200.millis());

loop {
// We can feed the watchdog like this:
// watchdog.feed();
cortex_m::asm::nop()
}
}
150 changes: 150 additions & 0 deletions src/independent_watchdog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
//! Independent Watchdog
//!
//! This module implements the embedded-hal
//! [Watchdog](https://docs.rs/embedded-hal/latest/embedded_hal/watchdog/trait.Watchdog.html)
//! trait for the Independent Watchdog peripheral.
//!
//! The Independent Watchdog peripheral triggers a system reset when its internal counter expires.
//!
//! # Examples
//!
//! - [IWDG Example](todo-insert-link-here)
//!
//! Originally from stm32h7-hal, adapted for stm32g4xx-hal
use crate::{
stm32::{iwdg::pr::PR_A, IWDG},
time::{MicroSecond, U32Ext},
};

/// The implementation of the hardware IWDG
pub struct IndependentWatchdog {
iwdg: IWDG,
}

impl IndependentWatchdog {
const CLOCK_SPEED: u32 = 32000;
const MAX_COUNTER_VALUE: u32 = 0x00000FFF;
const MAX_MILLIS_FOR_PRESCALER: [(PR_A, u32); 8] = [
(
PR_A::DivideBy4,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 4),
),
(
PR_A::DivideBy8,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 8),
),
(
PR_A::DivideBy16,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 16),
),
(
PR_A::DivideBy32,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 32),
),
(
PR_A::DivideBy64,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 64),
),
(
PR_A::DivideBy128,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 128),
),
(
PR_A::DivideBy256,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256),
),
(
PR_A::DivideBy256bis,
(Self::MAX_COUNTER_VALUE * 1000) / (Self::CLOCK_SPEED / 256),
),
];

/// Create a new instance
pub fn new(iwdg: IWDG) -> Self {
Self { iwdg }
}

/// Feed the watchdog, resetting the timer to 0
pub fn feed(&mut self) {
self.iwdg.kr.write(|w| w.key().reset());
}

/// Start the watchdog where it must be fed before the max time is over and
/// not before the min time has passed
pub fn start_windowed<T: Into<MicroSecond>>(&mut self, min_window_time: T, max_window_time: T) {
let min_window_time: MicroSecond = min_window_time.into();
let max_window_time: MicroSecond = max_window_time.into();

// Start the watchdog
self.iwdg.kr.write(|w| w.key().start());
// Enable register access
self.iwdg.kr.write(|w| w.key().enable());

// Set the prescaler
let (prescaler, _) = Self::MAX_MILLIS_FOR_PRESCALER
.iter()
.find(|(_, max_millis)| *max_millis >= max_window_time.0 / 1000)
.expect("IWDG max time is greater than is possible");
while self.iwdg.sr.read().pvu().bit_is_set() {
cortex_m::asm::nop();
}
self.iwdg.pr.write(|w| w.pr().variant(*prescaler));

// Reset the window value
while self.iwdg.sr.read().wvu().bit_is_set() {
cortex_m::asm::nop();
}
self.iwdg
.winr
.write(|w| w.win().bits(Self::MAX_COUNTER_VALUE as u16));

// Calculate the counter values
let reload_value = (max_window_time.0 / 1000) * (Self::CLOCK_SPEED / 1000)
/ Self::get_prescaler_divider(prescaler);
let window_value = (min_window_time.0 / 1000) * (Self::CLOCK_SPEED / 1000)
/ Self::get_prescaler_divider(prescaler);

// Set the reload value
while self.iwdg.sr.read().rvu().bit_is_set() {
cortex_m::asm::nop();
}
self.iwdg.rlr.write(|w| w.rl().bits(reload_value as u16));

self.feed();
// Enable register access
self.iwdg.kr.write(|w| w.key().enable());

// Set the window value
while self.iwdg.sr.read().wvu().bit_is_set() {
cortex_m::asm::nop();
}
self.iwdg
.winr
.write(|w| w.win().bits((reload_value - window_value) as u16));

// Wait until everything is set
while self.iwdg.sr.read().bits() != 0 {
cortex_m::asm::nop();
}

self.feed();
}

/// Start the watchdog with the given max time and no minimal time
pub fn start<T: Into<MicroSecond>>(&mut self, max_time: T) {
self.start_windowed(0_u32.ms(), max_time.into());
}

fn get_prescaler_divider(prescaler: &PR_A) -> u32 {
match prescaler {
PR_A::DivideBy4 => 4,
PR_A::DivideBy8 => 8,
PR_A::DivideBy16 => 16,
PR_A::DivideBy32 => 32,
PR_A::DivideBy64 => 64,
PR_A::DivideBy128 => 128,
PR_A::DivideBy256 => 256,
PR_A::DivideBy256bis => 256,
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,4 @@ pub mod syscfg;
pub mod time;
pub mod timer;
// pub mod watchdog;
pub mod independent_watchdog;