mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-10 18:24:11 +01:00
OP-423 Step-1: split system stack and implement water mark for IRQstack:
- use IRQStack for ISRs (at begening of SRAM) (let's call it the irq stack) - use end of heap for stack needed during initialization (let's call it the init stack). - the systemStats in GCS indicate the remaining bytes in the IRQ stack (this is realy usefull to monitor our (nested) IRQs. This is the base ground to provide as much memory as possible available at task creation time. Next step is to re-organize the initialization in order to move all the init out of the thread's stacks onto the init stack. This will provide as much memory as possible available at task creation time. Basically the stack during initialization will be destroyed once the scheduler starts and dynamic alloc are made (since the init stack is at the end of the heap). We will need to make sure we don't clobber the heap during initialization otherwise this will lead to stack corruption.
This commit is contained in:
parent
9c6f2e0aea
commit
7598e898fa
@ -71,6 +71,10 @@ configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
|
|||||||
NVIC value of 255. */
|
NVIC value of 255. */
|
||||||
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
|
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
|
||||||
|
|
||||||
|
#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
|
||||||
|
#define CHECK_IRQ_STACK
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
@ -87,6 +87,8 @@
|
|||||||
/* Alarm Thresholds */
|
/* Alarm Thresholds */
|
||||||
#define HEAP_LIMIT_WARNING 350
|
#define HEAP_LIMIT_WARNING 350
|
||||||
#define HEAP_LIMIT_CRITICAL 250
|
#define HEAP_LIMIT_CRITICAL 250
|
||||||
|
#define IRQSTACK_LIMIT_WARNING 150
|
||||||
|
#define IRQSTACK_LIMIT_CRITICAL 80
|
||||||
#define CPULOAD_LIMIT_WARNING 80
|
#define CPULOAD_LIMIT_WARNING 80
|
||||||
#define CPULOAD_LIMIT_CRITICAL 95
|
#define CPULOAD_LIMIT_CRITICAL 95
|
||||||
|
|
||||||
|
@ -260,6 +260,48 @@ static void updateWDGstats()
|
|||||||
WatchdogStatusSet(&watchdogStatus);
|
WatchdogStatusSet(&watchdogStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called periodically to update the system stats
|
||||||
|
*/
|
||||||
|
static uint16_t GetFreeIrqStackSize(void)
|
||||||
|
{
|
||||||
|
uint32_t i = 0x200;
|
||||||
|
|
||||||
|
#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
|
||||||
|
extern uint32_t _irq_stack_top;
|
||||||
|
extern uint32_t _irq_stack_end;
|
||||||
|
uint32_t pattern = 0x0000A5A5;
|
||||||
|
uint32_t *ptr = &_irq_stack_end;
|
||||||
|
|
||||||
|
#if 1 /* the ugly way accurate but takes more time, useful for debugging */
|
||||||
|
uint32_t stack_size = (((uint32_t)&_irq_stack_top - (uint32_t)&_irq_stack_end) & ~3 ) / 4;
|
||||||
|
|
||||||
|
for (i=0; i< stack_size; i++)
|
||||||
|
{
|
||||||
|
if (ptr[i] != pattern)
|
||||||
|
{
|
||||||
|
i=i*4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* faster way but not accurate */
|
||||||
|
if (*(volatile uint32_t *)((uint32_t)ptr + IRQSTACK_LIMIT_CRITICAL) != pattern)
|
||||||
|
{
|
||||||
|
i = IRQSTACK_LIMIT_CRITICAL - 1;
|
||||||
|
}
|
||||||
|
else if (*(volatile uint32_t *)((uint32_t)ptr + IRQSTACK_LIMIT_WARNING) != pattern)
|
||||||
|
{
|
||||||
|
i = IRQSTACK_LIMIT_WARNING - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = IRQSTACK_LIMIT_WARNING;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called periodically to update the system stats
|
* Called periodically to update the system stats
|
||||||
*/
|
*/
|
||||||
@ -278,6 +320,9 @@ static void updateStats()
|
|||||||
stats.HeapRemaining = xPortGetFreeHeapSize();
|
stats.HeapRemaining = xPortGetFreeHeapSize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Get Irq stack status
|
||||||
|
stats.IRQStackRemaining = GetFreeIrqStackSize();
|
||||||
|
|
||||||
// When idleCounterClear was not reset by the idle-task, it means the idle-task did not run
|
// When idleCounterClear was not reset by the idle-task, it means the idle-task did not run
|
||||||
if (idleCounterClear) {
|
if (idleCounterClear) {
|
||||||
idleCounter = 0;
|
idleCounter = 0;
|
||||||
@ -320,6 +365,17 @@ static void updateSystemAlarms()
|
|||||||
AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY);
|
AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
|
||||||
|
// Check IRQ stack
|
||||||
|
if (stats.IRQStackRemaining < IRQSTACK_LIMIT_CRITICAL) {
|
||||||
|
AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL);
|
||||||
|
} else if (stats.IRQStackRemaining < IRQSTACK_LIMIT_WARNING) {
|
||||||
|
AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING);
|
||||||
|
} else {
|
||||||
|
AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check CPU load
|
// Check CPU load
|
||||||
if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) {
|
if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) {
|
||||||
AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL);
|
AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL);
|
||||||
|
@ -81,7 +81,7 @@ static union xRTOS_HEAP
|
|||||||
volatile unsigned long ulDummy;
|
volatile unsigned long ulDummy;
|
||||||
#endif
|
#endif
|
||||||
unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
|
unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||||
} xHeap;
|
} xHeap __attribute__ ((section (".heap")));
|
||||||
|
|
||||||
static size_t xNextFreeByte = ( size_t ) 0;
|
static size_t xNextFreeByte = ( size_t ) 0;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
/* This is the size of the stack for early init and for all FreeRTOS IRQs */
|
||||||
|
_irq_stack_size = 0x180;
|
||||||
|
|
||||||
/* Stub out these functions since we don't use them anyway */
|
/* Stub out these functions since we don't use them anyway */
|
||||||
PROVIDE ( vPortSVCHandler = 0 ) ;
|
PROVIDE ( vPortSVCHandler = 0 ) ;
|
||||||
PROVIDE ( xPortPendSVHandler = 0 ) ;
|
PROVIDE ( xPortPendSVHandler = 0 ) ;
|
||||||
@ -43,6 +46,23 @@ SECTIONS
|
|||||||
_etext = .;
|
_etext = .;
|
||||||
_sidata = .;
|
_sidata = .;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This stack is used both as the initial sp during early init as well as ultimately
|
||||||
|
* being used as the STM32's MSP (Main Stack Pointer) which is the same stack that
|
||||||
|
* is used for _all_ interrupt handlers. The end of this stack should be placed
|
||||||
|
* against the lowest address in RAM so that a stack overrun results in a hard fault
|
||||||
|
* at the first access beyond the end of the stack.
|
||||||
|
*/
|
||||||
|
.irq_stack :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_irq_stack_end = . ;
|
||||||
|
. = . + _irq_stack_size ;
|
||||||
|
. = ALIGN(4);
|
||||||
|
_irq_stack_top = . - 4 ;
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > SRAM
|
||||||
|
|
||||||
.data : AT (_etext)
|
.data : AT (_etext)
|
||||||
{
|
{
|
||||||
_sdata = .;
|
_sdata = .;
|
||||||
@ -51,6 +71,8 @@ SECTIONS
|
|||||||
_edata = . ;
|
_edata = . ;
|
||||||
} > SRAM
|
} > SRAM
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* .bss section which is used for uninitialized data */
|
/* .bss section which is used for uninitialized data */
|
||||||
.bss (NOLOAD) :
|
.bss (NOLOAD) :
|
||||||
{
|
{
|
||||||
@ -61,6 +83,16 @@ SECTIONS
|
|||||||
_ebss = . ;
|
_ebss = . ;
|
||||||
} > SRAM
|
} > SRAM
|
||||||
|
|
||||||
|
.heap (NOLOAD) :
|
||||||
|
{
|
||||||
|
_sheap = . ;
|
||||||
|
*(.heap)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_eheap = . ;
|
||||||
|
_init_stack_top = . - 4 ;
|
||||||
|
. = ALIGN(4);
|
||||||
|
} > SRAM
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_end = . ;
|
_end = . ;
|
||||||
|
|
||||||
|
@ -61,6 +61,40 @@ defined in linker script */
|
|||||||
.type Reset_Handler, %function
|
.type Reset_Handler, %function
|
||||||
Reset_Handler:
|
Reset_Handler:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From COrtex-M3 reference manual:
|
||||||
|
* - Handler IRQ always use SP_main
|
||||||
|
* - Process use SP_main or SP_process
|
||||||
|
* Here, we will use beginning of SRAM for IRQ (SP_main)
|
||||||
|
* and end of heap for initialization (SP_process).
|
||||||
|
* Once the schedule starts, all threads will use their own stack
|
||||||
|
* from heap and NOBOBY should use SP_process again.
|
||||||
|
*/
|
||||||
|
/* Do set/reset the stack pointers */
|
||||||
|
LDR r0, =_irq_stack_top
|
||||||
|
MSR msp, r0
|
||||||
|
LDR r0, =_init_stack_top
|
||||||
|
MSR psp, r0
|
||||||
|
/* DO
|
||||||
|
* - stay in thread process mode
|
||||||
|
* - stay in privilege level
|
||||||
|
* - use process stack
|
||||||
|
*/
|
||||||
|
add r0, #2
|
||||||
|
MSR control, r0
|
||||||
|
ISB
|
||||||
|
/* Fill IRQ stack for watermark monitoring */
|
||||||
|
ldr r2, =_irq_stack_end
|
||||||
|
b LoopFillIRQStack
|
||||||
|
|
||||||
|
FillIRQStack:
|
||||||
|
movw r3, #0xA5A5
|
||||||
|
str r3, [r2], #4
|
||||||
|
|
||||||
|
LoopFillIRQStack:
|
||||||
|
ldr r3, = _irq_stack_top
|
||||||
|
cmp r2, r3
|
||||||
|
bcc FillIRQStack
|
||||||
/* Copy the data segment initializers from flash to SRAM */
|
/* Copy the data segment initializers from flash to SRAM */
|
||||||
movs r1, #0
|
movs r1, #0
|
||||||
b LoopCopyDataInit
|
b LoopCopyDataInit
|
||||||
@ -119,7 +153,7 @@ Infinite_Loop:
|
|||||||
|
|
||||||
|
|
||||||
g_pfnVectors:
|
g_pfnVectors:
|
||||||
.word _estack
|
.word _irq_stack_top /*_irq_stack_top */
|
||||||
.word Reset_Handler
|
.word Reset_Handler
|
||||||
.word NMI_Handler
|
.word NMI_Handler
|
||||||
.word HardFault_Handler
|
.word HardFault_Handler
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<description>CPU and memory usage from OpenPilot computer. </description>
|
<description>CPU and memory usage from OpenPilot computer. </description>
|
||||||
<field name="FlightTime" units="ms" type="uint32" elements="1"/>
|
<field name="FlightTime" units="ms" type="uint32" elements="1"/>
|
||||||
<field name="HeapRemaining" units="bytes" type="uint16" elements="1"/>
|
<field name="HeapRemaining" units="bytes" type="uint16" elements="1"/>
|
||||||
|
<field name="IRQStackRemaining" units="bytes" type="uint16" elements="1"/>
|
||||||
<field name="CPULoad" units="%" type="uint8" elements="1"/>
|
<field name="CPULoad" units="%" type="uint8" elements="1"/>
|
||||||
<field name="CPUTemp" units="C" type="int8" elements="1"/>
|
<field name="CPUTemp" units="C" type="int8" elements="1"/>
|
||||||
<access gcs="readwrite" flight="readwrite"/>
|
<access gcs="readwrite" flight="readwrite"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user