main函数之任务创建

2009-5-10
       今天来看下主要的一个系统函数,这个重量级的函数叫做任务创建,在 freertos 中的全名叫 xTaskCreate ,原型如下:
signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode,
const signed portCHAR * const pcName, //task
unsigned portSHORT usStackDepth,     //task 栈的深度
void *pvParameters,                  //task 的参数
unsigned portBASE_TYPE uxPriority,   //task 的优先级
xTaskHandle *pxCreatedTask )        //task 的句柄
几点说明:
1 )所谓的返回值 portBASE_TYPE 其实就是 int
2 pdTASK_CODE pvTaskCode ,该参数就是进程体,实为函数指针。定义如下:
       typedef void (*pdTASK_CODE)( void * );
3 xTaskHandle ,定义为 typedef void * xTaskHandle;
 
       下面来看看这个超级牛函数的实现,说是超级牛函数是因为该函数的地位。实现却并非想像般复杂。具体有对以下几个函数的调用
(1)       prvAllocateTCBAndStack ,用于分配该 task TCB 【任务控制块】和栈
(2)       prvInitialiseTCBVariables ,初始化新分配的 task TCB
(3)       设置栈顶位置
(4)       pxPortInitialiseStack ,初始化新分配的栈
(5)       判断该新创建 task 是否为系统的第一个 task 。是则初始化 task 的各所需链表
(6)       设置当前系统的 TCB
(7)       prvAddTaskToReadyQueue ,添加新创建的 task TCB task 就绪队列中
(8)       如果调度已开始,并且新创建的 task 的优先级高于当前的 task ,则直接进行调度 taskYIELD
 
下面看下栈的初始化函数的实现:
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
       /* Simulate the stack frame as it would be created by a context switch
       interrupt. */
       *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;
}
这里别的都好理解,就是为什么 LR R0 等这些的寄存器的入栈调用不怎么理解,为何是 0 ,比如 LR ,接下来的就是 R12, R3, R2 and R1 。或许要看下硬件( stm32 )的 spec
 
在这里顺便说一下,由于各 cpu 的栈实现方式不一样,以及寄存器地址的不同,所以每个平台( cpu )上的这个栈初始化函数的实现都不一样。具体实现见 source\portable\ 平台 \cpu 类型 \port.c 中的实现, source\portable\iar\arm_cm3
 
       接着也是重量级的函数, prvInitialiseTaskLists ,这个函数。对这个函数,源代码中的注释是这样的, This is the first task to be created so do the preliminary initialisation required. 涉及到 tasklist 这里就先不介绍了。
 
       再看这里的最后一个超级重量级的函数,直接调度函数 taskYIELD
#define taskYIELD()                                  portYIELD() source\include\task.h
#define portYIELD()                                  vPortYieldFromISR()
【注意】 这个宏定义也是和栈初始化函数一样是和平台相关的,所以也就是在 portable 目录下的某个平台 +cpu 下了。实现在 portmacro.h
void vPortYieldFromISR( void )
{
       /* Set a PendSV to request a context switch. */
       *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}
上面的这个最终实现是在 iar 上面的【 source\portable\iar\arm_cm3\port.c
#define portNVIC_INT_CTRL                    ( ( volatile unsigned portLONG *) 0xe000ed04 )
#define portNVIC_PENDSVSET                 0x10000000
这两个宏没有看懂是什么意思,这里标识一下,后续待解 *************************

你可能感兴趣的:(职场,休闲,freertos)