Style: redo the stuyles

This commit is contained in:
Alfred Gedeon 2020-08-12 22:46:27 -07:00 committed by alfred gedeon
parent bb8d79cd51
commit b0630a3bef
55 changed files with 10171 additions and 9890 deletions

View file

@ -26,16 +26,16 @@
*/ */
/* /*
* Changes from V1.00: Changes from V1.00:
*
+ Call to taskYIELD() from within tick ISR has been replaced by the more + Call to taskYIELD() from within tick ISR has been replaced by the more
+ efficient portSWITCH_CONTEXT(). efficient portSWITCH_CONTEXT().
+ ISR function definitions renamed to include the prv prefix. + ISR function definitions renamed to include the prv prefix.
+
+ Changes from V2.6.1 Changes from V2.6.1
+
+ Replaced the sUsingPreemption variable with the configUSE_PREEMPTION + Replaced the sUsingPreemption variable with the configUSE_PREEMPTION
+ macro to be consistent with the later ports. macro to be consistent with the later ports.
*/ */
/*----------------------------------------------------------- /*-----------------------------------------------------------
@ -68,16 +68,14 @@ static void prvSetTickFrequency( uint32_t ulTickRateHz );
static void prvExitFunction( void ); static void prvExitFunction( void );
/* The ISR used depends on whether the preemptive or cooperative scheduler /* The ISR used depends on whether the preemptive or cooperative scheduler
* is being used. */ is being used. */
#if( configUSE_PREEMPTION == 1 ) #if( configUSE_PREEMPTION == 1 )
/* Tick service routine used by the scheduler when preemptive scheduling is /* Tick service routine used by the scheduler when preemptive scheduling is
* being used. */ being used. */
static void __interrupt __far prvPreemptiveTick( void ); static void __interrupt __far prvPreemptiveTick( void );
#else #else
/* Tick service routine used by the scheduler when cooperative scheduling is /* Tick service routine used by the scheduler when cooperative scheduling is
* being used. */ being used. */
static void __interrupt __far prvNonPreemptiveTick( void ); static void __interrupt __far prvNonPreemptiveTick( void );
#endif #endif
@ -90,8 +88,8 @@ static void __interrupt __far prvYieldProcessor( void );
static BaseType_t xSchedulerRunning = pdFALSE; static BaseType_t xSchedulerRunning = pdFALSE;
/* Points to the original routine installed on the vector we use for manual /* Points to the original routine installed on the vector we use for manual
* context switches. This is then used to restore the original routine during context switches. This is then used to restore the original routine during
* prvExitFunction(). */ prvExitFunction(). */
static void ( __interrupt __far *pxOldSwitchISR )(); static void ( __interrupt __far *pxOldSwitchISR )();
/* Used to restore the original DOS context when the scheduler is ended. */ /* Used to restore the original DOS context when the scheduler is ended. */
@ -105,11 +103,11 @@ BaseType_t xPortStartScheduler( void )
/* This is called with interrupts already disabled. */ /* This is called with interrupts already disabled. */
/* Remember what was on the interrupts we are going to use /* Remember what was on the interrupts we are going to use
* so we can put them back later if required. */ so we can put them back later if required. */
pxOldSwitchISR = _dos_getvect( portSWITCH_INT_NUMBER ); pxOldSwitchISR = _dos_getvect( portSWITCH_INT_NUMBER );
/* Put our manual switch (yield) function on a known /* Put our manual switch (yield) function on a known
* vector. */ vector. */
_dos_setvect( portSWITCH_INT_NUMBER, prvYieldProcessor ); _dos_setvect( portSWITCH_INT_NUMBER, prvYieldProcessor );
#if( configUSE_PREEMPTION == 1 ) #if( configUSE_PREEMPTION == 1 )
@ -145,7 +143,7 @@ BaseType_t xPortStartScheduler( void )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The ISR used depends on whether the preemptive or cooperative scheduler /* The ISR used depends on whether the preemptive or cooperative scheduler
* is being used. */ is being used. */
#if( configUSE_PREEMPTION == 1 ) #if( configUSE_PREEMPTION == 1 )
static void __interrupt __far prvPreemptiveTick( void ) static void __interrupt __far prvPreemptiveTick( void )
{ {
@ -159,15 +157,15 @@ BaseType_t xPortStartScheduler( void )
/* Reset the PIC ready for the next time. */ /* Reset the PIC ready for the next time. */
portRESET_PIC(); portRESET_PIC();
} }
#else /* if ( configUSE_PREEMPTION == 1 ) */ #else
static void __interrupt __far prvNonPreemptiveTick( void ) static void __interrupt __far prvNonPreemptiveTick( void )
{ {
/* Same as preemptive tick, but the cooperative scheduler is being used /* Same as preemptive tick, but the cooperative scheduler is being used
* so we don't have to switch in the context of the next task. */ so we don't have to switch in the context of the next task. */
xTaskIncrementTick(); xTaskIncrementTick();
portRESET_PIC(); portRESET_PIC();
} }
#endif /* if ( configUSE_PREEMPTION == 1 ) */ #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void __interrupt __far prvYieldProcessor( void ) static void __interrupt __far prvYieldProcessor( void )
@ -180,8 +178,8 @@ static void __interrupt __far prvYieldProcessor( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Jump back to the processor state prior to starting the /* Jump back to the processor state prior to starting the
* scheduler. This means we are not going to be using a scheduler. This means we are not going to be using a
* task stack frame so the task can be deleted. */ task stack frame so the task can be deleted. */
longjmp( xJumpBuf, 1 ); longjmp( xJumpBuf, 1 );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -192,19 +190,18 @@ static void prvExitFunction( void )
uint16_t usTimer0Control; uint16_t usTimer0Control;
/* Interrupts should be disabled here anyway - but no /* Interrupts should be disabled here anyway - but no
* harm in making sure. */ harm in making sure. */
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
if( xSchedulerRunning == pdTRUE ) if( xSchedulerRunning == pdTRUE )
{ {
/* Put back the switch interrupt routines that was in place /* Put back the switch interrupt routines that was in place
* before the scheduler started. */ before the scheduler started. */
_dos_setvect( portSWITCH_INT_NUMBER, pxOldSwitchISR ); _dos_setvect( portSWITCH_INT_NUMBER, pxOldSwitchISR );
} }
/* Disable the timer used for the tick to ensure the scheduler is /* Disable the timer used for the tick to ensure the scheduler is
* not called before restoring interrupts. There was previously nothing not called before restoring interrupts. There was previously nothing
* on this timer so there is no old ISR to restore. */ on this timer so there is no old ISR to restore. */
portOUTPUT_WORD( portTIMER_1_CONTROL_REGISTER, usTimerDisable ); portOUTPUT_WORD( portTIMER_1_CONTROL_REGISTER, usTimerDisable );
/* Restart the DOS tick. */ /* Restart the DOS tick. */
@ -244,3 +241,4 @@ static void prvSetTickFrequency( uint32_t ulTickRateHz )
/*lint +e950 */ /*lint +e950 */

View file

@ -61,8 +61,7 @@ typedef unsigned short UBaseType_t;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section handling. */ /* Critical section handling. */
#define portENTER_CRITICAL() \ #define portENTER_CRITICAL() __asm{ pushf } \
__asm{ pushf } \
__asm{ cli } \ __asm{ cli } \
#define portEXIT_CRITICAL() __asm{ popf } #define portEXIT_CRITICAL() __asm{ popf }
@ -95,3 +94,4 @@ typedef unsigned short UBaseType_t;
#define portTASK_FUNCTION( vTaskFunction, vParameters ) void vTaskFunction( void *pvParameters ) #define portTASK_FUNCTION( vTaskFunction, vParameters ) void vTaskFunction( void *pvParameters )
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -26,15 +26,15 @@
*/ */
/* /*
* Changes from V2.6.1 Changes from V2.6.1
*
+ Replaced the sUsingPreemption variable with the configUSE_PREEMPTION + Replaced the sUsingPreemption variable with the configUSE_PREEMPTION
+ macro to be consistent with the later ports. macro to be consistent with the later ports.
+
+ Changes from V4.0.1 Changes from V4.0.1
+
+ Add function prvSetTickFrequencyDefault() to set the DOS tick back to + Add function prvSetTickFrequencyDefault() to set the DOS tick back to
+ its proper value when the scheduler exits. its proper value when the scheduler exits.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -61,21 +61,19 @@ static void prvSetTickFrequency( uint32_t ulTickRateHz );
static void prvExitFunction( void ); static void prvExitFunction( void );
/* Either chain to the DOS tick (which itself clears the PIC) or clear the PIC /* Either chain to the DOS tick (which itself clears the PIC) or clear the PIC
* directly. We chain to the DOS tick as close as possible to the standard DOS directly. We chain to the DOS tick as close as possible to the standard DOS
* tick rate. */ tick rate. */
static void prvPortResetPIC( void ); static void prvPortResetPIC( void );
/* The ISR used depends on whether the preemptive or cooperative /* The ISR used depends on whether the preemptive or cooperative
* scheduler is being used. */ scheduler is being used. */
#if( configUSE_PREEMPTION == 1 ) #if( configUSE_PREEMPTION == 1 )
/* Tick service routine used by the scheduler when preemptive scheduling is /* Tick service routine used by the scheduler when preemptive scheduling is
* being used. */ being used. */
static void __interrupt __far prvPreemptiveTick( void ); static void __interrupt __far prvPreemptiveTick( void );
#else #else
/* Tick service routine used by the scheduler when cooperative scheduling is /* Tick service routine used by the scheduler when cooperative scheduling is
* being used. */ being used. */
static void __interrupt __far prvNonPreemptiveTick( void ); static void __interrupt __far prvNonPreemptiveTick( void );
#endif #endif
@ -83,7 +81,7 @@ static void prvPortResetPIC( void );
static void __interrupt __far prvYieldProcessor( void ); static void __interrupt __far prvYieldProcessor( void );
/* Set the tick frequency back so the floppy drive works correctly when the /* Set the tick frequency back so the floppy drive works correctly when the
* scheduler exits. */ scheduler exits. */
static void prvSetTickFrequencyDefault( void ); static void prvSetTickFrequencyDefault( void );
/*lint -e956 File scopes necessary here. */ /*lint -e956 File scopes necessary here. */
@ -113,7 +111,7 @@ BaseType_t xPortStartScheduler( void )
/* This is called with interrupts already disabled. */ /* This is called with interrupts already disabled. */
/* Remember what was on the interrupts we are going to use /* Remember what was on the interrupts we are going to use
* so we can put them back later if required. */ so we can put them back later if required. */
pxOldSwitchISR = _dos_getvect( portSWITCH_INT_NUMBER ); pxOldSwitchISR = _dos_getvect( portSWITCH_INT_NUMBER );
pxOriginalTickISR = _dos_getvect( portTIMER_INT_NUMBER ); pxOriginalTickISR = _dos_getvect( portTIMER_INT_NUMBER );
pxOldSwitchISRPlus1 = _dos_getvect( portSWITCH_INT_NUMBER + 1 ); pxOldSwitchISRPlus1 = _dos_getvect( portSWITCH_INT_NUMBER + 1 );
@ -121,15 +119,15 @@ BaseType_t xPortStartScheduler( void )
prvSetTickFrequency( configTICK_RATE_HZ ); prvSetTickFrequency( configTICK_RATE_HZ );
/* Put our manual switch (yield) function on a known /* Put our manual switch (yield) function on a known
* vector. */ vector. */
_dos_setvect( portSWITCH_INT_NUMBER, prvYieldProcessor ); _dos_setvect( portSWITCH_INT_NUMBER, prvYieldProcessor );
/* Put the old tick on a different interrupt number so we can /* Put the old tick on a different interrupt number so we can
* call it when we want. */ call it when we want. */
_dos_setvect( portSWITCH_INT_NUMBER + 1, pxOriginalTickISR ); _dos_setvect( portSWITCH_INT_NUMBER + 1, pxOriginalTickISR );
/* The ISR used depends on whether the preemptive or cooperative /* The ISR used depends on whether the preemptive or cooperative
* scheduler is being used. */ scheduler is being used. */
#if( configUSE_PREEMPTION == 1 ) #if( configUSE_PREEMPTION == 1 )
{ {
/* Put our tick switch function on the timer interrupt. */ /* Put our tick switch function on the timer interrupt. */
@ -143,8 +141,8 @@ BaseType_t xPortStartScheduler( void )
#endif #endif
/* Setup a counter that is used to call the DOS interrupt as close /* Setup a counter that is used to call the DOS interrupt as close
* to it's original frequency as can be achieved given our chosen tick to it's original frequency as can be achieved given our chosen tick
* frequency. */ frequency. */
sDOSTickCounter = portTICKS_PER_DOS_TICK; sDOSTickCounter = portTICKS_PER_DOS_TICK;
/* Clean up function if we want to return to DOS. */ /* Clean up function if we want to return to DOS. */
@ -166,7 +164,7 @@ BaseType_t xPortStartScheduler( void )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The ISR used depends on whether the preemptive or cooperative /* The ISR used depends on whether the preemptive or cooperative
* scheduler is being used. */ scheduler is being used. */
#if( configUSE_PREEMPTION == 1 ) #if( configUSE_PREEMPTION == 1 )
static void __interrupt __far prvPreemptiveTick( void ) static void __interrupt __far prvPreemptiveTick( void )
{ {
@ -180,15 +178,15 @@ BaseType_t xPortStartScheduler( void )
/* Reset the PIC ready for the next time. */ /* Reset the PIC ready for the next time. */
prvPortResetPIC(); prvPortResetPIC();
} }
#else /* if ( configUSE_PREEMPTION == 1 ) */ #else
static void __interrupt __far prvNonPreemptiveTick( void ) static void __interrupt __far prvNonPreemptiveTick( void )
{ {
/* Same as preemptive tick, but the cooperative scheduler is being used /* Same as preemptive tick, but the cooperative scheduler is being used
* so we don't have to switch in the context of the next task. */ so we don't have to switch in the context of the next task. */
xTaskIncrementTick(); xTaskIncrementTick();
prvPortResetPIC(); prvPortResetPIC();
} }
#endif /* if ( configUSE_PREEMPTION == 1 ) */ #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void __interrupt __far prvYieldProcessor( void ) static void __interrupt __far prvYieldProcessor( void )
@ -201,22 +199,19 @@ static void __interrupt __far prvYieldProcessor( void )
static void prvPortResetPIC( void ) static void prvPortResetPIC( void )
{ {
/* We are going to call the DOS tick interrupt at as close a /* We are going to call the DOS tick interrupt at as close a
* frequency to the normal DOS tick as possible. */ frequency to the normal DOS tick as possible. */
/* WE SHOULD NOT DO THIS IF YIELD WAS CALLED. */ /* WE SHOULD NOT DO THIS IF YIELD WAS CALLED. */
--sDOSTickCounter; --sDOSTickCounter;
if( sDOSTickCounter <= 0 ) if( sDOSTickCounter <= 0 )
{ {
sDOSTickCounter = ( int16_t ) portTICKS_PER_DOS_TICK; sDOSTickCounter = ( int16_t ) portTICKS_PER_DOS_TICK;
__asm { __asm{ int portSWITCH_INT_NUMBER + 1 };
int portSWITCH_INT_NUMBER + 1
};
} }
else else
{ {
/* Reset the PIC as the DOS tick is not being called to /* Reset the PIC as the DOS tick is not being called to
* do it. */ do it. */
__asm __asm
{ {
mov al, 20H mov al, 20H
@ -229,8 +224,8 @@ static void prvPortResetPIC( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Jump back to the processor state prior to starting the /* Jump back to the processor state prior to starting the
* scheduler. This means we are not going to be using a scheduler. This means we are not going to be using a
* task stack frame so the task can be deleted. */ task stack frame so the task can be deleted. */
longjmp( xJumpBuf, 1 ); longjmp( xJumpBuf, 1 );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -240,9 +235,8 @@ static void prvExitFunction( void )
void ( __interrupt __far *pxOriginalTickISR )(); void ( __interrupt __far *pxOriginalTickISR )();
/* Interrupts should be disabled here anyway - but no /* Interrupts should be disabled here anyway - but no
* harm in making sure. */ harm in making sure. */
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
if( xSchedulerRunning == pdTRUE ) if( xSchedulerRunning == pdTRUE )
{ {
/* Set the DOS tick back onto the timer ticker. */ /* Set the DOS tick back onto the timer ticker. */
@ -251,13 +245,12 @@ static void prvExitFunction( void )
prvSetTickFrequencyDefault(); prvSetTickFrequencyDefault();
/* Put back the switch interrupt routines that was in place /* Put back the switch interrupt routines that was in place
* before the scheduler started. */ before the scheduler started. */
_dos_setvect( portSWITCH_INT_NUMBER, pxOldSwitchISR ); _dos_setvect( portSWITCH_INT_NUMBER, pxOldSwitchISR );
_dos_setvect( portSWITCH_INT_NUMBER + 1, pxOldSwitchISRPlus1 ); _dos_setvect( portSWITCH_INT_NUMBER + 1, pxOldSwitchISRPlus1 );
} }
/* The tick timer is back how DOS wants it. We can re-enable /* The tick timer is back how DOS wants it. We can re-enable
* interrupts without the scheduler being called. */ interrupts without the scheduler being called. */
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -292,3 +285,4 @@ static void prvSetTickFrequencyDefault( void )
/*lint +e950 */ /*lint +e950 */

View file

@ -61,8 +61,7 @@ typedef unsigned short UBaseType_t;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Critical section management. */ /* Critical section management. */
#define portENTER_CRITICAL() \ #define portENTER_CRITICAL() __asm{ pushf } \
__asm{ pushf } \
__asm{ cli } \ __asm{ cli } \
#define portEXIT_CRITICAL() __asm{ popf } #define portEXIT_CRITICAL() __asm{ popf }
@ -95,3 +94,4 @@ typedef unsigned short UBaseType_t;
#define portTASK_FUNCTION( vTaskFunction, pvParameters ) void vTaskFunction( void *pvParameters ) #define portTASK_FUNCTION( vTaskFunction, pvParameters ) void vTaskFunction( void *pvParameters )
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -47,10 +47,10 @@ void portSWITCH_CONTEXT( void );
void portFIRST_CONTEXT( void ); void portFIRST_CONTEXT( void );
/* There are slightly different versions depending on whether you are building /* There are slightly different versions depending on whether you are building
* to include debugger information. If debugger information is used then there to include debugger information. If debugger information is used then there
* are a couple of extra bytes left of the ISR stack (presumably for use by the are a couple of extra bytes left of the ISR stack (presumably for use by the
* debugger). The true stack pointer is then stored in the bp register. We add debugger). The true stack pointer is then stored in the bp register. We add
* 2 to the stack pointer to remove the extra bytes before we restore our context. */ 2 to the stack pointer to remove the extra bytes before we restore our context. */
#define portSWITCH_CONTEXT() \ #define portSWITCH_CONTEXT() \
asm { mov ax, seg pxCurrentTCB } \ asm { mov ax, seg pxCurrentTCB } \
@ -83,4 +83,5 @@ void portFIRST_CONTEXT( void );
__asm { iret } __asm { iret }
#endif /* ifndef PORT_ASM_H */ #endif

View file

@ -26,14 +26,14 @@
*/ */
/* /*
* Changes from V1.00: Changes from V1.00:
*
+ pxPortInitialiseStack() now initialises the stack of new tasks to the + pxPortInitialiseStack() now initialises the stack of new tasks to the
+ same format used by the compiler. This allows the compiler generated same format used by the compiler. This allows the compiler generated
+ interrupt mechanism to be used for context switches. interrupt mechanism to be used for context switches.
+
+ Changes from V2.6.1 Changes from V2.6.1
+
+ Move usPortCheckFreeStackSpace() to tasks.c. + Move usPortCheckFreeStackSpace() to tasks.c.
*/ */
@ -45,14 +45,12 @@
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* See header file for description. */ /* See header file for description. */
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
TaskFunction_t pxCode,
void * pvParameters )
{ {
StackType_t DS_Reg = 0; StackType_t DS_Reg = 0;
/* Place a few bytes of known values on the bottom of the stack. /* Place a few bytes of known values on the bottom of the stack.
* This is just useful for debugging. */ This is just useful for debugging. */
*pxTopOfStack = 0x1111; *pxTopOfStack = 0x1111;
pxTopOfStack--; pxTopOfStack--;
@ -69,8 +67,8 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
/*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */ /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */
/* We are going to start the scheduler using a return from interrupt /* We are going to start the scheduler using a return from interrupt
* instruction to load the program counter, so first there would be the instruction to load the program counter, so first there would be the
* function call with parameters preamble. */ function call with parameters preamble. */
*pxTopOfStack = FP_SEG( pvParameters ); *pxTopOfStack = FP_SEG( pvParameters );
pxTopOfStack--; pxTopOfStack--;
@ -90,8 +88,8 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
pxTopOfStack--; pxTopOfStack--;
/* The remaining registers would be pushed on the stack by our context /* The remaining registers would be pushed on the stack by our context
* switch function. These are loaded with values simply to make debugging switch function. These are loaded with values simply to make debugging
* easier. */ easier. */
*pxTopOfStack = ( StackType_t ) 0xAAAA; /* AX */ *pxTopOfStack = ( StackType_t ) 0xAAAA; /* AX */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0xBBBB; /* BX */ *pxTopOfStack = ( StackType_t ) 0xBBBB; /* BX */
@ -104,9 +102,7 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
pxTopOfStack--; pxTopOfStack--;
/* We need the true data segment. */ /* We need the true data segment. */
__asm { __asm{ MOV DS_Reg, DS };
MOV DS_Reg, DS
};
*pxTopOfStack = DS_Reg; /* DS */ *pxTopOfStack = DS_Reg; /* DS */
pxTopOfStack--; pxTopOfStack--;
@ -121,3 +117,4 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
return pxTopOfStack; return pxTopOfStack;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -38,7 +38,7 @@
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) ) #define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
@ -55,15 +55,15 @@
#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) #define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have /* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle * occurred while the SysTick counter is stopped during tickless idle
calculations. */ * calculations. */
#ifndef portMISSED_COUNTS_FACTOR #ifndef portMISSED_COUNTS_FACTOR
#define portMISSED_COUNTS_FACTOR ( 45UL ) #define portMISSED_COUNTS_FACTOR ( 45UL )
#endif #endif
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the * prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */ * debugger. */
#ifdef configTASK_RETURN_ADDRESS #ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else #else
@ -97,7 +97,7 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. */ * variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -130,10 +130,12 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t 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 /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--; pxTopOfStack--;
@ -153,22 +155,23 @@ static void prvTaskExitError( void )
volatile uint32_t ulDummy = 0UL; volatile uint32_t ulDummy = 0UL;
/* A function that implements a task must not exit or attempt to return to /* 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 * its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ). * should instead call vTaskDelete( NULL ).
*
Artificially force an assert() to be triggered if configASSERT() is * Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */ * defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL ); configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
while( ulDummy == 0 ) while( ulDummy == 0 )
{ {
/* This file calls prvTaskExitError() after the scheduler has been /* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined * started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings * but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy * about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and * volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears * therefore not output an 'unreachable code' warning for code that appears
after it. */ * after it. */
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -176,15 +179,15 @@ volatile uint32_t ulDummy = 0UL;
void vPortSVCHandler( void ) void vPortSVCHandler( void )
{ {
/* This function is no longer used, but retained for backward /* This function is no longer used, but retained for backward
compatibility. */ * compatibility. */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vPortStartFirstTask( void ) void vPortStartFirstTask( void )
{ {
/* The MSP stack is not reset as, unlike on M3/4 parts, there is no vector /* 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. * 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. */ * Not all M0 parts have the application vector table at address 0. */
__asm volatile ( __asm volatile (
" .syntax unified \n" " .syntax unified \n"
" ldr r2, pxCurrentTCBConst2 \n"/* Obtain location of pxCurrentTCB. */ " ldr r2, pxCurrentTCBConst2 \n"/* Obtain location of pxCurrentTCB. */
@ -214,11 +217,11 @@ void vPortStartFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* Make PendSV, CallSV and SysTick the same priority as the kernel. */ /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -228,11 +231,11 @@ BaseType_t xPortStartScheduler( void )
vPortStartFirstTask(); vPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task /* 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 * exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this * not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call * functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the * vTaskSwitchContext() so link time optimisation does not remove the
symbol. */ * symbol. */
vTaskSwitchContext(); vTaskSwitchContext();
prvTaskExitError(); prvTaskExitError();
@ -244,7 +247,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -255,7 +258,7 @@ void vPortYield( void )
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required but do ensure the code is completely /* Barriers are normally not required but do ensure the code is completely
within the specified behaviour for the architecture. */ * within the specified behaviour for the architecture. */
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
@ -274,6 +277,7 @@ void vPortExitCritical( void )
{ {
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
@ -407,43 +411,44 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
} }
/* Stop the SysTick momentarily. The time the SysTick is stopped for /* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will * is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the * inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */ * kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime /* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way * tick periods. -1 is used because this code will execute part way
through one of the tick periods. */ * through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation ) if( ulReloadValue > ulStoppedTimerCompensation )
{ {
ulReloadValue -= ulStoppedTimerCompensation; ulReloadValue -= ulStoppedTimerCompensation;
} }
/* Enter a critical section but don't use the taskENTER_CRITICAL() /* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */ * method as that will mask interrupts that should exit sleep mode. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler /* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */ * to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep ) if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{ {
/* Restart from whatever is left in the count register to complete /* Restart from whatever is left in the count register to complete
this tick period. */ * this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick /* Reset the reload register to the value required for normal tick
periods. */ * periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction() /* Re-enable interrupts - see comments above the cpsid instruction()
above. */ * above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
} }
else else
@ -452,69 +457,71 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
portNVIC_SYSTICK_LOAD_REG = ulReloadValue; portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to /* Clear the SysTick count flag and set the count value back to
zero. */ * zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains * set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi * its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle * should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */ * time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime; xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 ) if( xModifiableIdleTime > 0 )
{ {
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" ); __asm volatile ( "wfi" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU /* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above * out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */ * __disable_interrupt() call above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable interrupts again because the clock is about to be stopped /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase * and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar * any slippage between the time maintained by the RTOS and calendar
time. */ * time. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable the SysTick clock without reading the /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the * portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again, * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can * the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny * be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar * drift of the time maintained by the kernel with respect to calendar
time*/ * time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT ); portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and /* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being * been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet * correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick * to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */ * must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count /* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the * reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick * portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */ * period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow /* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something * underflowed because the post sleep hook did something
that took too long. */ * that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{ {
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
@ -523,30 +530,30 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this /* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped * function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */ * forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
{ {
/* Something other than the tick interrupt ended the sleep. /* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick * Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part * periods (not the ulReload value which accounted for part
ticks). */ * ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor /* How many complete tick periods passed while the processor
was waiting? */ * was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick /* The reload value is set to whatever fraction of a single tick
period remains. */ * period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
} }
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard * again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */ * value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );

View file

@ -64,7 +64,7 @@ typedef unsigned long UBaseType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -122,4 +122,3 @@ extern void vClearInterruptMaskFromISR( uint32_t ulMask ) __attribute__((naked)
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -22,6 +22,7 @@
* http://www.FreeRTOS.org * http://www.FreeRTOS.org
* http://aws.amazon.com/freertos * http://aws.amazon.com/freertos
* *
* 1 tab == 4 spaces!
*/ */
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining

View file

@ -244,6 +244,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
/** /**
* @brief Allocate a secure context for the task. * @brief Allocate a secure context for the task.
* *
@ -269,6 +270,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
/** /**
* @brief Checks whether or not the processor is privileged. * @brief Checks whether or not the processor is privileged.
* *

View file

@ -96,7 +96,8 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize, uint32_t ulIsTaskPrivileged ) secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
uint32_t ulIsTaskPrivileged )
#else /* configENABLE_MPU */ #else /* configENABLE_MPU */
secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize ) secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize )
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
@ -104,6 +105,7 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
uint8_t * pucStackMemory = NULL; uint8_t * pucStackMemory = NULL;
uint32_t ulIPSR; uint32_t ulIPSR;
SecureContextHandle_t xSecureContextHandle = NULL; SecureContextHandle_t xSecureContextHandle = NULL;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
uint32_t * pulCurrentStackPointer = NULL; uint32_t * pulCurrentStackPointer = NULL;
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
@ -144,6 +146,7 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
* context switch. */ * context switch. */
pulCurrentStackPointer = ( uint32_t * ) xSecureContextHandle->pucStackStart; pulCurrentStackPointer = ( uint32_t * ) xSecureContextHandle->pucStackStart;
pulCurrentStackPointer--; pulCurrentStackPointer--;
if( ulIsTaskPrivileged ) if( ulIsTaskPrivileged )
{ {
*( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED; *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;
@ -162,7 +165,6 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
/* Current SP is set to the starting of the stack. This /* Current SP is set to the starting of the stack. This
* value programmed in the PSP register on context switch. */ * value programmed in the PSP register on context switch. */
xSecureContextHandle->pucCurrentStackPointer = xSecureContextHandle->pucStackStart; xSecureContextHandle->pucCurrentStackPointer = xSecureContextHandle->pucStackStart;
} }
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
} }

View file

@ -70,7 +70,8 @@ void SecureContext_Init( void );
* otherwise. * otherwise.
*/ */
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize, uint32_t ulIsTaskPrivileged ); SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
uint32_t ulIsTaskPrivileged );
#else /* configENABLE_MPU */ #else /* configENABLE_MPU */
SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize ); SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize );
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */

View file

@ -63,6 +63,7 @@
/* Allocate the memory for the heap. */ /* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 ) #if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS /* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */ * heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ secureconfigTOTAL_HEAP_SIZE ]; extern uint8_t ucHeap[ secureconfigTOTAL_HEAP_SIZE ];
@ -191,6 +192,7 @@ uint8_t *puc;
/* Do the block being inserted, and the block it is being inserted after /* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */ * make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator; puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert ) if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{ {
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
@ -204,6 +206,7 @@ uint8_t *puc;
/* Do the block being inserted, and the block it is being inserted before /* Do the block being inserted, and the block it is being inserted before
* make a contiguous block of memory? */ * make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert; puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock ) if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{ {
if( pxIterator->pxNextFreeBlock != pxEnd ) if( pxIterator->pxNextFreeBlock != pxEnd )
@ -289,6 +292,7 @@ void *pvReturn = NULL;
* one of adequate size is found. */ * one of adequate size is found. */
pxPreviousBlock = &xStart; pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock; pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{ {
pxPreviousBlock = pxBlock; pxPreviousBlock = pxBlock;
@ -376,7 +380,7 @@ void *pvReturn = NULL;
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
#endif #endif /* if ( secureconfigUSE_MALLOC_FAILED_HOOK == 1 ) */
secureportASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) secureportBYTE_ALIGNMENT_MASK ) == 0 ); secureportASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) secureportBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn; return pvReturn;

View file

@ -127,7 +127,7 @@
{ \ { \
secureportDISABLE_SECURE_INTERRUPTS(); \ secureportDISABLE_SECURE_INTERRUPTS(); \
secureportDISABLE_NON_SECURE_INTERRUPTS(); \ secureportDISABLE_NON_SECURE_INTERRUPTS(); \
for( ;; ); \ for( ; ; ) {; } \
} }
#endif /* __SECURE_PORT_MACROS_H__ */ #endif /* __SECURE_PORT_MACROS_H__ */

View file

@ -244,6 +244,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
/** /**
* @brief Allocate a secure context for the task. * @brief Allocate a secure context for the task.
* *
@ -269,6 +270,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
/** /**
* @brief Checks whether or not the processor is privileged. * @brief Checks whether or not the processor is privileged.
* *

View file

@ -34,8 +34,8 @@
#include "task.h" #include "task.h"
/* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is /* For backward compatibility, ensure configKERNEL_INTERRUPT_PRIORITY is
defined. The value should also ensure backward compatibility. * defined. The value should also ensure backward compatibility.
FreeRTOS.org versions prior to V4.4.0 did not include this definition. */ * FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
#ifndef configKERNEL_INTERRUPT_PRIORITY #ifndef configKERNEL_INTERRUPT_PRIORITY
#define configKERNEL_INTERRUPT_PRIORITY 255 #define configKERNEL_INTERRUPT_PRIORITY 255
#endif #endif
@ -45,8 +45,9 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the same /* The way the SysTick is clocked is not modified in case it is not the same
as the core. */ * as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif #endif
@ -54,7 +55,7 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */ /* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
@ -85,17 +86,17 @@ FreeRTOS.org versions prior to V4.4.0 did not include this definition. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) #define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* A fiddle factor to estimate the number of SysTick counts that would have /* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle * occurred while the SysTick counter is stopped during tickless idle
calculations. */ * calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL ) #define portMISSED_COUNTS_FACTOR ( 45UL )
/* For strict compliance with the Cortex-M spec the task start address should /* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the * prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */ * debugger. */
#ifdef configTASK_RETURN_ADDRESS #ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else #else
@ -129,7 +130,7 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. */ * variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
@ -171,10 +172,12 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t 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 /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--; pxTopOfStack--;
@ -194,22 +197,23 @@ static void prvTaskExitError( void )
volatile uint32_t ulDummy = 0UL; volatile uint32_t ulDummy = 0UL;
/* A function that implements a task must not exit or attempt to return to /* 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 * its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ). * should instead call vTaskDelete( NULL ).
*
Artificially force an assert() to be triggered if configASSERT() is * Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */ * defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL ); configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
while( ulDummy == 0 ) while( ulDummy == 0 )
{ {
/* This file calls prvTaskExitError() after the scheduler has been /* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined * started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings * but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy * about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and * volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears * therefore not output an 'unreachable code' warning for code that appears
after it. */ * after it. */
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -258,7 +262,7 @@ static void prvPortStartFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
@ -268,15 +272,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible. * ensure interrupt entry is as fast and simple as possible.
*
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -286,8 +290,9 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
ulMaxPRIGROUPValue--; ulMaxPRIGROUPValue--;
@ -297,8 +302,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -306,29 +311,29 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -338,11 +343,11 @@ BaseType_t xPortStartScheduler( void )
prvPortStartFirstTask(); prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task /* 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 * exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this * not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call * functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the * vTaskSwitchContext() so link time optimisation does not remove the
symbol. */ * symbol. */
vTaskSwitchContext(); vTaskSwitchContext();
prvTaskExitError(); prvTaskExitError();
@ -354,7 +359,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -365,10 +370,10 @@ void vPortEnterCritical( void )
uxCriticalNesting++; uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so /* 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 * 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 * 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 * the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */ * assert function also uses a critical section. */
if( uxCriticalNesting == 1 ) if( uxCriticalNesting == 1 )
{ {
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
@ -380,6 +385,7 @@ void vPortExitCritical( void )
{ {
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
@ -427,16 +433,16 @@ void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
/* The SysTick runs at the lowest interrupt priority, so when this interrupt /* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to * executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already * save and then restore the interrupt mask value as its value is already
known. */ * known. */
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* A context switch is required. Context switching is performed in /* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */ * the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
} }
@ -458,43 +464,44 @@ void xPortSysTickHandler( void )
} }
/* Stop the SysTick momentarily. The time the SysTick is stopped for /* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will * is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the * inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */ * kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime /* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way * tick periods. -1 is used because this code will execute part way
through one of the tick periods. */ * through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation ) if( ulReloadValue > ulStoppedTimerCompensation )
{ {
ulReloadValue -= ulStoppedTimerCompensation; ulReloadValue -= ulStoppedTimerCompensation;
} }
/* Enter a critical section but don't use the taskENTER_CRITICAL() /* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */ * method as that will mask interrupts that should exit sleep mode. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler /* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */ * to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep ) if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{ {
/* Restart from whatever is left in the count register to complete /* Restart from whatever is left in the count register to complete
this tick period. */ * this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick /* Reset the reload register to the value required for normal tick
periods. */ * periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction() /* Re-enable interrupts - see comments above the cpsid instruction()
above. */ * above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
} }
else else
@ -503,69 +510,71 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulReloadValue; portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to /* Clear the SysTick count flag and set the count value back to
zero. */ * zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains * set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi * its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle * should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */ * time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime; xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 ) if( xModifiableIdleTime > 0 )
{ {
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" ); __asm volatile ( "wfi" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU /* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above * out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */ * __disable_interrupt() call above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable interrupts again because the clock is about to be stopped /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase * and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar * any slippage between the time maintained by the RTOS and calendar
time. */ * time. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable the SysTick clock without reading the /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the * portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again, * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can * the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny * be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar * drift of the time maintained by the kernel with respect to calendar
time*/ * time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT ); portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and /* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being * been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet * correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick * to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */ * must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count /* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the * reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick * portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */ * period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow /* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something * underflowed because the post sleep hook did something
that took too long. */ * that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{ {
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
@ -574,30 +583,30 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this /* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped * function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */ * forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
{ {
/* Something other than the tick interrupt ended the sleep. /* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick * Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part * periods (not the ulReload value which accounted for part
ticks). */ * ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor /* How many complete tick periods passed while the processor
was waiting? */ * was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick /* The reload value is set to whatever fraction of a single tick
period remains. */ * period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
} }
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard * again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */ * value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
@ -653,66 +662,45 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
*
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
*
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
*
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */ * of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */

View file

@ -64,7 +64,7 @@ typedef unsigned long UBaseType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -83,7 +83,7 @@ typedef unsigned long UBaseType_t;
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\ \
/* Barriers are normally not required but do ensure the code is completely \ /* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \ * within the specified behaviour for the architecture. */ \
__asm volatile ( "dsb" ::: "memory" ); \ __asm volatile ( "dsb" ::: "memory" ); \
__asm volatile ( "isb" ); \ __asm volatile ( "isb" ); \
} }
@ -107,8 +107,8 @@ extern void vPortExitCritical( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files * not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ * (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -133,6 +133,7 @@ not necessary for to use this port. They are defined so the common demo files
uint8_t ucReturn; uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" ); __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn; return ucReturn;
} }
@ -222,7 +223,7 @@ uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
); );
/* This return will not be reached but is necessary to prevent compiler /* This return will not be reached but is necessary to prevent compiler
warnings. */ * warnings. */
return ulOriginalBASEPRI; return ulOriginalBASEPRI;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -243,4 +244,3 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -74,7 +74,7 @@
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL ) #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
@ -86,6 +86,7 @@
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the /* The way the SysTick is clocked is not modified in case it is not the
* same a the core. */ * same a the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
@ -206,6 +207,7 @@
#define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_XPSR ( 0x01000000 )
#if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) #if ( configRUN_FREERTOS_SECURE_ONLY == 1 )
/** /**
* @brief Initial EXC_RETURN value. * @brief Initial EXC_RETURN value.
* *
@ -222,6 +224,7 @@
*/ */
#define portINITIAL_EXC_RETURN ( 0xfffffffd ) #define portINITIAL_EXC_RETURN ( 0xfffffffd )
#else #else
/** /**
* @brief Initial EXC_RETURN value. * @brief Initial EXC_RETURN value.
* *
@ -286,6 +289,7 @@
static void prvTaskExitError( void ); static void prvTaskExitError( void );
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
/** /**
* @brief Setup the Memory Protection Unit (MPU). * @brief Setup the Memory Protection Unit (MPU).
*/ */
@ -293,6 +297,7 @@ static void prvTaskExitError( void );
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
#if ( configENABLE_FPU == 1 ) #if ( configENABLE_FPU == 1 )
/** /**
* @brief Setup the Floating Point Unit (FPU). * @brief Setup the Floating Point Unit (FPU).
*/ */
@ -345,33 +350,35 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t *pulCallerStackAddress ) PRIVI
* @brief Each task maintains its own interrupt status in the critical nesting * @brief Each task maintains its own interrupt status in the critical nesting
* variable. * variable.
*/ */
static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL; PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
/** /**
* @brief Saved as part of the task context to indicate which context the * @brief Saved as part of the task context to indicate which context the
* task is using on the secure side. * task is using on the secure side.
*/ */
portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT;
#endif /* configENABLE_TRUSTZONE */ #endif /* configENABLE_TRUSTZONE */
#if ( configUSE_TICKLESS_IDLE == 1 ) #if ( configUSE_TICKLESS_IDLE == 1 )
/** /**
* @brief The number of SysTick increments that make up one tick period. * @brief The number of SysTick increments that make up one tick period.
*/ */
static uint32_t ulTimerCountsForOneTick = 0; PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0;
/** /**
* @brief The maximum number of tick periods that can be suppressed is * @brief The maximum number of tick periods that can be suppressed is
* limited by the 24 bit resolution of the SysTick timer. * limited by the 24 bit resolution of the SysTick timer.
*/ */
static uint32_t xMaximumPossibleSuppressedTicks = 0; PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0;
/** /**
* @brief Compensate for the CPU cycles that pass while the SysTick is * @brief Compensate for the CPU cycles that pass while the SysTick is
* stopped (low power functionality only). * stopped (low power functionality only).
*/ */
static uint32_t ulStoppedTimerCompensation = 0; PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -397,6 +404,7 @@ static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
* tick periods. -1 is used because this code will execute part way * tick periods. -1 is used because this code will execute part way
* through one of the tick periods. */ * through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation ) if( ulReloadValue > ulStoppedTimerCompensation )
{ {
ulReloadValue -= ulStoppedTimerCompensation; ulReloadValue -= ulStoppedTimerCompensation;
@ -447,12 +455,14 @@ static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
* so a copy is taken. */ * so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime; xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 ) if( xModifiableIdleTime > 0 )
{ {
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" ); __asm volatile ( "wfi" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU /* Re-enable interrupts to allow the interrupt that brought the MCU
@ -557,7 +567,7 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FUNC
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ /* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -591,6 +601,7 @@ volatile uint32_t ulDummy = 0UL;
static void prvSetupMPU( void ) /* PRIVILEGED_FUNCTION */ static void prvSetupMPU( void ) /* PRIVILEGED_FUNCTION */
{ {
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __privileged_functions_start__; extern uint32_t * __privileged_functions_start__;
@ -601,7 +612,7 @@ volatile uint32_t ulDummy = 0UL;
extern uint32_t * __unprivileged_flash_end__; extern uint32_t * __unprivileged_flash_end__;
extern uint32_t * __privileged_sram_start__; extern uint32_t * __privileged_sram_start__;
extern uint32_t * __privileged_sram_end__; extern uint32_t * __privileged_sram_end__;
#else #else /* if defined( __ARMCC_VERSION ) */
/* Declaration when these variable are exported from linker scripts. */ /* Declaration when these variable are exported from linker scripts. */
extern uint32_t __privileged_functions_start__[]; extern uint32_t __privileged_functions_start__[];
extern uint32_t __privileged_functions_end__[]; extern uint32_t __privileged_functions_end__[];
@ -754,6 +765,7 @@ void vPortSVCHandler_C( uint32_t *pulCallerStackAddress ) /* PRIVILEGED_FUNCTION
{ {
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__; extern uint32_t * __syscalls_flash_start__;
@ -784,7 +796,7 @@ uint8_t ucSVCNumber;
{ {
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
case portSVC_ALLOCATE_SECURE_CONTEXT: case portSVC_ALLOCATE_SECURE_CONTEXT:
{
/* R0 contains the stack size passed as parameter to the /* R0 contains the stack size passed as parameter to the
* vPortAllocateSecureContext function. */ * vPortAllocateSecureContext function. */
ulR0 = pulCallerStackAddress[ 0 ]; ulR0 = pulCallerStackAddress[ 0 ];
@ -801,7 +813,7 @@ uint8_t ucSVCNumber;
/* Allocate and load a context for the secure task. */ /* Allocate and load a context for the secure task. */
xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged ); xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged );
} }
#else #else /* if ( configENABLE_MPU == 1 ) */
{ {
/* Allocate and load a context for the secure task. */ /* Allocate and load a context for the secure task. */
xSecureContext = SecureContext_AllocateContext( ulR0 ); xSecureContext = SecureContext_AllocateContext( ulR0 );
@ -810,22 +822,18 @@ uint8_t ucSVCNumber;
configASSERT( xSecureContext != NULL ); configASSERT( xSecureContext != NULL );
SecureContext_LoadContext( xSecureContext ); SecureContext_LoadContext( xSecureContext );
}
break; break;
case portSVC_FREE_SECURE_CONTEXT: case portSVC_FREE_SECURE_CONTEXT:
{
/* R0 contains the secure context handle to be freed. */ /* R0 contains the secure context handle to be freed. */
ulR0 = pulCallerStackAddress[ 0 ]; ulR0 = pulCallerStackAddress[ 0 ];
/* Free the secure context. */ /* Free the secure context. */
SecureContext_FreeContext( ( SecureContextHandle_t ) ulR0 ); SecureContext_FreeContext( ( SecureContextHandle_t ) ulR0 );
}
break; break;
#endif /* configENABLE_TRUSTZONE */ #endif /* configENABLE_TRUSTZONE */
case portSVC_START_SCHEDULER: case portSVC_START_SCHEDULER:
{
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
{ {
/* De-prioritize the non-secure exceptions so that the /* De-prioritize the non-secure exceptions so that the
@ -847,36 +855,39 @@ uint8_t ucSVCNumber;
/* Setup the context of the first task so that the first task starts /* Setup the context of the first task so that the first task starts
* executing. */ * executing. */
vRestoreContextOfFirstTask(); vRestoreContextOfFirstTask();
}
break; break;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
case portSVC_RAISE_PRIVILEGE: case portSVC_RAISE_PRIVILEGE:
{
/* Only raise the privilege, if the svc was raised from any of /* Only raise the privilege, if the svc was raised from any of
* the system calls. */ * the system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ && if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
{ {
vRaisePrivilege(); vRaisePrivilege();
} }
}
break; break;
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
default: default:
{
/* Incorrect SVC call. */ /* Incorrect SVC call. */
configASSERT( pdFALSE ); configASSERT( pdFALSE );
} }
} }
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) /* PRIVILEGED_FUNCTION */ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged ) /* PRIVILEGED_FUNCTION */
#else #else
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters ) /* PRIVILEGED_FUNCTION */ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters ) /* PRIVILEGED_FUNCTION */
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
@ -897,6 +908,7 @@ uint8_t ucSVCNumber;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
{ {
pxTopOfStack--; pxTopOfStack--;
if( xRunPrivileged == pdTRUE ) if( xRunPrivileged == pdTRUE )
{ {
*pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */ *pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */
@ -958,6 +970,7 @@ uint8_t ucSVCNumber;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
{ {
pxTopOfStack--; pxTopOfStack--;
if( xRunPrivileged == pdTRUE ) if( xRunPrivileged == pdTRUE )
{ {
*pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */ *pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */
@ -988,8 +1001,8 @@ uint8_t ucSVCNumber;
BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
{ {
/* Make PendSV, CallSV and SysTick the same priority as the kernel. */ /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
{ {
@ -1031,10 +1044,23 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
const struct xMEMORY_REGION * const xRegions,
StackType_t * pxBottomOfStack,
uint32_t ulStackDepth )
{ {
uint32_t ulRegionStartAddress, ulRegionEndAddress, ulRegionNumber; uint32_t ulRegionStartAddress, ulRegionEndAddress, ulRegionNumber;
int32_t lIndex = 0; int32_t lIndex = 0;
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __privileged_sram_start__;
extern uint32_t * __privileged_sram_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __privileged_sram_start__[];
extern uint32_t __privileged_sram_end__[];
#endif /* defined( __ARMCC_VERSION ) */
/* Setup MAIR0. */ /* Setup MAIR0. */
xMPUSettings->ulMAIR0 = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); xMPUSettings->ulMAIR0 = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK );
@ -1046,9 +1072,23 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
* the stack region has already been configured. */ * the stack region has already been configured. */
if( ulStackDepth > 0 ) if( ulStackDepth > 0 )
{ {
/* Define the region that allows access to the stack. */ ulRegionStartAddress = ( uint32_t ) pxBottomOfStack;
ulRegionStartAddress = ( ( uint32_t ) pxBottomOfStack ) & portMPU_RBAR_ADDRESS_MASK;
ulRegionEndAddress = ( uint32_t ) pxBottomOfStack + ( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) - 1; ulRegionEndAddress = ( uint32_t ) pxBottomOfStack + ( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) - 1;
/* If the stack is within the privileged SRAM, do not protect it
* using a separate MPU region. This is needed because privileged
* SRAM is already protected using an MPU region and ARMv8-M does
* not allow overlapping MPU regions. */
if( ulRegionStartAddress >= ( uint32_t ) __privileged_sram_start__ &&
ulRegionEndAddress <= ( uint32_t ) __privileged_sram_end__ )
{
xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = 0;
xMPUSettings->xRegionsSettings[ 0 ].ulRLAR = 0;
}
else
{
/* Define the region that allows access to the stack. */
ulRegionStartAddress &= portMPU_RBAR_ADDRESS_MASK;
ulRegionEndAddress &= portMPU_RLAR_ADDRESS_MASK; ulRegionEndAddress &= portMPU_RLAR_ADDRESS_MASK;
xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = ( ulRegionStartAddress ) | xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = ( ulRegionStartAddress ) |
@ -1060,6 +1100,7 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
( portMPU_RLAR_ATTR_INDEX0 ) | ( portMPU_RLAR_ATTR_INDEX0 ) |
( portMPU_RLAR_REGION_ENABLE ); ( portMPU_RLAR_REGION_ENABLE );
} }
}
/* User supplied configurable regions. */ /* User supplied configurable regions. */
for( ulRegionNumber = 1; ulRegionNumber <= portNUM_CONFIGURABLE_REGIONS; ulRegionNumber++ ) for( ulRegionNumber = 1; ulRegionNumber <= portNUM_CONFIGURABLE_REGIONS; ulRegionNumber++ )

View file

@ -244,6 +244,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
/** /**
* @brief Allocate a secure context for the task. * @brief Allocate a secure context for the task.
* *
@ -269,6 +270,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
/** /**
* @brief Checks whether or not the processor is privileged. * @brief Checks whether or not the processor is privileged.
* *

View file

@ -96,7 +96,8 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize, uint32_t ulIsTaskPrivileged ) secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
uint32_t ulIsTaskPrivileged )
#else /* configENABLE_MPU */ #else /* configENABLE_MPU */
secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize ) secureportNON_SECURE_CALLABLE SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize )
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
@ -104,6 +105,7 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
uint8_t * pucStackMemory = NULL; uint8_t * pucStackMemory = NULL;
uint32_t ulIPSR; uint32_t ulIPSR;
SecureContextHandle_t xSecureContextHandle = NULL; SecureContextHandle_t xSecureContextHandle = NULL;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
uint32_t * pulCurrentStackPointer = NULL; uint32_t * pulCurrentStackPointer = NULL;
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
@ -144,6 +146,7 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
* context switch. */ * context switch. */
pulCurrentStackPointer = ( uint32_t * ) xSecureContextHandle->pucStackStart; pulCurrentStackPointer = ( uint32_t * ) xSecureContextHandle->pucStackStart;
pulCurrentStackPointer--; pulCurrentStackPointer--;
if( ulIsTaskPrivileged ) if( ulIsTaskPrivileged )
{ {
*( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED; *( pulCurrentStackPointer ) = securecontextCONTROL_VALUE_PRIVILEGED;
@ -162,7 +165,6 @@ secureportNON_SECURE_CALLABLE void SecureContext_Init( void )
/* Current SP is set to the starting of the stack. This /* Current SP is set to the starting of the stack. This
* value programmed in the PSP register on context switch. */ * value programmed in the PSP register on context switch. */
xSecureContextHandle->pucCurrentStackPointer = xSecureContextHandle->pucStackStart; xSecureContextHandle->pucCurrentStackPointer = xSecureContextHandle->pucStackStart;
} }
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
} }

View file

@ -70,7 +70,8 @@ void SecureContext_Init( void );
* otherwise. * otherwise.
*/ */
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize, uint32_t ulIsTaskPrivileged ); SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize,
uint32_t ulIsTaskPrivileged );
#else /* configENABLE_MPU */ #else /* configENABLE_MPU */
SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize ); SecureContextHandle_t SecureContext_AllocateContext( uint32_t ulSecureStackSize );
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */

View file

@ -63,6 +63,7 @@
/* Allocate the memory for the heap. */ /* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 ) #if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS /* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */ * heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ secureconfigTOTAL_HEAP_SIZE ]; extern uint8_t ucHeap[ secureconfigTOTAL_HEAP_SIZE ];
@ -191,6 +192,7 @@ uint8_t *puc;
/* Do the block being inserted, and the block it is being inserted after /* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */ * make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator; puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert ) if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{ {
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
@ -204,6 +206,7 @@ uint8_t *puc;
/* Do the block being inserted, and the block it is being inserted before /* Do the block being inserted, and the block it is being inserted before
* make a contiguous block of memory? */ * make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert; puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock ) if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{ {
if( pxIterator->pxNextFreeBlock != pxEnd ) if( pxIterator->pxNextFreeBlock != pxEnd )
@ -289,6 +292,7 @@ void *pvReturn = NULL;
* one of adequate size is found. */ * one of adequate size is found. */
pxPreviousBlock = &xStart; pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock; pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{ {
pxPreviousBlock = pxBlock; pxPreviousBlock = pxBlock;
@ -376,7 +380,7 @@ void *pvReturn = NULL;
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} }
#endif #endif /* if ( secureconfigUSE_MALLOC_FAILED_HOOK == 1 ) */
secureportASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) secureportBYTE_ALIGNMENT_MASK ) == 0 ); secureportASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) secureportBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn; return pvReturn;

View file

@ -127,7 +127,7 @@
{ \ { \
secureportDISABLE_SECURE_INTERRUPTS(); \ secureportDISABLE_SECURE_INTERRUPTS(); \
secureportDISABLE_NON_SECURE_INTERRUPTS(); \ secureportDISABLE_NON_SECURE_INTERRUPTS(); \
for( ;; ); \ for( ; ; ) {; } \
} }
#endif /* __SECURE_PORT_MACROS_H__ */ #endif /* __SECURE_PORT_MACROS_H__ */

View file

@ -74,7 +74,7 @@
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL ) #define portNVIC_SYSTICK_COUNT_FLAG_BIT ( 1UL << 16UL )
@ -86,6 +86,7 @@
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the /* The way the SysTick is clocked is not modified in case it is not the
* same a the core. */ * same a the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
@ -206,6 +207,7 @@
#define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_XPSR ( 0x01000000 )
#if ( configRUN_FREERTOS_SECURE_ONLY == 1 ) #if ( configRUN_FREERTOS_SECURE_ONLY == 1 )
/** /**
* @brief Initial EXC_RETURN value. * @brief Initial EXC_RETURN value.
* *
@ -222,6 +224,7 @@
*/ */
#define portINITIAL_EXC_RETURN ( 0xfffffffd ) #define portINITIAL_EXC_RETURN ( 0xfffffffd )
#else #else
/** /**
* @brief Initial EXC_RETURN value. * @brief Initial EXC_RETURN value.
* *
@ -286,6 +289,7 @@
static void prvTaskExitError( void ); static void prvTaskExitError( void );
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
/** /**
* @brief Setup the Memory Protection Unit (MPU). * @brief Setup the Memory Protection Unit (MPU).
*/ */
@ -293,6 +297,7 @@ static void prvTaskExitError( void );
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
#if ( configENABLE_FPU == 1 ) #if ( configENABLE_FPU == 1 )
/** /**
* @brief Setup the Floating Point Unit (FPU). * @brief Setup the Floating Point Unit (FPU).
*/ */
@ -345,33 +350,35 @@ portDONT_DISCARD void vPortSVCHandler_C( uint32_t *pulCallerStackAddress ) PRIVI
* @brief Each task maintains its own interrupt status in the critical nesting * @brief Each task maintains its own interrupt status in the critical nesting
* variable. * variable.
*/ */
static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL; PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
/** /**
* @brief Saved as part of the task context to indicate which context the * @brief Saved as part of the task context to indicate which context the
* task is using on the secure side. * task is using on the secure side.
*/ */
portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT; PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT;
#endif /* configENABLE_TRUSTZONE */ #endif /* configENABLE_TRUSTZONE */
#if ( configUSE_TICKLESS_IDLE == 1 ) #if ( configUSE_TICKLESS_IDLE == 1 )
/** /**
* @brief The number of SysTick increments that make up one tick period. * @brief The number of SysTick increments that make up one tick period.
*/ */
static uint32_t ulTimerCountsForOneTick = 0; PRIVILEGED_DATA static uint32_t ulTimerCountsForOneTick = 0;
/** /**
* @brief The maximum number of tick periods that can be suppressed is * @brief The maximum number of tick periods that can be suppressed is
* limited by the 24 bit resolution of the SysTick timer. * limited by the 24 bit resolution of the SysTick timer.
*/ */
static uint32_t xMaximumPossibleSuppressedTicks = 0; PRIVILEGED_DATA static uint32_t xMaximumPossibleSuppressedTicks = 0;
/** /**
* @brief Compensate for the CPU cycles that pass while the SysTick is * @brief Compensate for the CPU cycles that pass while the SysTick is
* stopped (low power functionality only). * stopped (low power functionality only).
*/ */
static uint32_t ulStoppedTimerCompensation = 0; PRIVILEGED_DATA static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -397,6 +404,7 @@ static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
* tick periods. -1 is used because this code will execute part way * tick periods. -1 is used because this code will execute part way
* through one of the tick periods. */ * through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation ) if( ulReloadValue > ulStoppedTimerCompensation )
{ {
ulReloadValue -= ulStoppedTimerCompensation; ulReloadValue -= ulStoppedTimerCompensation;
@ -447,12 +455,14 @@ static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
* so a copy is taken. */ * so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime; xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 ) if( xModifiableIdleTime > 0 )
{ {
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" ); __asm volatile ( "wfi" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU /* Re-enable interrupts to allow the interrupt that brought the MCU
@ -557,7 +567,7 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void ) /* PRIVILEGED_FUNC
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Configure SysTick to interrupt at the requested rate. */ /* Configure SysTick to interrupt at the requested rate. */
portNVIC_SYSTICK_LOAD_REG = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -591,6 +601,7 @@ volatile uint32_t ulDummy = 0UL;
static void prvSetupMPU( void ) /* PRIVILEGED_FUNCTION */ static void prvSetupMPU( void ) /* PRIVILEGED_FUNCTION */
{ {
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __privileged_functions_start__; extern uint32_t * __privileged_functions_start__;
@ -601,7 +612,7 @@ volatile uint32_t ulDummy = 0UL;
extern uint32_t * __unprivileged_flash_end__; extern uint32_t * __unprivileged_flash_end__;
extern uint32_t * __privileged_sram_start__; extern uint32_t * __privileged_sram_start__;
extern uint32_t * __privileged_sram_end__; extern uint32_t * __privileged_sram_end__;
#else #else /* if defined( __ARMCC_VERSION ) */
/* Declaration when these variable are exported from linker scripts. */ /* Declaration when these variable are exported from linker scripts. */
extern uint32_t __privileged_functions_start__[]; extern uint32_t __privileged_functions_start__[];
extern uint32_t __privileged_functions_end__[]; extern uint32_t __privileged_functions_end__[];
@ -754,6 +765,7 @@ void vPortSVCHandler_C( uint32_t *pulCallerStackAddress ) /* PRIVILEGED_FUNCTION
{ {
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__; extern uint32_t * __syscalls_flash_start__;
@ -784,7 +796,7 @@ uint8_t ucSVCNumber;
{ {
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
case portSVC_ALLOCATE_SECURE_CONTEXT: case portSVC_ALLOCATE_SECURE_CONTEXT:
{
/* R0 contains the stack size passed as parameter to the /* R0 contains the stack size passed as parameter to the
* vPortAllocateSecureContext function. */ * vPortAllocateSecureContext function. */
ulR0 = pulCallerStackAddress[ 0 ]; ulR0 = pulCallerStackAddress[ 0 ];
@ -801,7 +813,7 @@ uint8_t ucSVCNumber;
/* Allocate and load a context for the secure task. */ /* Allocate and load a context for the secure task. */
xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged ); xSecureContext = SecureContext_AllocateContext( ulR0, ulIsTaskPrivileged );
} }
#else #else /* if ( configENABLE_MPU == 1 ) */
{ {
/* Allocate and load a context for the secure task. */ /* Allocate and load a context for the secure task. */
xSecureContext = SecureContext_AllocateContext( ulR0 ); xSecureContext = SecureContext_AllocateContext( ulR0 );
@ -810,22 +822,18 @@ uint8_t ucSVCNumber;
configASSERT( xSecureContext != NULL ); configASSERT( xSecureContext != NULL );
SecureContext_LoadContext( xSecureContext ); SecureContext_LoadContext( xSecureContext );
}
break; break;
case portSVC_FREE_SECURE_CONTEXT: case portSVC_FREE_SECURE_CONTEXT:
{
/* R0 contains the secure context handle to be freed. */ /* R0 contains the secure context handle to be freed. */
ulR0 = pulCallerStackAddress[ 0 ]; ulR0 = pulCallerStackAddress[ 0 ];
/* Free the secure context. */ /* Free the secure context. */
SecureContext_FreeContext( ( SecureContextHandle_t ) ulR0 ); SecureContext_FreeContext( ( SecureContextHandle_t ) ulR0 );
}
break; break;
#endif /* configENABLE_TRUSTZONE */ #endif /* configENABLE_TRUSTZONE */
case portSVC_START_SCHEDULER: case portSVC_START_SCHEDULER:
{
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
{ {
/* De-prioritize the non-secure exceptions so that the /* De-prioritize the non-secure exceptions so that the
@ -847,36 +855,39 @@ uint8_t ucSVCNumber;
/* Setup the context of the first task so that the first task starts /* Setup the context of the first task so that the first task starts
* executing. */ * executing. */
vRestoreContextOfFirstTask(); vRestoreContextOfFirstTask();
}
break; break;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
case portSVC_RAISE_PRIVILEGE: case portSVC_RAISE_PRIVILEGE:
{
/* Only raise the privilege, if the svc was raised from any of /* Only raise the privilege, if the svc was raised from any of
* the system calls. */ * the system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ && if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ ) ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
{ {
vRaisePrivilege(); vRaisePrivilege();
} }
}
break; break;
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
default: default:
{
/* Incorrect SVC call. */ /* Incorrect SVC call. */
configASSERT( pdFALSE ); configASSERT( pdFALSE );
} }
} }
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) /* PRIVILEGED_FUNCTION */ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged ) /* PRIVILEGED_FUNCTION */
#else #else
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, StackType_t *pxEndOfStack, TaskFunction_t pxCode, void *pvParameters ) /* PRIVILEGED_FUNCTION */ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
StackType_t * pxEndOfStack,
TaskFunction_t pxCode,
void * pvParameters ) /* PRIVILEGED_FUNCTION */
#endif /* configENABLE_MPU */ #endif /* configENABLE_MPU */
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
@ -897,6 +908,7 @@ uint8_t ucSVCNumber;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
{ {
pxTopOfStack--; pxTopOfStack--;
if( xRunPrivileged == pdTRUE ) if( xRunPrivileged == pdTRUE )
{ {
*pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */ *pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */
@ -958,6 +970,7 @@ uint8_t ucSVCNumber;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
{ {
pxTopOfStack--; pxTopOfStack--;
if( xRunPrivileged == pdTRUE ) if( xRunPrivileged == pdTRUE )
{ {
*pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */ *pxTopOfStack = portINITIAL_CONTROL_PRIVILEGED; /* Slot used to hold this task's CONTROL value. */
@ -988,8 +1001,8 @@ uint8_t ucSVCNumber;
BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */ BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
{ {
/* Make PendSV, CallSV and SysTick the same priority as the kernel. */ /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
{ {
@ -1031,10 +1044,23 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
const struct xMEMORY_REGION * const xRegions,
StackType_t * pxBottomOfStack,
uint32_t ulStackDepth )
{ {
uint32_t ulRegionStartAddress, ulRegionEndAddress, ulRegionNumber; uint32_t ulRegionStartAddress, ulRegionEndAddress, ulRegionNumber;
int32_t lIndex = 0; int32_t lIndex = 0;
#if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */
extern uint32_t * __privileged_sram_start__;
extern uint32_t * __privileged_sram_end__;
#else
/* Declaration when these variable are exported from linker scripts. */
extern uint32_t __privileged_sram_start__[];
extern uint32_t __privileged_sram_end__[];
#endif /* defined( __ARMCC_VERSION ) */
/* Setup MAIR0. */ /* Setup MAIR0. */
xMPUSettings->ulMAIR0 = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK ); xMPUSettings->ulMAIR0 = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK );
@ -1046,9 +1072,23 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
* the stack region has already been configured. */ * the stack region has already been configured. */
if( ulStackDepth > 0 ) if( ulStackDepth > 0 )
{ {
/* Define the region that allows access to the stack. */ ulRegionStartAddress = ( uint32_t ) pxBottomOfStack;
ulRegionStartAddress = ( ( uint32_t ) pxBottomOfStack ) & portMPU_RBAR_ADDRESS_MASK;
ulRegionEndAddress = ( uint32_t ) pxBottomOfStack + ( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) - 1; ulRegionEndAddress = ( uint32_t ) pxBottomOfStack + ( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) - 1;
/* If the stack is within the privileged SRAM, do not protect it
* using a separate MPU region. This is needed because privileged
* SRAM is already protected using an MPU region and ARMv8-M does
* not allow overlapping MPU regions. */
if( ulRegionStartAddress >= ( uint32_t ) __privileged_sram_start__ &&
ulRegionEndAddress <= ( uint32_t ) __privileged_sram_end__ )
{
xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = 0;
xMPUSettings->xRegionsSettings[ 0 ].ulRLAR = 0;
}
else
{
/* Define the region that allows access to the stack. */
ulRegionStartAddress &= portMPU_RBAR_ADDRESS_MASK;
ulRegionEndAddress &= portMPU_RLAR_ADDRESS_MASK; ulRegionEndAddress &= portMPU_RLAR_ADDRESS_MASK;
xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = ( ulRegionStartAddress ) | xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = ( ulRegionStartAddress ) |
@ -1060,6 +1100,7 @@ void vPortEndScheduler( void ) /* PRIVILEGED_FUNCTION */
( portMPU_RLAR_ATTR_INDEX0 ) | ( portMPU_RLAR_ATTR_INDEX0 ) |
( portMPU_RLAR_REGION_ENABLE ); ( portMPU_RLAR_REGION_ENABLE );
} }
}
/* User supplied configurable regions. */ /* User supplied configurable regions. */
for( ulRegionNumber = 1; ulRegionNumber <= portNUM_CONFIGURABLE_REGIONS; ulRegionNumber++ ) for( ulRegionNumber = 1; ulRegionNumber <= portNUM_CONFIGURABLE_REGIONS; ulRegionNumber++ )

View file

@ -244,6 +244,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_TRUSTZONE == 1 ) #if ( configENABLE_TRUSTZONE == 1 )
/** /**
* @brief Allocate a secure context for the task. * @brief Allocate a secure context for the task.
* *
@ -269,6 +270,7 @@ typedef struct MPU_SETTINGS
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 ) #if ( configENABLE_MPU == 1 )
/** /**
* @brief Checks whether or not the processor is privileged. * @brief Checks whether or not the processor is privileged.
* *

View file

@ -26,7 +26,7 @@
*/ */
/*----------------------------------------------------------- /*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM3 port. * Implementation of functions defined in portable.h for the ARM CM3 MPU port.
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
@ -45,6 +45,7 @@
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the same /* The way the SysTick is clocked is not modified in case it is not the same
* as the core. */ * as the core. */
#define portNVIC_SYSTICK_CLK ( 0 ) #define portNVIC_SYSTICK_CLK ( 0 )
@ -54,8 +55,8 @@
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSPRI1_REG ( * ( ( volatile uint32_t * ) 0xe000ed1c ) ) #define portNVIC_SHPR2_REG ( *( ( volatile uint32_t * ) 0xe000ed1c ) )
#define portNVIC_SYS_CTRL_STATE_REG ( *( ( volatile uint32_t * ) 0xe000ed24 ) ) #define portNVIC_SYS_CTRL_STATE_REG ( *( ( volatile uint32_t * ) 0xe000ed24 ) )
#define portNVIC_MEM_FAULT_ENABLE ( 1UL << 16UL ) #define portNVIC_MEM_FAULT_ENABLE ( 1UL << 16UL )
@ -191,7 +192,10 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged )
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
* interrupt. */ * interrupt. */
@ -241,8 +245,10 @@ static void prvSVCHandler( uint32_t *pulParam )
{ {
uint8_t ucSVCNumber; uint8_t ucSVCNumber;
uint32_t ulPC; uint32_t ulPC;
#if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__; extern uint32_t * __syscalls_flash_start__;
@ -261,11 +267,14 @@ uint32_t ulPC;
switch( ucSVCNumber ) switch( ucSVCNumber )
{ {
case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; case portSVC_START_SCHEDULER:
portNVIC_SHPR2_REG |= portNVIC_SVC_PRI;
prvRestoreContextOfFirstTask(); prvRestoreContextOfFirstTask();
break; break;
case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; case portSVC_YIELD:
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required /* Barriers are normally not required
* but do ensure the code is completely * but do ensure the code is completely
* within the specified behaviour for the * within the specified behaviour for the
@ -280,8 +289,9 @@ uint32_t ulPC;
case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the
* svc was raised from any of the * svc was raised from any of the
* system calls. */ * system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ ) if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
{ {
__asm volatile __asm volatile
( (
@ -291,9 +301,11 @@ uint32_t ulPC;
::: "r1", "memory" ::: "r1", "memory"
); );
} }
break; break;
#else #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
case portSVC_RAISE_PRIVILEGE : __asm volatile case portSVC_RAISE_PRIVILEGE:
__asm volatile
( (
" mrs r1, control \n"/* Obtain current control value. */ " mrs r1, control \n"/* Obtain current control value. */
" bic r1, #1 \n"/* Set privilege bit. */ " bic r1, #1 \n"/* Set privilege bit. */
@ -371,7 +383,7 @@ BaseType_t xPortStartScheduler( void )
* functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
* "FromISR". FreeRTOS maintains separate thread and ISR API functions * "FromISR". FreeRTOS maintains separate thread and ISR API functions
* to ensure interrupt entry is as fast and simple as possible. * to ensure interrupt entry is as fast and simple as possible.
*
* Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
@ -388,6 +400,7 @@ BaseType_t xPortStartScheduler( void )
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
* of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
ulMaxPRIGROUPValue--; ulMaxPRIGROUPValue--;
@ -426,8 +439,8 @@ BaseType_t xPortStartScheduler( void )
/* Make PendSV and SysTick the same priority as the kernel, and the SVC /* Make PendSV and SysTick the same priority as the kernel, and the SVC
* handler higher priority so it can be used to exit a critical section (where * handler higher priority so it can be used to exit a critical section (where
* lower priorities are masked). */ * lower priorities are masked). */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Configure the regions in the MPU that are common to all tasks. */ /* Configure the regions in the MPU that are common to all tasks. */
prvSetupMPU(); prvSetupMPU();
@ -484,10 +497,12 @@ BaseType_t xRunningPrivileged = xPortRaisePrivilege();
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
} }
vPortResetPrivilege( xRunningPrivileged ); vPortResetPrivilege( xRunningPrivileged );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -700,7 +715,10 @@ void vResetPrivilege( void ) /* __attribute__ (( naked )) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
const struct xMEMORY_REGION * const xRegions,
StackType_t * pxBottomOfStack,
uint32_t ulStackDepth )
{ {
extern uint32_t __SRAM_segment_start__[]; extern uint32_t __SRAM_segment_start__[];
extern uint32_t __SRAM_segment_end__[]; extern uint32_t __SRAM_segment_end__[];
@ -818,20 +836,20 @@ uint32_t ul;
* function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
* from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
* configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
* Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
* interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
* be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
* configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
* Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
* default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
* which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
* and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
*
* FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
* interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
*
* The following links provide detailed information: * The following links provide detailed information:
* http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
* http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
@ -844,7 +862,7 @@ uint32_t ul;
* the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
* to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
* this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
*
* If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
* configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
* devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the

View file

@ -64,7 +64,7 @@ typedef unsigned long UBaseType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -126,7 +126,7 @@ typedef struct MPU_SETTINGS
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\ \
/* Barriers are normally not required but do ensure the code is completely \ /* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \ * within the specified behaviour for the architecture. */ \
__asm volatile ( "dsb" ::: "memory" ); \ __asm volatile ( "dsb" ::: "memory" ); \
__asm volatile ( "isb" ); \ __asm volatile ( "isb" ); \
} }
@ -150,8 +150,8 @@ extern void vPortExitCritical( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files * not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ * (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -169,6 +169,7 @@ not necessary for to use this port. They are defined so the common demo files
uint8_t ucReturn; uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" ); __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn; return ucReturn;
} }
@ -279,7 +280,7 @@ uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
); );
/* This return will not be reached but is necessary to prevent compiler /* This return will not be reached but is necessary to prevent compiler
warnings. */ * warnings. */
return ulOriginalBASEPRI; return ulOriginalBASEPRI;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -296,7 +297,7 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY #ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
#warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security. https://www.freertos.org/FreeRTOS-V10.3.x.html" #warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security. https: /*www.freertos.org/FreeRTOS-V10.3.x.html" */
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0 #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -305,4 +306,3 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -42,8 +42,9 @@
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the same /* The way the SysTick is clocked is not modified in case it is not the same
as the core. */ * as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif #endif
@ -51,7 +52,7 @@
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */ /* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
@ -60,7 +61,7 @@
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7 /* Constants used to detect a Cortex-M7 r0p1 core, which should use the ARM_CM7
r0p1 port. */ * r0p1 port. */
#define portCPUID ( *( ( volatile uint32_t * ) 0xE000ed00 ) ) #define portCPUID ( *( ( volatile uint32_t * ) 0xE000ed00 ) )
#define portCORTEX_M7_r0p1_ID ( 0x410FC271UL ) #define portCORTEX_M7_r0p1_ID ( 0x410FC271UL )
#define portCORTEX_M7_r0p0_ID ( 0x410FC270UL ) #define portCORTEX_M7_r0p0_ID ( 0x410FC270UL )
@ -93,17 +94,17 @@ r0p1 port. */
#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) #define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* For strict compliance with the Cortex-M spec the task start address should /* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* A fiddle factor to estimate the number of SysTick counts that would have /* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle * occurred while the SysTick counter is stopped during tickless idle
calculations. */ * calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL ) #define portMISSED_COUNTS_FACTOR ( 45UL )
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the * prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */ * debugger. */
#ifdef configTASK_RETURN_ADDRESS #ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else #else
@ -142,7 +143,7 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. */ * variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
@ -184,13 +185,15 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t 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 /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit /* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */ * of interrupts, and to ensure alignment. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
@ -204,7 +207,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its /* A save method is being used that requires each task to maintain its
own exec return value. */ * own exec return value. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN; *pxTopOfStack = portINITIAL_EXC_RETURN;
@ -219,22 +222,23 @@ static void prvTaskExitError( void )
volatile uint32_t ulDummy = 0; volatile uint32_t ulDummy = 0;
/* A function that implements a task must not exit or attempt to return to /* 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 * its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ). * should instead call vTaskDelete( NULL ).
*
Artificially force an assert() to be triggered if configASSERT() is * Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */ * defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL ); configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
while( ulDummy == 0 ) while( ulDummy == 0 )
{ {
/* This file calls prvTaskExitError() after the scheduler has been /* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined * started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings * but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy * about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and * volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears * therefore not output an 'unreachable code' warning for code that appears
after it. */ * after it. */
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -261,9 +265,9 @@ void vPortSVCHandler( void )
static void prvPortStartFirstTask( void ) static void prvPortStartFirstTask( void )
{ {
/* Start the first task. This also clears the bit that indicates the FPU is /* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which * in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack * would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */ * for lazy saving of FPU registers. */
__asm volatile ( __asm volatile (
" ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */ " ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n" " ldr r0, [r0] \n"
@ -288,12 +292,12 @@ static void prvPortStartFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
/* This port can be used on all revisions of the Cortex-M7 core other than /* This port can be used on all revisions of the Cortex-M7 core other than
the r0p1 parts. r0p1 parts should use the port from the * the r0p1 parts. r0p1 parts should use the port from the
/source/portable/GCC/ARM_CM7/r0p1 directory. */ * /source/portable/GCC/ARM_CM7/r0p1 directory. */
configASSERT( portCPUID != portCORTEX_M7_r0p1_ID ); configASSERT( portCPUID != portCORTEX_M7_r0p1_ID );
configASSERT( portCPUID != portCORTEX_M7_r0p0_ID ); configASSERT( portCPUID != portCORTEX_M7_r0p0_ID );
@ -304,15 +308,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible. * ensure interrupt entry is as fast and simple as possible.
*
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -322,8 +326,9 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
ulMaxPRIGROUPValue--; ulMaxPRIGROUPValue--;
@ -333,8 +338,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -342,29 +347,29 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -380,11 +385,11 @@ BaseType_t xPortStartScheduler( void )
prvPortStartFirstTask(); prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task /* 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 * exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this * not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call * functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the * vTaskSwitchContext() so link time optimisation does not remove the
symbol. */ * symbol. */
vTaskSwitchContext(); vTaskSwitchContext();
prvTaskExitError(); prvTaskExitError();
@ -396,7 +401,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -407,10 +412,10 @@ void vPortEnterCritical( void )
uxCriticalNesting++; uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so /* 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 * 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 * 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 * the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */ * assert function also uses a critical section. */
if( uxCriticalNesting == 1 ) if( uxCriticalNesting == 1 )
{ {
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
@ -422,6 +427,7 @@ void vPortExitCritical( void )
{ {
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
@ -489,16 +495,16 @@ void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
/* The SysTick runs at the lowest interrupt priority, so when this interrupt /* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to * executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already * save and then restore the interrupt mask value as its value is already
known. */ * known. */
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* A context switch is required. Context switching is performed in /* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */ * the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
} }
@ -520,43 +526,44 @@ void xPortSysTickHandler( void )
} }
/* Stop the SysTick momentarily. The time the SysTick is stopped for /* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will * is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the * inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */ * kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime /* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way * tick periods. -1 is used because this code will execute part way
through one of the tick periods. */ * through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation ) if( ulReloadValue > ulStoppedTimerCompensation )
{ {
ulReloadValue -= ulStoppedTimerCompensation; ulReloadValue -= ulStoppedTimerCompensation;
} }
/* Enter a critical section but don't use the taskENTER_CRITICAL() /* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */ * method as that will mask interrupts that should exit sleep mode. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler /* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */ * to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep ) if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{ {
/* Restart from whatever is left in the count register to complete /* Restart from whatever is left in the count register to complete
this tick period. */ * this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick /* Reset the reload register to the value required for normal tick
periods. */ * periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction() /* Re-enable interrupts - see comments above the cpsid instruction()
above. */ * above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
} }
else else
@ -565,69 +572,71 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulReloadValue; portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to /* Clear the SysTick count flag and set the count value back to
zero. */ * zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains * set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi * its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle * should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */ * time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime; xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 ) if( xModifiableIdleTime > 0 )
{ {
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" ); __asm volatile ( "wfi" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU /* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above * out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */ * __disable_interrupt() call above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable interrupts again because the clock is about to be stopped /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase * and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar * any slippage between the time maintained by the RTOS and calendar
time. */ * time. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable the SysTick clock without reading the /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the * portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again, * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can * the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny * be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar * drift of the time maintained by the kernel with respect to calendar
time*/ * time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT ); portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and /* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being * been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet * correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick * to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */ * must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count /* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the * reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick * portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */ * period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow /* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something * underflowed because the post sleep hook did something
that took too long. */ * that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{ {
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
@ -636,30 +645,30 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this /* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped * function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */ * forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
{ {
/* Something other than the tick interrupt ended the sleep. /* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick * Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part * periods (not the ulReload value which accounted for part
ticks). */ * ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor /* How many complete tick periods passed while the processor
was waiting? */ * was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick /* The reload value is set to whatever fraction of a single tick
period remains. */ * period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
} }
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard * again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */ * value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
@ -731,47 +740,45 @@ static void vPortEnableVFP( void )
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
*
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
*
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
*
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */ * of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */

View file

@ -64,7 +64,7 @@ typedef unsigned long UBaseType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -83,7 +83,7 @@ typedef unsigned long UBaseType_t;
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\ \
/* Barriers are normally not required but do ensure the code is completely \ /* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \ * within the specified behaviour for the architecture. */ \
__asm volatile ( "dsb" ::: "memory" ); \ __asm volatile ( "dsb" ::: "memory" ); \
__asm volatile ( "isb" ); \ __asm volatile ( "isb" ); \
} }
@ -107,8 +107,8 @@ extern void vPortExitCritical( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files * not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ * (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -133,6 +133,7 @@ not necessary for to use this port. They are defined so the common demo files
uint8_t ucReturn; uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" ); __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn; return ucReturn;
} }
@ -220,7 +221,7 @@ uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
); );
/* This return will not be reached but is necessary to prevent compiler /* This return will not be reached but is necessary to prevent compiler
warnings. */ * warnings. */
return ulOriginalBASEPRI; return ulOriginalBASEPRI;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -241,4 +242,3 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -26,12 +26,12 @@
*/ */
/*----------------------------------------------------------- /*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM3 port. * Implementation of functions defined in portable.h for the ARM CM4 MPU port.
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when * all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */ * task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* Scheduler includes. */ /* Scheduler includes. */
@ -49,8 +49,9 @@ task.h is included from an application file. */
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the same /* The way the SysTick is clocked is not modified in case it is not the same
as the core. */ * as the core. */
#define portNVIC_SYSTICK_CLK ( 0 ) #define portNVIC_SYSTICK_CLK ( 0 )
#endif #endif
@ -58,8 +59,8 @@ task.h is included from an application file. */
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_SYSPRI1_REG ( * ( ( volatile uint32_t * ) 0xe000ed1c ) ) #define portNVIC_SHPR2_REG ( *( ( volatile uint32_t * ) 0xe000ed1c ) )
#define portNVIC_SYS_CTRL_STATE_REG ( *( ( volatile uint32_t * ) 0xe000ed24 ) ) #define portNVIC_SYS_CTRL_STATE_REG ( *( ( volatile uint32_t * ) 0xe000ed24 ) )
#define portNVIC_MEM_FAULT_ENABLE ( 1UL << 16UL ) #define portNVIC_MEM_FAULT_ENABLE ( 1UL << 16UL )
@ -68,7 +69,7 @@ task.h is included from an application file. */
#define portMPU_REGION_BASE_ADDRESS_REG ( *( ( volatile uint32_t * ) 0xe000ed9C ) ) #define portMPU_REGION_BASE_ADDRESS_REG ( *( ( volatile uint32_t * ) 0xe000ed9C ) )
#define portMPU_REGION_ATTRIBUTE_REG ( *( ( volatile uint32_t * ) 0xe000edA0 ) ) #define portMPU_REGION_ATTRIBUTE_REG ( *( ( volatile uint32_t * ) 0xe000edA0 ) )
#define portMPU_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed94 ) ) #define portMPU_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed94 ) )
#define portEXPECTED_MPU_TYPE_VALUE ( 8UL << 8UL ) /* 8 regions, unified. */ #define portEXPECTED_MPU_TYPE_VALUE ( portTOTAL_NUM_REGIONS << 8UL )
#define portMPU_ENABLE ( 0x01UL ) #define portMPU_ENABLE ( 0x01UL )
#define portMPU_BACKGROUND_ENABLE ( 1UL << 2UL ) #define portMPU_BACKGROUND_ENABLE ( 1UL << 2UL )
#define portPRIVILEGED_EXECUTION_START_ADDRESS ( 0UL ) #define portPRIVILEGED_EXECUTION_START_ADDRESS ( 0UL )
@ -108,7 +109,7 @@ task.h is included from an application file. */
#define portOFFSET_TO_PC ( 6 ) #define portOFFSET_TO_PC ( 6 )
/* For strict compliance with the Cortex-M spec the task start address should /* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* /*
@ -185,8 +186,8 @@ extern void vPortResetPrivilege( BaseType_t xRunningPrivileged );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. Note this is not saved as part of the task context as context * variable. Note this is not saved as part of the task context as context
switches can only occur when uxCriticalNesting is zero. */ * switches can only occur when uxCriticalNesting is zero. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
@ -205,10 +206,13 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters,
BaseType_t xRunPrivileged )
{ {
/* Simulate the stack frame as it would be created by a context switch /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--; pxTopOfStack--;
@ -219,7 +223,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its /* A save method is being used that requires each task to maintain its
own exec return value. */ * own exec return value. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN; *pxTopOfStack = portINITIAL_EXC_RETURN;
@ -261,8 +265,10 @@ static void prvSVCHandler( uint32_t *pulParam )
{ {
uint8_t ucSVCNumber; uint8_t ucSVCNumber;
uint32_t ulPC; uint32_t ulPC;
#if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __syscalls_flash_start__; extern uint32_t * __syscalls_flash_start__;
@ -275,21 +281,24 @@ uint32_t ulPC;
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */ #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
/* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
argument (r0) is pulParam[ 0 ]. */ * argument (r0) is pulParam[ 0 ]. */
ulPC = pulParam[ portOFFSET_TO_PC ]; ulPC = pulParam[ portOFFSET_TO_PC ];
ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ]; ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
switch( ucSVCNumber ) switch( ucSVCNumber )
{ {
case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; case portSVC_START_SCHEDULER:
portNVIC_SHPR2_REG |= portNVIC_SVC_PRI;
prvRestoreContextOfFirstTask(); prvRestoreContextOfFirstTask();
break; break;
case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; case portSVC_YIELD:
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
/* Barriers are normally not required /* Barriers are normally not required
but do ensure the code is completely * but do ensure the code is completely
within the specified behaviour for the * within the specified behaviour for the
architecture. */ * architecture. */
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
@ -299,8 +308,9 @@ uint32_t ulPC;
case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the
* svc was raised from any of the * svc was raised from any of the
* system calls. */ * system calls. */
if( ulPC >= ( uint32_t ) __syscalls_flash_start__ &&
ulPC <= ( uint32_t ) __syscalls_flash_end__ ) if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
{ {
__asm volatile __asm volatile
( (
@ -310,9 +320,11 @@ uint32_t ulPC;
::: "r1", "memory" ::: "r1", "memory"
); );
} }
break; break;
#else #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
case portSVC_RAISE_PRIVILEGE : __asm volatile case portSVC_RAISE_PRIVILEGE:
__asm volatile
( (
" mrs r1, control \n"/* Obtain current control value. */ " mrs r1, control \n"/* Obtain current control value. */
" bic r1, #1 \n"/* Set privilege bit. */ " bic r1, #1 \n"/* Set privilege bit. */
@ -348,8 +360,15 @@ static void prvRestoreContextOfFirstTask( void )
" str r3, [r2] \n"/* Disable MPU. */ " str r3, [r2] \n"/* Disable MPU. */
" \n" " \n"
" ldr r2, =0xe000ed9c \n"/* Region Base Address register. */ " ldr r2, =0xe000ed9c \n"/* Region Base Address register. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers from TCB. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
" stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ " stmia r2, {r4-r11} \n" /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */
" \n"
#if ( portTOTAL_NUM_REGIONS == 16 )
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
" stmia r2, {r4-r11} \n" /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */
" stmia r2, {r4-r11} \n" /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */
#endif /* portTOTAL_NUM_REGIONS == 16. */
" \n" " \n"
" ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */ " ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
" ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */ " ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
@ -376,7 +395,7 @@ static void prvRestoreContextOfFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See
http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ); configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
@ -386,15 +405,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible. * ensure interrupt entry is as fast and simple as possible.
*
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -404,8 +423,9 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
ulMaxPRIGROUPValue--; ulMaxPRIGROUPValue--;
@ -415,8 +435,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -424,34 +444,34 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the same priority as the kernel, and the SVC /* Make PendSV and SysTick the same priority as the kernel, and the SVC
handler higher priority so it can be used to exit a critical section (where * handler higher priority so it can be used to exit a critical section (where
lower priorities are masked). */ * lower priorities are masked). */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Configure the regions in the MPU that are common to all tasks. */ /* Configure the regions in the MPU that are common to all tasks. */
prvSetupMPU(); prvSetupMPU();
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -464,9 +484,9 @@ BaseType_t xPortStartScheduler( void )
*( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;
/* Start the first task. This also clears the bit that indicates the FPU is /* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which * in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack * would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */ * for lazy saving of FPU registers. */
__asm volatile ( __asm volatile (
" ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */ " ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n" " ldr r0, [r0] \n"
@ -491,7 +511,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -513,10 +533,12 @@ BaseType_t xRunningPrivileged = xPortRaisePrivilege();
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
} }
vPortResetPrivilege( xRunningPrivileged ); vPortResetPrivilege( xRunningPrivileged );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -562,8 +584,15 @@ void xPortPendSVHandler( void )
" str r3, [r2] \n"/* Disable MPU. */ " str r3, [r2] \n"/* Disable MPU. */
" \n" " \n"
" ldr r2, =0xe000ed9c \n"/* Region Base Address register. */ " ldr r2, =0xe000ed9c \n"/* Region Base Address register. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers from TCB. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
" stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ " stmia r2, {r4-r11} \n" /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */
" \n"
#if ( portTOTAL_NUM_REGIONS == 16 )
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
" stmia r2, {r4-r11} \n" /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
" ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */
" stmia r2, {r4-r11} \n" /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */
#endif /* portTOTAL_NUM_REGIONS == 16. */
" \n" " \n"
" ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */ " ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
" ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */ " ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
@ -640,6 +669,7 @@ static void vPortEnableVFP( void )
static void prvSetupMPU( void ) static void prvSetupMPU( void )
{ {
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __privileged_functions_start__; extern uint32_t * __privileged_functions_start__;
@ -656,7 +686,14 @@ static void prvSetupMPU( void )
extern uint32_t __FLASH_segment_end__[]; extern uint32_t __FLASH_segment_end__[];
extern uint32_t __privileged_data_start__[]; extern uint32_t __privileged_data_start__[];
extern uint32_t __privileged_data_end__[]; extern uint32_t __privileged_data_end__[];
#endif #endif /* if defined( __ARMCC_VERSION ) */
/* The only permitted number of regions are 8 or 16. */
configASSERT( ( portTOTAL_NUM_REGIONS == 8 ) || ( portTOTAL_NUM_REGIONS == 16 ) );
/* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */
configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );
/* Check the expected MPU is present. */ /* Check the expected MPU is present. */
if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
{ {
@ -666,34 +703,34 @@ static void prvSetupMPU( void )
( portUNPRIVILEGED_FLASH_REGION ); ( portUNPRIVILEGED_FLASH_REGION );
portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) | portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |
( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the privileged flash for privileged only access. This is where /* Setup the privileged flash for privileged only access. This is where
the kernel code is placed. */ * the kernel code is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_FLASH_REGION ); ( portPRIVILEGED_FLASH_REGION );
portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) | portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |
( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) |
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Setup the privileged data RAM region. This is where the kernel data /* Setup the privileged data RAM region. This is where the kernel data
is placed. */ * is placed. */
portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portPRIVILEGED_RAM_REGION ); ( portPRIVILEGED_RAM_REGION );
portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* By default allow everything to access the general peripherals. The /* By default allow everything to access the general peripherals. The
system peripherals and registers are protected. */ * system peripherals and registers are protected. */
portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) | portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
( portGENERAL_PERIPHERALS_REGION ); ( portGENERAL_PERIPHERALS_REGION );
@ -716,7 +753,7 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
uint32_t ulRegionSize, ulReturnValue = 4; uint32_t ulRegionSize, ulReturnValue = 4;
/* 32 is the smallest region size, 31 is the largest valid value for /* 32 is the smallest region size, 31 is the largest valid value for
ulReturnValue. */ * ulReturnValue. */
for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) ) for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
{ {
if( ulActualSizeInBytes <= ulRegionSize ) if( ulActualSizeInBytes <= ulRegionSize )
@ -730,7 +767,7 @@ uint32_t ulRegionSize, ulReturnValue = 4;
} }
/* Shift the code by one before returning so it can be written directly /* Shift the code by one before returning so it can be written directly
into the the correct bit position of the attribute register. */ * into the the correct bit position of the attribute register. */
return( ulReturnValue << 1UL ); return( ulReturnValue << 1UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -765,9 +802,13 @@ void vResetPrivilege( void ) /* __attribute__ (( naked )) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
const struct xMEMORY_REGION * const xRegions,
StackType_t * pxBottomOfStack,
uint32_t ulStackDepth )
{ {
#if defined( __ARMCC_VERSION ) #if defined( __ARMCC_VERSION )
/* Declaration when these variable are defined in code instead of being /* Declaration when these variable are defined in code instead of being
* exported from linker scripts. */ * exported from linker scripts. */
extern uint32_t * __SRAM_segment_start__; extern uint32_t * __SRAM_segment_start__;
@ -780,7 +821,7 @@ void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMOR
extern uint32_t __SRAM_segment_end__[]; extern uint32_t __SRAM_segment_end__[];
extern uint32_t __privileged_data_start__[]; extern uint32_t __privileged_data_start__[];
extern uint32_t __privileged_data_end__[]; extern uint32_t __privileged_data_end__[];
#endif #endif /* if defined( __ARMCC_VERSION ) */
int32_t lIndex; int32_t lIndex;
uint32_t ul; uint32_t ul;
@ -795,12 +836,12 @@ uint32_t ul;
xMPUSettings->xRegion[ 0 ].ulRegionAttribute = xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
( portMPU_REGION_READ_WRITE ) | ( portMPU_REGION_READ_WRITE ) |
( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
/* Re-instate the privileged only RAM region as xRegion[ 0 ] will have /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
just removed the privileged only parameters. */ * just removed the privileged only parameters. */
xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress = xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -808,7 +849,7 @@ uint32_t ul;
xMPUSettings->xRegion[ 1 ].ulRegionAttribute = xMPUSettings->xRegion[ 1 ].ulRegionAttribute =
( portMPU_REGION_PRIVILEGED_READ_WRITE ) | ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
@ -822,9 +863,9 @@ uint32_t ul;
else else
{ {
/* This function is called automatically when the task is created - in /* This function is called automatically when the task is created - in
which case the stack region parameters will be valid. At all other * which case the stack region parameters will be valid. At all other
times the stack parameters will not be valid and it is assumed that the * times the stack parameters will not be valid and it is assumed that the
stack region has already been configured. */ * stack region has already been configured. */
if( ulStackDepth > 0 ) if( ulStackDepth > 0 )
{ {
/* Define the region that allows access to the stack. */ /* Define the region that allows access to the stack. */
@ -836,7 +877,7 @@ uint32_t ul;
xMPUSettings->xRegion[ 0 ].ulRegionAttribute = xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
( portMPU_REGION_READ_WRITE ) | /* Read and write. */ ( portMPU_REGION_READ_WRITE ) | /* Read and write. */
( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) | ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |
( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |
( portMPU_REGION_ENABLE ); ( portMPU_REGION_ENABLE );
} }
@ -847,8 +888,8 @@ uint32_t ul;
if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL ) if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
{ {
/* Translate the generic region definition contained in /* Translate the generic region definition contained in
xRegions into the CM3 specific MPU settings that are then * xRegions into the CM4 specific MPU settings that are then
stored in xMPUSettings. */ * stored in xMPUSettings. */
xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) | ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
( portMPU_REGION_VALID ) | ( portMPU_REGION_VALID ) |
@ -889,48 +930,46 @@ uint32_t ul;
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
*
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
*
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
*
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredicable behaviour. */ * of zero will result in unpredicable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -64,7 +64,7 @@ typedef unsigned long UBaseType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -80,6 +80,92 @@ typedef unsigned long UBaseType_t;
#define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL ) #define portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY ( 0x02UL << 24UL )
#define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL ) #define portMPU_REGION_CACHEABLE_BUFFERABLE ( 0x07UL << 16UL )
#define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL ) #define portMPU_REGION_EXECUTE_NEVER ( 0x01UL << 28UL )
/* Location of the TEX,S,C,B bits in the MPU Region Attribute and Size
* Register (RASR). */
#define portMPU_RASR_TEX_S_C_B_LOCATION ( 16UL )
#define portMPU_RASR_TEX_S_C_B_MASK ( 0x3FUL )
/* MPU settings that can be overriden in FreeRTOSConfig.h. */
#ifndef configTOTAL_MPU_REGIONS
/* Define to 8 for backward compatibility. */
#define configTOTAL_MPU_REGIONS ( 8UL )
#endif
/*
* The TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits define the
* memory type, and where necessary the cacheable and shareable properties
* of the memory region.
*
* The TEX, C, and B bits together indicate the memory type of the region,
* and:
* - For Normal memory, the cacheable properties of the region.
* - For Device memory, whether the region is shareable.
*
* For Normal memory regions, the S bit indicates whether the region is
* shareable. For Strongly-ordered and Device memory, the S bit is ignored.
*
* See the following two tables for setting TEX, S, C and B bits for
* unprivileged flash, privileged flash and privileged RAM regions.
*
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| TEX | C | B | Memory type | Description or Normal region cacheability | Shareable? |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 000 | 0 | 0 | Strongly-ordered | Strongly ordered | Shareable |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 000 | 0 | 1 | Device | Shared device | Shareable |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 000 | 1 | 0 | Normal | Outer and inner write-through; no write allocate | S bit |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 000 | 1 | 1 | Normal | Outer and inner write-back; no write allocate | S bit |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 001 | 0 | 0 | Normal | Outer and inner Non-cacheable | S bit |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 001 | 0 | 1 | Reserved | Reserved | Reserved |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 001 | 1 | 0 | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED | IMPLEMENTATION DEFINED |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 001 | 1 | 1 | Normal | Outer and inner write-back; write and read allocate | S bit |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 010 | 0 | 0 | Device | Non-shared device | Not shareable |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 010 | 0 | 1 | Reserved | Reserved | Reserved |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 010 | 1 | X | Reserved | Reserved | Reserved |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 011 | X | X | Reserved | Reserved | Reserved |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
| 1BB | A | A | Normal | Cached memory, with AA and BB indicating the inner and | Reserved |
| | | | | outer cacheability rules that must be exported on the | |
| | | | | bus. See the table below for the cacheability policy | |
| | | | | encoding. memory, BB=Outer policy, AA=Inner policy. | |
+-----+---+---+------------------------+--------------------------------------------------------+-------------------------+
+-----------------------------------------+----------------------------------------+
| AA or BB subfield of {TEX,C,B} encoding | Cacheability policy |
+-----------------------------------------+----------------------------------------+
| 00 | Non-cacheable |
+-----------------------------------------+----------------------------------------+
| 01 | Write-back, write and read allocate |
+-----------------------------------------+----------------------------------------+
| 10 | Write-through, no write allocate |
+-----------------------------------------+----------------------------------------+
| 11 | Write-back, no write allocate |
+-----------------------------------------+----------------------------------------+
*/
/* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for flash
* region. */
#ifndef configTEX_S_C_B_FLASH
/* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */
#define configTEX_S_C_B_FLASH ( 0x07UL )
#endif
/* TEX, Shareable (S), Cacheable (C) and Bufferable (B) bits for RAM
* region. */
#ifndef configTEX_S_C_B_SRAM
/* Default to TEX=000, S=1, C=1, B=1 for backward compatibility. */
#define configTEX_S_C_B_SRAM ( 0x07UL )
#endif
#define portUNPRIVILEGED_FLASH_REGION ( 0UL ) #define portUNPRIVILEGED_FLASH_REGION ( 0UL )
#define portPRIVILEGED_FLASH_REGION ( 1UL ) #define portPRIVILEGED_FLASH_REGION ( 1UL )
@ -87,9 +173,9 @@ typedef unsigned long UBaseType_t;
#define portGENERAL_PERIPHERALS_REGION ( 3UL ) #define portGENERAL_PERIPHERALS_REGION ( 3UL )
#define portSTACK_REGION ( 4UL ) #define portSTACK_REGION ( 4UL )
#define portFIRST_CONFIGURABLE_REGION ( 5UL ) #define portFIRST_CONFIGURABLE_REGION ( 5UL )
#define portLAST_CONFIGURABLE_REGION ( 7UL ) #define portTOTAL_NUM_REGIONS ( configTOTAL_MPU_REGIONS )
#define portNUM_CONFIGURABLE_REGIONS ( ( portLAST_CONFIGURABLE_REGION - portFIRST_CONFIGURABLE_REGION ) + 1 ) #define portNUM_CONFIGURABLE_REGIONS ( portTOTAL_NUM_REGIONS - portFIRST_CONFIGURABLE_REGION )
#define portTOTAL_NUM_REGIONS ( portNUM_CONFIGURABLE_REGIONS + 1 ) /* Plus one to make space for the stack region. */ #define portLAST_CONFIGURABLE_REGION ( portTOTAL_NUM_REGIONS - 1 )
#define portSWITCH_TO_USER_MODE() __asm volatile ( " mrs r0, control \n orr r0, #1 \n msr control, r0 " ::: "r0", "memory" ) #define portSWITCH_TO_USER_MODE() __asm volatile ( " mrs r0, control \n orr r0, #1 \n msr control, r0 " ::: "r0", "memory" )
@ -126,7 +212,7 @@ typedef struct MPU_SETTINGS
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\ \
/* Barriers are normally not required but do ensure the code is completely \ /* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \ * within the specified behaviour for the architecture. */ \
__asm volatile ( "dsb" ::: "memory" ); \ __asm volatile ( "dsb" ::: "memory" ); \
__asm volatile ( "isb" ); \ __asm volatile ( "isb" ); \
} }
@ -150,8 +236,8 @@ extern void vPortExitCritical( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files * not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ * (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -169,6 +255,7 @@ not necessary for to use this port. They are defined so the common demo files
uint8_t ucReturn; uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" ); __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn; return ucReturn;
} }
@ -279,7 +366,7 @@ uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
); );
/* This return will not be reached but is necessary to prevent compiler /* This return will not be reached but is necessary to prevent compiler
warnings. */ * warnings. */
return ulOriginalBASEPRI; return ulOriginalBASEPRI;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -296,7 +383,7 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
#ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY #ifndef configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY
#warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security. https://www.freertos.org/FreeRTOS-V10.3.x.html" #warning "configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not defined. We recommend defining it to 1 in FreeRTOSConfig.h for better security. https: /*www.freertos.org/FreeRTOS-V10.3.x.html" */
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0 #define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 0
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -305,4 +392,3 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -26,7 +26,7 @@
*/ */
/*----------------------------------------------------------- /*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the ARM CM4F port. * Implementation of functions defined in portable.h for the ARM CM7 port.
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Scheduler includes. */ /* Scheduler includes. */
@ -42,8 +42,9 @@
/* Ensure the SysTick is clocked at the same frequency as the core. */ /* Ensure the SysTick is clocked at the same frequency as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL ) #define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#else #else
/* The way the SysTick is clocked is not modified in case it is not the same /* The way the SysTick is clocked is not modified in case it is not the same
as the core. */ * as the core. */
#define portNVIC_SYSTICK_CLK_BIT ( 0 ) #define portNVIC_SYSTICK_CLK_BIT ( 0 )
#endif #endif
@ -51,7 +52,7 @@
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) ) #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) ) #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) ) #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
/* ...then bits in the registers. */ /* ...then bits in the registers. */
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL ) #define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL ) #define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
@ -87,17 +88,17 @@
#define portMAX_24_BIT_NUMBER ( 0xffffffUL ) #define portMAX_24_BIT_NUMBER ( 0xffffffUL )
/* For strict compliance with the Cortex-M spec the task start address should /* For strict compliance with the Cortex-M spec the task start address should
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
/* A fiddle factor to estimate the number of SysTick counts that would have /* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle * occurred while the SysTick counter is stopped during tickless idle
calculations. */ * calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL ) #define portMISSED_COUNTS_FACTOR ( 45UL )
/* Let the user override the pre-loading of the initial LR with the address of /* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the * prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */ * debugger. */
#ifdef configTASK_RETURN_ADDRESS #ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else #else
@ -136,7 +137,7 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting /* Each task maintains its own interrupt status in the critical nesting
variable. */ * variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
@ -178,13 +179,15 @@ static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t 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 /* Simulate the stack frame as it would be created by a context switch
interrupt. */ * interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit /* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */ * of interrupts, and to ensure alignment. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
@ -198,7 +201,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */ *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its /* A save method is being used that requires each task to maintain its
own exec return value. */ * own exec return value. */
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN; *pxTopOfStack = portINITIAL_EXC_RETURN;
@ -213,22 +216,23 @@ static void prvTaskExitError( void )
volatile uint32_t ulDummy = 0; volatile uint32_t ulDummy = 0;
/* A function that implements a task must not exit or attempt to return to /* 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 * its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ). * should instead call vTaskDelete( NULL ).
*
Artificially force an assert() to be triggered if configASSERT() is * Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */ * defined, then stop here so application writers can catch the error. */
configASSERT( uxCriticalNesting == ~0UL ); configASSERT( uxCriticalNesting == ~0UL );
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
while( ulDummy == 0 ) while( ulDummy == 0 )
{ {
/* This file calls prvTaskExitError() after the scheduler has been /* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined * started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings * but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy * about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and * volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears * therefore not output an 'unreachable code' warning for code that appears
after it. */ * after it. */
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -255,9 +259,9 @@ void vPortSVCHandler( void )
static void prvPortStartFirstTask( void ) static void prvPortStartFirstTask( void )
{ {
/* Start the first task. This also clears the bit that indicates the FPU is /* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which * in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the SVC stack * would otherwise result in the unnecessary leaving of space in the SVC stack
for lazy saving of FPU registers. */ * for lazy saving of FPU registers. */
__asm volatile ( __asm volatile (
" ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */ " ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n" " ldr r0, [r0] \n"
@ -282,7 +286,7 @@ static void prvPortStartFirstTask( void )
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ * See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY ); configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
#if ( configASSERT_DEFINED == 1 ) #if ( configASSERT_DEFINED == 1 )
@ -292,15 +296,15 @@ BaseType_t xPortStartScheduler( void )
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine the maximum priority from which ISR safe FreeRTOS API /* Determine the maximum priority from which ISR safe FreeRTOS API
functions can be called. ISR safe functions are those that end in * functions can be called. ISR safe functions are those that end in
"FromISR". FreeRTOS maintains separate thread and ISR API functions to * "FromISR". FreeRTOS maintains separate thread and ISR API functions to
ensure interrupt entry is as fast and simple as possible. * ensure interrupt entry is as fast and simple as possible.
*
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to all /* Determine the number of priority bits available. First write to all
possible bits. */ * possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -310,8 +314,9 @@ BaseType_t xPortStartScheduler( void )
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
/* Calculate the maximum acceptable priority group value for the number /* Calculate the maximum acceptable priority group value for the number
of bits read back. */ * of bits read back. */
ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
{ {
ulMaxPRIGROUPValue--; ulMaxPRIGROUPValue--;
@ -321,8 +326,8 @@ BaseType_t xPortStartScheduler( void )
#ifdef __NVIC_PRIO_BITS #ifdef __NVIC_PRIO_BITS
{ {
/* Check the CMSIS configuration that defines the number of /* Check the CMSIS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
} }
#endif #endif
@ -330,29 +335,29 @@ BaseType_t xPortStartScheduler( void )
#ifdef configPRIO_BITS #ifdef configPRIO_BITS
{ {
/* Check the FreeRTOS configuration that defines the number of /* Check the FreeRTOS configuration that defines the number of
priority bits matches the number of priority bits actually queried * priority bits matches the number of priority bits actually queried
from the hardware. */ * from the hardware. */
configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
} }
#endif #endif
/* Shift the priority group value back to its position within the AIRCR /* Shift the priority group value back to its position within the AIRCR
register. */ * register. */
ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Make PendSV and SysTick the lowest priority interrupts. */ /* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled /* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */ * here already. */
vPortSetupTimerInterrupt(); vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */ /* Initialise the critical nesting count ready for the first task. */
@ -368,11 +373,11 @@ BaseType_t xPortStartScheduler( void )
prvPortStartFirstTask(); prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task /* 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 * exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this * not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call * functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the * vTaskSwitchContext() so link time optimisation does not remove the
symbol. */ * symbol. */
vTaskSwitchContext(); vTaskSwitchContext();
prvTaskExitError(); prvTaskExitError();
@ -384,7 +389,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( uxCriticalNesting == 1000UL ); configASSERT( uxCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -395,10 +400,10 @@ void vPortEnterCritical( void )
uxCriticalNesting++; uxCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so /* 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 * 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 * 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 * the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */ * assert function also uses a critical section. */
if( uxCriticalNesting == 1 ) if( uxCriticalNesting == 1 )
{ {
configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 ); configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
@ -410,6 +415,7 @@ void vPortExitCritical( void )
{ {
configASSERT( uxCriticalNesting ); configASSERT( uxCriticalNesting );
uxCriticalNesting--; uxCriticalNesting--;
if( uxCriticalNesting == 0 ) if( uxCriticalNesting == 0 )
{ {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();
@ -479,16 +485,16 @@ void xPortPendSVHandler( void )
void xPortSysTickHandler( void ) void xPortSysTickHandler( void )
{ {
/* The SysTick runs at the lowest interrupt priority, so when this interrupt /* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to * executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already * save and then restore the interrupt mask value as its value is already
known. */ * known. */
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
{ {
/* Increment the RTOS tick. */ /* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE ) if( xTaskIncrementTick() != pdFALSE )
{ {
/* A context switch is required. Context switching is performed in /* A context switch is required. Context switching is performed in
the PendSV interrupt. Pend the PendSV interrupt. */ * the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
} }
} }
@ -510,43 +516,44 @@ void xPortSysTickHandler( void )
} }
/* Stop the SysTick momentarily. The time the SysTick is stopped for /* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will * is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the * inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */ * kernel with respect to calendar time. */
portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
/* Calculate the reload value required to wait xExpectedIdleTime /* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way * tick periods. -1 is used because this code will execute part way
through one of the tick periods. */ * through one of the tick periods. */
ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) ); ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );
if( ulReloadValue > ulStoppedTimerCompensation ) if( ulReloadValue > ulStoppedTimerCompensation )
{ {
ulReloadValue -= ulStoppedTimerCompensation; ulReloadValue -= ulStoppedTimerCompensation;
} }
/* Enter a critical section but don't use the taskENTER_CRITICAL() /* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */ * method as that will mask interrupts that should exit sleep mode. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* If a context switch is pending or a task is waiting for the scheduler /* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */ * to be unsuspended then abandon the low power entry. */
if( eTaskConfirmSleepModeStatus() == eAbortSleep ) if( eTaskConfirmSleepModeStatus() == eAbortSleep )
{ {
/* Restart from whatever is left in the count register to complete /* Restart from whatever is left in the count register to complete
this tick period. */ * this tick period. */
portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Reset the reload register to the value required for normal tick /* Reset the reload register to the value required for normal tick
periods. */ * periods. */
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
/* Re-enable interrupts - see comments above the cpsid instruction() /* Re-enable interrupts - see comments above the cpsid instruction()
above. */ * above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
} }
else else
@ -555,69 +562,71 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulReloadValue; portNVIC_SYSTICK_LOAD_REG = ulReloadValue;
/* Clear the SysTick count flag and set the count value back to /* Clear the SysTick count flag and set the count value back to
zero. */ * zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
/* Restart SysTick. */ /* Restart SysTick. */
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains * set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi * its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle * should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */ * time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime; xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
if( xModifiableIdleTime > 0 ) if( xModifiableIdleTime > 0 )
{ {
__asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "dsb" ::: "memory" );
__asm volatile ( "wfi" ); __asm volatile ( "wfi" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts to allow the interrupt that brought the MCU /* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. see comments above * out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */ * __disable_interrupt() call above. */
__asm volatile ( "cpsie i" ::: "memory" ); __asm volatile ( "cpsie i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable interrupts again because the clock is about to be stopped /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase * and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar * any slippage between the time maintained by the RTOS and calendar
time. */ * time. */
__asm volatile ( "cpsid i" ::: "memory" ); __asm volatile ( "cpsid i" ::: "memory" );
__asm volatile ( "dsb" ); __asm volatile ( "dsb" );
__asm volatile ( "isb" ); __asm volatile ( "isb" );
/* Disable the SysTick clock without reading the /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the * portNVIC_SYSTICK_CTRL_REG register to ensure the
portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again, * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,
the time the SysTick is stopped for is accounted for as best it can * the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny * be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar * drift of the time maintained by the kernel with respect to calendar
time*/ * time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT ); portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and /* Determine if the SysTick clock has already counted to zero and
been set back to the current reload value (the reload back being * been set back to the current reload value (the reload back being
correct for the entire expected idle time) or if the SysTick is yet * correct for the entire expected idle time) or if the SysTick is yet
to count to zero (in which case an interrupt other than the SysTick * to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */ * must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt is already pending, and the SysTick count /* The tick interrupt is already pending, and the SysTick count
reloaded with ulReloadValue. Reset the * reloaded with ulReloadValue. Reset the
portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick * portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
period. */ * period. */
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
/* Don't allow a tiny value, or values that have somehow /* Don't allow a tiny value, or values that have somehow
underflowed because the post sleep hook did something * underflowed because the post sleep hook did something
that took too long. */ * that took too long. */
if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
{ {
ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
@ -626,30 +635,30 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* As the pending tick will be processed as soon as this /* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped * function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */ * forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
{ {
/* Something other than the tick interrupt ended the sleep. /* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick * Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part * periods (not the ulReload value which accounted for part
ticks). */ * ticks). */
ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG; ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
/* How many complete tick periods passed while the processor /* How many complete tick periods passed while the processor
was waiting? */ * was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick; ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick /* The reload value is set to whatever fraction of a single tick
period remains. */ * period remains. */
portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements; portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
} }
/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
again, then set portNVIC_SYSTICK_LOAD_REG back to its standard * again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
value. */ * value. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
@ -721,47 +730,45 @@ static void vPortEnableVFP( void )
ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Interrupts that use the FreeRTOS API must not be left at their * Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority, * default priority of zero as that is the highest possible priority,
which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
and therefore also guaranteed to be invalid. * and therefore also guaranteed to be invalid.
*
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. * interrupt entry is as fast and simple as possible.
*
The following links provide detailed information: * The following links provide detailed information:
http://www.freertos.org/RTOS-Cortex-M3-M4.html * http://www.freertos.org/RTOS-Cortex-M3-M4.html
http://www.freertos.org/FAQHelp.html */ * http://www.freertos.org/FAQHelp.html */
configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
} }
/* Priority grouping: The interrupt controller (NVIC) allows the bits /* Priority grouping: The interrupt controller (NVIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
*
If the application only uses CMSIS libraries for interrupt * If the application only uses CMSIS libraries for interrupt
configuration then the correct setting can be achieved on all Cortex-M * configuration then the correct setting can be achieved on all Cortex-M
devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
scheduler. Note however that some vendor specific peripheral libraries * scheduler. Note however that some vendor specific peripheral libraries
assume a non-zero priority group setting, in which cases using a value * assume a non-zero priority group setting, in which cases using a value
of zero will result in unpredictable behaviour. */ * of zero will result in unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */

View file

@ -64,7 +64,7 @@ typedef unsigned long UBaseType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */ * not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -83,7 +83,7 @@ typedef unsigned long UBaseType_t;
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\ \
/* Barriers are normally not required but do ensure the code is completely \ /* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */ \ * within the specified behaviour for the architecture. */ \
__asm volatile ( "dsb" ::: "memory" ); \ __asm volatile ( "dsb" ::: "memory" ); \
__asm volatile ( "isb" ); \ __asm volatile ( "isb" ); \
} }
@ -107,8 +107,8 @@ extern void vPortExitCritical( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
not necessary for to use this port. They are defined so the common demo files * not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ * (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -133,6 +133,7 @@ not necessary for to use this port. They are defined so the common demo files
uint8_t ucReturn; uint8_t ucReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" ); __asm volatile ( "clz %0, %1" : "=r" ( ucReturn ) : "r" ( ulBitmap ) : "memory" );
return ucReturn; return ucReturn;
} }
@ -224,7 +225,7 @@ uint32_t ulOriginalBASEPRI, ulNewBASEPRI;
); );
/* This return will not be reached but is necessary to prevent compiler /* This return will not be reached but is necessary to prevent compiler
warnings. */ * warnings. */
return ulOriginalBASEPRI; return ulOriginalBASEPRI;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -245,4 +246,3 @@ portFORCE_INLINE static void vPortSetBASEPRI( uint32_t ulNewMaskValue )
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -33,23 +33,23 @@
#include "task.h" #include "task.h"
#ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS #ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS
#error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. Refer to Cortex-A equivalent: http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html #error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. Refer to Cortex-A equivalent: http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */
#endif #endif
#ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET #ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET
#error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. Refer to Cortex-A equivalent: http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html #error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. Refer to Cortex-A equivalent: http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */
#endif #endif
#ifndef configUNIQUE_INTERRUPT_PRIORITIES #ifndef configUNIQUE_INTERRUPT_PRIORITIES
#error configUNIQUE_INTERRUPT_PRIORITIES must be defined. Refer to Cortex-A equivalent: http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html #error configUNIQUE_INTERRUPT_PRIORITIES must be defined. Refer to Cortex-A equivalent: http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */
#endif #endif
#ifndef configSETUP_TICK_INTERRUPT #ifndef configSETUP_TICK_INTERRUPT
#error configSETUP_TICK_INTERRUPT() must be defined. Refer to Cortex-A equivalent: http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html #error configSETUP_TICK_INTERRUPT() must be defined. Refer to Cortex-A equivalent: http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */
#endif /* configSETUP_TICK_INTERRUPT */ #endif /* configSETUP_TICK_INTERRUPT */
#ifndef configMAX_API_CALL_INTERRUPT_PRIORITY #ifndef configMAX_API_CALL_INTERRUPT_PRIORITY
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. Refer to Cortex-A equivalent: http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html #error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. Refer to Cortex-A equivalent: http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */
#endif #endif
#if configMAX_API_CALL_INTERRUPT_PRIORITY == 0 #if configMAX_API_CALL_INTERRUPT_PRIORITY == 0
@ -73,24 +73,24 @@
#endif #endif
/* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in /* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
portmacro.h. */ * portmacro.h. */
#ifndef configCLEAR_TICK_INTERRUPT #ifndef configCLEAR_TICK_INTERRUPT
#define configCLEAR_TICK_INTERRUPT() #define configCLEAR_TICK_INTERRUPT()
#endif #endif
/* A critical section is exited when the critical section nesting count reaches /* A critical section is exited when the critical section nesting count reaches
this value. */ * this value. */
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 ) #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
/* In all GICs 255 can be written to the priority mask register to unmask all /* In all GICs 255 can be written to the priority mask register to unmask all
(but the lowest) interrupt priority. */ * (but the lowest) interrupt priority. */
#define portUNMASK_VALUE ( 0xFFUL ) #define portUNMASK_VALUE ( 0xFFUL )
/* Tasks are not created with a floating point context, but can be given a /* Tasks are not created with a floating point context, but can be given a
floating point context after they have been created. A variable is stored as * 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 * 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 * does not have an FPU context, or any other value if the task does have an FPU
context. */ * context. */
#define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 ) #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
/* Constants required to setup the initial task context. */ /* Constants required to setup the initial task context. */
@ -100,19 +100,19 @@ context. */
#define portTHUMB_MODE_ADDRESS ( 0x01UL ) #define portTHUMB_MODE_ADDRESS ( 0x01UL )
/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary /* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
point is zero. */ * point is zero. */
#define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 ) #define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
/* Masks all bits in the APSR other than the mode bits. */ /* Masks all bits in the APSR other than the mode bits. */
#define portAPSR_MODE_BITS_MASK ( 0x1F ) #define portAPSR_MODE_BITS_MASK ( 0x1F )
/* The value of the mode bits in the APSR when the CPU is executing in user /* The value of the mode bits in the APSR when the CPU is executing in user
mode. */ * mode. */
#define portAPSR_USER_MODE ( 0x10 ) #define portAPSR_USER_MODE ( 0x10 )
/* The critical section macros only mask interrupts up to an application /* The critical section macros only mask interrupts up to an application
determined priority level. Sometimes it is necessary to turn interrupt off in * determined priority level. Sometimes it is necessary to turn interrupt off in
the CPU itself before modifying certain hardware registers. */ * the CPU itself before modifying certain hardware registers. */
#define portCPU_IRQ_DISABLE() \ #define portCPU_IRQ_DISABLE() \
__asm volatile ( "CPSID i" ::: "memory" ); \ __asm volatile ( "CPSID i" ::: "memory" ); \
__asm volatile ( "DSB" ); \ __asm volatile ( "DSB" ); \
@ -139,14 +139,27 @@ the CPU itself before modifying certain hardware registers. */
#define portBIT_0_SET ( ( uint8_t ) 0x01 ) #define portBIT_0_SET ( ( uint8_t ) 0x01 )
/* Let the user override the pre-loading of the initial LR with the address of /* 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 * prvTaskExitError() in case is messes up unwinding of the stack in the
debugger. */ * debugger. */
#ifdef configTASK_RETURN_ADDRESS #ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else #else
#define portTASK_RETURN_ADDRESS prvTaskExitError #define portTASK_RETURN_ADDRESS prvTaskExitError
#endif #endif
/* Adding the necessary stuff in order to be able to determine from C code wheter or not the IRQs are enabled at the processor level (not interrupt controller level) */
#define GET_CPSR() ({u32 rval = 0U; \
__asm__ __volatile__(\
"mrs %0, cpsr\n"\
: "=r" (rval)\
);\
rval;\
})
#define CPSR_IRQ_ENABLE_MASK 0x80U
#define IS_IRQ_DISABLED() ({unsigned int val = 0; val = (GET_CPSR() & CPSR_IRQ_ENABLE_MASK) ? 1 : 0; val;})
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -163,21 +176,21 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* A variable is used to keep track of the critical section nesting. This /* A variable is used to keep track of the critical section nesting. This
variable has to be stored as part of the task context and must be initialised to * 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 * 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 * 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. */ * automatically be set to 0 when the first task is started. */
volatile uint32_t ulCriticalNesting = 9999UL; volatile uint32_t ulCriticalNesting = 9999UL;
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then /* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
a floating point context must be saved and restored for the task. */ * a floating point context must be saved and restored for the task. */
uint32_t ulPortTaskHasFPUContext = pdFALSE; uint32_t ulPortTaskHasFPUContext = pdFALSE;
/* Set to 1 to pend a context switch from an ISR. */ /* Set to 1 to pend a context switch from an ISR. */
uint32_t ulPortYieldRequired = pdFALSE; uint32_t ulPortYieldRequired = pdFALSE;
/* Counts the interrupt nesting depth. A context switch is only performed if /* Counts the interrupt nesting depth. A context switch is only performed if
if the nesting depth is 0. */ * if the nesting depth is 0. */
uint32_t ulPortInterruptNesting = 0UL; uint32_t ulPortInterruptNesting = 0UL;
/* Used in asm code. */ /* Used in asm code. */
@ -191,14 +204,16 @@ __attribute__(( used )) const uint32_t ulMaxAPIPriorityMask = ( configMAX_API_CA
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters )
{ {
/* Setup the initial stack of the task. The stack is set exactly as /* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT() macro. * expected by the portRESTORE_CONTEXT() macro.
*
The fist real value on the stack is the status register, which is set for * 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 * system mode, with interrupts enabled. A few NULLs are added first to ensure
GDB does not try decoding a non-existent return address. */ * GDB does not try decoding a non-existent return address. */
*pxTopOfStack = ( StackType_t ) NULL; *pxTopOfStack = ( StackType_t ) NULL;
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) NULL; *pxTopOfStack = ( StackType_t ) NULL;
@ -250,13 +265,13 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
pxTopOfStack--; pxTopOfStack--;
/* The task will start with a critical nesting count of 0 as interrupts are /* The task will start with a critical nesting count of 0 as interrupts are
enabled. */ * enabled. */
*pxTopOfStack = portNO_CRITICAL_NESTING; *pxTopOfStack = portNO_CRITICAL_NESTING;
pxTopOfStack--; pxTopOfStack--;
/* The task will start without a floating point context. A task that uses /* The task will start without a floating point context. A task that uses
the floating point hardware must call vPortTaskUsesFPU() before executing * the floating point hardware must call vPortTaskUsesFPU() before executing
any floating point instructions. */ * any floating point instructions. */
*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT; *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
return pxTopOfStack; return pxTopOfStack;
@ -266,14 +281,17 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
static void prvTaskExitError( void ) static void prvTaskExitError( void )
{ {
/* A function that implements a task must not exit or attempt to return to /* 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 * its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ). * should instead call vTaskDelete( NULL ).
*
Artificially force an assert() to be triggered if configASSERT() is * Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */ * defined, then stop here so application writers can catch the error. */
configASSERT( ulPortInterruptNesting == ~0UL ); configASSERT( ulPortInterruptNesting == ~0UL );
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
for( ;; );
for( ; ; )
{
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -288,12 +306,12 @@ uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
volatile uint8_t ucMaxPriorityValue; volatile uint8_t ucMaxPriorityValue;
/* Determine how many priority bits are implemented in the GIC. /* Determine how many priority bits are implemented in the GIC.
*
Save the interrupt priority value that is about to be clobbered. */ * Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister; ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to /* Determine the number of priority bits available. First write to
all possible bits. */ * all possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
@ -305,8 +323,9 @@ uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
ucMaxPriorityValue >>= ( uint8_t ) 0x01; ucMaxPriorityValue >>= ( uint8_t ) 0x01;
/* If ulCycles reaches 0 then ucMaxPriorityValue must have been /* If ulCycles reaches 0 then ucMaxPriorityValue must have been
read as 0, indicating a misconfiguration. */ * read as 0, indicating a misconfiguration. */
ulCycles--; ulCycles--;
if( ulCycles == 0 ) if( ulCycles == 0 )
{ {
break; break;
@ -314,17 +333,17 @@ uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
} }
/* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read /* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
value. */ * value. */
configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY ); configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );
/* Restore the clobbered interrupt priority register to its original /* Restore the clobbered interrupt priority register to its original
value. */ * value. */
*pucFirstUserPriorityRegister = ulOriginalPriority; *pucFirstUserPriorityRegister = ulOriginalPriority;
} }
#endif /* conifgASSERT_DEFINED */ #endif /* conifgASSERT_DEFINED */
/* Only continue if the CPU is not in User mode. The CPU must be in a /* Only continue if the CPU is not in User mode. The CPU must be in a
Privileged mode for the scheduler to start. */ * Privileged mode for the scheduler to start. */
__asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" ); __asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" );
ulAPSR &= portAPSR_MODE_BITS_MASK; ulAPSR &= portAPSR_MODE_BITS_MASK;
configASSERT( ulAPSR != portAPSR_USER_MODE ); configASSERT( ulAPSR != portAPSR_USER_MODE );
@ -332,16 +351,16 @@ uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
if( ulAPSR != portAPSR_USER_MODE ) if( ulAPSR != portAPSR_USER_MODE )
{ {
/* Only continue if the binary point value is set to its lowest possible /* Only continue if the binary point value is set to its lowest possible
setting. See the comments in vPortValidateInterruptPriority() below for * setting. See the comments in vPortValidateInterruptPriority() below for
more information. */ * more information. */
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ); configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ) if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
{ {
/* Interrupts are turned off in the CPU itself to ensure tick does /* Interrupts are turned off in the CPU itself to ensure tick does
not execute while the scheduler is being started. Interrupts are * not execute while the scheduler is being started. Interrupts are
automatically turned back on in the CPU when the first task starts * automatically turned back on in the CPU when the first task starts
executing. */ * executing. */
portCPU_IRQ_DISABLE(); portCPU_IRQ_DISABLE();
/* Start the timer that generates the tick ISR. */ /* Start the timer that generates the tick ISR. */
@ -353,10 +372,10 @@ uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
} }
/* Will only get here if vTaskStartScheduler() was called with the CPU in /* 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 * a non-privileged mode or the binary point register was not set to its lowest
possible value. prvTaskExitError() is referenced to prevent a compiler * possible value. prvTaskExitError() is referenced to prevent a compiler
warning about it being defined but not referenced in the case that the user * warning about it being defined but not referenced in the case that the user
defines their own exit address. */ * defines their own exit address. */
( void ) prvTaskExitError; ( void ) prvTaskExitError;
return 0; return 0;
} }
@ -365,7 +384,7 @@ uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */ * Artificially force an assert. */
configASSERT( ulCriticalNesting == 1000UL ); configASSERT( ulCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -376,15 +395,15 @@ void vPortEnterCritical( void )
ulPortSetInterruptMask(); ulPortSetInterruptMask();
/* Now interrupts are disabled ulCriticalNesting can be accessed /* Now interrupts are disabled ulCriticalNesting can be accessed
directly. Increment ulCriticalNesting to keep a count of how many times * directly. Increment ulCriticalNesting to keep a count of how many times
portENTER_CRITICAL() has been called. */ * portENTER_CRITICAL() has been called. */
ulCriticalNesting++; ulCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so /* 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 * 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 * 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 * the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */ * assert function also uses a critical section. */
if( ulCriticalNesting == 1 ) if( ulCriticalNesting == 1 )
{ {
configASSERT( ulPortInterruptNesting == 0 ); configASSERT( ulPortInterruptNesting == 0 );
@ -397,15 +416,15 @@ void vPortExitCritical( void )
if( ulCriticalNesting > portNO_CRITICAL_NESTING ) if( ulCriticalNesting > portNO_CRITICAL_NESTING )
{ {
/* Decrement the nesting count as the critical section is being /* Decrement the nesting count as the critical section is being
exited. */ * exited. */
ulCriticalNesting--; ulCriticalNesting--;
/* If the nesting level has reached zero then all interrupt /* If the nesting level has reached zero then all interrupt
priorities must be re-enabled. */ * priorities must be re-enabled. */
if( ulCriticalNesting == portNO_CRITICAL_NESTING ) if( ulCriticalNesting == portNO_CRITICAL_NESTING )
{ {
/* Critical nesting has reached zero so all interrupt priorities /* Critical nesting has reached zero so all interrupt priorities
should be unmasked. */ * should be unmasked. */
portCLEAR_INTERRUPT_MASK(); portCLEAR_INTERRUPT_MASK();
} }
} }
@ -415,10 +434,10 @@ void vPortExitCritical( void )
void FreeRTOS_Tick_Handler( void ) void FreeRTOS_Tick_Handler( void )
{ {
/* Set interrupt mask before altering scheduler structures. The tick /* Set interrupt mask before altering scheduler structures. The tick
handler runs at the lowest priority, so interrupts cannot already be masked, * handler runs at the lowest priority, so interrupts cannot already be masked,
so there is no need to save and restore the current mask value. It is * so there is no need to save and restore the current mask value. It is
necessary to turn off interrupts in the CPU itself while the ICCPMR is being * necessary to turn off interrupts in the CPU itself while the ICCPMR is being
updated. */ * updated. */
portCPU_IRQ_DISABLE(); portCPU_IRQ_DISABLE();
portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
__asm volatile ( "dsb \n" __asm volatile ( "dsb \n"
@ -442,7 +461,7 @@ void vPortTaskUsesFPU( void )
uint32_t ulInitialFPSCR = 0; uint32_t ulInitialFPSCR = 0;
/* A task is registering the fact that it needs an FPU context. Set the /* 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). */ * FPU flag (which is saved as part of the task context). */
ulPortTaskHasFPUContext = pdTRUE; ulPortTaskHasFPUContext = pdTRUE;
/* Initialise the floating point status register. */ /* Initialise the floating point status register. */
@ -462,10 +481,17 @@ void vPortClearInterruptMask( uint32_t ulNewMaskValue )
uint32_t ulPortSetInterruptMask( void ) uint32_t ulPortSetInterruptMask( void )
{ {
uint32_t ulReturn; uint32_t ulReturn;
uint32_t wasIRQDisabled;
/* We keep track of if the IRQ are enabled in the CPU (as opposed to interrupts masked in the interrupt controller, like the intend of this function).
* This is very important because when the CPU is interrupted, among other things, the hardware clears the IRQ Enable bit in the CPSR of the IRQ CPU Mode in which
* we enter. */
wasIRQDisabled = IS_IRQ_DISABLED();
/* Interrupt in the CPU must be turned off while the ICCPMR is being /* Interrupt in the CPU must be turned off while the ICCPMR is being
updated. */ * updated. */
portCPU_IRQ_DISABLE(); portCPU_IRQ_DISABLE();
if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ) if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
{ {
/* Interrupts were already masked. */ /* Interrupts were already masked. */
@ -478,6 +504,18 @@ uint32_t ulReturn;
__asm volatile ( "dsb \n" __asm volatile ( "dsb \n"
"isb \n"::: "memory" ); "isb \n"::: "memory" );
} }
/* Just like this function returns a value of wether or not the interrupts where masked in the interrupt controller in order to avoid race condition when
* calling its matching vPortClearInterruptMask function, we needed a 'wasIRQDisabled' variable holding the state of the IRQ Enable bit in the CPSR in order
* to leave that bit in it's original state. Like mentioned above, hardware automatically clear the IRQEnable bit upon trapping into IRQ Mode, so the programmer
* cannot make assumption about it's state. Very rare, but very important race condition is avoided with this when this function is called in an ISR. The race
* condition in question was discovered when integrating tracealyzer code. Inside the function 'void vTaskSwitchContext( void )' in tasks.c, there is a macro 'traceTASK_SWITCHED_IN();'
* which gets replaced by something when using the tracing capabilities. That macro protects some critical section with matching calls to 'ulPortSetInterruptMask'
* and 'vPortClearInterruptMask'. At the time of calling those functions, the interrupt mask is not set in the interrupt controller, thus the only protecting barrier
* against the CPU traping into recursive interrupt was the IRQ Enable bit in the CPSR. By not taking it into acount, the very code that protects the CPU against
* critical section violation just enabled it to happen : A SysTick was waiting to happen, and calling 'portCPU_IRQ_ENABLE' would enable it to occur... Thus triggering a
* switch of context while already performing a switch context. */
if(!wasIRQDisabled)
portCPU_IRQ_ENABLE(); portCPU_IRQ_ENABLE();
return ulReturn; return ulReturn;
@ -489,37 +527,34 @@ uint32_t ulReturn;
void vPortValidateInterruptPriority( void ) void vPortValidateInterruptPriority( void )
{ {
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above * an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called * function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below * from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
Numerically low interrupt priority numbers represent logically high * Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must * interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than * be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
FreeRTOS maintains separate thread and ISR API functions to ensure * FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. */ * interrupt entry is as fast and simple as possible. */
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ); configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
/* Priority grouping: The interrupt controller (GIC) allows the bits /* Priority grouping: The interrupt controller (GIC) allows the bits
that define each interrupt's priority to be split between bits that * that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define * define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined * the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if * to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority). * this is not the case (if some bits represent a sub-priority).
*
The priority grouping is configured by the GIC's binary point register * The priority grouping is configured by the GIC's binary point register
(ICCBPR). Writing 0 to ICCBPR will ensure it is set to its lowest * (ICCBPR). Writing 0 to ICCBPR will ensure it is set to its lowest
possible value (which may be above 0). */ * possible value (which may be above 0). */
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ); configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -95,7 +95,7 @@ extern void vPortClearInterruptMask( uint32_t ulNewMaskValue );
extern void vPortInstallFreeRTOSVectorTable( void ); extern void vPortInstallFreeRTOSVectorTable( void );
/* These macros do not globally disable/enable interrupts. They do mask off /* These macros do not globally disable/enable interrupts. They do mask off
interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */ * interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */
#define portENTER_CRITICAL() vPortEnterCritical(); #define portENTER_CRITICAL() vPortEnterCritical();
#define portEXIT_CRITICAL() vPortExitCritical(); #define portEXIT_CRITICAL() vPortExitCritical();
#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
@ -106,17 +106,17 @@ interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
not required for this port but included in case common demo code that uses these * not required for this port but included in case common demo code that uses these
macros is used. */ * macros is used. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/* Prototype of the FreeRTOS tick handler. This must be installed as the /* Prototype of the FreeRTOS tick handler. This must be installed as the
handler for whichever peripheral is used to generate the RTOS tick. */ * handler for whichever peripheral is used to generate the RTOS tick. */
void FreeRTOS_Tick_Handler( void ); void FreeRTOS_Tick_Handler( void );
/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU() /* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()
before any floating point instructions are executed. */ * before any floating point instructions are executed. */
void vPortTaskUsesFPU( void ); void vPortTaskUsesFPU( void );
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU() #define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
@ -154,7 +154,7 @@ void vPortTaskUsesFPU( void );
/* The number of bits to shift for an interrupt priority is dependent on the /* The number of bits to shift for an interrupt priority is dependent on the
number of bits implemented by the interrupt controller. */ * number of bits implemented by the interrupt controller. */
#if configUNIQUE_INTERRUPT_PRIORITIES == 16 #if configUNIQUE_INTERRUPT_PRIORITIES == 16
#define portPRIORITY_SHIFT 4 #define portPRIORITY_SHIFT 4
#define portMAX_BINARY_POINT_VALUE 3 #define portMAX_BINARY_POINT_VALUE 3
@ -170,9 +170,9 @@ number of bits implemented by the interrupt controller. */
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256 #elif configUNIQUE_INTERRUPT_PRIORITIES == 256
#define portPRIORITY_SHIFT 0 #define portPRIORITY_SHIFT 0
#define portMAX_BINARY_POINT_VALUE 0 #define portMAX_BINARY_POINT_VALUE 0
#else #else /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware #error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
#endif #endif /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */
/* Interrupt controller access addresses. */ /* Interrupt controller access addresses. */
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 ) #define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
@ -192,4 +192,3 @@ number of bits implemented by the interrupt controller. */
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" ) #define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -57,10 +57,10 @@
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The code generated by the Keil compiler does not maintain separate /* The code generated by the Keil compiler does not maintain separate
* stack and frame pointers. The portENTER_CRITICAL macro cannot therefore stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
* use the stack as per other ports. Instead a variable is used to keep use the stack as per other ports. Instead a variable is used to keep
* track of the critical section nesting. This variable has to be stored track of the critical section nesting. This variable has to be stored
* as part of the task context and must be initialised to a non zero value. */ as part of the task context and must be initialised to a non zero value. */
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 ) #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
volatile uint32_t ulCriticalNesting = 9999UL; volatile uint32_t ulCriticalNesting = 9999UL;
@ -81,26 +81,24 @@ extern __asm void vPortStartFirstTask( void );
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
TaskFunction_t pxCode,
void * pvParameters )
{ {
StackType_t *pxOriginalTOS; StackType_t *pxOriginalTOS;
/* Setup the initial stack of the task. The stack is set exactly as /* Setup the initial stack of the task. The stack is set exactly as
* expected by the portRESTORE_CONTEXT() macro. expected by the portRESTORE_CONTEXT() macro.
*
* Remember where the top of the (simulated) stack is before we place Remember where the top of the (simulated) stack is before we place
* anything on it. */ anything on it. */
pxOriginalTOS = pxTopOfStack; pxOriginalTOS = pxTopOfStack;
/* To ensure asserts in tasks.c don't fail, although in this case the assert /* To ensure asserts in tasks.c don't fail, although in this case the assert
* is not really required. */ is not really required. */
pxTopOfStack--; pxTopOfStack--;
/* First on the stack is the return address - which in this case is the /* First on the stack is the return address - which in this case is the
* start of the task. The offset is added to make the return address appear start of the task. The offset is added to make the return address appear
* as it would within an IRQ ISR. */ as it would within an IRQ ISR. */
*pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE; *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
pxTopOfStack--; pxTopOfStack--;
@ -136,7 +134,7 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
pxTopOfStack--; pxTopOfStack--;
/* The last thing onto the stack is the status register, which is set for /* The last thing onto the stack is the status register, which is set for
* system mode, with interrupts enabled. */ system mode, with interrupts enabled. */
*pxTopOfStack = ( StackType_t ) portINITIAL_SPSR; *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00UL ) if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00UL )
@ -148,10 +146,10 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
pxTopOfStack--; pxTopOfStack--;
/* The code generated by the Keil compiler does not maintain separate /* The code generated by the Keil compiler does not maintain separate
* stack and frame pointers. The portENTER_CRITICAL macro cannot therefore stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
* use the stack as per other ports. Instead a variable is used to keep use the stack as per other ports. Instead a variable is used to keep
* track of the critical section nesting. This variable has to be stored track of the critical section nesting. This variable has to be stored
* as part of the task context and is initially set to zero. */ as part of the task context and is initially set to zero. */
*pxTopOfStack = portNO_CRITICAL_SECTION_NESTING; *pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;
return pxTopOfStack; return pxTopOfStack;
@ -164,7 +162,7 @@ BaseType_t xPortStartScheduler( void )
prvSetupTimerInterrupt(); prvSetupTimerInterrupt();
/* Start the first task. This is done from portISR.c as ARM mode must be /* Start the first task. This is done from portISR.c as ARM mode must be
* used. */ used. */
vPortStartFirstTask(); vPortStartFirstTask();
/* Should not get here! */ /* Should not get here! */
@ -175,8 +173,8 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* It is unlikely that the ARM port will require this function as there /* It is unlikely that the ARM port will require this function as there
* is nothing to return to. If this is required - stop the tick ISR then is nothing to return to. If this is required - stop the tick ISR then
* return back to main. */ return back to main. */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -190,14 +188,14 @@ void vPortEndScheduler( void )
void vNonPreemptiveTick( void ) __irq void vNonPreemptiveTick( void ) __irq
{ {
/* Increment the tick count - this may make a delaying task ready /* Increment the tick count - this may make a delaying task ready
* to run - but a context switch is not performed. */ to run - but a context switch is not performed. */
xTaskIncrementTick(); xTaskIncrementTick();
T0IR = portTIMER_MATCH_ISR_BIT; /* Clear the timer event */ T0IR = portTIMER_MATCH_ISR_BIT; /* Clear the timer event */
VICVectAddr = portCLEAR_VIC_INTERRUPT; /* Acknowledge the Interrupt */ VICVectAddr = portCLEAR_VIC_INTERRUPT; /* Acknowledge the Interrupt */
} }
#else /* if configUSE_PREEMPTION == 0 */ #else
/* /*
************************************************************************** **************************************************************************
@ -209,7 +207,7 @@ void vPortEndScheduler( void )
void vPreemptiveTick( void ); void vPreemptiveTick( void );
#endif /* if configUSE_PREEMPTION == 0 */ #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvSetupTimerInterrupt( void ) static void prvSetupTimerInterrupt( void )
@ -217,14 +215,14 @@ static void prvSetupTimerInterrupt( void )
uint32_t ulCompareMatch; uint32_t ulCompareMatch;
/* A 1ms tick does not require the use of the timer prescale. This is /* A 1ms tick does not require the use of the timer prescale. This is
* defaulted to zero but can be used if necessary. */ defaulted to zero but can be used if necessary. */
T0PR = portPRESCALE_VALUE; T0PR = portPRESCALE_VALUE;
/* Calculate the match value required for our wanted tick rate. */ /* Calculate the match value required for our wanted tick rate. */
ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ; ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
/* Protect against divide by zero. Using an if() statement still results /* Protect against divide by zero. Using an if() statement still results
* in a warning - hence the #if. */ in a warning - hence the #if. */
#if portPRESCALE_VALUE != 0 #if portPRESCALE_VALUE != 0
{ {
ulCompareMatch /= ( portPRESCALE_VALUE + 1 ); ulCompareMatch /= ( portPRESCALE_VALUE + 1 );
@ -241,7 +239,7 @@ static void prvSetupTimerInterrupt( void )
VICIntEnable |= portTIMER_VIC_CHANNEL_BIT; VICIntEnable |= portTIMER_VIC_CHANNEL_BIT;
/* The ISR installed depends on whether the preemptive or cooperative /* The ISR installed depends on whether the preemptive or cooperative
* scheduler is being used. */ scheduler is being used. */
#if configUSE_PREEMPTION == 1 #if configUSE_PREEMPTION == 1
{ {
VICVectAddr0 = ( uint32_t ) vPreemptiveTick; VICVectAddr0 = ( uint32_t ) vPreemptiveTick;
@ -255,7 +253,7 @@ static void prvSetupTimerInterrupt( void )
VICVectCntl0 = portTIMER_VIC_CHANNEL | portTIMER_VIC_ENABLE; VICVectCntl0 = portTIMER_VIC_CHANNEL | portTIMER_VIC_ENABLE;
/* Start the timer - interrupts are disabled when this function is called /* Start the timer - interrupts are disabled when this function is called
* so it is okay to do this here. */ so it is okay to do this here. */
T0TCR = portENABLE_TIMER; T0TCR = portENABLE_TIMER;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -266,8 +264,8 @@ void vPortEnterCritical( void )
__disable_irq(); __disable_irq();
/* Now interrupts are disabled ulCriticalNesting can be accessed /* Now interrupts are disabled ulCriticalNesting can be accessed
* directly. Increment ulCriticalNesting to keep a count of how many times directly. Increment ulCriticalNesting to keep a count of how many times
* portENTER_CRITICAL() has been called. */ portENTER_CRITICAL() has been called. */
ulCriticalNesting++; ulCriticalNesting++;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -280,7 +278,7 @@ void vPortExitCritical( void )
ulCriticalNesting--; ulCriticalNesting--;
/* If the nesting level has reached zero then interrupts should be /* If the nesting level has reached zero then interrupts should be
* re-enabled. */ re-enabled. */
if( ulCriticalNesting == portNO_CRITICAL_NESTING ) if( ulCriticalNesting == portNO_CRITICAL_NESTING )
{ {
/* Enable interrupts as per portEXIT_CRITICAL(). */ /* Enable interrupts as per portEXIT_CRITICAL(). */
@ -289,3 +287,5 @@ void vPortExitCritical( void )
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -143,3 +143,4 @@
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -33,23 +33,23 @@
#include "task.h" #include "task.h"
#ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS #ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS
#error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. See http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */ #error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif #endif
#ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET #ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET
#error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. See http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */ #error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif #endif
#ifndef configUNIQUE_INTERRUPT_PRIORITIES #ifndef configUNIQUE_INTERRUPT_PRIORITIES
#error configUNIQUE_INTERRUPT_PRIORITIES must be defined. See http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */ #error configUNIQUE_INTERRUPT_PRIORITIES must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif #endif
#ifndef configSETUP_TICK_INTERRUPT #ifndef configSETUP_TICK_INTERRUPT
#error configSETUP_TICK_INTERRUPT() must be defined. See http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */ #error configSETUP_TICK_INTERRUPT() must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif /* configSETUP_TICK_INTERRUPT */ #endif /* configSETUP_TICK_INTERRUPT */
#ifndef configMAX_API_CALL_INTERRUPT_PRIORITY #ifndef configMAX_API_CALL_INTERRUPT_PRIORITY
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. See http: /*www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html */ #error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif #endif
#if configMAX_API_CALL_INTERRUPT_PRIORITY == 0 #if configMAX_API_CALL_INTERRUPT_PRIORITY == 0
@ -77,7 +77,7 @@
#endif #endif
/* The number of bits to shift for an interrupt priority is dependent on the /* The number of bits to shift for an interrupt priority is dependent on the
* number of bits implemented by the interrupt controller. */ number of bits implemented by the interrupt controller. */
#if configUNIQUE_INTERRUPT_PRIORITIES == 16 #if configUNIQUE_INTERRUPT_PRIORITIES == 16
#define portPRIORITY_SHIFT 4 #define portPRIORITY_SHIFT 4
#define portMAX_BINARY_POINT_VALUE 3 #define portMAX_BINARY_POINT_VALUE 3
@ -93,23 +93,23 @@
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256 #elif configUNIQUE_INTERRUPT_PRIORITIES == 256
#define portPRIORITY_SHIFT 0 #define portPRIORITY_SHIFT 0
#define portMAX_BINARY_POINT_VALUE 0 #define portMAX_BINARY_POINT_VALUE 0
#else /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */ #else
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware #error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
#endif /* if configUNIQUE_INTERRUPT_PRIORITIES == 16 */ #endif
/* A critical section is exited when the critical section nesting count reaches /* A critical section is exited when the critical section nesting count reaches
* this value. */ this value. */
#define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 ) #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
/* In all GICs 255 can be written to the priority mask register to unmask all /* In all GICs 255 can be written to the priority mask register to unmask all
* (but the lowest) interrupt priority. */ (but the lowest) interrupt priority. */
#define portUNMASK_VALUE ( 0xFFUL ) #define portUNMASK_VALUE ( 0xFFUL )
/* Tasks are not created with a floating point context, but can be given a /* Tasks are not created with a floating point context, but can be given a
* floating point context after they have been created. A variable is stored as 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 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 does not have an FPU context, or any other value if the task does have an FPU
* context. */ context. */
#define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 ) #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
/* Interrupt controller access addresses. */ /* Interrupt controller access addresses. */
@ -127,7 +127,7 @@
#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) ) #define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary /* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
* point is zero. */ point is zero. */
#define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 ) #define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
/* Constants required to setup the initial task context. */ /* Constants required to setup the initial task context. */
@ -139,7 +139,7 @@
#define portAPSR_MODE_BITS_MASK ( 0x1F ) #define portAPSR_MODE_BITS_MASK ( 0x1F )
/* The value of the mode bits in the APSR when the CPU is executing in user /* The value of the mode bits in the APSR when the CPU is executing in user
* mode. */ mode. */
#define portAPSR_USER_MODE ( 0x10 ) #define portAPSR_USER_MODE ( 0x10 )
/* Macro to unmask all interrupt priorities. */ /* Macro to unmask all interrupt priorities. */
@ -168,29 +168,29 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* A variable is used to keep track of the critical section nesting. This /* A variable is used to keep track of the critical section nesting. This
* variable has to be stored as part of the task context and must be initialised to 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 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 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. */ automatically be set to 0 when the first task is started. */
volatile uint32_t ulCriticalNesting = 9999UL; volatile uint32_t ulCriticalNesting = 9999UL;
/* Used to pass constants into the ASM code. The address at which variables are /* Used to pass constants into the ASM code. The address at which variables are
* placed is the constant value so indirect loads in the asm code are not placed is the constant value so indirect loads in the asm code are not
* required. */ required. */
uint32_t ulICCIAR __attribute__( ( at( portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ) ) ); uint32_t ulICCIAR __attribute__( ( at( portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ) ) );
uint32_t ulICCEOIR __attribute__( ( at( portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ) ) ); uint32_t ulICCEOIR __attribute__( ( at( portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ) ) );
uint32_t ulICCPMR __attribute__( ( at( portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ) ) ); uint32_t ulICCPMR __attribute__( ( at( portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ) ) );
uint32_t ulAsmAPIPriorityMask __attribute__( ( at( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ) ); uint32_t ulAsmAPIPriorityMask __attribute__( ( at( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ) );
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then /* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
* a floating point context must be saved and restored for the task. */ a floating point context must be saved and restored for the task. */
uint32_t ulPortTaskHasFPUContext = pdFALSE; uint32_t ulPortTaskHasFPUContext = pdFALSE;
/* Set to 1 to pend a context switch from an ISR. */ /* Set to 1 to pend a context switch from an ISR. */
uint32_t ulPortYieldRequired = pdFALSE; uint32_t ulPortYieldRequired = pdFALSE;
/* Counts the interrupt nesting depth. A context switch is only performed if /* Counts the interrupt nesting depth. A context switch is only performed if
* if the nesting depth is 0. */ if the nesting depth is 0. */
uint32_t ulPortInterruptNesting = 0UL; uint32_t ulPortInterruptNesting = 0UL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -198,16 +198,14 @@ uint32_t ulPortInterruptNesting = 0UL;
/* /*
* See header file for description. * See header file for description.
*/ */
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
TaskFunction_t pxCode,
void * pvParameters )
{ {
/* Setup the initial stack of the task. The stack is set exactly as /* Setup the initial stack of the task. The stack is set exactly as
* expected by the portRESTORE_CONTEXT() macro. expected by the portRESTORE_CONTEXT() macro.
*
* The fist real value on the stack is the status register, which is set for 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 system mode, with interrupts enabled. A few NULLs are added first to ensure
* GDB does not try decoding a non-existent return address. */ GDB does not try decoding a non-existent return address. */
*pxTopOfStack = NULL; *pxTopOfStack = NULL;
pxTopOfStack--; pxTopOfStack--;
*pxTopOfStack = NULL; *pxTopOfStack = NULL;
@ -259,13 +257,13 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
pxTopOfStack--; pxTopOfStack--;
/* The task will start with a critical nesting count of 0 as interrupts are /* The task will start with a critical nesting count of 0 as interrupts are
* enabled. */ enabled. */
*pxTopOfStack = portNO_CRITICAL_NESTING; *pxTopOfStack = portNO_CRITICAL_NESTING;
pxTopOfStack--; pxTopOfStack--;
/* The task will start without a floating point context. A task that uses /* The task will start without a floating point context. A task that uses
* the floating point hardware must call vPortTaskUsesFPU() before executing the floating point hardware must call vPortTaskUsesFPU() before executing
* any floating point instructions. */ any floating point instructions. */
*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT; *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
return pxTopOfStack; return pxTopOfStack;
@ -275,17 +273,14 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
static void prvTaskExitError( void ) static void prvTaskExitError( void )
{ {
/* A function that implements a task must not exit or attempt to return to /* 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 its caller as there is nothing to return to. If a task wants to exit it
* should instead call vTaskDelete( NULL ). should instead call vTaskDelete( NULL ).
*
* Artificially force an assert() to be triggered if configASSERT() is Artificially force an assert() to be triggered if configASSERT() is
* defined, then stop here so application writers can catch the error. */ defined, then stop here so application writers can catch the error. */
configASSERT( ulPortInterruptNesting == ~0UL ); configASSERT( ulPortInterruptNesting == ~0UL );
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
for( ;; );
for( ; ; )
{
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -294,7 +289,7 @@ BaseType_t xPortStartScheduler( void )
uint32_t ulAPSR; uint32_t ulAPSR;
/* Only continue if the CPU is not in User mode. The CPU must be in a /* Only continue if the CPU is not in User mode. The CPU must be in a
* Privileged mode for the scheduler to start. */ Privileged mode for the scheduler to start. */
__asm( "MRS ulAPSR, APSR" ); __asm( "MRS ulAPSR, APSR" );
ulAPSR &= portAPSR_MODE_BITS_MASK; ulAPSR &= portAPSR_MODE_BITS_MASK;
configASSERT( ulAPSR != portAPSR_USER_MODE ); configASSERT( ulAPSR != portAPSR_USER_MODE );
@ -302,8 +297,8 @@ BaseType_t xPortStartScheduler( void )
if( ulAPSR != portAPSR_USER_MODE ) if( ulAPSR != portAPSR_USER_MODE )
{ {
/* Only continue if the binary point value is set to its lowest possible /* Only continue if the binary point value is set to its lowest possible
* setting. See the comments in vPortValidateInterruptPriority() below for setting. See the comments in vPortValidateInterruptPriority() below for
* more information. */ more information. */
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ); configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ) if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
@ -317,8 +312,8 @@ BaseType_t xPortStartScheduler( void )
} }
/* Will only get here if vTaskStartScheduler() was called with the CPU in /* 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 a non-privileged mode or the binary point register was not set to its lowest
* possible value. */ possible value. */
return 0; return 0;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -326,7 +321,7 @@ BaseType_t xPortStartScheduler( void )
void vPortEndScheduler( void ) void vPortEndScheduler( void )
{ {
/* Not implemented in ports where there is nothing to return to. /* Not implemented in ports where there is nothing to return to.
* Artificially force an assert. */ Artificially force an assert. */
configASSERT( ulCriticalNesting == 1000UL ); configASSERT( ulCriticalNesting == 1000UL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -337,15 +332,15 @@ void vPortEnterCritical( void )
ulPortSetInterruptMask(); ulPortSetInterruptMask();
/* Now interrupts are disabled ulCriticalNesting can be accessed /* Now interrupts are disabled ulCriticalNesting can be accessed
* directly. Increment ulCriticalNesting to keep a count of how many times directly. Increment ulCriticalNesting to keep a count of how many times
* portENTER_CRITICAL() has been called. */ portENTER_CRITICAL() has been called. */
ulCriticalNesting++; ulCriticalNesting++;
/* This is not the interrupt safe version of the enter critical function so /* 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 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 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 the critical nesting count is 1 to protect against recursive calls if the
* assert function also uses a critical section. */ assert function also uses a critical section. */
if( ulCriticalNesting == 1 ) if( ulCriticalNesting == 1 )
{ {
configASSERT( ulPortInterruptNesting == 0 ); configASSERT( ulPortInterruptNesting == 0 );
@ -358,15 +353,15 @@ void vPortExitCritical( void )
if( ulCriticalNesting > portNO_CRITICAL_NESTING ) if( ulCriticalNesting > portNO_CRITICAL_NESTING )
{ {
/* Decrement the nesting count as the critical section is being /* Decrement the nesting count as the critical section is being
* exited. */ exited. */
ulCriticalNesting--; ulCriticalNesting--;
/* If the nesting level has reached zero then all interrupt /* If the nesting level has reached zero then all interrupt
* priorities must be re-enabled. */ priorities must be re-enabled. */
if( ulCriticalNesting == portNO_CRITICAL_NESTING ) if( ulCriticalNesting == portNO_CRITICAL_NESTING )
{ {
/* Critical nesting has reached zero so all interrupt priorities /* Critical nesting has reached zero so all interrupt priorities
* should be unmasked. */ should be unmasked. */
portCLEAR_INTERRUPT_MASK(); portCLEAR_INTERRUPT_MASK();
} }
} }
@ -376,8 +371,8 @@ void vPortExitCritical( void )
void FreeRTOS_Tick_Handler( void ) void FreeRTOS_Tick_Handler( void )
{ {
/* Set interrupt mask before altering scheduler structures. The tick /* Set interrupt mask before altering scheduler structures. The tick
* handler runs at the lowest priority, so interrupts cannot already be masked, handler runs at the lowest priority, so interrupts cannot already be masked,
* so there is no need to save and restore the current mask value. */ so there is no need to save and restore the current mask value. */
__disable_irq(); __disable_irq();
portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
__asm( "DSB \n" __asm( "DSB \n"
@ -401,7 +396,7 @@ void vPortTaskUsesFPU( void )
uint32_t ulInitialFPSCR = 0; uint32_t ulInitialFPSCR = 0;
/* A task is registering the fact that it needs an FPU context. Set the /* 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). */ FPU flag (which is saved as part of the task context). */
ulPortTaskHasFPUContext = pdTRUE; ulPortTaskHasFPUContext = pdTRUE;
/* Initialise the floating point status register. */ /* Initialise the floating point status register. */
@ -423,7 +418,6 @@ uint32_t ulPortSetInterruptMask( void )
uint32_t ulReturn; uint32_t ulReturn;
__disable_irq(); __disable_irq();
if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ) if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
{ {
/* Interrupts were already masked. */ /* Interrupts were already masked. */
@ -436,7 +430,6 @@ uint32_t ulPortSetInterruptMask( void )
__asm( "DSB \n" __asm( "DSB \n"
"ISB \n" ); "ISB \n" );
} }
__enable_irq(); __enable_irq();
return ulReturn; return ulReturn;
@ -448,36 +441,40 @@ uint32_t ulPortSetInterruptMask( void )
void vPortValidateInterruptPriority( void ) void vPortValidateInterruptPriority( void )
{ {
/* The following assertion will fail if a service routine (ISR) for /* The following assertion will fail if a service routine (ISR) for
* an interrupt that has been assigned a priority above an interrupt that has been assigned a priority above
* configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
* function. ISR safe FreeRTOS API functions must *only* be called function. ISR safe FreeRTOS API functions must *only* be called
* from interrupts that have been assigned a priority at or below from interrupts that have been assigned a priority at or below
* configMAX_SYSCALL_INTERRUPT_PRIORITY. configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
* Numerically low interrupt priority numbers represent logically high Numerically low interrupt priority numbers represent logically high
* interrupt priorities, therefore the priority of the interrupt must interrupt priorities, therefore the priority of the interrupt must
* be set to a value equal to or numerically *higher* than be set to a value equal to or numerically *higher* than
* configMAX_SYSCALL_INTERRUPT_PRIORITY. configMAX_SYSCALL_INTERRUPT_PRIORITY.
*
* FreeRTOS maintains separate thread and ISR API functions to ensure FreeRTOS maintains separate thread and ISR API functions to ensure
* interrupt entry is as fast and simple as possible. interrupt entry is as fast and simple as possible.
*
* The following links provide detailed information: The following links provide detailed information:
* http://www.freertos.org/RTOS-Cortex-M3-M4.html http://www.freertos.org/RTOS-Cortex-M3-M4.html
* http://www.freertos.org/FAQHelp.html */ http://www.freertos.org/FAQHelp.html */
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ); configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
/* Priority grouping: The interrupt controller (GIC) allows the bits /* Priority grouping: The interrupt controller (GIC) allows the bits
* that define each interrupt's priority to be split between bits that that define each interrupt's priority to be split between bits that
* define the interrupt's pre-emption priority bits and bits that define define the interrupt's pre-emption priority bits and bits that define
* the interrupt's sub-priority. For simplicity all bits must be defined the interrupt's sub-priority. For simplicity all bits must be defined
* to be pre-emption priority bits. The following assertion will fail if to be pre-emption priority bits. The following assertion will fail if
* this is not the case (if some bits represent a sub-priority). this is not the case (if some bits represent a sub-priority).
*
* The priority grouping is configured by the GIC's binary point register The priority grouping is configured by the GIC's binary point register
* (ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest (ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest
* possible value (which may be above 0). */ possible value (which may be above 0). */
configASSERT( portICCBPR_BINARY_POINT_REGISTER <= portMAX_BINARY_POINT_VALUE ); configASSERT( portICCBPR_BINARY_POINT_REGISTER <= portMAX_BINARY_POINT_VALUE );
} }
#endif /* configASSERT_DEFINED */ #endif /* configASSERT_DEFINED */

View file

@ -64,7 +64,7 @@
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
* not need to be guarded with a critical section. */ not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1 #define portTICK_TYPE_IS_ATOMIC 1
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -103,7 +103,7 @@
extern void vPortClearInterruptMask( uint32_t ulNewMaskValue ); extern void vPortClearInterruptMask( uint32_t ulNewMaskValue );
/* These macros do not globally disable/enable interrupts. They do mask off /* These macros do not globally disable/enable interrupts. They do mask off
* interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */ interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */
#define portENTER_CRITICAL() vPortEnterCritical(); #define portENTER_CRITICAL() vPortEnterCritical();
#define portEXIT_CRITICAL() vPortExitCritical(); #define portEXIT_CRITICAL() vPortExitCritical();
#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask()
@ -114,17 +114,17 @@
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are /* Task function macros as described on the FreeRTOS.org WEB site. These are
* not required for this port but included in case common demo code that uses these not required for this port but included in case common demo code that uses these
* macros is used. */ macros is used. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/* Prototype of the FreeRTOS tick handler. This must be installed as the /* Prototype of the FreeRTOS tick handler. This must be installed as the
* handler for whichever peripheral is used to generate the RTOS tick. */ handler for whichever peripheral is used to generate the RTOS tick. */
void FreeRTOS_Tick_Handler( void ); void FreeRTOS_Tick_Handler( void );
/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU() /* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()
* before any floating point instructions are executed. */ before any floating point instructions are executed. */
void vPortTaskUsesFPU( void ); void vPortTaskUsesFPU( void );
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU() #define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
@ -160,3 +160,4 @@
#endif #endif
#endif /* PORTMACRO_H */ #endif /* PORTMACRO_H */

View file

@ -22,6 +22,7 @@
* http://www.FreeRTOS.org * http://www.FreeRTOS.org
* http://aws.amazon.com/freertos * http://aws.amazon.com/freertos
* *
* 1 tab == 4 spaces!
*/ */
/*----------------------------------------------------------- /*-----------------------------------------------------------

View file

@ -22,6 +22,7 @@
* http://www.FreeRTOS.org * http://www.FreeRTOS.org
* http://aws.amazon.com/freertos * http://aws.amazon.com/freertos
* *
* 1 tab == 4 spaces!
*/ */