X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=FreeRTOS%2FSource%2Fportable%2FGCC%2FARM_CM0%2Fport.c;h=0ea67a50c4810c87a986d8be82cec5570e6a1bd0;hb=61e4c8bcd10d8a2d87dfda1962932c88f0c7a92f;hp=bf1d58bb6209ed9b5872c0fa8e6f9ccfe8255e73;hpb=7f682e03ddc9f629d828cb8b61033bba85d9df67;p=freertos diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c index bf1d58bb6..0ea67a50c 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c @@ -1,5 +1,6 @@ /* - FreeRTOS V7.5.1 - Copyright (C) 2013 Real Time Engineers Ltd. + FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -71,10 +72,10 @@ #include "task.h" /* Constants required to manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile unsigned long *) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile unsigned long *) 0xe000e014 ) -#define portNVIC_INT_CTRL ( ( volatile unsigned long *) 0xe000ed04 ) -#define portNVIC_SYSPRI2 ( ( volatile unsigned long *) 0xe000ed20 ) +#define portNVIC_SYSTICK_CTRL ( ( volatile uint32_t *) 0xe000e010 ) +#define portNVIC_SYSTICK_LOAD ( ( volatile uint32_t *) 0xe000e014 ) +#define portNVIC_INT_CTRL ( ( volatile uint32_t *) 0xe000ed04 ) +#define portNVIC_SYSPRI2 ( ( volatile uint32_t *) 0xe000ed20 ) #define portNVIC_SYSTICK_CLK 0x00000004 #define portNVIC_SYSTICK_INT 0x00000002 #define portNVIC_SYSTICK_ENABLE 0x00000001 @@ -86,9 +87,18 @@ /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) +/* Let the user override the pre-loading of the initial LR with the address of +prvTaskExitError() in case is messes up unwinding of the stack in the +debugger. */ +#ifdef configTASK_RETURN_ADDRESS + #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS +#else + #define portTASK_RETURN_ADDRESS prvTaskExitError +#endif + /* Each task maintains its own interrupt status in the critical nesting variable. */ -static unsigned portBASE_TYPE uxCriticalNesting = 0xaaaaaaaa; +static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; /* * Setup the timer to generate the tick interrupts. @@ -100,79 +110,90 @@ static void prvSetupTimerInterrupt( void ); */ void xPortPendSVHandler( void ) __attribute__ (( naked )); void xPortSysTickHandler( void ); -void vPortSVCHandler( void ) __attribute__ (( naked )); +void vPortSVCHandler( void ); /* * Start first task is a separate function so it can be tested in isolation. */ static void vPortStartFirstTask( void ) __attribute__ (( naked )); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* * See header file for description. */ -portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) +StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) { /* Simulate the stack frame as it would be created by a context switch interrupt. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ pxTopOfStack--; - *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ - pxTopOfStack -= 6; /* LR, R12, R3..R1 */ - *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ + *pxTopOfStack = ( StackType_t ) pxCode; /* PC */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */ + pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ + *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ pxTopOfStack -= 8; /* R11..R4. */ return pxTopOfStack; } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + void vPortSVCHandler( void ) { - __asm volatile ( - " ldr r3, pxCurrentTCBConst2 \n" /* Restore the context. */ - " ldr r1, [r3] \n" /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */ - " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */ - " add r0, r0, #16 \n" /* Move to the high registers. */ - " ldmia r0!, {r4-r7} \n" /* Pop the high registers. */ - " mov r8, r4 \n" - " mov r9, r5 \n" - " mov r10, r6 \n" - " mov r11, r7 \n" - " \n" - " msr psp, r0 \n" /* Remember the new top of stack for the task. */ - " \n" - " sub r0, r0, #32 \n" /* Go back for the low registers that are not automatically restored. */ - " ldmia r0!, {r4-r7} \n" /* Pop low registers. */ - " mov r1, r14 \n" /* OR R14 with 0x0d. */ - " movs r0, #0x0d \n" - " orr r1, r0 \n" - " bx r1 \n" - " \n" - " .align 2 \n" - "pxCurrentTCBConst2: .word pxCurrentTCB \n" - ); + /* This function is no longer used, but retained for backward + compatibility. */ } /*-----------------------------------------------------------*/ void vPortStartFirstTask( void ) { + /* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector + table offset register that can be used to locate the initial stack value. + Not all M0 parts have the application vector table at address 0. */ __asm volatile( - " movs r0, #0x00 \n" /* Locate the top of stack. */ - " ldr r0, [r0] \n" - " msr msp, r0 \n" /* Set the msp back to the start of the stack. */ - " cpsie i \n" /* Globally enable interrupts. */ - " svc 0 \n" /* System call to start first task. */ - " nop \n" - ); + " ldr r2, pxCurrentTCBConst2 \n" /* Obtain location of pxCurrentTCB. */ + " ldr r3, [r2] \n" + " ldr r0, [r3] \n" /* The first item in pxCurrentTCB is the task top of stack. */ + " add r0, #32 \n" /* Discard everything up to r0. */ + " msr psp, r0 \n" /* This is now the new top of stack to use in the task. */ + " movs r0, #2 \n" /* Switch to the psp stack. */ + " msr CONTROL, r0 \n" + " pop {r0-r5} \n" /* Pop the registers that are saved automatically. */ + " mov lr, r5 \n" /* lr is now in r5. */ + " cpsie i \n" /* The first task has its context and interrupts can be enabled. */ + " pop {pc} \n" /* Finally, pop the PC to jump to the user defined task code. */ + " \n" + " .align 2 \n" + "pxCurrentTCBConst2: .word pxCurrentTCB " + ); } /*-----------------------------------------------------------*/ /* * See header file for description. */ -portBASE_TYPE xPortStartScheduler( void ) +BaseType_t xPortStartScheduler( void ) { /* Make PendSV, CallSV and SysTick the same priroity as the kernel. */ *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; @@ -188,6 +209,12 @@ portBASE_TYPE xPortStartScheduler( void ) /* Start the first task. */ vPortStartFirstTask(); + /* Should never get here as the tasks will now be executing! Call the task + exit error function to prevent compiler warnings about a static function + not being called in the case that the application writer overrides this + functionality by defining configTASK_RETURN_ADDRESS. */ + prvTaskExitError(); + /* Should not get here! */ return 0; } @@ -195,8 +222,9 @@ portBASE_TYPE xPortStartScheduler( void ) void vPortEndScheduler( void ) { - /* It is unlikely that the CM0 port will require this function as there - is nothing to return to. */ + /* Not implemented in ports where there is nothing to return to. + Artificially force an assert. */ + configASSERT( uxCriticalNesting == 1000UL ); } /*-----------------------------------------------------------*/ @@ -223,6 +251,7 @@ void vPortEnterCritical( void ) void vPortExitCritical( void ) { + configASSERT( uxCriticalNesting ); uxCriticalNesting--; if( uxCriticalNesting == 0 ) { @@ -231,6 +260,31 @@ void vPortExitCritical( void ) } /*-----------------------------------------------------------*/ +uint32_t ulSetInterruptMaskFromISR( void ) +{ + __asm volatile( + " mrs r0, PRIMASK \n" + " cpsid i \n" + " bx lr " + ); + + /* To avoid compiler warnings. This line will never be reached. */ + return 0; +} +/*-----------------------------------------------------------*/ + +void vClearInterruptMaskFromISR( uint32_t ulMask ) +{ + __asm volatile( + " msr PRIMASK, r0 \n" + " bx lr " + ); + + /* Just to avoid compiler warning. */ + ( void ) ulMask; +} +/*-----------------------------------------------------------*/ + void xPortPendSVHandler( void ) { /* This is a naked function. */ @@ -281,9 +335,9 @@ void xPortPendSVHandler( void ) void xPortSysTickHandler( void ) { -unsigned long ulDummy; +uint32_t ulPreviousMask; - ulDummy = portSET_INTERRUPT_MASK_FROM_ISR(); + ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR(); { /* Increment the RTOS tick. */ if( xTaskIncrementTick() != pdFALSE ) @@ -292,7 +346,7 @@ unsigned long ulDummy; *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask ); } /*-----------------------------------------------------------*/