From c78aacb3e5d1c790cd5c972f068b7176e5bd289b Mon Sep 17 00:00:00 2001 From: rtel Date: Wed, 20 May 2015 15:46:40 +0000 Subject: [PATCH] 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. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2350 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/include/portable.h | 8 ++ FreeRTOS/Source/include/projdefs.h | 4 +- FreeRTOS/Source/include/queue.h | 2 +- FreeRTOS/Source/include/task.h | 4 +- .../Source/portable/GCC/ARM_CA9/portmacro.h | 2 +- .../Source/portable/MPLAB/PIC32MZ/portmacro.h | 8 +- FreeRTOS/Source/queue.c | 4 +- FreeRTOS/Source/tasks.c | 103 +++++++++++++----- FreeRTOS/Source/timers.c | 4 +- 9 files changed, 96 insertions(+), 43 deletions(-) diff --git a/FreeRTOS/Source/include/portable.h b/FreeRTOS/Source/include/portable.h index 73386cb58..9188fe930 100644 --- a/FreeRTOS/Source/include/portable.h +++ b/FreeRTOS/Source/include/portable.h @@ -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 diff --git a/FreeRTOS/Source/include/projdefs.h b/FreeRTOS/Source/include/projdefs.h index 2dedeb807..115d35670 100644 --- a/FreeRTOS/Source/include/projdefs.h +++ b/FreeRTOS/Source/include/projdefs.h @@ -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 diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index c3e2ed500..438a426bd 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -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; diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index a62eafc6e..63b02fca9 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -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 diff --git a/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h b/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h index 1b7f18a7f..ba1ca3d9b 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h +++ b/FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h @@ -192,7 +192,7 @@ void vPortTaskUsesFPU( void ); #endif /* configASSERT */ #define portNOP() __asm volatile( "NOP" ) - +#define portINLINE __inline #ifdef __cplusplus } /* extern C */ diff --git a/FreeRTOS/Source/portable/MPLAB/PIC32MZ/portmacro.h b/FreeRTOS/Source/portable/MPLAB/PIC32MZ/portmacro.h index 95d13b87a..86bd8b0c4 100644 --- a/FreeRTOS/Source/portable/MPLAB/PIC32MZ/portmacro.h +++ b/FreeRTOS/Source/portable/MPLAB/PIC32MZ/portmacro.h @@ -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(); \ diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c index d25cdc8d3..931116fb8 100644 --- a/FreeRTOS/Source/queue.c +++ b/FreeRTOS/Source/queue.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 { diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index c07e88f2a..d3ec721c8 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -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 diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index 797b25226..e1de26f11 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -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 ) { -- 2.39.5