学习ARM开发(21)

OS任务切换源程序分析

       先要声明任务指针,因为后面需要使用。

       //任务指针.

volatile TASK_TCB* volatile g_pCurrentTask = NULL;

volatile TASK_TCB* volatile g_pCurrentTask1 = NULL;

volatile TASK_TCB* volatile g_pCurrentTask2 = NULL;

接着就需要初始化这些任务栈,用下面的代码进行初始化,为了简单,全部使用内存地址操作的方式,当然后面会改成动态地分配内存的方式。代码如下:

///////////////////////////////////////////////////////////////////////////////

//函数名称:   TaskInitStack

//函数功能:   分配任务的栈。

//输入参数:

//输出参数:

// :   

//开发人员:   蔡军生

//    :   2006/02/26

//修改说明:  

//

///////////////////////////////////////////////////////////////////////////////

void TaskInitStack(void)

{

       g_pCurrentTask1 = (PTASK_TCB)0x0c700000;

       g_pCurrentTask1->pStackStart = (UINT*)(0x0c700000+0x200);

       g_pCurrentTask1->pStackTop = g_pCurrentTask1->pStackStart + 0x100;

 

       g_pCurrentTask2 = (PTASK_TCB)(0x0c700000 + 0x400);

       g_pCurrentTask2->pStackStart = (UINT*)(0x0c700000+0x400 + 0x200);

       g_pCurrentTask2->pStackTop = g_pCurrentTask2->pStackStart + 0x100;

}

 

接着再创建两个简单的任务,它们都是输出一行字符串,就等待一会,代码如下:

//

void TaskTest1(void)

{    

       for(;;)

       {

              Lock();

              puts("TaskTest1/n");

              UnLock();

 

              SoftDelay(100);

       }

}

//

void TaskTest2(void)

{    

       for(;;)

       {

              Lock();

              puts("TaskTest2/n");

              UnLock();

 

              SoftDelay(100);

       }

}

 

然后再初始化任务栈,代码如下:

void TaskStart(void)

{

      

       //

       UINT* pTemp = g_pCurrentTask1->pStackTop;

       //

       *g_pCurrentTask1->pStackTop =  (UINT)TaskTest1;

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x14141414; /* R14 */

       g_pCurrentTask1->pStackTop--;

 

//       *g_pCurrentTask1->pStackTop = (UINT)pTemp;       /* R13 */

//       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x12121212; /* R12 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x11111111;   /* R11 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x10101010; /* R10 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x09090909; /* R9 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x08080808; /* R8 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x07070707; /* R7 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x06060606; /* R6 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x05050505; /* R5 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x04040404; /* R4 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x03030303; /* R3 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x02020202; /* R2 */

       g_pCurrentTask1->pStackTop--;

 

 

       *g_pCurrentTask1->pStackTop = (UINT)0x01010101; /* R1 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0;       /* R0 */

       g_pCurrentTask1->pStackTop--;

 

       *g_pCurrentTask1->pStackTop = (UINT)0x13;  /* SPSR */

 

 

       //

       //

       //

       pTemp = g_pCurrentTask2->pStackTop;

       //

       *g_pCurrentTask2->pStackTop =  (UINT)TaskTest2;

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x14141414; /* R14 */

       g_pCurrentTask2->pStackTop--;

 

//       *g_pCurrentTask2->pStackTop = (UINT)pTemp;       /* R13 */

//       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x12121212; /* R12 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x11111111;   /* R11 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x10101010; /* R10 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x09090909; /* R9 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x08080808; /* R8 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x07070707; /* R7 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x06060606; /* R6 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x05050505; /* R5 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x04040404; /* R4 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x03030303; /* R3 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x02020202; /* R2 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x01010101; /* R1 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0;       /* R0 */

       g_pCurrentTask2->pStackTop--;

 

       *g_pCurrentTask2->pStackTop = (UINT)0x13;  /* SPSR */

      

       //设置首先运行的任务是1.

       g_pCurrentTask = g_pCurrentTask1;

}

代码初始化了两个任务栈后,接着设置第一个任务为优先运行的任务。

 

最后就需要进行中断任务调度任务进行运行了,代码如下:

///////////////////////////////////////////////////////////////////////////////

//函数名称:   EIntTickIsr

//函数功能:   时钟中断函数。

//输入参数:

//输出参数:

// :    

//开发人员:   蔡军生

//    :   2006/02/26

//修改说明:  

//

///////////////////////////////////////////////////////////////////////////////

void EIntTickIsr(void) __attribute__((naked));

void EIntTickIsr(void)

{

       //保存R0-R12寄存器到栈里.

       asm volatile(" STMDB  SP!, {R0-R12} ");

      

       //关闭TICK中断.

       INTMSK |= BIT_GLOBAL|BIT_TICK;

 

       //取得保存IRQLR地址,并保存LR.

       asm volatile (" LDR     R0,=g_dwIRQLR" );

       asm volatile (" SUBS    LR,LR,#4 ");

       asm volatile (" STR           LR,[R0] ");

 

       //取回前面保存的R0-R12寄存的值.

       asm volatile (" LDMIA       SP!, {R0-R12} ");

 

       //取得最后返回的SPSR,就是SVC模式下的CPSR.

       //IRQ模式切换回到SVC模式.

       asm volatile (" MRS          LR,SPSR ");

       asm volatile (" ORR           LR,#0xc0 ");

       asm volatile (" MSR          CPSR,LR ");

 

       //现在已经转换回到SVC模式,取回IRQ模式下保存的LR.

       //R0的值保存到栈中第二个位置.

       asm volatile (" STR     R0,[SP,#-8] ");

 

       //从保存位置取回IRQ模式下保存的LR.

       asm volatile (" LDR     R0,=g_dwIRQLR" );

       asm volatile (" LDR     R0,[R0] ");

 

       //IRQ模式下的LR保存到栈里,就是出栈时的PC.

       asm volatile (" STMDB   SP!,{R0} ");

 

       //从栈里第二个位置取回先前保存的R0.

       asm volatile (" SUBS    SP,SP,#4 ");

       asm volatile (" LDMIA   SP!,{R0} ");

 

       //保存R0-R12,LR到栈里,入栈顺序是刚好相反的.

       asm volatile (" STMDB   SP!,{R0-R12,LR} ");

 

       //保存CPSR的值到栈里,就是SPSR的位置.

       asm volatile (" MRS     R4,CPSR ");

       asm volatile (" BIC     R4,#0xc0 ");

       asm volatile (" STMDB   SP!,{R4} ");

 

       //保存栈顶到任务指针里.

       asm volatile ( "LDR           R0, %0" : : "m" (g_pCurrentTask) );

       asm volatile ( "STR           SP, [R0]" );

 

       //增加时钟计数.

       g_dwTickCount++;  

       //    

       printf("g_dwTickCount = (%d)/n",g_dwTickCount);

       //    

       //清除屏蔽位.

       I_ISPC = BIT_TICK;           

       INTMSK &= ~(BIT_GLOBAL|BIT_TICK);

 

       //

       if (g_dwTickCount < 3)

       {

              g_pCurrentTask = g_pCurrentTask1;

       }

       else if (g_dwTickCount < 4)

       {

              g_pCurrentTask = g_pCurrentTask2;

       }

       else

       {

              g_dwTickCount = 0;

       }

 

       //取得新任务指针

       asm volatile ( "LDR           R0, %0" : : "m" (g_pCurrentTask) );  

       asm volatile ( "LDR           SP, [R0]" );

 

       //取回SPSR.

       asm volatile ( "LDMIA       SP!, {R0}" );

       asm volatile ( "MSR          SPSR, R0" );

 

       //取回R0-R12,LR,PC,并运行最后的任务.

       asm volatile ( "LDMIA       SP!, {R0-R12,LR,PC}^" );

}

 

写完上面的代码,就可以真正地实现了任务调度了。有了以上的代码,写其它复杂的任务调试都变得很容易了,这些代码得来是不太容易的,我经历了好几个星期的调试才通过的。

这些都是在我的S3C44B0开发板上调试通过的,如果你没有开发板,可以跟我购买。联系方法ccaimouse#gmail.com请把#换成@)。

posted @ 2006-02-26 13:21  ajuanabc  阅读(163)  评论(0编辑  收藏  举报