Skip to content
Open
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
14 changes: 12 additions & 2 deletions boards/nucleo_u545re_q/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ struct NucleoU545RE {
stm32u545::tim::Tim2<'static>,
>,
>,
// Comment the line below if you don't need a watchdog
watchdog: &'static stm32u545::iwdg::Iwdg,
}

impl SyscallDriverLookup for NucleoU545RE {
Expand All @@ -75,7 +77,10 @@ impl KernelResources<ChipHw> for NucleoU545RE {
type ProcessFault = ();
type Scheduler = components::sched::round_robin::RoundRobinComponentType;
type SchedulerTimer = cortexm33::systick::SysTick;
type WatchDog = ();
// Comment the line below if you do not need a watchdog
type WatchDog = stm32u545::iwdg::Iwdg;
// Uncomment the line below if you dont need a watchdog
// type WatchDog = ();
type ContextSwitchCallback = ();

fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
Expand All @@ -94,7 +99,9 @@ impl KernelResources<ChipHw> for NucleoU545RE {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
// Return &() if you don't need a watchdog
// &()
self.watchdog
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
Expand Down Expand Up @@ -151,6 +158,8 @@ unsafe fn start() -> (
stm32u545::usart::Usart::new(stm32u545::usart::USART1_BASE)
);
usart1.register();
// Comment the line blow if you do not need a watchdog
let iwdg = static_init!(stm32u545::iwdg::Iwdg, stm32u545::iwdg::Iwdg::new());

// Load Peripherals Bundle
let periphs = static_init!(
Expand Down Expand Up @@ -244,6 +253,7 @@ unsafe fn start() -> (
led,
button,
alarm,
watchdog: iwdg, // Comment this if you do not need a watchdog
}
);

Expand Down
2 changes: 1 addition & 1 deletion chips/stm32u545/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#![no_std]

pub use stm32u5xx::{chip, dma, exti, gpio, rcc, tim, usart};
pub use stm32u5xx::{chip, dma, exti, gpio, iwdg, rcc, tim, usart};

use cortexm33::{CortexM33, CortexMVariant};

Expand Down
1 change: 1 addition & 0 deletions chips/stm32u5xx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Currently supported peripherals:
- USART (Universal Synchronous/Asynchronous Receiver Transmitter)
- GPDMA (Global Programmable DMA)
- TIM2 (Timer)
- IWDG (Independent Watchdog)
136 changes: 136 additions & 0 deletions chips/stm32u5xx/src/iwdg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright OxidOS Automotive 2026.

use kernel::platform::watchdog::WatchDog;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{
register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
};
use kernel::utilities::StaticRef;

register_structs! {
IwdgRegisters {
// Key register
(0x00 => kr: WriteOnly<u32, KR::Register>),
// Prescaler register
(0x04 => pr: ReadWrite<u32, PR::Register>),
// Reload register
(0x08 => rlr: ReadWrite<u32, RLR::Register>),
// Status register
(0x0C => sr: ReadOnly<u32, SR::Register>),
// Window register
(0x10 => winr: ReadWrite<u32, WINR::Register>),
// Early wake-up register
(0x14 => ewcr: ReadWrite<u32, EWCR::Register>),
(0x18 => @END),
}
}

register_bitfields! [u32,
KR [
KEY OFFSET(0) NUMBITS(16) [
Reload = 0xAAAA, // Reset the timer
Unlock = 0x5555, // Unlock registers for writing
Start = 0xCCCC, // Start timer
],
],

PR [
// Prescaler divider
PR OFFSET(0) NUMBITS(4) [
DivideBy4 = 0b0000,
DivideBy8 = 0b0001,
DivideBy16 = 0b0010,
DivideBy32 = 0b0011,
DivideBy64 = 0b0100,
DivideBy128 = 0b0101,
DivideBy256 = 0b0110,
DivideBy512 = 0b0111,
],
],

RLR [
// Watchdog counter reload value
RL OFFSET(0) NUMBITS(12) [
Thousand = 1000u32,
],
],

SR [
// Watchdog early interrupt flag
EWIF OFFSET(14) NUMBITS(1) [],

// Watchdog interrupt comparartor value update
EWU OFFSET(3) NUMBITS(1) [],

// Watchdog counter window value update
WVU OFFSET(2) NUMBITS(1) [],

// Watchdog counter reload value update
RVU OFFSET(1) NUMBITS(1) [],

// Watchdog prescaler value update
PVU OFFSET(0) NUMBITS(1) [],
],

WINR [
// Watchdog counter window value
WIN OFFSET(0) NUMBITS(12) [],
],

EWCR [

// Watchdog early interrupt enable
EWIE OFFSET(15) NUMBITS(1) [],

// Watchdog early interrupt acknowledge
EWIC OFFSET(14) NUMBITS(1) [],

// Watchdog counter early wake-up interrupt value
EWIT OFFSET(0) NUMBITS(12) [],
]
];

const IWDG_BASE: StaticRef<IwdgRegisters> =
unsafe { StaticRef::new(0x40003000 as *const IwdgRegisters) };

pub struct Iwdg {
registers: StaticRef<IwdgRegisters>,
}

impl Iwdg {
pub const fn new() -> Iwdg {
Iwdg {
registers: IWDG_BASE,
}
}
}

impl WatchDog for Iwdg {
fn setup(&self) {
self.registers.kr.write(KR::KEY::Unlock);

while self.registers.sr.is_set(SR::PVU) || self.registers.sr.is_set(SR::RVU) {
// Block the executor until hardware is ready
}

// 32hz / 32 = 1hz => one tick per ms => 1000 to RL register means 1 second timeout before reboot
self.registers.pr.write(PR::PR::DivideBy32);
self.registers.rlr.write(RLR::RL::Thousand);

self.registers.kr.write(KR::KEY::Start);
self.tickle();
}

fn tickle(&self) {
// Reset the counter
self.registers.kr.write(KR::KEY::Reload);
}

fn suspend(&self) {}

fn resume(&self) {
self.tickle();
}
}
1 change: 1 addition & 0 deletions chips/stm32u5xx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod chip;
pub mod dma;
pub mod exti;
pub mod gpio;
pub mod iwdg;
pub mod nvic;
pub mod rcc;
pub mod tim;
Expand Down
Loading