Search This Blog

Jul 26, 2012

Debug Hard Fault Error in Arm Cortex M3


   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.