aaa1982 发表于 2009-4-1 16:30:00

请教cortex-m3关于ucos移植的问题

各位好:

正在看ucos在cortex-m3核的移植。

请教各位一个问题:关于堆栈初始化,下面是

OsTaskStkInit()函数,该函数用在任务建立函数(TaskCreat() or TaskCreatExt())中。

函数的内容比较好理解,就是模拟任务上下文切换的步骤进行了一次入栈,然后返回堆栈的地址。翻了一下ucos的书关于ucos移植部分,说OSTaskStkInit()

主要的工作是定义一下堆栈数据的结构。对于这个解释比较不理解。感觉开辟一个数组空间就可以了,为什么还要费劲模拟一次入栈的操作呢,现在没有弄

明白,总是感觉这么做既没有意义还浪费地方(执行完该程序堆栈空间就少了一些,这些被OSTaskStkInit()推进去的数据还有弹出来的可能么? )

请教各位高手不吝赐教。

aaa1982

OS_STK *OSTaskStkInit (void(*task)(void*parg), void*parg, OS_STK*ptos, INT16Uopt)
{
    OS_STK *stk;


    (void)opt;                                                          /*'opt' is not used, prevent*/
                                                                        /*warning 没有用'opt',       */
                                                                        /*防止编译警告                */
                                                                           
    stk = ptos;                                                         /*Load stack pointer          */
                                                                        /*装载堆栈指针                */                                    

                                                                        /*Registers stacked as if   */
                                                                        /*auto-saved on exception   */            
                                                                      /*模拟成异常,自动把寄存器压栈*/

    *(stk) = (INT32U)0x01000000L;                                       /*xPSR                        */
    *(--stk) = (INT32U)task;                                          /*Entry Point of the task   */
                                                                        /*任务入口地址                */
    *(--stk) = (INT32U)0xFFFFFFFEL;                                     /*R14 (LR)(init value will*/
                                                                        /*cause fault if ever used)   */
                                                                           
    *(--stk) = (INT32U)0x12121212L;                                     /*R12                         */
    *(--stk) = (INT32U)0x03030303L;                                     /*R3                        */
    *(--stk) = (INT32U)0x02020202L;                                     /*R2                        */
    *(--stk) = (INT32U)0x01010101L;                                     /*R1                        */
    *(--stk) = (INT32U)parg;                                          /*R0 : argument输入参数   */
                                                                        /*Remaining registers saved on*/
                                                                        /*process stack               */   
                                                                      /*剩下的寄存器保存到堆栈      */

    *(--stk) = (INT32U)0x11111111L;                                     /*R11                         */
    *(--stk) = (INT32U)0x10101010L;                                     /*R10                         */
    *(--stk) = (INT32U)0x09090909L;                                     /*R9                        */
    *(--stk) = (INT32U)0x08080808L;                                     /*R8                        */
    *(--stk) = (INT32U)0x07070707L;                                     /*R7                        */
    *(--stk) = (INT32U)0x06060606L;                                     /*R6                        */
    *(--stk) = (INT32U)0x05050505L;                                     /*R5                        */
    *(--stk) = (INT32U)0x04040404L;                                     /*R4                        */

    return(stk);
}

aaa1982 发表于 2009-4-1 17:34:19

又看了一下,好像明白一点了,是不是应该这么理解

模拟入栈的数据是在第一次任务切换,切换到该任务的时候需要弹出来的数据,这样就可以理解入栈的PC值就是task()函数的地址

了。其他的数据,LR需要满足exc_return的要求,别的是不是就没有什么要求了,反正都是从Task()函数的开始处开始执行程序。

感谢各位指教

aaa1982

bluelucky 发表于 2009-4-2 08:54:22

把任务第一次启动与任务切换系统对接,提供启动参数,另外这样做还可以在今后需要扩展功能时准备一些数据。比如,可以在任务退出后跳至系统指定的地址

aaa1982 发表于 2009-4-2 22:22:00

感谢bluelucky版主:

“把任务第一次启动与任务切换系统对接,提供启动参数”这句话比较理解了,因为任务调度函数会根据任务的SP探出参数,从上面的代码可以看出来,第一次弹到PC的值就是Task函数的首地址。也就是每个任务的第一次任务切换都是从每个任务的首地址开始执行的。



“比如,可以在任务退出后跳至系统指定的地址”这句话不是很理解,能在进一步解释一下么。

实在感谢

aaa1982

bluelucky 发表于 2009-4-3 10:19:45

在任务的主函数返回后,或者调用由操作系统提供任务返回(如Exit())函数后,就像一般函数返回那样,会先弹出LR,然后执行BX LR指令。如果在启动任务前就设置好了将要返回的地址并压入任务的栈顶处,就实现了决定任务退出后跳入的地址,通常是操作系统响应任务退出的函数。
在实践中,任务返回后由操作系统接管善后工作的方式还有很多

aaa1982 发表于 2009-4-3 11:23:03

十分感谢bluelucky!


“在任务的主函数返回后,或者调用由操作系统提供任务返回(如Exit())函数后,就像一般函数返回那样,会先弹出LR,然后执行BX LR

指令。”在ucos中,在每个任务结束的时候都要调用OS_Sched()(任务中)或者Int_Exit()(中断中),这两个函数因该就是版主说的

“操作系统响应任务退出的函数”

根据版主的说法,可以先定义好LR(指向操作系统响应任务退出的函数),然后再任务返回的时候执行Bx LR,跳到“操作系统响应任务

退出的函数”这样和直接在任务结束的时候调用“操作系统响应任务退出的函数”有什么区别呢(类似于BL 操作系统响应任务退出的函

数)

不知道理解的对不对,再次感谢版主

aaa1982

aaa1982 发表于 2009-4-6 21:43:09

不好意思顶一下

bluelucky 发表于 2009-4-7 09:28:45

对任务的启动与停止处理,每个操作系统可以有自己的作法。如果支持,一般是创建任务的时候就做好任务退出后操作系统接管善后工作的准备,并且提供相应的创建选项与退出任务的API函数。不会允许应用程序手工调用"BX LR"之类的函数的,而是由操作系统完成
uC/OS-II的Int_Exit()是在离开中断服务程序时调用的。而OS_Sched()一般是操作系统内部调用的,功能是在最高就绪优先级可能发生变化的场合下(如响应了中断,释放了互斥量等)重新调度,是实时性能的直接体现

aaa1982 发表于 2009-4-7 11:07:48

感谢回答:
不好意思把另外的帖子的问题放到这里面问吧。

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=974779&bbs_page_no=1&bbs_id=3011

"现在uC/OS2能在CM3上跑了,可有网友指出移植有问题,在CtxSW中会破坏R4,R5的值。我不知道这个移植中是否利用了CM3的诸多新性"。
(上面是问题部分)

下面是zlg提供的UC/OS模板中OSCtxSw的代码


OSCtxSw
    PUSH    {R4, R5}
    LDR   R4, =NVIC_INT_CTRL                                          ;trigger the PendSV exception
                                                                        ;触发软件中断
    LDR   R5, =NVIC_PENDSVSET
    STR   R5,
    POP   {R4, R5}
    BX      LR

有一点比较迷惑STR   R5, 触发PendSV中断以后,自动入栈的的PC是POP{R4,R5}么?换句话说,触发PendSV以后是立刻进入中断步骤(入栈、取地址、进入中断程序)还是要在执行一到两条指令在进入中断步骤。

但是无论如何,都应该不会破坏R4,R5(无论中断在POP{R4,R5}之前进入,还是中断在BX LR之前进入,都不会破坏返回到该任务以后的R4,R5的值)。
 

aaa1982 发表于 2009-4-7 11:11:36

还有关于另一个问题,也是bluelucky版主提到过的

“ 我印象最深的有一个指令是返回某寄存器的值中前导0的个数,叫CLZ.W。这让我突然想起uC/OS2的调度中就绪位图查找表,我感觉这个指令能完成以前需要查表才能做的事。”

如果用CLZ.W找到最高位1的位置,确实可以不用查表了,但是感觉找最高优先级任务用的时间应该差不多吧。只不过比起查表来少了256

个字节的空间。可不可以这么理解呢。

aaa1982

bluelucky 发表于 2009-4-8 08:51:58

CLZ指令主要作用就是可以省去查找表
这段代码我是没看出什么问题,汗

aaa1982 发表于 2009-4-8 09:08:27

感谢

所以应该在任务切换的时候R4,R5的值不会被破坏,对吧。

还有一个问题,突然发现很多好的帖子都被放到“虚拟总坛里面了”这里反而看不到,不知道为什么。

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=2013982&bbs_page_no=1&search_mode=3&search_text=elex&bbs_id=9999


我觉得挺好的一篇帖子。版主能不能给移回来。

不知道还有多少没发现的好帖子。

gorden_gan 发表于 2009-5-21 22:48:23

LZ~~我看到你这句话
“有一点比较迷惑STR   R5, 触发PendSV中断以后,自动入栈的的PC是POP{R4,R5}么?换句话说,触发PendSV以后是立刻进入中断步骤(入栈、取地址、进入中断程序)还是要在执行一到两条指令在进入中断步骤。”

我感觉你好像对ucos在CM3下 切换上下文的特点没理解~~
STR   R5, 触发PendSV中断~~线程还是继续往下运行~~并不进入PendSV中断,因为这时是处于OS_ENTER_CRITICAL()状态下~~PendSV中断将被挂起~~而不进入~~直到OS_EXIT_CRITICAL()后进入中断PendSV,切换上下文。
这个是CM3 NVIC的特点~~比如 ARM7下 SWI是不会因为 OS_ENTER_CRITICAL()而屏蔽的~~所以是触发后直接进入中断(就像LZ理解的那样)
你可以去看看ucos官方那个移植CM3的文档~~里面有个图很清楚的说明了这个问题~~

aaa1982 发表于 2009-5-22 13:21:20

感谢gorden_gan:

其实问这个问题主要是想问一下关于数据、指令缓存的问题(不知道这么表达是不是合适)

我就是想知道从执行STR   R5, ,到这句话真正起作用,大概有没有什么时间间隔。

感谢你的提醒,

OSCtxSw是 OS_Sched()里面调用的,而OS_Sched()好像确实在开始的时候OS_ENTER_CRITICAL()了,并在OSCtxSw()调用完了以后才
OS_EXIT_CRITICAL() ,这点我没有注意到。

感谢!



另外“比如 ARM7下 SWI是不会因为 OS_ENTER_CRITICAL()而屏蔽的~~所以是触发后直接进入中断(就像LZ理解的那样)”

如果假设这样(当然实际情况不是这样),上面的上下文切换程序也不会破坏R4,R5的值吧。

说明白一点,就是假设执行完STR   R5, 就跳到pendsv异常去了,也不会破坏R4,R5的值吧。

感谢

yemingxp 发表于 2009-5-22 13:39:51

请问楼主看的什么CORTEX M3 UCOS移植资料,能共享吗,谢谢。

aaa1982 发表于 2009-5-22 14:52:38

就是参考了zlg的模板,强烈建议初学者买一个试一下,1138才100多点。

如果你不想买,我也可以上传一份,就是移植的内容,主要是涉及一些任务调用和堆栈的初始化。

globby 发表于 2009-8-9 00:48:19

marks

vbhome 发表于 2009-10-7 21:14:19

marks too

lcyc51 发表于 2014-3-1 14:55:36

mark 很不错。
页: [1]
查看完整版本: 请教cortex-m3关于ucos移植的问题