mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-06-06 12:29:03 -04:00
Kernel changes to improve power saving:
+ The timer task now blocks indefinitely if there are no timers active, allowing eTaskConfirmSleepModeStatus to return eNoTasksWaitingTimeout when configUSE_TIMERS is set to 1. + The next unblock time is calculated automatically after a task unblocks when waiting for a notification, allowing deep sleep to be entered earlier.
This commit is contained in:
parent
067c1573c3
commit
267dc24bb3
|
@ -94,6 +94,14 @@ must be set in the compiler's include path. */
|
||||||
#include "portmacro.h"
|
#include "portmacro.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 32
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x001f )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if portBYTE_ALIGNMENT == 16
|
||||||
|
#define portBYTE_ALIGNMENT_MASK ( 0x000f )
|
||||||
|
#endif
|
||||||
|
|
||||||
#if portBYTE_ALIGNMENT == 8
|
#if portBYTE_ALIGNMENT == 8
|
||||||
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1676,7 +1676,7 @@ QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const Ti
|
||||||
QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION;
|
QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/* Not public API functions. */
|
/* Not public API functions. */
|
||||||
void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION;
|
||||||
BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION;
|
BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION;
|
||||||
void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION;
|
void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION;
|
||||||
UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION;
|
UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION;
|
||||||
|
|
|
@ -1684,7 +1684,7 @@ BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClea
|
||||||
* \defgroup xTaskNotifyGive xTaskNotifyGive
|
* \defgroup xTaskNotifyGive xTaskNotifyGive
|
||||||
* \ingroup TaskNotifications
|
* \ingroup TaskNotifications
|
||||||
*/
|
*/
|
||||||
#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement );
|
#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* task. h
|
* task. h
|
||||||
|
@ -1876,7 +1876,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xIte
|
||||||
* indefinitely, whereas vTaskPlaceOnEventList() does.
|
* indefinitely, whereas vTaskPlaceOnEventList() does.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||||
|
|
|
@ -192,7 +192,7 @@ void vPortTaskUsesFPU( void );
|
||||||
#endif /* configASSERT */
|
#endif /* configASSERT */
|
||||||
|
|
||||||
#define portNOP() __asm volatile( "NOP" )
|
#define portNOP() __asm volatile( "NOP" )
|
||||||
|
#define portINLINE __inline
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern C */
|
} /* extern C */
|
||||||
|
|
|
@ -137,7 +137,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
|
||||||
#ifdef configASSERT
|
#ifdef configASSERT
|
||||||
#define portDISABLE_INTERRUPTS() \
|
#define portDISABLE_INTERRUPTS() \
|
||||||
{ \
|
{ \
|
||||||
uint32_t ulStatus; \
|
uint32_t ulStatus; \
|
||||||
\
|
\
|
||||||
/* Mask interrupts at and below the kernel interrupt priority. */ \
|
/* Mask interrupts at and below the kernel interrupt priority. */ \
|
||||||
ulStatus = _CP0_GET_STATUS(); \
|
ulStatus = _CP0_GET_STATUS(); \
|
||||||
|
@ -152,7 +152,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
|
||||||
#else /* configASSERT */
|
#else /* configASSERT */
|
||||||
#define portDISABLE_INTERRUPTS() \
|
#define portDISABLE_INTERRUPTS() \
|
||||||
{ \
|
{ \
|
||||||
uint32_t ulStatus; \
|
uint32_t ulStatus; \
|
||||||
\
|
\
|
||||||
/* Mask interrupts at and below the kernel interrupt priority. */ \
|
/* Mask interrupts at and below the kernel interrupt priority. */ \
|
||||||
ulStatus = _CP0_GET_STATUS(); \
|
ulStatus = _CP0_GET_STATUS(); \
|
||||||
|
@ -163,7 +163,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
|
||||||
|
|
||||||
#define portENABLE_INTERRUPTS() \
|
#define portENABLE_INTERRUPTS() \
|
||||||
{ \
|
{ \
|
||||||
uint32_t ulStatus; \
|
uint32_t ulStatus; \
|
||||||
\
|
\
|
||||||
/* Unmask all interrupts. */ \
|
/* Unmask all interrupts. */ \
|
||||||
ulStatus = _CP0_GET_STATUS(); \
|
ulStatus = _CP0_GET_STATUS(); \
|
||||||
|
@ -210,7 +210,7 @@ extern void vPortClearInterruptMaskFromISR( UBaseType_t );
|
||||||
|
|
||||||
#define portYIELD() \
|
#define portYIELD() \
|
||||||
{ \
|
{ \
|
||||||
uint32_t ulCause; \
|
uint32_t ulCause; \
|
||||||
\
|
\
|
||||||
/* Trigger software interrupt. */ \
|
/* Trigger software interrupt. */ \
|
||||||
ulCause = _CP0_GET_CAUSE(); \
|
ulCause = _CP0_GET_CAUSE(); \
|
||||||
|
|
|
@ -2403,7 +2403,7 @@ BaseType_t xReturn;
|
||||||
|
|
||||||
#if ( configUSE_TIMERS == 1 )
|
#if ( configUSE_TIMERS == 1 )
|
||||||
|
|
||||||
void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait )
|
void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )
|
||||||
{
|
{
|
||||||
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
|
@ -2425,7 +2425,7 @@ BaseType_t xReturn;
|
||||||
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
|
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
|
||||||
{
|
{
|
||||||
/* There is nothing in the queue, block for the specified period. */
|
/* There is nothing in the queue, block for the specified period. */
|
||||||
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,8 +99,8 @@ functions but without including stdio.h here. */
|
||||||
#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
|
#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
|
||||||
|
|
||||||
/* Sanity check the configuration. */
|
/* Sanity check the configuration. */
|
||||||
#if configUSE_TICKLESS_IDLE != 0
|
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||||
#if INCLUDE_vTaskSuspend != 1
|
#if( INCLUDE_vTaskSuspend != 1 )
|
||||||
#error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
|
#error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
|
||||||
#endif /* INCLUDE_vTaskSuspend */
|
#endif /* INCLUDE_vTaskSuspend */
|
||||||
#endif /* configUSE_TICKLESS_IDLE */
|
#endif /* configUSE_TICKLESS_IDLE */
|
||||||
|
@ -2387,7 +2387,7 @@ TickType_t xTimeToWake;
|
||||||
|
|
||||||
#if configUSE_TIMERS == 1
|
#if configUSE_TIMERS == 1
|
||||||
|
|
||||||
void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait )
|
void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )
|
||||||
{
|
{
|
||||||
TickType_t xTimeToWake;
|
TickType_t xTimeToWake;
|
||||||
|
|
||||||
|
@ -2420,12 +2420,44 @@ TickType_t xTimeToWake;
|
||||||
mtCOVERAGE_TEST_MARKER();
|
mtCOVERAGE_TEST_MARKER();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the time at which the task should be woken if the event does
|
/* If vTaskSuspend() is available then the suspended task list is also
|
||||||
not occur. This may overflow but this doesn't matter. */
|
available and a task that is blocking indefinitely can enter the
|
||||||
xTimeToWake = xTickCount + xTicksToWait;
|
suspended state (it is not really suspended as it will re-enter the
|
||||||
|
Ready state when the event it is waiting indefinitely for occurs).
|
||||||
|
Blocking indefinitely is useful when using tickless idle mode as when
|
||||||
|
all tasks are blocked indefinitely all timers can be turned off. */
|
||||||
|
#if( INCLUDE_vTaskSuspend == 1 )
|
||||||
|
{
|
||||||
|
if( xWaitIndefinitely == pdTRUE )
|
||||||
|
{
|
||||||
|
/* Add the task to the suspended task list instead of a delayed
|
||||||
|
task list to ensure the task is not woken by a timing event. It
|
||||||
|
will block indefinitely. */
|
||||||
|
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Calculate the time at which the task should be woken if the
|
||||||
|
event does not occur. This may overflow but this doesn't
|
||||||
|
matter. */
|
||||||
|
xTimeToWake = xTickCount + xTicksToWait;
|
||||||
|
traceTASK_DELAY_UNTIL();
|
||||||
|
prvAddCurrentTaskToDelayedList( xTimeToWake );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
/* Calculate the time at which the task should be woken if the event
|
||||||
|
does not occur. This may overflow but this doesn't matter. */
|
||||||
|
xTimeToWake = xTickCount + xTicksToWait;
|
||||||
|
traceTASK_DELAY_UNTIL();
|
||||||
|
prvAddCurrentTaskToDelayedList( xTimeToWake );
|
||||||
|
|
||||||
traceTASK_DELAY_UNTIL();
|
/* Remove compiler warnings when INCLUDE_vTaskSuspend() is not
|
||||||
prvAddCurrentTaskToDelayedList( xTimeToWake );
|
defined. */
|
||||||
|
( void ) xWaitIndefinitely;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* configUSE_TIMERS */
|
#endif /* configUSE_TIMERS */
|
||||||
|
@ -2481,12 +2513,12 @@ BaseType_t xReturn;
|
||||||
xReturn = pdFALSE;
|
xReturn = pdFALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if( configUSE_TICKLESS_IDLE == 1 )
|
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||||
{
|
{
|
||||||
/* If a task is blocked on a kernel object then xNextTaskUnblockTime
|
/* If a task is blocked on a kernel object then xNextTaskUnblockTime
|
||||||
might be set to the blocked task's time out time. If the task is
|
might be set to the blocked task's time out time. If the task is
|
||||||
unblocked for a reason other than a timeout xNextTaskUnblockTime is
|
unblocked for a reason other than a timeout xNextTaskUnblockTime is
|
||||||
normally left unchanged, because it is automatically get reset to a new
|
normally left unchanged, because it is automatically reset to a new
|
||||||
value when the tick count equals xNextTaskUnblockTime. However if
|
value when the tick count equals xNextTaskUnblockTime. However if
|
||||||
tickless idling is used it might be more important to enter sleep mode
|
tickless idling is used it might be more important to enter sleep mode
|
||||||
at the earliest possible time - so reset xNextTaskUnblockTime here to
|
at the earliest possible time - so reset xNextTaskUnblockTime here to
|
||||||
|
@ -2759,10 +2791,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if configUSE_TICKLESS_IDLE != 0
|
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||||
|
|
||||||
eSleepModeStatus eTaskConfirmSleepModeStatus( void )
|
eSleepModeStatus eTaskConfirmSleepModeStatus( void )
|
||||||
{
|
{
|
||||||
|
/* The idle task exists in addition to the application tasks. */
|
||||||
|
const UBaseType_t uxNonApplicationTasks = 1;
|
||||||
eSleepModeStatus eReturn = eStandardSleep;
|
eSleepModeStatus eReturn = eStandardSleep;
|
||||||
|
|
||||||
if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
|
if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
|
||||||
|
@ -2777,29 +2811,23 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if configUSE_TIMERS == 0
|
/* If all the tasks are in the suspended list (which might mean they
|
||||||
|
have an infinite block time rather than actually being suspended)
|
||||||
|
then it is safe to turn all clocks off and just wait for external
|
||||||
|
interrupts. */
|
||||||
|
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
|
||||||
{
|
{
|
||||||
/* The idle task exists in addition to the application tasks. */
|
eReturn = eNoTasksWaitingTimeout;
|
||||||
const UBaseType_t uxNonApplicationTasks = 1;
|
}
|
||||||
|
else
|
||||||
/* If timers are not being used and all the tasks are in the
|
{
|
||||||
suspended list (which might mean they have an infinite block
|
mtCOVERAGE_TEST_MARKER();
|
||||||
time rather than actually being suspended) then it is safe to
|
|
||||||
turn all clocks off and just wait for external interrupts. */
|
|
||||||
if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
|
|
||||||
{
|
|
||||||
eReturn = eNoTasksWaitingTimeout;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mtCOVERAGE_TEST_MARKER();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif /* configUSE_TIMERS */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return eReturn;
|
return eReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* configUSE_TICKLESS_IDLE */
|
#endif /* configUSE_TICKLESS_IDLE */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -2958,7 +2986,8 @@ UBaseType_t x;
|
||||||
{
|
{
|
||||||
TCB_t *pxTCB;
|
TCB_t *pxTCB;
|
||||||
|
|
||||||
/* If null is passed in here then we are deleting ourselves. */
|
/* If null is passed in here then we are modifying the MPU settings of
|
||||||
|
the calling task. */
|
||||||
pxTCB = prvGetTCBFromHandle( xTaskToModify );
|
pxTCB = prvGetTCBFromHandle( xTaskToModify );
|
||||||
|
|
||||||
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
|
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
|
||||||
|
@ -4165,6 +4194,22 @@ TickType_t uxReturn;
|
||||||
/* The task should not have been on an event list. */
|
/* The task should not have been on an event list. */
|
||||||
configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
|
configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );
|
||||||
|
|
||||||
|
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||||
|
{
|
||||||
|
/* If a task is blocked waiting for a notification then
|
||||||
|
xNextTaskUnblockTime might be set to the blocked task's time
|
||||||
|
out time. If the task is unblocked for a reason other than
|
||||||
|
a timeout xNextTaskUnblockTime is normally left unchanged,
|
||||||
|
because it will automatically get reset to a new value when
|
||||||
|
the tick count equals xNextTaskUnblockTime. However if
|
||||||
|
tickless idling is used it might be more important to enter
|
||||||
|
sleep mode at the earliest possible time - so reset
|
||||||
|
xNextTaskUnblockTime here to ensure it is updated at the
|
||||||
|
earliest possible time. */
|
||||||
|
prvResetNextTaskUnblockTime();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
|
if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
|
||||||
{
|
{
|
||||||
/* The notified task has a priority above the currently
|
/* The notified task has a priority above the currently
|
||||||
|
|
|
@ -195,7 +195,7 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||||
* Called by the timer service task to interpret and process a command it
|
* Called by the timer service task to interpret and process a command it
|
||||||
* received on the timer queue.
|
* received on the timer queue.
|
||||||
*/
|
*/
|
||||||
static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
|
static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
|
* Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
|
||||||
|
@ -468,7 +468,7 @@ BaseType_t xTimerListsWereSwitched;
|
||||||
received - whichever comes first. The following line cannot
|
received - whichever comes first. The following line cannot
|
||||||
be reached unless xNextExpireTime > xTimeNow, except in the
|
be reached unless xNextExpireTime > xTimeNow, except in the
|
||||||
case when the current timer list is empty. */
|
case when the current timer list is empty. */
|
||||||
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
|
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
|
||||||
|
|
||||||
if( xTaskResumeAll() == pdFALSE )
|
if( xTaskResumeAll() == pdFALSE )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue