Updates to the Cortex-M tickless idle code to reduce clock slippage.

Updates to prevent the vTaskSwitchContext() function being removed from GCC builds when link time optimisation is used.
pull/4/head
Richard Barry 8 years ago
parent 7ee26c1b5e
commit 464c2660ad

@ -75,7 +75,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 #if( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
@ -132,14 +132,6 @@ calculations. */
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 )
/* Required to allow portasm.asm access the configMAX_SYSCALL_INTERRUPT_PRIORITY
setting. */
const uint32_t ulMaxSyscallInterruptPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -164,10 +156,18 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Required to allow portasm.asm access the configMAX_SYSCALL_INTERRUPT_PRIORITY
setting. */
const uint32_t ulMaxSyscallInterruptPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -175,7 +175,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -183,7 +183,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -384,12 +384,12 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
#pragma WEAK( vPortSuppressTicksAndSleep ) #pragma WEAK( vPortSuppressTicksAndSleep )
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -466,23 +466,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__asm( " cpsie i" ); __asm( " cpsie i" );
__asm( " dsb" );
__asm( " isb" );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm( " cpsid i" );
__asm( " dsb" );
__asm( " isb" );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -497,11 +515,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -523,21 +539,18 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__asm( " cpsie i" );
} }
} }
#endif /* #if configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -620,7 +633,7 @@ void vPortSetupTimerInterrupt( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -79,7 +79,7 @@
#error This port can only be used when the project options are configured to enable hardware floating point support. #error This port can only be used when the project options are configured to enable hardware floating point support.
#endif #endif
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 #if( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
@ -141,14 +141,6 @@ calculations. */
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 )
/* Required to allow portasm.asm access the configMAX_SYSCALL_INTERRUPT_PRIORITY
setting. */
const uint32_t ulMaxSyscallInterruptPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -178,10 +170,18 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Required to allow portasm.asm access the configMAX_SYSCALL_INTERRUPT_PRIORITY
setting. */
const uint32_t ulMaxSyscallInterruptPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY;
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -189,7 +189,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -197,7 +197,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -409,12 +409,12 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
#pragma WEAK( vPortSuppressTicksAndSleep ) #pragma WEAK( vPortSuppressTicksAndSleep )
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -491,23 +491,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__asm( " cpsie i" ); __asm( " cpsie i" );
__asm( " dsb" );
__asm( " isb" );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm( " cpsid i" );
__asm( " dsb" );
__asm( " isb" );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -522,11 +540,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -548,21 +564,18 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__asm( " cpsie i" );
} }
} }
#endif /* #if configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -573,7 +586,7 @@ void xPortSysTickHandler( void )
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -645,7 +658,7 @@ void vPortSetupTimerInterrupt( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -101,10 +101,6 @@ debugger. */
#define portTASK_RETURN_ADDRESS prvTaskExitError #define portTASK_RETURN_ADDRESS prvTaskExitError
#endif #endif
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. * Setup the timer to generate the tick interrupts.
*/ */
@ -129,6 +125,12 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/*-----------------------------------------------------------*/
/* /*
* See header file for description. * See header file for description.
*/ */
@ -220,8 +222,11 @@ BaseType_t xPortStartScheduler( void )
/* 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. */ functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
prvTaskExitError(); prvTaskExitError();
vTaskSwitchContext();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;

@ -144,10 +144,6 @@ debugger. */
#define portTASK_RETURN_ADDRESS prvTaskExitError #define portTASK_RETURN_ADDRESS prvTaskExitError
#endif #endif
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -174,10 +170,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -185,7 +185,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -193,7 +193,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -202,7 +202,7 @@ static void prvTaskExitError( void );
* FreeRTOS API functions are not called from interrupts that have been assigned * FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/ */
#if ( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0; static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
@ -370,8 +370,11 @@ BaseType_t xPortStartScheduler( void )
/* 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. */ functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
prvTaskExitError(); prvTaskExitError();
vTaskSwitchContext();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -471,7 +474,7 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
@ -551,13 +554,28 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Re-enable interrupts - see comments above the cpsid instruction() /* Re-enable interrupts to allow the interrupt that brought the MCU
above. */ out of sleep mode to execute immediately. see comments above
__disable_interrupt() call above. */
__asm volatile( "cpsie i" ::: "memory" ); __asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__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. */ 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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
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
@ -569,8 +587,8 @@ void xPortSysTickHandler( void )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -585,11 +603,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -611,21 +627,18 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__asm volatile( "cpsie i" ::: "memory" );
} }
} }
#endif /* #if configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -635,7 +648,7 @@ void xPortSysTickHandler( void )
__attribute__(( weak )) void vPortSetupTimerInterrupt( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -707,7 +720,7 @@ __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -152,10 +152,6 @@ debugger. */
#define portTASK_RETURN_ADDRESS prvTaskExitError #define portTASK_RETURN_ADDRESS prvTaskExitError
#endif #endif
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -187,10 +183,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -198,7 +198,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -206,7 +206,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -215,7 +215,7 @@ static void prvTaskExitError( void );
* FreeRTOS API functions are not called from interrupts that have been assigned * FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/ */
#if ( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0; static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
@ -412,8 +412,11 @@ BaseType_t xPortStartScheduler( void )
/* 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. */ functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
prvTaskExitError(); prvTaskExitError();
vTaskSwitchContext();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -533,11 +536,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -613,23 +616,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" ::: "memory" ); __asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -644,11 +665,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -670,17 +689,14 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__asm volatile( "cpsie i" ::: "memory" );
} }
} }
@ -694,7 +710,7 @@ void xPortSysTickHandler( void )
__attribute__(( weak )) void vPortSetupTimerInterrupt( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -781,7 +797,7 @@ static void vPortEnableVFP( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -128,15 +128,15 @@
/* The systick is a 24-bit counter. */ /* The systick is a 24-bit counter. */
#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
have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
#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 )
/* 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. */
#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. */
@ -146,10 +146,6 @@ debugger. */
#define portTASK_RETURN_ADDRESS prvTaskExitError #define portTASK_RETURN_ADDRESS prvTaskExitError
#endif #endif
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -172,7 +168,7 @@ static void prvPortStartFirstTask( void ) __attribute__ (( naked ));
/* /*
* Function to enable the VFP. * Function to enable the VFP.
*/ */
static void vPortEnableVFP( void ) __attribute__ (( naked )); static void vPortEnableVFP( void ) __attribute__ (( naked ));
/* /*
* Used to catch tasks that attempt to return from their implementing function. * Used to catch tasks that attempt to return from their implementing function.
@ -181,10 +177,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -192,7 +192,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -200,7 +200,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -209,7 +209,7 @@ static void prvTaskExitError( void );
* FreeRTOS API functions are not called from interrupts that have been assigned * FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/ */
#if ( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0; static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
@ -400,8 +400,11 @@ BaseType_t xPortStartScheduler( void )
/* 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. */ functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
prvTaskExitError(); prvTaskExitError();
vTaskSwitchContext();
/* Should not get here! */ /* Should not get here! */
return 0; return 0;
@ -523,11 +526,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __attribute__((weak)) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -603,23 +606,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm volatile( "cpsie i" ::: "memory" ); __asm volatile( "cpsie i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm volatile( "cpsid i" ::: "memory" );
__asm volatile( "dsb" );
__asm volatile( "isb" );
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -634,11 +655,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -660,17 +679,14 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__asm volatile( "cpsie i" ::: "memory" );
} }
} }
@ -684,7 +700,7 @@ void xPortSysTickHandler( void )
__attribute__(( weak )) void vPortSetupTimerInterrupt( void ) __attribute__(( weak )) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -771,7 +787,7 @@ static void vPortEnableVFP( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -78,7 +78,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 #if( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
@ -142,10 +142,6 @@ FreeRTOS.org versions prior to V4.3.0 did not include this definition. */
#define configKERNEL_INTERRUPT_PRIORITY 255 #define configKERNEL_INTERRUPT_PRIORITY 255
#endif #endif
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -170,10 +166,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -181,7 +181,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -189,7 +189,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -198,7 +198,7 @@ static void prvTaskExitError( void );
* FreeRTOS API functions are not called from interrupts that have been assigned * FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/ */
#if ( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0; static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
@ -246,6 +246,10 @@ static void prvTaskExitError( void )
*/ */
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
#if( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
{ {
volatile uint32_t ulOriginalPriority; volatile uint32_t ulOriginalPriority;
@ -383,11 +387,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -417,7 +421,6 @@ void xPortSysTickHandler( void )
__DSB(); __DSB();
__ISB(); __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 )
@ -464,23 +467,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__enable_interrupt(); __enable_interrupt();
__DSB();
__ISB();
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_interrupt();
__DSB();
__ISB();
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -495,11 +516,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -521,21 +540,18 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__enable_interrupt();
} }
} }
#endif /* #if configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -571,7 +587,7 @@ __weak void vPortSetupTimerInterrupt( void )
uint8_t ucCurrentPriority; uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */ /* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */ /* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
@ -617,7 +633,7 @@ __weak void vPortSetupTimerInterrupt( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -85,6 +85,9 @@ extern "C" {
*----------------------------------------------------------- *-----------------------------------------------------------
*/ */
/* IAR includes. */
#include <intrinsics.h>
/* Type definitions. */ /* Type definitions. */
#define portCHAR char #define portCHAR char
#define portFLOAT float #define portFLOAT float
@ -138,7 +141,7 @@ typedef unsigned long UBaseType_t;
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif #endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */ /* Check the configuration. */
#if( configMAX_PRIORITIES > 32 ) #if( configMAX_PRIORITIES > 32 )
@ -151,7 +154,6 @@ typedef unsigned long UBaseType_t;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#include <intrinsics.h>
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

@ -71,7 +71,7 @@
* Implementation of functions defined in portable.h for the ARM CM4F port. * Implementation of functions defined in portable.h for the ARM CM4F port.
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Compiler includes. */ /* IAR includes. */
#include <intrinsics.h> #include <intrinsics.h>
/* Scheduler includes. */ /* Scheduler includes. */
@ -82,7 +82,7 @@
#error This port can only be used when the project options are configured to enable hardware floating point support. #error This port can only be used when the project options are configured to enable hardware floating point support.
#endif #endif
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 #if( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
@ -150,10 +150,6 @@ calculations. */
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 )
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -183,10 +179,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -194,7 +194,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -202,7 +202,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -211,7 +211,7 @@ static void prvTaskExitError( void );
* FreeRTOS API functions are not called from interrupts that have been assigned * FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/ */
#if ( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0; static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
@ -424,11 +424,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -458,7 +458,6 @@ void xPortSysTickHandler( void )
__DSB(); __DSB();
__ISB(); __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 )
@ -505,23 +504,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__enable_interrupt(); __enable_interrupt();
__DSB();
__ISB();
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_interrupt();
__DSB();
__ISB();
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -536,11 +553,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -562,21 +577,18 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__enable_interrupt();
} }
} }
#endif /* #if configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -612,7 +624,7 @@ __weak void vPortSetupTimerInterrupt( void )
uint8_t ucCurrentPriority; uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */ /* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */ /* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
@ -658,7 +670,7 @@ __weak void vPortSetupTimerInterrupt( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -84,6 +84,9 @@ extern "C" {
*----------------------------------------------------------- *-----------------------------------------------------------
*/ */
/* IAR includes. */
#include <intrinsics.h>
/* Type definitions. */ /* Type definitions. */
#define portCHAR char #define portCHAR char
#define portFLOAT float #define portFLOAT float
@ -137,7 +140,7 @@ typedef unsigned long UBaseType_t;
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif #endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */ /* Check the configuration. */
#if( configMAX_PRIORITIES > 32 ) #if( configMAX_PRIORITIES > 32 )
@ -150,7 +153,6 @@ typedef unsigned long UBaseType_t;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#include <intrinsics.h>
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

@ -71,7 +71,7 @@
* Implementation of functions defined in portable.h for the ARM CM4F port. * Implementation of functions defined in portable.h for the ARM CM4F port.
*----------------------------------------------------------*/ *----------------------------------------------------------*/
/* Compiler includes. */ /* IAR includes. */
#include <intrinsics.h> #include <intrinsics.h>
/* Scheduler includes. */ /* Scheduler includes. */
@ -82,7 +82,7 @@
#error This port can only be used when the project options are configured to enable hardware floating point support. #error This port can only be used when the project options are configured to enable hardware floating point support.
#endif #endif
#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 #if( configMAX_SYSCALL_INTERRUPT_PRIORITY == 0 )
#error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
#endif #endif
@ -144,10 +144,6 @@ calculations. */
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 )
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -177,10 +173,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -188,7 +188,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -196,7 +196,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -205,7 +205,7 @@ static void prvTaskExitError( void );
* FreeRTOS API functions are not called from interrupts that have been assigned * FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/ */
#if ( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0; static uint8_t ucMaxSysCallPriority = 0;
static uint32_t ulMaxPRIGROUPValue = 0; static uint32_t ulMaxPRIGROUPValue = 0;
static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
@ -265,6 +265,10 @@ static void prvTaskExitError( void )
*/ */
BaseType_t xPortStartScheduler( void ) BaseType_t xPortStartScheduler( void )
{ {
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
configASSERT( configMAX_SYSCALL_INTERRUPT_PRIORITY );
#if( configASSERT_DEFINED == 1 ) #if( configASSERT_DEFINED == 1 )
{ {
volatile uint32_t ulOriginalPriority; volatile uint32_t ulOriginalPriority;
@ -408,11 +412,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -488,23 +492,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_interrupt()
call above. */
__enable_interrupt(); __enable_interrupt();
__DSB();
__ISB();
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_interrupt();
__DSB();
__ISB();
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -519,11 +541,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -545,21 +565,18 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__enable_interrupt();
} }
} }
#endif /* #if configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -595,7 +612,7 @@ __weak void vPortSetupTimerInterrupt( void )
uint8_t ucCurrentPriority; uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */ /* Obtain the number of the currently executing interrupt. */
__asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) ); __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" );
/* Is the interrupt number a user defined interrupt? */ /* Is the interrupt number a user defined interrupt? */
if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
@ -641,7 +658,7 @@ __weak void vPortSetupTimerInterrupt( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -84,6 +84,9 @@ extern "C" {
*----------------------------------------------------------- *-----------------------------------------------------------
*/ */
/* IAR includes. */
#include <intrinsics.h>
/* Type definitions. */ /* Type definitions. */
#define portCHAR char #define portCHAR char
#define portFLOAT float #define portFLOAT float
@ -137,7 +140,7 @@ typedef unsigned long UBaseType_t;
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif #endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 #if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */ /* Check the configuration. */
#if( configMAX_PRIORITIES > 32 ) #if( configMAX_PRIORITIES > 32 )
@ -150,7 +153,6 @@ typedef unsigned long UBaseType_t;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#include <intrinsics.h>
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) ) #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __CLZ( ( uxReadyPriorities ) ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */

@ -196,7 +196,7 @@ static void prvTaskExitError( void );
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -204,7 +204,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -212,7 +212,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -535,7 +535,7 @@ void xPortSysTickHandler( void ) iv IVT_INT_SysTick ics ICS_AUTO
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -611,25 +611,41 @@ void xPortSysTickHandler( void ) iv IVT_INT_SysTick ics ICS_AUTO
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__asm { "cpsie i" }; __asm { "cpsie i" };
__asm { "wfi" }; __asm { "dsb" };
__asm { "isb" }; __asm { "isb" };
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__asm { "cpsid i" };
__asm { "dsb" };
__asm { "isb" };
/* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -644,11 +660,9 @@ void xPortSysTickHandler( void ) iv IVT_INT_SysTick ics ICS_AUTO
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -665,22 +679,19 @@ void xPortSysTickHandler( void ) iv IVT_INT_SysTick ics ICS_AUTO
/* 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 + 1 ) * 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__asm { "cpsie i" };
} }
} }
@ -696,7 +707,7 @@ void xPortSysTickHandler( void ) iv IVT_INT_SysTick ics ICS_AUTO
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -812,7 +823,7 @@ BaseType_t xReturn;
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -114,9 +114,6 @@ is defined. */
#define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL ) #define portNVIC_PENDSVCLEAR_BIT ( 1UL << 27UL )
#define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL ) #define portNVIC_PEND_SYSTICK_CLEAR_BIT ( 1UL << 25UL )
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
#define portVECTACTIVE_MASK ( 0xFFUL )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
@ -130,6 +127,9 @@ is defined. */
#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) #define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
#define portPRIGROUP_SHIFT ( 8UL ) #define portPRIGROUP_SHIFT ( 8UL )
/* Masks off all bits but the VECTACTIVE bits in the ICSR register. */
#define portVECTACTIVE_MASK ( 0xFFUL )
/* Constants required to set up the initial stack. */ /* Constants required to set up the initial stack. */
#define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_XPSR ( 0x01000000 )
@ -145,10 +145,6 @@ calculations. */
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 )
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -175,10 +171,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -186,7 +186,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -194,7 +194,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -313,6 +313,10 @@ BaseType_t xPortStartScheduler( void )
/* Read the value back to see how many bits stuck. */ /* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister; ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* The kernel interrupt priority should be set to the lowest
priority. */
configASSERT( ucMaxPriorityValue == ( configKERNEL_INTERRUPT_PRIORITY & ucMaxPriorityValue ) );
/* Use the same mask on the maximum system call priority. */ /* Use the same mask on the maximum system call priority. */
ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
@ -467,11 +471,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -547,23 +551,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_irq() call
above. */
__enable_irq(); __enable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -578,11 +600,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -604,17 +624,14 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__enable_irq();
} }
} }
@ -626,12 +643,12 @@ void xPortSysTickHandler( void )
* Setup the SysTick timer to generate the tick interrupts at the required * Setup the SysTick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
#if configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -714,7 +731,7 @@ __asm uint32_t vPortGetIPSR( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -156,10 +156,6 @@ calculations. */
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 )
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -191,10 +187,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -202,7 +202,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -210,7 +210,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -561,11 +561,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -641,23 +641,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_irq() call
above. */
__enable_irq(); __enable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -672,11 +690,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -698,17 +714,14 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__enable_irq();
} }
} }
@ -725,7 +738,7 @@ void xPortSysTickHandler( void )
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -808,7 +821,7 @@ __asm uint32_t vPortGetIPSR( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

@ -150,10 +150,6 @@ calculations. */
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 )
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* Setup the timer to generate the tick interrupts. The implementation in this * Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to * file is weak to allow application writers to change the timer used to
@ -185,10 +181,14 @@ static void prvTaskExitError( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
/* /*
* The number of SysTick increments that make up one tick period. * The number of SysTick increments that make up one tick period.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulTimerCountsForOneTick = 0; static uint32_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -196,7 +196,7 @@ static void prvTaskExitError( void );
* The maximum number of tick periods that can be suppressed is limited by the * The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer. * 24 bit resolution of the SysTick timer.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t xMaximumPossibleSuppressedTicks = 0; static uint32_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -204,7 +204,7 @@ static void prvTaskExitError( void );
* Compensate for the CPU cycles that pass while the SysTick is stopped (low * Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only. * power functionality only.
*/ */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
static uint32_t ulStoppedTimerCompensation = 0; static uint32_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
@ -547,11 +547,11 @@ void xPortSysTickHandler( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ {
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL; uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
TickType_t xModifiableIdleTime; TickType_t xModifiableIdleTime;
/* Make sure the SysTick reload value does not overflow the counter. */ /* Make sure the SysTick reload value does not overflow the counter. */
@ -627,23 +627,41 @@ void xPortSysTickHandler( void )
} }
configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
/* Stop SysTick. Again, the time the SysTick is stopped for is /* Re-enable interrupts to allow the interrupt that brought the MCU
accounted for as best it can be, but using the tickless mode will out of sleep mode to execute immediately. see comments above
inevitably result in some tiny drift of the time maintained by the __disable_interrupt() call above. */
kernel with respect to calendar time. */
ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;
portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
/* Re-enable interrupts - see comments above __disable_irq() call
above. */
__enable_irq(); __enable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_irq();
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) /* Disable the SysTick clock without reading the
portNVIC_SYSTICK_CTRL_REG register to ensure the
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
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT );
/* Determine if the SysTick clock has already counted to zero and
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
to count to zero (in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )
{ {
uint32_t ulCalculatedLoadValue; uint32_t ulCalculatedLoadValue;
/* The tick interrupt has already executed, and the SysTick /* The tick interrupt is already pending, and the SysTick count
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 );
@ -658,11 +676,9 @@ void xPortSysTickHandler( void )
portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
/* The tick interrupt handler will already have pended the tick /* As the pending tick will be processed as soon as this
processing in the kernel. As the pending tick will be function exits, the tick value maintained by the tick is stepped
processed as soon as this function exits, the tick value forward by one less than the time spent waiting. */
maintained by the tick is stepped forward by one less than the
time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL; ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
} }
else else
@ -684,17 +700,14 @@ void xPortSysTickHandler( void )
/* 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. The critical section is used to ensure the tick interrupt value. */
can only execute once in the case that the reload register is near
zero. */
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portENTER_CRITICAL();
{
portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
vTaskStepTick( ulCompleteTickPeriods ); vTaskStepTick( ulCompleteTickPeriods );
portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
}
portEXIT_CRITICAL(); /* Exit with interrpts enabled. */
__enable_irq();
} }
} }
@ -706,12 +719,12 @@ void xPortSysTickHandler( void )
* Setup the SysTick timer to generate the tick interrupts at the required * Setup the SysTick timer to generate the tick interrupts at the required
* frequency. * frequency.
*/ */
#if configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 #if( configOVERRIDE_DEFAULT_TICK_CONFIGURATION == 0 )
void vPortSetupTimerInterrupt( void ) void vPortSetupTimerInterrupt( void )
{ {
/* Calculate the constants required to configure the tick interrupt. */ /* Calculate the constants required to configure the tick interrupt. */
#if configUSE_TICKLESS_IDLE == 1 #if( configUSE_TICKLESS_IDLE == 1 )
{ {
ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ); ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick; xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
@ -794,7 +807,7 @@ __asm uint32_t vPortGetIPSR( void )
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 unpredictable behaviour. */
configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
} }

Loading…
Cancel
Save