Hello,
I am working on a C++ project using a Microchip SAMv71 (Cortex M7) and I have issues with some stack corruption when I use float.
During my development I encountered INVSTATE or IACCVIOL exceptions, and found that come from stack corruption as the return address was set to 0xA5A5A5A4 (the default stack pattern initialisation).
I identify the task that triggered the exception and it was using floating point calculation. For test, I implemented one of the math task found in the demo application which use float computation. I put it at high priority task, and each time it triggers the exception (no other tasks are running at this time).
The FPU is enabled at start-up, and the task code is running well on main context (either before start scheduler or during tick hook).
I share you the registers value when it entering in the memory fault exception, the task handle structure values and the stack content in memory.
Registers:
R0 0x00000001
R1 0x20402144
R2 0x10000000
R3 0xA5A5A5A5
R4 0xA5A5A5A5
R5 0xA5A5A5A5
R6 0x00400000
R7 0x00000064
R8 0xA5A5A5A5
R9 0xA5A5A5A5
R10 0xA5A5A5A5
R11 0xA5A5A5A5
R12 0x00400000
SP 0x20404E18
LR 0xFFFFFFFD
PC 0x00400308
xPSR 0x61000004
MSP 0x20404E18
PSP 0x2040A9E0
Stack memory
2040A860 00000208 FFFFFFFC A5A5A5A5 A5A5A5A5
2040A870 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A880 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A890 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A8A0 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A8B0 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A8C0 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A8D0 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A8E0 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A8F0 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A900 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A910 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A920 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A930 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A940 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A950 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A960 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A970 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A980 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A990 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040A9A0 A5A5A5A5 A5A5A5A5 A5A5A5A5 00000001
2040A9B0 2040AA4C 00400000 00000064 A5A5A5A5
2040A9C0 A5A5A5A5 A5A5A5A5 A5A5A5A5 004003B9
2040A9D0 00000000 20402144 10000000 E000E000
2040A9E0 00000001 20402144 10000000 A5A5A5A5
2040A9F0 00400000 004039C5 A5A5A5A4 61000000
2040AA00 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040AA10 A5A5A5A5 A5A5A5A5 A5A5A5A5 A5A5A5A5
2040AA20 00000064 00000000 00403899 00000001
2040AA30 2040AA4C 00403A8B 004039F9 20402120
2040AA40 20402134 0040D1E1 A5A5A5A5 00000064
2040AA50 A5A5A5A5 0040D25B A5A5A5A5 00404511
2040AA60 A5A5A5A5 A5A5A5A5 DEADBEEF DEADBEEF
stack handle = {
...
.pxStack = 0x2040A868,
.pxTopOfStack = 0x2040A9AC,
.ucStaticallyAllocated =2,
.uxBasePriority = 7,
.uxPriority = 7,
...
}
I recently moved to static task creation but no big change on the behaviour. I am using newlib implementation and passed to heap 3 (instead of 4) to use the same heap for all the system.
I checked for stack overflow but it doesn’t seem to be that. I filled the heap with DEADBEEF pattern, check the stack memory before/after task creation, and after the exception. I saw that the PSP and pxTopOfStack is not up-to-date but I supposed that it come from the ISR branching.
I followed the ARM FreeRTOS guideline, I try the solutions from this forums with similar issues.
I am trying the reproduce my bugs on the evaluation board from the demo application in order to share more things with you. By the way, I took the demo code from recent Github hash, and the minimal stack size configured is not enough for the “Notified” task (stack overflow hook is triggered).
Here is my FreeRTOS configuration:
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 3 // 7 priority levels.
#endif // __NVIC_PRIO_BITS
#define configMAX_PRIORITIES 8
#define configUSE_TICKLESS_IDLE 0
#define configCPU_CLOCK_HZ 300000000
#define configSYSTICK_CLOCK_HZ 150000000
#define configTICK_RATE_HZ 1000
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configSTACK_DEPTH_TYPE uint32_t
#define configMINIMAL_STACK_SIZE 128
#define configMAX_TASK_NAME_LEN 32
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0
#define configQUEUE_REGISTRY_SIZE 10
#define configUSE_QUEUE_SETS 1
#define configUSE_TIME_SLICING 1
#define configUSE_NEWLIB_REENTRANT 1
#define configENABLE_BACKWARD_COMPATIBILITY 0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
#define configUSE_MINI_LIST_ITEM 1
#define configMESSAGE_BUFFER_LENGTH_TYPE uint16_t
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE 32768
#define configHEAP_CLEAR_MEMORY_ON_FREE 1
#define configAPPLICATION_ALLOCATED_HEAP 1
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configUSE_SB_COMPLETED_CALLBACK 0
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 6
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH (2 * configMINIMAL_STACK_SIZE)
#define configKERNEL_INTERRUPT_PRIORITY (\
7 << (8 - configPRIO_BITS) \
)
#define configMAX_API_CALL_INTERRUPT_PRIORITY (\
4 << (8 - configPRIO_BITS) \
)
#define configMAX_SYSCALL_INTERRUPT_PRIORITY configMAX_API_CALL_INTERRUPT_PRIORITY
#define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); for(;;); }
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
#define configTOTAL_MPU_REGIONS 8
#define configTEX_S_C_B_FLASH 0x07ul
#define configTEX_S_C_B_SRAM 0x07ul
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1
#define configENABLE_ERRATA_837070_WORKAROUND 0
#define secureconfigMAX_SECURE_CONTEXTS 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_uxTaskGetStackHighWaterMark2 0
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_xTaskAbortDelay 1
#define INCLUDE_xTaskDelayUntil 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskResumeFromISR 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xQueueGetMutexHolder 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1
And the task code:
float d1_ = 123.4567;
float d2_ = 2345.6789;
float d3_ = -918.222;
const float expected = (d1_ + d2_) * d3_;
while (1)
{
float d1 = 123.4567;
float d2 = 2345.6789;
float d3 = -918.222;
float d4 = (d1 + d2) * d3;
if (fabs(d4 - expected) > 0.001)
// Set LED
else
// Clear LED
}