]> git.sur5r.net Git - freertos/commitdiff
Kernel changes to improve power saving:
authorrtel <rtel@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Wed, 20 May 2015 15:46:40 +0000 (15:46 +0000)
committerrtel <rtel@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Wed, 20 May 2015 15:46:40 +0000 (15:46 +0000)
+ 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
FreeRTOS/Source/include/projdefs.h
FreeRTOS/Source/include/queue.h
FreeRTOS/Source/include/task.h
FreeRTOS/Source/portable/GCC/ARM_CA9/portmacro.h
FreeRTOS/Source/portable/MPLAB/PIC32MZ/portmacro.h
FreeRTOS/Source/queue.c
FreeRTOS/Source/tasks.c
FreeRTOS/Source/timers.c

index 73386cb58472881aae7d9bc1632ddd7224c7ea92..9188fe930c1c73dde01450d08f5a9852d2f7a5c0 100644 (file)
@@ -94,6 +94,14 @@ must be set in the compiler's include path. */
        #include "portmacro.h"\r
 #endif\r
 \r
+#if portBYTE_ALIGNMENT == 32\r
+       #define portBYTE_ALIGNMENT_MASK ( 0x001f )\r
+#endif\r
+\r
+#if portBYTE_ALIGNMENT == 16\r
+       #define portBYTE_ALIGNMENT_MASK ( 0x000f )\r
+#endif\r
+\r
 #if portBYTE_ALIGNMENT == 8\r
        #define portBYTE_ALIGNMENT_MASK ( 0x0007 )\r
 #endif\r
index 2dedeb807c176c7af0fddd2da7131e6408b0ab1d..115d35670a3bc0b5fdff8d02f26a47696a0637a1 100644 (file)
@@ -103,7 +103,7 @@ typedef void (*TaskFunction_t)( void * );
        #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL\r
 #endif\r
 \r
-/* The following errno values are used by FreeRTOS+ components, not FreeRTOS \r
+/* The following errno values are used by FreeRTOS+ components, not FreeRTOS\r
 itself. */\r
 #define pdFREERTOS_ERRNO_NONE                  0       /* No errors */\r
 #define        pdFREERTOS_ERRNO_ENOENT                 2       /* No such file or directory */\r
@@ -145,7 +145,7 @@ itself. */
 #define        pdFREERTOS_ERRNO_EILSEQ                 138     /* An invalid UTF-16 sequence was encountered. */\r
 #define        pdFREERTOS_ERRNO_ECANCELED              140     /* Operation canceled. */\r
 \r
-/* The following endian values are used by FreeRTOS+ components, not FreeRTOS \r
+/* The following endian values are used by FreeRTOS+ components, not FreeRTOS\r
 itself. */\r
 #define pdFREERTOS_LITTLE_ENDIAN       0\r
 #define pdFREERTOS_BIG_ENDIAN          1\r
index c3e2ed500b03a226103f6e1d6e02ee2218bb1a23..438a426bdd5dc01682665b7e3e3af67cb6e98a06 100644 (file)
@@ -1676,7 +1676,7 @@ QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const Ti
 QueueSetMemberHandle_t xQueueSelectFromSetFromISR( QueueSetHandle_t xQueueSet ) PRIVILEGED_FUNCTION;\r
 \r
 /* Not public API functions. */\r
-void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;\r
+void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION;\r
 BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ) PRIVILEGED_FUNCTION;\r
 void vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber ) PRIVILEGED_FUNCTION;\r
 UBaseType_t uxQueueGetQueueNumber( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION;\r
index a62eafc6e8f1c6bceddae7f9a88a1953c17a310c..63b02fca93e74345f17e815fdfe2afe1306776ff 100644 (file)
@@ -1684,7 +1684,7 @@ BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClea
  * \defgroup xTaskNotifyGive xTaskNotifyGive\r
  * \ingroup TaskNotifications\r
  */\r
-#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement );\r
+#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )\r
 \r
 /**\r
  * task. h\r
@@ -1876,7 +1876,7 @@ void vTaskPlaceOnUnorderedEventList( List_t * pxEventList, const TickType_t xIte
  * indefinitely, whereas vTaskPlaceOnEventList() does.\r
  *\r
  */\r
-void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;\r
+void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely ) PRIVILEGED_FUNCTION;\r
 \r
 /*\r
  * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE.  IT IS AN\r
index 1b7f18a7f62d0df6df922347418d6712512c8f49..ba1ca3d9b8ec50bed6369a65b14fd1eedc87a44f 100644 (file)
@@ -192,7 +192,7 @@ void vPortTaskUsesFPU( void );
 #endif /* configASSERT */\r
 \r
 #define portNOP() __asm volatile( "NOP" )\r
-\r
+#define portINLINE __inline\r
 \r
 #ifdef __cplusplus\r
        } /* extern C */\r
index 95d13b87a7c02888572bf947de2b6153311aba5e..86bd8b0c43702d672766d5a0d92ec9a3749aa2eb 100644 (file)
@@ -137,7 +137,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
 #ifdef configASSERT\r
        #define portDISABLE_INTERRUPTS()                                                                                        \\r
        {                                                                                                                                                       \\r
-       uint32_t ulStatus;                                                                                                              \\r
+       uint32_t ulStatus;                                                                                                                      \\r
                                                                                                                                                                \\r
                /* Mask interrupts at and below the kernel interrupt priority. */               \\r
                ulStatus = _CP0_GET_STATUS();                                                                                   \\r
@@ -152,7 +152,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
 #else /* configASSERT */\r
        #define portDISABLE_INTERRUPTS()                                                                                \\r
        {                                                                                                                                               \\r
-       uint32_t ulStatus;                                                                                                      \\r
+       uint32_t ulStatus;                                                                                                              \\r
                                                                                                                                                        \\r
                /* Mask interrupts at and below the kernel interrupt priority. */       \\r
                ulStatus = _CP0_GET_STATUS();                                                                           \\r
@@ -163,7 +163,7 @@ ensure API function and interrupt entry is as fast and as simple as possible. */
 \r
 #define portENABLE_INTERRUPTS()                                                                                        \\r
 {                                                                                                                                              \\r
-uint32_t ulStatus;                                                                                                     \\r
+uint32_t ulStatus;                                                                                                             \\r
                                                                                                                                                \\r
        /* Unmask all interrupts. */                                                                            \\r
        ulStatus = _CP0_GET_STATUS();                                                                           \\r
@@ -210,7 +210,7 @@ extern void vPortClearInterruptMaskFromISR( UBaseType_t );
 \r
 #define portYIELD()                                                            \\r
 {                                                                                              \\r
-uint32_t ulCause;                                                      \\r
+uint32_t ulCause;                                                              \\r
                                                                                                \\r
        /* Trigger software interrupt. */                       \\r
        ulCause = _CP0_GET_CAUSE();                                     \\r
index d25cdc8d3de0555cdfceac971b89fa86350d123c..931116fb8bed810f488b9f865854ccaf1a5084f2 100644 (file)
@@ -2403,7 +2403,7 @@ BaseType_t xReturn;
 \r
 #if ( configUSE_TIMERS == 1 )\r
 \r
-       void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait )\r
+       void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )\r
        {\r
        Queue_t * const pxQueue = ( Queue_t * ) xQueue;\r
 \r
@@ -2425,7 +2425,7 @@ BaseType_t xReturn;
                if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )\r
                {\r
                        /* There is nothing in the queue, block for the specified period. */\r
-                       vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );\r
+                       vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely );\r
                }\r
                else\r
                {\r
index c07e88f2a05492294d6f52f77bfd9e6cbd7a770a..d3ec721c88ce7f6a2db32231270581e2992c58bc 100644 (file)
@@ -99,8 +99,8 @@ functions but without including stdio.h here. */
 #endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */\r
 \r
 /* Sanity check the configuration. */\r
-#if configUSE_TICKLESS_IDLE != 0\r
-       #if INCLUDE_vTaskSuspend != 1\r
+#if( configUSE_TICKLESS_IDLE != 0 )\r
+       #if( INCLUDE_vTaskSuspend != 1 )\r
                #error INCLUDE_vTaskSuspend must be set to 1 if configUSE_TICKLESS_IDLE is not set to 0\r
        #endif /* INCLUDE_vTaskSuspend */\r
 #endif /* configUSE_TICKLESS_IDLE */\r
@@ -2387,7 +2387,7 @@ TickType_t xTimeToWake;
 \r
 #if configUSE_TIMERS == 1\r
 \r
-       void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait )\r
+       void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, const TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )\r
        {\r
        TickType_t xTimeToWake;\r
 \r
@@ -2420,12 +2420,44 @@ TickType_t xTimeToWake;
                        mtCOVERAGE_TEST_MARKER();\r
                }\r
 \r
-               /* Calculate the time at which the task should be woken if the event does\r
-               not occur.  This may overflow but this doesn't matter. */\r
-               xTimeToWake = xTickCount + xTicksToWait;\r
+               /* If vTaskSuspend() is available then the suspended task list is also\r
+               available and a task that is blocking indefinitely can enter the\r
+               suspended state (it is not really suspended as it will re-enter the\r
+               Ready state when the event it is waiting indefinitely for occurs).\r
+               Blocking indefinitely is useful when using tickless idle mode as when\r
+               all tasks are blocked indefinitely all timers can be turned off. */\r
+               #if( INCLUDE_vTaskSuspend == 1 )\r
+               {\r
+                       if( xWaitIndefinitely == pdTRUE )\r
+                       {\r
+                               /* Add the task to the suspended task list instead of a delayed\r
+                               task list to ensure the task is not woken by a timing event.  It\r
+                               will block indefinitely. */\r
+                               vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xGenericListItem ) );\r
+                       }\r
+                       else\r
+                       {\r
+                               /* Calculate the time at which the task should be woken if the\r
+                               event does not occur.  This may overflow but this doesn't\r
+                               matter. */\r
+                               xTimeToWake = xTickCount + xTicksToWait;\r
+                               traceTASK_DELAY_UNTIL();\r
+                               prvAddCurrentTaskToDelayedList( xTimeToWake );\r
+                       }\r
+               }\r
+               #else\r
+               {\r
+                       /* Calculate the time at which the task should be woken if the event\r
+                       does not occur.  This may overflow but this doesn't matter. */\r
+                       xTimeToWake = xTickCount + xTicksToWait;\r
+                       traceTASK_DELAY_UNTIL();\r
+                       prvAddCurrentTaskToDelayedList( xTimeToWake );\r
 \r
-               traceTASK_DELAY_UNTIL();\r
-               prvAddCurrentTaskToDelayedList( xTimeToWake );\r
+                       /* Remove compiler warnings when INCLUDE_vTaskSuspend() is not\r
+                       defined. */\r
+                       ( void ) xWaitIndefinitely;\r
+               }\r
+               #endif\r
        }\r
 \r
 #endif /* configUSE_TIMERS */\r
@@ -2481,12 +2513,12 @@ BaseType_t xReturn;
                xReturn = pdFALSE;\r
        }\r
 \r
-       #if( configUSE_TICKLESS_IDLE == 1 )\r
+       #if( configUSE_TICKLESS_IDLE != 0 )\r
        {\r
                /* If a task is blocked on a kernel object then xNextTaskUnblockTime\r
                might be set to the blocked task's time out time.  If the task is\r
                unblocked for a reason other than a timeout xNextTaskUnblockTime is\r
-               normally left unchanged, because it is automatically get reset to a new\r
+               normally left unchanged, because it is automatically reset to a new\r
                value when the tick count equals xNextTaskUnblockTime.  However if\r
                tickless idling is used it might be more important to enter sleep mode\r
                at the earliest possible time - so reset xNextTaskUnblockTime here to\r
@@ -2759,10 +2791,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-#if configUSE_TICKLESS_IDLE != 0\r
+#if( configUSE_TICKLESS_IDLE != 0 )\r
 \r
        eSleepModeStatus eTaskConfirmSleepModeStatus( void )\r
        {\r
+       /* The idle task exists in addition to the application tasks. */\r
+       const UBaseType_t uxNonApplicationTasks = 1;\r
        eSleepModeStatus eReturn = eStandardSleep;\r
 \r
                if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0 )\r
@@ -2777,29 +2811,23 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
                }\r
                else\r
                {\r
-                       #if configUSE_TIMERS == 0\r
+                       /* If all the tasks are in the suspended list (which might mean they\r
+                       have an infinite block time rather than actually being suspended)\r
+                       then it is safe to turn all clocks off and just wait for external\r
+                       interrupts. */\r
+                       if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )\r
                        {\r
-                               /* The idle task exists in addition to the application tasks. */\r
-                               const UBaseType_t uxNonApplicationTasks = 1;\r
-\r
-                               /* If timers are not being used and all the tasks are in the\r
-                               suspended list (which might mean they have an infinite block\r
-                               time rather than actually being suspended) then it is safe to\r
-                               turn all clocks off and just wait for external interrupts. */\r
-                               if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )\r
-                               {\r
-                                       eReturn = eNoTasksWaitingTimeout;\r
-                               }\r
-                               else\r
-                               {\r
-                                       mtCOVERAGE_TEST_MARKER();\r
-                               }\r
+                               eReturn = eNoTasksWaitingTimeout;\r
+                       }\r
+                       else\r
+                       {\r
+                               mtCOVERAGE_TEST_MARKER();\r
                        }\r
-                       #endif /* configUSE_TIMERS */\r
                }\r
 \r
                return eReturn;\r
        }\r
+\r
 #endif /* configUSE_TICKLESS_IDLE */\r
 /*-----------------------------------------------------------*/\r
 \r
@@ -2958,7 +2986,8 @@ UBaseType_t x;
        {\r
        TCB_t *pxTCB;\r
 \r
-               /* If null is passed in here then we are deleting ourselves. */\r
+               /* If null is passed in here then we are modifying the MPU settings of\r
+               the calling task. */\r
                pxTCB = prvGetTCBFromHandle( xTaskToModify );\r
 \r
         vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, NULL, 0 );\r
@@ -4165,6 +4194,22 @@ TickType_t uxReturn;
                                /* The task should not have been on an event list. */\r
                                configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );\r
 \r
+                               #if( configUSE_TICKLESS_IDLE != 0 )\r
+                               {\r
+                                       /* If a task is blocked waiting for a notification then\r
+                                       xNextTaskUnblockTime might be set to the blocked task's time\r
+                                       out time.  If the task is unblocked for a reason other than\r
+                                       a timeout xNextTaskUnblockTime is normally left unchanged,\r
+                                       because it will automatically get reset to a new value when\r
+                                       the tick count equals xNextTaskUnblockTime.  However if\r
+                                       tickless idling is used it might be more important to enter\r
+                                       sleep mode at the earliest possible time - so reset\r
+                                       xNextTaskUnblockTime here to ensure it is updated at the\r
+                                       earliest possible time. */\r
+                                       prvResetNextTaskUnblockTime();\r
+                               }\r
+                               #endif\r
+\r
                                if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )\r
                                {\r
                                        /* The notified task has a priority above the currently\r
index 797b25226aaeec1067c014a7f8e7f24b2942ce47..e1de26f11aa86faed33c2f93f06f04d9ec31d3aa 100644 (file)
@@ -195,7 +195,7 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
  * Called by the timer service task to interpret and process a command it\r
  * received on the timer queue.\r
  */\r
-static void    prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;\r
+static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;\r
 \r
 /*\r
  * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,\r
@@ -468,7 +468,7 @@ BaseType_t xTimerListsWereSwitched;
                                received - whichever comes first.  The following line cannot\r
                                be reached unless xNextExpireTime > xTimeNow, except in the\r
                                case when the current timer list is empty. */\r
-                               vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );\r
+                               vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );\r
 \r
                                if( xTaskResumeAll() == pdFALSE )\r
                                {\r