微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > MC68K的C编译器实现μC/OS-II向MC68K移值解析方案

MC68K的C编译器实现μC/OS-II向MC68K移值解析方案

时间:06-19 来源:互联网 点击:

闲任务不停地向屏幕输出。这种情况非常麻烦,因为根据无法通过调试手段判断何时何处导致内核停止调度。

分析一下,当只有空闲任务运行时,代码为:

move.w sr,sr_temp

ori.w #0700,sr

addi.1 #1,OSIdleCtr

move.w sr_temp,sr

jmp ****

这5句语句在循环运行,而中断(这时只有定时中断)可以在任意一句语句中间切入。那么,如果在MOVE.W SR,SR_TEMP的时候产生了中断,就会执行中断(因为正要关中断,但还没有关上);而中断程序调用的OSIntENTER和OSIntEXIT都会调用 OS_ENTER_CRITICAL()来关闭中断,递增中断嵌套层数全局变量。这时,再次执行MOVE.W SR,SR_TEMP变量就被改写成关中断的值,当从中断返回到IDLE任务执行MOVE.W SR_TEMP,SR时,就关闭了中断,而不是恢复原来的状态寄存器。这样就导致内核无法响应中断,无法调度任务,只有IDLE任务在运行。

如何解决?最容易想到的方法是再增加一个全局变量,用来保存进入中断时的中断开关信息,退出中断恢复这个信息;但如果考虑到中断嵌套,相同的情况又出现了,并且如果一个任务在执行MOVE.W SR,SR_TEMP时被中断打断并且发生了任务调度,那么当个任务恢复时,它使用的中断信息SR_TEMP可以已经是被其他任务更改后的值了。内核无法响应中断,无法调度的任务可能依然存在。

给每个任务和中断都定义一个这样的全局变量,在不考虑中断嵌套的情况下似乎可以解决问题,但想象一下为每一个任务和中断提供一个单独的OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()函数所带来的工作量。显然这不一个好办法。

将中断信息推入堆栈是一个好主意,但我们会看到由此带来的一些更加隐蔽而复杂的问题。实现这个方法的程序代码如下:

#define OS_ENTER_CRITICAL() asm move SR,-(A7);

asm ori.w #0x0700,SR;

#define OS_EXIT_CRITICAL() asm move (A7)+,sr;

这样,每次调用OS_ENTER_CRITICAL(),都将当前的中断开关信息保存到当前任务堆栈或系统堆栈中断OS_EXIT_CRITICAL()时,恢复这个信息。

使用了这个方法后,必须小心地计算堆栈的使用情况,修改OS_CPU_A.ASM和 OS_CPU_C.C文件里的函数。以OSIntCtxSw()函数为例,这个函数将导致中断级的任务调度,即被中断打断的程序不能继续运行,退出中断中另一个优先级更高的任务得以运行。在这个函数中必须对被中断的任务堆栈进行清理,使得这个任务的堆栈看起来和一次正常的任务切换后的情况相同,这样,才能保证这个任务被正确地恢复运行。OSIntCtxSw()函数仅仅在 OSICntExit()函数中被调用。

须指出的是,在中断发生时,CPU32已经将全部的寄存器和状态寄存器,PC指针内容保存到了堆栈中,这样已经为被打断的任务的恢复作好了准备。如果按照正常的中断流程,在退出中断时,被打断的任务应该恢复运行。现在,由于执行了中断级的任务切换,被打断的任务不能立刻恢复,而是被挂起,这就要求在执行任务调度前调整堆栈,使得被中断打断的任务处于随时可以被恢复的状态。

在中断处理程序中,当执行到OSIntExit()时,堆栈的情况和刚刚进入中断还是相同的,是能够随时恢复被打断的任务的情况。那么,只需要忽略 OSIntExit()函数造成的堆栈变化。首先,是OSIntExit()函数本身的返回地址,长度为2个字;调用OS_ENTER_CRITICAL ()压入堆栈的状态寄存器,长度为1个字;最后,是OSIntCtxSw()函数的返回地址,长度为2个字。那么在OSIntCtxSw()进行任务切换时,首先要把这5个字的堆栈的内容清除,才能保证被中断任务的正确恢复。该语句如下:

ADDA #10,A7;

在完成了这些调整后,由于开关中断可能导致的内核调度死锁的可能已经不存在了。但是在这种情况下,另一个更加隐蔽的问题会出现,这个问题又是和使用的C编码器相关的。

问题出现在使用OSSemPend()函数时,一旦调用这个函数,CPU就会出现地址错误而进入异常处理,内核被终止。这个问题相当奇怪,因为, OSSemPend()函数完全是一个C语言写成的子函数,函数本身不应出现地址错误。通过阅读编译器编译出来的目标码发现了问题。EmPend()函数,发现这个函数没有任何局部变量。在进入OSSemPend()函数时,编译器不需要产生LINK指令来提供局部变量空间。所有的参数都是使用带偏移量的地址寄存器间接寻址方式直接从堆栈中取得,而且使用的地址寄存器就是A7寄存器。问题可能就在这里,OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL()对堆栈的操作都会调整A7寄存器,这就会导致下面的语句在利用A7作寄存器间接寻址时发生错乱,出现地址错误。

这需要详细研究编译器的特性。我们使用的HIWARE的编译器实际上已经考

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top