1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-01 09:24:10 +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:
Mathieu Rondonneau 2011-06-12 20:23:00 -07:00
parent 9c6f2e0aea
commit 7598e898fa
7 changed files with 132 additions and 3 deletions

View File

@ -71,6 +71,10 @@ configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32)
#define CHECK_IRQ_STACK
#endif
/**
* @}
*/

View File

@ -87,6 +87,8 @@
/* Alarm Thresholds */
#define HEAP_LIMIT_WARNING 350
#define HEAP_LIMIT_CRITICAL 250
#define IRQSTACK_LIMIT_WARNING 150
#define IRQSTACK_LIMIT_CRITICAL 80
#define CPULOAD_LIMIT_WARNING 80
#define CPULOAD_LIMIT_CRITICAL 95

View File

@ -118,7 +118,7 @@ static void systemTask(void *parameters)
ObjectPersistenceConnectCallback(&objectUpdatedCb);
// Main system loop
while (1) {
while (1) {
// Update the system statistics
updateStats();
@ -260,6 +260,48 @@ static void updateWDGstats()
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
*/
@ -278,6 +320,9 @@ static void updateStats()
stats.HeapRemaining = xPortGetFreeHeapSize();
#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
if (idleCounterClear) {
idleCounter = 0;
@ -320,6 +365,17 @@ static void updateSystemAlarms()
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
if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) {
AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL);

View File

@ -81,7 +81,7 @@ static union xRTOS_HEAP
volatile unsigned long ulDummy;
#endif
unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
} xHeap;
} xHeap __attribute__ ((section (".heap")));
static size_t xNextFreeByte = ( size_t ) 0;
/*-----------------------------------------------------------*/

View File

@ -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 */
PROVIDE ( vPortSVCHandler = 0 ) ;
PROVIDE ( xPortPendSVHandler = 0 ) ;
@ -43,6 +46,23 @@ SECTIONS
_etext = .;
_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)
{
_sdata = .;
@ -51,6 +71,8 @@ SECTIONS
_edata = . ;
} > SRAM
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
@ -60,6 +82,16 @@ SECTIONS
. = ALIGN(4);
_ebss = . ;
} > SRAM
.heap (NOLOAD) :
{
_sheap = . ;
*(.heap)
. = ALIGN(4);
_eheap = . ;
_init_stack_top = . - 4 ;
. = ALIGN(4);
} > SRAM
. = ALIGN(4);
_end = . ;

View File

@ -61,6 +61,40 @@ defined in linker script */
.type Reset_Handler, %function
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 */
movs r1, #0
b LoopCopyDataInit
@ -119,7 +153,7 @@ Infinite_Loop:
g_pfnVectors:
.word _estack
.word _irq_stack_top /*_irq_stack_top */
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler

View File

@ -3,6 +3,7 @@
<description>CPU and memory usage from OpenPilot computer. </description>
<field name="FlightTime" units="ms" type="uint32" 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="CPUTemp" units="C" type="int8" elements="1"/>
<access gcs="readwrite" flight="readwrite"/>