摘要:指出了μC/OS—III较μC/OS—II的改进和发展,说明了移植μC/OS—III的一般原则和方法,最后逐步给出了μC/OS—IlI在S12X架构上移植的步骤,读者按照该步骤就能够顺利完成移植工作。
关键词:μC/OS—III;S12X;CodeWarrior V5.1
引言
S12X架构是飞思卡尔公司推出的16位CPU,占有一定的单片机应用市场。μC/OS—III是.Micrium公司推出的一款实时操作系统(RTOS),它的前身——μC/OS—II,由于源码公开、实时性好、便于学习等优点,应用非常广泛,并被移植到了几乎所有主流的CPU架构上。但是到目前为止,μC/OS—III在S12X架构上还没有官方的移植版本。
μC/OS-III相比μC/OS—II作了很大的改进,整个内核基本被重写。任务的数量可无限多,只受限于系统存储器的大小;由于支持时间片轮转调度,任务的优先级可以相同;采用了延迟中断处理机制(deferred post),中断服务所要访问的全局变量数变得很少,使得大部分临界代码的保护只需要关闭调度器,而不需要关闭中断,大大缩短了系统的中断延迟;系统时钟服务(tick handling)被移到了任务级执行,进一步缩短了中断延迟;引入了时间戳的概念,用32位计数器为系统提供了精确的时标,用来计算每个任务的CPU使用率、最长关中断时间、最长关调度器时间等;提供了独特的、丰富的运行时统计参数,为更好地应用μC/OS—III提供了有力的基础。更深入地了解μC/OS—III内核,读者可以参见参考文献。
总之,μC/OS—III是μC/OS—II的全面升级,具有更短的中断延迟、更丰富的运行时参数、更丰富的调试手段、更优的代码组织、更灵活的配置和使用等,但是,μC/OS—III对于硬件却没有更高的要求:对于ROM的需求,μC/OS—III为6~24 KB,μC/OS—II为6~26KB;对于RAM的需求二者均为1 KB左右,可见μC/OS—III同样适合运行在低端的8位、16位单片机上。由于继承了μC/OS—II的优点,μC/OS—III有了这么多新的优秀特性,它应该会得到更广泛的应用。本文详细地讲述了μC/OS—III移植的方法和在S12X架构上移植的具体步骤,希望能对在该方面有需求的读者提供帮助。
1 μC/OS-III的移植方法
如前所述,μC/OS—III对于硬件的要求并不比μC/OS—II高多少。事实上,只要满足如下几条,μC/OS—III就能够被移植到该平台上:
①处理器带有支持标准C的工具链,并且需要支持32位数据。
②处理器支持中断,并能够提供10~1 000 Hz的周期中断作为系统的时钟节拍源。
③中断能够被关闭和打开。
④处理器有栈指针寄存器,并且所有其他的寄存器能够被存储和恢复。
⑤处理器能够支持足够的寻址空间。
这几个条件,现在的处理器架构都能够满足,S12X显然也满足,所以μC/OS—III能够移植到S12X架构上。
μC/OS—III的代码组织非常利于移植,代码按照模块分层次地组织在一起。移植时需要改动的模块和文件如表1所列。
2 μC/OS-III在S12X架构上移植的步骤
2.1 第一步:建立合适的起点
移植之前找一个合适的起点非常必要。这包括选择已经移植好的可运行的版本、工具链和开发板。由于不存在飞思卡尔16位CPU的μC/ OS—III的移植版本,这里选择K60移植版本。该移植版本的IAR示例工程可以从Micrium官方网站下载。工具链选择CodeWarrior Development Studio for S12(X)V5.1(以下简称CW5.1),开发板使用MC9S12XDP512的核心小板即可。K60的处理器基于Cortex—M4架构,是32位CPU,与S12X 16位处理器存在很大的差异,所以表1中所列的文件基本需要全部重写。
2.2 第二步:新建工程
打开CW5.1,新建工程,选择目标为MC9S12XDP512,调试方式为TBDML,采用C语言开发,选择小存储模式(small memory model),其余的选项按照默认设置即可。MC9S12XDP512采用了分页内存机制,扩展了16位CPU的64 KB寻址空间,它拥有512 KB的Flash,出于简单考虑,移植的过程中忽略这种分页机制,即所谓的小存储模式,只使用默认的64 KB的存储空间。对于大多数的16位单片机应用,这么大的存储空间应该够用。μC/OS—III的设计并没有固定代码和数据的位置,也没有固定中断的设置方法,也没有固定自己的启动代码,将这些都交给了工具链或者用户。μC/OS—III代码的运行开始于main函数,对于之前的C语言环境初始化、硬件初始化没有什么特殊的需求,对于自己的代码和数据段的放置也没有特别的要求,这应该说是一种灵活性。中断设置,需要在前述的prm文件中加入如下几行:
VECTOR 0_startup
VECTOR 7OS_CPU_SysTickHandler
VECTOR 4OSCtxSw
分别制定好用于任务切换的软中断和时钟节拍的RTI中断。
2.3 第三步:添加文件
打开资源管理器,在工程目录下新建表2所示目录,并从官网上下载的IAR示例工程中拷贝相应的文件。在CW5.1的工程中添加表2中新建的文件夹,并将上述拷贝的文件加入对应的文件夹。接下来需要修改路径设置:Edit->Standard Setting->Target->Access Paths,勾选Always Search Usei Paths。这样,添加文件的环节算是完成了。
2.4 第四步:修改文件
这一步是移植的关键,按照表2的总结,一共需要修改8个文件,接下来逐个说明。
(1)os_cpu_a.asm
该文件包含了OSStartHiglaRdy、OSCtxSw、OSIntCtxSw 三个实现任务切换的代码片段,将这3个片段定义到一个代码段,比如codesecti on2段,具体就是在文件开始处加上语句“codesection2:SECTION”即可。另外,μC/OS—III中这3个函数都是在临界代码段中访问,故不需要考虑共享变量的问题。OSCtxSw的代码如下:
该函数被设计成swi软中断的服务程序,所以1~2行代码结合中断响应时的入栈操作完成了被换出任务的上下文的保存,3行调用介入函数,4~7行修改了记录当前任务TCB和优先级的全局变量,8行将SP换成了换入任务的栈指针,9行执行后CPU会装载换入任务的上下文,从而完成了上下文切换。OSStartHighRdy和OSIntCtxSw的机制和OSCtxSw类似,代码分别如下:
应该注意到,这3个函数的功能仅仅是保存换出任务的上下文和装载换入任务的上下文,之所以这么简单,主要是因为S12X的寄存器很少,中断响应和返回过程硬件都自动完成了所有寄存器的保存和恢复。这也从一个侧面说明了为什么需要借助中断完成任务切换的一个原因:借助中断机制,可以高效简洁地完成上下文切换。
(2)os_cpu_c.c
这个文件里面至少需要修改两个函数,即任务栈初始化函数OSTaskStkInit和时钟节拍服务程序OS_CPU_SysTickHandler。遵照S12X中断的栈结构,OSTaskStkInit实现如下:
从栈顶到栈底依次为CCR、D、X、Y、PC,按照S12X的C语言参数传递规则,任务函数的传入参数被保存在了D寄存器对应的栈位置。
该宏保存被中断任务的栈顶指针,在其TCB结构中,之所以需要先递增SP、保存SP、再递减,是因为CPU_SR_ALLOC()宏定义了一个局部变量,该变量处在任务栈上,但是不属于上下文的一部分。
如果在该移植版本上写中断服务子程序,都需要写成上述格式,μC/OS-III才能够正常运行。另外,需要将OSTaskSwHook函数单独定义在os_cpu_a.asm文件中所定义的那个段中,这只需在该函数头尾加上如下语句:
#pragma CODE_SEG codesection2
void OSTaskSwHook(void){
……
}
#pragma CODE_SEG DEFAULT
这是因为该函数被os_cpu_a.asm文件中的3个汇编函数以bsr指令调用,而bsr只能够实现-128~+127范围的相对转移,故这里只需要将他们放在同一段,即可完成跳转。
os_cpu.h为头文件,需要定义上述OS_SAVE_SP()宏,其他的可以不更改,也可以删除那些没有被定义的声明(如原来的pendSV的服务子程),注意os_cpu_a.asm是完全重写,os_cpu_c.c只是修改上述两个函数。
(3)cpu.h
编译器无关的数据类型定义,可以参考Edit->Standard Setting->Compiler for HC12->type sizes,默认情况下char为8位,int和short为16位,long和long long为32位,该编译器不支持64位。该处理器为大端模式、栈生长方向为递减,其余的设置都很容易改动,这里不一一赘述。
(4)cpu_a.asm
替代对应的函数如下所示,其余的函数可以删除(μC/OS—III没有用到):
这几个函数完成相应的使能中断、关闭中断、保存中断状态并关闭、恢复中断状态这4个功能,都比较简单,这里不再赘述。
cpu_c.c文件中的函数其实都可以删了,当然也可以保留,因为这里面原来是一些关于中断向量操作、位带操作指令,这些都是特定于Cortex—M3的,S12X并没有位操作的对应指令。
最后是bsp.c和bsp.h,简单起见,bsp.c只定义了如下函数:
void BSP Init(void){
IRQCR=0x00;
RTICTL=0x74;
CRGINT|=0x80;
}
这算得上是最简单的“bsp包”了,仅仅设置并使能了RTI中断作为系统时钟中断(当然还关闭了IRQ中断)。该函数需要在第一个运行的用户任务中调用,开始μC/OS—III的心跳。
至此,所有必要的文件修改工作已经完成。
2.5 第五步:调试运行
经过上述步骤,如果编译、链接没有什么问题,写一个简单的应用,借助调试器就可以对基于μC/OS—III的应用进行调试了。其实在移植的过程中,第四步的很多细节都是在第五步的调试中发现问题并完善的。值得注意的是,由于MC9S12XDP512没有32位的计数器,所以bsp.c里面也没有初始化该计数器的代码,也没有提供系统所需的CPU_TS_TmrRd函数,所以以下几个宏应该配置如下:
#defineOS_CFG_TS_EN 0u
#define OS_CFG_SCHED_LOCK_TIME_MEAS_EN 0u
不定义CPU_CFG_INT_DIS_MEAS_EN宏,在这种配置下,系统所有依赖于时间戳的功能都被关闭。其余的μC/OS—III组件都可以使能。
结语
使用CW5.1集成开发环境的读者,只要按照以上步骤,即可在S12X系列单片机上完成μC/OS—III的移植和运行。本文还融入了笔者对于μC/OS—III的理解,希望能够帮助读者理解和熟悉μC/OS-III的移植工作,进一步加深对于该款优秀实时内核的理解。