diff --git a/Makefile b/Makefile index 041fb2702..e5c2cf45f 100644 --- a/Makefile +++ b/Makefile @@ -396,6 +396,7 @@ COMMON_SRC = \ drivers/serial.c \ drivers/serial_uart.c \ drivers/sound_beeper.c \ + drivers/stack_check.c \ drivers/system.c \ drivers/timer.c \ drivers/io_pca9685.c \ diff --git a/src/main/drivers/stack_check.c b/src/main/drivers/stack_check.c new file mode 100644 index 000000000..fed81d177 --- /dev/null +++ b/src/main/drivers/stack_check.c @@ -0,0 +1,64 @@ +/* + * stack_check.c + * + * Created on: 23 Aug 2016 + * Author: martinbudden + */ + +#include +#include +#include + +#include "platform.h" + +#ifdef STACK_CHECK + +#include "build/debug.h" + +#define STACK_FILL_CHAR 0xa5 + +extern char _estack; // end of stack, declared in .LD file +extern char _Min_Stack_Size; // declared in .LD file + +/* + * The ARM processor uses a full descending stack. This means the stack pointer holds the address + * of the last stacked item in memory. When the processor pushes a new item onto the stack, + * it decrements the stack pointer and then writes the item to the new memory location. + * + * + * RAM layout is generally as below, although some targets vary + * + * F1 Boards + * RAM is origin 0x20000000 length 20K that is: + * 0x20000000 to 0x20005000 + * + * F3 Boards + * RAM is origin 0x20000000 length 40K that is: + * 0x20000000 to 0x2000a000 + * + * F4 Boards + * RAM is origin 0x20000000 length 128K that is: + * 0x20000000 to 0x20020000 + * + */ +void taskStackCheck(void) +{ + char * const stackHighMem = &_estack; + const uint32_t stackSize = (uint32_t)&_Min_Stack_Size; + char * const stackLowMem = stackHighMem - stackSize; + const char * const stackCurrent = (char *)&stackLowMem; + + char *p; + for (p = stackLowMem; p < stackCurrent; ++p) { + if (*p != STACK_FILL_CHAR) { + break; + } + } +#ifdef DEBUG_STACK + debug[0] = (uint32_t)stackHighMem & 0xffff; + debug[1] = (uint32_t)stackLowMem & 0xffff; + debug[2] = (uint32_t)stackCurrent & 0xffff; + debug[3] = (uint32_t)p & 0xffff; // watermark +#endif +} +#endif diff --git a/src/main/main.c b/src/main/main.c index 7c163c5a0..be87fc01f 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -652,6 +652,9 @@ int main(void) #ifdef LED_STRIP setTaskEnabled(TASK_LEDSTRIP, feature(FEATURE_LED_STRIP)); #endif +#ifdef STACK_CHECK + setTaskEnabled(TASK_STACK_CHECK, true); +#endif #ifdef USE_PMW_SERVO_DRIVER setTaskEnabled(TASK_PWMDRIVER, feature(FEATURE_PWM_SERVO_DRIVER)); diff --git a/src/main/scheduler/scheduler.h b/src/main/scheduler/scheduler.h index 5c54e8a06..8183f3119 100755 --- a/src/main/scheduler/scheduler.h +++ b/src/main/scheduler/scheduler.h @@ -71,6 +71,9 @@ typedef enum { #ifdef USE_PMW_SERVO_DRIVER TASK_PWMDRIVER, #endif +#ifdef STACK_CHECK + TASK_STACK_CHECK, +#endif /* Count of real tasks */ TASK_COUNT, diff --git a/src/main/scheduler/scheduler_tasks.c b/src/main/scheduler/scheduler_tasks.c index 8b4475347..c277e6002 100755 --- a/src/main/scheduler/scheduler_tasks.c +++ b/src/main/scheduler/scheduler_tasks.c @@ -139,4 +139,12 @@ cfTask_t cfTasks[TASK_COUNT] = { }, #endif +#ifdef STACK_CHECK + [TASK_STACK_CHECK] = { + .taskName = "STACKCHECK", + .taskFunc = taskStackCheck, + .desiredPeriod = 1000000 / 10, // 10 Hz + .staticPriority = TASK_PRIORITY_IDLE, + }, +#endif }; diff --git a/src/main/scheduler/scheduler_tasks.h b/src/main/scheduler/scheduler_tasks.h index 4c957977d..a8f8e30c3 100644 --- a/src/main/scheduler/scheduler_tasks.h +++ b/src/main/scheduler/scheduler_tasks.h @@ -36,3 +36,4 @@ void taskSystem(void); #ifdef USE_PMW_SERVO_DRIVER void taskSyncPwmDriver(void); #endif +void taskStackCheck(void); diff --git a/src/main/target/CJMCU/target.h b/src/main/target/CJMCU/target.h index 4fab126bb..e02b5de6a 100644 --- a/src/main/target/CJMCU/target.h +++ b/src/main/target/CJMCU/target.h @@ -109,6 +109,9 @@ #undef BLACKBOX #endif +#define STACK_CHECK +#define DEBUG_STACK + // Number of available PWM outputs #define MAX_PWM_OUTPUT_PORTS 4 diff --git a/src/main/target/link/stm32_flash.ld b/src/main/target/link/stm32_flash.ld index c38f3d263..b4a832318 100644 --- a/src/main/target/link/stm32_flash.ld +++ b/src/main/target/link/stm32_flash.ld @@ -110,6 +110,9 @@ SECTIONS } >RAM /* User_heap_stack section, used to check that there is enough RAM left */ + _heap_stack_end = ORIGIN(RAM)+LENGTH(RAM) - 8; /* 8 bytes to allow for alignment */ + _heap_stack_begin = _heap_stack_end - _Min_Stack_Size - _Min_Heap_Size; + . = _heap_stack_begin; ._user_heap_stack : { . = ALIGN(4); @@ -118,7 +121,7 @@ SECTIONS . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(4); - } >RAM + } >RAM = 0xa5 /* MEMORY_bank1 section, code must be located here explicitly */ /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */