范例:使用 xTaskCreateStatic 静态创建任务
// Dimensions the buffer that the task being created will use as its stack.
#define STACK_SIZE 200
// Structure that will hold the TCB of the task being created.
StaticTask_t xTaskBuffer;
// Buffer that the task being created will use as its stack.
StackType_t xStack[ STACK_SIZE ];
// Function that implements the task being created.
void vTaskCode( void * pvParameters )
{
configASSERT( ( uint32_t ) pvParameters == 1UL );
for( ;; )
{
// Task code goes here.
}
}
// Function that creates a task.
void vOtherFunction( void )
{
TaskHandle_t xHandle = NULL;
xHandle = xTaskCreateStatic(
vTaskCode, // Function that implements the task.
"NAME", // Text name for the task.
STACK_SIZE, // Stack size in words, not bytes.
( void * ) 1, // Parameter passed into the task.
tskIDLE_PRIORITY,// Priority at which the task is created.
xStack, // Array to use as the task's stack.
&xTaskBuffer ); // Variable to hold the task's data structure.
vTaskSuspend( xHandle );
}
Internally, within the FreeRTOS implementation, tasks use two blocks of memory. The first block is used to hold the task’s data structures. The second block is used by the task as its stack. If a task is created using xTaskCreateStatic() then the application writer must provide the required memory. xTaskCreateStatic() therefore allows a task to be created without using any dynamic memory allocation.
TCB
/*
* Task control block. A task control block (TCB) is allocated for each task,
* and stores task state information, including a pointer to the task's context
* (the task's run time environment, including register values)
*/
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. */
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
StackType_t *pxStack; /*< Points to the start of the stack. */
char pcTaskName[configMAX_TASK_NAME_LEN]; /*< Descriptive name given to the task when created. */
StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
} tskTCB;
typedef tskTCB TCB_t;
静态创建任务 xTaskCreateStatic 的源码
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer )
{
TCB_t *pxNewTCB;
TaskHandle_t xReturn;
configASSERT( puxStackBuffer != NULL );
configASSERT( pxTaskBuffer != NULL );
if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
{
pxNewTCB = ( TCB_t * ) pxTaskBuffer;
pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
prvAddNewTaskToReadyList( pxNewTCB );
}
else
{
xReturn = NULL;
}
return xReturn;
}
设置列表项owner和value的宏定义
/*
* Access macro to set the owner of a list item. The owner of a list item
* is the object (usually a TCB) that contains the list item.
*/
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/*
* Access macro to set the value of the list item. In most cases the value is
* used to sort the list in descending order.
*/
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
列表声明
/*
* Definition of the only type of object that a list can contain.
*/
struct xLIST_ITEM
{
/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
/*< The value being listed. In most cases this is used to sort the list in descending order. */
configLIST_VOLATILE TickType_t xItemValue;
/*< Pointer to the next ListItem_t in the list. */
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
/*< Pointer to the previous ListItem_t in the list. */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
/*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
void * pvOwner;
/*< Pointer to the list in which this list item is placed (if any). */
void * configLIST_VOLATILE pvContainer;
/*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
};
/* For some reason lint wants this as two separate definitions. */
typedef struct xLIST_ITEM ListItem_t;
初始化任务列表
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB,
const MemoryRegion_t * const xRegions )
{
StackType_t *pxTopOfStack;
UBaseType_t x;
/* Calculate the top of stack address. */
{
pxTopOfStack = pxNewTCB->pxStack;
/* Check the alignment of the stack buffer is correct. */
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
/* The other extreme of the stack space is required if stack checking is performed. */
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
}
/* Store the task name in the TCB. */
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
if( pcName[ x ] == 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* Ensure the name string is terminated in the case that the string length
was greater or equal to configMAX_TASK_NAME_LEN. */
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
/* This is used as an array index so must ensure it's not too large. First
remove the privilege bit if one is present. */
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewTCB->uxPriority = uxPriority;
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
/* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get
back to the containing TCB from a generic item in a list. */
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
{
/* Avoid compiler warning about unreferenced parameter. */
( void ) xRegions;
}
/* Initialize the TCB stack to look as if the task was already running,
but had been interrupted by the scheduler. The return address is set
to the start of the task function. Once the stack has been initialised
the top of stack variable is updated. */
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
if( ( void * ) pxCreatedTask != NULL )
{
/* Pass the handle out in an anonymous way. The handle can be used to
change the created task's priority, delete the created task, etc.*/
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
把新创建的任务添加的任务列表
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks++;
if( pxCurrentTCB == NULL )
{
pxCurrentTCB = pxNewTCB;
/* This is the first task to be created so do the preliminary initialisation required.*/
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
{
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* If the scheduler is not already running, make this task the
current task if it is the highest priority task to be created
so far. */
if( xSchedulerRunning == pdFALSE )
{
if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++;
traceTASK_CREATE( pxNewTCB );
prvAddTaskToReadyList( pxNewTCB );
portSETUP_TCB( pxNewTCB );
}
taskEXIT_CRITICAL();
if( xSchedulerRunning != pdFALSE )
{
if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
定义任务数量为0
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U;
初始化列表 list
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first task.
*/
static void prvInitialiseTaskLists( void )
{
UBaseType_t uxPriority;
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
}
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
vListInitialise( &xPendingReadyList );
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList using list2. */
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
全局变量声明
/* Lists for ready and blocked tasks. --------------------*/
/*< Prioritised ready tasks. */
PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
/*< Delayed tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList1;
/*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t xDelayedTaskList2;
/*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
PRIVILEGED_DATA static List_t xPendingReadyList;