log2 causes a fault in STM32F4 MCU in C

1

Why does this code cause hard fault and jumps into infinite loop?

#include <stdint.h>
#include <math.h>

void myfunc()
{  
    const double val = 1;
    double log_res = log2(val); // <----- THIS CAUSES A FAULT
    //double log_res = log2(1); // This works
}

When I replace val in the evil line by a hard-coded 1, the code works. So the problem happens only when I pass val to log2 (as shown in code). Why is this happening?

I am using STM32CubeIDE (eclipse based), with STM32F429ZI MCU.

UPDATE:

Checking the exception in the disassembly window showed that this is the exception happened:

fffffff9: Failed to execute MI command: -data-disassemble -s 4294967289 -e 4294967429 -- 3 Error message from debugger back end: Cannot access memory at address 0xfffffffe

Any one has idea why is this happening?

Update 2:

Debugging in the assembly instructions:

54            const double val = 1;
08000e0a:   mov.w   r3, #0
08000e0e:   ldr     r4, [pc, #64]   ; (0x8000e50 <myfunc+88>)
08000e10:   strd    r3, r4, [r7, #16]
55            double log_res = log2(val);
08000e14:   vldr    d0, [r7, #16] // <------ X THIS LINE CAUSES THE PROBLEM X
08000e18:   bl      0x8002a9c <log>
08000e1c:   vmov    r0, r1, d0
08000e20:   add     r3, pc, #36     ; (adr r3, 0x8000e48 <myfunc+80>)
08000e22:   ldrd    r2, r3, [r3]
08000e26:   bl      0x800085c <__divdf3>

The emphisized line has d0=0, r7=0x2002ffcc

After executing this line, the disassembler jumps to WWDG_IRQHandler.

Update 3:

GCC Assembler options (not sure what does this do):

-mcpu=cortex-m4 -g3 -c -x assembler-with-cpp --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb

GCC compiler options:

-mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32F429I_DISC1 -DSTM32 -DSTM32F429ZITx -DSTM32F4 -DDEBUG -DSTM32F429xx -c -I..\Inc -I../Inc/CMSIS/Include -I../Inc/CMSIS/Device/ST/STM32F4xx/Include -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb

GCC linker options:

-mcpu=cortex-m4 -T"C:\Users\mne\STM32CubeIDE\workspace_1.0.0\MyUSB\STM32F429ZITX_FLASH.ld" --specs=nosys.specs -Wl,-Map="${ProjName}.map" -Wl,--gc-sections -static --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -Wl,--start-group -lc -lm -Wl,--end-group

Udpate 4:

The problem seems to happend with many functions of math.h, e.g. fmin.

c
arm
stm32
stm32f4
stm32cubeide
asked on Stack Overflow Sep 28, 2019 by Mohammed Noureldin • edited Oct 26, 2019 by Mohammed Noureldin

4 Answers

3

You appear to be omitting the flags -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb from your compiler options, and including them only in your assembler options. (You might substitute -march=armv7-m -mtune=cortex-m4 for -mcpu=cortex-m4.) Therefore, your compiler is generating code for the wrong floating-point ABI. You specified the hard ABI, but are generating a call to the soft library function rather than inline assembly instructions.

Edit: If the compiler is generating instructions your FPU does not support, as Richard at ImageCraft observes, you might try changing the flags to --mcpu=cortex-m4 --mfpu=auto.

Note that any level of optimizaiton, even -O1, is enough for GCC to fold the constant and optimize the call to double position = 0.0;. You might need to have the function return position; to get it to emit this code with optimizations on. (I assume this is a simplified MCVE, as you would never actually need to compute log2(1) at runtime.)

answered on Stack Overflow Sep 30, 2019 by Davislor • edited Sep 30, 2019 by Davislor
2

The problem is here:

08000e14: vldr d0, [r7, #16] // <------ X THIS LINE CAUSES THE PROBLEM X

"d0" is a 64-bit VFP register. However, Cortex-M4F only has 32-bit FPU (registers s0, s1, etc.). Cortex-M7F has 64-bit FPU but that's not what you are using.

So the instruction is invalid for the Cortex-M4F core which causes the fault. I could duplicate this with GCC 2018-Q4 release. The problem will go away if you remove the -mfloat-abi=hard, as it then uses the ARM core CPU registers to pass the argument. So that's the fix I'd recommend.

As for the root cause, I will need to do some more investigations.

answered on Stack Overflow Sep 30, 2019 by Richard at ImageCraft • edited Oct 26, 2019 by Mohammed Noureldin
0

regarding your question:

When I replace val in the evil line by a hard-coded 1, the code works. So the problem happens only when I pass val to log2 (as shown in code). Why is this happening?

The following statement:

double position = log2(first_set);

is NOT passing the variable val to the function: log2()

I would expect such a coding error (since first_set is not defined) to result in the code not compiling.

answered on Stack Overflow Sep 29, 2019 by user3629249
0

The STMF4 series does not support double precision floats. Change the double to float to use single precision floats.

answered on Stack Overflow Oct 1, 2019 by Dan Green

User contributions licensed under CC BY-SA 3.0