mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-06-05 20:09:05 -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"
|
||||
#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
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
||||
#endif
|
||||
|
|
|
@ -1676,7 +1676,7 @@ QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const Ti
|
|||
QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/* 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;
|
||||
void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) 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
|
||||
* \ingroup TaskNotifications
|
||||
*/
|
||||
#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement );
|
||||
#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
|
||||
|
||||
/**
|
||||
* task. h
|
||||
|
@ -1876,7 +1876,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xIte
|
|||
* 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
|
||||
|
|
|
@ -192,7 +192,7 @@ void vPortTaskUsesFPU( void );
|
|||
#endif /* configASSERT */
|
||||
|
||||
#define portNOP() __asm volatile( "NOP" )
|
||||
|
||||
#define portINLINE __inline
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern C */
|
||||
|
|
|
@ -2403,7 +2403,7 @@ BaseType_t xReturn;
|
|||
|
||||
#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;
|
||||
|
||||
|
@ -2425,7 +2425,7 @@ BaseType_t xReturn;
|
|||
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
|
||||
{
|
||||
/* There is nothing in the queue, block for the specified period. */
|
||||
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
||||
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -99,8 +99,8 @@ functions but without including stdio.h here. */
|
|||
#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
|
||||
|
||||
/* Sanity check the configuration. */
|
||||
#if configUSE_TICKLESS_IDLE != 0
|
||||
#if INCLUDE_vTaskSuspend != 1
|
||||
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||
#if( INCLUDE_vTaskSuspend != 1 )
|
||||
#error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0
|
||||
#endif /* INCLUDE_vTaskSuspend */
|
||||
#endif /* configUSE_TICKLESS_IDLE */
|
||||
|
@ -2387,7 +2387,7 @@ TickType_t xTimeToWake;
|
|||
|
||||
#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;
|
||||
|
||||
|
@ -2420,13 +2420,45 @@ TickType_t xTimeToWake;
|
|||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Calculate the time at which the task should be woken if the event does
|
||||
not occur. This may overflow but this doesn't matter. */
|
||||
/* If vTaskSuspend() is available then the suspended task list is also
|
||||
available and a task that is blocking indefinitely can enter the
|
||||
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 );
|
||||
|
||||
/* Remove compiler warnings when INCLUDE_vTaskSuspend() is not
|
||||
defined. */
|
||||
( void ) xWaitIndefinitely;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* configUSE_TIMERS */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
@ -2481,12 +2513,12 @@ BaseType_t xReturn;
|
|||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
#if( configUSE_TICKLESS_IDLE == 1 )
|
||||
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||
{
|
||||
/* 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
|
||||
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
|
||||
tickless idling is used it might be more important to enter sleep mode
|
||||
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 )
|
||||
{
|
||||
/* The idle task exists in addition to the application tasks. */
|
||||
const UBaseType_t uxNonApplicationTasks = 1;
|
||||
eSleepModeStatus eReturn = eStandardSleep;
|
||||
|
||||
if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )
|
||||
|
@ -2777,15 +2811,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
|||
}
|
||||
else
|
||||
{
|
||||
#if configUSE_TIMERS == 0
|
||||
{
|
||||
/* The idle task exists in addition to the application tasks. */
|
||||
const UBaseType_t uxNonApplicationTasks = 1;
|
||||
|
||||
/* If timers are not being used and 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 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 ) )
|
||||
{
|
||||
eReturn = eNoTasksWaitingTimeout;
|
||||
|
@ -2795,11 +2824,10 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
|||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif /* configUSE_TIMERS */
|
||||
}
|
||||
|
||||
return eReturn;
|
||||
}
|
||||
|
||||
#endif /* configUSE_TICKLESS_IDLE */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
@ -2958,7 +2986,8 @@ UBaseType_t x;
|
|||
{
|
||||
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 );
|
||||
|
||||
vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );
|
||||
|
@ -4165,6 +4194,22 @@ TickType_t uxReturn;
|
|||
/* The task should not have been on an event list. */
|
||||
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 )
|
||||
{
|
||||
/* The notified task has a priority above the currently
|
||||
|
|
|
@ -468,7 +468,7 @@ BaseType_t xTimerListsWereSwitched;
|
|||
received - whichever comes first. The following line cannot
|
||||
be reached unless xNextExpireTime > xTimeNow, except in the
|
||||
case when the current timer list is empty. */
|
||||
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
|
||||
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );
|
||||
|
||||
if( xTaskResumeAll() == pdFALSE )
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue