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.
pull/1/head
Richard Barry 10 years ago
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,12 +2420,44 @@ 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…
Cancel
Save