Skip to content

stm32: implement WWDG peripheral (windowed watchdog)#19350

Open
dpgeorge wants to merge 2 commits into
micropython:masterfrom
dpgeorge:stm32-implement-wwdg
Open

stm32: implement WWDG peripheral (windowed watchdog)#19350
dpgeorge wants to merge 2 commits into
micropython:masterfrom
dpgeorge:stm32-implement-wwdg

Conversation

@dpgeorge

Copy link
Copy Markdown
Member

Summary

The stm32 port already supports machine.WDT(), which accesses the IWDG peripheral (independent watchdog).

This PR adds support for the STM32 WWDG peripheral (windowed watchdog), through the same, standard machine.WDT() class interface. It's accessed as peripheral id=1.

So now it's possible to have 2 watchdogs, like this:

import machine

w1 = machine.WDT(timeout=5000)  # IWDG
w2 = machine.WDT(1, timeout=100)  #WWDG
w1.feed()
w2.feed()

The maximum timeout is quite limited on this watchdog due to the limited prescaler values, for example:

  • STM32F4 at 168MHz: 49ms max timeout (at 96MHz it's 87ms max)
  • STM32F7 at 216MHz: 38ms max timeout
  • STM32N6 at 800MHz: 167ms max timeout
  • STM32WB at 64MHz: 524ms max timeout

So it needs to be used with care.

Testing

Tested on:

  • PYBV10
  • PYB_SF6
  • NUCLEO_WB55
  • OPENMV_N6

Trade-offs and Alternatives

The hardest decision here is how to name/access the peripherals. All existing ports have only one watchdog exposed, and it's the default when you do machine.WDT() -- that's equivalent to machine.WDT(0).

But now with more than one watchdog, how to name them? The stm32 datasheets call them IWDG and WWDG on everything except H7 which has two of each: IWDG1, IWDG2, WWDG1 and WWDG2 (only IWDG1/WWDG1 are currently implemented on H7).

Note that mimxrt also has multiple watchdogs: WDOG1, WDOG2 (and WDOG3 if it exists on the MCU). Currently only WDOG1 is exposed (as machine.WDT(0)).

To be consistent with other stm32 peripheral naming, the IWDG1/IWDG2 should probably be accessed via id=1 and id=2 respectively. Then WWDG1/WWDG2 could be id=3 and id=4... although that's not very intuitive. Instead they could be named by a string like machine.WDT("WWDG1") etc. The default machine.WDT() would still access IWDG(1), but I guess it should also be available via the string "IWDG"/"IWDG1".

Generative AI

Not used.

dpgeorge added 2 commits June 17, 2026 16:01
This adds support for the STM32 WWDG peripheral, through the standard
`machine.WDT()` class interface.  It's accessed as peripheral id=1.

The maximum timeout is quite limited on this watchdog due to the limited
prescale values, for example:
- STM32F4 at 168MHz: 49ms max timeout (at 96MHz it's 87ms max)
- STM32F7 at 216MHz: 38ms max timeout
- STM32N6 at 800MHz: 167ms max timeout
- STM32WB at 64MHz: 524ms max timeout

Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
@dpgeorge

Copy link
Copy Markdown
Member Author

@kwagyeman FYI. Note that the timeout is very limited. The N6 with 167ms is actually a relatively large timeout value!

Do you need to access all 4 watchdogs on the H7? If so, do you have any good ideas for naming them (see above)?

@github-actions

Copy link
Copy Markdown

Code size report:

Reference:  unix/README: Update the supported targets list. [d901e98]
Comparison: docs/library/machine.WDT: Mention stm32 WWDG in WDT docs. [merge of b8fbadf]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:  +256 +0.064% PYBV10[incl +12(data)]
      esp32:    +0 +0.000% ESP32_GENERIC
     mimxrt:    +0 +0.000% TEENSY40
        rp2:    +0 +0.000% RPI_PICO_W
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@kwagyeman

Copy link
Copy Markdown
Contributor

@dpgeorge - Probably, mapping string names to a simple linear dict with numeric keys is fine. Then you can pass an ID (arbitrary number) or a string (less arbitrary). What matters is that they no longer move after being assigned.

As for the watchdogs, yes, enable all. And for the timeout, it's fine as long as a user uses asyncio and doesn't block. The reason for the WWDG is that the other one doesn't turn off when you go into deep sleep, so you get reset by it during sleep.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants