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
2pdTASK_CODE pvTaskCode,该参数就是进程体,实为函数指针。定义如下:
       typedef void (*pdTASK_CODE)( void * );
3xTaskHandle,定义为typedef void * xTaskHandle;
 
       下面来看看这个超级牛函数的实现,说是超级牛函数是因为该函数的地位。实现却并非想像般复杂。具体有对以下几个函数的调用
(1)       prvAllocateTCBAndStack,用于分配该taskTCB【任务控制块】和栈
(2)       prvInitialiseTCBVariables,初始化新分配的task TCB
(3)       设置栈顶位置
(4)       pxPortInitialiseStack,初始化新分配的栈
(5)       判断该新创建task是否为系统的第一个task。是则初始化task的各所需链表
(6)       设置当前系统的TCB
(7)       prvAddTaskToReadyQueue,添加新创建的taskTCBtask就绪队列中
(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;
}
这里别的都好理解,就是为什么LRR0等这些的寄存器的入栈调用不怎么理解,为何是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
这两个宏没有看懂是什么意思,这里标识一下,后续待解*************************