1 //*****************************************************************************
2 //
3 //! @file am_hal_wdt.c
4 //!
5 //! @brief Watchdog Timer
6 //!
7 //! @addtogroup wdt_4p WDT - Watchdog Timer Functionality
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51
52 //*****************************************************************************
53 //
54 // Static function prototypes
55 //
56 //*****************************************************************************
57 static uint32_t dsp_wdt_config(am_hal_wdt_select_e eTimer, void *pvConfig);
58
59 //*****************************************************************************
60 //
61 // Configure the watchdog timer.
62 //
63 //*****************************************************************************
64 uint32_t
am_hal_wdt_config(am_hal_wdt_select_e eTimer,void * pvConfig)65 am_hal_wdt_config(am_hal_wdt_select_e eTimer, void *pvConfig)
66 {
67 uint32_t ui32ConfigValue;
68 am_hal_wdt_config_t *psConfig = pvConfig;
69
70 //
71 // Check to see if we're configuring the MCU watchdog, or one of the DSP
72 // watchdogs.
73 //
74 if (eTimer == AM_HAL_WDT_MCU)
75 {
76 ui32ConfigValue = 0;
77
78 //
79 // Apply the settings from our configuration structure.
80 //
81 ui32ConfigValue |= _VAL2FLD(WDT_CFG_CLKSEL, psConfig->eClockSource);
82 ui32ConfigValue |= _VAL2FLD(WDT_CFG_INTVAL, psConfig->ui32InterruptValue);
83 ui32ConfigValue |= _VAL2FLD(WDT_CFG_RESVAL, psConfig->ui32ResetValue);
84
85 if (psConfig->bAlertOnDSPReset)
86 {
87 ui32ConfigValue |= _VAL2FLD(WDT_CFG_DSPRESETINTEN, 1);
88 }
89
90 if (psConfig->bResetEnable)
91 {
92 ui32ConfigValue |= _VAL2FLD(WDT_CFG_RESEN, 1);
93 }
94
95 if (psConfig->bInterruptEnable)
96 {
97 ui32ConfigValue |= _VAL2FLD(WDT_CFG_INTEN, 1);
98 }
99
100 //
101 // Write the settings to the WDT config register.
102 //
103 WDT->CFG = ui32ConfigValue;
104
105 //
106 // Enabled the WDT Reset if requested.
107 //
108 RSTGEN->CFG_b.WDREN = psConfig->bResetEnable;
109
110 return AM_HAL_STATUS_SUCCESS;
111 }
112 else
113 {
114 //
115 // DSP register settings are a little different.
116 //
117 return dsp_wdt_config(eTimer, pvConfig);
118 }
119 }
120
121 //*****************************************************************************
122 //
123 // Configure the watchdog for a DSP.
124 //
125 //*****************************************************************************
126 uint32_t
dsp_wdt_config(am_hal_wdt_select_e eTimer,void * pvConfig)127 dsp_wdt_config(am_hal_wdt_select_e eTimer, void *pvConfig)
128 {
129 uint32_t ui32ConfigValue = 0;
130 am_hal_wdt_config_dsp_t *psConfig = pvConfig;
131
132 switch (eTimer)
133 {
134 case AM_HAL_WDT_DSP0:
135 //
136 // Apply the settings from our configuration structure.
137 //
138 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0PMRESVAL, psConfig->ui32PMResetValue);
139 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0INTVAL, psConfig->ui32InterruptValue);
140 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0RESVAL, psConfig->ui32ResetValue);
141
142 if (psConfig->bPMResetEnable)
143 {
144 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0PMRESEN, 1);
145 }
146
147 if (psConfig->bResetEnable)
148 {
149 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0RESEN, 1);
150 }
151
152 if (psConfig->bInterruptEnable)
153 {
154 ui32ConfigValue |= _FLD2VAL(WDT_DSP0CFG_DSP0INTEN, 1);
155 }
156
157 //
158 // Write the settings to the WDT config register.
159 //
160 WDT->DSP0CFG = ui32ConfigValue;
161 break;
162
163 case AM_HAL_WDT_DSP1:
164 //
165 // Apply the settings from our configuration structure.
166 //
167 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1PMRESVAL, psConfig->ui32PMResetValue);
168 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1INTVAL, psConfig->ui32InterruptValue);
169 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1RESVAL, psConfig->ui32ResetValue);
170
171 if (psConfig->bPMResetEnable)
172 {
173 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1PMRESEN, 1);
174 }
175
176 if (psConfig->bResetEnable)
177 {
178 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1RESEN, 1);
179 }
180
181 if (psConfig->bInterruptEnable)
182 {
183 ui32ConfigValue |= _FLD2VAL(WDT_DSP1CFG_DSP1INTEN, 1);
184 }
185
186 //
187 // Write the settings to the WDT config register.
188 //
189 WDT->DSP1CFG = ui32ConfigValue;
190 break;
191
192 //
193 // Error. The option we were given was not a valid DSP WDT.
194 //
195 default:
196 return AM_HAL_STATUS_FAIL;
197 }
198
199 return AM_HAL_STATUS_SUCCESS;
200 }
201
202 //*****************************************************************************
203 //
204 // Enables the watchdog timer.
205 //
206 //*****************************************************************************
207 uint32_t
am_hal_wdt_start(am_hal_wdt_select_e eTimer,bool bLock)208 am_hal_wdt_start(am_hal_wdt_select_e eTimer, bool bLock)
209 {
210 //
211 // Enable the timer.
212 //
213 switch (eTimer)
214 {
215 case AM_HAL_WDT_MCU:
216 WDT->RSTRT = WDT_RSTRT_RSTRT_KEYVALUE;
217 WDT->CFG_b.WDTEN = 1;
218 break;
219
220 case AM_HAL_WDT_DSP0:
221 WDT->DSP0RSTRT = WDT_DSP0RSTRT_DSP0RSTART_KEYVALUE;
222 WDT->DSP0CFG_b.DSP0WDTEN = 1;
223 break;
224
225 case AM_HAL_WDT_DSP1:
226 WDT->DSP1RSTRT = WDT_DSP1RSTRT_DSP1RSTART_KEYVALUE;
227 WDT->DSP1CFG_b.DSP1WDTEN = 1;
228 break;
229
230 default:
231 return AM_HAL_STATUS_FAIL;
232 }
233
234 //
235 // Lock the timer if we were asked to do so.
236 //
237 if (bLock)
238 {
239 switch (eTimer)
240 {
241 case AM_HAL_WDT_MCU:
242 WDT->LOCK = WDT_LOCK_LOCK_KEYVALUE;
243 break;
244
245 case AM_HAL_WDT_DSP0:
246 WDT->DSP0TLOCK = WDT_DSP0TLOCK_DSP0LOCK_KEYVALUE;
247 break;
248
249 case AM_HAL_WDT_DSP1:
250 WDT->DSP1TLOCK = WDT_DSP1TLOCK_DSP1LOCK_KEYVALUE;
251 break;
252
253 default:
254 return AM_HAL_STATUS_FAIL;
255 }
256 }
257
258 return AM_HAL_STATUS_SUCCESS;
259 }
260
261 //*****************************************************************************
262 //
263 // Disables the watchdog timer.
264 //
265 //*****************************************************************************
266 uint32_t
am_hal_wdt_stop(am_hal_wdt_select_e eTimer)267 am_hal_wdt_stop(am_hal_wdt_select_e eTimer)
268 {
269 switch (eTimer)
270 {
271 case AM_HAL_WDT_MCU:
272 WDT->CFG_b.WDTEN = 0;
273 break;
274
275 case AM_HAL_WDT_DSP0:
276 WDT->DSP0CFG_b.DSP0WDTEN = 0;
277 break;
278
279 case AM_HAL_WDT_DSP1:
280 WDT->DSP1CFG_b.DSP1WDTEN = 0;
281 break;
282
283 default:
284 return AM_HAL_STATUS_FAIL;
285 }
286
287 return AM_HAL_STATUS_SUCCESS;
288 }
289
290 //*****************************************************************************
291 //
292 // Restart (pet/feed) the watchdgog
293 //
294 //*****************************************************************************
295 uint32_t
am_hal_wdt_restart(am_hal_wdt_select_e eTimer)296 am_hal_wdt_restart(am_hal_wdt_select_e eTimer)
297 {
298 switch (eTimer)
299 {
300 case AM_HAL_WDT_MCU:
301 WDT->RSTRT = WDT_RSTRT_RSTRT_KEYVALUE;
302 break;
303
304 case AM_HAL_WDT_DSP0:
305 WDT->DSP0RSTRT = WDT_DSP0RSTRT_DSP0RSTART_KEYVALUE;
306 break;
307
308 case AM_HAL_WDT_DSP1:
309 WDT->DSP1RSTRT = WDT_DSP1RSTRT_DSP1RSTART_KEYVALUE;
310 break;
311
312 default:
313 return AM_HAL_STATUS_FAIL;
314 }
315
316 return AM_HAL_STATUS_SUCCESS;
317 }
318
319 //*****************************************************************************
320 //
321 // Reads the watchdog timer's current value.
322 //
323 //*****************************************************************************
324 uint32_t
am_hal_wdt_read(am_hal_wdt_select_e eTimer,uint32_t * ui32Value)325 am_hal_wdt_read(am_hal_wdt_select_e eTimer, uint32_t *ui32Value)
326 {
327 switch (eTimer)
328 {
329 case AM_HAL_WDT_MCU:
330 *ui32Value = WDT->COUNT;
331 break;
332
333 case AM_HAL_WDT_DSP0:
334 *ui32Value = WDT->DSP0COUNT;
335 break;
336
337 case AM_HAL_WDT_DSP1:
338 *ui32Value = WDT->DSP1COUNT;
339 break;
340
341 default:
342 return AM_HAL_STATUS_FAIL;
343 }
344
345 return AM_HAL_STATUS_SUCCESS;
346 }
347
348 //*****************************************************************************
349 //
350 // Watchdog interrupt enable.
351 //
352 //*****************************************************************************
353 uint32_t
am_hal_wdt_interrupt_enable(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)354 am_hal_wdt_interrupt_enable(am_hal_wdt_select_e eTimer,
355 uint32_t ui32InterruptMask)
356 {
357 switch (eTimer)
358 {
359 case AM_HAL_WDT_MCU:
360 WDT->WDTIEREN |= ui32InterruptMask;
361 break;
362
363 case AM_HAL_WDT_DSP0:
364 WDT->DSP0IEREN |= ui32InterruptMask;
365 break;
366
367 case AM_HAL_WDT_DSP1:
368 WDT->DSP1IEREN |= ui32InterruptMask;
369 break;
370
371 default:
372 return AM_HAL_STATUS_FAIL;
373 }
374
375 return AM_HAL_STATUS_SUCCESS;
376 }
377
378 //*****************************************************************************
379 //
380 // Check to see which WDT interrupts are enabled.
381 //
382 //*****************************************************************************
383 uint32_t
am_hal_wdt_interrupt_enable_get(am_hal_wdt_select_e eTimer,uint32_t * pui32InterruptMask)384 am_hal_wdt_interrupt_enable_get(am_hal_wdt_select_e eTimer,
385 uint32_t *pui32InterruptMask)
386 {
387 switch (eTimer)
388 {
389 case AM_HAL_WDT_MCU:
390 *pui32InterruptMask = WDT->WDTIEREN;
391 break;
392
393 case AM_HAL_WDT_DSP0:
394 *pui32InterruptMask = WDT->DSP0IEREN;
395 break;
396
397 case AM_HAL_WDT_DSP1:
398 *pui32InterruptMask = WDT->DSP1IEREN;
399 break;
400
401 default:
402 return AM_HAL_STATUS_FAIL;
403 }
404
405 return AM_HAL_STATUS_SUCCESS;
406 }
407
408 //*****************************************************************************
409 //
410 // Disable a WDT interrupt.
411 //
412 //*****************************************************************************
413 uint32_t
am_hal_wdt_interrupt_disable(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)414 am_hal_wdt_interrupt_disable(am_hal_wdt_select_e eTimer,
415 uint32_t ui32InterruptMask)
416 {
417 switch (eTimer)
418 {
419 case AM_HAL_WDT_MCU:
420 WDT->WDTIEREN &= ~ui32InterruptMask;
421 break;
422
423 case AM_HAL_WDT_DSP0:
424 WDT->DSP0IEREN &= ~ui32InterruptMask;
425 break;
426
427 case AM_HAL_WDT_DSP1:
428 WDT->DSP1IEREN &= ~ui32InterruptMask;
429 break;
430
431 default:
432 return AM_HAL_STATUS_FAIL;
433 }
434
435 return AM_HAL_STATUS_SUCCESS;
436 }
437
438 //*****************************************************************************
439 //
440 // Read the WDT interrupt status.
441 //
442 //*****************************************************************************
443 uint32_t
am_hal_wdt_interrupt_status_get(am_hal_wdt_select_e eTimer,uint32_t * pui32InterruptMask,bool bEnabledOnly)444 am_hal_wdt_interrupt_status_get(am_hal_wdt_select_e eTimer,
445 uint32_t *pui32InterruptMask,
446 bool bEnabledOnly)
447 {
448 uint32_t ui32Status;
449
450 if (bEnabledOnly)
451 {
452 switch (eTimer)
453 {
454 case AM_HAL_WDT_MCU:
455 ui32Status = WDT->WDTIERSTAT;
456 ui32Status &= WDT->WDTIEREN;
457 break;
458
459 case AM_HAL_WDT_DSP0:
460 ui32Status = WDT->DSP0IERSTAT;
461 ui32Status &= WDT->DSP0IEREN;
462 break;
463
464 case AM_HAL_WDT_DSP1:
465 ui32Status = WDT->DSP1IERSTAT;
466 ui32Status &= WDT->DSP1IEREN;
467 break;
468
469 default:
470 return AM_HAL_STATUS_FAIL;
471 }
472
473 *pui32InterruptMask = ui32Status;
474 }
475 else
476 {
477 switch (eTimer)
478 {
479 case AM_HAL_WDT_MCU:
480 *pui32InterruptMask = WDT->WDTIERSTAT;
481 break;
482
483 case AM_HAL_WDT_DSP0:
484 *pui32InterruptMask = WDT->DSP0IERSTAT;
485 break;
486
487 case AM_HAL_WDT_DSP1:
488 *pui32InterruptMask = WDT->DSP1IERSTAT;
489 break;
490
491 default:
492 return AM_HAL_STATUS_FAIL;
493 }
494 }
495
496 return AM_HAL_STATUS_SUCCESS;
497 }
498
499 //*****************************************************************************
500 //
501 // Clears the WDT interrupt.
502 //
503 //*****************************************************************************
504 uint32_t
am_hal_wdt_interrupt_clear(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)505 am_hal_wdt_interrupt_clear(am_hal_wdt_select_e eTimer,
506 uint32_t ui32InterruptMask)
507 {
508 switch (eTimer)
509 {
510 case AM_HAL_WDT_MCU:
511 WDT->WDTIERCLR = ui32InterruptMask;
512 break;
513
514 case AM_HAL_WDT_DSP0:
515 WDT->DSP0IERCLR = ui32InterruptMask;
516 break;
517
518 case AM_HAL_WDT_DSP1:
519 WDT->DSP1IERCLR = ui32InterruptMask;
520 break;
521
522 default:
523 return AM_HAL_STATUS_FAIL;
524 }
525
526 return AM_HAL_STATUS_SUCCESS;
527 }
528
529 //*****************************************************************************
530 //
531 // Sets a WDT interrupt.
532 //
533 //*****************************************************************************
534 uint32_t
am_hal_wdt_interrupt_set(am_hal_wdt_select_e eTimer,uint32_t ui32InterruptMask)535 am_hal_wdt_interrupt_set(am_hal_wdt_select_e eTimer,
536 uint32_t ui32InterruptMask)
537 {
538 switch (eTimer)
539 {
540 case AM_HAL_WDT_MCU:
541 WDT->WDTIERSET = ui32InterruptMask;
542 break;
543
544 case AM_HAL_WDT_DSP0:
545 WDT->DSP0IERSET = ui32InterruptMask;
546 break;
547
548 case AM_HAL_WDT_DSP1:
549 WDT->DSP1IERSET = ui32InterruptMask;
550 break;
551
552 default:
553 return AM_HAL_STATUS_FAIL;
554 }
555 return AM_HAL_STATUS_SUCCESS;
556 }
557
558 //*****************************************************************************
559 //
560 // End Doxygen group.
561 //! @}
562 //
563 //*****************************************************************************
564