Skip to main content

Crate embassy_task_watchdog

Crate embassy_task_watchdog 

Source
Expand description

§embassy-task-watchdog

A robust, flexible watchdog management library for embedded systems that multiplexes multiple task watchdogs into a single hardware watchdog timer, preventing system lockups when tasks fail to respond

This crate provides a task registration pattern that monitors multiple tasks and ensures they are all still active, feeding the hardware watchdog only if all tasks are healthy.

Multiplexed Task Diagram

§Key Features

  • Task Multiplexing: Consolidates multiple independent task watchdogs into a single hardware watchdog, triggering if any task fails to check in
  • Static and Automated Task Management: Tasks are registered at compile-time, allowing hassle-free integration without dynamic memory allocation, and with minimal boilerplate using the provided #[task] macro. By default, the library supports 32 watchdog tasks. The limit can be changed by setting the EMBASSY_TASK_WATCHDOG_MAX_TASKS variable either in your .cargo/config.toml, or by passing it as an environment variable to cargo, e.g. EMBASSY_TASK_WATCHDOG_MAX_TASKS=8 cargo build. The check is disabled in debug builds to prevent errors in IDEs, but exceeding the number of tasks will trigger a compiler error in the release build.
  • Async Support: Works with asynchronous (Embassy) execution environments
  • Configurable Timeouts: Individual timeout durations for each registered task
  • no_std Compatible: Designed for resource-constrained embedded environments without an operating system

§Usage

The following is a complete, minimal, example for using the task-watchdog crate using embassy-rs on an RP2040 or RP2350 (Pico or Pico 2). It uses static allocation (no alloc), and creates two tasks with different timeouts, both of which are policed by task-watchdog, and in turn, the hardware watchdog.


#[embassy_executor::main]
async fn main(spawner: Spawner) {
    // Initialize the hardare peripherals
    let p = embassy_rp::init(Config::default());
    // Create the watchdog runner, store it in a static cell, and get the watchdog and watchdog runner task.
    let (watchdog, watchdogtask) = create_watchdog!(p.WATCHDOG, config);
    // Spawn tasks that will feed the watchdog
    spawner.must_spawn(main_task(watchdog));
    spawner.must_spawn(second_task(watchdog));
    // Finally spawn the watchdog - this will start the hardware watchdog, and feed it
    // for as long as _all_ tasks are healthy.
    spawner.must_spawn(watchdog_task(watchdogtask));
}
// Provide a simple embassy task for the watchdog
#[embassy_executor::task]
async fn watchdog_task(watchdog: WatchdogRunner) -> ! {
    watchdog.run().await
}
// Implement your main task
#[embassy_task_watchdog::task(timeout = Duration::from_millis(1500))]
async fn main_task(watchdog: TaskWatchdog) -> ! {
    loop {
        // Feed the watchdog
        watchdog.feed().await;
        // Do some work
        Timer::after(Duration::from_millis(1000)).await;
    }
}
// Implement your second task
#[embassy_task_watchdog::task(timeout = Duration::from_millis(2000))]
async fn second_task(watchdog: TaskWatchdog) -> ! {
    loop {
        // Feed the watchdog
        watchdog.feed().await;
        // Do some work
        Timer::after(Duration::from_millis(2000)).await;
    }
}

See the examples for more usage examples.

§Targets

For embedded devices you need to install and specify your target when building. Use:

  • RP2040 - thumbv6m-none-eabi
  • RP2350 - thumbv8m.main-none-eabihf

§Feature Flags

The following feature flags are supported

  • rp: Enable the Raspberry Pi MCU-specific embassy implementation
  • defmt-embassy-rp: Enable logging with defmt for the RP2040 and RP2350 embassy
  • stm32: Enable the STM32 MCU-specific embassy implementation
  • defmt-embassy-stm32: Enable logging with defmt for the STM32 embassy
  • defmt: Enable defmt logging of associated structs and enums.
  • defmt-messages: Enable defmt logging of events and errors in the library.

§Example Feature/Target combination

This builds the library for RP2040 with embassy and defmt support:

cargo build --features rp,defmt-embassy-rp --target thumbv6m-none-eabi
§Note

It is recommended to build the project and run it by writing the build configuration in .cargo/config.toml, and executing cargo build without any additional arguments.

§Inspiration

This work is inspired heavily by the task-watchdog crate by Piers Finlayson, which provides a similar task multiplexing watchdog for embedded systems. It has not been maintained in almost a year (last commit was on April 10, 2025). This crate is a fork of that work, with the following goals:

  • Update the codebase to be compatible with the latest versions of Rust and Embassy, and to use modern Rust features and idioms.
  • Automate the task registration process with a procedural macro, to reduce boilerplate and make it easier to use.
  • Get rid of custom task identifier types through the task_watchdog::Id trait.

To achieve these goals, the codebase has been refactored and the scope has been limited to embassy-based async applications, which is the primary use case for this crate. The API has been redesigned to be more ergonomic and easier to use, while still providing the same core functionality of multiplexing multiple task watchdogs into a single hardware watchdog timer.

Modules§

embassy_rprp
An async implementation of embassy-task-watchdog for use with the RP2040 and RP2350 embassy implementations.
embassy_stm32stm32
An async implementation of embassy-task-watchdog for use with the STM32 embassy implementations.

Macros§

create_watchdogstm32 and rp
Initialize the static memory for the watchdog, and return the watchdog and the watchdog runner task. Pass the TaskWatchdog struct to your tasks to be able to feed the watchdog. Execute the WatchdogRunner::run function inside a spawned task to monitor the tasks and feed the hardware watchdog.

Structs§

WatchdogConfig
Configuration for the watchdog.

Enums§

ResetReason
Represents the reason for a system reset.

Traits§

HardwareWatchdog
Represents a hardware-level watchdog that can be fed and reset the system.

Attribute Macros§

task
This decorator macro replaces embassy_executor::task to create an async task that can be monitored by the task-watchdog.