任务定义
//宏定义 任务创建函数 #define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
//任务 创建任务 signed portBASE_TYPE xTaskGenericCreate( pdTASK_CODE pxTaskCode,///指向任务的入口函数. const signed char * const pcName, //描述任务的名字。主要便于调试 unsigned short usStackDepth, //指定任务堆栈的深度 void *pvParameters, //指针用于作为一个参数传向创建的任务 unsigned portBASE_TYPE uxPriority, //任务运行时的优先级 xTaskHandle *pxCreatedTask, //用于传出任务的句柄,在API对该创建出来的任务进行引用如改变任务优先级 portSTACK_TYPE *puxStackBuffer, //堆栈缓冲区 const xMemoryRegion * const xRegions /*缓存区*/ ) { signed portBASE_TYPE xReturn; tskTCB * pxNewTCB; configASSERT( pxTaskCode ); configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) ); /* 为TCB 和 堆栈分配空间 */ pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer ); if( pxNewTCB != NULL ) /* 如果 TCB 空间分配成功 */ { portSTACK_TYPE *pxTopOfStack; #if( portUSING_MPU_WRAPPERS == 1 ) /* Should the task be created in privileged mode? 特权模式 */ portBASE_TYPE xRunPrivileged; if( ( uxPriority & portPRIVILEGE_BIT ) != 0U ) { xRunPrivileged = pdTRUE; } else { xRunPrivileged = pdFALSE; } uxPriority &= ~portPRIVILEGE_BIT; #endif /* portUSING_MPU_WRAPPERS == 1 */ /* 计算堆栈栈顶的位置 */ #if( portSTACK_GROWTH < 0 ) { pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( unsigned short ) 1 ); /* pxStack 指向堆栈的起始地址 */ pxTopOfStack = ( portSTACK_TYPE * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */ /* 堆栈有地址对齐的要求 */ /*内存对齐 */ configASSERT( ( ( ( unsigned long ) pxTopOfStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); } #else /* portSTACK_GROWTH */ { pxTopOfStack = pxNewTCB->pxStack; /* 新建的堆栈是空的,所以堆栈的栈顶就在起始地址处(正生堆栈)*/ /* 内存对齐 */ configASSERT( ( ( ( unsigned long ) pxNewTCB->pxStack & ( unsigned long ) portBYTE_ALIGNMENT_MASK ) == 0UL ) ); /* If we want to use stack checking on architectures that use a positive stack growth direction then we also need to store the other extreme of the stack space. */ /* 如果要做堆栈检查,就要知道堆栈的另一端界限在哪里 */ pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 ); } #endif /* portSTACK_GROWTH */ /* 设置 TCB 的各个部分 */ prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth ); /* 初始化堆栈,使得任务好像被中断函数中断了一样,中断返回地址就是任务的首地址 */ /*一旦被初始化堆栈顶部的堆栈变量将被更新。 */ /* 初始化任务堆栈,并将返回地址保存在tcb中的pxTopOfStack变量*/ #if( portUSING_MPU_WRAPPERS == 1 ) { pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged ); } #else /* portUSING_MPU_WRAPPERS */ { //汇编语言对堆栈进行初始化 pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters ); } #endif /* portUSING_MPU_WRAPPERS */ if( ( void * ) pxCreatedTask != NULL ) //任务句柄 { /* 返回任务的句柄 */ *pxCreatedTask = ( xTaskHandle ) pxNewTCB; } /*关中断*/ taskENTER_CRITICAL(); { /*更新系统的任务数*/ uxCurrentNumberOfTasks++; if( pxCurrentTCB == NULL ) { /* 没有其他任务, 或者其他任务在挂起状态 设为当前任务 */ pxCurrentTCB = pxNewTCB; if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 ) { //这是第一个任务,初始化任务状态切换调度时使用的几个链表 prvInitialiseTaskLists(); } } else { /* 如果调度没有运行使得当前任务为最高级任务 */ if( xSchedulerRunning == pdFALSE ) { if( pxCurrentTCB->uxPriority <= uxPriority ) { pxCurrentTCB = pxNewTCB; } } } if( pxNewTCB->uxPriority > uxTopUsedPriority ) { uxTopUsedPriority = pxNewTCB->uxPriority; } uxTaskNumber++; #if ( configUSE_TRACE_FACILITY == 1 ) { /* Add a counter into the TCB 仅仅为了追踪*/ pxNewTCB->uxTCBNumber = uxTaskNumber; } #endif /* configUSE_TRACE_FACILITY */ traceTASK_CREATE( pxNewTCB ); prvAddTaskToReadyList( pxNewTCB ); //添加到就绪链表中 xReturn = pdPASS; portSETUP_TCB( pxNewTCB ); } taskEXIT_CRITICAL(); } else //分配失败 { xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; traceTASK_CREATE_FAILED(); //无定义 } if( xReturn == pdPASS ) { if( xSchedulerRunning != pdFALSE ) //切换状态 { if( pxCurrentTCB->uxPriority < uxPriority ) { portYIELD_WITHIN_API(); //保存现成,然后选择下一个任务 } } } return xReturn; }
#define taskENTER_CRITICAL() portENTER_CRITICAL() #define portENTER_CRITICAL() vPortEnterCritical() void vPortEnterCritical( void ) { portDISABLE_INTERRUPTS(); uxCriticalNesting++; } #define portDISABLE_INTERRUPTS() vPortSetInterruptMask() 关中断 __asm void vPortSetInterruptMask( void ) { PRESERVE8 push { r0 } mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY msr basepri, r0 pop { r0 } bx r14 } //通过basepri 屏蔽所有中断
static void prvInitialiseTaskLists( void ) { unsigned portBASE_TYPE uxPriority; for( uxPriority = ( unsigned portBASE_TYPE ) 0U; uxPriority < ( unsigned portBASE_TYPE ) configMAX_PRIORITIES; uxPriority++ ) { vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );//初始化就绪链表数组 } vListInitialise( &xDelayedTaskList1 );//初始化延时链表1 vListInitialise( &xDelayedTaskList2 );//初始化延时列表2 vListInitialise( &xPendingReadyList );//初始化调度器挂起时就绪链表 #if ( INCLUDE_vTaskDelete == 1 ) { vListInitialise( &xTasksWaitingTermination );//初始化被删除任务链表 } #endif /* INCLUDE_vTaskDelete */ #if ( INCLUDE_vTaskSuspend == 1 ) { vListInitialise( &xSuspendedTaskList );//初始化 } #endif /* INCLUDE_vTaskSuspend */ /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList using list2. */ pxDelayedTaskList = &xDelayedTaskList1; pxOverflowDelayedTaskList = &xDelayedTaskList2; }
void vListInitialise( xList * const pxList ) { /* 列表结构包含了一个列项目 被用来标记一个列表的结尾 To initialise the list the list end is inserted 作为唯一列的输入. */ pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ /* 列结束的值 是列表中可能的最高值 确保他能留在队列的最后*/ pxList->xListEnd.xItemValue = portMAX_DELAY; /* 列尾的下一个和上一个指针指向他本身,当列是空时 */ pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U; }
#define portYIELD_WITHIN_API portYIELD #define portYIELD() vPortYieldFromISR() void vPortYieldFromISR( void ) //请求中断函数 { /* Set a PendSV to request a context switch. */ *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; }
static tskTCB *prvAllocateTCBAndStack( unsigned short usStackDepth, portSTACK_TYPE *puxStackBuffer ) { tskTCB *pxNewTCB; /* 分配TCB内存*/ pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) ); if( pxNewTCB != NULL ) { /* 分配任务 所需要的内存*/ pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMallocAligned( ( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) ), puxStackBuffer ); if( pxNewTCB->pxStack == NULL ) { /*任务内存分配失败,删掉新分配的TCB内存*/ vPortFree( pxNewTCB ); pxNewTCB = NULL; } else { /* 为了调试的*/ memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) ); } } return pxNewTCB; //返回新创建的任务 }
static void prvInitialiseTCBVariables( tskTCB *pxTCB, const signed char * const pcName, unsigned portBASE_TYPE uxPriority, const xMemoryRegion * const xRegions, unsigned short usStackDepth ) { #if configMAX_TASK_NAME_LEN > 1 { /* Don't bring strncpy into the build unnecessarily. */ strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned short ) configMAX_TASK_NAME_LEN ); } #endif pxTCB->pcTaskName[ ( unsigned short ) configMAX_TASK_NAME_LEN - ( unsigned short ) 1 ] = ( signed char ) '\0'; //确保任务优先级 不超过 定义的最大优先级 if( uxPriority >= configMAX_PRIORITIES ) { uxPriority = configMAX_PRIORITIES - ( unsigned portBASE_TYPE ) 1U; } pxTCB->uxPriority = uxPriority; #if ( configUSE_MUTEXES == 1 ) { pxTCB->uxBasePriority = uxPriority; } #endif vListInitialiseItem( &( pxTCB->xGenericListItem ) ); //初始化任务链表 vListInitialiseItem( &( pxTCB->xEventListItem ) ); //初始化事件链表 /* Set the pxTCB as a link back from the xListItem. This is so we can get back to the containing TCB from a generic item in a list. */ listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB ); /* Event lists are always in priority order. */ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority ); listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB ); #if ( portCRITICAL_NESTING_IN_TCB == 1 ) { pxTCB->uxCriticalNesting = ( unsigned portBASE_TYPE ) 0; } #endif #if ( configUSE_APPLICATION_TASK_TAG == 1 ) { pxTCB->pxTaskTag = NULL; } #endif #if ( configGENERATE_RUN_TIME_STATS == 1 ) { pxTCB->ulRunTimeCounter = 0UL; } #endif #if ( portUSING_MPU_WRAPPERS == 1 ) { vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth ); } #else { ( void ) xRegions; ( void ) usStackDepth; } #endif }
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) { pxTopOfStack--; *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; *pxTopOfStack = 0; /* LR */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */ pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */ return pxTopOfStack; }
#define prvAddTaskToReadyQueue( pxTCB ) \ if( ( pxTCB )->uxPriority > uxTopReadyPriority ) \ { \ uxTopReadyPriority = ( pxTCB )->uxPriority; \ } \ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xGenericListItem ) )