ucos-II在ARM7上的移植(2)

2019-01-19 12:35

SP = OSTCBHighRdy->OSTCBStkPtr; /*取得就绪的高优先级任务的栈顶指针*/ 恢复该任务的现场(); /*于是便可通过刚取得的栈顶指针恢复该任务 */ 执行中断返回指令; /*若OSCtxSw含有软中断指令则需中断返回,本移植不使用软中断*/ }

3) OSIntCtxSw() 函数

该函数用于中断级的上下文切换。由于CPU响应时钟节拍中断后,处理器从svc进入了irq模式,并进入时钟节拍中断服务函数OSTickISR,OSTickISR函数发现若有高优先级任务需要运行,则系统不返回中断前的任务,而直接调度就绪的高优先级任务使之尽快得到执行,以保证实时性能。但是由于OSTickISR函数一开始已经保存过任务中断前的CPU现场,因此OSIntCtxSW()不需要再进行类似的操作。当OSTickISR调用OSIntExit函数找出需要运行的更高优先级任务后,OSIntExit会将该任务的TCB指针放在OSTCBHighRdy中,然后OSIntExit在最后调用OSIntCtxSW函数来从OSTCBHighRdy中获取堆栈指针然后恢复该高优先级任务的现场,使得其继续执行,并不再返回时钟节拍中断服务程序。显然,OSIntCtxSW函数的过程和OSCtxSW函数的后半部分操作相同,因此,OSCtxSW可以借用OSIntCtxSW的代码。

4) OSTickISR()函数

在CPU响应时钟节拍中断后,程序指针PC发生跳转后进入该函数,由于OSTickISR调用OSTimeTick函数使得所有的延时节拍不为0的任务延时节拍数减1,并调用OSIntExit函数来找出就绪的高优先级任务,若需要切换,则最后由OSIntCtxSw来完成新任务的调度,否则仍然返回到被时钟节拍中断的任务。OSTickISR函数的伪码和注释: void OSTickISR(void) {

保存处理器寄存器;/*注意在irq模式下保存CPSR_svc时,要先强制切换到svc模式*/

调用OSIntEnter(); /* 防止在嵌套的中断中发生调度 */

给产生中断的设备清中断; /*本操作已由OSTimeTick中的OSTimeTickHook函数完成*/

调用OSTimeTick(); /*将所有任务不为0的延时节拍数减1*/

调用OSIntExit(); /*检索就绪任务,并将需要调度的高优先级任务的堆栈指针存到OSTCBHighRdy中去,然后调用OSIntCtxSW恢复该任务的现场*/ 恢复处理器寄存器;

执行中断返回指令; /*若没有中断级任务切换,则返回到中断前的任务*/ }

5) ARMDisableInt和ARMEnableInt函数

ARMDisableInt是用来暂时禁止FIQ及IRQ中断的函数,ARMEnableInt则是恢复ARMDisableInt执行前的中断使能状态,二者成对使用,用来保护临界段代码不被中断破坏。本移植使用方式2,即在进入临界段代码前关中断,完成后恢复先前的中断使能状态。

下面给出OS_CPU_A.S的全部内容和注释。

; *****OS_CPU_A.S文件汇编代码开始***** AREA |subr|, CODE, READONLY ;声明为代码段 ;***** OSStartHighRdy代码开始*****

EXPORT OSStartHighRdy ;关键词EXPORT表示声明此函数被其他文件使用,下同

IMPORT OSTaskSwHook ;关键词IMPORT声明此函数/参量在其他文件中定义,下同

IMPORT OSTCBHighRdy IMPORT OSRunning

OSStartHighRdy ; 使就绪表中任务最高的优先级的任务开始运行 BL OSTaskSwHook ; 调用用户的Hook函数,空函数

LDR r4,=OSRunning ; 将OSRunning置1,声明多任务OS开始运行 MOV r5, #1 STRB r5, [r4]

LDR r4, =OSTCBHighRdy ; 伪指令,取得存储OSTCBHighRdy的地址 LDR r4, [r4] ; 得到最高优先级任务的任务堆栈地址 LDR sp, [r4] ; 切换到新任务的堆栈

LDMFD sp!, {r4} ;从新任务堆栈中读取第一个参数(CPSR)到(r4)

MSR cpsr_cxsf, r4 ;再传给cpsr,堆栈中的CPSR弹出到CPU的cpsr寄存器 LDMFD sp!, {r0-r12,lr,pc} ;依次恢复该任务r0~r12,lr,pc,切换到该任务

; *****下面开始OSCtxSw函数,完成任务级的任务切换***** EXPORT OSCtxSw IMPORT OSPrioCur IMPORT OSPrioHighRdy IMPORT OSTCBCur IMPORT OSTaskSwHook

IMPORT OSTCBHighRdy;该变量指向任务切换后即将运行的任务的OS_TCB OSCtxSw

STMFD sp!, {lr} ; OSCtxSw是被调用的,lr的值就是调用前的PC值,入栈 STMFD sp!, {r0-r12,lr} ; 将lr和其他寄存器入栈 MRS r4, cpsr ;通过MRS指令将cpsr入栈

STMFD sp!, {r4} ; 被挂起的当前任务的寄存器保存完毕,下面接着保存该 ;任务的堆栈指针,以便下次恢复时,可以找到其堆栈指针,便可恢复其寄存器 LDR r4, =OSTCBCur ; 得到当前TCB块的地址,传给r4

LDR r5, [r4] ; 将OSTCBCur中的值传给r5,注意OSTCBCur存的是指针 STR sp, [r5] ; 将当前任务的sp传到OSTCBCur存的指针中去

; *****下面OSCtxSw准备恢复优先级更高的就绪任务,这部分可共用OSIntCtxSw的代码

*****

; *****OSIntCtxSw函数开始***** EXPORT OSIntCtxSw IMPORT OSTaskSwHook OSIntCtxSw ;准备任务切换

BL OSTaskSwHook ;调用Hook函数,此为空函数 LDR r4, =OSTCBHighRdy

LDR r4, [r4] ;将高优先级的任务栈顶指针存到r4中 LDR r5, =OSTCBCur

STR r4, [r5] ; OSTCBCur = OSTCBHighRdy LDR r6, =OSPrioHighRdy;取出高优先级 LDRB r6, [r6] ;优先级,字节传送 LDR r5, =OSPrioCur

STRB r6, [r5] ; OSPrioCur = OSPrioHighRdy LDR sp, [r4] ;从r4中取得要恢复的任务的栈顶指针 LDMFD sp!, {r4} ;弹出任务栈中的第一个参数,即cpsr MSR cpsr_cxsf, r4 ;首先开始恢复cpsr

LDMFD sp!, {r0-r12,lr,pc} ;依次恢复r0~r12,lr,pc,任务切换

; *****OSTickISR开始***** EXPORT OSTickISR IMPORT OSIntEnter IMPORT OSTimeTick IMPORT OSIntExit

LINK_SAVE DCD 0 ;用来保存时钟节拍中断前的lr,以便计算出pc而使之入栈 PSR_SAVE DCD 0 ;用来保存中断前的spsr,中断产生时,svc模式下的cpsr存

到spsr

OSTickISR ;时钟节拍中断服务程序入口,需要用户在主函数中安装 STMFD sp!, {r4} ;因为r4下面要使用,故先保存r4到irq模式的堆栈中 LDR r4, =LINK_SAVE ; 准备保存LR,SPSR,以便得到中断前的pc和cpsr_svc STR lr, [r4] ; LINK_SAVE = lr_irq,此时lr=PC(中断发生前)+4 MRS lr, spsr ;lr已保存,用lr取得spsr(保存的是中断前的cpsr) STR lr, [r4, #4] ; PSR_SAVE = spsr_irq LDMFD sp!, {r4} ;恢复r4

ORR lr, lr, #0x80 ;在上下文切换前,屏蔽irq中断。注意lr存的是中断前

的cpsr

MSR cpsr_cxsf, lr ;中断产生前是svc模式,故必须要切换到此模式下保存现场

SUB sp, sp, #4 ;按任务栈结构,空一个空间预留给PC STMFD sp!, {r0-r12,lr} ; 依次保存lr、r12~r0

LDR r4, =LINK_SAVE ;准备保存pc,取得存svc模式下发生中断前lr的地址 LDR lr, [r4, #0]

SUB lr, lr, #4 ;中断前的pc = LINK_SAVE - 4,此前lr为异常前pc+4的值 STR lr, [sp, #(14*4)];保存pc到任务栈中预留的空间

LDR r4, [r4, #4] ;开始保存cpsr,r4 = PSR_SAVE,即中断前的cpsr_svc STMFD sp!, {r4} ;保存svc模式下任务的cpsr,寄存器保护完毕 LDR r4, =OSTCBCur ;下面开始将该堆栈指针传给OSTCBCur所指向的指针 LDR r4, [r4] ;便于OSIntExit函数判断是否当前任务优先级最高 STR sp, [r4] ;在OSTCBCur->OSTCBstkptr保存被中断的任务的栈顶指针 BL OSIntEnter ;异常前的上下文保存好之后,开始准备中断服务,将OSIntNesting++

BL OSTimeTick ;将所有延时节拍不为1的任务的节拍数都减1,并清中断标志 BL OSIntExit ;将OSIntNesting--,并判断是否有高优先级任务就绪,若有, ;则调用OSIntCtxSw()调度该任务并不再返回; 若没有则返回到这里

LDMFD sp!, {r4} ;这里sp存的仍是调用OSIntEnter前的sp,即被中断的任务

栈顶指针

MSR cpsr_cxsf, r4 ;从堆栈中恢复中断前任务的cpsr,注意此时irq才被重新允许

LDMFD sp!, {r0-r12,lr,pc} ;恢复中断前任务的 r0-r12,lr和pc,返回被中断的任务

;******OSTickISR函数代码完成,下面是临界段代码前后开关中断的函数******

EXPORT ARMDisableInt ARMDisableInt

MRS r0, cpsr ;由于任务和内核都运行在svc模式下,因此可方便地操作cpsr STMFD sp!, {r0} ; 保存当前的cpsr ORR r0, r0, #0xc0 ;屏蔽FIQ,IRQ中断 MSR cpsr_c, r0 ;回写cpsr,只屏蔽IRQ中断 MOV pc, lr ;返回 EXPORT ARMEnableInt

ARMEnableInt ;必须和ARMDisableInt成对使用

LDMFD sp!, {r0} ;弹出在ARMDisableInt中被保存的cpsr MSR cpsr_c, r0 ;恢复关中断前的cpsr MOV pc, lr ;返回 END ;汇编代码结束

;*****OS_CPU_A.S文件结束****** 4 小结

这里较详细地叙述了轻量级的实时内核μC/OS-II在ARM7处理器(S344B0X)的移植过程,并给出了简练而实用的代码,移植代码和移植思想对于μC/OS-II在其他ARM处理器上的移植具有较强的借鉴意义。


ucos-II在ARM7上的移植(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:03优秀孩子是怎样训练出来的

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: