I was assigned a
USB Audio project validation task. Run the code and every time I play music
from PC, the code enters HardFault handler. The Hardware environment is
SiM3u164, ARM cortex M3 core.
void HardFault_Handler(void)
{
printf("HardFault_Handler\n");
/*NO SECOND LEVEL HANDLER SPECIFIED (halt USED)*/
halt();
}
It is a good opportunity for me to solve HardFault
issue on a total new and big project. Let’s start it.
1.
The first thing is to check value in Stack and
PC.
Sp=0x20007e18, PC=0x0000b37C
2.
Open the map file, find 0x0000b37c
.text.HardFault_Handler
0x0000b37c 0x18
./src/generated/gCPU.o
0x0000b37c
HardFault_Handler
Of course it is HardFault_Handler address,
it is useless for us.
3.
Open memory view, type 0x20007e18, we got
context in stack memory area.
0x0,0x1,0x5079,0x20001778,0x0,0x5145,0xc06328f1,0x20000032…
In ARM cortex M3, Flash address range is 0x00-0x3FFFF; SRAM address range
is 0x20000000-0x20007FFF. So we can see there are two addresses in stack,
0x5079 and 0x5145, there are the last function executed. Let’s check the map
file again.
4.
0x5079 is 0x5078 due to thumb mode; we can see
it is si32UsbTrace_poller. And 0x5145 is in the range of si32Usb_initiliaze_trace.
The file is si32UsbDebug.o
.text.si32UsbTrace_poller
0x00005078 0x7c
./src/si32Library/si32UsbComponent/si32UsbCoreComponent/si32UsbDebug.o
0x00005078
si32UsbTrace_poller
.text.si32Usb_initialize_trace
0x000050f4 0x58
./src/si32Library/si32UsbComponent/si32UsbCoreComponent/si32UsbDebug.o
0x000050f4
si32Usb_initialize_trace
.text.si32UsbTrace
0x0000514c 0xb0
./src/si32Library/si32UsbComponent/si32UsbCoreComponent/si32UsbDebug.o
0x0000514c
si32UsbTrace
5.
Here is the si32Usb_initalize_trace() function
in si32UsbDebug.c, we can see si32UsbTrace_poller was called here.
//------------------------------------------------------------------------------
// initialize the static memory
allocations required by all instances.
void si32Usb_initialize_trace(void)
{
// create a queue of debug logging messages that can be
// stored in sequence, but printed in the background
si32QueueObject_initialize(&si32UsbTraceQueue,
si32UsbTraceCapacity,
sizeof(si32UsbTraceQueueMemory[0]),
si32UsbTraceQueueMemory);
// reschedule this poller
si32RunLoopObject_post_work_request(si32GetCurrentRunLoop(),
1, // lo prio
si32UsbTrace_poller,
&si32UsbTraceQueue,
NULL);
}
6.
Move cursor on
si32RunLoopObject_post_work_request(), press F2 to expand the macro.(I am using
Precision32) Here is the macro, can see it execute function si32GetCurrentRunLoop.
((si32RunLoopObject
*)((si32GetCurrentRunLoop())))->runLoopObject.functions->post_work_request(((si32GetCurrentRunLoop())),
(1), (si32UsbTrace_poller), (&si32UsbTraceQueue), (((void *)0)))
7.
Move cursor on
si32GetCurrentRunLoop(), press F3 jump to declaration, it return a _the_current_run_loop,
check the value, it is zero. It return a NULL pointer which cause HardFault
error!
si32RunLoopObject* si32GetCurrentRunLoop()
{
}
8.
Solution.
The fastest way is disable execute si32Usb_initialize_trace().
Look up it, only si32UsbTrace, just disable this functional.
void si32UsbTrace(const char * fmt, ...)
{
va_list ap;
_begin_critical_section();
va_start(ap, fmt);
static volatile bool bInit=false;
#if 0
if(!bInit)
{
bInit=true;
si32Usb_initialize_trace();
}
if(!si32QueueObject_is_full(&si32UsbTraceQueue))
{
si32UsbTraceType trace;
trace.fmt=fmt;
trace.arg = va_arg(ap,
uint32_t);
si32QueueObject_write(&si32UsbTraceQueue, &trace );
_end_critical_section();
}
else
{
_end_critical_section();
fputc('*',stdout);
}
#endif
va_end(ap);
}
9.
Validate.
Re-build the code and run, play music from
PC, I can hear audio from device speaker. It is done.