@@ -62,6 +62,124 @@ Use `Write` and `Read` for whole-register access. Use `Update` and `Get` when
6262you need to modify or read individual fields within a register without
6363disturbing other bits.
6464
65+ ### Timeouts
66+
67+ Most drivers poll hardware status registers in busy-wait loops (e.g., waiting
68+ for a DMA transfer to complete, a flash erase to finish, or an AES computation
69+ to produce a result). wolfHAL provides an optional timeout mechanism to bound
70+ these waits and prevent infinite hangs if hardware misbehaves.
71+
72+ #### Timeout Struct
73+
74+ The board creates a `whal_Timeout` instance with a tick source and a timeout
75+ duration. Drivers receive a pointer to it through their configuration struct:
76+
77+ ```c
78+ typedef struct {
79+ uint32_t timeoutTicks; /* max ticks before timeout */
80+ uint32_t startTick; /* snapshot, set by START */
81+ uint32_t (*GetTick)(void); /* board-provided tick source */
82+ } whal_Timeout;
83+ ```
84+
85+ The tick units are determined by the board's ` GetTick ` implementation. A 1 kHz
86+ SysTick gives millisecond ticks; a 1 MHz timer gives microsecond ticks. Drivers
87+ do not need to know the tick rate.
88+
89+ #### whal_Reg_ReadPoll
90+
91+ For the common case of polling a register bit, use ` whal_Reg_ReadPoll ` from
92+ ` wolfHAL/regmap.h ` :
93+
94+ ``` c
95+ whal_Error whal_Reg_ReadPoll (size_t base, size_t offset,
96+ size_t mask, size_t value,
97+ whal_Timeout * timeout);
98+ ```
99+
100+ This polls until `(reg & mask) == value` or the timeout expires. Pass the mask
101+ as the value to wait for bits to be set, or `0` to wait for bits to be clear:
102+
103+ ```c
104+ /* Wait for TXE flag to be set */
105+ err = whal_Reg_ReadPoll(base, SPI_SR_REG, SPI_SR_TXE_Msk,
106+ SPI_SR_TXE_Msk, cfg->timeout);
107+
108+ /* Wait for BSY flag to be clear */
109+ err = whal_Reg_ReadPoll(base, SPI_SR_REG, SPI_SR_BSY_Msk,
110+ 0, cfg->timeout);
111+ ```
112+
113+ A NULL timeout pointer means unbounded wait (poll forever).
114+
115+ #### Driver-Specific Helpers
116+
117+ When a driver has many polling sites that also need post-poll cleanup (e.g.,
118+ clearing a flag), wrap the pattern in a local helper to avoid code duplication:
119+
120+ ``` c
121+ static whal_Error WaitForCCF (size_t base, whal_Timeout * timeout)
122+ {
123+ whal_Error err;
124+ err = whal_Reg_ReadPoll(base, AES_SR_REG, AES_SR_CCF_Msk,
125+ AES_SR_CCF_Msk, timeout);
126+ if (err)
127+ return err;
128+ whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk);
129+ return WHAL_SUCCESS;
130+ }
131+ ```
132+
133+ This keeps code size small — one function body shared across all call sites
134+ instead of inlined polling loops at each location.
135+
136+ #### Cleanup on Timeout
137+
138+ When a timeout occurs during an operation that has enabled a hardware mode
139+ (e.g., flash programming mode, AES enable), the driver must still clean up
140+ before returning. Use a `goto cleanup` pattern:
141+
142+ ```c
143+ whal_Error err = WHAL_SUCCESS;
144+
145+ whal_Reg_Update(base, CR_REG, PG_Msk, 1); /* enable programming mode */
146+
147+ for (...) {
148+ err = whal_Reg_ReadPoll(base, SR_REG, BSY_Msk, 0, cfg->timeout);
149+ if (err)
150+ goto cleanup;
151+ }
152+
153+ cleanup:
154+ whal_Reg_Update(base, CR_REG, PG_Msk, 0); /* always disable */
155+ return err;
156+ ```
157+
158+ Never return directly from inside a polling loop if the peripheral is in a
159+ mode that requires cleanup.
160+
161+ #### Compile-Time Disable
162+
163+ Define ` WHAL_CFG_NO_TIMEOUT ` to remove all timeout logic from the binary.
164+ When defined, ` WHAL_TIMEOUT_START ` becomes a no-op and ` WHAL_TIMEOUT_EXPIRED `
165+ always evaluates to ` 0 ` , so polling loops run until the hardware condition is
166+ met with no overhead.
167+
168+ #### Adding Timeout to a Config Struct
169+
170+ Driver config structs that use polling should include an optional timeout
171+ pointer:
172+
173+ ``` c
174+ typedef struct {
175+ /* ... other config fields ... */
176+ whal_Timeout *timeout;
177+ } whal_MyplatformFoo_Cfg;
178+ ```
179+
180+ The timeout is optional — if the board does not set it (NULL), all waits are
181+ unbounded.
182+
65183### Avoiding Bloat
66184
67185When a peripheral has multiple distinct operating modes or configurations,
0 commit comments