Implement functionality that allows the memory required to create a queue or semaphore to be allocated statically.

Update the standard demo task that tests statically allocated tasks to also test statically allocated queues.
This commit is contained in:
Richard Barry 2016-01-19 13:41:28 +00:00
parent eae4815bf3
commit cf0ed4e2ac
10 changed files with 592 additions and 211 deletions

View file

@ -405,7 +405,7 @@ const uint32_t ulMaxDivisor = 0xff, ulDivisorShift = 0x08;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) void vApplicationGetIdleTaskMemory( StaticTCB_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize )
{ {
/* configUSE_STATIC_ALLOCATION is set to 1, so the application has the /* 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 opportunity to supply the buffers that will be used by the Idle task as its
@ -417,7 +417,7 @@ void vApplicationGetIdleTaskMemory( DummyTCB_t **ppxIdleTaskTCBBuffer, StackType
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vApplicationGetTimerTaskMemory( DummyTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) void vApplicationGetTimerTaskMemory( StaticTCB_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize )
{ {
/* configUSE_STATIC_ALLOCATION is set to 1, so the application has the /* 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 opportunity to supply the buffers that will be used by the Timer/RTOS daemon

View file

@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.freertos.org/Atmel_SAMV7_Cortex-M7_RTOS_Demo.html
IDList=

View file

@ -72,7 +72,10 @@
* In this case, there was difficulty generating interrupts from TC1, so only * In this case, there was difficulty generating interrupts from TC1, so only
* TC0 is used. Nested interrupts are instead generated by manually pending the * TC0 is used. Nested interrupts are instead generated by manually pending the
* TC1 interrupt from inside the TC0 interrupt handler. This means TC1 must be * TC1 interrupt from inside the TC0 interrupt handler. This means TC1 must be
* assigned an interrupt priority above TC0. * assigned an interrupt priority above TC0. [Note this arrangement does not
* really fulfil the purpose of the test as the nesting always occurs at the
* same point in the code, whereas the test is designed to test nesting
* occurring within the queue API functions]
*/ */
/* Scheduler includes. */ /* Scheduler includes. */

View file

@ -70,12 +70,11 @@
/* /*
* Demonstrates how to create FreeRTOS objects using pre-allocated memory, * Demonstrates how to create FreeRTOS objects using pre-allocated memory,
* rather than the normal dynamically allocated memory. Currently only tasks * rather than the normal dynamically allocated memory.
* are being allocated statically.
* *
* Two buffers are required by a task - one that is used by the task as its * 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). * stack, and one that holds the task's control block (TCB).
* prvStaticallyAllocatedTaskCreator() creates and deletes tasks with all * prvStaticallyAllocatedCreator() creates and deletes tasks with all
* possible combinations of statically allocated and dynamically allocated * possible combinations of statically allocated and dynamically allocated
* stacks and TCBs. * stacks and TCBs.
*/ */
@ -83,6 +82,8 @@
/* Scheduler include files. */ /* Scheduler include files. */
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "queue.h"
#include "semphr.h"
/* Demo program include files. */ /* Demo program include files. */
#include "StaticAllocation.h" #include "StaticAllocation.h"
@ -90,26 +91,60 @@
/* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */ /* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) #if( configSUPPORT_STATIC_ALLOCATION == 1 )
/* The priority at which the task that performs the tests is created. */
#define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
/* The length of the queue, in items, not bytes, used in the queue static
allocation tests. */
#define staticQUEUE_LENGTH_IN_ITEMS ( 5 )
/* A block time of 0 simply means "don't block". */
#define staticDONT_BLOCK ( ( TickType_t ) 0 )
/* Binary semaphores have a maximum count of 1. */
#define staticBINARY_SEMAPHORE_MAX_COUNT ( 1 )
/*-----------------------------------------------------------*/
/* /*
* A task that is created multiple times, using both statically and dynamically * A task that is created and deleted multiple times, using both statically and
* allocated stack and TCB. * dynamically allocated stack and TCB.
*/ */
static void prvStaticallyAllocatedTask( void *pvParameters ); static void prvStaticallyAllocatedTask( void *pvParameters );
/* /*
* The task that creates and deletes the prvStaticallyAllocatedTask() task, * The task that repeatedly creates and deletes statically allocated tasks, and
* using various priorities, and sometimes with statically and sometimes * other RTOS objects.
* dynamically allocated stack and TCB.
*/ */
static void prvStaticallyAllocatedTaskCreator( void *pvParameters ); static void prvStaticallyAllocatedCreator( void *pvParameters );
/* /*
* Utility function to create pseudo random numbers. * Utility function to create pseudo random numbers.
*/ */
static UBaseType_t prvRand( void ); static UBaseType_t prvRand( void );
/*
* A function that demonstrates and tests the xTaskCreateStatic() API function
* by creating and then deleting tasks with both dynamically and statically
* allocated TCBs and stacks.
*/
static void prvCreateAndDeleteStaticallyAllocatedTasks( void );
/*
* A function that demonstrates and tests the xQueueCreateStatic() API function
* by creating and then deleting queues with both dynamically and statically
* allocated queue structures and queue storage areas.
*/
static void prvCreateAndDeleteStaticallyAllocatedQueues( void );
/*
* A function that demonstrates and tests the xSemaphoreCreateBinaryStatic() API
* macro by creating and then deleting binary semaphores with both dynamically
* and statically allocated semaphore structures.
*/
static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void );
/* /*
* The task that creates and deletes other tasks has to delay occasionally to * 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 * ensure lower priority tasks are not starved of processing time. A pseudo
@ -118,21 +153,32 @@ static UBaseType_t prvRand( void );
*/ */
static TickType_t prvGetNextDelayTime( void ); static TickType_t prvGetNextDelayTime( void );
/*
* Checks the basic operation of a queue after it has been created.
*/
static void prvCheckQueueFunction( QueueHandle_t xQueue );
/*
* Checks the basic operation of a binary semaphore after it has been created.
*/
static void prvCheckSemaphoreFunction( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* DummyTCB_t is a publicly accessible structure that has the same size and /* StaticTCB_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 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 for applications to know the size of the TCB (which is dependent on the
architecture and configuration file settings) without breaking the strict data architecture and configuration file settings) without breaking the strict data
hiding policy by exposing the real TCB. This DummyTCB_t variable is passed into hiding policy by exposing the real TCB. This StaticTCB_t variable is passed
the xTaskCreateStatic() function, and will hold the task's TCB. */ into the xTaskCreateStatic() function that creates the
static DummyTCB_t xTCBBuffer; prvStaticallyAllocatedCreator() task, and will hold the TCB of the created
tasks. */
static StaticTCB_t xCreatorTaskTCBBuffer;
/* This is the stack that will be used by the task. The alignment requirements /* This is the stack that will be used by the prvStaticallyAllocatedCreator()
for the stack depend on the architecture, and the method of forcing an alignment task, which is itself created using statically allocated buffers (so without any
is dependent on the compiler, but any bad alignment is corrected inside the dynamic memory allocation). */
FreeRTOS code. */ static StackType_t uxCreatorTaskStackBuffer[ configMINIMAL_STACK_SIZE ];
static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
/* Used by the pseudo random number generating function. */ /* Used by the pseudo random number generating function. */
static uint32_t ulNextRand = 0; static uint32_t ulNextRand = 0;
@ -141,6 +187,9 @@ static uint32_t ulNextRand = 0;
stalled. */ stalled. */
static volatile UBaseType_t uxCycleCounter = 0; static volatile UBaseType_t uxCycleCounter = 0;
/* A variable that gets set to pdTRUE if an error is detected. */
static BaseType_t xErrorOccurred = pdFALSE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartStaticallyAllocatedTasks( void ) void vStartStaticallyAllocatedTasks( void )
@ -148,27 +197,347 @@ void vStartStaticallyAllocatedTasks( void )
/* Create a single task, which then repeatedly creates and deletes the /* Create a single task, which then repeatedly creates and deletes the
task implemented by prvStaticallyAllocatedTask() at various different task implemented by prvStaticallyAllocatedTask() at various different
priorities, and both with and without statically allocated TCB and stack. */ priorities, and both with and without statically allocated TCB and stack. */
xTaskCreate( prvStaticallyAllocatedTaskCreator, "StatCreate", configMINIMAL_STACK_SIZE, NULL, staticTASK_PRIORITY, NULL ); 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! */
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. */
&( uxCreatorTaskStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
&xCreatorTaskTCBBuffer ); /* The variable that will hold the task's TCB. */
/* Pseudo seed the random number generator. */ /* Pseudo seed the random number generator. */
ulNextRand = ( uint32_t ) prvRand; ulNextRand = ( uint32_t ) prvRand;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvStaticallyAllocatedTaskCreator( void *pvParameters ) static void prvStaticallyAllocatedCreator( void *pvParameters )
{ {
TaskHandle_t xCreatedTask;
BaseType_t xReturned;
/* Avoid compiler warnings. */ /* Avoid compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ;; )
{ {
prvCreateAndDeleteStaticallyAllocatedTasks();
prvCreateAndDeleteStaticallyAllocatedQueues();
prvCreateAndDeleteStaticallyAllocatedBinarySemaphores();
}
}
/*-----------------------------------------------------------*/
static void prvCheckSemaphoreFunction( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount )
{
BaseType_t xReturned;
UBaseType_t x;
const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 );
TickType_t xTickCount;
/* The binary semaphore should start 'empty', so a call to xSemaphoreTake()
should fail. */
xTickCount = xTaskGetTickCount();
xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
if( ( xTaskGetTickCount() - xTickCount) < xShortBlockTime )
{
/* Did not block on the semaphore as long as expected. */
xErrorOccurred = pdTRUE;
}
if( xReturned != pdFAIL )
{
xErrorOccurred = pdTRUE;
}
/* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount
times. */
for( x = 0; x < uxMaxCount; x++ )
{
xReturned = xSemaphoreGive( xSemaphore );
if( xReturned == pdFAIL )
{
xErrorOccurred = pdTRUE;
}
}
/* Giving the semaphore again should fail, as it is 'full'. */
xReturned = xSemaphoreGive( xSemaphore );
if( xReturned != pdFAIL )
{
xErrorOccurred = pdTRUE;
}
configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount );
/* Should now be possible to 'take' the semaphore up to a maximum of
uxMaxCount times without blocking. */
for( x = 0; x < uxMaxCount; x++ )
{
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
if( xReturned == pdFAIL )
{
xErrorOccurred = pdTRUE;
}
}
/* Back to the starting condition, where the semaphore should not be
available. */
xTickCount = xTaskGetTickCount();
xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
if( ( xTaskGetTickCount() - xTickCount) < xShortBlockTime )
{
/* Did not block on the semaphore as long as expected. */
xErrorOccurred = pdTRUE;
}
if( xReturned != pdFAIL )
{
xErrorOccurred = pdTRUE;
}
configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
}
/*-----------------------------------------------------------*/
static void prvCheckQueueFunction( QueueHandle_t xQueue )
{
uint64_t ull, ullRead;
BaseType_t xReturned, xLoop;
/* This test is done twice to ensure the queue storage area wraps. */
for( xLoop = 0; xLoop < 2; xLoop++ )
{
/* A very basic test that the queue can be written to and read from as
expected. First the queue should be empty. */
xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_EMPTY )
{
xErrorOccurred = pdTRUE;
}
/* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS
times. */
for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
{
xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
}
/* Should not now be possible to write to the queue again. */
xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_FULL )
{
xErrorOccurred = pdTRUE;
}
/* Now read back from the queue to ensure the data read back matches that
written. */
for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
{
xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
if( ullRead != ull )
{
xErrorOccurred = pdTRUE;
}
}
/* The queue should be empty again. */
xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_EMPTY )
{
xErrorOccurred = pdTRUE;
}
}
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedQueues( void )
{
QueueHandle_t xQueue;
/* StaticQueue_t is a publicly accessible structure that has the same size and
alignment requirements as the real queue structure. It is provided as a
mechanism for applications to know the size of the queue (which is dependent on
the architecture and configuration file settings) without breaking the strict
data hiding policy by exposing the real queue internals. This StaticQueue_t
variable is passed into the xQueueCreateStatic() function calls within this
function. */
static StaticQueue_t xStaticQueue;
/* The queue storage area must be large enough to hold the maximum number of
items it is possible for the queue to hold at any one time, which equals the
queue length (in items, not bytes) multiplied by the size of each item. In this
case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items. See
http://www.freertos.org/Embedded-RTOS-Queues.html */
static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ];
/* Create the queue. xQueueCreateStatic() has two more parameters than the
usual xQueueCreate() function. The first new paraemter is a pointer to the
pre-allocated queue storage area. The second new parameter is a pointer to
the StaticQueue_t structure that will hold the queue state information in
an anonymous way. If either pointer is passed as NULL then the respective
data will be allocated dynamically as if xQueueCreate() had been called. */
xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ), /* The size of each item. */
ucQueueStorageArea, /* The buffer used to hold items within the queue. */
&xStaticQueue ); /* The static queue structure that will hold the state of the queue. */
/* The queue handle should equal the static queue structure passed into the
xQueueCreateStatic() function. */
configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );
/* Ensure the queue passes a few sanity checks as a valid queue. */
prvCheckQueueFunction( xQueue );
/* Delete the queue again so the buffers can be reused. */
vQueueDelete( xQueue );
/* The queue created above had a statically allocated queue storage area and
queue structure. Repeat the above with three more times - with different
combinations of static and dynamic allocation. */
xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ), /* The size of each item. */
NULL, /* Allocate the buffer used to hold items within the queue dynamically. */
&xStaticQueue ); /* The static queue structure that will hold the state of the queue. */
configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );
prvCheckQueueFunction( xQueue );
vQueueDelete( xQueue );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ), /* The size of each item. */
ucQueueStorageArea, /* The buffer used to hold items within the queue. */
NULL ); /* The queue structure is allocated dynamically. */
prvCheckQueueFunction( xQueue );
vQueueDelete( xQueue );
xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ), /* The size of each item. */
NULL, /* Allocate the buffer used to hold items within the queue dynamically. */
NULL ); /* The queue structure is allocated dynamically. */
prvCheckQueueFunction( xQueue );
vQueueDelete( xQueue );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void )
{
SemaphoreHandle_t xSemaphore;
/* StaticSemaphore_t is a publicly accessible structure that has the same size
and alignment requirements as the real semaphore structure. It is provided as a
mechanism for applications to know the size of the semaphore (which is dependent
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 xSemaphoreCreateBinary() 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. */
/* Create the semaphore. xSemaphoreCreateBinaryStatic() has one more
parameter than the usual xSemaphoreCreateBinary() function. The paraemter
is a pointer to the pre-allocated StaticSemaphore_t structure, which will
hold information on the semaphore in an anonymous way. If the pointer is
passed as NULL then the structure will be allocated dynamically, just as
when xSemaphoreCreateBinary() is called. */
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed
into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
/* The semaphore created above had a statically allocated semaphore
structure. Repeat the above using NULL as the xSemaphoreCreateBinaryStatic()
parameter so the queue structure is instead allocated dynamically. */
xSemaphore = xSemaphoreCreateBinaryStatic( NULL );
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
/* There isn't a static version of the old and deprecated
vSemaphoreCreateBinary() macro (because its deprecated!), but check it is
still functioning correctly when configSUPPORT_STATIC_ALLOCATION is set to
1. */
vSemaphoreCreateBinary( xSemaphore );
/* The macro starts with the binary semaphore available, but the test
function expects it to be unavailable. */
if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL )
{
xErrorOccurred = pdTRUE;
}
prvCheckSemaphoreFunction( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
vSemaphoreDelete( xSemaphore );
/* 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;
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. */
/* 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
above for more information. */
static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
/* Create the task. xTaskCreateStatic() has two more parameters than /* Create the task. xTaskCreateStatic() has two more parameters than
the usual xTaskCreate() function. The first new parameter is a pointer to 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 the pre-allocated stack. The second new parameter is a pointer to the
DummyTCB_t structure that will hold the task's TCB. If either pointer is StaticTCB_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 passed as NULL then the respective object will be allocated dynamically as
if xTaskCreate() had been called. */ if xTaskCreate() had been called. */
xReturned = xTaskCreateStatic( xReturned = xTaskCreateStatic(
@ -183,7 +552,10 @@ BaseType_t xReturned;
/* Check the task was created correctly, then delete the task. */ /* Check the task was created correctly, then delete the task. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask ); vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */ /* Ensure lower priority tasks get CPU time. */
@ -202,7 +574,10 @@ BaseType_t xReturned;
&xTCBBuffer ); /* The variable that will hold that task's TCB. */ &xTCBBuffer ); /* The variable that will hold that task's TCB. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask ); vTaskDelete( xCreatedTask );
/* Just to show the check task that this task is still executing. */ /* Just to show the check task that this task is still executing. */
@ -222,7 +597,10 @@ BaseType_t xReturned;
NULL ); /* This time dynamically allocate the TCB. */ NULL ); /* This time dynamically allocate the TCB. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask ); vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */ /* Ensure lower priority tasks get CPU time. */
@ -239,7 +617,10 @@ BaseType_t xReturned;
NULL ); /* This time dynamically allocate the stack and TCB. */ NULL ); /* This time dynamically allocate the stack and TCB. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask ); vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */ /* Ensure lower priority tasks get CPU time. */
@ -248,7 +629,6 @@ BaseType_t xReturned;
/* Just to show the check task that this task is still executing. */ /* Just to show the check task that this task is still executing. */
uxCycleCounter++; uxCycleCounter++;
} }
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvStaticallyAllocatedTask( void *pvParameters ) static void prvStaticallyAllocatedTask( void *pvParameters )
@ -299,13 +679,21 @@ static UBaseType_t uxLastCycleCounter = 0;
BaseType_t xReturn; BaseType_t xReturn;
if( uxCycleCounter == uxLastCycleCounter ) if( uxCycleCounter == uxLastCycleCounter )
{
xErrorOccurred = pdTRUE;
}
else
{
uxLastCycleCounter = uxCycleCounter;
}
if( xErrorOccurred != pdFALSE )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else else
{ {
xReturn = pdPASS; xReturn = pdPASS;
uxLastCycleCounter = uxCycleCounter;
} }
return xReturn; return xReturn;

View file

@ -193,7 +193,7 @@ UBaseType_t ux;
/* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */ /* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ ) for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
{ {
configASSERT( xSemaphoreGetCount( xSemaphore ) == ( countMAX_COUNT_VALUE - ux ) ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == ( countMAX_COUNT_VALUE - ux ) );
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS ) if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS )
{ {
@ -210,7 +210,7 @@ UBaseType_t ux;
/* If the semaphore count is zero then we should not be able to 'take' /* If the semaphore count is zero then we should not be able to 'take'
the semaphore. */ the semaphore. */
configASSERT( xSemaphoreGetCount( xSemaphore ) == 0 ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS ) if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -232,7 +232,7 @@ UBaseType_t ux;
/* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */ /* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ ) for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
{ {
configASSERT( xSemaphoreGetCount( xSemaphore ) == ux ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == ux );
if( xSemaphoreGive( xSemaphore ) != pdPASS ) if( xSemaphoreGive( xSemaphore ) != pdPASS )
{ {

View file

@ -922,7 +922,7 @@ typedef struct xSTATIC_TCB
eDummy eDummy19; eDummy eDummy19;
#endif #endif
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
UBaseType_t uxDummy20; uint8_t uxDummy20;
#endif #endif
} StaticTCB_t; } StaticTCB_t;
@ -964,6 +964,8 @@ typedef struct xSTATIC_QUEUE
} StaticQueue_t; } StaticQueue_t;
typedef StaticQueue_t StaticSemaphore_t;
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -170,7 +170,11 @@ typedef void * QueueSetMemberHandle_t;
* \defgroup xQueueCreate xQueueCreate * \defgroup xQueueCreate xQueueCreate
* \ingroup QueueManagement * \ingroup QueueManagement
*/ */
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( uxQueueLength, uxItemSize, queueQUEUE_TYPE_BASE ) #define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( uxQueueLength, uxItemSize, NULL, NULL, queueQUEUE_TYPE_BASE )
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xQueueCreateStatic( uxQueueLength, uxItemSize, pucQueueStorage, pxStaticQueue ) xQueueGenericCreate( uxQueueLength, uxItemSize, pucQueueStorage, pxStaticQueue, queueQUEUE_TYPE_BASE )
#endif
/** /**
* queue. h * queue. h
@ -1554,7 +1558,7 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION
* Generic version of the queue creation function, which is in turn called by * Generic version of the queue creation function, which is in turn called by
* any queue, semaphore or mutex creation function or macro. * any queue, semaphore or mutex creation function or macro.
*/ */
QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION; QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType ) PRIVILEGED_FUNCTION;
/* /*
* Queue sets provide a mechanism to allow a task to block (pend) on a read * Queue sets provide a mechanism to allow a task to block (pend) on a read

View file

@ -87,6 +87,10 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h * semphr. h
* <pre>vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )</pre> * <pre>vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )</pre>
* *
* In many usage scenarios it is faster and more memory efficient to use a
* direct to task notification in place of a binary semaphore!
* http://www.freertos.org/RTOS-task-notifications.html
*
* This old vSemaphoreCreateBinary() macro is now deprecated in favour of the * This old vSemaphoreCreateBinary() macro is now deprecated in favour of the
* xSemaphoreCreateBinary() function. Note that binary semaphores created using * xSemaphoreCreateBinary() function. Note that binary semaphores created using
* the vSemaphoreCreateBinary() macro are created in a state such that the * the vSemaphoreCreateBinary() macro are created in a state such that the
@ -130,7 +134,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
*/ */
#define vSemaphoreCreateBinary( xSemaphore ) \ #define vSemaphoreCreateBinary( xSemaphore ) \
{ \ { \
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \ ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, NULL, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
if( ( xSemaphore ) != NULL ) \ if( ( xSemaphore ) != NULL ) \
{ \ { \
( void ) xSemaphoreGive( ( xSemaphore ) ); \ ( void ) xSemaphoreGive( ( xSemaphore ) ); \
@ -141,6 +145,10 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h * semphr. h
* <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre> * <pre>SemaphoreHandle_t xSemaphoreCreateBinary( void )</pre>
* *
* In many usage scenarios it is faster and more memory efficient to use a
* direct to task notification in place of a binary semaphore!
* http://www.freertos.org/RTOS-task-notifications.html
*
* The old vSemaphoreCreateBinary() macro is now deprecated in favour of this * The old vSemaphoreCreateBinary() macro is now deprecated in favour of this
* xSemaphoreCreateBinary() function. Note that binary semaphores created using * xSemaphoreCreateBinary() function. Note that binary semaphores created using
* the vSemaphoreCreateBinary() macro are created in a state such that the * the vSemaphoreCreateBinary() macro are created in a state such that the
@ -182,7 +190,8 @@ typedef QueueHandle_t SemaphoreHandle_t;
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
* \ingroup Semaphores * \ingroup Semaphores
*/ */
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ) #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 )
/** /**
* semphr. h * semphr. h
@ -849,7 +858,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semaphore is not available. * semaphore is not available.
* *
*/ */
#define xSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) ) #define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
#endif /* SEMAPHORE_H */ #endif /* SEMAPHORE_H */

View file

@ -128,12 +128,6 @@ typedef enum
eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */ eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */
} eNotifyAction; } eNotifyAction;
/* For data hiding purposes. */
typedef enum
{
eNothing = 0
} eDummy;
/* /*
* Used internally only. * Used internally only.
*/ */
@ -197,58 +191,6 @@ typedef enum
eNotified eNotified
} eNotifyValue; } eNotifyValue;
/*
* 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.
*/
typedef struct xDUMMY_TCB
{
void *pxDummy1;
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xDummy2;
#endif
ListItem_t xDummy3[ 2 ];
UBaseType_t uxDummy5;
void *pxDummy6;
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
#if ( portSTACK_GROWTH > 0 )
void *pxDummy8;
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxDummy9;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxDummy10[ 2 ];
#endif
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxDummy12[ 2 ];
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
void *pxDummy14;
#endif
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
uint32_t ulDummy16;
#endif
#if ( configUSE_NEWLIB_REENTRANT == 1 )
struct _reent xDummy17;
#endif
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
uint32_t ulDummy18;
eDummy eDummy19;
#endif
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
UBaseType_t uxDummy20;
#endif
} DummyTCB_t;
/** /**
* Defines the priority used by the idle task. This must not be modified. * Defines the priority used by the idle task. This must not be modified.
* *
@ -420,7 +362,7 @@ is used in assert() statements. */
UBaseType_t uxPriority, UBaseType_t uxPriority,
TaskHandle_t *pvCreatedTask, TaskHandle_t *pvCreatedTask,
StackType_t *pxStackBuffer, StackType_t *pxStackBuffer,
DummyTCB_t *pxTCBBuffer StaticTCB_t *pxTCBBuffer
);</pre> );</pre>
* *
* Create a new task and add it to the list of tasks that are ready to run. * Create a new task and add it to the list of tasks that are ready to run.
@ -460,7 +402,7 @@ is used in assert() statements. */
* @param pxTCBBuffer If pxTCBBuffer is NULL then the TCB (which is the * @param pxTCBBuffer If pxTCBBuffer is NULL then the TCB (which is the
* structures used internally within FreeRTOS to hold information on the task) * structures used internally within FreeRTOS to hold information on the task)
* will be allocated dynamically, just as when xTaskCreate() is used. If * will be allocated dynamically, just as when xTaskCreate() is used. If
* pxTCBBuffer is not NULL then it must point to a variable of type DummyTCB_T, * pxTCBBuffer is not NULL then it must point to a variable of type StaticTCB_t,
* which will then be used as the TCB of the task being created. * 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 * @return pdPASS if the task was successfully created and added to a ready
@ -476,7 +418,7 @@ is used in assert() statements. */
#define STACK_SIZE 200 #define STACK_SIZE 200
// Structure that will hold the TCB of the task being created. // Structure that will hold the TCB of the task being created.
DummyTCB_t xTCB; StaticTCB_t xTCB;
// Buffer that the task being created will use as its stack. // Buffer that the task being created will use as its stack.
StackType_t xStack[ STACK_SIZE ]; StackType_t xStack[ STACK_SIZE ];
@ -2153,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 * Generic version of the task creation function which is in turn called by the
* xTaskCreate() and xTaskCreateRestricted() macros. * 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, DummyTCB_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, StaticTCB_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. * Get the uxTCBNumber assigned to the task referenced by the xTask parameter.

View file

@ -239,6 +239,17 @@ static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvIte
*/ */
static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION; static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer ) PRIVILEGED_FUNCTION;
/*
* A queue requires two blocks of memory; a structure to hold the queue state
* and a storage area to hold the items in the queue. The memory is assigned
* by prvAllocateQueueMemory(). If ppucQueueStorage is NULL then the queue
* storage will allocated dynamically, otherwise the buffer passed in
* ppucQueueStorage will be used. If pxStaticQueue is NULL then the queue
* structure will be allocated dynamically, otherwise the buffer pointed to by
* pxStaticQueue will be used.
*/
static Queue_t *prvAllocateQueueMemory( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t **ppucQueueStorage, StaticQueue_t *pxStaticQueue );
#if ( configUSE_QUEUE_SETS == 1 ) #if ( configUSE_QUEUE_SETS == 1 )
/* /*
* Checks to see if a queue is a member of a queue set, and if so, notifies * Checks to see if a queue is a member of a queue set, and if so, notifies
@ -331,8 +342,8 @@ size_t xQueueSizeInBytes;
#if( ( configASSERT_DEFINED == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) #if( ( configASSERT_DEFINED == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
{ {
/* Sanity check that the size of the structure used to declare a /* Sanity check that the size of the structure used to declare a
variable of type DummyQueue_t or DummySemaphore_t equals the size of the variable of type StaticQueue_t or StaticSemaphore_t equals the size of
real queue and semaphore structures. */ the real queue and semaphore structures. */
volatile size_t xSize = sizeof( StaticQueue_t ); volatile size_t xSize = sizeof( StaticQueue_t );
configASSERT( xSize == sizeof( Queue_t ) ); configASSERT( xSize == sizeof( Queue_t ) );
} }
@ -345,9 +356,9 @@ size_t xQueueSizeInBytes;
} }
else else
{ {
/* The queue is one byte longer than asked for to make wrap checking /* Allocate enough space to hold the maximum number of items that can be
easier/faster. */ in the queue at any time. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
} }
#if( configSUPPORT_STATIC_ALLOCATION == 0 ) #if( configSUPPORT_STATIC_ALLOCATION == 0 )
@ -399,8 +410,17 @@ size_t xQueueSizeInBytes;
{ {
vPortFree( ( void * ) pxNewQueue ); vPortFree( ( void * ) pxNewQueue );
} }
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewQueue = NULL; pxNewQueue = NULL;
} }
else
{
mtCOVERAGE_TEST_MARKER();
}
} }
else else
{ {
@ -1860,6 +1880,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
freed. */ freed. */
vPortFree( pxQueue->pcHead ); vPortFree( pxQueue->pcHead );
} }
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( pxQueue->ucStaticAllocationFlags & queueSTATICALLY_ALLOCATED_QUEUE_STRUCT ) == 0 ) if( ( pxQueue->ucStaticAllocationFlags & queueSTATICALLY_ALLOCATED_QUEUE_STRUCT ) == 0 )
{ {
@ -1867,6 +1891,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
free. */ free. */
vPortFree( pxQueue ); vPortFree( pxQueue );
} }
else
{
mtCOVERAGE_TEST_MARKER();
}
} }
#endif #endif
} }