Float and double cause hardfault handler on STM32F417

ophelieadveez wrote on Wednesday, April 26, 2017:

Hi,
I’m working on IAR. I’m using FreeRTOS v9.0.0 on a STM32F417 microcontroller.
I encounter problems when I declare and use float variables and double variables.
The following code causes an Hardfault Handler.

void vTestTask(void *pvParameters)
{
for(;;)
{
float test;
test = (float)(0x22);
vTaskDelay(2000U);
}
}

Some details:

  • I use heap 4.
  • MCU frequency 16MHz
  • Operating system used the systick
  • FPU is activated.
  • The heap is located in the RTOS_RESERVED region, which is located in the CCRAM (see the linker file above).
  • The hardfault doesn’t occur when I write this code outside the task.
  • The hardfault occurs when vTaskDelay function ends, so it seems it’s when the context task is restored.

Could you give me some hint please ?
Please find abovemy FreeRTOSConfig.h file and the linker file.

Regards,
Ophélie

Linker file:
/###ICF### Section handled by ICF editor, don’t touch! /
/
-Editor annotation file-
/
/
IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" /
/
-Specials-
/
define symbol ICFEDIT_intvec_start = 0x08000000;
/
-Memory Regions-/
define symbol ICFEDIT_region_ROM_start = 0x08000000;
define symbol ICFEDIT_region_ROM_end = 0x080DFFFF;
define symbol ICFEDIT_region_RAM_start = 0x20000000;
define symbol ICFEDIT_region_RAM_end = 0x2001FAFF;
define symbol ICFEDIT_region_CCMRAM_start = 0x10000000;
define symbol ICFEDIT_region_CCMRAM_end = 0x1000FFFF;
/
-Sizes-/
define symbol ICFEDIT_size_cstack = 0x500;
define symbol ICFEDIT_size_heap = 0x00;
/
*** End of ICF editor section. ###ICF###*/

define memory mem with size = 4G;
define region ROM_region = mem:[from ICFEDIT_region_ROM_start to ICFEDIT_region_ROM_end];
define region RAM_region = mem:[from ICFEDIT_region_RAM_start to ICFEDIT_region_RAM_end];
define region CCMRAM_region = mem:[from ICFEDIT_region_CCMRAM_start to ICFEDIT_region_CCMRAM_end];

define block CSTACK with alignment = 8, size = ICFEDIT_size_cstack { };
define block HEAP with alignment = 8, size = ICFEDIT_size_heap { };

initialize by copy { readwrite };
do not initialize { section .noinit };

place at address mem:ICFEDIT_intvec_start { readonly section .intvec };

place in ROM_region { readonly };
place in CCMRAM_region { readwrite data section RTOS_RESERVED_RAM };
place in RAM_region { readwrite, block CSTACK, block HEAP};

FreeRTOSCongig.h:

#ifdef __ICCARM__
#include "system_stm32f4xx.h"
extern void assert_failed(uint8_t* file, uint32_t line); /* Function prototype defined in errorUtils.h */
#endif

#define configUSE_PREEMPTION                          1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION       1
#define configUSE_TICKLESS_IDLE                       1
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP         5
#define configCPU_CLOCK_HZ                            SystemCoreClock
#define configTICK_RATE_HZ                            100
#ifdef NDEBUG
/* TODO : remove NDEBUG once we have real board : if we remove it we lost debug, but with right SWD connection it should work */
#define configSYSTICK_CLOCK_HZ                        SystemCoreClock/8
#endif
#define configMAX_PRIORITIES                          10
#define configMINIMAL_STACK_SIZE                      128
#define configMAX_TASK_NAME_LEN                       16
#define configUSE_16_BIT_TICKS                        0
#define configIDLE_SHOULD_YIELD                       1
#define configUSE_TASK_NOTIFICATIONS                  1
#define configUSE_MUTEXES                             1
#define configUSE_RECURSIVE_MUTEXES                   0
#define configUSE_COUNTING_SEMAPHORES                 1
#define configUSE_ALTERNATIVE_API                     0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE                     40
#define configUSE_QUEUE_SETS                          1
#define configUSE_TIME_SLICING                        0
#define configUSE_NEWLIB_REENTRANT                    0
#define configENABLE_BACKWARD_COMPATIBILITY           1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS       5
#define configUSE_APPLICATION_TASK_TAG	              0

/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION               0
#define configSUPPORT_DYNAMIC_ALLOCATION              1
#define configTOTAL_HEAP_SIZE                         (17 * 1024)
#define configAPPLICATION_ALLOCATED_HEAP              1

/* Hook function related definitions. */
#define configUSE_IDLE_HOOK                           0
#define configUSE_TICK_HOOK                           0
#ifndef NDEBUG
#define configCHECK_FOR_STACK_OVERFLOW	              2
#else
#define configCHECK_FOR_STACK_OVERFLOW	              0
#endif
#define configUSE_MALLOC_FAILED_HOOK                  0
#define configUSE_DAEMON_TASK_STARTUP_HOOK            0

/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS                 0
#define configUSE_TRACE_FACILITY                      0
#define configUSE_STATS_FORMATTING_FUNCTIONS          0

/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES                         0
#define configMAX_CO_ROUTINE_PRIORITIES               2

/* Software timer related definitions. */
#define configUSE_TIMERS                              1
#define configTIMER_TASK_PRIORITY                     5
#define configTIMER_QUEUE_LENGTH                      5
#define configTIMER_TASK_STACK_DEPTH                  configMINIMAL_STACK_SIZE

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			  15

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5

/* Interrupt nesting behaviour configuration. */
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS       		                    __NVIC_PRIO_BITS
#else
#define configPRIO_BITS       		                    4 /* 15 priority levels - __NVIC_PRIO_BITS value is 4 */
#endif
#define configKERNEL_INTERRUPT_PRIORITY               ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY          ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/* Define to trap errors during development. */
#define configASSERT( x ) if( ( x ) == 0 ) { assert_failed(__FILE__, __LINE__); }

/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet                      1
#define INCLUDE_uxTaskPriorityGet                     1
#define INCLUDE_vTaskDelete                           1
#define INCLUDE_vTaskSuspend                          1
#define INCLUDE_xResumeFromISR                        1
#define INCLUDE_vTaskDelayUntil                       1
#define INCLUDE_vTaskDelay                            1
#define INCLUDE_xTaskGetSchedulerState                1
#define INCLUDE_xTaskGetCurrentTaskHandle             1
#define INCLUDE_uxTaskGetStackHighWaterMark           0
#define INCLUDE_xTaskGetIdleTaskHandle                0
#define INCLUDE_eTaskGetState                         0
#define INCLUDE_xEventGroupSetBitFromISR              1
#define INCLUDE_xTimerPendFunctionCall                0
#define INCLUDE_xTaskAbortDelay                       0
#define INCLUDE_xTaskGetHandle                        0
#define INCLUDE_xTaskResumeFromISR                    1

rtel wrote on Wednesday, April 26, 2017:

Thanks for providing so much detail. In this case there are two things
that will effect how floating point variables are handled, first is the
port are using and second is the compiler’s command line (where the MCU
to build for and the floating point unit the MCU has must be specified).
Can you please ensure you are using the code from the
FreeRTOS/Source/portable/[compiler]/ARM_CM4F directory and not the
ARM_CM3 directory, and also show the command line you are using.

ophelieadveez wrote on Wednesday, April 26, 2017:

We are using the code from the ARM_CM4F directory.
We work on IAR so we don’t use command line. We set VFPv4 (FPU) on the project settings.
Floating point variables were working with the FreeRTOS version 8.3.2.

rtel wrote on Wednesday, April 26, 2017:

Put a break point on the first line of the function that implements the
task - before anything has been pushed onto the stack - normally putting
a break point on the opening bracket ‘{’ does the trick (you can view
the asm code when the break point has been it to ensure the stack has
not been modified) - then let me know the value of the stack pointer.

ophelieadveez wrote on Thursday, April 27, 2017:

Please find attached a view from IAR. My task is LoRaManagerTask and you can see the start of stack and the top of stack. Is the stack of a task filled from the top to the start ?
I realize these addresses were 4 bytes aligned. It might be a problem in my case.

ophelieadveez wrote on Tuesday, May 02, 2017:

Any news ?

rtel wrote on Tuesday, May 02, 2017:

Sorry - didn’t realise you had posted again.

Unfortunately the screen shot does not provide the information required as it shows the top of the stack at the time the screen shot was taken. I need to see the stack pointer when it enters the task function, before the stack pointer has been moved to accomodate any stack used by the task itself.

ophelieadveez wrote on Thursday, May 04, 2017:

Which variable should I study to get the stack pointer value ?

rtel wrote on Thursday, May 04, 2017:

You need to view the stack pointer register in the debugger.

Put a break point on the opening bracket of a task function, as below:

void MyTask( void *pvParameters )
{ // << Put the break point here
int32_t MyVariable;

When the break point is hit open the registers view in IAR and tell me
the value of R13.

ophelieadveez wrote on Friday, May 05, 2017:

The value of R13 is 0x20000EB8.

rtel wrote on Friday, May 05, 2017:

That value is as it should be, divisible by 8, so I’m afraid I don’t
know why the floats are not working, but it doesn’t seem to be related
to the code executing in a task.

maxicor88 wrote on Tuesday, May 09, 2017:

Hello, I am Maximiliano, I am having the same issue as Tlemsani Ophélie. Is any news on this. I checked the stack pointer an is divisible by 8.

My project is based on stm32f334, also a cortexm4

maxicor88 wrote on Tuesday, May 09, 2017:

Well, I think I got my problem, I double checked if my compiler was understanding I wanted to use the fpu unit, and found out it was one flag missing, in my case was “-mfpu=fpv4-sp-d16”

I hope it also solves your project.

Regards

ophelieadveez wrote on Tuesday, May 09, 2017:

Hello Maximiliano. I have already activated VFPv4 on my IAR project. I have attached a view of IAR.
Is it the same as the flag you are talking about ?

ophelieadveez wrote on Wednesday, May 10, 2017:

And where did you add the missing flag ?

ophelieadveez wrote on Wednesday, May 10, 2017:

I added the flag but I still have the problem.
I have tried on another IAR project. The error is the same.
I have tried the same code on the last IAR version (32Kbyte Kickstart, ARM 8.11.1) with the last version of the compiler but I still have an hardfault handler.
Do you have a workspace example on IAR working on a Cortex M4?

rtel wrote on Wednesday, May 10, 2017:

Are you actually enabling the floating point unit? The first post in
this thread said is FPU was active, but it is worth double checking. I
have used the floating point unit extensively in all our testing and the
only problem I have ever had was when sprintf()'ing a floating point
value when the stack was misaligned (4-byte instead of 8-byte).

ophelieadveez wrote on Wednesday, May 10, 2017:

Yes I have enabled the floating point unit.
We have used FreeRTOS for 4 years. Floating point unit were working on FreeRTOS version 8.2.0 and when we decided to use FreeRTOS version 9.0.0 we had this problem.
Do you have a workspace example on IAR working on a Cortex M4? I can also send you my IAR worspace.

rtel wrote on Wednesday, May 10, 2017:

Probably the closest for you as its using an ST part, albeit an M7, is
in the following directory (same as the M4F port barring a silicon bug
fix unrelated to the FPU):
FreeRTOS/Demo/CORTEX_M7_STM32F7_STM32756G-EVAL_IAR_Keil

There are non ST IAR M4F projects in the following directories:

FreeRTOS/demo/CORTEX_M4F_Infineon_XMC4000_IAR
FreeRTOS/demo/CORTEX_M4F_MSP432_LaunchPad_IAR_CCS_Keil

and probably others.

All of these test the floating point unit.

ophelieadveez wrote on Thursday, May 11, 2017:

Hi,

I found the root cause but I don’t really get it. The problem is linked with the xPortPendSVHandler. If I specify in startup_stm32f417xx.s that I want to use xPortPendSVHandler instead of PendSV_Handler, everything works correclty. But if I want to use instead PendSV_Handler and call xPortPendSVHandler inside the handler (that’s what I was doing) the programm crashes. I found there http://www.freertos.org/FreeRTOS_Support_Forum_Archive/February_2012/freertos_STM32F2_hard_fault_5015439.html that we can’t do that way for PendSV_Handler, but can you explain why ?
I was using this method because I want to have special treatment in SysTick_Handler (in addition with calling xPortSysTickHandler) so to have an unified way to handle things I did it for the 3 handlers (SysTick_Handler, PendSV_Handler and SVC_Handler).

Thanks,