From 6dc660a203285f3e4fd7e90d8809c0e3dd928bee Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Thu, 2 Jul 2026 13:02:03 +0300 Subject: [PATCH 1/9] Started working in IDWG for stm32u5 chips Signed-off-by: Oleksandr --- chips/stm32u5xx/src/idwg.rs | 129 ++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 chips/stm32u5xx/src/idwg.rs diff --git a/chips/stm32u5xx/src/idwg.rs b/chips/stm32u5xx/src/idwg.rs new file mode 100644 index 0000000000..1bae972a35 --- /dev/null +++ b/chips/stm32u5xx/src/idwg.rs @@ -0,0 +1,129 @@ +use kernel::platform::watchdog::WatchDog; +use kernel::utilities::registers::{ + register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly, +}; +use kernel::utilities::StaticRef; + +register_structs! { + IdwgRegisters { + // Key register + (0x00 => kr: WriteOnly), + // Prescaler register + (0x04 => pr: ReadWrite rlr: ReadWrite sr: ReadOnly winr: ReadWrite ewcr: ReadWrite @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) [] + ], + + 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 IDWG_BASE: StaticRef = + unsafe { StaticRef::new(0x40003000 as *const IdwgRegisters) }; + +pub struct Idwg { + registers: IdwgRegisters, +} + +impl Idwg { + pub const fn new() { + Idwg { + registers: IDWG_BASE, + } + } +} + +impl WatchDog for Idwg { + 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 + } + + // 1 second + self.registers.pr.write(PR::PR::DivideBy32); + self.registers.rlr.write(1000); + + self.registers.kr.write(KR::KEY::Start); + self.tickle(); + } + + fn tickle(&self) { + // Reset the counter + self.register.rk.write(KR::KEY::Reload); + } + + fn suspend(&self) {} + + fn resume(&self) { + self.tickle(); + } +} From abe8a91c1c5073b7fe39df4e19380fafa6f00ebb Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Thu, 2 Jul 2026 14:52:16 +0300 Subject: [PATCH 2/9] feat: iwdg implementation Signed-off-by: Oleksandr --- boards/nucleo_u545re_q/src/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/boards/nucleo_u545re_q/src/main.rs b/boards/nucleo_u545re_q/src/main.rs index 7f8403b6b2..adbe403044 100644 --- a/boards/nucleo_u545re_q/src/main.rs +++ b/boards/nucleo_u545re_q/src/main.rs @@ -52,6 +52,7 @@ struct NucleoU545RE { stm32u545::tim::Tim2<'static>, >, >, + watchdog: &'static stm32u545::iwdg::Iwdg, } impl SyscallDriverLookup for NucleoU545RE { @@ -75,7 +76,7 @@ impl KernelResources for NucleoU545RE { type ProcessFault = (); type Scheduler = components::sched::round_robin::RoundRobinComponentType; type SchedulerTimer = cortexm33::systick::SysTick; - type WatchDog = (); + type WatchDog = stm32u545::iwdg::Iwdg; type ContextSwitchCallback = (); fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { @@ -94,7 +95,7 @@ impl KernelResources for NucleoU545RE { &self.systick } fn watchdog(&self) -> &Self::WatchDog { - &() + &self.watchdog } fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { &() @@ -151,6 +152,7 @@ unsafe fn start() -> ( stm32u545::usart::Usart::new(stm32u545::usart::USART1_BASE) ); usart1.register(); + let iwdg = static_init!(stm32u545::iwdg::Iwdg, stm32u545::iwdg::Iwdg::new()); // Load Peripherals Bundle let periphs = static_init!( @@ -244,6 +246,7 @@ unsafe fn start() -> ( led, button, alarm, + watchdog: iwdg, } ); From c4e6311b8350f30156249707e8bec76b82bf55e8 Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Thu, 2 Jul 2026 15:03:01 +0300 Subject: [PATCH 3/9] feat: iwdg implementation fix Signed-off-by: Oleksandr --- chips/stm32u545/src/lib.rs | 2 +- chips/stm32u5xx/src/iwdg.rs | 132 ++++++++++++++++++++++++++++++++++++ chips/stm32u5xx/src/lib.rs | 1 + 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 chips/stm32u5xx/src/iwdg.rs diff --git a/chips/stm32u545/src/lib.rs b/chips/stm32u545/src/lib.rs index 9bb37ae830..3a80d1b9b4 100644 --- a/chips/stm32u545/src/lib.rs +++ b/chips/stm32u545/src/lib.rs @@ -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}; diff --git a/chips/stm32u5xx/src/iwdg.rs b/chips/stm32u5xx/src/iwdg.rs new file mode 100644 index 0000000000..f811b4c929 --- /dev/null +++ b/chips/stm32u5xx/src/iwdg.rs @@ -0,0 +1,132 @@ +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), + // Prescaler register + (0x04 => pr: ReadWrite), + // Reload register + (0x08 => rlr: ReadWrite), + // Status register + (0x0C => sr: ReadOnly), + // Window register + (0x10 => winr: ReadWrite), + // Early wake-up register + (0x14 => ewcr: ReadWrite), + (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 = + unsafe { StaticRef::new(0x40003000 as *const IwdgRegisters) }; + +pub struct Iwdg { + registers: StaticRef, +} + +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 + } + + // 1 second + 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(); + } +} diff --git a/chips/stm32u5xx/src/lib.rs b/chips/stm32u5xx/src/lib.rs index f9bc0e4651..6a80f3dc08 100644 --- a/chips/stm32u5xx/src/lib.rs +++ b/chips/stm32u5xx/src/lib.rs @@ -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; From 83888de42604548df4fa890fb0d475bae5b1d2cb Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Thu, 2 Jul 2026 15:20:28 +0300 Subject: [PATCH 4/9] fix failing test Signed-off-by: Oleksandr --- boards/nucleo_u545re_q/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/nucleo_u545re_q/src/main.rs b/boards/nucleo_u545re_q/src/main.rs index adbe403044..c0ce904c4a 100644 --- a/boards/nucleo_u545re_q/src/main.rs +++ b/boards/nucleo_u545re_q/src/main.rs @@ -95,7 +95,7 @@ impl KernelResources for NucleoU545RE { &self.systick } fn watchdog(&self) -> &Self::WatchDog { - &self.watchdog + self.watchdog } fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { &() From f44d816ac268d71f286861375ee150f5c705bcc0 Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Thu, 2 Jul 2026 15:23:53 +0300 Subject: [PATCH 5/9] Remove redudandt file Signed-off-by: Oleksandr --- chips/stm32u5xx/src/idwg.rs | 129 ------------------------------------ 1 file changed, 129 deletions(-) delete mode 100644 chips/stm32u5xx/src/idwg.rs diff --git a/chips/stm32u5xx/src/idwg.rs b/chips/stm32u5xx/src/idwg.rs deleted file mode 100644 index 1bae972a35..0000000000 --- a/chips/stm32u5xx/src/idwg.rs +++ /dev/null @@ -1,129 +0,0 @@ -use kernel::platform::watchdog::WatchDog; -use kernel::utilities::registers::{ - register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly, -}; -use kernel::utilities::StaticRef; - -register_structs! { - IdwgRegisters { - // Key register - (0x00 => kr: WriteOnly), - // Prescaler register - (0x04 => pr: ReadWrite rlr: ReadWrite sr: ReadOnly winr: ReadWrite ewcr: ReadWrite @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) [] - ], - - 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 IDWG_BASE: StaticRef = - unsafe { StaticRef::new(0x40003000 as *const IdwgRegisters) }; - -pub struct Idwg { - registers: IdwgRegisters, -} - -impl Idwg { - pub const fn new() { - Idwg { - registers: IDWG_BASE, - } - } -} - -impl WatchDog for Idwg { - 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 - } - - // 1 second - self.registers.pr.write(PR::PR::DivideBy32); - self.registers.rlr.write(1000); - - self.registers.kr.write(KR::KEY::Start); - self.tickle(); - } - - fn tickle(&self) { - // Reset the counter - self.register.rk.write(KR::KEY::Reload); - } - - fn suspend(&self) {} - - fn resume(&self) { - self.tickle(); - } -} From ebf35d29d7f019037c29ff875e830571cc496189 Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Thu, 2 Jul 2026 16:03:57 +0300 Subject: [PATCH 6/9] add licence Signed-off-by: Oleksandr --- chips/stm32u5xx/src/iwdg.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chips/stm32u5xx/src/iwdg.rs b/chips/stm32u5xx/src/iwdg.rs index f811b4c929..6784e586a5 100644 --- a/chips/stm32u5xx/src/iwdg.rs +++ b/chips/stm32u5xx/src/iwdg.rs @@ -1,3 +1,7 @@ +// 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::{ From 537d5302a4718654ee1d750bb2109cb6318b8746 Mon Sep 17 00:00:00 2001 From: Oleksandr <88773083+sanyaswee@users.noreply.github.com> Date: Thu, 2 Jul 2026 16:10:22 +0300 Subject: [PATCH 7/9] Update docs Signed-off-by: Oleksandr --- chips/stm32u5xx/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/chips/stm32u5xx/README.md b/chips/stm32u5xx/README.md index 7679a6c50f..afeb64836a 100644 --- a/chips/stm32u5xx/README.md +++ b/chips/stm32u5xx/README.md @@ -12,3 +12,4 @@ Currently supported peripherals: - USART (Universal Synchronous/Asynchronous Receiver Transmitter) - GPDMA (Global Programmable DMA) - TIM2 (Timer) +- IWDG (Independent Watchdog) From 51970283b0371491dc57c178aecf8f46c3871b4c Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Fri, 3 Jul 2026 11:34:54 +0300 Subject: [PATCH 8/9] Added comments on how to disable the watchdog Signed-off-by: Oleksandr --- boards/nucleo_u545re_q/src/main.rs | 9 ++++++++- chips/stm32u5xx/src/iwdg.rs | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/boards/nucleo_u545re_q/src/main.rs b/boards/nucleo_u545re_q/src/main.rs index c0ce904c4a..81634fa650 100644 --- a/boards/nucleo_u545re_q/src/main.rs +++ b/boards/nucleo_u545re_q/src/main.rs @@ -52,6 +52,7 @@ struct NucleoU545RE { stm32u545::tim::Tim2<'static>, >, >, + // Comment the line below if you don't need a watchdog watchdog: &'static stm32u545::iwdg::Iwdg, } @@ -76,7 +77,10 @@ impl KernelResources for NucleoU545RE { type ProcessFault = (); type Scheduler = components::sched::round_robin::RoundRobinComponentType; type SchedulerTimer = cortexm33::systick::SysTick; + // 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 { @@ -95,6 +99,8 @@ impl KernelResources 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 { @@ -152,6 +158,7 @@ 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 @@ -246,7 +253,7 @@ unsafe fn start() -> ( led, button, alarm, - watchdog: iwdg, + watchdog: iwdg, // Comment this if you do not need a watchdog } ); diff --git a/chips/stm32u5xx/src/iwdg.rs b/chips/stm32u5xx/src/iwdg.rs index 6784e586a5..701c19e24e 100644 --- a/chips/stm32u5xx/src/iwdg.rs +++ b/chips/stm32u5xx/src/iwdg.rs @@ -33,6 +33,7 @@ register_bitfields! [u32, Reload = 0xAAAA, // Reset the timer Unlock = 0x5555, // Unlock registers for writing Start = 0xCCCC, // Start timer + Reset = 0x0000, // Reset value ], ], @@ -115,7 +116,7 @@ impl WatchDog for Iwdg { // Block the executor until hardware is ready } - // 1 second + // 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); From 13220beaf73b031434f9ef56a9d31cf59bdd2726 Mon Sep 17 00:00:00 2001 From: Oleksandr Date: Fri, 3 Jul 2026 11:38:20 +0300 Subject: [PATCH 9/9] Remove redudnant reset key Signed-off-by: Oleksandr --- chips/stm32u5xx/src/iwdg.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/chips/stm32u5xx/src/iwdg.rs b/chips/stm32u5xx/src/iwdg.rs index 701c19e24e..4689a1649f 100644 --- a/chips/stm32u5xx/src/iwdg.rs +++ b/chips/stm32u5xx/src/iwdg.rs @@ -33,7 +33,6 @@ register_bitfields! [u32, Reload = 0xAAAA, // Reset the timer Unlock = 0x5555, // Unlock registers for writing Start = 0xCCCC, // Start timer - Reset = 0x0000, // Reset value ], ],