1 //*****************************************************************************
2 //
3 //! @file am_util_faultisr.c
4 //!
5 //! @brief An extended hard-fault handler.
6 //!
7 //! This module is portable to all Ambiq Apollo products with minimal HAL or BSP
8 //! dependencies (SWO output). It collects the fault information into the sHalFaultData
9 //! structure, which it then prints to stdout (typically SWO).
10 //!
11 //! By default this handler, when included in the build overrides the weak binding of
12 //! the default hardfault handler. It allocates 512 bytes of global variable space for
13 //! a local stack which guarantees diagnostic output under all hardfault conditions. If
14 //! the local stack is not wanted/needed, remove the macro AM_LOCAL_STACK below. If
15 //! the local stack is disabled, and the SP was invalid at the time of the hardfault,
16 //! a second hardfault can occur before any diagnostic data is collected.
17 //!
18 //! This handler outputs information about the state of the processor at the time
19 //! the hardfault occurred to stdout (typically SWO). If output is not desired remove
20 //! the macro AM_UTIL_FAULTISR_PRINT below. When prints are disabled, the fault
21 //! information is available in the local sHalFaultData structure.
22 //!
23 //! The handler does not return. After outputting the diagnostic information, it
24 //! spins forever, it does not recover or try and return to the program that caused
25 //! the hardfault.
26 //!
27 //! Upon entry (caused by a hardfault), it switches to a local stack in case
28 //! the cause of the hardfault was a stack related issue. The stack is sized
29 //! large enough to provide for the local variables and the stack space needed
30 //! for the ouput functions calls being used.
31 //!
32 //! It is compiler/platform independent enabling it to be used with GCC, Keil,
33 //! IAR and easily ported to other tools chains
34 //!
35 //! @addtogroup faultisr FaultISR - Extended Hard Fault ISR
36 //! @ingroup utils
37 //! @{
38 //
39 //*****************************************************************************
40
41 //*****************************************************************************
42 //
43 // Copyright (c) 2023, Ambiq Micro, Inc.
44 // All rights reserved.
45 //
46 // Redistribution and use in source and binary forms, with or without
47 // modification, are permitted provided that the following conditions are met:
48 //
49 // 1. Redistributions of source code must retain the above copyright notice,
50 // this list of conditions and the following disclaimer.
51 //
52 // 2. Redistributions in binary form must reproduce the above copyright
53 // notice, this list of conditions and the following disclaimer in the
54 // documentation and/or other materials provided with the distribution.
55 //
56 // 3. Neither the name of the copyright holder nor the names of its
57 // contributors may be used to endorse or promote products derived from this
58 // software without specific prior written permission.
59 //
60 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
61 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
64 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
65 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
66 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
67 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
68 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
69 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
70 // POSSIBILITY OF SUCH DAMAGE.
71 //
72 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
73 //
74 //*****************************************************************************
75
76 #include <stdint.h>
77 #include "am_mcu_apollo.h"
78
79 //*****************************************************************************
80 //
81 // Macros
82 //
83 //*****************************************************************************
84
85 #define AM_LOCAL_STACK // when defined use local stack for HF Diagnostics
86 //#define AM_UTIL_FAULTISR_PRINT // when defined print output to stdout (SWO)
87
88 //
89 // Macros used by am_util_faultisr_collect_data().
90 //
91 #define AM_REG_SYSCTRL_CFSR_O 0xE000ED28
92 #define AM_REG_SYSCTRL_BFAR_O 0xE000ED38
93 #define AM_REGVAL(x) (*((volatile uint32_t *)(x)))
94
95 //
96 // Macros for valid stack ranges.
97 //
98 #if defined(AM_PART_APOLLO4B) || defined(AM_PART_APOLLO4P) || defined(AM_PART_APOLLO4L)
99 #define AM_SP_LOW SRAM_BASEADDR
100 #define AM_SP_HIGH (SRAM_BASEADDR + RAM_TOTAL_SIZE)
101 #elif defined(AM_PART_APOLLO3P)
102 #define AM_SP_LOW SRAM_BASEADDR
103 #define AM_SP_HIGH (SRAM_BASEADDR + ( 768 * 1024 ))
104 #elif defined(AM_PART_APOLLO3)
105 #define AM_SP_LOW SRAM_BASEADDR
106 #define AM_SP_HIGH (SRAM_BASEADDR + ( 384 * 1024 ))
107 #elif defined(AM_PART_APOLLO2)
108 #define AM_SP_LOW SRAM_BASEADDR
109 #define AM_SP_HIGH (SRAM_BASEADDR + ( 256 * 1024 ))
110 #elif defined(AM_PART_APOLLO)
111 #define AM_SP_LOW SRAM_BASEADDR
112 #define AM_SP_HIGH (SRAM_BASEADDR + ( 64 * 1024 ))
113 #endif
114
115 //*****************************************************************************
116 //
117 // Globals
118 //
119 //*****************************************************************************
120
121 // temporary stack (in case the HF was caused by invalid stack)
122 #if defined(AM_LOCAL_STACK)
123 uint8_t gFaultStack[512]; // needs ~320 bytes (+7 for 8-byte alignment)
124 #endif
125
126 //*****************************************************************************
127 //
128 // Data structures
129 //
130 //*****************************************************************************
131 //
132 // Define a structure for local storage in am_util_faultisr_collect_data().
133 // Set structure alignment to 1 byte to minimize storage requirements.
134 //
135 #pragma pack(1)
136 typedef struct
137 {
138 //
139 // Stacked registers
140 //
141 volatile uint32_t u32R0;
142 volatile uint32_t u32R1;
143 volatile uint32_t u32R2;
144 volatile uint32_t u32R3;
145 volatile uint32_t u32R12;
146 volatile uint32_t u32LR;
147 volatile uint32_t u32PC;
148 volatile uint32_t u32PSR;
149
150 //
151 // Other data
152 //
153 volatile uint32_t u32FaultAddr;
154 volatile uint32_t u32BFAR;
155 volatile uint32_t u32CFSR;
156 volatile uint8_t u8MMSR;
157 volatile uint8_t u8BFSR;
158 volatile uint16_t u16UFSR;
159
160 } am_fault_t;
161
162
163 //
164 // Restore the default structure alignment
165 //
166 #pragma pack()
167
168 //*****************************************************************************
169 //
170 // Prototypes
171 //
172 //*****************************************************************************
173 void am_util_faultisr_collect_data(uint32_t u32IsrSP);
174 bool am_valid_sp(uint32_t u32IsrSP);
175
176 //
177 // Prototype for printf, if used.
178 //
179 extern uint32_t am_util_stdio_printf(char *pui8Fmt, ...);
180
181
182 //*****************************************************************************
183 //
184 // getStackedReg() will retrieve a specified register value, as it was stacked
185 // by the processor after the fault, from the stack.
186 //
187 // The registers are stacked in the following order:
188 // R0, R1, R2, R3, R12, LR, PC, PSR.
189 // To get R0 from the stack, call getStackedReg(0), r1 is getStackedReg(1)...
190 //
191 //*****************************************************************************
192 #if (defined (__ARMCC_VERSION)) && (__ARMCC_VERSION < 6000000)
193 __asm uint32_t
194 #if AM_CMSIS_REGS
HardFault_Handler(void)195 HardFault_Handler(void)
196 #else // AM_CMSIS_REGS
197 am_fault_isr(void)
198 #endif // AM_CMSIS_REGS
199
200 #if defined(AM_LOCAL_STACK)
201 {
202 PRESERVE8
203 import am_util_faultisr_collect_data
204 import gFaultStack
205 tst lr, #4 // Check if we should use MSP or PSP
206 ite eq // Instrs executed when: eq,ne
207 mrseq r0, msp // t: bit2=0 indicating MSP stack
208 mrsne r0, psp // e: bit2=1 indicating PSP stack
209 ldr r1, =gFaultStack // get address of the base of the temp_stack
210 add r1, r1, #512 // address of the top of the stack.
211 bic r1, #3 // make sure the new stack is 8-byte aligned
212 mov sp, r1 // move the new stack address to the SP
213 b am_util_faultisr_collect_data // no return - simple branch to get fault info
214 nop // Avoid compiler warning about padding 2 bytes
215 }
216 #else // no local stack
217 {
218 PRESERVE8
219 import am_util_faultisr_collect_data
220 tst lr, #4 // Check if we should use MSP or PSP
221 ite eq // Instrs executed when: eq,ne
222 mrseq r0, msp // t: bit2=0 indicating MSP stack
223 mrsne r0, psp // e: bit2=1 indicating PSP stack
224 b am_util_faultisr_collect_data // no return - simple branch to get fault info
225 }
226 #endif
227
228 __asm uint32_t
getStackedReg(uint32_t regnum,uint32_t u32SP)229 getStackedReg(uint32_t regnum, uint32_t u32SP)
230 {
231 lsls r0, r0, #2
232 adds r0, r0, r1
233 ldr r0, [r0]
234 bx lr
235 }
236
237 #elif (defined (__ARMCC_VERSION)) && (__ARMCC_VERSION > 6000000)
238 uint32_t __attribute__((naked))
239 #if AM_CMSIS_REGS
HardFault_Handler(void)240 HardFault_Handler(void)
241 #else // AM_CMSIS_REGS
242 am_fault_isr(void)
243 #endif // AM_CMSIS_REGS
244 {
245 __asm(" tst lr, #4\n" // Check if we should use MSP or PSP
246 " ite eq\n" // Instrs executed when: eq,ne
247 " mrseq r0, msp\n" // t: bit2=0 indicating MSP stack
248 " mrsne r0, psp\n"); // e: bit2=1 indicating PSP stack
249 #if defined(AM_LOCAL_STACK)
250 __asm(" ldr r1, =gFaultStack\n" // get address of the base of the temp_stack
251 " add r1, r1, #512\n" // address of the top of the stack.
252 " bic r1, #3\n" // make sure the new stack is 8-byte aligned
253 " mov sp,r1\n"); // move the new stack address to the SP
254 #endif
255 __asm(" b am_util_faultisr_collect_data\n"); // no return - simple branch to get fault info
256 }
257
258 uint32_t __attribute__((naked))
getStackedReg(uint32_t regnum,uint32_t u32SP)259 getStackedReg(uint32_t regnum, uint32_t u32SP)
260 {
261 __asm(" lsls r0, r0, #2");
262 __asm(" adds r0, r1");
263 __asm(" ldr r0, [r0]");
264 __asm(" bx lr");
265 }
266 #elif defined(__GNUC_STDC_INLINE__)
267 uint32_t __attribute__((naked))
268 #if AM_CMSIS_REGS
HardFault_Handler(void)269 HardFault_Handler(void)
270 #else // AM_CMSIS_REGS
271 am_fault_isr(void)
272 #endif // AM_CMSIS_REGS
273 {
274 __asm(" tst lr, #4\n" // Check if we should use MSP or PSP
275 " ite eq\n" // Instrs executed when: eq,ne
276 " mrseq r0, msp\n" // t: bit2=0 indicating MSP stack
277 " mrsne r0, psp\n"); // e: bit2=1 indicating PSP stack
278 #if defined(AM_LOCAL_STACK)
279 __asm(" ldr r1, =gFaultStack\n" // get address of the base of the temp_stack
280 " add r1, r1, #512\n" // address of the top of the stack.
281 " bic r1, #3\n" // make sure the new stack is 8-byte aligned
282 " mov sp,r1\n"); // move the new stack address to the SP
283 #endif
284 __asm(" b am_util_faultisr_collect_data\n"); // no return - simple branch to get fault info
285 }
286
287 uint32_t __attribute__((naked))
getStackedReg(uint32_t regnum,uint32_t u32SP)288 getStackedReg(uint32_t regnum, uint32_t u32SP)
289 {
290 __asm(" lsls r0, r0, #2");
291 __asm(" adds r0, r1");
292 __asm(" ldr r0, [r0]");
293 __asm(" bx lr");
294 }
295 #elif defined(__IAR_SYSTEMS_ICC__)
296 #pragma diag_suppress = Pe940 // Suppress IAR compiler warning about missing
297 // return statement on a non-void function
298 __stackless uint32_t
299 #if AM_CMSIS_REGS
HardFault_Handler(void)300 HardFault_Handler(void)
301 #else // AM_CMSIS_REGS
302 am_fault_isr(void)
303 #endif // AM_CMSIS_REGS
304 {
305 __asm(" tst lr, #4\n" // Check if we should use MSP or PSP
306 " ite eq\n" // Instrs executed when: eq,ne
307 " mrseq r0, msp\n" // t: bit2=0 indicating MSP stack
308 " mrsne r0, psp\n"); // e: bit2=1 indicating PSP stack
309 #if defined(AM_LOCAL_STACK)
310 __asm(" ldr r1, =gFaultStack\n" // get address of the base of the temp_stack
311 " add r1, r1, #512\n" // address of the top of the stack.
312 " bic r1, #3\n" // make sure the new stack is 8-byte aligned
313 " mov sp,r1\n"); // move the new stack address to the SP
314 #endif
315 __asm(" b am_util_faultisr_collect_data\n"); // no return - simple branch to get fault info
316 }
317
318 __stackless uint32_t
getStackedReg(uint32_t regnum,uint32_t u32SP)319 getStackedReg(uint32_t regnum, uint32_t u32SP)
320 {
321 __asm(" lsls r0, r0, #2");
322 __asm(" adds r0, r0, r1");
323 __asm(" ldr r0, [r0]");
324 __asm(" bx lr");
325 }
326 #pragma diag_default = Pe940 // Restore IAR compiler warning
327 #endif
328
329 //*****************************************************************************
330 //
331 // am_util_faultisr_collect_data(uint32_t u32IsrSP);
332 //
333 // This function is intended to be called by HardFault_Handler(), called
334 // when the processor receives a hard fault interrupt. This part of the
335 // handler parses through the various fault codes and saves them into a data
336 // structure so they can be readily examined by the user in the debugger.
337 //
338 // The input u32IsrSP is expected to be the value of the stack pointer when
339 // HardFault_Handler() was called.
340 //
341 //*****************************************************************************
342 void
am_util_faultisr_collect_data(uint32_t u32IsrSP)343 am_util_faultisr_collect_data(uint32_t u32IsrSP)
344 {
345 volatile am_fault_t sFaultData;
346 #if defined(AM_PART_APOLLO4B) || defined(AM_PART_APOLLO4P) || defined(AM_PART_APOLLO4L)
347 am_hal_fault_status_t sHalFaultData = {0};
348 #elif defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P) || defined(AM_PART_APOLLO2) || defined(AM_PART_APOLLO)
349 am_hal_mcuctrl_fault_t sHalFaultData = {0};
350 #endif // if defined(AM_PART_APOLLO4X)
351
352 uint32_t u32Mask = 0;
353
354 //
355 // Following is a brief overview of fault information provided by the M4.
356 // More details can be found in the Cortex M4 User Guide.
357 //
358 // CFSR (Configurable Fault Status Reg) contains MMSR, BFSR, and UFSR:
359 // 7:0 MMSR (MemManage)
360 // [0] IACCVIOL Instr fetch from a location that does not
361 // permit execution.
362 // [1] DACCVIOL Data access violation flag. MMAR contains
363 // address of the attempted access.
364 // [2] Reserved
365 // [3] MUNSTKERR MemMange fault on unstacking for a return
366 // from exception.
367 // [4] MSTKERR MemMange fault on stacking for exception
368 // entry.
369 // [5] MLSPERR MemMange fault during FP lazy state
370 // preservation.
371 // [6] Reserved
372 // [7] MMARVALID MemManage Fault Addr Reg (MMFAR) valid flag.
373 // 15:8 BusFault
374 // [0] IBUSERR If set, instruction bus error.
375 // [1] PRECISERR Data bus error. Stacked PC points to instr
376 // that caused the fault.
377 // [2] IMPRECISERR Data bus error, but stacked return addr is not
378 // related to the instr that caused the error and
379 // BFAR is not valid.
380 // [3] UNSTKERR Bus fault on unstacking for a return from
381 // exception.
382 // [4] STKERR Bus fault on stacking for exception entry.
383 // [5] LSPERR Bus fault during FP lazy state preservation.
384 // [6] Reserved
385 // [7] BFARVALID BFAR valid.
386 // 31:16 UFSR (UsageFault)
387 // [0] UNDEFINSTR Undefined instruction.
388 // [1] INVSTATE Invalid state.
389 // [2] INVPC Invalid PC load.
390 // [3] NOCP No coprocessor.
391 // [7:4] Reserved
392 // [8] UNALIGNED Unaligned access.
393 // [9] DIVBYZERO Divide by zero.
394 // [15:10] Reserved
395 //
396
397 //
398 // u32Mask is used for 2 things: 1) in the print loop, 2) as a spot to set
399 // a breakpoint at the end of the routine. If the printing is not used,
400 // we'll get a compiler warning; so to avoid that warning, we'll use it
401 // in a dummy assignment here.
402 //
403 sFaultData.u32CFSR = u32Mask; // Avoid compiler warning
404 sFaultData.u32CFSR = AM_REGVAL(AM_REG_SYSCTRL_CFSR_O);
405 sFaultData.u8MMSR = (sFaultData.u32CFSR >> 0) & 0xff;
406 sFaultData.u8BFSR = (sFaultData.u32CFSR >> 8) & 0xff;
407 sFaultData.u16UFSR = (sFaultData.u32CFSR >> 16) & 0xffff;
408
409 //
410 // The address of the location that caused the fault. e.g. if accessing an
411 // invalid data location caused the fault, that address will appear here.
412 //
413 sFaultData.u32BFAR = AM_REGVAL(AM_REG_SYSCTRL_BFAR_O);
414
415 // make sure that the SP points to a valid address (so that accessing the stack frame doesn't cause another fault).
416 if (am_valid_sp(u32IsrSP))
417 {
418 //
419 // The address of the instruction that caused the fault is the stacked PC
420 // if BFSR bit1 is set.
421 //
422 sFaultData.u32FaultAddr = (sFaultData.u8BFSR & 0x02) ? getStackedReg(6, u32IsrSP) : 0xffffffff;
423
424 //
425 // Get the stacked registers.
426 // Note - the address of the instruction that caused the fault is u32PC.
427 //
428 sFaultData.u32R0 = getStackedReg(0, u32IsrSP);
429 sFaultData.u32R1 = getStackedReg(1, u32IsrSP);
430 sFaultData.u32R2 = getStackedReg(2, u32IsrSP);
431 sFaultData.u32R3 = getStackedReg(3, u32IsrSP);
432 sFaultData.u32R12 = getStackedReg(4, u32IsrSP);
433 sFaultData.u32LR = getStackedReg(5, u32IsrSP);
434 sFaultData.u32PC = getStackedReg(6, u32IsrSP);
435 sFaultData.u32PSR = getStackedReg(7, u32IsrSP);
436 }
437 //
438 // Use the HAL MCUCTRL functions to read the fault data.
439 //
440 #if defined(AM_PART_APOLLO4B) || defined(AM_PART_APOLLO4P) || defined(AM_PART_APOLLO4L)
441 am_hal_fault_status_get(&sHalFaultData);
442 #elif defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
443 am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_FAULT_STATUS, &sHalFaultData);
444 #elif defined(AM_PART_APOLLO2) || defined(AM_PART_APOLLO)
445 am_hal_mcuctrl_fault_status(&sHalFaultData);
446 #endif
447
448 #ifdef AM_UTIL_FAULTISR_PRINT
449 //
450 // If printf has previously been initialized in the application, we should
451 // be able to print out the fault information.
452 //
453 am_util_stdio_printf("** Hard Fault Occurred:\n\n");
454 if (!am_valid_sp(u32IsrSP))
455 {
456 am_util_stdio_printf(" Invalid SP when Hard Fault occured: 0x%08X (no Stacked data)\n\n");
457 }
458 else
459 {
460 am_util_stdio_printf("Hard Fault stacked data:\n");
461 am_util_stdio_printf(" R0 = 0x%08X\n", sFaultData.u32R0);
462 am_util_stdio_printf(" R1 = 0x%08X\n", sFaultData.u32R1);
463 am_util_stdio_printf(" R2 = 0x%08X\n", sFaultData.u32R2);
464 am_util_stdio_printf(" R3 = 0x%08X\n", sFaultData.u32R3);
465 am_util_stdio_printf(" R12 = 0x%08X\n", sFaultData.u32R12);
466 am_util_stdio_printf(" LR = 0x%08X\n", sFaultData.u32LR);
467 am_util_stdio_printf(" PC = 0x%08X\n", sFaultData.u32PC);
468 am_util_stdio_printf(" PSR = 0x%08X\n\n", sFaultData.u32PSR);
469 }
470 am_util_stdio_printf("Other Hard Fault data:\n");
471 am_util_stdio_printf(" Fault address = 0x%08X\n", sFaultData.u32FaultAddr);
472 am_util_stdio_printf(" BFAR (Bus Fault Addr Reg) = 0x%08X\n", sFaultData.u32BFAR);
473 am_util_stdio_printf(" MMSR (Mem Mgmt Fault Status Reg) = 0x%02X\n", sFaultData.u8MMSR);
474 am_util_stdio_printf(" UFSR (Usage Fault Status Reg) = 0x%04X\n", sFaultData.u16UFSR);
475 am_util_stdio_printf(" BFSR (Bus Fault Status Reg) = 0x%02X\n", sFaultData.u8BFSR);
476 //
477 // Print out any bits set in the BFSR.
478 //
479 u32Mask = 0x80;
480 while (u32Mask)
481 {
482 switch (sFaultData.u8BFSR & u32Mask)
483 {
484 case 0x80:
485 am_util_stdio_printf(" BFSR bit7: BFARVALID\n");
486 break;
487 case 0x40:
488 am_util_stdio_printf(" BFSR bit6: RESERVED\n");
489 break;
490 case 0x20:
491 am_util_stdio_printf(" BFSR bit5: LSPERR\n");
492 break;
493 case 0x10:
494 am_util_stdio_printf(" BFSR bit4: STKERR\n");
495 break;
496 case 0x08:
497 am_util_stdio_printf(" BFSR bit3: UNSTKERR\n");
498 break;
499 case 0x04:
500 am_util_stdio_printf(" BFSR bit2: IMPRECISERR\n");
501 break;
502 case 0x02:
503 am_util_stdio_printf(" BFSR bit1: PRECISEERR\n");
504 break;
505 case 0x01:
506 am_util_stdio_printf(" BFSR bit0: IBUSERR\n");
507 break;
508 default:
509 break;
510 }
511 u32Mask >>= 1;
512 }
513
514 //
515 // Print out any Apollo* Internal fault information - if any
516 //
517 if (sHalFaultData.bICODE || sHalFaultData.bDCODE || sHalFaultData.bSYS)
518 {
519 am_util_stdio_printf("\nMCU Fault data:\n");
520 }
521 if (sHalFaultData.bICODE)
522 {
523 am_util_stdio_printf(" ICODE Fault Address: 0x%08X\n", sHalFaultData.ui32ICODE);
524 }
525 if (sHalFaultData.bDCODE)
526 {
527 am_util_stdio_printf(" DCODE Fault Address: 0x%08X\n", sHalFaultData.ui32DCODE);
528 }
529 if (sHalFaultData.bSYS)
530 {
531 am_util_stdio_printf(" SYS Fault Address: 0x%08X\n", sHalFaultData.ui32SYS);
532 }
533 //
534 // Spin in an infinite loop.
535 // We need to spin here inside the function so that we have access to
536 // local data, i.e. sFaultData.
537 //
538 am_util_stdio_printf("\n\nDone with output. Entering infinite loop.\n\n");
539
540 #endif // AM_UTIL_FAULTISR_PRINT
541
542 u32Mask = 0;
543
544 while (1) { }; // spin forever
545 }
546
547 //*****************************************************************************
548 //
549 // am_valid_sp(uint32_t u32IsrSP);
550 //
551 // This function does a range on the SP to make sure it appears to be valid
552 //
553 // The input param u32IsrSP is expected to be the value of the stack pointer in
554 // use when the hardfault occured.
555 //
556 //*****************************************************************************
557 bool
am_valid_sp(uint32_t u32IsrSP)558 am_valid_sp(uint32_t u32IsrSP)
559 {
560 return ( (u32IsrSP >= AM_SP_LOW) && (u32IsrSP < AM_SP_HIGH) ) ? true : false;
561 }
562 //*****************************************************************************
563
564
565 //*****************************************************************************
566 //
567 // End Doxygen group.
568 //! @}
569 //
570 //*****************************************************************************
571