FreeRTOS内核启动

本文屏蔽了大量的技术细节,只是简单的阐述内核启动的实现。由于本人才疏学浅知识有限,如有错误,还请各位不吝赐教。

从任务调度开始

void vTaskStartScheduler( void ) /* 这个函数创建了idle任务,并且创建软件定时器任务 ,到最后调用xPortStartScheduler */

看看xPortStartScheduler 函数做了什么

 1 BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
 2 {
 3     /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
 4 
 5     /* 设置PendSV和Systick中断优先级为最低,这里是操作寄存器直接设置,为什么要设置最低,因为任务切换就是在PendSV中运行,为了让其他中断能够及时的运行,为什么要在PendSV中切换任务,因为PendSV可以挂起延迟执行,具体参考Cortex-M3 权威指南 第7章异常SVC和PendSV */
 6     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
 7 
 8     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
 9 
10     #if ( configENABLE_MPU == 1 )
11         {
12             /* Setup the Memory Protection Unit (MPU). */
13             prvSetupMPU();
14         }
15     #endif /* configENABLE_MPU */
16 
17     /* Start the timer that generates the tick ISR. Interrupts are disabled
18      * here already. */
19     vPortSetupTimerInterrupt();
20 
21     /* Initialize the critical nesting count ready for the first task. */
22     ulCriticalNesting = 0;     /* 此变量表示临界段嵌套次数,可以表示是否在中断里 */
23 
24     /* Start the first task. */
25     vStartFirstTask();         
26 
27     /* Should never get here as the tasks will now be executing. Call the task
28      * exit error function to prevent compiler warnings about a static function
29      * not being called in the case that the application writer overrides this
30      * functionality by defining configTASK_RETURN_ADDRESS. Call
31      * vTaskSwitchContext() so link time optimization does not remove the
32      * symbol. */
33     vTaskSwitchContext();  /* 查找最高的优先级 */
34     prvTaskExitError();
35 
36     /* Should not get here. */
37     return 0;
38 }
39     

taskSELECT_HIGHEST_PRIORITY_TASK 函数实现了优先级的查找,提供了两种办法,这里只研究一种

 1 #define taskSELECT_HIGHEST_PRIORITY_TASK()                                
 2     {                                                                         
 3         UBaseType_t uxTopPriority = uxTopReadyPriority;                       
 4                                                                               
 5         /* Find the highest priority queue that contains ready tasks. */      
 6         while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) 
 7         {                                                                     
 8             configASSERT( uxTopPriority );                                    
 9             --uxTopPriority;                                                  
10         }                                                                     
11                                                                               
12         /* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of 
13          * the  same priority get an equal share of the processor time. */                    
14         listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); 
15         uxTopReadyPriority = uxTopPriority;                                                   
16     } /* taskSELECT_HIGHEST_PRIORITY_TASK */
寻找最高的优先级,更新pxCurrentTCB
  while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) )
  表示就绪表中是否有任务。没有任务就下标减一继续找,因为下标就是优先级,直到找到了优先级。
  如果跳出while,表示找到了最高优先级的任务。有任务表示最高的优先级,因为下标越小,优先级越低。
  listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) )
  找到的列表项更新到当前Tcb.
  uxTopReadyPriority = uxTopPriority;  
  更新最高的就绪优先级
  pxReadyTasksLists里面存放的是Tcb(准确来说应该是存放Tcb里面的 xStateListItem 列表项)
 
第二种是使用前导零指令CLZ,意思是32个bit表示优先级,哪个位是0就减掉。

参考野火教程的一句话: 任务控制块里面有一个 xStateListItem 成员, 数据类型为 ListItem_t, 我们将任务插入
到就绪列表里面,就是通过将任务控制块的 xStateListItem 这个节点插入到就绪列表中来实
现的。如果把就绪列表比作是晾衣架, 任务是衣服,那 xStateListItem 就是晾衣架上面的钩
子,每个任务都自带晾衣架钩子,就是为了把自己挂在各种不同的链表中 。

xPortPendSVHandler,次函数进行任务切换。

邮箱:422705581@qq.com
原文地址:https://www.cnblogs.com/yangdh/p/13845521.html