From c4048f14ba54529db8a393769426b0822b712c2a Mon Sep 17 00:00:00 2001 From: rtel Date: Thu, 21 Jan 2016 14:10:04 +0000 Subject: [PATCH] Provide the ability to create event groups and software timers using pre statically allocated memory - now all RTOS objects can be created using statically allocated memory. Rename StaticTCB_t to StaticTask_t. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2407 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c | 4 +- .../Demo/Common/Minimal/StaticAllocation.c | 355 +++++++++++++++--- ...-directory-only-see-FreeRTOS-Plus-TCP.url} | 3 +- FreeRTOS/Source/event_groups.c | 34 +- FreeRTOS/Source/include/FreeRTOS.h | 98 ++++- FreeRTOS/Source/include/event_groups.h | 32 +- FreeRTOS/Source/include/queue.h | 2 +- FreeRTOS/Source/include/semphr.h | 20 +- FreeRTOS/Source/include/task.h | 10 +- FreeRTOS/Source/include/timers.h | 7 +- FreeRTOS/Source/tasks.c | 10 +- FreeRTOS/Source/timers.c | 68 +++- 12 files changed, 534 insertions(+), 109 deletions(-) rename FreeRTOS/Demo/Common/ethernet/{See-also-proprietary-FreeRTOS-Plus-UDP-product.url => Legacy-directory-only-see-FreeRTOS-Plus-TCP.url} (62%) diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c index 2e68aed54..b7d05a952 100644 --- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c +++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main.c @@ -405,7 +405,7 @@ const uint32_t ulMaxDivisor = 0xff, ulDivisorShift = 0x08; } /*-----------------------------------------------------------*/ -void vApplicationGetIdleTaskMemory( StaticTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) { /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the opportunity to supply the buffers that will be used by the Idle task as its @@ -417,7 +417,7 @@ void vApplicationGetIdleTaskMemory( StaticTCB_t **ppxIdleTaskTCBBuffer, StackTyp } /*-----------------------------------------------------------*/ -void vApplicationGetTimerTaskMemory( StaticTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) { /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the opportunity to supply the buffers that will be used by the Timer/RTOS daemon diff --git a/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c b/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c index ee35d4ec1..71d4d00b7 100644 --- a/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c +++ b/FreeRTOS/Demo/Common/Minimal/StaticAllocation.c @@ -70,13 +70,9 @@ /* * Demonstrates how to create FreeRTOS objects using pre-allocated memory, - * rather than the normal dynamically allocated memory. - * - * Two buffers are required by a task - one that is used by the task as its - * stack, and one that holds the task's control block (TCB). - * prvStaticallyAllocatedCreator() creates and deletes tasks with all - * possible combinations of statically allocated and dynamically allocated - * stacks and TCBs. + * rather than the normal dynamically allocated memory, and tests objects being + * created and deleted with both statically allocated memory and dynamically + * allocated memory. */ /* Scheduler include files. */ @@ -84,6 +80,8 @@ #include "task.h" #include "queue.h" #include "semphr.h" +#include "event_groups.h" +#include "timers.h" /* Demo program include files. */ #include "StaticAllocation.h" @@ -104,14 +102,14 @@ allocation tests. */ /* Binary semaphores have a maximum count of 1. */ #define staticBINARY_SEMAPHORE_MAX_COUNT ( 1 ) +/* The size of the stack used by the task that runs the tests. */ +#define staticCREATOR_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) -/*-----------------------------------------------------------*/ +/* The number of times the software timer will execute before stopping itself. */ +#define staticMAX_TIMER_CALLBACK_EXECUTIONS ( 5 ) -/* - * A task that is created and deleted multiple times, using both statically and - * dynamically allocated stack and TCB. - */ -static void prvStaticallyAllocatedTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ /* * The task that repeatedly creates and deletes statically allocated tasks, and @@ -120,9 +118,16 @@ static void prvStaticallyAllocatedTask( void *pvParameters ); static void prvStaticallyAllocatedCreator( void *pvParameters ); /* - * Utility function to create pseudo random numbers. + * The callback function used by the software timer that is repeatedly created + * and deleted using both static and dynamically allocated memory. */ -static UBaseType_t prvRand( void ); +static void prvTimerCallback( TimerHandle_t xExpiredTimer ); + +/* + * A task that is created and deleted multiple times, using both statically and + * dynamically allocated stack and TCB. + */ +static void prvStaticallyAllocatedTask( void *pvParameters ); /* * A function that demonstrates and tests the xTaskCreateStatic() API function @@ -131,6 +136,13 @@ static UBaseType_t prvRand( void ); */ static void prvCreateAndDeleteStaticallyAllocatedTasks( void ); +/* + * A function that demonstrates and tests the xEventGroupCreateStatic() API + * function by creating and then deleting event groups using both dynamically + * and statically allocated event group structures. + */ +static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void ); + /* * A function that demonstrates and tests the xQueueCreateStatic() API function * by creating and then deleting queues with both dynamically and statically @@ -145,6 +157,13 @@ static void prvCreateAndDeleteStaticallyAllocatedQueues( void ); */ static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void ); +/* + * A function that demonstrates and tests the xTimerCreateStatic() API macro by + * creating and then deleting software timers with both dynamically and + * statically allocated timer structures. + */ +static void prvCreateAndDeleteStaticallyAllocatedTimers( void ); + /* * A function that demonstrates and tests the xSemaphoreCreateMutexStatic() API * macro by creating and then deleting mutexes with both dynamically and @@ -167,6 +186,11 @@ static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void ); */ static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void ); +/* + * Utility function to create pseudo random numbers. + */ +static UBaseType_t prvRand( void ); + /* * The task that creates and deletes other tasks has to delay occasionally to * ensure lower priority tasks are not starved of processing time. A pseudo @@ -178,34 +202,39 @@ static TickType_t prvGetNextDelayTime( void ); /* * Checks the basic operation of a queue after it has been created. */ -static void prvCheckQueueFunction( QueueHandle_t xQueue ); +static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue ); /* * Checks the basic operation of a recursive mutex after it has been created. */ -static void prvCheckRecursiveSemaphoreFunction( SemaphoreHandle_t xSemaphore ); +static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore ); /* * Checks the basic operation of a binary semaphore after it has been created. */ -static void prvCheckSemaphoreFunction( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ); +static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ); + +/* + * Checks the basic operation of an event group after it has been created. + */ +static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup ); /*-----------------------------------------------------------*/ -/* StaticTCB_t is a publicly accessible structure that has the same size and +/* StaticTask_t is a publicly accessible structure that has the same size and alignment requirements as the real TCB structure. It is provided as a mechanism for applications to know the size of the TCB (which is dependent on the architecture and configuration file settings) without breaking the strict data -hiding policy by exposing the real TCB. This StaticTCB_t variable is passed +hiding policy by exposing the real TCB. This StaticTask_t variable is passed into the xTaskCreateStatic() function that creates the prvStaticallyAllocatedCreator() task, and will hold the TCB of the created tasks. */ -static StaticTCB_t xCreatorTaskTCBBuffer; +static StaticTask_t xCreatorTaskTCBBuffer; /* This is the stack that will be used by the prvStaticallyAllocatedCreator() task, which is itself created using statically allocated buffers (so without any dynamic memory allocation). */ -static StackType_t uxCreatorTaskStackBuffer[ configMINIMAL_STACK_SIZE ]; +static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ]; /* Used by the pseudo random number generating function. */ static uint32_t ulNextRand = 0; @@ -224,9 +253,9 @@ void vStartStaticallyAllocatedTasks( void ) /* Create a single task, which then repeatedly creates and deletes the task implemented by prvStaticallyAllocatedTask() at various different priorities, and both with and without statically allocated TCB and stack. */ - xTaskCreateStatic( prvStaticallyAllocatedCreator, /* The function that implements the task being created. */ + xTaskCreateStatic( prvStaticallyAllocatedCreator, /* The function that implements the task being created. */ "StatCreate", /* Text name for the task - not used by the RTOS, its just to assist debugging. */ - configMINIMAL_STACK_SIZE, /* Size of the buffer passed in as the stack - in words, not bytes! */ + staticCREATOR_TASK_STACK_SIZE, /* Size of the buffer passed in as the stack - in words, not bytes! */ NULL, /* Parameter passed into the task - not used in this case. */ staticTASK_PRIORITY, /* Priority of the task. */ NULL, /* Handle of the task being created, not used in this case. */ @@ -254,11 +283,58 @@ static void prvStaticallyAllocatedCreator( void *pvParameters ) prvCreateAndDeleteStaticallyAllocatedCountingSemaphores(); prvCreateAndDeleteStaticallyAllocatedMutexes(); prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes(); + prvCreateAndDeleteStaticallyAllocatedEventGroups(); + prvCreateAndDeleteStaticallyAllocatedTimers(); + } +} +/*-----------------------------------------------------------*/ + +static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup ) +{ +EventBits_t xEventBits; +const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55; + + /* The event group should not have any bits set yet. */ + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != ( EventBits_t ) 0 ) + { + xErrorOccurred = pdTRUE; + } + + /* Some some bits, then read them back to check they are as expected. */ + xEventGroupSetBits( xEventGroup, xFirstTestBits ); + + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != xFirstTestBits ) + { + xErrorOccurred = pdTRUE; + } + + xEventGroupSetBits( xEventGroup, xSecondTestBits ); + + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != ( xFirstTestBits | xSecondTestBits ) ) + { + xErrorOccurred = pdTRUE; + } + + /* Finally try clearing some bits too and check that operation proceeds as + expected. */ + xEventGroupClearBits( xEventGroup, xFirstTestBits ); + + xEventBits = xEventGroupGetBits( xEventGroup ); + + if( xEventBits != xSecondTestBits ) + { + xErrorOccurred = pdTRUE; } } /*-----------------------------------------------------------*/ -static void prvCheckSemaphoreFunction( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ) +static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ) { BaseType_t xReturned; UBaseType_t x; @@ -335,7 +411,7 @@ TickType_t xTickCount; } /*-----------------------------------------------------------*/ -static void prvCheckQueueFunction( QueueHandle_t xQueue ) +static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue ) { uint64_t ull, ullRead; BaseType_t xReturned, xLoop; @@ -396,7 +472,7 @@ BaseType_t xReturned, xLoop; } /*-----------------------------------------------------------*/ -static void prvCheckRecursiveSemaphoreFunction( SemaphoreHandle_t xSemaphore ) +static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore ) { const BaseType_t xLoops = 5; BaseType_t x, xReturned; @@ -458,7 +534,7 @@ StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic() function calls within this function. NOTE: In most usage scenarios now it is faster and more memory efficient to use a direct to task notification instead of a counting semaphore. http://www.freertos.org/RTOS-task-notifications.html */ -static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much stack space. */ +StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateCountingStatic() has one more parameter than the usual xSemaphoreCreateCounting() function. The paraemter @@ -473,7 +549,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckSemaphoreFunction( xSemaphore, uxMaxCount ); + prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -486,7 +562,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, NULL ); /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckSemaphoreFunction( xSemaphore, uxMaxCount ); + prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -510,7 +586,7 @@ on the architecture and configuration file settings) without breaking the strict data hiding policy by exposing the real semaphore internals. This StaticSemaphore_t variable is passed into the xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */ -static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much stack space. */ +StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateRecursiveMutexStatic() has one more parameter than the usual xSemaphoreCreateRecursiveMutex() function. @@ -526,7 +602,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much /* Ensure the semaphore passes a few sanity checks as a valid recursive semaphore. */ - prvCheckRecursiveSemaphoreFunction( xSemaphore ); + prvSanityCheckCreatedRecursiveMutex( xSemaphore ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -539,7 +615,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much xSemaphore = xSemaphoreCreateRecursiveMutexStatic( NULL ); /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckRecursiveSemaphoreFunction( xSemaphore ); + prvSanityCheckCreatedRecursiveMutex( xSemaphore ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -588,7 +664,7 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_ configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue ); /* Ensure the queue passes a few sanity checks as a valid queue. */ - prvCheckQueueFunction( xQueue ); + prvSanityCheckCreatedQueue( xQueue ); /* Delete the queue again so the buffers can be reused. */ vQueueDelete( xQueue ); @@ -604,7 +680,7 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_ &xStaticQueue ); /* The static queue structure that will hold the state of the queue. */ configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue ); - prvCheckQueueFunction( xQueue ); + prvSanityCheckCreatedQueue( xQueue ); vQueueDelete( xQueue ); /* Ensure lower priority tasks get CPU time. */ @@ -618,7 +694,7 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_ ucQueueStorageArea, /* The buffer used to hold items within the queue. */ NULL ); /* The queue structure is allocated dynamically. */ - prvCheckQueueFunction( xQueue ); + prvSanityCheckCreatedQueue( xQueue ); vQueueDelete( xQueue ); xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */ @@ -626,7 +702,7 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_ NULL, /* Allocate the buffer used to hold items within the queue dynamically. */ NULL ); /* The queue structure is allocated dynamically. */ - prvCheckQueueFunction( xQueue ); + prvSanityCheckCreatedQueue( xQueue ); vQueueDelete( xQueue ); /* Ensure lower priority tasks get CPU time. */ @@ -649,7 +725,7 @@ on the architecture and configuration file settings) without breaking the strict data hiding policy by exposing the real semaphore internals. This StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic() function calls within this function. */ -static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much stack space. */ +StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateMutexStatic() has one more parameter than the usual xSemaphoreCreateMutex() function. The paraemter @@ -664,7 +740,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); /* Take the mutex so the mutex is in the state expected by the - prvCheckSemaphoreFunction() function. */ + prvSanityCheckCreatedSemaphore() function. */ xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); if( xReturned != pdPASS ) @@ -673,7 +749,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much } /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -685,7 +761,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much xSemaphore = xSemaphoreCreateMutexStatic( NULL ); /* Take the mutex so the mutex is in the state expected by the - prvCheckSemaphoreFunction() function. */ + prvSanityCheckCreatedSemaphore() function. */ xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); if( xReturned != pdPASS ) @@ -694,7 +770,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much } /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -720,7 +796,7 @@ StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic() function calls within this function. NOTE: In most usage scenarios now it is faster and more memory efficient to use a direct to task notification instead of a binary semaphore. http://www.freertos.org/RTOS-task-notifications.html */ -static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much stack space. */ +StaticSemaphore_t xSemaphoreBuffer; /* Create the semaphore. xSemaphoreCreateBinaryStatic() has one more parameter than the usual xSemaphoreCreateBinary() function. The paraemter @@ -735,7 +811,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -747,7 +823,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much xSemaphore = xSemaphoreCreateBinaryStatic( NULL ); /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ - prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); /* Delete the semaphore again so the buffers can be reused. */ vSemaphoreDelete( xSemaphore ); @@ -767,7 +843,7 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much xErrorOccurred = pdTRUE; } - prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); + prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); vSemaphoreDelete( xSemaphore ); /* Ensure lower priority tasks get CPU time. */ @@ -778,6 +854,189 @@ static StaticSemaphore_t xSemaphoreBuffer; /* Static so it doesn't use too much } /*-----------------------------------------------------------*/ +static void prvTimerCallback( TimerHandle_t xExpiredTimer ) +{ +UBaseType_t *puxVariableToIncrement; +BaseType_t xReturned; + + /* Obtain the address of the variable to increment from the timer ID. */ + puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer ); + + /* Increment the variable to show the timer callback has executed. */ + ( *puxVariableToIncrement )++; + + /* If this callback has executed the required number of times, stop the + timer. */ + if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS ) + { + /* This is called from a timer callback so must not block. */ + xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvCreateAndDeleteStaticallyAllocatedTimers( void ) +{ +TimerHandle_t xTimer; +UBaseType_t uxVariableToIncrement; +const TickType_t xTimerPeriod = pdMS_TO_TICKS( 20 ); +BaseType_t xReturned; + +/* StaticTimer_t is a publicly accessible structure that has the same size +and alignment requirements as the real timer structure. It is provided as a +mechanism for applications to know the size of the timer structure (which is +dependent on the architecture and configuration file settings) without breaking +the strict data hiding policy by exposing the real timer internals. This +StaticTimer_t variable is passed into the xTimerCreateStatic() function calls +within this function. */ +StaticTimer_t xTimerBuffer; + + /* Create the software time. xTimerCreateStatic() has an extra parameter + than the normal xTimerCreate() API function. The parameter is a pointer to + the StaticTimer_t structure that will hold the software timer structure. If + the parameter is passed as NULL then the structure will be allocated + dynamically, just as if xTimerCreate() had been called. */ + xTimer = xTimerCreateStatic( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */ + xTimerPeriod, /* The period of the timer in ticks. */ + pdTRUE, /* This is an auto-reload timer. */ + ( void * ) &uxVariableToIncrement, /* The variable incremented by the test is passed into the timer callback using the timer ID. */ + prvTimerCallback, /* The function to execute when the timer expires. */ + &xTimerBuffer ); /* The buffer that will hold the software timer structure. */ + + /* The timer handle should equal the static timer structure passed into the + xTimerCreateStatic() function. */ + configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer ); + + /* Set the variable to 0, wait for a few timer periods to expire, then check + the timer callback has incremented the variable to the expected value. */ + uxVariableToIncrement = 0; + + /* This is a low priority so a block time should not be needed. */ + xReturned = xTimerStart( xTimer, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS ); + + /* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS + times, and then stopped itself. */ + if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS ) + { + xErrorOccurred = pdTRUE; + } + + /* Finished with the timer, delete it. */ + xReturned = xTimerDelete( xTimer, staticDONT_BLOCK ); + + /* Again, as this is a low priority task it is expected that the timer + command will have been sent even without a block time being used. */ + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + /* Just to show the check task that this task is still executing. */ + uxCycleCounter++; + + /* The software timer created above had a statically allocated timer + structure. Repeat the above using NULL as the xTimerCreateStatic() + parameter so the timer structure is instead allocated dynamically. */ + xTimer = xTimerCreateStatic( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */ + xTimerPeriod, /* The period of the timer in ticks. */ + pdTRUE, /* This is an auto-reload timer. */ + ( void * ) &uxVariableToIncrement, /* The variable incremented by the test is passed into the timer callback using the timer ID. */ + prvTimerCallback, /* The function to execute when the timer expires. */ + NULL ); /* A buffer is not passed this time, so the timer should be allocated dynamically. */ + uxVariableToIncrement = 0; + xReturned = xTimerStart( xTimer, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS ); + + /* Just to show the check task that this task is still executing. */ + uxCycleCounter++; + + if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS ) + { + xErrorOccurred = pdTRUE; + } + + xReturned = xTimerDelete( xTimer, staticDONT_BLOCK ); + + if( xReturned != pdPASS ) + { + xErrorOccurred = pdTRUE; + } + + /* Just to show the check task that this task is still executing. */ + uxCycleCounter++; +} +/*-----------------------------------------------------------*/ + +static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void ) +{ +EventGroupHandle_t xEventGroup; + +/* StaticEventGroup_t is a publicly accessible structure that has the same size +and alignment requirements as the real event group structure. It is provided as +a mechanism for applications to know the size of the event group (which is +dependent on the architecture and configuration file settings) without breaking +the strict data hiding policy by exposing the real event group internals. This +StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic() +function calls within this function. */ +StaticEventGroup_t xEventGroupBuffer; + + /* Create the event group. xEventGroupCreateStatic() has an extra parameter + than the normal xEventGroupCreate() API function. The parameter is a + pointer to the StaticEventGroup_t structure that will hold the event group + structure. If the parameter is passed as NULL then the structure will be + allocated dynamically, just as if xEventGroupCreate() had been called. */ + xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer ); + + /* The event group handle should equal the static event group structure + passed into the xEventGroupCreateStatic() function. */ + configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer ); + + /* Ensure the event group passes a few sanity checks as a valid event + group. */ + prvSanityCheckCreatedEventGroup( xEventGroup ); + + /* Delete the event group again so the buffers can be reused. */ + vEventGroupDelete( xEventGroup ); + + + /* The event group created above had a statically allocated event group + structure. Repeat the above using NULL as the xEventGroupCreateStatic() + parameter so the event group structure is instead allocated dynamically. */ + xEventGroup = xEventGroupCreateStatic( NULL ); + + /* Ensure the event group passes a few sanity checks as a valid event + group. */ + prvSanityCheckCreatedEventGroup( xEventGroup ); + + /* Delete the event group again so the buffers can be reused. */ + vEventGroupDelete( xEventGroup ); + + /* Ensure lower priority tasks get CPU time. */ + vTaskDelay( prvGetNextDelayTime() ); + + /* Just to show the check task that this task is still executing. */ + uxCycleCounter++; +} +/*-----------------------------------------------------------*/ + static void prvCreateAndDeleteStaticallyAllocatedTasks( void ) { TaskHandle_t xCreatedTask; @@ -786,7 +1045,7 @@ BaseType_t xReturned; /* The variable that will hold the TCB of tasks created by this function. See the comments above the declaration of the xCreatorTaskTCBBuffer variable for more information. */ -static StaticTCB_t xTCBBuffer; /* Static so it does not use too much stack space. */ +StaticTask_t xTCBBuffer; /* This buffer that will be used as the stack of tasks created by this function. See the comments above the declaration of the uxCreatorTaskStackBuffer[] array @@ -796,7 +1055,7 @@ static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ]; /* Create the task. xTaskCreateStatic() has two more parameters than the usual xTaskCreate() function. The first new parameter is a pointer to the pre-allocated stack. The second new parameter is a pointer to the - StaticTCB_t structure that will hold the task's TCB. If either pointer is + StaticTask_t structure that will hold the task's TCB. If either pointer is passed as NULL then the respective object will be allocated dynamically as if xTaskCreate() had been called. */ xReturned = xTaskCreateStatic( diff --git a/FreeRTOS/Demo/Common/ethernet/See-also-proprietary-FreeRTOS-Plus-UDP-product.url b/FreeRTOS/Demo/Common/ethernet/Legacy-directory-only-see-FreeRTOS-Plus-TCP.url similarity index 62% rename from FreeRTOS/Demo/Common/ethernet/See-also-proprietary-FreeRTOS-Plus-UDP-product.url rename to FreeRTOS/Demo/Common/ethernet/Legacy-directory-only-see-FreeRTOS-Plus-TCP.url index 434898e55..d9919c92c 100644 --- a/FreeRTOS/Demo/Common/ethernet/See-also-proprietary-FreeRTOS-Plus-UDP-product.url +++ b/FreeRTOS/Demo/Common/ethernet/Legacy-directory-only-see-FreeRTOS-Plus-TCP.url @@ -1,5 +1,6 @@ [InternetShortcut] -URL=http://www.freertos.org/udp +URL=http://www.freertos.org/tcp IDList= +HotKey=0 [{000214A0-0000-0000-C000-000000000046}] Prop3=19,2 diff --git a/FreeRTOS/Source/event_groups.c b/FreeRTOS/Source/event_groups.c index e8fe1a7fb..4d0ba5b8a 100644 --- a/FreeRTOS/Source/event_groups.c +++ b/FreeRTOS/Source/event_groups.c @@ -111,6 +111,9 @@ typedef struct xEventGroupDefinition UBaseType_t uxEventGroupNumber; #endif + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + uint8_t ucStaticallyAllocated; + #endif } EventGroup_t; /*-----------------------------------------------------------*/ @@ -127,15 +130,36 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co /*-----------------------------------------------------------*/ -EventGroupHandle_t xEventGroupCreate( void ) +EventGroupHandle_t xEventGroupGenericCreate( StaticEventGroup_t *pxStaticEventGroup ) { EventGroup_t *pxEventBits; - pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); + if( pxStaticEventGroup == NULL ) + { + /* The user has not provided a statically allocated event group, so + create on dynamically. */ + pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); + } + else + { + /* The user has provided a statically allocated event group - use it. */ + pxEventBits = ( EventGroup_t * ) pxStaticEventGroup; + } + if( pxEventBits != NULL ) { pxEventBits->uxEventBits = 0; vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); + + if( pxStaticEventGroup == NULL ) + { + pxEventBits->ucStaticallyAllocated = pdFALSE; + } + else + { + pxEventBits->ucStaticallyAllocated = pdTRUE; + } + traceEVENT_GROUP_CREATE( pxEventBits ); } else @@ -580,7 +604,11 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); } - vPortFree( pxEventBits ); + /* Only free the memory if it was allocated dynamically. */ + if( pxEventBits->ucStaticallyAllocated == pdFALSE ) + { + vPortFree( pxEventBits ); + } } ( void ) xTaskResumeAll(); } diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index cb75a6fb3..ab0da0df5 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -876,12 +876,17 @@ typedef enum } eDummy; /* - * In line with software engineering best practice, FreeRTOS implements a strict - * data hiding policy, so the real task control block (TCB) structure is not - * accessible to the application code. However, if the application writer wants - * to statically allocate a TCB then the size of the TCB needs to be know. The - * dummy TCB structure below is used for this purpose. Its size will allows - * match the size of the real TCB, no matter what the FreeRTOSConfig.h settings. + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Task structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a task then + * the size of the task object needs to be know. The StaticTask_t structure + * below is provided for this purpose. Its sizes and alignment requirements are + * guaranteed to match those of the genuine structure, no matter which + * architecture is being used, and no matter how the values in FreeRTOSConfig.h + * are set. Its contents are somewhat obfuscated in the hope users will + * recognise that it would be unwise to make direct use of the structure members. */ typedef struct xSTATIC_TCB { @@ -925,16 +930,21 @@ typedef struct xSTATIC_TCB uint8_t uxDummy20; #endif -} StaticTCB_t; +} StaticTask_t; /* - * In line with software engineering best practice, FreeRTOS implements a strict - * data hiding policy, so the queue structure is not accessible to the - * application code. However, if the application writer wants to statically - * allocate a queue (or one of the other objects that uses a queue as its base - * structure) then the size of the queue needs to be know. The dummy queue - * structure below is used for this purpose. Its size will allows match the - * size of the real queue, no matter what the FreeRTOSConfig.h settings. + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the Queue structure used internally by + * FreeRTOS is not accessible to application code. However, if the application + * writer wants to statically allocate the memory required to create a queue + * then the size of the queue object needs to be know. The StaticQueue_t + * structure below is provided for this purpose. Its sizes and alignment + * requirements are guaranteed to match those of the genuine structure, no + * matter which architecture is being used, and no matter how the values in + * FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in the hope + * users will recognise that it would be unwise to make direct use of the + * structure members. */ typedef struct xSTATIC_QUEUE { @@ -963,9 +973,67 @@ typedef struct xSTATIC_QUEUE #endif } StaticQueue_t; - typedef StaticQueue_t StaticSemaphore_t; +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the event group structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create an event group then the size of the event group object needs to be + * know. The StaticEventGroup_t structure below is provided for this purpose. + * Its sizes and alignment requirements are guaranteed to match those of the + * genuine structure, no matter which architecture is being used, and no matter + * how the values in FreeRTOSConfig.h are set. Its contents are somewhat + * obfuscated in the hope users will recognise that it would be unwise to make + * direct use of the structure members. + */ +typedef struct xSTATIC_EVENT_GROUP +{ + TickType_t xDummy1; + StaticList_t xDummy2; + + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy3; + #endif + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + uint8_t ucStaticallyAllocated; + #endif + +} StaticEventGroup_t; + +/* + * In line with software engineering best practice, especially when supplying a + * library that is likely to change in future versions, FreeRTOS implements a + * strict data hiding policy. This means the software timer structure used + * internally by FreeRTOS is not accessible to application code. However, if + * the application writer wants to statically allocate the memory required to + * create a software timer then the size of the queue object needs to be know. + * The StaticTimer_t structure below is provided for this purpose. Its sizes + * and alignment requirements are guaranteed to match those of the genuine + * structure, no matter which architecture is being used, and no matter how the + * values in FreeRTOSConfig.h are set. Its contents are somewhat obfuscated in + * the hope users will recognise that it would be unwise to make direct use of + * the structure members. + */ +typedef struct xSTATIC_TIMER +{ + void *pvDummy1; + StaticListItem_t xDummy2; + TickType_t xDummy3; + UBaseType_t uxDummy4; + void *pvDummy5[ 2 ]; + #if( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxDummy6; + #endif + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + uint8_t ucStaticallyAllocated; + #endif + +} StaticTimer_t; #ifdef __cplusplus } diff --git a/FreeRTOS/Source/include/event_groups.h b/FreeRTOS/Source/include/event_groups.h index b2642b644..46a16bdea 100644 --- a/FreeRTOS/Source/include/event_groups.h +++ b/FreeRTOS/Source/include/event_groups.h @@ -121,10 +121,10 @@ extern "C" { */ typedef void * EventGroupHandle_t; -/* +/* * The type that holds event bits always matches TickType_t - therefore the * number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1, - * 32 bits if set to 0. + * 32 bits if set to 0. * * \defgroup EventBits_t EventBits_t * \ingroup EventGroup @@ -173,7 +173,11 @@ typedef TickType_t EventBits_t; * \defgroup xEventGroupCreate xEventGroupCreate * \ingroup EventGroup */ -EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION; +#define xEventGroupCreate() xEventGroupGenericCreate( NULL ) + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xEventGroupCreateStatic( pxStaticEventGroup ) xEventGroupGenericCreate( ( pxStaticEventGroup ) ) +#endif /** * event_groups.h @@ -340,8 +344,8 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit * while interrupts are disabled, so protects event groups that are accessed * from tasks by suspending the scheduler rather than disabling interrupts. As * a result event groups cannot be accessed directly from an interrupt service - * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the - * timer task to have the clear operation performed in the context of the timer + * routine. Therefore xEventGroupClearBitsFromISR() sends a message to the + * timer task to have the clear operation performed in the context of the timer * task. * * @param xEventGroup The event group in which the bits are to be cleared. @@ -350,8 +354,8 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit * For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3 * and bit 0 set uxBitsToClear to 0x09. * - * @return If the request to execute the function was posted successfully then - * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned * if the timer service queue was full. * * Example usage: @@ -491,8 +495,8 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_ * *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the * example code below. * - * @return If the request to execute the function was posted successfully then - * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned + * @return If the request to execute the function was posted successfully then + * pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned * if the timer service queue was full. * * Example usage: @@ -521,8 +525,8 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_ if( xResult == pdPASS ) { // If xHigherPriorityTaskWoken is now set to pdTRUE then a context - // switch should be requested. The macro used is port specific and - // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - + // switch should be requested. The macro used is port specific and + // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() - // refer to the documentation page for the port being used. portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } @@ -717,6 +721,12 @@ void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION; void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION; void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION; +/* + * Generic version of the event group creation function, which is in turn called + * by the event group creation macros. + */ +EventGroupHandle_t xEventGroupGenericCreate( StaticEventGroup_t *pxStaticEventGroup ); + #if (configUSE_TRACE_FACILITY == 1) UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION; #endif diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index def602807..128a94540 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -174,7 +174,7 @@ typedef void * QueueSetMemberHandle_t; #if( configSUPPORT_STATIC_ALLOCATION == 1 ) #define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxStaticQueue ) xQueueGenericCreate( uxQueueLength, uxItemSize, pucQueueStorage, pxStaticQueue, queueQUEUE_TYPE_BASE ) -#endif +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * queue. h diff --git a/FreeRTOS/Source/include/semphr.h b/FreeRTOS/Source/include/semphr.h index b6d6ac3b5..4f5b7fd71 100644 --- a/FreeRTOS/Source/include/semphr.h +++ b/FreeRTOS/Source/include/semphr.h @@ -191,7 +191,10 @@ typedef QueueHandle_t SemaphoreHandle_t; * \ingroup Semaphores */ #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, NULL, queueQUEUE_TYPE_BINARY_SEMAPHORE ) -#define xSemaphoreCreateBinaryStatic( pxStaticQueue ) xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_BINARY_SEMAPHORE ) + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateBinaryStatic( pxStaticQueue ) xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h @@ -700,7 +703,10 @@ typedef QueueHandle_t SemaphoreHandle_t; * \ingroup Semaphores */ #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, NULL ) -#define xSemaphoreCreateMutexStatic( pxStaticQueue ) xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, ( pxStaticQueue ) ) + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateMutexStatic( pxStaticQueue ) xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, ( pxStaticQueue ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** @@ -756,7 +762,10 @@ typedef QueueHandle_t SemaphoreHandle_t; * \ingroup Semaphores */ #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, NULL ) -#define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h @@ -820,7 +829,10 @@ typedef QueueHandle_t SemaphoreHandle_t; * \ingroup Semaphores */ #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( NULL ) ) -#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxStaticSemaphore ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( pxStaticSemaphore ) ) + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxStaticSemaphore ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), ( pxStaticSemaphore ) ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * semphr. h diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index a4d423b27..235f65071 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -362,7 +362,7 @@ is used in assert() statements. */ UBaseType_t uxPriority, TaskHandle_t *pvCreatedTask, StackType_t *pxStackBuffer, - StaticTCB_t *pxTCBBuffer + StaticTask_t *pxTCBBuffer ); * * Create a new task and add it to the list of tasks that are ready to run. @@ -402,7 +402,7 @@ is used in assert() statements. */ * @param pxTCBBuffer If pxTCBBuffer is NULL then the TCB (which is the * structures used internally within FreeRTOS to hold information on the task) * will be allocated dynamically, just as when xTaskCreate() is used. If - * pxTCBBuffer is not NULL then it must point to a variable of type StaticTCB_t, + * pxTCBBuffer is not NULL then it must point to a variable of type StaticTask_t, * which will then be used as the TCB of the task being created. * * @return pdPASS if the task was successfully created and added to a ready @@ -418,7 +418,7 @@ is used in assert() statements. */ #define STACK_SIZE 200 // Structure that will hold the TCB of the task being created. - StaticTCB_t xTCB; + StaticTask_t xTCB; // Buffer that the task being created will use as its stack. StackType_t xStack[ STACK_SIZE ]; @@ -454,7 +454,7 @@ is used in assert() statements. */ */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) #define xTaskCreateStatic( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, puxStackBuffer, pxDummyTCB ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( puxStackBuffer ), ( pxDummyTCB ), ( NULL ) ) -#endif +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * task. h @@ -2095,7 +2095,7 @@ BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGE * Generic version of the task creation function which is in turn called by the * xTaskCreate() and xTaskCreateRestricted() macros. */ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, StaticTCB_t * const pxTCBBuffer, const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, StaticTask_t * const pxTCBBuffer, const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ /* * Get the uxTCBNumber assigned to the task referenced by the xTask parameter. diff --git a/FreeRTOS/Source/include/timers.h b/FreeRTOS/Source/include/timers.h index 3c6c6bf30..c4582d134 100644 --- a/FreeRTOS/Source/include/timers.h +++ b/FreeRTOS/Source/include/timers.h @@ -257,7 +257,11 @@ typedef void (*PendedFunction_t)( void *, uint32_t ); * } * @endverbatim */ -TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +#define xTimerCreate( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction ) xTimerGenericCreate( ( pcTimerName ), ( xTimerPeriodInTicks ), ( uxAutoReload ), ( pvTimerID ), ( pxCallbackFunction ), NULL ) + +#if( configSUPPORT_STATIC_ALLOCATION == 1 ) + #define xTimerCreateStatic( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxStaticTimer ) xTimerGenericCreate( ( pcTimerName ), ( xTimerPeriodInTicks ), ( uxAutoReload ), ( pvTimerID ), ( pxCallbackFunction ), pxStaticTimer ) +#endif /* configSUPPORT_STATIC_ALLOCATION */ /** * void *pvTimerGetTimerID( TimerHandle_t xTimer ); @@ -1136,6 +1140,7 @@ const char * pcTimerGetTimerName( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION; /* */ BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION; BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; +TimerHandle_t xTimerGenericCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxStaticTimer ) PRIVILEGED_FUNCTION; #ifdef __cplusplus } diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c index dcd137923..432d0783c 100644 --- a/FreeRTOS/Source/tasks.c +++ b/FreeRTOS/Source/tasks.c @@ -426,7 +426,7 @@ to its original value when it is released. */ #endif #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - extern void vApplicationGetIdleTaskMemory( StaticTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ); + extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ); #endif /* File private functions. --------------------------------*/ @@ -554,7 +554,7 @@ static void prvResetNextTaskUnblockTime( void ); #endif /*-----------------------------------------------------------*/ -BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, StaticTCB_t * const pxTCBBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, StaticTask_t * const pxTCBBuffer, const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { BaseType_t xReturn; TCB_t * pxNewTCB; @@ -1546,7 +1546,7 @@ StackType_t *pxTopOfStack; void vTaskStartScheduler( void ) { BaseType_t xReturn; -StaticTCB_t *pxIdleTaskTCBBuffer = NULL; +StaticTask_t *pxIdleTaskTCBBuffer = NULL; StackType_t *pxIdleTaskStackBuffer = NULL; uint16_t usIdleTaskStackSize = tskIDLE_STACK_SIZE; @@ -3152,9 +3152,9 @@ TCB_t *pxNewTCB; #if( ( configASSERT_DEFINED == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) { /* Sanity check that the size of the structure used to declare a - variable of type StaticTCB_t matches the size of the actual TCB_t + variable of type StaticTask_t matches the size of the actual TCB_t structure. */ - volatile size_t xSize = sizeof( StaticTCB_t ); + volatile size_t xSize = sizeof( StaticTask_t ); configASSERT( xSize == sizeof( TCB_t ) ); } #endif /* configASSERT_DEFINED */ diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index 11681723d..904189dc2 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -112,6 +112,10 @@ typedef struct tmrTimerControl #if( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ #endif + + #if( configSUPPORT_STATIC_ALLOCATION == 1 ) + uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created from a StaticTimer_t structure, and pdFALSE if the timer structure was allocated dynamically. */ + #endif } xTIMER; /* The old xTIMER name is maintained above then typedefed to the new Timer_t @@ -184,7 +188,7 @@ PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL; following callback function - which enables the application to optionally provide the memory that will be used by the timer task as the task's stack and TCB. */ - extern void vApplicationGetTimerTaskMemory( StaticTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ); + extern void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ); #endif @@ -250,7 +254,7 @@ static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseTy BaseType_t xTimerCreateTimerTask( void ) { BaseType_t xReturn = pdFAIL; -StaticTCB_t *pxTimerTaskTCBBuffer = NULL; +StaticTask_t *pxTimerTaskTCBBuffer = NULL; StackType_t *pxTimerTaskStackBuffer = NULL; uint16_t usTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; @@ -294,10 +298,20 @@ uint16_t usTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } /*-----------------------------------------------------------*/ -TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ +TimerHandle_t xTimerGenericCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxStaticTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { Timer_t *pxNewTimer; + #if( ( configASSERT_DEFINED == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticTimer_t equals the size of the real timer + structures. */ + volatile size_t xSize = sizeof( StaticTimer_t ); + configASSERT( xSize == sizeof( Timer_t ) ); + } + #endif /* configASSERT_DEFINED */ + /* Allocate the timer structure. */ if( xTimerPeriodInTicks == ( TickType_t ) 0U ) { @@ -305,14 +319,25 @@ Timer_t *pxNewTimer; } else { - pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + /* If the user passed in a statically allocated timer structure then use + it, otherwise allocate the structure dynamically. */ + if( pxStaticTimer == NULL ) + { + pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + } + else + { + pxNewTimer = ( Timer_t * ) pxStaticTimer; + } + if( pxNewTimer != NULL ) { /* Ensure the infrastructure used by the timer service task has been created/initialised. */ prvCheckForValidListAndQueue(); - /* Initialise the timer structure members using the function parameters. */ + /* Initialise the timer structure members using the function + parameters. */ pxNewTimer->pcTimerName = pcTimerName; pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; pxNewTimer->uxAutoReload = uxAutoReload; @@ -320,6 +345,15 @@ Timer_t *pxNewTimer; pxNewTimer->pxCallbackFunction = pxCallbackFunction; vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + if( pxStaticTimer == NULL ) + { + pxNewTimer->ucStaticallyAllocated = pdFALSE; + } + else + { + pxNewTimer->ucStaticallyAllocated = pdTRUE; + } + traceTIMER_CREATE( pxNewTimer ); } else @@ -716,19 +750,27 @@ TickType_t xTimeNow; pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); - /* The new period does not really have a reference, and can be - longer or shorter than the old one. The command time is - therefore set to the current time, and as the period cannot be - zero the next expiry time can only be in the future, meaning - (unlike for the xTimerStart() case above) there is no fail case - that needs to be handled here. */ + /* The new period does not really have a reference, and can + be longer or shorter than the old one. The command time is + therefore set to the current time, and as the period cannot + be zero the next expiry time can only be in the future, + meaning (unlike for the xTimerStart() case above) there is + no fail case that needs to be handled here. */ ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow ); break; case tmrCOMMAND_DELETE : /* The timer has already been removed from the active list, - just free up the memory. */ - vPortFree( pxTimer ); + just free up the memory if the memory was dynamically + allocated. */ + if( pxTimer->ucStaticallyAllocated == pdFALSE ) + { + vPortFree( pxTimer ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } break; default : -- 2.39.2