19

I have an application that I am porting from the Keil IDE to build with the GNU toolchain due to license issues. I have successfully be able to set up, build, flash and run the application on the device.

The application on the GNU side is for some reason is getting stuck in the weak linked IRQ handler for the WWDG which is an infinite loop. The application does not enable the WWDG, and it is disabled at reset by default. I have also verified that the configuration registers are at their default startup values.

The only difference, other than compilers, are the linker and startup files. However, both the startup files, and linker files used by both toolchains are defaults generated by STM.

Any idea what may be causing this? I'm about at my wits end here.

Using the stm32f103XX, let me know if any other information would be helpful.

EDIT: Using the comments below I was able to ascertain that it is, in fact, the HardFault_Handler that is being triggered. I have included the backtrace output below if that may be of help

GDB BT:

0 HardFault_Handler ()

1 (signal handler called)

2 0x720a3de in ?? ()

3 0x80005534 in foo ()

Backtrace stopped: previous frame identical to this frame (corrupt stack?)

2 things stand out to me, though im no gdb expert. 1) foo is not a function, it is a const array of chars and 2) 0x0720a3de is not a valid memory address the flash address range starts at 0x08000000

Wulfric Lee
  • 869
  • 1
  • 8
  • 19
gettingSmarter
  • 591
  • 1
  • 4
  • 14
  • 2
    Are you sure it's really the WWDG? Another `while(1);` may be sharing that code due to optimization. Does the map file show only the WWDG at that address? – D Krueger Dec 23 '14 at 16:44
  • 2
    You may be on to something. It appears that in the .elf file all the default irq symbols point to the same address, which I suppose means it's just a coincidence that the WWDG_IRQ name is ues in the debugger. I will add stong link functions for the irq's so I can figure out which one exactly is the culprit. – gettingSmarter Dec 23 '14 at 16:54
  • I got stuck in the `HardFault_Handler` too, I spend the whole day and night to figure out the reason, it turned out that I forgot to compile all peripheral files(`stm32f10x_adc.o`, `stm32f10x_bkp.o`, `stm32f10x_can.o`, `stm32f10x_cec.o`... `misc.o`) and link them, I feel I'm a fool‍♂️ – Wulfric Lee Feb 08 '19 at 15:23

8 Answers8

12

So thanks to the kick in the pants by D Krueger. I was able to figure out that the HardFault_Handler was what was actually being called. So, anyone that stumbles on this post, verify which IRQ is truly being called by writing temporary functions to cover the likely culprits i.e. HardFault. The true issue for the IRQ call is a bad memory access by memcpy which I am on my way to solving next.

gettingSmarter
  • 591
  • 1
  • 4
  • 14
  • I am pretty sure that you will find that the bad memory access is not "*by memcpy*", but rather *your call* to memcpy. – Clifford Dec 24 '14 at 09:27
  • 3
    The final culprit turned out to be my failure to link with the correct options I was compiling with. I forgot to link with -mthumb and -mcpu=cortex-m3 options. So I was linking with the incorrect c libraries. – gettingSmarter Dec 29 '14 at 19:07
  • What do you put in the "temporary functions" to know which one is called? LED on through GPIO? Breakpoint? – Matthieu Dec 12 '18 at 14:55
6

I've had this problem due to the same root cause as awilhite. I'm using Atollic TrueStudio 8.0.0. I used it to start a project for STM32F030 and (probably manually) added libraries folder with stm32f0xx.h, which defines ADC1_IRQn (IRQ channel number used in NVIC setup).

And I implemented ADC1_IRQHandler(void) in my main.c (as I'm used to and it always worked so far -- x_IRQn -> x_IRQHandler)

But after 2 days frustration, I found out, that startup_stm32f0xx.s in my project defines ADC1_COMP_IRQHandler.

So, ultimately, my ADC interrupt handler was undefined and when the ADC generated the interrupt, the program crashed (WWDG interrupt).

I hope this helps to people like me, who think they did implement their handler but in fact, they did not.

Mike
  • 161
  • 1
  • 3
  • Thanks to you I had only one day of frustration :) The `startup_xxx.s` defines the function names expected for interrupt vectors. When blindly copy-pasting sources from one project to another, it is easy to miss that part, when the original code is using `ADC1_IRQHandler()` but the STM32 is in fact calling `ADC1_COMP_IRQHandler()`. – Matthieu Dec 12 '18 at 15:24
5

I had exactly the same error as OP (apparent WWDG interrupt, but actually the HardFault_Handler firing) when porting an example for the STM32F3 Discovery board to compile in CooCox CoIDE 1.7.7 with STM32Cube F3 libraries (v1.1.0). The code ran fine as long as I didn't try using any interrupts, but as soon as I turned on the SysTick timer interrupt, the HardFault exception tripped.

The problem was that I had neglected to include the stm32f3xx_it.h and stm32f3xx_it.c files in the project. Their absence wasn't causing any compiler warnings/errors. Once they were compiled & linked in, the code with interrupts ran fine.

3

I had a very similar problem when merging two projects generated separately by STM32CubeMX for an STM32F2XX processor. One project was using the Ethernet peripheral, while the other was not. Besides that one difference, the two projects used the same set of peripherals.

After integrating the two projects together by manually copying files, the application would end up in the WWDG_IRQHandler after starting the first task (when interrupts are enabled for the first time). I first confirmed that the WDGA bit of the WWDG register was indeed not set and, therefore, that the WWDG peripheral was disabled. Next, I verified that the interrupt vector table was initialized correctly. Finally, after several hours of digging, I realized that I had not defined the ETH_IRQHandler function in stm32f2xx_it.c, which provoked the Ethernet interrupt to be handled by the default handler, masking itself as the WWDG_IRQHandler -- likely due to optimization.

awilhite
  • 103
  • 1
  • 9
3

The core problem is that the Default Handler is called instead of another irq handler. I doubt that our situations are the same but here is my solution:

I was working on a c++ project, the same happened to me. This was the first time I made a project from scratch & with CMSIS. After some unsuccessful attempts I went through a generated project when I noticed that in the stm32xxxx_it.h the IRQ handler function prototypes are guarded by these:

extern "C"
{
    void TIM7_IRQHandler(void);
}

With these guards the linker could find my own interrupt handler functions.

bmann
  • 71
  • 6
  • Just the exact Issue I've – Hamza Hajeir Jan 25 '21 at 11:59
  • I'm using platformio, I had to manually change `stm32f1xx_it.c` to `stm32f1xx_it.cpp` too. I don't know the header file doesn't catch the __cplusplus definition, and why it's compiled with C compiler. That could be a PlatformIO issue. or my lack of understanding... maybe. – Hamza Hajeir Jan 25 '21 at 12:00
2

I'll expand a bit on what led me here, and how I use the insight from @Mike to correct it.

I had a project running fine on a demo project in Eclipse SW4STM32, but with sources and headers scattered all over the place so I wanted to have a more "compact" project easier to customize and use as a base for minor modifications (and easier to follow in Git).

I created an empty AC6 project targetting the same board. It generated the HAL drivers, the startup_stm32.s and LinkerScript.ld. I then copied all of the .c and corresponding .h from the original project to my new project (which was a pain in itself because they were scattered in BSP, CMSIS, Components, Middlewares, etc. directories). Everything compiled and seemed to work, until I started modifying a bit.

In the debugger, it seemed all function calls were working until the while(1) main loop where I ended up in the Default_Handler defined in the startup_stm32.s, seemingly from WWDG_IRQHandler. That was, in fact, the default IRQ handler for not-user-defined handlers (WWDG_IRQHandler being the first one declared, it was reported as such by gdb, as indicated by @D Krüger).

I started looking at compiler and linker options or linker script, without much luck, until I realized the only file I didn't check was the startup_stm32.s, which was indeed different.

I blindly copy-pasted it and voilà!

The explanation I could give is that the STM32 is calling IRQ handlers defined in the startup_stm32.s when interrupt occur, all of them initially pointing to Default_Handler() (later overriden by the linker). So if a .c file you copied defines a handler with a slightly different name (but consistent with its own startup_xxx.s), you'll end up with the Default_Handler() being called (which is an infinite loop) instead of the one you defined. And things go wrong.

See https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html for more information.

N.B. I'm not happy to blindly copy-paste without fully understanding, but time constraints and milestones usually push you to territories you're not happy to explore...

Matthieu
  • 2,529
  • 4
  • 49
  • 80
0

In my case, I had a function written in the GCC assembly that was migrated from the ARM assembly. The problem went away after I had added the .thumb_func line to the assembly file.

I was getting this error:

(gdb) c
+c
Continuing.

Program received signal SIGINT, Interrupt.
WWDG_IRQHandler () at ...startup_stm32f40_41xxx.s:121

(gdb) bt
#0  WWDG_IRQHandler () at ...startup_stm32f40_41xxx.s:12
#1  <signal handler called>
#2  RTOS_SysTick_Handler () at ...osKernel.s:18
#3  <signal handler called>
#4  0x0800021a in task0 () at ...main.cpp:10
#5  0x08000214 in frame_dummy ()
#6  0x00000000 in ?? ()

RTOS_SysTick_Handler is a function written in assembly and the WWDG_IRQHandler was always triggered before any first assembly instructions in that function (tried different instructions and it didn't change anything).

I was doing some tweaks around the C code and at some point, I hit another handler: UsageFault which led me to the .thumb_func hint: ARM Cortex M4 SVC_Handler "UsageFault".

Stanislav Pankevich
  • 9,838
  • 6
  • 60
  • 113
-1

Will add my 5 cents. I had this issue on stm32h7, but for me the cause was that the cube "forgot" to add TIM16_IRQHandler when TIM16 is used as the timebase source. It was not happening at the beginning but after several code regenerations. Looks like a bug in the cube, as the TIM16 was still set, but the interrupt handler got removed. So toggking to TIM17 and back resolved the issue.

Evgeny Erlihman
  • 439
  • 4
  • 11