DIY编程器网

标题: 嵌入式系统μC/OS-II在LPC2119上的移植方法和技巧 [打印本页]

作者: liyf    时间: 2012-1-27 13:59
标题: 嵌入式系统μC/OS-II在LPC2119上的移植方法和技巧

                      本文在分析实时嵌入式系统mC/OS-II和LPC2119芯片的基础上,对mC/OS-II向处理器上移植前需要了解的知识和需要做的前期准备工作进行了分析和讨论,最后给出了移植的具体工作。论文着重分析了mC/OS-II的移植。
  μC/OS-II是一个完整的,可移植、可固化、可裁减的占先式实时多任务内核,它功能强大,支持56个用户任务,支持信号量、邮箱、消息队列等多种常用的进程间通信机制。公开源代码,程序可读性强、移植性好,同时可免费获得。
  LPC2119是由PHILIPS生产的一款32位ARM7TDMI-S微处理器,其核心为高性能的32位RISC体系结构,并具有高密度的16位指令集和极低的功耗。具有零等待128K字节的片内FLASH,16K的SRAM,无需扩展存储器,使系统更为简单、可靠。
  表1






  图1? μC/OS-II硬件和软件体系结构
  μC/OS-II的结构如图1所示。
  如图1所示,与处理器相关的代码只有三个文件,一般移植的时候只要修改这三个文件就可以了。
  编写启动代码
  启动代码是芯片复位后进入C语言的main()函数前执行的一段代码,主要是为运行C语言程序提供基本运行环境,如初始化外围部件、存储器系统等。因此启动代码的功能有些类似PC机中的BIOS和VxWorks中的 Bootloader。由于飞利浦未提供该芯片的启动代码,所以需要自己编写启动代码。
  启动代码可以划分为五个文件: STartup.s、IRQ.s、stack.s、heap.s和target.c。Startup.s包含了前面提到的异常向量表和系统初始化代码,一般无需改动;IRQ.s包含中断服务程序与C程序的接口代码,可根据实际使用的中断情况进行少量修改;stack.s和heap.s保存C语言使用的堆和栈的开始位置;target.c包含目标板特殊的代码,包括异常处理程序和目标板初始化程序,可根据程序的需要修改。






  图2? 系统基本初始化Tar get Peset1 ni t()流程图
  由于启动代码的编写很长,而本文只是想指出编写启动代码是移植前必须做的准备工作并对其进行简要说明,因此在这里就不具体列出所有代码(具体的启动代码见参考文献[1]),而给出一个很重要的目标板初始化程序中的函数TargetReseTInit()的流程图,从中可以看出在进入main ()函数前对系统进行的基本初始化工作的具体步骤。
  移植
  有了上面的知识和编写启动代码这项准备工作完成后,就可以进入具体移植阶段了。主要完成以下工作:
  ① 为了增强代码的可移植性,所有C文件添加头文件includes.h。
  ② 用户程序添加config.h。
  ③ 在文件OS_CPU.H中需要添加或修改的主要代码有:
  定义不依赖于编译器的数据类型:
  typedef unsigned char?? INT8U;
  typedef unsigned short? INT16U;
  typedef unsigned int??? INT32U;
  typedef INT32U?????? OS_STK;
  使用软中断SWI作底层接口:
  __swi(0x00) void OS_TASK_SW(void);????????? /*? 任务级任务切换函数? */
  __swi(0x01) void _OSStartHighRdy(void);??????? /*? 运行优先级最高的任务 */
  __swi(0x02) void OS_ENteR_CRITICAL(void);?? /*关中断 */
  __swi(0x03) void OS_EXIT_CRITICAL(void);???? /*? 开中断 */
  __swi(0x80) void ChangeToSYSMode(void);????? /*? 任务切换到系统模式 */
  __swi(0x81) void ChangeToUSRMode(void);???? /* 任务切换到用户模式 */
  #define OS_STK_GROWTH??? 1????????? /* 堆栈是从上往下长的*/
  定义工作模式:
  #define???? USR32Mode?????? 0x10???????????? /* 用户模式 */
  #define???? SYS32Mode?????? 0x1f????????????? /*? 系统模式*/
  #define???? NoInt??????????? 0x80
  #ifndef???? USER_USING_MODE
  #define?? USER_USING_MODE? USR32Mode?? /*? 任务缺省模式*/
  #endif
  定义开关信号量:??? extern? OS_STK? OsEnterSum
  ④ 在文件OS_CPU_C.C中需要添加或修改的代码:
  OS_ENTER_CRITICAL()代码
  __asm
  {??? MRS???? R0, SPSR
  ORR???? R0, R0, #NoInt
  MSR???? SPSR_c, R0
  }
  OsEnterSum++;
  OS_EXIT_CRITICAL()代码
  if (--OsEnterSum == 0)
  {? __asm
  {??? MRS???? R0, SPSR
  BIC???? R0, R0, #NoInt
  MSR???? SPSR_c, R0
  }
  }
  编写任务堆栈的初始化代码:
  OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
  {? OS_STK? *stk;
  opt? = opt;????????????? /* 'opt'? 没有使用。作用是避免编译器警告 */
  stk? = ptos;????? /* 获取堆栈指针*/
  /* 建立任务环境,使用满递减堆栈 */
  *stk = (OS_STK) task;???? /* pc */
  *--stk = (OS_STK) task;??? /* lr */
  *--stk = 0;?????????????????????? /* r12 */
  ??????????????????????????????? /*r11?r2*/
  *--stk = 0;??????????????? /* r1 */
  *--stk = (unsigned int) pdata;??????????? /* r0,第一个参数使用R0传递 */
  *--stk = (USER_USING_MODE|0x00);?? /* spsr,允许 IRQ, FIQ 中断 */
  *--stk = 0;?????????????????????????? /* 关中断计数器OsEnterSum; */
  return (stk);
  }
  编写如void OSInitHookBegin ( )、void OSInitHookEnd ( )、void OSTaskCreateHook ( )、void OSTaskDelHook ( )等钩子函数,用户可根据需要自行添加代码。
  ⑤ 在文件OS_CPU_A.S中需要添加或修改的代码:
  编写运行优先级最高的就绪任务函数OSStartHighRdy()调用的__OSStartHighRdy代码
  __OSStartHighRdy
  MSR???? CPSR_c, #(NoInt | SYS32Mode)
  LDR???? R4, =OSRunning
  MOV???? R5, #1
  STRB??? R5, [R4]
  BL????? OSTaskSwHook
  LDR???? R6, =OSTCBHighRdy
  LDR???? R6, [R6]
  B?????? OSIntCtxSw_1
  编写OSIntCtxSw代码
  由于篇幅所限,这里给出OSIntCtxSw函数原型,可由此编写代码。源代码详见参考文献[1]。
  void OSIntCtxSw(void)
  {
  调用用户定义的OSTaskSwHook();
  STCBCur=OSTCBHighRdy;
  SPrioCur=OSPrioHighRdy;
  得到需要恢复的任务的堆栈指针;
  堆栈指针=OSTCBHighRdy->OSTCBStkPtr;
  将所有处理器寄存器从新任务的堆栈中恢复出来;
  执行中断返回指令;
  }
  由于篇幅所限,以上给出了移植时需要修改的与处理器相关的三个文件中的主要代码,当然更详细的移植说明可见参考文献[1].为了验证移植成功与否,你可以编写一个简单用户程序(例如通过串口通讯在PC界面显示字符)与mC/OS-II一起编译烧写进芯片来检验,笔者已经试验成功。
  需要避免的错误
  用户程序中的includes.h要修改为config.h,这是因为后者包含了前者和特定的头文件以及配置项。
  数据类型的定义不能直接使用C中的short、int、long等,因为它们与处理器类型有关,隐含着不可移植性,所以在OS_CPU.H中定义移植性强的不依赖于编译器的数据类型。
  必须定义堆栈的生长方向,1表示堆栈从上往下长,0表示堆栈从下往上长,ARM处理器两种方式都支持,但使用的ADS编译器仅支持从上往下长的方式,因此必须定义为1,否则将发生寄存器值入栈错误。
  注意任务堆栈初始化函数中的stk指针定义成INT32U,这是因为我们的处理器是32位的,对堆栈操作也是4字节对齐的。如果处理器是16位的,且对堆栈访问也是2字节对齐的,就要将stk定义成INT16U,否则将会发生严重错误。
  结语
  μC/OS-II具有很好的可靠性、实时性和可裁减性,很适合于工业控制、通信等对实时性、可靠性要求高的领域。笔者采用广州周立功公司的EASYARN2100试验开发板,已经成功把μC/OS-II移植到该开发板上。如果用户对ARM处理器及相关底层硬件和μC/OS-II有一定了解,参照本文,对将μC/OS-II移植到LPC21xx系列ARM处理器上大有帮助。
            




欢迎光临 DIY编程器网 (http://diybcq.com/) Powered by Discuz! X3.2