2014-07-13 03:21:04 +08:00
/*
2020-09-18 06:25:15 +08:00
* FreeRTOS Kernel V10 .4 .1
2020-02-08 04:14:50 +08:00
* Copyright ( C ) 2020 Amazon . com , Inc . or its affiliates . All Rights Reserved .
2017-11-30 00:53:26 +08:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
* the Software , and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
2017-12-19 06:54:18 +08:00
* copies or substantial portions of the Software .
2017-11-30 00:53:26 +08:00
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER
* IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
2020-08-21 05:59:28 +08:00
* https : //www.FreeRTOS.org
* https : //github.com/FreeRTOS
2017-11-30 00:53:26 +08:00
*
2020-07-08 08:42:07 +08:00
* 1 tab = = 4 spaces !
2017-11-30 00:53:26 +08:00
*/
2014-07-13 03:21:04 +08:00
/* IAR includes. */
# include <intrinsics.h>
/* Scheduler includes. */
# include "FreeRTOS.h"
# include "task.h"
# if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
2020-08-18 01:51:02 +08:00
/* Check the configuration. */
# if( configMAX_PRIORITIES > 32 )
# error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
# endif
2014-07-13 03:21:04 +08:00
# endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
2014-10-16 05:01:31 +08:00
# ifndef configSETUP_TICK_INTERRUPT
2020-08-18 01:51:02 +08:00
# error configSETUP_TICK_INTERRUPT() must be defined in FreeRTOSConfig.h to call the function that sets up the tick interrupt. A default that uses the PIT is provided in the official demo application.
2014-10-16 05:01:31 +08:00
# endif
# ifndef configCLEAR_TICK_INTERRUPT
2020-08-18 01:51:02 +08:00
# error configCLEAR_TICK_INTERRUPT must be defined in FreeRTOSConfig.h to clear which ever interrupt was used to generate the tick interrupt. A default that uses the PIT is provided in the official demo application.
2014-10-16 05:01:31 +08:00
# endif
2014-07-13 03:21:04 +08:00
/* A critical section is exited when the critical section nesting count reaches
2020-08-18 01:51:02 +08:00
this value . */
# define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
2014-07-13 03:21:04 +08:00
/* Tasks are not created with a floating point context, but can be given a
2020-08-18 01:51:02 +08:00
floating point context after they have been created . A variable is stored as
part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
does not have an FPU context , or any other value if the task does have an FPU
context . */
# define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
2014-07-13 03:21:04 +08:00
/* Constants required to setup the initial task context. */
2020-08-18 01:51:02 +08:00
# define portINITIAL_SPSR ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
# define portTHUMB_MODE_BIT ( ( StackType_t ) 0x20 )
# define portTHUMB_MODE_ADDRESS ( 0x01UL )
2014-07-13 03:21:04 +08:00
/* Masks all bits in the APSR other than the mode bits. */
2020-08-18 01:51:02 +08:00
# define portAPSR_MODE_BITS_MASK ( 0x1F )
2014-07-13 03:21:04 +08:00
/* The value of the mode bits in the APSR when the CPU is executing in user
2020-08-18 01:51:02 +08:00
mode . */
# define portAPSR_USER_MODE ( 0x10 )
2014-07-13 03:21:04 +08:00
/*-----------------------------------------------------------*/
/*
* Starts the first task executing . This function is necessarily written in
* assembly code so is implemented in portASM . s .
*/
extern void vPortRestoreTaskContext ( void ) ;
2014-07-30 05:31:04 +08:00
/*
* Used to catch tasks that attempt to return from their implementing function .
*/
static void prvTaskExitError ( void ) ;
2014-07-13 03:21:04 +08:00
/*-----------------------------------------------------------*/
/* A variable is used to keep track of the critical section nesting. This
2020-08-18 01:51:02 +08:00
variable has to be stored as part of the task context and must be initialised to
a non zero value to ensure interrupts don ' t inadvertently become unmasked before
the scheduler starts . As it is stored as part of the task context it will
automatically be set to 0 when the first task is started . */
2020-07-08 08:42:07 +08:00
volatile uint32_t ulCriticalNesting = 9999UL ;
2014-07-13 03:21:04 +08:00
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero
2020-08-18 01:51:02 +08:00
then a floating point context must be saved and restored for the task . */
2020-07-08 08:42:07 +08:00
uint32_t ulPortTaskHasFPUContext = pdFALSE ;
2014-07-13 03:21:04 +08:00
/* Set to 1 to pend a context switch from an ISR. */
2020-07-08 08:42:07 +08:00
uint32_t ulPortYieldRequired = pdFALSE ;
2014-07-13 03:21:04 +08:00
/* Counts the interrupt nesting depth. A context switch is only performed if
2020-08-18 01:51:02 +08:00
if the nesting depth is 0. */
2020-07-08 08:42:07 +08:00
uint32_t ulPortInterruptNesting = 0UL ;
2014-07-13 03:21:04 +08:00
/*-----------------------------------------------------------*/
/*
* See header file for description .
*/
2020-08-18 01:51:02 +08:00
StackType_t * pxPortInitialiseStack ( StackType_t * pxTopOfStack , TaskFunction_t pxCode , void * pvParameters )
2014-07-13 03:21:04 +08:00
{
2020-08-18 01:51:02 +08:00
/* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT ( ) macro .
The fist real value on the stack is the status register , which is set for
system mode , with interrupts enabled . A few NULLs are added first to ensure
GDB does not try decoding a non - existent return address . */
* pxTopOfStack = NULL ;
pxTopOfStack - - ;
* pxTopOfStack = NULL ;
pxTopOfStack - - ;
* pxTopOfStack = NULL ;
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) portINITIAL_SPSR ;
if ( ( ( uint32_t ) pxCode & portTHUMB_MODE_ADDRESS ) ! = 0x00UL )
{
/* The task will start in THUMB mode. */
* pxTopOfStack | = portTHUMB_MODE_BIT ;
}
pxTopOfStack - - ;
/* Next the return address, which in this case is the start of the task. */
* pxTopOfStack = ( StackType_t ) pxCode ;
pxTopOfStack - - ;
/* Next all the registers other than the stack pointer. */
* pxTopOfStack = ( StackType_t ) prvTaskExitError ; /* R14 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x12121212 ; /* R12 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x11111111 ; /* R11 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x10101010 ; /* R10 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x09090909 ; /* R9 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x08080808 ; /* R8 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x07070707 ; /* R7 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x06060606 ; /* R6 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x05050505 ; /* R5 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x04040404 ; /* R4 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x03030303 ; /* R3 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x02020202 ; /* R2 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) 0x01010101 ; /* R1 */
pxTopOfStack - - ;
* pxTopOfStack = ( StackType_t ) pvParameters ; /* R0 */
pxTopOfStack - - ;
/* The task will start with a critical nesting count of 0 as interrupts are
enabled . */
* pxTopOfStack = portNO_CRITICAL_NESTING ;
pxTopOfStack - - ;
/* The task will start without a floating point context. A task that uses
the floating point hardware must call vPortTaskUsesFPU ( ) before executing
any floating point instructions . */
* pxTopOfStack = portNO_FLOATING_POINT_CONTEXT ;
return pxTopOfStack ;
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
2014-07-30 05:31:04 +08:00
static void prvTaskExitError ( void )
{
2020-08-18 01:51:02 +08:00
/* 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 ( ulPortInterruptNesting = = ~ 0UL ) ;
portDISABLE_INTERRUPTS ( ) ;
for ( ; ; ) ;
2014-07-30 05:31:04 +08:00
}
/*-----------------------------------------------------------*/
2014-07-13 03:21:04 +08:00
BaseType_t xPortStartScheduler ( void )
{
2020-08-18 01:51:02 +08:00
uint32_t ulAPSR ;
/* Only continue if the CPU is not in User mode. The CPU must be in a
Privileged mode for the scheduler to start . */
__asm volatile ( " MRS %0, APSR " : " =r " ( ulAPSR ) ) ;
ulAPSR & = portAPSR_MODE_BITS_MASK ;
configASSERT ( ulAPSR ! = portAPSR_USER_MODE ) ;
if ( ulAPSR ! = portAPSR_USER_MODE )
{
/* Start the timer that generates the tick ISR. */
configSETUP_TICK_INTERRUPT ( ) ;
vPortRestoreTaskContext ( ) ;
}
/* Will only get here if vTaskStartScheduler() was called with the CPU in
a non - privileged mode or the binary point register was not set to its lowest
possible value . */
return 0 ;
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
void vPortEndScheduler ( void )
{
2020-08-18 01:51:02 +08:00
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert . */
configASSERT ( ulCriticalNesting = = 1000UL ) ;
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
void vPortEnterCritical ( void )
{
2020-08-18 01:51:02 +08:00
portDISABLE_INTERRUPTS ( ) ;
/* Now interrupts are disabled ulCriticalNesting can be accessed
directly . Increment ulCriticalNesting to keep a count of how many times
portENTER_CRITICAL ( ) has been called . */
ulCriticalNesting + + ;
/* This is not the interrupt safe version of the enter critical function so
assert ( ) if it is being called from an interrupt context . Only API
functions that end in " FromISR " can be used in an interrupt . Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section . */
if ( ulCriticalNesting = = 1 )
{
configASSERT ( ulPortInterruptNesting = = 0 ) ;
}
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
void vPortExitCritical ( void )
{
2020-08-18 01:51:02 +08:00
if ( ulCriticalNesting > portNO_CRITICAL_NESTING )
{
/* Decrement the nesting count as the critical section is being
exited . */
ulCriticalNesting - - ;
/* If the nesting level has reached zero then all interrupt
priorities must be re - enabled . */
if ( ulCriticalNesting = = portNO_CRITICAL_NESTING )
{
/* Critical nesting has reached zero so all interrupt priorities
should be unmasked . */
portENABLE_INTERRUPTS ( ) ;
}
}
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
void FreeRTOS_Tick_Handler ( void )
{
2020-08-18 01:51:02 +08:00
portDISABLE_INTERRUPTS ( ) ;
2014-07-13 03:21:04 +08:00
2020-08-18 01:51:02 +08:00
/* Increment the RTOS tick. */
if ( xTaskIncrementTick ( ) ! = pdFALSE )
{
ulPortYieldRequired = pdTRUE ;
}
2014-07-13 03:21:04 +08:00
2020-08-18 01:51:02 +08:00
portENABLE_INTERRUPTS ( ) ;
configCLEAR_TICK_INTERRUPT ( ) ;
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
void vPortTaskUsesFPU ( void )
{
2020-08-18 01:51:02 +08:00
uint32_t ulInitialFPSCR = 0 ;
2014-07-13 03:21:04 +08:00
2020-08-18 01:51:02 +08:00
/* A task is registering the fact that it needs an FPU context. Set the
FPU flag ( which is saved as part of the task context ) . */
ulPortTaskHasFPUContext = pdTRUE ;
2014-07-13 03:21:04 +08:00
2020-08-18 01:51:02 +08:00
/* Initialise the floating point status register. */
__asm ( " FMXR FPSCR, %0 " : : " r " ( ulInitialFPSCR ) ) ;
2014-07-13 03:21:04 +08:00
}
/*-----------------------------------------------------------*/
2020-08-18 01:51:02 +08:00