毫无保留ucoslwip稳定版2我移植的ucos参考ver_第1页
毫无保留ucoslwip稳定版2我移植的ucos参考ver_第2页
毫无保留ucoslwip稳定版2我移植的ucos参考ver_第3页
毫无保留ucoslwip稳定版2我移植的ucos参考ver_第4页
已阅读5页,还剩6页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、uc/OS 移植参考任务切换中的部分代码是和 CPU 相关的,该部分包括:OS_ENTER_CRITICAL(其原身为 void ARMDisable(void))进入临界区,关闭中断OS_EXIT_CRITICAL(其原身为void ARMEnable(void))退出临界区,打开中断OSStartHighRdy;从系统中切换到第一个任务OS_TASK_SW;从任务中切换到任务OSCtxSw;任务被中断,从中断中切换到任务OSTaskStkInit;初始化任务中断,在构造任务时调用。首先,先来一些公共的内容:一、任务系统(除了中断)运行在 SYS 模式下,该模式没有SPSR二、所有希望在中断

2、中实现任务调度的处理程序必须使用 IRQ 中断同时使用 OSEnter 和OSExit,这是因为 OSExit 中执行切换的 OSCtxSw 直接操作 IRQ 的堆栈来实现了被中断现场的数据保护(详情见下)。系统开始时不Fiq 中断打开,但是,不可以在其中使用 OSCtxSw(即不可调用OSEnter 和OSExit),简单的不涉及到任务状态的代码可以使用。IRQ 中断不支持 IRQ 嵌套,但支持 FIQ 的嵌套。三、ARM 的 c 编译器对子函数调用的汇编处理也是值得注意的部分。调用函数一般使用 bl,但也有时用 b。请看下面的图例,自己去理解。图一的函数关系a;void fun1(void

3、); void fun2(void); main() a+;fun1(); a+;void fun1(void) a+;fun2(); a+;void fun2(void) a+;图二的函数关系a;void fun1(void); void fun2(void); main() a+;fun1();void fun1(void) a+;fun2();void fun2(void)a+;区别在于调用函数的语句之后是否还有代码。四、标准堆栈格式为任务切换函数所承认的堆栈格式如下:按标准格式调整好的栈内容,都可以被顺利的弹出现场。其次,来对代码进行分析:一、OSTaskStkInit,代码如下:OS

4、_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata,OS_STK *ptos, 16U opt)unsigned*stk;optstk= opt;= (unsigned/*opt is not used, prevent warning*/*)ptos;/* Load stack poer*/* build a context for the new task */*-stk = (unsigned*-stk = (unsigned) task;) task;/* pc */* lr */*-stk = 0;*-stk = 0;*

5、-stk = 0;*-stk = 0;*-stk = 0;/* r12 */* r11 */* r10 */* r9 */* r8 */*-stk = 0;*-stk = 0;*-stk = 0;*-stk = 0;*-stk = 0;*-stk = 0;*-stk = 0;*-stk = (unsigned*-stk = (0 x1f|0 x00);*-stk = (0 x1f|0 x00);/这是标准的栈结构 return (void *)stk);/* r7 */* r6 */* r5 */* r4 */* r3 */* r2 */* r1 */* r0 */* cpsrSys mode

6、 FIQ IRQ Enable*/* spsrSys mode FIQ IRQ Enable */) pdata;用于任务初始化时堆栈的建立,为 OSTaskCreate()调用;结构清晰,参见标准栈结构。其来源于:OS_CPU_C.c二、OSStartHighRdy,代码如下:EXPORT OSStartHighRdy;功能示例;STCBHighRdy-OSTCBStkPtr;OSTCBCur=OSTCBHighRdy;弹出现场OSStartHighRdyLDRLDRr4, addr_OSTCBCur; Get current task TCB addressr5, addr_OSTCBHi

7、ghRdy; Get highest priority task TCB addressLDR LDR;Sr5, r5sp, r5; get stack poer; switch to the new stackTCBHighRdy-OSTCBStkPtrSTR r5, r4; set new current task TCB address;OSTCBCur=OSTCBHighRdyLDMFD MSR LDMFD MSRLDMFDsp!, r4 CPSR_cxsf, r4 sp!, r4CPSR_cxsf, r4; YYY; get new se from top of the stack;

8、 CPSR should be SYS32Modesp!, r0-r12, lr, pc ; start the new task用于系统开始时,从系统切换到第一个任务,为OSStart()调用。其来源于:OS_CPU_a.s三、OS_ENTER/EXIT_CRITICAL,这是两个宏,定义见代码,注意对压栈方式论证的分析:下面的代码来源于 OS_CPU.h#defineOS_CRITICAL_METHOD0#if #define #define#endifOS_CRITICAL_METHOD = 0OS_ENTER_CRITICAL()ARMDisable() /disableOS_EXIT

9、_CRITICAL() ARMEnable()/enable下面的代码来源于 OS_CPU_a.s;下面是两个开关中断的函数,其只用来操作 CPSR 中的 I 位,;不要担心进入切换前的任务被了中断:主动放弃 CPU 的;任务,其 CPSR 一定是中断的(注意理解),但是其返回;一定是返回到OSCtxSw 之后,“”时,自然会有 enable 来恢;复中断,凡是中断放弃 CPU 的任务,CPSR 一定是允许中断的。;不论怎样返回也一定返回到被中断的现场。;带来的版本是利用用户的堆栈来盛放 CPSR,随后 pop 出来。;在这里是不可以的:使用栈方式保存 CPSR 要保证 Enable 在切换后

10、;可以被运行到,在 OSSched 中(主动放弃 CPU)OS_TASK_SW 被Disable 与 Enable;前后包围,进入 OS_TASK_SW 也可以从中返回,进出时栈结构是相同的;这是可以使用的。;但是,在中断切换的情况下便不同了,在 OSCtxSw 前的 Disable;使用的栈内容不能被保存起来,只将任务运行时的现场保护起来,;不会保留中断标志的压栈信息,因此,这种方式也可使用,但是在没有;增加效率的前提下反而会将堆栈结构复杂化,不建议使用。EXPORT ARMDisableARMDisableSTMDB MRS ORR MSR LDMIAMOVsp!, r0 ;r0 要保存,

11、不可以破坏调用函数的现场r0, CPSRr0, r0, #0 x80CPSR_c, r0 sp!, r0 pc, lrEXPORT ARMEnable ARMEnableSTMDB sp!, r0MRSr0, CPSRBIC r0, r0, #0 x80MSR LDMIAMOVCPSR_c, r0 sp!, r0pc, lr其来源于:OS_CPU_a.s四、OS_TASK_SW,见代码:EXPORT OS_TASK_SW;功能示例;现场压栈;OSPrioCur = OSPrioHighRdy;OSTCBCur-OSTCBStkPtr=SP 保存 SP 到当前任务控制块;STCBHighRdy-

12、OSTCBStkPtr;OSTCBCur=OSTCBHighRdy;弹出现场OS_TASK_SWSTMFD sp!, lrSTMFD sp!, lr; save pc; save lr;分析:OS_TASK_SW 是个函数,在任务间接的调用它时会在最后失去 CPU,再次;获得 CPU 时,其恰好在 OS_TASK_SW 调用完毕后的那个位置,因此,lr 被放入pc;在栈中的位置;此外,lr 放入 lr 在栈中的位置也是无关紧要的,因为,子函数;返回时的 lr 是无意义的。STMFD MRS STMFD;MRSsp!, r0-r12 r4, CPSRsp!, r4r4, SPSR; save r

13、egister file and ret address; save current PSR; YYY+ 这里掉是因为任务运行的;模式是 SYS,没有SPSR,栈中的 CPSR 与 SPSR 相同; YYY+ save SPSRSTMFDsp!, r4LDR LDR LDRBSTRBr4, addr_OSPrioCurr5, addr_OSPrioHighRdy r6, r5r6, r4; OSPrioCur = OSPrioHighRdy; Get current task TCB addressLDRLDRr4, addr_OSTCBCurr5, r4STR sp, r5; store s

14、p in preempted taskss TCB;OSTCBCur-OSTCBStkPtr=SP 保存 SP 到当前任务控制块; Get highest priority task TCB addressLDR LDR LDR;Sr6, addr_OSTCBHighRdyr6, r6sp, r6; get new tasks stack poerTCBHighRdy-OSTCBStkPtr 更新 SP 为即将运行的任务STR r6, r4; set new current task TCB address; OSTCBCur = OSTCBHighRdyLDMFD;MSR LDMFD MSR

15、LDMFDsp!, r4 SPSR_cxsf, r4 sp!, r4CPSR_cxsf, r4; YYY+; YYY+运行在 sys 模式下,无需 SPSR 的更新; YYY+; YYY+sp!, r0-r12, lr, pc ; YYY+;现场恢复完毕其来源于:OS_CPU_a.s这个函数是任务主动放弃 CPU 时最终调用的的函数, 其为 OSSched() 调用, 前后为OS_ENTER/EXIT_CRITICAL 所包围。因此进入OS_TASK_SW 时,IRQ 是被的,保存到堆栈中的 CPSR I 位也是为 1,但是放心,OS_TASK_SW 保存的现场恰好是从OSSched()中 O

16、S_TASK_SW 返回的地方,任务时紧接着是后面解除的代码。五、OSCtxSw,首先,见调用示意图:可见,中断中的调用是较复杂,嵌套较深,这也是的原因。在 OSCtxSw 中从底向上发掘数据其次,见代码,根据上图的 IRQ 栈结构,可以分析如何将其中的有用数据搬运到被中断任务的堆栈中:IMPORTIRQ_STACK EXPORTOSCtxSwCtxSw;该函数运行在 IRQ 状态,他返回 SYS 模式,并将压入 SP_IRQ 的;现场数据搬运到 SP_SYS 中构造出标准栈,保存该栈指针;再;切换到其它的任务中(后半部分与 OSCtxSw 相同);该函数是不返回的,IRQ 处理函数在调用到该

17、函数时,不知道OS;已经压了多少的栈,而不需要从栈顶向下挖掘出当时压;入的现场,只要知道进入 IRQ 状态时的SP 是多少,便可以;由栈底来发掘出 r0-r12 和 pc+4(其实就是 lr_IRQ),见图;这种方法建立的前提是:在 IRQ 的中断处理代码之前对其SP 赋值;这样便不可以实现 IRQ 的嵌套了。;IRQ 处理代码的最前有一句 LDRSP,=IRQ_STACK(见 init.s)LDRr0,=IRQ_STACK ;要找到这个地方sub SP,r0,#14*4;压入的内容从r0-r12 pc+4(lr_irq)14 个;字,现在SP 指向最低位置的r0,可见 图四mrs r0,SP

18、SR;在 IRQ 状态下读SPSR 其实就是被中断现场的 CPSR;现在,irq 栈中的最低位置为 CPSRstmfdsp!,r0orrmsrr0,r0,#0 x80;spsr 中的 I 位CPSR_cxsf,r0 ;返回现场状态,注意,这时 lr_sys 还没变;要不是 sys 模式,SPSR 也是没变的ldr ldrsubr0,=IRQ_STACKr1,r0,#-1*4! ;现在 r0 指向 PC+4,且取出放入r1 r1,r1,#4 ;现在 r1 中是返回的 PCstmfdstmfdsp!,r1 ;压入 pcsp!,lr ;压入 lr现在开始构造标准的任务栈ldmdb stmfd ldm

19、db stmfdcpsr,r0-r12r0!,r4-r11;r0 指向 PC+4,先减后 sp!,r4-r11r0!,r4-r9出 8 个,参见 移植参的栈示意sp!,r4-r9;两次批量搬运从 irq 栈到 sys 栈转移 14 个数据,有低到高;mrs spsr,r4;若任务运行模式不为 sys 则,spsr 需要保存,否则,依然压入 CPSR;r4 中为 CPSRstmfdsp!,r4;到此为止,的标准栈结构已经建立起来,所有需要的现场已被压到 sp_sys;后面的内容和OSCtxSw 的后半部分相同,依次为;OSPrioCur = OSPrioHighRdy;OSTCBCur-OSTC

20、BStkPtr=SP 保存 SP 到当前任务控制块;STCBHighRdy-OSTCBStkPtr;OSTCBCur=OSTCBHighRdy;弹出现场LDR LDR LDRBSTRBr4, addr_OSPrioCurr5, addr_OSPrioHighRdy r6, r5r6, r4; OSPrioCur = OSPrioHighRdy; Get current task TCB addressLDRLDRr4, addr_OSTCBCurr5, r4STR sp, r5; store sp in preempted taskss TCB;OSTCBCur-OSTCBStkPtr=SP

21、保存 SP 到当前任务控制块; Get highest priority task TCB addressLDR LDR LDR;Sr6, addr_OSTCBHighRdyr6, r6sp, r6; get new tasks stack poerTCBHighRdy-OSTCBStkPtr 更新 SP 为即将运行的任务STR r6, r4; set new current task TCB address; OSTCBCur = OSTCBHighRdyLDMFD;MSR LDMFD MSRLDMFDsp!, r4 SPSR_cxsf, r4 sp!, r4CPSR_cxsf, r4; Y

22、YY+; YYY+运行在 sys 模式下,无需 SPSR 的更新; YYY+; YYY+sp!, r0-r12, lr, pc ; YYY+;现场恢复完毕其来源于:OS_CPU_a.s小结:OSCtxSw 是一个较为复杂的函数,作为任务的中断终结者,他的是 IRQ 的堆栈,有用的现场数据在 IRQ 进入时便被压到 IRQ 栈的最低层,CSPR、SP、PC、LR 全部被换。因此,只能先回到SYS 的任务模式,而后由 IRQ 的栈中从底而上取出数据,按标准格式压入任务堆栈。其后的事情与OS_CTX_SW 相同。此外,如果在 OSExit()的判断中,没有新任务需要切换运行,OSCtxSw 便不会被

23、运行,其会层层返回正常的回到被中断的任务。OSCtxSw 对堆栈的处理方式使不可以实现 IRQ 嵌套,但是,OSCtxSw 是健壮的不论前面嵌套了多少的函数,堆栈被压入多少的内容,回到任务。都可以用OSCtxSw 直接的未实现的技术和对未来的想法:周立功的 ARM 书上有关于 ucOS 系统和用户代码分开编译加载的内容,它是将系统单独编译,将系统调用的函数地址组一张表格放到确定的地方,烧写到 flash 中;用户程序加载后,到这张表格中调用系统服务。我有一种更好的想法:ARM 有SWI 软中断的功能,完全可以将所有的系统调用加载在 SVC状态下的SWI 处理函数中。这样,系统烧写在 flash 中,其后加载用户任务,直接执行软中断即可。于 ucOS 移植成功后总结2004-4-7第三次移植的小结:前后移植了 3 次,其关键之处在于中断后对堆栈的处理以及 OSCtxSw 的编写,三

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论