基于Cortex—M4内核的μCOS—Ⅱ移植
2016-04-26江达飞
江达飞
【摘 要】针对TI公司新推出的基于Cortex-M4内核的TM4C123G高性能低功耗芯片,详细介绍了嵌入式开源实时操作系统μCOS-Ⅱ在芯片上的移植方法。根据移植的需求,首先介绍了芯片的一些基本功能以及相关的软件开发环境,然后结合芯片的固有特性以及μCOS-Ⅱ移植的需求,使用C语言和汇编语言修改了相关的源文件,并详细阐述了修改的原因。
【关键词】Cortex-M4;μCOS-Ⅱ;TM4C123G;移植
0 引言
目前,嵌入式芯片已经被广泛应用到我们的生活工作中,各种智能电子设备中都有他们的身影,例如智能冰箱、云电视、智能窗帘、扫地机器人等等。嵌入式处理器在所有的处理器市场中已经占据了94%以上份额。在诸多的嵌入式芯片中,基于Cortex-M系列芯片以它高能效的兼容性以及易于使用性获得了广大开发者的青睐。
随着芯片性能的提高,芯片所承担的任务将变得更为复杂,与之前的MCU相比,嵌入式芯片可能需要同时运行几十个不同的任务,因此如何更有效的编写应用层软件,管理众多的硬件模块以及满足每一个任务对实时性的要求已成了亟待解决的问题。使用传统的方式进行嵌入式开发时,开发人员需要在充分了解硬件的基础上设计出驱动程序,并直接在主程序中调用不同的驱动函数完成相关功能。然而,当系统需要完成的任务数量变多时,设计人员将很难保证每一个任务所需要的CPU资源。使用嵌入式实时操作系统的优点是:它可以统一管理系统资源,让开发人员从复杂的CPU资源分配中解脱出来,自动调度多个不同任务程序,提高程序开发效率;将硬件与软件剥离开来,减少软件与硬件的直接相关度,提高系统的可靠性。
μC/OS-II由美国嵌入式系统专家Jean J.Labrosse设计开发,可被移植到多种微处理器中,它是一个可以裁剪的操作系统,通过设置os_cfg.h头文件中的相关宏定义,可启用或者禁用相关的功能。它拥占256个优先级,是一个多任务抢占式的实时内核,优先级序号越低,其任务的优先级就越高,当高优先级任务就绪,就会中断低优先级任务,保证高优先级任务的实时性。μC/OS-II已经通过联邦航空局(FAA)商用航行器认证,符合航空无线电技术委员会(RTCA)DO-178B标准。
Cortex-M4处理器是ARM公司开发的新一代嵌入式处理器,在M3的基础上,它新增了FPU、DSP和并行计算等功能,极大提高了运算能力。本次移植使用了TI公司生产的TM4C123G芯片,其基于ARM Cortex M4F的内核设计实现,浮点运算符合IEEE754标准,CPU位数32位,主频最高可达80MHz,拥有低功耗模式, systick时钟和嵌套向量中断控制器NVIC,适用于μC/OS-II的移植。软件使用了TI公司提供的CCS集成开发环境。
1 μC/OS-II的移植
μC/OS-II v2.91的源代码分为三个部分,其中第一部分文件放置在Configure文件夹中,用于配置/裁剪系统;另外一部分文件放在Source文件夹中,此部分程序是操作系统的核心文件,无需修改;最后一部分文件在Ports文件夹中,内部包含OS_CPU.h、OS_CPU.c、OS_CPU_A.asm三个文件。在不同的芯片上使用μC/OS-II时,需要结合芯片的特性,对这三个文件进行修改。
1.1 OS_CPU.h文件的移植
该头文件定义了数据类型、处理器堆栈数据字长度、堆栈的增长方向、任务切换的宏定义和临界区访问的处理方法。
由于不同的处理器其内部一次所能处理的字长不一致,因此对于不同的CPU来说,int,unsigned int等数据类型它的字长可能是不同的,μC/OS-II为了保证可移植性,程序中自己定义了一套数据类型,例如使用INT32U表示无符号32位整形,TM4C123G是32位处理器,其unsigned int表示32位无符号整形,因此可以使用typedef将unsigned int定义为INT32U。然而,对于其它一些16位的处理器来说,unsigned int可能表示的是16位无符号整形,因此INT32U必须被定义为unsigned long型。
临界段又被称为关键代码区,是指一小段代码,同一时刻只能够允许一个线程存取资源。在它能够执行前,必须独占某些共享资源的访问权,一旦线程进入了临界段,就意味着在这期间,其它想要获得该共享资源访问权的线程必须等待该线程处理完成,并释放资源。这是让若干行代码能够以原子操作方式来使用资源的一种方法。μC/OS-II是一个抢占式的实时内核,在进入和退出临界段时需要关闭和打开中断,它使用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()这两个宏来控制中断打开或者关闭,并提供了三种方式:①直接通过使用指令_disable_interrupt()和_enable_interrupts()开关中断;②将当前的中断状态字压至堆栈,然后再关闭中断,当中断结束后,再将堆栈中的状态字弹出;③保存当前CPU状态字至局部变量,然后关中断,当需要开中断时,再将局部变量恢复至CPU寄存器中。使用前两种方式会造成CPU在中断前后状态不一致,但第三种方式需要汇编指令支持。TM4C123G芯片使用Thumb-2指令集,支持MRS指令,可以将CPU状态寄存器的值返回至通用寄存器中,因此可以使用第三种方式控制中断。OS_CPU_SR_Save和OS_CPU_SR_Restore在.asm文件中定义,由于ARM编译器默认会将函数的第一个参数传送至R0通用寄存器,因此它们可以定义为:
OS_CPU_SR_Save
MRS R0, PRIMASK //保存CPU状态寄存器
CPSID I //关中断
BX LR
OS_CPU_SR_Restore
MSR PRIMASK, R0 //恢复CPU状态寄存器
BX LR
堆栈增长方向是指数据入栈时字节变量在内存中的存储顺序,Cortex-M4内核支持的是“向下生长的满栈”方式,即堆栈SP指针在压入一个新的数据时,其值需要先被减去4,然后再存入新的数值。因此宏OS_STK_GROWT的值被设置为1。
1.2 OS_CPU.c文件的移植
OS_CPU.c文件中包含移植中可以在C语言环境下实现的代码。在该文件中,包含了多个hook钩子函数、OSTaskStkInit()任务堆栈初始化函数和Tmr_TickISR_Handler()时钟中断服务函数,其中 OSTaskStkInit()和Tmr_TickISR_Handler()函数是移植能否成功的关键。
OSTaskStkInit()在任务创建函数OSTaskCreate()函数中被调用,用于创建一个新的线程,因此,在刚开始,需要在堆栈中模拟一个线程刚被中断的假象。在cortex-M4内核中,当系统被中断时,xPSR,PC,LR,R12,R3~R0寄存器将被自动保存至堆栈之中,R11~R4则在需要时,通过人工的方式进行保存。另外由于cortex-M4包含浮点运算单元FPU,如果该单元被启用,则内部的FPSCR,S0~S15寄存器也会自动保存至堆栈中,S16~S31寄存器通过人工方式保存。为了模拟任务线程被中断的场景,OSTaskStkInit()的定义如下:
OS_STK *OSTaskStkInit()
{
保存FPSCR及S15~S0寄存器;//保存FPU自动保存的寄存器
保存xPSR,xPSR,PC,LR,R12,R3~R0等寄存器;//保存CPU自动保存的寄存器
保存S16~S31寄存器;//保存FPU中需要人工保存的寄存器
保存R4~R11寄存器;//保存CPU中需要人工保存的通用寄存器
}
Tmr_TickISR_Handler()是时钟中断函数,其内部调用了μC/OS-II的节拍服务函数OSTimeTick(),在实时操作系统中起着”心脏“的作用。Tmr_TickISR_Handler()可以使用通用时间定时器或者看门狗定时器,但在cortex-M4内核中,单独为RTOS提供了一个24位周期性定时器systick,使用它作为系统时钟的优势是:所有基于ARM架构的M3或是M4内核,其内部都会有一个systick定时器,这样做方便了程序在不同的器件之间的移植。
1.3 OS_CPU_A.asm文件的移植
该文件中包含多个用于任务切换的关键函数,由于要涉及寄存器的保存与恢复,因此只能使用汇编语言实现。另外,由于使用CCS作为编译环境,因此在文件的起始处,使用.global引入外部C文件声明的函数,使用.def引出本文件中声明的函数。
OSStartHighRdy()函数的作用是启动第一个最高优先级任务,它的工作过程分为以下五个步骤:①设置PendSV异常中断的优先级为最低。这样能够保证上下文切换是在没有任何中断需要被响应时进行的,保证系统的实时性。②设置PSP进程栈指针为0,指定是第一次任务切换。③设置OSRunning标志位1,表示系统已开始运行。④触发PendSV中断,实现上下文切换。⑤使能中断。
OSCtxSw()和OSIntCtxSw()两个函数的功能类似,都是完成任务的切换,不同的是一个是任务级的,一个是中断级的,但由于是在cortex-M4上移植,所有的任务切换工作都在PendSV中断函数中完成,以加快处理速度,因此这两个函数的内容是完全一致的,只要触发PendSV中断即可。
PendSV函数是完成任务切换的核心函数,为了实现高低优先级任务间的切换,该函数必须完成以下几个操作:①获取进程堆栈指针PSP,如果是0则表示当前是第一次任务切换,无需保存寄存器;②保存S16~S31寄存器,其它FPU寄存器系统将自动保存;③保存R4~R11通用寄存器,其它CPU寄存器系统自动保存;④将PSP指针保存至TCB中,令OSTCBStkPtr指针的值等于PSP;⑤调用OSTaskSwHook钩子函数,在任务切换之前完成用户需要完成的一些特定工作;⑥获得当前就绪的最高优先级任务,并从相应的TCB中获得进程堆栈指针;⑦根据获取的堆栈指针,从相应的堆栈中将S16~S31恢复至FPU中;⑧恢复R4~R11寄存器到CPU中,并执行相应的中断返回指令。
2 总结
通过对基于cortex-M4内核的TM4C123G芯片工作原理以及内部寄存器研究,结合μC/OS-II实时操作系统移植的需求,正确配置了OS_CPU.h,OS_CPU.c,OS_CPU_A.asm三个文件,实现了实时操作系统在M4内核上的移植,实验表明,使用操作系统可以很好的控制TM4C123G开发板上LED灯的闪烁,证明移植是成功的。
【参考文献】
[1]肖圣兵,肖红菊.μC/OS-II在ARM+Cortex-M3处理器上的移植[J].电子技术设计与运用,2014,8:54-55.
[2]关海,冯大政.μC/OS-II在基于Cortex-M3核的ARM处理器上的移植[J].电子科技,2009,22:69-73.
[3]潘丽蕊,袁保社.基于Cortex-M3核的μC/OS-II移植与应用[J].电脑知识与技术, 2010,5111-5114.
[4]卢有亮.嵌入式实时操作系统[M].北京:电子工业出版社,2014.
[责任编辑:汤静]