任務定義
數組
//宏定義 任務建立函數 #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 ) )