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

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

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

先级。 OSTaskCreateExt()还需要一些其他参数,但与OSTaskStkInit()没有关系。OSTaskStkInit()只需要以上提到的 3个参数:task、pdata、ptos。由于MC68K堆栈是16位宽的(以字为单位),OSTaskStkInit()将创立一个指向以字为单位的内存区域的指针,同时要求堆栈指针指向空堆栈的顶端。堆栈初始化工作结束后,OSTaskStkInit()返回新的堆栈顶指针, OSTaskCreate()或OSTaskCreateExt()将指针保存在任务的OS_TCB中。

三、移植中的几点注意事项

由于μC/OS-II运行的实时性,调试内核几乎不可能。一旦移植过程中内核运行不稳定,很难确定是什么地方的问题,更困难的是有些现象几乎是不可重复的。这就需要详细了解内核运行机理,认真分析,找出可能存在的问题。下面就来分析这些移植过程中的问题。

1.编译器的优化选项

在移植过程中,除了要熟悉μC/OS-II和目标芯片之外,熟悉使用的C编码器也非常重要。通常C编译器都会提供一些优化代码的选项,在移植μc/OS-II的过程中,这些选项往往会带来麻烦。下面是移植中与HIWARE的C编译器有关的例子。

通常在调用子程序或进入中断时,C编译器会自动保存CPU内部寄存器到堆栈中。例如,在进入中断时编译器会加入下面2条指令:

LINK #$0000,A6;

MOVEM.L D0/D1/D3/D4/D5/D6/D7/A0/A1/A2/A3/A4/A5,-(A7);

这2 条汇编指令的作用是将CPU的数据寄存器D0~D7、地址寄存器A0~A5保存到堆栈中,再将此时的堆栈指针A7也保存到堆栈中,并使用A6作为临时的堆栈指针。这本是一个非常好的优化选项,可以防止在中断中偶然地更改了数据寄存器或地址寄存器;但在μC/OS-II中,这个机制将对OS_CPU_C.C 和OS_CPU_ASM.ASM中的几个子程序和中断服务例程产生致命的影响。

OS_CPU_C.C和OS_CPU_ASM.ASM中的子程序中断引发任务调度,当前的任务被挂起。挂起任务是通过下面的语句来完成的:

MOVEM.L A0-A6/D0-D7,-(A7);

MOVE.L @OSTCBCur,A2;

MOVE.L (A2),A1;

MOVE.L A7,(A1);

保存任务的指针和所有数据地址寄存器的值,那么理想情况下,此时的任务堆栈应该是如图1所示的情况(以OSCtxSw()函数为例,可以对应到OS_CPU_C.C和OS_CPU_ASM.ASM中的其他函数和中断处理例程)。

那么恢复挂起的任务时,只要通过如下语句:

MOVE.L OSTCBHighRdy,A1;

MOVE.L @OSTCBCur,A2;

MOVE.L A1,(A2);

MOVE.L (A1),A7;

MOVEM.L (A7)+,A0-A6/D0-D7;

将保存在任务TCB中的任务堆栈指针恢复,再恢复数据地址寄存器,最后执行OSCtxSw()的中断返回,就可以顺利地恢复被挂起的任务。

如果C编译器在OSCtxSw()函数入口处插入了2条保存数据地址寄存器和堆栈指针的语句后,再执行挂起任务的语句,任务的堆栈会变成图2所示的情况。编译器引起了堆栈的变化,如果所有的任务都是用这种方式挂起和恢复的,并不会产生致命的问题,因为编码器退出OSCtxSw()函数时会插入如下语句恢复堆栈:

MOVEM.L (A7)+,D0-D7/A0-A5;

UNLK A6;

问题在于初始化任务的时候,每个任务实际上是按照图1所示的堆栈结构被初始化的,那么,按照图2的堆栈结构来恢复自然会导致堆栈崩溃。

解决这个问题的方法很多,可以改定任务初始化的代码以适应C编译器的这个“优化”,也可以在进入OSCtxSw()函数时首先调用如下语句恢复堆栈,抵消C编码器的影响:

MOVEM.L (A7)+,D0-D7/A0-A5;

UNLK A6;

而在退出OSCtxSw()函数前再调用如下语句模拟出更动的堆栈:

LINK #$0000,A6

MOVEM.L D0-D7/A0-A5,-(A7);

较好的方法当然是调整编译器,取消这个优化选项。如果无法调整编译器,就只有用以上办法来适应编译器了。

2.开关中断的方法

在μC/OS -II中,开关中断是非常重要的,它可以保证关键代码或访问全局变量时不受中断的意外影响。CPU32的中断控制比较复杂,提供了7级具有不同级别的中断;可以选择关闭或打开某几级中断。但多级中断会使得μC/OS-II的中断处理变得复杂。在简单的应用或初次尝试移植μC/OS-II时,可以使用全开全关的方法。

如果考虑多级中断,必须注意到中断开关级别的控制是一个重要的信息,在关闭中断之前需要将这个信息保存起来,在对应的开中断时恢复这个中断级别控制信息。最容易想到的方法是用一个全局变量存存这个信息。

使用这个方法的程序如下:

#define OS_EXIT_CRITICAL() asm move SR_TEMP,sr;

#define OS_ENTER_CRITICAL() asm move.w SR,SR_TEMP;

asm ori.w #0x0700,SR;

接着构造两个任务,每个任务分别向屏幕输出一句话,同时修改内核的代码,让空闲任务也输出一句话。运行内核,通常在几分钟内会发现内核停止调试,只有空

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

网站地图

Top