任务创建函数
BaseType_t xTaskCreate(TaskFunction_t pxTaskCode, const char *const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void *const pvParameters, UBaseType_t uxPriority,
TaskHandle_t *const pxCreatedTask)
pvTaskCode: 函数指针
pcName: 任务名
usStackDepth: 栈空间大小(((size_t)usStackDepth) * sizeof(StackType_t))
pvParameters: 参数指针
uxPriority: 任务的优先级(数值越小优先级越低)
pvCreatedTask:任务句柄
任务控制块
/* 任务TCB */
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; /* 栈顶地址 */
#if (portUSING_MPU_WRAPPERS == 1)
xMPU_SETTINGS xMPUSettings;
#endif
ListItem_t xStateListItem; /* 状态列表项:运行、就绪、阻塞、挂起、删除 */
ListItem_t xEventListItem; /* 事件列表项:任务优先级 */
UBaseType_t uxPriority; /* 优先级 */
StackType_t *pxStack; /* 栈指针 */
char pcTaskName[configMAX_TASK_NAME_LEN]; /* 任务名 */
#if ((portSTACK_GROWTH > 0) || (configRECORD_STACK_HIGH_ADDRESS == 1))
StackType_t *pxEndOfStack;
#endif
#if (portCRITICAL_NESTING_IN_TCB == 1)
UBaseType_t uxCriticalNesting;
#endif
#if (configUSE_TRACE_FACILITY == 1)
UBaseType_t uxTCBNumber;
UBaseType_t uxTaskNumber;
#endif
#if (configUSE_MUTEXES == 1)
UBaseType_t uxBasePriority;
UBaseType_t uxMutexesHeld;
#endif
#if (configUSE_APPLICATION_TASK_TAG == 1)
TaskHookFunction_t pxTaskTag;
#endif
#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0)
void *pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS];
#endif
#if (configGENERATE_RUN_TIME_STATS == 1)
uint32_t ulRunTimeCounter;
#endif
#if (configUSE_NEWLIB_REENTRANT == 1)
struct _reent xNewLib_reent;
#endif
#if (configUSE_TASK_NOTIFICATIONS == 1)
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0)
uint8_t ucStaticallyAllocated;
#endif
#if (INCLUDE_xTaskAbortDelay == 1)
uint8_t ucDelayAborted;
#endif
#if (configUSE_POSIX_ERRNO == 1)
int iTaskErrno;
#endif
}tskTCB;
typedef tskTCB TCB_t;
创建任务:
1.申请栈内存
2.申请TCB内存
3.初始化任务名、优先级、状态列表项、事件列表项、初始化栈
4.将任务加入就绪列表,如果优先级高于当前任务优先级进行抢占
BaseType_t xTaskCreate(TaskFunction_t pxTaskCode, const char *const pcName,
const configSTACK_DEPTH_TYPE usStackDepth, void *const pvParameters,
UBaseType_t uxPriority, TaskHandle_t *const pxCreatedTask)
{
TCB_t *pxNewTCB;
BaseType_t xReturn;
#if (portSTACK_GROWTH > 0)
{
pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t));
if(pxNewTCB != NULL)
{
pxNewTCB->pxStack = (StackType_t *)pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));
if(pxNewTCB->pxStack == NULL)
{
vPortFree(pxNewTCB);
pxNewTCB = NULL;
}
}
}
#else
{
StackType_t *pxStack;
/* 从堆区中动态分配任务栈空间 */
pxStack = pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));
if(pxStack != NULL)
{
/* 从堆区中动态分配TCB内存空间 */
pxNewTCB = (TCB_t *)pvPortMalloc(sizeof(TCB_t));
if(pxNewTCB != NULL)
{
/* 初始化任务栈指针 */
pxNewTCB->pxStack = pxStack;
}
else
{
vPortFree(pxStack);
}
}
else
{
pxNewTCB = NULL;
}
}
#endif
if(pxNewTCB != NULL)
{
#if (tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0)
{
pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
}
#endif
/* 初始化TCB的一些数据:任务名、优先级、状态列表项、事件列表项、栈 */
prvInitialiseNewTask(pxTaskCode, pcName, (uint32_t)usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL);
/* 将新任务加入就绪列表,如果是第一个任务则设置为当前任务或者优先级高于当前任务优先级进行抢占 */
prvAddNewTaskToReadyList(pxNewTCB);
/* 任务创建成功 */
xReturn = pdPASS;
}
else
{
/* 堆空间不足 */
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
详细看一下,初始化新任务TCB和将新任务加入就绪列表
/* 初始化新任务TCB */
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;
#if (portUSING_MPU_WRAPPERS == 1)
BaseType_t xRunPrivileged;
if((uxPriority & portPRIVILEGE_BIT) != 0U)
{
xRunPrivileged = pdTRUE;
}
else
{
xRunPrivileged = pdFALSE;
}
uxPriority &= ~portPRIVILEGE_BIT;
#endif
configASSERT(pcName);
#if (tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1)
{
(void)memset(pxNewTCB->pxStack, (int)tskSTACK_FILL_BYTE, (size_t)ulStackDepth * sizeof(StackType_t));
}
#endif
#if (portSTACK_GROWTH < 0)
{
/* 初始化栈顶指针 */
pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth - (uint32_t)1]);
pxTopOfStack = (StackType_t *)(((portPOINTER_SIZE_TYPE)pxTopOfStack) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
configASSERT((((portPOINTER_SIZE_TYPE)pxTopOfStack & (portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK) == 0UL));
#if (configRECORD_STACK_HIGH_ADDRESS == 1)
{
pxNewTCB->pxEndOfStack = pxTopOfStack;
}
#endif
}
#else
{
pxTopOfStack = pxNewTCB->pxStack;
configASSERT((((portPOINTER_SIZE_TYPE)pxNewTCB->pxStack & (portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK) == 0UL));
pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + (ulStackDepth - (uint32_t)1);
}
#endif
/* 初始化任务名 */
for(x = (UBaseType_t)0; x < (UBaseType_t)configMAX_TASK_NAME_LEN; x++)
{
pxNewTCB->pcTaskName[x] = pcName[x];
if(pcName[x] == (char)0x00)
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0';
/* 初始化优先级 */
if(uxPriority >= (UBaseType_t)configMAX_PRIORITIES)
{
uxPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewTCB->uxPriority = uxPriority;
#if (configUSE_MUTEXES == 1)
{
pxNewTCB->uxBasePriority = uxPriority;
pxNewTCB->uxMutexesHeld = 0;
}
#endif
/* 初始化状态列表项,不指向任何列表 */
vListInitialiseItem(&(pxNewTCB->xStateListItem));
/* 初始化事件列表项,不指向任何列表 */
vListInitialiseItem(&(pxNewTCB->xEventListItem));
/* 设置状态列表项所属TCB */
listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB);
/* 设置事件列表项值为任务优先级 */
listSET_LIST_ITEM_VALUE(&(pxNewTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriority);
/* 设置事件列表项所属TCB */
listSET_LIST_ITEM_OWNER(&(pxNewTCB->xEventListItem), pxNewTCB);
#if (portCRITICAL_NESTING_IN_TCB == 1)
{
pxNewTCB->uxCriticalNesting = (UBaseType_t)0U;
}
#endif
#if (configUSE_APPLICATION_TASK_TAG == 1)
{
pxNewTCB->pxTaskTag = NULL;
}
#endif
#if (configGENERATE_RUN_TIME_STATS == 1)
{
pxNewTCB->ulRunTimeCounter = 0UL;
}
#endif
#if (portUSING_MPU_WRAPPERS == 1)
{
vPortStoreTaskMPUSettings(&(pxNewTCB->xMPUSettings), xRegions, pxNewTCB->pxStack, ulStackDepth);
}
#else
{
(void)xRegions;
}
#endif
#if (configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0)
{
for(x = 0; x < (UBaseType_t)configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++)
{
pxNewTCB->pvThreadLocalStoragePointers[x] = NULL;
}
}
#endif
#if (configUSE_TASK_NOTIFICATIONS == 1)
{
pxNewTCB->ulNotifiedValue = 0;
pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
}
#endif
#if (configUSE_NEWLIB_REENTRANT == 1)
{
_REENT_INIT_PTR((&(pxNewTCB->xNewLib_reent)));
}
#endif
#if (INCLUDE_xTaskAbortDelay == 1)
{
pxNewTCB->ucDelayAborted = pdFALSE;
}
#endif
#if (portUSING_MPU_WRAPPERS == 1)
{
pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged);
}
#else
{
/* 初始化任务栈 */
pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
}
#endif
/* 返回任务句柄(TCB指针) */
if(pxCreatedTask != NULL)
{
*pxCreatedTask = (TaskHandle_t)pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 将新任务加入就绪列表 */
static void prvAddNewTaskToReadyList(TCB_t *pxNewTCB)
{
/* 进入临界区 */
taskENTER_CRITICAL();
{
/* 当前任务数加一 */
uxCurrentNumberOfTasks++;
/* 第一个任务 */
if(pxCurrentTCB == NULL)
{
/* 初始化当前任务 */
pxCurrentTCB = pxNewTCB;
if(uxCurrentNumberOfTasks == (UBaseType_t)1)
{
/* 初始化所有任务列表 */
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* 调度器没有正在运行 */
if(xSchedulerRunning == pdFALSE)
{
/* 如果新任务优先级高于当前任务优先级,将新任务切换成当前任务 */
if(pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority)
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* 任务数id号加一 */
uxTaskNumber++;
#if (configUSE_TRACE_FACILITY == 1)
{
pxNewTCB->uxTCBNumber = uxTaskNumber;
}
#endif
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();
}
}
在看初始化任务堆栈源代码之前,先了解一下基础知识,参考《Cortex-M3 权威指南》的第九章(中断的具体行为)
发生异常之后会自动进行三个步骤:
1.入栈 2.取向量 3.选择堆栈指针MSP/PSP,更新堆栈指针SP,更新链接寄存器LR,更新程序计数器PC
初始化任务栈其实就是模拟异常发生之后的自动入栈过程
/* 初始化任务栈 */
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
{
/* 初始化xPSR值0x01000000 */
/* APSR中N、Z、C、V、Q均为0 */
/* IPSR为中断号,线程模式时为0 */
/* EPSR中T=1(STM32属于thumb),ICI/IT=0(没搞懂) */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR;
/* 初始化PC值,LSB始终为0 */
pxTopOfStack--;
*pxTopOfStack = ((StackType_t)pxCode) & portSTART_ADDRESS_MASK;
/* 初始化链接寄存器,正常任务都是死循环,一旦退出进入prvTaskExitError */
pxTopOfStack--;
*pxTopOfStack = (StackType_t)prvTaskExitError; /* LR */
/* 预留R1、R2、R3、R12空间 */
/* 初始化R0为任务参数 */
pxTopOfStack -= 5;
*pxTopOfStack = (StackType_t)pvParameters;
/* 预留R4、R5、R6、R7、R8、R9、R10、R11空间 */
pxTopOfStack -= 8;
return pxTopOfStack;
}