UCOS-II任务堆栈初始化函数移植

http://blog.sina.com.cn/s/blog_6d589a300100nc3n.html###

(2010-10-20 16:34:40)
标签:

杂谈

分类:UCOSII

UCOS-II的在建立任务函数中要对新建任务的堆栈进行初始化。堆栈初始化函数原型是:

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg,OS_STK *ptos, INT16U opt);

void (*task)(void *pd): 定义一个函数指针变量task,这个函数指针指向的函数有一个void *类型的参数,没有返回值。

p_arg:是任务开始执行时,传递给任务的参数的指针。

Ptos:是分配给任务的堆栈栈顶的指针。

Opt:在OSTaskCreate()函数中调用OSTaskStkInit()函数时,Opt为0。因为OSTaskStkInit()函数不支持在任务的建立过程中设置选项。OSTaskCreateExt()函数支持这个选项。

OSTaskStkInit()是一个指针函数,也就是返回值是一个指针,返回初始化后的堆栈的栈顶。

 

任务建立前要先建立任务堆栈。

我现在用的是LPC2214,ARM7内核,定义

typedef unsigned int  OS_STK;

OS_STK为32位数据类型

#define          TASK_STK_SIZE        512

OS_STK TaskStartStk[TASK_STK_SIZE];

定义一个数组作为任务堆栈,堆栈长度512*4 = 2K字节,乘4是因为OS_STK是32位数据类型。

当调用函数OSTaskCreate()创建一个任务时,把数组的指针传递给函数OSTaskCreate()中的堆栈栈顶指针ptos,就可以把该数组和任务关联起来成为该任务的任务堆栈。

 

先了解下栈顶和栈底。

栈顶是堆栈中存储第一个数据的地方。栈底是堆栈中存储最后1个数据的地方。

UCOS-II任务堆栈初始化函数移植

栈顶和栈底刚开始我总是弄混,想当然认为栈顶应该就是在堆栈中所有数据的最上面。理解成最上面有歧义,因为还有个方向问题。可以把最先送入堆栈的数看做是最上面,也可以把最后进入堆栈的数看做是最上面。我觉得准确的理解就是栈顶是最先送入堆栈的数放的地方。

TaskStartStk[0]是数组中的最低地址,TaskStartStk[TASK_STK_SIZE -1]是数组中的最高地址。

如果是递增方式堆栈,那么栈顶就是最低地址&TaskStartStk[0],栈底是最高地址& TaskStartStk[TASK_STK_SIZE- 1]。

如果是递减方式堆栈,那么栈顶就是最高地址&TaskStartStk[TASK_STK_SIZE- 1],栈底是最低地址&TaskStartStk[0]。

 

Ucos在LPC2214上移植,堆栈为递减方式,

#define ARM_SYS_MODE   (0x0000001FL)

OSTaskStkInit()移植代码如下:

OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg,OS_STK *ptos, INT16U opt)

{

    OS_STK*stk;

 

   opt     =opt;                     

   stk     = ptos;                    

   *(stk)    =(OS_STK)task;           

    *(--stk)  =(INT32U)0x14141414L;    

    *(--stk)=(INT32U)0x12121212L;        

    *(--stk)=(INT32U)0x11111111L;        

    *(--stk)=(INT32U)0x10101010L;        

    *(--stk)=(INT32U)0x09090909L;        

    *(--stk)=(INT32U)0x08080808L;        

    *(--stk)=(INT32U)0x07070707L;        

 

    return(stk);

}

OSTaskStkInit()返回值就是初始化完成后的堆栈指针,放在任务控制块的开始,OSTCBStkPtr中。堆栈初始化完成后堆栈指针是&TaskStartStk[TASK_STK_SIZE- 1-15];这个值应该放在R13(SP)中,这里为什么没处理R13呢?

在任务第一次开始执行时,操作系统首先得到任务的任务控制块,然后从任务控制块得到任务的堆栈指针,再把这个堆栈指针送到R13(SP)。然后再OSCtxSw()函数中把初始化的各个寄存器的值送到对应的CPU寄存器,所以在OSTaskStkInit()函数里不用处理R13。在任务执行过一次之后,任务被中断切换到其它任务之前,就会从R13(SP)得到堆栈指针当前的位置,在OSCtxSw()函数中把CPU的R0-R12,R14等值压到R13(SP)指定的堆栈中。

OSTaskStkInit()中数据进栈的顺序要和OSCtxSw()中数据出栈的顺序对应。

PC值是最后出栈,所以要最先进栈。把任务函数的地址压入堆栈。出栈后,任务函数地址送入PC后,就开始执行任务函数。

R14是返回地址,但是任务函数是一个无限循环,只有在任务调度时才会退出,而在任务调度时切换到另一个任务时,会把另一个任务堆栈中存储的R14的值送到R14,保证程序在另一个任务被中断时的断点继续运行。所以在初始化堆栈时,R14的值是没有用的,可以随意赋值。

R1-R12可以随意赋值。

R0用来存储任务传递的参数。选择R0,是因为任务的参数在编译时是通过R0来传递的。

最后设置一个任务运行时的状态寄存器CPSR值,压入堆栈。

返回堆栈初始化完成后的指针给任务控制块的OSTCBStkPtr。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值