cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3xx - Hardfault_Handler due to failed vector table fetch

SVasi.1
Associate II

First I want to say that I am a newbie in this field. I am trying to upload and debug a code on a custom-made board based on STM32F303CB chip through a NUCLEO-F446RE board. I am using Eclipse IDE (2019-12), a GNU toolchain and a SEGGER J-Link debugging software.

The code builds successfully with no errors, anyway when starting to debug, a HardFault_handler is called. The code was not written by me. I doubt that the problem is in the code itself (it builds) and rather think that some setting of the tools is not right (correct me if I am wrong). I also tried the same procedure on several boards, so I would exclude a hardware issue as well.

The debugger hangs when initializing the USB in the function **MX_USB_Init()**, leading to a HardFault_handler. When debugging in single-step mode, most funcitons within MX_USB_init() execute successfully, except **USBD_Start(&hUsbDeviceFS)**. When stepping into USBD_Start(...), it arrives in the while(1) loop of the HardFault_handler. 

When debugging in resume mode (no single step), debugger would also hang at previous functions which work properly in single-step mode such as **HAL_PCD_Init(&hpcd_USB_FS)**, **HAL_PCDEx_PMAConfig**, **USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC)**, **USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS)** and again **USBD_Start(&hUsbDeviceFS)**.

I commented out the empty Hardfault_Handler() function in stm32f3xx_it.c generated by CubeMX and caused the calling of the default CMSIS Hardfault_Handler() function in exception_handlers.c. Doing that in the debug console I get the values of several registers:

   SEGGER J-Link GDB Server V6.60f - Terminal output channel

  [HardFault]

  Stack frame:

   R0 = 00000000

   R1 = 0000BF00

   R2 = 40005C00

   R3 = 00000001

   R12 = 0000E000

   LR = FFFFFFF9

   PC = F3EF8008

   PSR = 6000005B

  FSR/FAR:

   CFSR = 00000001

   HFSR = 40000000

   DFSR = 00000000

   AFSR = 00000000

  Misc

   LR/EXC_RETURN= FFFFFFF1

  Connection closed by the GDB server.

Then in the book "Mastering STM32" I read about the following meanings of the above register values:

LR = FFFF FFF9 - CPU has been running "regular code" (CPU was in thread mode) when the Hard Fault exception was called. It was not an interrupt. The stack used was MSP, FPU Unit disabled.

HFSR = 4000 0000 - the VECTBL bit is set which indicates that the Hard Fault is caused by **failed vector table fetch**. The explanation is as follows:

"Bus error received during a vector table fetch. This happens because the vector table is invalid (the most of the times we forgot to include the assembly file provided by ST or we forgot to modify its extension from lower .s to capital .S)."

In my project there is no .s or .S file and no function is referring to such a file. This makes me think that maybe the programmer is trying to write to a wrong address in the memory because there is no proper startup file. Does that make sense for you? Any help would be appreciated.

Thanks in advance!

1 ACCEPTED SOLUTION

Accepted Solutions
SVasi.1
Associate II

SOLUTION:

It appeared that really the startup_stm32fXXXxX.S file was missing. I solved the problem by creating a new dummy project for my MCU using CubeMX and generating the code for Other IDEs (GPDSC). Then I copied the generated .s file (in my case startup_stm32f303xc.s) to the system->src->cmsis folder of the original project and deleted the files system_DEVICE.c and vectors_DEVICE.c. I changed the file extension from small .s to capital .S, compiled the project and then I was able to flash and debug the microcontroller successfully.

Thank you!

View solution in original post

6 REPLIES 6

Maybe you try to run your code from RAM and don't copy the vector table properly, or you use some kind of a bootloader and again don't change VTOR properly.

Check the location of the vector table in disasm, and in debugger check value of SCB->VTOR.

JW

SVasi.1
Associate II

Hi Jan,

not sure if I'm doing the right thing but here are the results:

SCB->VTOR is being updated twice:

  • First in the SystemInit() routine in system_stm32f3xx.c:
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */

Where FLASH_BASE is 0x08000000 and VECT_TAB_OFFSET is 0x0. Here is the disassembly:

203         SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
0000135a:   mov.w   r2, #134217728  ; 0x8000000
0000135e:   ldr     r3, [pc, #16]   ; (0x1370 <SystemInit+88>)
00001360:   str     r2, [r3, #8]
00001362:   bx      lr
00001364:   asrs    r0, r0, #32
00001366:   ands    r2, r0
00001368:   stmia   r0!, {r2, r3}
0000136a:   ldr??.w pc, [pc, #-3276]        ; 0x6a0 <ADPD105_setLedCurrent+184>
0000136e:   vpadd.f32       d14, d0, d0
00001372:   b.n     0x1376 <SystemCoreClockUpdate+2>

After this operation the value of SCB->VTOR is 0x08000000.

  • Just after SystemInit() the following line is executed from _initialize_hardware.c:
  SCB->VTOR = (uint32_t)(&__vectors_start);

The value of __vectors_start ist 0x2000a000 and apparently the &__vectors_start is 0x0 because SCB->VTOR becomes 0 after this iteration. Here is the disassembly:

 65         SCB->VTOR = (uint32_t)(&__vectors_start);
000003ba:   ldr     r3, [pc, #8]    ; (0x3c4 <__initialize_hardware_early+16>)
000003bc:   ldr     r2, [pc, #8]    ; (0x3c8 <__initialize_hardware_early+20>)
000003be:   str     r2, [r3, #8]
000003c0:   pop     {r3, pc}
000003c2:   nop     
000003c4:   stc     0, cr14, [r0, #-0]
000003c8:   movs    r0, r0
000003ca:   movs    r0, r0

Is this what you mean?

SV

I meant, look into disasm to find out where the vector table actually is - I don't doubt a simple C line which assigns a value to a register would translate into anything unexpected... (But yes, finding the table alone does not mean there is no code which would copy it into RAM somewhere.)

> _initialize_hardware.c:

> &__vectors_start is 0x0 because SCB->VTOR becomes 0 after this iteration

This is unusual and probably points towards the problem. Find out, what is the purpose of that pointer in that file - I'd guess it's part of some framework, maybe a company framework? There surely must be some documentation accompanying it, if not, well then it's up to you to hack out its purpose and how its value is supposed to be filled in.

JW

SVasi.1
Associate II

Hi JW,

as I couldn't find what disasm exactly you refer to, I used a tool called readelf to show the .elf file disassembly. Here are the lines that are related to __vectors_start and __vector_start__:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .isr_vector       PROGBITS        00000000 010000 00028c 00  AX  0   0  4
...
Symbol table '.symtab' contains 931 entries:
...
   622: 00000000     0 NOTYPE  GLOBAL DEFAULT  ABS __vectors_start__
...
   809: 00000000     0 NOTYPE  GLOBAL DEFAULT  ABS __vectors_start

Actually __vector_start and __vector_start__ are defined in the linker script (sections.ld):

SECTIONS
{
    /*
     * For Cortex-M devices, the beginning of the startup code is stored in
     * the .isr_vector section, which goes to FLASH. 
     */
    .isr_vector : ALIGN(4)
    {
        FILL(0xFF)
        
        __vectors_start = ABSOLUTE(.) ;
        __vectors_start__ = ABSOLUTE(.) ; /* STM specific definition */
        KEEP(*(.isr_vector))     	/* Interrupt vectors */
        
		KEEP(*(.cfmconfig))			/* Freescale configuration words */   
		     
        /* 
         * This section is here for convenience, to store the
         * startup code at the beginning of the flash area, hoping that
         * this will increase the readability of the listing.
         */
        *(.after_vectors .after_vectors.*)	/* Startup code and ISR */
 
    } >FLASH

And here are the lines in the .map file related to them:

                0x00000000                __vectors_start = ABSOLUTE (.)
                0x00000000                __vectors_start__ = ABSOLUTE (.)
 *(.isr_vector)
 .isr_vector    0x00000000       0x44 ./system/src/cmsis/vectors_DEVICE.o
                0x00000000                __isr_vectors

As the project was created with an older version of Eclipse and the GNU ARM toolchain and used to work, could it be possible that the issue is due to the newer versions, libraries etc.?

SVasi.1
Associate II

SOLUTION:

It appeared that really the startup_stm32fXXXxX.S file was missing. I solved the problem by creating a new dummy project for my MCU using CubeMX and generating the code for Other IDEs (GPDSC). Then I copied the generated .s file (in my case startup_stm32f303xc.s) to the system->src->cmsis folder of the original project and deleted the files system_DEVICE.c and vectors_DEVICE.c. I changed the file extension from small .s to capital .S, compiled the project and then I was able to flash and debug the microcontroller successfully.

Thank you!

Thanks for coming back with the solution.

Please chose your post as Best, so that the thread is marked as solved.

JW