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

@ -103,7 +103,7 @@ typedef void (*TaskFunction_t)( void * );
#define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL
#endif
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
itself. */
#define pdFREERTOS_ERRNO_NONE 0 /* No errors */
#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
@ -145,7 +145,7 @@ itself. */
#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
itself. */
#define pdFREERTOS_LITTLE_ENDIAN 0
#define pdFREERTOS_BIG_ENDIAN 1

@ -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 */

@ -137,7 +137,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
#ifdef configASSERT
#define portDISABLE_INTERRUPTS() \
{ \
uint32_t ulStatus; \
uint32_t ulStatus; \
\
/* Mask interrupts at and below the kernel interrupt priority. */ \
ulStatus = _CP0_GET_STATUS(); \
@ -152,7 +152,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
#else /* configASSERT */
#define portDISABLE_INTERRUPTS() \
{ \
uint32_t ulStatus; \
uint32_t ulStatus; \
\
/* Mask interrupts at and below the kernel interrupt priority. */ \
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() \
{ \
uint32_t ulStatus; \
uint32_t ulStatus; \
\
/* Unmask all interrupts. */ \
ulStatus = _CP0_GET_STATUS(); \
@ -210,7 +210,7 @@ extern void vPortClearInterruptMaskFromISR( UBaseType_t );
#define portYIELD() \
{ \
uint32_t ulCause; \
uint32_t ulCause; \
\
/* Trigger software interrupt. */ \
ulCause = _CP0_GET_CAUSE(); \

@ -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. */
xTimeToWake = xTickCount + xTicksToWait;
/* 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 );
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,29 +2811,23 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
}
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. */
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( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
{
eReturn = eNoTasksWaitingTimeout;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
eReturn = eNoTasksWaitingTimeout;
}
else
{
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

@ -195,7 +195,7 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
* Called by the timer service task to interpret and process a command it
* 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,
@ -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