新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > μC/OS-II在80x86上的移植

μC/OS-II在80x86上的移植

作者: 时间:2016-10-08 来源:网络 收藏

OSIntExit()函数检查任务就绪状态,如果需要进行任务切换,将调用OSIntCtxSw()。所以

OSIntCtxSw()又称为中断级的任务切换函数。由于在调用OSIntCtxSw()之前已经发生了中断,

OSIntCtxSw()将默认CPU寄存器已经保存在被中断任务的堆栈中了。

图F 9.4 任务级任务切换时的80x86堆栈结构.

程序清单L9.5给出的代码大部分与OSCtxSw()的代码相同,不同之处是,第一,由于中断已

经发生, 此处不需要再保存CPU寄存器 (没有PUSHA,PUSHES,或PUSHDS) ; 第二, OSIntCtxSw()需要调整堆栈指针,去掉堆栈中一些不需要的内容,以使堆栈中只包含任务的运行环境。图F9.5可以帮助读者理解这一过程。

程序清单L 9.5 OSIntCtxSw().

_OSIntCtxSwPROCFAR

;;IgnorecallstoOSIntExitandOSIntCtxSw

;ADDSP,8;(UncommentifOS_CRITICAL_METHODis1,seeOS_CPU.H)(1)

ADDSP,10;(UncommentifOS_CRITICAL_METHODis2,seeOS_CPU.H)

;

MOVAX,SEG_OSTCBCur; 载入DS

MOVDS,AX

;

LESBX,DWORDPTRDS:_OSTCBCur;OSTCBCur->OSTCBStkPtr=SS:SP(2)

MOVES:[BX+2],SS

MOVES:[BX+0],SP

;

CALLFARPTR_OSTaskSwHook(3)

;

MOVAX,WORDPTRDS:_OSTCBHighRdy+2;OSTCBCur=OSTCBHighRdy(4)

MOVDX,WORDPTRDS:_OSTCBHighRdy

MOVWORDPTRDS:_OSTCBCur+2,AX

MOVWORDPTRDS:_OSTCBCur,DX

;

MOVAL,BYTEPTRDS:_OSPrioHighRdy;OSPrioCur=OSPrioHighRdy(5)

MOVBYTEPTRDS:_OSPrioCur,AL

;

LESBX,DWORDPTRDS:_OSTCBHighRdy;SS:SP=OSTCBHighRdy-

>OSTCBStkPtr (6)

MOVSS,ES:[BX+2]

MOVSP,ES:[BX]

;

POPDS; 载入新任务的CPU环境 (7)

POPES (8)

POPA (9)

;

IRET; 返回新任务 (10)

;

_OSIntCtxSwENDP

图F 9.5 中断级任务切换时的80x86堆栈结构

当中断发生后,CPU在完成当前指令后,进入中断处理过程。首先是保存现场,将返回地址

压入当前任务堆栈,然后保存状态寄存器的内容。接下来CPU从中断向量处找到中断服务程序的

入口地址,运行中断服务程序。在μC/OS-II中,要求用户的中断服务程序在开头保存CPU其他寄

存器的内容[图F9.5(1)]。此后,用户必须调用OSIntEnter()或着把全局变量OSIntNesting加1。

此时,被中断任务的堆栈中保存了任务的全部运行环境。在中断服务程序中,有可能引起任务

就绪状态的改变而需要任务切换,例如调用了OSMboxPost(),OSQPostFront(),OSQPost(),或试

图唤醒一个优先级更高的任务(调用OSTaskResume()),还可能调用OSTimeTick(),

OSTimeDlyResume()等等。

μC/OS-II要求用户在中断服务程序的末尾调用OSInt Exit(),以检查任务就绪状态。在调用

OSInt Exit()后,返回地址会压入堆栈中[图F9.5(2)]。

进入OSIntExit()后,由于要访问临界代码区,首先关闭中断。由于OS_ENTER_CRITICAL()可

能有不同的操作(见9.03.02节),状态寄存器SW的内容有可能被压入堆栈[图F9.5(3)]。如果

确实要进行任务切换,指针OSTCBHighRdy将指向新的就绪任务的OS_TCB,OSIntExit()会调用

OSIntCtxSw()完成任务切换。注意,调用OSIntCtxSw()会在再一次在堆栈中保存返回地址[图

F9.5(4)]。在进行任务切换的时候,我们希望堆栈中只保留一次中断发生的任务环境(如图

F9.5(1)),而忽略掉由于函数嵌套调用而压入的一系列返回地址(图F9.5(2),(3),(4))。忽

略的方法也很简单,只要把堆栈指针加一个固定的值就可以了[图F9.5(5)/程序清单L9.5(1)]。

如果用方法2实现OS_ENTER_CRITICAL(),这个固定值是10;如果用方法1,则是8。实际操作中

还与编译器以及编译模式有关。例如,有些编译器会为OSIntExit()在堆栈中分配临时变量,这

都会影响具体占用堆栈的大小,这一点需要提醒用户注意。

一但堆栈指针重新定位后,就被保存到将要被挂起的任务OS_TCB中[图F9.5(6)/程序清单

L9.5(2)]。在μC/OS-II中(包括μC/OS),OSIntCtxSw()是唯一一个与编译器相关的函数,也是

用户问的最多的。如果您的系统移植后运行一段时间后就会死机,就应该怀疑是OSIntCtxSw()

中堆栈指针重新定位的问题。

当当前任务的现场保存完毕后,用户定义的对外接口函数OSTaskSwHook()会被调用[程序清

单L9.5(3)]。注意到OSTCBCur指向当前任务的OS_TCB,OSTCBHighRdy指向新任务的OS_TCB。在

函数OSTaskSwHook()中用户可以访问这两个任务的OS_TCB。如果不用对外接口函数,请在头文

件中关闭相应的开关选项,提高任务切换的速度。

从对外接口函数OSTaskSwHook()返回后,由于任务的更替,变量OSTCBHighRdy被拷贝到

OSTCBCur中[程序清单L9.5(4)],同样,OSPrioHighRdy被拷贝到OSPrioCur中[程序清单

L9.5(5)]。此时,OSIntCtxSw()将载入新任务的CPU环境,首先从新任务OS_TCB中取出SS和SP寄

存器的值[图F9.5(7)/程序清单L9.5(6)],然后运行POPDS[图F9.5(8)/程序清单L9.5(7)],

POPES[图F9.5(9)/程序清单L9.5(8)],POPA[图F9.5(10)/程序清单L9.5(9)]取出其他寄存器

的值,最后用中断返回指令IRET[图F9.5(11)/程序清单L9.5(10)]完成任务切换。

需要注意的是在运行OSIntCtxSw()和用户定义的OSTaskSwHook()函数期间,中断是禁止的。

9.04.04 OSTickISR()

在9.03.05节中,我们已经提到过实时系统中时钟节拍发生频率的问题,应该在10到100Hz



关键词:

评论


相关推荐

技术专区

关闭