Float numbers crash my program but double numbers don't

I have encountered a very strange problem recently。I plan to change the data that needs to be read frequently from double type to float type because I am worried about the errors caused by the interruption of data reading and I have already done so on some variables。Then I found this problem:

If I run a task like this:

void float_test(void)
{
	const TickType_t delay_time = pdMS_TO_TICKS(10);
	TickType_t lastweak = xTaskGetTickCount();
	
	float a = 0.0;
	float b = 0.1;
	
	while(1)
	{
		if(a < 10000)
		{
			a += 12 * b;
		}
		vTaskDelayUntil(&lastweak, delay_time);
	}
}

xTaskCreate((void*)float_test, "tsp", 100, NULL, 5, NULL);

then my program will be crashed,but if I change the task like this:

void float_test(void)
{
	const TickType_t delay_time = pdMS_TO_TICKS(10);
	TickType_t lastweak = xTaskGetTickCount();
	
	double a = 0.0;
	double b = 0.1;
	
	while(1)
	{
		if(a < 10000)
		{
			a += 12 * b;
		}
		vTaskDelayUntil(&lastweak, delay_time);
	}
}

xTaskCreate((void*)float_test, "tsp", 100, NULL, 5, NULL);

or like this:

void float_test(void)
{
	const TickType_t delay_time = pdMS_TO_TICKS(10);
	TickType_t lastweak = xTaskGetTickCount();
	
	float a = 0.0;
	float b = 0.1;
	
	while(1)
	{
		if(a < 10000)
		{
			12 * b;
		}
		vTaskDelayUntil(&lastweak, delay_time);
	}
}

xTaskCreate((void*)float_test, "tsp", 100, NULL, 5, NULL);

the program can run normally.

In addition, I tested whether similar codes in the bare metal state return errors, and the result is that all the above conditions can operate normally.

My chip is ATSAM4E16E and the IDE is ATMEL Studio(Microchip Studio)7, and the compilation settings is

-pipe -fno-strict-aliasing -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror-implicit-function-declaration -Wpointer-arith -std=gnu99 -ffunction-sections -fdata-sections -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int -Wmain -Wparentheses -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef -Wshadow -Wbad-function-cast -Wwrite-strings -Wsign-compare -Waggregate-return -Wmissing-declarations -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked -Wredundant-decls -Wnested-externs -Wlong-long -Wunreachable-code -Wcast-align --param max-inline-insns-single=500 -mfloat-abi=softfp -mfpu=fpv4-sp-d16

I try to change the FTP settings to soft or hard but it didn’t work。However, when I use the routines in ASF, these tasks can run。

I want to know what settings I am aware of that cause this problem, so that I can avoid this error in the future when there is no routine

Does you project create a listing, like an LSS file?

Could you look up the assembler code that is produced for the crashing version of float_test()?

Btw, the expression 12 * b is probably never executed?

One big thing to note is that I think your processor has HARDWARE float, but software double support. You may need to check your configuration to sure that FreeRTOS is configured to save the hardware floating status of tasks and interrupts that use floating point.

That should happen automatically (without any specific configuration) if you use the port files from FreeRTOS/Source/Portable/[compiler]/ARM_CM4F - the 'F" being "F"loat.

What is portBYTE_ALIGNMENT set to? If you are using an ancient kernel version it may be 4, which won’t work for float instructions, but I’m pretty sure only early ARM_CM3 versions had it set to 4 (before float was an option).

Assuming the system is configured to use the M4F port and not the M3 port for “efficiency” if it has been configured not to expect the use of Floating Point.

Sorry for not responding in time,the value of portBYTE_ALIGNMENT is 8.

After I copied the FreeRTOSConfig.h file in the ASF built-in routine to my own project, this problem disappeared (but it seems that there are still some kicking problems, and I am just debugging). I guess I missed something in the manual configuration process, which caused the system to not use the FPU correctly

Sorry for not responding in time,the assembler code is :

--- E:\AtmelProject\library\library\Debug/../src/test/PIDtest.c ----------------
{
004020B0 80.b5                 push	{r7, lr}		 
004020B2 84.b0                 sub	sp, #16		 
004020B4 00.af                 add	r7, sp, #0		 
	const TickType_t delay_time = pdMS_TO_TICKS(10);
004020B6 0a.23                 movs	r3, #10		 
004020B8 bb.60                 str	r3, [r7, #8]		 
	TickType_t lastweak = xTaskGetTickCount();
004020BA 12.4b                 ldr	r3, [pc, #72]		 
004020BC 98.47                 blx	r3		 
004020BE 03.46                 mov	r3, r0		 
004020C0 3b.60                 str	r3, [r7]		 
	float a = 0.0;
004020C2 4f.f0.00.03           mov.w	r3, #0		 
004020C6 fb.60                 str	r3, [r7, #12]		 
	float b = 0.1;
004020C8 0f.4b                 ldr	r3, [pc, #60]		 
004020CA 7b.60                 str	r3, [r7, #4]		 
		if(a < 10000)
004020CC d7.ed.03.7a           vldr	s15, [r7, #12]		 
004020D0 9f.ed.0e.7a           vldr	s14, [pc, #56]		 
004020D4 f4.ee.c7.7a           vcmpe.f32	s15, s14		 
004020D8 f1.ee.10.fa           vmrs	APSR_nzcv, fpscr		 
004020DC 0b.d5                 bpl	#22		 
			a += 12 * b;
004020DE d7.ed.01.7a           vldr	s15, [r7, #4]		 
004020E2 b2.ee.08.7a           vmov.f32	s14, #1.200000e+01		 
004020E6 67.ee.87.7a           vmul.f32	s15, s15, s14		 
004020EA 97.ed.03.7a           vldr	s14, [r7, #12]		 
004020EE 77.ee.27.7a           vadd.f32	s15, s14, s15		 
004020F2 c7.ed.03.7a           vstr	s15, [r7, #12]		 
		vTaskDelayUntil(&lastweak, delay_time);
004020F6 3b.46                 mov	r3, r7		 
004020F8 b9.68                 ldr	r1, [r7, #8]		 
004020FA 18.46                 mov	r0, r3		 
004020FC 04.4b                 ldr	r3, [pc, #16]		 
004020FE 98.47                 blx	r3		 
		if(a < 10000)
00402100 e4.e7                 b	#-56		 
00402102 00.bf                 nop		 

Thank you for the listing.

004020BA 12.4b                 ldr	r3, [pc, #72]		 

Here pc equals 0x4020BA, which is a 2-byte aligned address.
It is retrieving the constant value 12, stored as 4 bytes.

But it looks like the access will fail, unless the CPU allows these unaligned access.

Can you put the debugger in assembler mode, once you’re running the function.

And what happens if you write the constants as as floating point numbers?

    if(a < (float)10000.0)
    {
        a += b * (float)12.0;
    }