第一章 调度器
vTaskStartScheduler( void ):
1、创建prvIdleTask空闲任务;
2、若空闲任务创建成功,则创建xTimerCreateTimerTask时间任务;
3、若时间任务创建成功,则:
1)关中断;
2)调用xPortStartScheduler()开启调度器。
xPortStartScheduler():
(1)Make PendSV and SysTick the lowest priority interrupts.
(2)开启定时器中断,prvSetupTimerInterrupt();
(3)运行第一个任务vPortStartFirstTask()。
//
第二章 任务创建、删除、挂起、恢复
任务创建过程,xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
1、创建任务参数有任务函数、任务名称、堆栈大小、任务函数参数、任务优先级、任务句柄六个参数;
2、根据堆栈增长方向来决定TCB、堆栈前后顺序:
1)向上增长,先TCB后堆栈;
2)向下增长,先堆栈后TCB。
3、调用prvInitialiseNewTask,初始化任务:
1)参数有任务函数、任务名称、堆栈大小、任务参数、任务优先级、任务句柄、任务控制块和xRegions;
2)根据堆栈增长方向来决定任务分配堆栈的Top:
(1)向上增长,pxTopOfStack = pxNewTCB->pxStack;
(2)向下增长,pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 )。
3)赋值任务名称;
4)设置任务优先级;
5)初始化xStateListItem;
6)初始化xEventListItem;
7)xStateListItem指定所有者;
8)按优先级大小排列xEventListItem,并指定其所有者;
9)调用pxPortInitialiseStack函数,初始化栈顶信息,以便后面任务运行;
10)把任务控制块赋值给任务句柄。
4、调用prvAddNewTaskToReadyList,加入ready任务列表:
1)进入保护区,taskENTER_CRITICAL();
2)uxCurrentNumberOfTasks++;
3)如果当前运行控制块为NULL,则把当前创建的任务控制赋值给它;然后初始化prvInitialiseTaskLists();
4)如果xSchedulerRunning为pdFALSE,确保最高优先级为当前任务;
5)uxTaskNumber++;
6)prvAddTaskToReadyList( pxNewTCB )添加到ready任务表;
prvAddTaskToReadyList:
(1)确保优先级高的排在前面;
(2)vListInsertEnd根据优先级插入Readylist列表。
7)taskEXIT_CRITICAL()退出保护区;
8)若xSchedulerRunning != pdFALSE,新创建任务优先级比当前运行任务搞,调用taskYIELD_IF_USING_PREEMPTION()触发任务切换。
任务删除,vTaskDelete( TaskHandle_t xTaskToDelete )
1、传入参数只有需要删除的任务句柄,也就是TCB;
2、taskENTER_CRITICAL()进入保护区;
3、xTaskToDelete若为NULL,则删除当前运行任务;
4、uxListRemove( &( pxTCB->xStateListItem ),移除任务TCB中的状态列表项;
5、判断pxTCB->xEventListItem的pvContainer 是否为NULL,若不是NULL,则uxListRemove( &( pxTCB->xEventListItem ) )移除事件列表项;
6、uxTaskNumber++;
7、若要删除当前运行任务本身,vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) )把任务状态列表项插入等待
终止的列表pxIndex索引指向列表项之前,++uxDeletedTasksWaitingCleanUp;;
若不是删除当前运行任务本身,--uxCurrentNumberOfTasks,prvDeleteTCB( pxTCB )释放TCB,prvResetNextTaskUnblockTime();
8、taskEXIT_CRITICAL()退出保护区;
9、若调度器未被挂起且删除当前运行任务,则调用portYIELD_WITHIN_API(),触发一次任务切换。
任务挂起,vTaskSuspend( TaskHandle_t xTaskToSuspend )
1、传入参数只有需要删除的任务句柄,也就是TCB;
2、taskENTER_CRITICAL();
3、调用prvGetTCBFromHandle()获取句柄,若传入参数为NULL,则获取正在运行的任务句柄;
4、调用uxListRemove()从任务列表中移除;
5、如果该任务在等待事件,调用uxListRemove(),从事件列表中移除;
6、调用vListInsertEnd()把被删除的状态列表插入xSuspendedTaskList;
7、taskEXIT_CRITICAL();
8、如果调度器未被挂起,在临界区,调用prvResetNextTaskUnblockTime(),复位解除阻塞时间;
9、当删除的是当前运行任务,且调度器未被挂起,调用portYIELD_WITHIN_API()强制任务切换;当删除的是当前运行任务,且调度器挂起,若未有任务
进入就绪状态则pxCurrentTCB = NULL,若还有任务就绪,调用vTaskSwitchContext()。
任务恢复,vTaskResume( TaskHandle_t xTaskToResume )
1、传入的TCB不为NULL且不是当前运行任务;
2、taskENTER_CRITICAL();
3、调用prvTaskIsTaskSuspended( pxTCB )判断是否为挂起任务,如果是挂起路网,调用uxListRemove()从挂起列表移除,调用prvAddTaskToReadyList()
添加到任务就绪表中;
4、如果恢复任务优先级比当前运行任务高,则调用taskYIELD_IF_USING_PREEMPTION()进行一次任务切换。
第三章 任务控制块、任务堆栈
1、任务控制块(TCB_t),每个任务需要储存的一些属性集合,基本成员如下:
1)pxTopOfStack,栈顶指针;
2)xStateListItem,任务状态列表项,有就绪、阻塞、挂起;
3)xEventListItem,事件列表项;
4)uxPriority,优先级;
5)pxStack,堆栈指针;
6)pcTaskName,任务名称。
2、任务堆栈:保存任务运行状态的堆栈。
//
第四章 列表和列表项
1、列表,一种数据结构,用来跟踪FreeRTOS中的任务,主要成员如下:
1)uxNumberOfItems,存储的列表项数量;
2)pxIndex,当前列表的索引号;
3)xListEnd,mini列表项,用在列表末尾。
2、列表项,存储具体信息功能,主要成员如下:
1)xItemValue,用来按降序排列;
2)pxNext,指向下一个列表项;
3)pxPrevious,指向前一个列表项;
4)pvOwner,这个列表的所有者,指向TCB结构体;
5)pvContainer,归属哪个列表,根据这个可知道列表是在就绪列表还是阻塞列表或者其她列表中,没有时未null。
3、mini列表项,列表项的缩减版,主要成员如下:
1)xItemValue,用来按降序排列;
2)pxNext,指向下一个列表项;
3)pxPrevious,指向前一个列表项。
4、列表初始化,vListInitialise过程如下:
1)列表指针pxIndex指向xListEnd;
2)xListEnd.xItemValue设置成最高,确保只有xListEnd;
3)xListEnd.pxNext和xListEnd.pxPrevious都指向自己。
4)设置列表两头值。
5、列表项操作情况,如下:
(一)初始化,vListInitialiseItem过程如下:
1)列表项的pvContainer(所在运行列表指向)设为NULL;
2)设置列表两头值
(二)插入列表项,vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )过程如下:
1)列表和列表项完整性检查;
2)根据pxNewListItem->xItemValue值降序寻找插入位置;
3)插入列表项;
4)pxNewListItem->pvContainer,指向插入的列表。
5)列表数量加1。
(三)末尾插入列表项,vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )过程如下:
1)插入pxList->pxIndex之前,也就是最后一个。
2)pxNewListItem->pvContainer,指向插入的列表。
3)列表数量加1。
(四)删除列表项,uxListRemove( ListItem_t * const pxItemToRemove )过程如下:
1)找到列表项所在列表pxItemToRemove->pvContainer;
2)删除列表项;
3)确保pxList->pxIndex指向有效列表项;
4)被删除的列表项pxItemToRemove->pvContainer 赋值NULL;
5)列表数量uxNumberOfItems减一。
(五)遍历列表,listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )过程如下:
1)列表pxIndex指向下个列表项;
2)如果为最后结尾列表项,则pxIndex指向起始列表项;
3)获取新指向的列表项的pvOwner,即TCB。
/
第五章 内存管理
1、内存碎片问题
多次申请释放操作后,内存被分割成若干小碎片,随着程序运行,可能内存不够导致程序奔溃。
2、