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

@ -374,15 +374,15 @@ volatile size_t x;
/* Extremely crude standard library implementations in lieu of having a C
library. */
for( x = 0; x < xBytes; x++ )
{
if( pucMem1[ x ] != pucMem2[ x ] )
{
break;
}
}
for( x = 0; x < xBytes; x++ )
{
if( pucMem1[ x ] != pucMem2[ x ] )
{
break;
}
}
return xBytes - x;
return xBytes - x;
}
/*-----------------------------------------------------------*/
@ -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
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
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
* 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
* 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. */
@ -119,9 +122,9 @@ uint32_t ulDivider, ulTCCLKS;
NVIC_ClearPendingIRQ( TC1_IRQn );
NVIC_SetPriority( TC0_IRQn, tmrLOWER_PRIORITY );
NVIC_SetPriority( TC1_IRQn, tmrHIGHER_PRIORITY );
NVIC_EnableIRQ( TC0_IRQn );
NVIC_EnableIRQ( TC1_IRQn );
NVIC_EnableIRQ( TC0_IRQn );
NVIC_EnableIRQ( TC1_IRQn );
/* Start the timer last of all. */
tc_start( TC0, 0 );
}
@ -144,7 +147,7 @@ static uint32_t ulISRCount = 0;
/* Pend an interrupt that will nest with this interrupt. */
NVIC_SetPendingIRQ( TC1_IRQn );
}
/* Call the IntQ test function for this channel. */
portYIELD_FROM_ISR( xFirstTimerHandler() );
}

View File

@ -70,12 +70,11 @@
/*
* Demonstrates how to create FreeRTOS objects using pre-allocated memory,
* rather than the normal dynamically allocated memory. Currently only tasks
* are being allocated statically.
* 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).
* prvStaticallyAllocatedTaskCreator() creates and deletes tasks with all
* prvStaticallyAllocatedCreator() creates and deletes tasks with all
* possible combinations of statically allocated and dynamically allocated
* stacks and TCBs.
*/
@ -83,6 +82,8 @@
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* Demo program include files. */
#include "StaticAllocation.h"
@ -90,26 +91,60 @@
/* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
#define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
/* The priority at which the task that performs the tests is created. */
#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
* allocated stack and TCB.
* 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 creates and deletes the prvStaticallyAllocatedTask() task,
* using various priorities, and sometimes with statically and sometimes
* dynamically allocated stack and TCB.
* The task that repeatedly creates and deletes statically allocated tasks, and
* other RTOS objects.
*/
static void prvStaticallyAllocatedTaskCreator( void *pvParameters );
static void prvStaticallyAllocatedCreator( void *pvParameters );
/*
* Utility function to create pseudo random numbers.
*/
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
* 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 );
/*
* 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
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 DummyTCB_t variable is passed into
the xTaskCreateStatic() function, and will hold the task's TCB. */
static DummyTCB_t xTCBBuffer;
hiding policy by exposing the real TCB. This StaticTCB_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;
/* This is the stack that will be used by the task. The alignment requirements
for the stack depend on the architecture, and the method of forcing an alignment
is dependent on the compiler, but any bad alignment is corrected inside the
FreeRTOS code. */
static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
/* 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 ];
/* Used by the pseudo random number generating function. */
static uint32_t ulNextRand = 0;
@ -141,6 +187,9 @@ static uint32_t ulNextRand = 0;
stalled. */
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 )
@ -148,109 +197,440 @@ 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. */
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. */
ulNextRand = ( uint32_t ) prvRand;
}
/*-----------------------------------------------------------*/
static void prvStaticallyAllocatedTaskCreator( void *pvParameters )
static void prvStaticallyAllocatedCreator( void *pvParameters )
{
TaskHandle_t xCreatedTask;
BaseType_t xReturned;
/* Avoid compiler warnings. */
( void ) pvParameters;
for( ;; )
{
/* 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
DummyTCB_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(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
tskIDLE_PRIORITY, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
&( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
&xTCBBuffer ); /* The variable that will hold that task's TCB. */
/* Check the task was created correctly, then delete the task. */
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
/* Create and delete the task a few times again - testing both static and
dynamic allocation for the stack and TCB. */
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
staticTASK_PRIORITY + 1, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
NULL, /* This time, dynamically allocate the stack. */
&xTCBBuffer ); /* The variable that will hold that task's TCB. */
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
vTaskDelete( xCreatedTask );
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
staticTASK_PRIORITY - 1, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
&( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
NULL ); /* This time dynamically allocate the TCB. */
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
staticTASK_PRIORITY, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
NULL, /* This time dynamically allocate the stack and TCB. */
NULL ); /* This time dynamically allocate the stack and TCB. */
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
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
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
passed as NULL then the respective object will be allocated dynamically as
if xTaskCreate() had been called. */
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
tskIDLE_PRIORITY, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
&( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
&xTCBBuffer ); /* The variable that will hold that task's TCB. */
/* Check the task was created correctly, then delete the task. */
configASSERT( xReturned == pdPASS );
if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
/* Create and delete the task a few times again - testing both static and
dynamic allocation for the stack and TCB. */
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
staticTASK_PRIORITY + 1, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
NULL, /* This time, dynamically allocate the stack. */
&xTCBBuffer ); /* The variable that will hold that task's TCB. */
configASSERT( xReturned == pdPASS );
if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask );
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
staticTASK_PRIORITY - 1, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
&( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
NULL ); /* This time dynamically allocate the TCB. */
configASSERT( xReturned == pdPASS );
if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
xReturned = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
staticTASK_PRIORITY, /* The priority of the task. */
&xCreatedTask, /* Handle of the task being created. */
NULL, /* This time dynamically allocate the stack and TCB. */
NULL ); /* This time dynamically allocate the stack and TCB. */
configASSERT( xReturned == pdPASS );
if( xReturned != pdPASS )
{
xErrorOccurred = pdTRUE;
}
vTaskDelete( xCreatedTask );
/* Ensure lower priority tasks get CPU time. */
vTaskDelay( prvGetNextDelayTime() );
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
}
/*-----------------------------------------------------------*/
static void prvStaticallyAllocatedTask( void *pvParameters )
{
( void ) pvParameters;
@ -299,13 +679,21 @@ static UBaseType_t uxLastCycleCounter = 0;
BaseType_t xReturn;
if( uxCycleCounter == uxLastCycleCounter )
{
xErrorOccurred = pdTRUE;
}
else
{
uxLastCycleCounter = uxCycleCounter;
}
if( xErrorOccurred != pdFALSE )
{
xReturn = pdFAIL;
}
else
{
xReturn = pdPASS;
uxLastCycleCounter = uxCycleCounter;
}
return xReturn;

View File

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

View File

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

View File

@ -170,7 +170,11 @@ typedef void * QueueSetMemberHandle_t;
* \defgroup xQueueCreate xQueueCreate
* \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
@ -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
* 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

View File

@ -87,6 +87,10 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semphr. h
* <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
* xSemaphoreCreateBinary() function. Note that binary semaphores created using
* the vSemaphoreCreateBinary() macro are created in a state such that the
@ -128,19 +132,23 @@ typedef QueueHandle_t SemaphoreHandle_t;
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
* \ingroup Semaphores
*/
#define vSemaphoreCreateBinary( xSemaphore ) \
{ \
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
if( ( xSemaphore ) != NULL ) \
{ \
( void ) xSemaphoreGive( ( xSemaphore ) ); \
} \
#define vSemaphoreCreateBinary( xSemaphore ) \
{ \
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, NULL, queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
if( ( xSemaphore ) != NULL ) \
{ \
( void ) xSemaphoreGive( ( xSemaphore ) ); \
} \
}
/**
* semphr. h
* <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
* xSemaphoreCreateBinary() function. Note that binary semaphores created using
* the vSemaphoreCreateBinary() macro are created in a state such that the
@ -182,7 +190,8 @@ typedef QueueHandle_t SemaphoreHandle_t;
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
* \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
@ -849,7 +858,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* semaphore is not available.
*
*/
#define xSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
#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. */
} eNotifyAction;
/* For data hiding purposes. */
typedef enum
{
eNothing = 0
} eDummy;
/*
* Used internally only.
*/
@ -197,58 +191,6 @@ typedef enum
eNotified
} 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.
*
@ -420,14 +362,14 @@ is used in assert() statements. */
UBaseType_t uxPriority,
TaskHandle_t *pvCreatedTask,
StackType_t *pxStackBuffer,
DummyTCB_t *pxTCBBuffer
StaticTCB_t *pxTCBBuffer
);</pre>
*
* Create a new task and add it to the list of tasks that are ready to run.
* If a task is created using xTaskCreate() then the stack and task control
* If a task is created using xTaskCreate() then the stack and task control
* block (TCB) used by the task are allocated dynamically. If a task is created
* using xTaskCreateStatic() then the application writer can optionally provide
* the buffers that will hold the task stack and TCB respectively.
* the buffers that will hold the task stack and TCB respectively.
* xTaskCreateStatic() therefore allows tasks to be created without any dynamic
* memory allocation.
*
@ -435,7 +377,7 @@ is used in assert() statements. */
* must be implemented to never return (i.e. continuous loop).
*
* @param pcName A descriptive name for the task. This is mainly used to
* facilitate debugging. The maximum length of the string is defined by
* facilitate debugging. The maximum length of the string is defined by
* configMAX_TASK_NAME_LEN in FreeRTOSConfig.h.
*
* @param usStackDepth The size of the task stack specified as the number of
@ -453,14 +395,14 @@ is used in assert() statements. */
*
* @param pxStackBuffer If pxStackBuffer is NULL then the stack used by the
* task will be allocated dynamically, just as if the task was created using
* xTaskCreate(). if pxStackBuffer is not NULL then it must point to a
* xTaskCreate(). if pxStackBuffer is not NULL then it must point to a
* StackType_t array that has at least usStackDepth indexes - the array will
* then be used as the task's stack.
*
* @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 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.
*
* @return pdPASS if the task was successfully created and added to a ready
@ -476,11 +418,11 @@ is used in assert() statements. */
#define STACK_SIZE 200
// 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.
StackType_t xStack[ STACK_SIZE ];
// Task to be created.
void vTaskCode( void * pvParameters )
{
@ -500,7 +442,7 @@ is used in assert() statements. */
xTaskCreate( vTaskCode, // As per xTaskCreate() parameter.
"NAME", // As per xTaskCreate() parameter.
STACK_SIZE, // As per xTaskCreate() parameter.
&ucParameterToPass, // As per xTaskCreate() parameter.
&ucParameterToPass, // As per xTaskCreate() parameter.
tskIDLE_PRIORITY, // As per xTaskCreate() parameter.
&xHandle, // As per xTaskCreate() parameter.
xStack, // Pointer to the buffer that the task being created will use as its stack.
@ -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
* 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.

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;
/*
* 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 )
/*
* 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 ) )
{
/* 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
real queue and semaphore structures. */
variable of type StaticQueue_t or StaticSemaphore_t equals the size of
the real queue and semaphore structures. */
volatile size_t xSize = sizeof( StaticQueue_t );
configASSERT( xSize == sizeof( Queue_t ) );
}
@ -345,9 +356,9 @@ size_t xQueueSizeInBytes;
}
else
{
/* The queue is one byte longer than asked for to make wrap checking
easier/faster. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
/* Allocate enough space to hold the maximum number of items that can be
in the queue at any time. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
}
#if( configSUPPORT_STATIC_ALLOCATION == 0 )
@ -361,7 +372,7 @@ size_t xQueueSizeInBytes;
storage area. */
*ppucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t );
}
/* The pxStaticQueue parameter is not used. Remove compiler warnings. */
( void ) pxStaticQueue;
}
@ -399,8 +410,17 @@ size_t xQueueSizeInBytes;
{
vPortFree( ( void * ) pxNewQueue );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewQueue = NULL;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
@ -1860,6 +1880,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
freed. */
vPortFree( pxQueue->pcHead );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( pxQueue->ucStaticAllocationFlags & queueSTATICALLY_ALLOCATED_QUEUE_STRUCT ) == 0 )
{
@ -1867,6 +1891,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
free. */
vPortFree( pxQueue );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
}