ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_wdt.c File Reference

Software Watchdog Timer (WDT) driver implementation. More...

#include "ra8_wdt.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_hw_err.h"
#include "ra8_icu.h"
#include "ra8_log.h"
#include "ra8_ofs.h"
#include "ra8_wdt_regs.h"
Include dependency graph for ra8_wdt.c:

Go to the source code of this file.

Data Structures

struct  ra8_wdt_sub_t
 One entry in the multi-subscriber dispatch table. More...

Enumerations

enum  ra8_wdt_legacy_slot_t : uint8_t { k_ra8_wdt_legacy_slot = 0U }
 Slot reserved for the legacy single-callback API. More...
enum  ra8_wdt_status_combined_t : uint16_t { k_ra8_wdt_status_all }
 Union of the two WDTSR top-flag bits the driver cares about. More...

Functions

static ra8_err_t internal_default_ofs_reader (uintptr_t ofs_addr, uint32_t *out_word)
 Default OFSm reader: dereferences the address as a 32-bit word.
static bool internal_clock_div_is_valid (ra8_wdt_clock_div_t div)
 Reject CKS encodings the silicon marks as "Setting prohibited".
static bool internal_timeout_sel_is_valid (ra8_wdt_timeout_sel_t sel)
 Reject TOPS encodings outside the documented 2-bit range.
static uint16_t internal_pack_wdtcr (const ra8_wdt_cfg_t *cfg)
 Pack a ra8_wdt_cfg_t into a 16-bit WDTCR word.
static void internal_subs_clear_all (void)
 Clear every subscriber slot.
ra8_err_t ra8_wdt_init (const ra8_wdt_cfg_t *cfg)
 Initialise the WDT in register-start mode.
ra8_err_t ra8_wdt_deinit (void)
 Quiesce the driver into a Sleep-stop posture.
void ra8_wdt_refresh_deferred (void)
 Refresh the software WDT counter (WDT0).
ra8_err_t ra8_wdt_refresh_for (ra8_wdt_instance_t which)
 Refresh a specific WDT instance.
ra8_err_t ra8_wdt_get_status (uint16_t *out_mask)
 Read the WDTSR status flag bits.
ra8_err_t ra8_wdt_clear_status (void)
 Clear the WDTSR underflow / refresh-error flags.
ra8_err_t ra8_wdt_clear_status_blocking (uint16_t mask)
 Clear specific WDTSR flag bits and busy-wait until they read 0.
ra8_err_t ra8_wdt_get_counter (uint16_t *out_count)
 Read the live CNTVAL[13:0] down-counter value.
ra8_err_t ra8_wdt_timeout_cycles_get (ra8_wdt_timeout_sel_t sel, uint16_t *out_cycles)
 Decode a ra8_wdt_timeout_sel_t into its cycle count.
ra8_err_t ra8_wdt_pclkb_divisor (ra8_wdt_clock_div_t div, uint16_t *out_divisor)
 Decode a ra8_wdt_clock_div_t into its numeric divisor.
ra8_err_t ra8_wdt_total_pclkb_cycles (ra8_wdt_timeout_sel_t sel, ra8_wdt_clock_div_t div, uint32_t *out_pclkb_cycles)
 Compute the effective timeout in PCLKB cycles.
ra8_err_t ra8_wdt_attach_handler (ra8_wdt_event_fn_t fn, void *ctx)
 Register a callback invoked from the WDT NMI / underflow ISR.
ra8_err_t ra8_wdt_subscribe (ra8_wdt_event_fn_t fn, void *ctx, uint8_t *out_slot)
 Add a hot-pluggable subscriber to the WDT NMI dispatch list.
ra8_err_t ra8_wdt_unsubscribe (uint8_t slot)
 Remove a previously-registered subscriber.
uint8_t ra8_wdt_subscriber_count (void)
 Number of currently-installed subscribers.
void ra8_wdt_dispatch (void)
 Dispatch a WDT event – snapshot WDTSR + fan-out to subscribers.
ra8_err_t ra8_wdt_install_nmi (void)
 Enable the WDT bit in NMIER so the NMI line fires on underflow.
ra8_err_t ra8_wdt_uninstall_nmi (void)
 Disable the WDT bit in NMIER (counterpart to ra8_wdt_install_nmi).
ra8_err_t ra8_wdt_enter_stop (void)
 Enable counter halt on Sleep entry.
ra8_err_t ra8_wdt_exit_stop (void)
 Disable counter halt on Sleep entry.
ra8_err_t ra8_wdt_ofs_reader_set (ra8_wdt_ofs_reader_fn_t reader)
 Override the OFSm reader hook used by ra8_wdt_ofs_get.
static bool internal_sel_field_uniform (uint32_t sel, uint32_t shift, uint32_t mask)
 Report whether one multi-bit OFS3_SEL field holds a legal encoding.
static bool internal_ofs3_sel_is_legal (uint32_t sel)
 Report whether an OFS3_SEL word is legal in every multi-bit field.
static ra8_err_t internal_read_wdt1_word (uint32_t *out_word)
 Resolve WDT1's effective option word from the OFS3 family.
static void internal_decode_ofs_word (uint32_t ofsm, ra8_wdt_ofs_decoded_t *out)
 Decode the seven WDT fields out of a resolved OFSm word.
ra8_err_t ra8_wdt_ofs_get (ra8_wdt_instance_t which, ra8_wdt_ofs_decoded_t *out)
 Decode an OFSm option-setting word into ra8_wdt_cfg_t.

Variables

static const char * s_tag = "WDT"
 Module log tag.
static ra8_wdt_sub_t s_wdt_subs [k_ra8_wdt_max_subs]
 Dispatch table of registered subscribers.
static ra8_wdt_ofs_reader_fn_t s_ofs_reader = internal_default_ofs_reader
 Active OFSm reader hook (dependency-inverted for test isolation).

Detailed Description

Software Watchdog Timer (WDT) driver implementation.

Tag
[Ring 3 / HAL] {World: S}

Register-start-mode driver for the RA8D2 WDT (HUM Ch 27, p 1256-1270). The companion IWDT lives in ra8_iwdt.c; do not confuse the two.

OFS0 relationship

In auto-start mode the OFS0 option-setting register (HUM Ch 7) latches every period / clock-divider / window / reset-vs-NMI / Sleep-stop bit before this driver runs, and the runtime WDTCR / WDTRCR / WDTCSTPR registers become read-only-as-zero. This driver therefore makes ra8_wdt_init()'s register writes harmless no-ops in that mode while still issuing the first refresh – so the same call site works in either configuration. The decoded OFSm view is exposed by ra8_wdt_ofs_get() so the application can introspect what the boot ROM latched.

In register-start mode (OFS0.WDT0STRT = 1) the same ra8_wdt_init() writes WDTCR / WDTRCR / WDTCSTPR exactly once and then refreshes WDTRR to arm the counter. HUM Ch 27.3.2 limits these three control registers to a single post-reset write, which the driver respects implicitly by exposing only one init entry point.

NMI wiring

The WDT underflow / refresh-error event is not an IELSR-routed peripheral interrupt – it is a non-maskable interrupt source on the ICU's NMIER (HUM Ch 14.2.14 p 542 lists WDTEN at bit 1). ra8_wdt_install_nmi enables that bit (and clears any stale status); the dispatch entry point ra8_wdt_dispatch is what the NMI handler calls.

Multi-subscriber model

The driver maintains a static k_ra8_wdt_max_subs slot table so several modules (state-of-health logger, crash recorder, app cleanup task, ...) can fan-out the same event without any module owning the single callback slot exclusively. The legacy single- callback ra8_wdt_attach_handler still works – it owns one dedicated slot in the same table.

Every register access carries a HUM Ch 27.x citation.

Definition in file ra8_wdt.c.

Enumeration Type Documentation

◆ ra8_wdt_legacy_slot_t

enum ra8_wdt_legacy_slot_t : uint8_t

Slot reserved for the legacy single-callback API.

ra8_wdt_attach_handler shares the same dispatch table as the multi-subscriber API but always lives in slot 0; that way both APIs can coexist without one tearing down the other's entry.

Enumerator
k_ra8_wdt_legacy_slot 

RA8 wdt legacy slot.

Definition at line 104 of file ra8_wdt.c.

◆ ra8_wdt_status_combined_t

enum ra8_wdt_status_combined_t : uint16_t

Union of the two WDTSR top-flag bits the driver cares about.

Enumerator
k_ra8_wdt_status_all 

RA8 wdt status all.

Definition at line 165 of file ra8_wdt.c.

Function Documentation

◆ internal_clock_div_is_valid()

bool internal_clock_div_is_valid ( ra8_wdt_clock_div_t div)
static

Reject CKS encodings the silicon marks as "Setting prohibited".

Parameters
[in]divCaller-supplied divider value.
Returns
true iff div is one of the legal encodings in HUM Ch 27.2.2 p 1258.

See implementation.

Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 191 of file ra8_wdt.c.

References k_ra8_wdt_clkdiv_128, k_ra8_wdt_clkdiv_2048, k_ra8_wdt_clkdiv_4, k_ra8_wdt_clkdiv_512, k_ra8_wdt_clkdiv_64, k_ra8_wdt_clkdiv_8192, and RA8_INTERNAL.

Referenced by ra8_wdt_init().

◆ internal_decode_ofs_word()

void internal_decode_ofs_word ( uint32_t ofsm,
ra8_wdt_ofs_decoded_t * out )
static

Decode the seven WDT fields out of a resolved OFSm word.

Field positions are identical for OFS0's WDT0* fields (HUM Ch 7.2.1 p 280) and OFS3's WDT1* fields (HUM Ch 7.2.6 p 287), so one decoder serves both instances.

Parameters
[in]ofsmResolved 32-bit option word.
[out]outReceives the decoded view.
Precondition
out is non-null (callers validate).
ofsm is a fully resolved option word – for WDT1 that means the OFS3_SEL mux has already been applied.
Postcondition
Every field of *out is assigned.
out->auto_start agrees with out->start_mode.
Note
Thread-safe: touches only its arguments.
Since
0.1.0

Definition at line 802 of file ra8_wdt.c.

References ra8_wdt_ofs_decoded_t::auto_start, ra8_wdt_ofs_decoded_t::cfg, ra8_wdt_cfg_t::clock_div, k_ra8_wdt_ofs_mask_cks, k_ra8_wdt_ofs_mask_rpes, k_ra8_wdt_ofs_mask_rpss, k_ra8_wdt_ofs_mask_rstirqs, k_ra8_wdt_ofs_mask_stpctl, k_ra8_wdt_ofs_mask_strt, k_ra8_wdt_ofs_mask_tops, k_ra8_wdt_ofs_shift_cks, k_ra8_wdt_ofs_shift_rpes, k_ra8_wdt_ofs_shift_rpss, k_ra8_wdt_ofs_shift_rstirqs, k_ra8_wdt_ofs_shift_stpctl, k_ra8_wdt_ofs_shift_strt, k_ra8_wdt_ofs_shift_tops, k_ra8_wdt_ofs_strt_auto, ra8_wdt_cfg_t::on_expiry, RA8_INTERNAL, ra8_wdt_ofs_decoded_t::start_mode, ra8_wdt_cfg_t::stop_in_sleep, ra8_wdt_cfg_t::timeout, ra8_wdt_cfg_t::window_end, and ra8_wdt_cfg_t::window_start.

Referenced by ra8_wdt_ofs_get().

◆ internal_default_ofs_reader()

ra8_err_t internal_default_ofs_reader ( uintptr_t ofs_addr,
uint32_t * out_word )
static

Default OFSm reader: dereferences the address as a 32-bit word.

Used when ra8_wdt_ofs_reader_set(nullptr) is the active reader choice. On the target this maps to a real flash / MRAM read; in unit tests the ra8_wdt_ofs_reader_set hook is normally swapped for a stub that returns canned data.

Parameters
[in]ofs_addrSee implementation.
[in]out_wordSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 142 of file ra8_wdt.c.

References k_ra8_err_null_ptr, k_ra8_ok, and RA8_INTERNAL.

Referenced by ra8_wdt_ofs_reader_set().

◆ internal_ofs3_sel_is_legal()

bool internal_ofs3_sel_is_legal ( uint32_t sel)
static

Report whether an OFS3_SEL word is legal in every multi-bit field.

Checks the four multi-bit selector fields (TOPS, CKS, RPES, RPSS). The three single-bit selectors (STRT, RSTIRQS, STPCTL) cannot be mixed and so are always legal.

Parameters
[in]selRaw OFS3_SEL word.
Returns
Whether every multi-bit selector field is uniform.
Return values
trueAll four fields are uniform; the word can be used as a mux.
falseAt least one field holds a prohibited mixed encoding.
Precondition
sel was read from k_ra8_ofs3_sel_addr.
The shift/mask pairs used below describe OFS3_SEL's field layout, which is identical to OFS3's by construction (HUM Ch 7.2.6 / 7.2.7).
Postcondition
No state is modified.
A true result means sel is safe to use as a bitwise mux.
Note
Thread-safe: pure function of its argument.
MC/DC:
Decision: four ANDed calls to internal_sel_field_uniform – N+1 = 5 vectors, exercised by test_ra8_wdt_ofs.c.
Since
0.1.0

Definition at line 716 of file ra8_wdt.c.

References internal_sel_field_uniform(), k_ra8_wdt_ofs_mask_cks, k_ra8_wdt_ofs_mask_rpes, k_ra8_wdt_ofs_mask_rpss, k_ra8_wdt_ofs_mask_tops, k_ra8_wdt_ofs_shift_cks, k_ra8_wdt_ofs_shift_rpes, k_ra8_wdt_ofs_shift_rpss, k_ra8_wdt_ofs_shift_tops, and RA8_INTERNAL.

Referenced by internal_read_wdt1_word().

◆ internal_pack_wdtcr()

uint16_t internal_pack_wdtcr ( const ra8_wdt_cfg_t * cfg)
static

Pack a ra8_wdt_cfg_t into a 16-bit WDTCR word.

Parameters
[in]cfgCaller-validated configuration block.
Returns
The 16-bit value to write into WDTCR.

See implementation.

Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 256 of file ra8_wdt.c.

References ra8_wdt_cfg_t::clock_div, k_ra8_wdt_mask_cks, k_ra8_wdt_mask_rpes, k_ra8_wdt_mask_rpss, k_ra8_wdt_mask_tops, k_ra8_wdt_shift_cks, k_ra8_wdt_shift_rpes, k_ra8_wdt_shift_rpss, k_ra8_wdt_shift_tops, RA8_INTERNAL, ra8_wdt_cfg_t::timeout, ra8_wdt_cfg_t::window_end, and ra8_wdt_cfg_t::window_start.

Referenced by ra8_wdt_init().

◆ internal_read_wdt1_word()

ra8_err_t internal_read_wdt1_word ( uint32_t * out_word)
static

Resolve WDT1's effective option word from the OFS3 family.

WDT1's boot configuration is not a single word. HUM Ch 7.2.7 p 289 makes OFS3_SEL a per-field selector between the secure copy OFS3_SEC and the non-secure copy OFS3: a selector bit of 0 takes the field from OFS3_SEC, 1 takes it from OFS3. Because each selector bit occupies the same position as the field it governs, the resolution is a bitwise mux over k_ra8_wdt_ofs_field_mask.

Parameters
[out]out_wordReceives the resolved 32-bit option word.
Returns
Result code.
Return values
k_ra8_okResolved.
k_ra8_err_null_ptrout_word was null.
k_ra8_err_invalid_stateOFS3_SEL holds a prohibited encoding.
k_ra8_err_*Whatever the reader hook returned.
Precondition
out_word is non-null.
The active reader can reach the secure option-setting region.
Postcondition
On success *out_word holds the field-wise resolved word.
On failure *out_word is untouched.
Note
Not thread-safe: reads the module-scope reader hook.
Since
0.1.0

Definition at line 751 of file ra8_wdt.c.

References internal_ofs3_sel_is_legal(), k_ra8_err_invalid_state, k_ra8_err_null_ptr, k_ra8_ofs3_addr, k_ra8_ofs3_sec_addr, k_ra8_ofs3_sel_addr, k_ra8_ok, k_ra8_wdt_ofs_field_mask, RA8_INTERNAL, ra8_log_error, s_ofs_reader, and s_tag.

Referenced by ra8_wdt_ofs_get().

◆ internal_sel_field_uniform()

bool internal_sel_field_uniform ( uint32_t sel,
uint32_t shift,
uint32_t mask )
static

Report whether one multi-bit OFS3_SEL field holds a legal encoding.

HUM Ch 7.2.7 p 289 permits only all-zeroes (select OFS3_SEC) or all-ones (select OFS3) in each multi-bit selector field; every mixed encoding is marked "Setting prohibit". A prohibited value leaves the hardware's choice undefined, so it must be rejected rather than decoded.

Parameters
[in]selRaw OFS3_SEL word.
[in]shiftBit position of the field's low bit.
[in]maskField width mask, pre-shift (e.g. 0x3 for a 2-bit field).
Returns
Whether the field is uniformly set or uniformly clear.
Return values
trueThe field is all-zeroes or all-ones.
falseThe field is a prohibited mixed encoding.
Precondition
mask is a contiguous low-aligned bit mask (0x3 for a 2-bit field).
shift places the field inside the 32-bit word: shift + width <= 32.
Postcondition
No state is modified.
The result depends only on the bits mask selects at shift.
Note
Thread-safe: pure function of its arguments.
Since
0.1.0

Definition at line 682 of file ra8_wdt.c.

References RA8_INTERNAL.

Referenced by internal_ofs3_sel_is_legal().

◆ internal_subs_clear_all()

void internal_subs_clear_all ( void )
static

Clear every subscriber slot.

See implementation.

Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 283 of file ra8_wdt.c.

References k_ra8_wdt_max_subs, RA8_INTERNAL, and s_wdt_subs.

Referenced by ra8_wdt_deinit().

◆ internal_timeout_sel_is_valid()

bool internal_timeout_sel_is_valid ( ra8_wdt_timeout_sel_t sel)
static

Reject TOPS encodings outside the documented 2-bit range.

Parameters
[in]selCaller-supplied timeout selector.
Returns
true iff sel is one of the four legal TOPS values.

See implementation.

Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 223 of file ra8_wdt.c.

References k_ra8_wdt_timeout_1024, k_ra8_wdt_timeout_16384, k_ra8_wdt_timeout_4096, k_ra8_wdt_timeout_8192, and RA8_INTERNAL.

Referenced by ra8_wdt_init().

◆ ra8_wdt_attach_handler()

ra8_err_t ra8_wdt_attach_handler ( ra8_wdt_event_fn_t fn,
void * ctx )
nodiscard

Register a callback invoked from the WDT NMI / underflow ISR.

Single-callback wrapper preserved from v0.2.0 so existing wiring keeps compiling. Internally just calls ra8_wdt_subscribe / ra8_wdt_unsubscribe with a private "legacy" slot, so it coexists with the multi-subscriber API without losing entries.

Parameters
[in]fnCallback fn (may be nullptr to clear).
[in]ctxContext pointer forwarded to fn.
Returns
ra8_err_t
Return values
k_ra8_okSlot updated.
k_ra8_err_no_memSubscriber table full and a non-null fn was supplied (theoretical).
Precondition
Caller is in single-writer init context.
No NMI is being dispatched concurrently.
Postcondition
Subsequent ra8_wdt_dispatch calls invoke fn.
ctx is captured exactly as passed.
Note
Not thread-safe – attach during init only.
See also
ra8_wdt_subscribe Multi-subscriber alternative.
Since
0.1.0

Definition at line 519 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_legacy_slot, and s_wdt_subs.

◆ ra8_wdt_clear_status()

ra8_err_t ra8_wdt_clear_status ( void )
nodiscard

Clear the WDTSR underflow / refresh-error flags.

Writes 0 to UNDFF and REFEF (write-1 has no effect, per HUM Ch 27.2.3 p 1261). The flag clear takes N + 1 PCLKB cycles to land, where N depends on the CKS divider; the driver does not busy-wait, so an immediate read-back may still return the old value. Use ra8_wdt_clear_status_blocking for the polled variant.

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds.
Precondition
WDT block has been powered.
Caller is in a single-writer context.
Postcondition
UNDFF / REFEF will read 0 within (N + 1) PCLKB cycles.
CNTVAL[13:0] is unaffected.
Note
Not thread-safe.
Since
0.1.0

Definition at line 379 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_status_all, ra8_wdt(), and r_wdt_regs_t::WDTSR.

Referenced by wdt_window_demo_iter().

◆ ra8_wdt_clear_status_blocking()

ra8_err_t ra8_wdt_clear_status_blocking ( uint16_t mask)
nodiscard

Clear specific WDTSR flag bits and busy-wait until they read 0.

HUM Ch 27.2.3 p 1261 documents that the W0C flag clear takes N + 1 PCLKB cycles to land. This helper polls the register up to k_ra8_wdt_clear_max_polls times and returns k_ra8_err_hw_timeout if the bit is still set when the budget runs out (the FSP analogue is the do/while loop in R_WDT_StatusClear).

Parameters
[in]maskBit mask of flags to clear (any combination of k_ra8_wdt_status_underflow / ..._refresh).
Returns
ra8_err_t
Return values
k_ra8_okTargeted flags read 0 within budget.
k_ra8_err_invalid_argmask outside the legal flag bits.
k_ra8_err_hw_timeoutFlag still latched after k_ra8_wdt_clear_max_polls.
Precondition
WDT block has been powered.
Caller is in single-writer context (or has masked IRQs).
Postcondition
On success, the targeted bits in WDTSR read 0.
On hw_timeout, hardware state is unchanged from a single ra8_wdt_clear_status call.
Note
Not thread-safe.
Since
0.1.0

Definition at line 389 of file ra8_wdt.c.

References k_ra8_err_hw_timeout, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_wdt_clear_max_polls, k_ra8_wdt_status_all, k_ra8_wdt_status_none, ra8_log_error, ra8_wdt(), s_tag, and r_wdt_regs_t::WDTSR.

◆ ra8_wdt_deinit()

ra8_err_t ra8_wdt_deinit ( void )
nodiscard

Quiesce the driver into a Sleep-stop posture.

Sets WDTCSTPR.SLCSTP so the counter halts when the CPU enters Sleep / Deep Sleep. The WDT itself cannot be disarmed once started, so this is the closest analogue to a "deinit" the silicon allows. Also clears every multi-subscriber slot so a follow-up ra8_wdt_init starts from a known callback table.

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds.
Precondition
ra8_wdt_init has been called.
Caller is in a single-writer context.
Postcondition
WDTCSTPR.SLCSTP = 1 (in register-start mode).
Counter still runs while CPU is awake.
Subscriber table is empty (every slot {nullptr, nullptr}).
Note
No-op in auto-start mode – WDTCSTPR is then read-only-zero.
Since
0.1.0

Definition at line 332 of file ra8_wdt.c.

References internal_subs_clear_all(), k_ra8_ok, k_ra8_wdt_cstpr_slcstp, ra8_log_info, ra8_wdt(), s_tag, and r_wdt_regs_t::WDTCSTPR.

◆ ra8_wdt_dispatch()

void ra8_wdt_dispatch ( void )

Dispatch a WDT event – snapshot WDTSR + fan-out to subscribers.

Latches the UNDFF / REFEF bits, clears them, then invokes every registered subscriber (legacy attach_handler + multi-sub list) in registration order. Intended to be called from the WDT NMI vector. The status mask is captured before the W0C clear so all subscribers see the same snapshot.

Precondition
WDT block has been powered.
Called from NMI context (interrupts disabled).
Postcondition
WDTSR's UNDFF and REFEF bits will read 0 within (N + 1) PCLKB cycles.
Every populated subscriber slot has been invoked exactly once.
Note
Safe to call when no subscriber is registered (becomes a flag clear with no further effect).
Since
0.1.0

Definition at line 575 of file ra8_wdt.c.

References k_ra8_wdt_max_subs, k_ra8_wdt_status_all, ra8_wdt(), s_wdt_subs, and r_wdt_regs_t::WDTSR.

◆ ra8_wdt_enter_stop()

ra8_err_t ra8_wdt_enter_stop ( void )
nodiscard

Enable counter halt on Sleep entry.

Sets WDTCSTPR.SLCSTP. In auto-start mode this is a no-op because the same field is locked from OFS0.

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds.
Precondition
ra8_wdt_init has been called.
Caller is in a single-writer context.
Postcondition
WDTCSTPR.SLCSTP = 1 (register-start mode).
Counter halts on the next WFI / WFE.
Note
Idempotent.
Since
0.1.0

Definition at line 628 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_cstpr_slcstp, ra8_wdt(), and r_wdt_regs_t::WDTCSTPR.

◆ ra8_wdt_exit_stop()

ra8_err_t ra8_wdt_exit_stop ( void )
nodiscard

Disable counter halt on Sleep entry.

Clears WDTCSTPR.SLCSTP so the counter keeps decrementing in Sleep. Useful when the application uses Sleep as an idle posture but still wants the WDT to fire if the wake source never arrives.

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds.
Precondition
ra8_wdt_init has been called.
Caller is in a single-writer context.
Postcondition
WDTCSTPR.SLCSTP = 0 (register-start mode).
Counter continues to count in Sleep.
Note
Idempotent.
Since
0.1.0

Definition at line 637 of file ra8_wdt.c.

References k_ra8_ok, ra8_wdt(), and r_wdt_regs_t::WDTCSTPR.

◆ ra8_wdt_get_counter()

ra8_err_t ra8_wdt_get_counter ( uint16_t * out_count)
nodiscard

Read the live CNTVAL[13:0] down-counter value.

Parameters
[out]out_countReceives the current counter; range 0..0x3FFF. The hardware notes the read may differ from the actual count by 1 (HUM Ch 27.2.3 p 1261).
Returns
ra8_err_t
Return values
k_ra8_okCounter read.
k_ra8_err_null_ptrout_count was null.
Precondition
out_count is non-null.
WDT block has been powered.
Postcondition
*out_count <= 0x3FFF.
No side effect on WDTSR.
Note
Read-only; safe to call from any context.
Since
0.1.0

Definition at line 428 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_sr_cnt_mask, RA8_CHECK_NULL_PTR, ra8_wdt(), and s_tag.

Referenced by wdt_window_demo_iter().

◆ ra8_wdt_get_status()

ra8_err_t ra8_wdt_get_status ( uint16_t * out_mask)
nodiscard

Read the WDTSR status flag bits.

Parameters
[out]out_maskReceives k_ra8_wdt_status_underflow and / or k_ra8_wdt_status_refresh (others = 0).
Returns
ra8_err_t
Return values
k_ra8_okStatus read.
k_ra8_err_null_ptrout_mask was null.
Precondition
out_mask is non-null.
WDT block has been powered (always-on for this peripheral).
Postcondition
*out_mask is one of the k_ra8_wdt_status_* masks.
No side effect on WDTSR.
Note
Thread-safe wrt other readers; concurrent writers must serialise the access.
Since
0.1.0

Definition at line 371 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_status_all, RA8_CHECK_NULL_PTR, ra8_wdt(), and s_tag.

◆ ra8_wdt_init()

ra8_err_t ra8_wdt_init ( const ra8_wdt_cfg_t * cfg)
nodiscard

Initialise the WDT in register-start mode.

Programmes WDTCR with the timeout / clock divider / window selection from cfg, WDTRCR with the reset-vs-NMI choice, and WDTCSTPR with the Sleep-stop selection. After all three are written this function issues the first refresh, which is what actually arms the counter.

Algorithm:

  1. Validate cfg non-null.
  2. Validate cfg->clock_div against the legal CKS encodings.
  3. Build WDTCR by shifting each field into place.
  4. Write WDTCR (one 16-bit transaction), WDTRCR, WDTCSTPR.
  5. Issue the unlock sequence on WDTRR to arm the counter.

In auto-start mode the WDTCR / WDTRCR / WDTCSTPR writes are silently dropped by silicon, but the refresh still works – so the function is safe to call in either mode.

Parameters
[in]cfgPointer to the configuration block.
Returns
ra8_err_t Result code.
Return values
k_ra8_okCounter armed.
k_ra8_err_null_ptrcfg was null.
k_ra8_err_invalid_argcfg->clock_div is not one of the legal CKS encodings.
Precondition
cfg is non-null.
PCLKB has been started by the CGC driver.
Postcondition
WDTCR / WDTRCR / WDTCSTPR reflect cfg (register-start mode).
WDTRR holds 0xFF – the counter has been refreshed once.
Note
Not thread-safe – call from init context only. The WDT control registers can only be written once after reset (HUM Ch 27.3.2 "Controlling Writes to the WDTCR, WDTRCR, and WDTCSTPR Registers"), so subsequent calls have no effect.
See also
ra8_wdt_refresh_deferred Run-time heartbeat.
ra8_wdt_deinit Counterpart that disables in Sleep.
Since
0.1.0

Definition at line 296 of file ra8_wdt.c.

References ra8_wdt_cfg_t::clock_div, internal_clock_div_is_valid(), internal_pack_wdtcr(), internal_timeout_sel_is_valid(), k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_wdt_cstpr_slcstp, k_ra8_wdt_on_expiry_reset, k_ra8_wdt_rcr_rstirqs, k_ra8_wdt_sleep_stop_count, ra8_wdt_cfg_t::on_expiry, RA8_CHECK_NULL_PTR, ra8_log_info, ra8_wdt(), ra8_wdt_refresh(), s_tag, ra8_wdt_cfg_t::stop_in_sleep, ra8_wdt_cfg_t::timeout, r_wdt_regs_t::WDTCR, r_wdt_regs_t::WDTCSTPR, and r_wdt_regs_t::WDTRCR.

Referenced by main(), ra8_nsc_wdt_start(), sh_wdt_arm_or_halt(), wdt_rr_arm_and_wait_for_reset(), and wdt_sup_demo_bring_up().

◆ ra8_wdt_install_nmi()

ra8_err_t ra8_wdt_install_nmi ( void )
nodiscard

Enable the WDT bit in NMIER so the NMI line fires on underflow.

HUM Ch 14.2.14 p 542 – NMIER is sticky-set; once written it cannot be cleared by software except via the matching ra8_wdt_uninstall_nmi helper which goes through ra8_icu_nmi_disable. Use this from the boot sequence after the ICU is initialized but before the WDT starts decrementing.

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds (the underlying ra8_icu_nmi_enable only OR's into the register).
Precondition
ra8_icu_init has been called.
Caller is in single-writer init context.
Postcondition
NMIER.WDTEN reads 1.
NMICLR has cleared any stale WDT NMI status.
Since
0.1.0

Definition at line 598 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_nmier_wdten_mask, ra8_icu_nmi_clear(), and ra8_icu_nmi_enable().

◆ ra8_wdt_ofs_get()

ra8_err_t ra8_wdt_ofs_get ( ra8_wdt_instance_t which,
ra8_wdt_ofs_decoded_t * out )
nodiscard

Decode an OFSm option-setting word into ra8_wdt_cfg_t.

Recovers the seven WDT fields the boot ROM latched when OFSm.WDTnSTRT == 0, per HUM Ch 27.3.8 Table 27.5 p 1269. The two instances read different numbers of words, because the hardware does:

  • k_ra8_wdt0one read of OFS0 (HUM Ch 7.2.1 p 280). OFS0 is a single secure-region word with no _SEC / _SEL companions.
  • k_ra8_wdt1three reads. OFS3_SEL (HUM Ch 7.2.7 p 289) selects, per field, whether WDT1 latched that field from OFS3_SEC (selector 0) or OFS3 (selector 1), so the effective word is a mux of the two copies. Reading either copy alone reports a configuration the hardware may not be using.

The WDT driver is read-only with respect to OFSm; only ra8_ofs.c may write the option-setting sections. Every fetch goes through the ra8_wdt_ofs_reader_set hook so unit tests / bring-up code can supply canned words without touching MRAM.

Parameters
[in]whichInstance whose OFSm word should be decoded.
[out]outReceives the decoded view.
Returns
ra8_err_t
Return values
k_ra8_okDecoded.
k_ra8_err_null_ptrout was null.
k_ra8_err_invalid_argwhich is not a known instance.
k_ra8_err_invalid_statewhich was k_ra8_wdt1 and OFS3_SEL holds an encoding HUM Ch 7.2.7 p 289 marks "Setting prohibit".
k_ra8_err_*Whatever the reader hook returned.
Precondition
out is non-null.
which < k_ra8_wdt_instance_count.
Postcondition
out->cfg mirrors the latched OFSm fields.
out->auto_start matches out->start_mode == k_ra8_wdt_ofs_strt_auto.
Note
Read-only; callable from any context.
Warning
Secure-world only under the default reader – see ra8_wdt_ofs_reader_fn_t.
See also
ra8_ofs_addr_t The addresses this reads.
Since
0.1.0

Definition at line 824 of file ra8_wdt.c.

References internal_decode_ofs_word(), internal_read_wdt1_word(), k_ra8_err_invalid_arg, k_ra8_ofs0_addr, k_ra8_ok, k_ra8_wdt0, k_ra8_wdt_instance_count, RA8_CHECK_NULL_PTR, s_ofs_reader, and s_tag.

◆ ra8_wdt_ofs_reader_set()

ra8_err_t ra8_wdt_ofs_reader_set ( ra8_wdt_ofs_reader_fn_t reader)
nodiscard

Override the OFSm reader hook used by ra8_wdt_ofs_get.

Pass nullptr to restore the default reader (direct MMIO read). Production code never needs to call this; it exists for unit tests and for early-bring-up code that has not yet mapped the option- setting page.

Parameters
[in]readerNew reader function or nullptr for default.
Returns
Always k_ra8_ok.
Precondition
Caller is in single-writer init context.
Postcondition
Subsequent ra8_wdt_ofs_get calls go through reader.
Since
0.1.0

Definition at line 651 of file ra8_wdt.c.

References internal_default_ofs_reader(), k_ra8_ok, and s_ofs_reader.

◆ ra8_wdt_pclkb_divisor()

ra8_err_t ra8_wdt_pclkb_divisor ( ra8_wdt_clock_div_t div,
uint16_t * out_divisor )
nodiscard

Decode a ra8_wdt_clock_div_t into its numeric divisor.

Parameters
[in]divCKS field (k_ra8_wdt_clkdiv_*).
[out]out_divisorReceives the divisor in {4, 64, 128, 512, 2048, 8192} per HUM Ch 27.2.2 p 1258.
Returns
ra8_err_t
Return values
k_ra8_okDecoded.
k_ra8_err_null_ptrout_divisor was null.
k_ra8_err_invalid_argdiv not a legal CKS encoding.
Precondition
out_divisor is non-null.
div is one of the legal CKS encodings.
Postcondition
*out_divisor is one of {4, 64, 128, 512, 2048, 8192}.
No hardware state is touched.
Since
0.1.0

Definition at line 464 of file ra8_wdt.c.

References k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_wdt_clkdiv_128, k_ra8_wdt_clkdiv_2048, k_ra8_wdt_clkdiv_4, k_ra8_wdt_clkdiv_512, k_ra8_wdt_clkdiv_64, k_ra8_wdt_clkdiv_8192, k_ra8_wdt_div_value_128, k_ra8_wdt_div_value_2048, k_ra8_wdt_div_value_4, k_ra8_wdt_div_value_512, k_ra8_wdt_div_value_64, k_ra8_wdt_div_value_8192, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by ra8_wdt_total_pclkb_cycles().

◆ ra8_wdt_refresh_deferred()

void ra8_wdt_refresh_deferred ( void )

Refresh the software WDT counter (WDT0).

Thin wrapper around the inline ra8_wdt_refresh helper in the register header so other compilation units do not have to pull in ra8_wdt_regs.h.

Precondition
WDT has been armed (auto-start out of reset, or ra8_wdt_init succeeded).
Refresh occurs strictly inside the refresh-permitted window programmed by cfg->window_start / cfg->window_end.
Postcondition
WDTRR holds 0xFF.
Down-counter is reloaded.
Note
Not thread-safe.
Since
0.1.0

Definition at line 350 of file ra8_wdt.c.

References ra8_wdt_refresh().

Referenced by internal_default_refresh(), and ra8_nsc_wdt_refresh().

◆ ra8_wdt_refresh_for()

ra8_err_t ra8_wdt_refresh_for ( ra8_wdt_instance_t which)
nodiscard

Refresh a specific WDT instance.

Parameters
[in]whichInstance to refresh (k_ra8_wdt0 or k_ra8_wdt1).
Returns
ra8_err_t
Return values
k_ra8_okCounter refreshed.
k_ra8_err_invalid_argwhich not a known instance.
Precondition
which < k_ra8_wdt_instance_count.
WDT has been armed.
Postcondition
Targeted WDT's WDTRR holds 0xFF.
Targeted WDT down-counter is reloaded.
Since
0.1.0

Definition at line 356 of file ra8_wdt.c.

References k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_wdt_instance_count, and ra8_wdt_refresh_instance().

Referenced by sh_run(), wdt_rr_arm_and_wait_for_reset(), and wdt_window_demo_iter().

◆ ra8_wdt_subscribe()

ra8_err_t ra8_wdt_subscribe ( ra8_wdt_event_fn_t fn,
void * ctx,
uint8_t * out_slot )
nodiscard

Add a hot-pluggable subscriber to the WDT NMI dispatch list.

Multiple modules can listen for the underflow / refresh-error event (an SoH logger, the application crash recorder, a watchdog-aware task scheduler,...). Each ra8_wdt_subscribe call grabs the first free slot in the static dispatch table; ra8_wdt_dispatch later walks every populated slot in registration order.

Parameters
[in]fnCallback. Must not be nullptr.
[in]ctxCaller-supplied pointer forwarded to fn on every dispatch.
[out]out_slotReceives the slot index (0..k_ra8_wdt_max_subs-1) assigned to this subscriber. May be nullptr if the caller doesn't need it.
Returns
ra8_err_t
Return values
k_ra8_okSubscriber installed.
k_ra8_err_null_ptrfn was null.
k_ra8_err_no_memAll k_ra8_wdt_max_subs slots are taken.
Precondition
fn is non-null.
Caller is in single-writer init context (subscribe is not NMI-safe; do all subscribes during boot).
Postcondition
On success, exactly one previously-empty slot is filled.
Slot count grows by 1.
Note
Not thread-safe; treat the subscriber table as immutable once interrupts are unmasked.
See also
ra8_wdt_unsubscribe Inverse operation.
Since
0.1.0

Definition at line 529 of file ra8_wdt.c.

References k_ra8_err_no_mem, k_ra8_ok, k_ra8_wdt_max_subs, RA8_CHECK_NULL_PTR, ra8_log_error, s_tag, and s_wdt_subs.

◆ ra8_wdt_subscriber_count()

uint8_t ra8_wdt_subscriber_count ( void )

Number of currently-installed subscribers.

Diagnostic accessor used by tests and dump helpers. Counts only slots whose fn is non-null.

Returns
The current populated-slot count.
Precondition
None.
Postcondition
No state is mutated.
Since
0.1.0
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.

Definition at line 563 of file ra8_wdt.c.

References k_ra8_wdt_max_subs, and s_wdt_subs.

◆ ra8_wdt_timeout_cycles_get()

ra8_err_t ra8_wdt_timeout_cycles_get ( ra8_wdt_timeout_sel_t sel,
uint16_t * out_cycles )
nodiscard

Decode a ra8_wdt_timeout_sel_t into its cycle count.

Parameters
[in]selTOPS field (k_ra8_wdt_timeout_*).
[out]out_cyclesReceives the cycle count (1024 / 4096 / 8192 / 16384) per HUM Ch 27.2.2 Table 27.2 p 1259.
Returns
ra8_err_t
Return values
k_ra8_okDecoded.
k_ra8_err_null_ptrout_cycles was null.
k_ra8_err_invalid_argsel outside 0..3.
Precondition
out_cycles is non-null.
sel is a valid TOPS encoding.
Postcondition
*out_cycles is one of {1024, 4096, 8192, 16384}.
No hardware state is touched.
Since
0.1.0

Definition at line 442 of file ra8_wdt.c.

References k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_wdt_cycles_1024, k_ra8_wdt_cycles_16384, k_ra8_wdt_cycles_4096, k_ra8_wdt_cycles_8192, k_ra8_wdt_timeout_1024, k_ra8_wdt_timeout_16384, k_ra8_wdt_timeout_4096, k_ra8_wdt_timeout_8192, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by ra8_wdt_total_pclkb_cycles().

◆ ra8_wdt_total_pclkb_cycles()

ra8_err_t ra8_wdt_total_pclkb_cycles ( ra8_wdt_timeout_sel_t sel,
ra8_wdt_clock_div_t div,
uint32_t * out_pclkb_cycles )
nodiscard

Compute the effective timeout in PCLKB cycles.

Returns cycles_for(TOPS) * divisor_for(CKS) as a 32-bit value. Matches Table 27.2 p 1259 row by row – e.g. CKS=PCLKB/8192, TOPS=16384 yields 134_217_728 PCLKB cycles.

Parameters
[in]selTOPS field.
[in]divCKS field.
[out]out_pclkb_cyclesReceives the product.
Returns
ra8_err_t
Return values
k_ra8_okComputed.
k_ra8_err_null_ptrout_pclkb_cycles was null.
k_ra8_err_invalid_argsel or div invalid.
Precondition
out_pclkb_cycles is non-null.
sel and div decode successfully.
Postcondition
*out_pclkb_cycles <= 134_217_728 (largest table entry).
No hardware state is touched.
Since
0.1.0

Definition at line 492 of file ra8_wdt.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_wdt_pclkb_divisor(), ra8_wdt_timeout_cycles_get(), and s_tag.

◆ ra8_wdt_uninstall_nmi()

ra8_err_t ra8_wdt_uninstall_nmi ( void )
nodiscard

Disable the WDT bit in NMIER (counterpart to ra8_wdt_install_nmi).

Returns
ra8_err_t
Return values
k_ra8_okAlways succeeds.
Precondition
ra8_icu_init has been called.
Caller is in single-writer context.
Postcondition
NMIER.WDTEN reads 0.
Pending WDT NMI status is cleared via NMICLR.
Since
0.1.0

Definition at line 612 of file ra8_wdt.c.

References k_ra8_ok, k_ra8_wdt_nmier_wdten_mask, ra8_icu_nmi_clear(), and ra8_icu_nmi_disable().

◆ ra8_wdt_unsubscribe()

ra8_err_t ra8_wdt_unsubscribe ( uint8_t slot)
nodiscard

Remove a previously-registered subscriber.

Parameters
[in]slotSlot index returned by ra8_wdt_subscribe.
Returns
ra8_err_t
Return values
k_ra8_okSlot freed.
k_ra8_err_invalid_argslot out of range.
k_ra8_err_not_foundSlot was already empty.
Precondition
slot < k_ra8_wdt_max_subs.
Caller is in single-writer init context.
Postcondition
Slot reads {nullptr, nullptr}.
Subsequent dispatches skip the slot.
Since
0.1.0

Definition at line 550 of file ra8_wdt.c.

References k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_ok, k_ra8_wdt_max_subs, and s_wdt_subs.

Variable Documentation

◆ s_ofs_reader

Active OFSm reader hook (dependency-inverted for test isolation).

Definition at line 159 of file ra8_wdt.c.

Referenced by internal_read_wdt1_word(), ra8_wdt_ofs_get(), and ra8_wdt_ofs_reader_set().

◆ s_tag

const char* s_tag = "WDT"
static

Module log tag.

Passed as the first argument to ra8_log_* so log lines are easy to grep.

Note
Read-only; do not modify.

Definition at line 79 of file ra8_wdt.c.

◆ s_wdt_subs

ra8_wdt_sub_t s_wdt_subs[k_ra8_wdt_max_subs]
static

Dispatch table of registered subscribers.

Static storage; cleared at C startup and again during ra8_wdt_deinit. Slot 0 is owned by the legacy single-callback API; slots 1..k_ra8_wdt_max_subs-1 are claimed by ra8_wdt_subscribe.

Warning
Do not write directly – always go through the public ra8_wdt_* API.

Definition at line 120 of file ra8_wdt.c.

Referenced by internal_subs_clear_all(), ra8_wdt_attach_handler(), ra8_wdt_dispatch(), ra8_wdt_subscribe(), ra8_wdt_subscriber_count(), and ra8_wdt_unsubscribe().