Skip to main content
jaromir sukuba
Associate
November 19, 2021
Solved

[SOLVED] Sprintf with floating point number crashing into hard fault on STM32L476, working fine with STM32F091

  • November 19, 2021
  • 5 replies
  • 16145 views

I'm trying to use this C code

#include <stdio.h>
 
 
char arr[50];
int var_int;
float var_float;
 
int main (void)
{
while (1)
	{
	var_int++;
	sprintf (arr,"RES 1 %d",var_int);
	var_float = var_float + 0.1;
	sprintf (arr,"RES2 %d %f",var_int,var_float);
	}
}

on STM32L476 nucleo kit, with STM32CubeIDE (Version: 1.5.0 Build: 8698_20201117_1050 (UTC)), I'm using debugger, stepping the code and observing variables in expression window, however the code always fails at second sprintf call (the one with float variable). Before trying to execute second sprintf call I can see proper output from first sprintf call, as well as float variable with proper value

0693W00000GYFKSQA5.pngbut after second sprintf call I find the MCU executing endless loop after fault. The second sprintf managed to print output up to the floating point part.

0693W00000GYFJyQAP.pngI started fresh project for this, didn't modify linker file nor any project settings, with exception of ticking "Use float with with printf from newlib-nano"

0693W00000GYFMYQA5.pngI suppose hard fault from sprintf is not desired outcome, but I can't find any obvious way to fix this.

For sake of completeness, due to size, map file is pasted here https://pastebin.com/CeyVYpEP and build output follows.

12:32:09 **** Incremental Build of configuration Debug for project test476 ****
make -j2 all 
arm-none-eabi-gcc "../Src/main.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32L4 -DSTM32 -DNUCLEO_L476RG -DDEBUG -DSTM32L476RGTx -c -I../Inc -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Src/main.d" -MT"Src/main.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Src/main.o"
arm-none-eabi-gcc -o "test476.elf" @"objects.list" -mcpu=cortex-m4 -T"/home/jarin/STM32CubeIDE/workspace_1.5.0/test476/STM32L476RGTX_FLASH.ld" --specs=nosys.specs -Wl,-Map="test476.map" -Wl,--gc-sections -static --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -u _printf_float -Wl,--start-group -lc -lm -Wl,--end-group
Finished building target: test476.elf
 
arm-none-eabi-objdump -h -S test476.elf > "test476.list"
arm-none-eabi-objcopy -O binary test476.elf "test476.bin"
Finished building: test476.bin
Finished building: test476.list
 
arm-none-eabi-size test476.elf 
 
 text	 data	 bss	 dec	 hex	filename
 12520	 472	 1640	 14632	 3928	test476.elf
Finished building: default.size.stdout
 
 
12:32:10 Build Finished. 0 errors, 0 warnings. (took 830ms)

I tried the same source, with the same project setup modification (single checkbox to use float functions) on STM32F091 nucleo kit, where it works as I expect (second printf doesn't crash and prints desired output to char array).

Perhaps I'm overlooking something very obvious, but I can't see where the problem is.

Also, I'm aware of printf and similar functions not being the most fitting for small embedded systems, but this is probably not the topic here.

This topic has been closed for replies.
Best answer by jaromir sukuba

Yes, those are valid points, thanks. I tried to examine the MCU state at the fault state.

0693W00000GYGsHQAX.pngBit 2 in LR is 0, therefore main stack was active at the exception moment, SP points to 0x20017e58, examining this part of memory reveals PC at address SP+0x18, that is 0x0800100A. Disassembly window shows 'vmov   d0, r8, r9' instruction at this address, inside _printf_float function.

vmov makes sense in this context - moving between VFP and registers. R8 and R9 values looked benign to me. While I was at it, I checked CPACR

register and found it's all zeroes, so that FPU wasn't even enabled. I was apparently using wrong version of startup code. After enabling the FPU code works as expected.

Thanks for pushing me to the right direction.

For now I consider this problem as solved.

5 replies

Tesla DeLorean
Guru
November 19, 2021

You're showing it in the Default Handler

Get a proper Hard Fault handler, and look at what's actually faulting, the processor registers at the fault, and the immediate and preceding instructions.

Are you sure it's not a Division by Zero, Usage Fault?

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
jaromir sukuba
Associate
November 19, 2021

That is good observation, I was a bit too quick and didn't show VECTACTIVE bits in SCB->ICSR, set to 0x03, pointing indeed to Hard fault.

I have no sources for library *printf functions in my project to step into and take a look at offending piece of code.

Tesla DeLorean
Guru
November 19, 2021

It doesn't matter if you have the source, the processor is executing machine instructions, not your C code.

You can look at a disassembly view, or generate a listing file of ALL the code.

With some context for the Fault you can determine if it is an issue with parameters, alignment, FPU settings, bugs in the library, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
MM..1
Chief III
November 19, 2021

You are not first that report sprintf problem with float. Maybe try

char arr[500];
int var_int;
float var_float=0.0;

jaromir sukuba
Associate
November 19, 2021

I tried to increase arr size as you suggested, explicitly initialize both variables, with no effect on the result. Sprintf code shouldn't fail with any value of integer of float variable anyway.

Also, I tried to increase minimal stack and heap size from default 0x400 and 0x200 respectively (as set in supplied linker file) to somehow absurd 0x2000 bytes, with no effect as well.

TDK
November 19, 2021

Read VECTACTIVE bits in SCB->ICSR to determine what interrupt it is in. As Tesla says, that is not the hardfault handler.

"If you feel a post has answered your question, please click ""Accept as Solution""."
jaromir sukuba
Associate
November 19, 2021

VECTACTIVE bits in SCB->ICSR read as 0x03, therefore it should be indeed hard fault vector.

0693W00000GYGVqQAP.png

waclawek.jan
Super User
November 20, 2021

*printf() in mcu? Meh... ;)

Even if a nanovoltmeter displaying in semilogarithmic form may be an interesting idea, I personally would still write the conversion myself. K&R's legacy in this case is IMO just too extensive/expensive, and you probably don't need 99% of the features it offers; and you also don't need/want the gotchas it may bring in (although one might argue that this is consequence of not following the basic C rules - C7.1.4#4 in this case - but who does truly and rigorously follow all of them, after all?). But yes, it's your leg and your shot. and I should just shut up.

This all of course wouldn't spare you from the hardfault, would you use floats for any other purpose. My story is, that I tried to be smart and enabled coprocessor not in startup code i.e. not in asm, but in C, in the very first line of main(). This worked OK. Much later, one day, gcc decided that - as main() is treated as a standard function (gcc may have a switch to change this and this may or may not work on Cortex-M, I did not investigate deeper) and due to code growth the usage of floats in main() exceeded the number of registers alotted as callee-saves in ABI - that it needs to save some of the the caller-saves float registers on stack in the function prologue. So that was before the very first line in main(), enabling coprocessor, was executed. And that was it.

JW

PS. Please select your post with the solution as "Best", so that thread is marked as solved.

FEvra.1
Associate
June 1, 2023

How can i disable WWDG_IRQHandler?