UC_OS在龙芯处理器上的移植及性能分析
ucos_II移植总结
Ucos_II移植总结:之前已经基本算是成功的移植过ucos-II(内存管理部分没有处理),但是由于可恶的硬盘故障,让我的劳动成果付诸东流。
其间的一些移植经验没有及时总结,现在想来颇有点从头再来的悲壮!鉴于之前的教训,这次,边移植边总结,以防重蹈覆辙。
还好之前的移植过程已经解决了部分棘手的难题,现在复现一下权当是复习一下arm和ucos_II了。
这次的移植还是基于SEP4020芯片,其中的一些引导代码和中断处理代码还是照搬已经写好的代码吧,现在已经没有自己动手写的激情了!下面按照自己的移植步骤一步步总结吧:第一步:创建工程,将基本的启动代码照搬过来,建立一个最小系统,能够在开发板上运行成功。
第二步:将ucos-II源代码copy过来。
第三步:对基本的语法错误进行改正。
对工程进行编译,根据提示进行基本语法的改正。
主要包括:INCLUDES.h中头文件的调用第四步:对需要自己手动编写的函数首先要清空,防止编译报错,然后一步步手动编写代码。
1、临界段代码:os_cpu.h中OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()两个宏重新定义为我们自己写的开关中断函数。
Os_cpu_a.s文件添加如下代码:AREA MCUINIT , CODE, READONLYENTRY;/* 开启IRQ中断*/;voidEnableInterrupt(void);{EXPORT EnableInterruptEnableInterruptmrs r0,CPSRbic r0, r0, #0x80 ;set bit7 to 0msr CPSR_cxsf,r0movpc,lr ;Return to caller;};/* 关闭IRQ中断*/;voidDisableInterrupt(void);{EXPORT DisableInterruptDisableInterruptmrs r0,CPSRorr r0, r0, #0x80 ;set bit7 to 1msr CPSR_cxsf,r0movpc,lr ;Return to caller;}END2、OS_CPU_A.S文件代码编写AREA MCUINIT , CODE, READONLYENTRY;/* 开启IRQ中断*/;voidEnableInterrupt(void);{EXPORT EnableInterruptEnableInterruptmrs r0,CPSRbic r0, r0, #0x80 ;set bit7 to 0msr CPSR_cxsf,r0movpc,lr ;Return to caller;};/* 关闭IRQ中断*/;voidDisableInterrupt(void);{EXPORT DisableInterruptDisableInterruptmrs r0,CPSRorr r0, r0, #0x80 ;set bit7 to 1msr CPSR_cxsf,r0movpc,lr ;Return to caller;};任务切换代码OSCTXSWEXPORT OS_TASK_SW_ARMOS_TASK_SW_ARMSTMFD sp!, {lr} ; save pcSTMFD sp!, {lr} ; save lrMRS r14, SPSRSTMFD sp!, {r14} ; save current PSRSTMFD sp!, {r0-r12} ; save register file and ret address ;; OSPrioCur = OSPrioHighRdyIMPORT OSPrioCurIMPORT OSPrioHighRdyLDR r4, =OSPrioCurLDR r5, =OSPrioHighRdyLDRB r6, [r5]STRB r6, [r4]; Get current task TCB addressIMPORT OSTCBCurLDR r4, =OSTCBCurLDR r5, [r4]STR sp, [r5] ; store sp in preempted taskss TCB; Get highest priority task TCB addressIMPORT OSTCBHighRdyLDR r6, =OSTCBHighRdyLDR r6, [r6]LDR sp, [r6] ; get new tasks stack pointer; OSTCBCur = OSTCBHighRdySTR r6, [r4] ; set new current task TCB address;LDMFD sp!, {r0-r12} ; YYY+LDMFD sp!, {r14} ; YYY+; LDR r14, =0x000000D3MSR CPSR_cxsf, r14 ; YYY+;调试时屏掉此句才会跑的通,待解决LDMFD sp!, {lr,pc} ; YYY+;OS启动时开始运行创建的最高优先级任务; void OSStartHighRdy(void); ; Start the task with the highest priority;;EXPORT OSStartHighRdyOSStartHighRdyIMPORT OSTCBCurIMPORT OSTCBHighRdyIMPORT OSRunningLDR r4, =OSTCBCur ; Get current task TCB addressLDR r5, =OSTCBHighRdy ; Get highest priority task TCB addressLDR r5, [r5] ; get stack pointerLDR sp, [r5] ; switch to the new stackSTR r5, [r4] ; set new current task TCB address;OSRunning = 1 'TURE'LDR r4, =0x01 ; Get current task TCB addressLDR r5, =OSRunning ; Get highest priority task TCB addressSTRB r4, [r5];LDMFD sp!, {r0-r12} ; start the new taskLDMFD sp!, {r14} ; get new state from top of the stackMSR CPSR_cxsf, r14 ; CPSR should be SVC32ModeLDMFD sp!, {lr,pc};中断级任务切换EXPORT OSIntCtxSwOSIntCtxSwIMPORT OSTCBCurIMPORT OSPrioCurIMPORT OSTCBHighRdyIMPORT OSPrioHighRdyIMPORT OSTaskSwHookBL OSTaskSwHook;OSTCBCur = OSTCBHighRdyLDR r4, =OSTCBCurLDR r5, =OSTCBHighRdyLDR r6, [r5]STR r6, [r4];OSPrioCur = OSPrioHighRdyLDR r4, =OSPrioCurLDR r5, =OSPrioHighRdyLDRB r6, [r5]STRB r6, [r4];sp = OSTCBHighRdy->OSTCBStkPtrLDR r6, =OSTCBHighRdyLDR r6, [r6]LDR sp, [r6] ; get new tasks stack pointerLDMFD sp!,{r0, r1};在timedly中断服务程序中,函数开始压栈两个寄存器,为保证堆栈中数据一致,需出栈对齐;resume registersLDMFD sp!, {r0-r12} ; start the new taskLDMFD sp!, {r14} ; get new state from top of the stack; LDR r14, =0x000000D3MSR CPSR_cxsf, r14 ; CPSR SVC32Mode调试时屏掉此句才会跑的通,待解决LDMFD sp!, {lr,pc}END中断服务程序代码IRQ_DOstmfd sp!, {r0,r1}ldr r0, =IRQ_R1str r1, [r0]ldmfd sp!, {r0}ldr r1, =IRQ_R0str r0, [r1] ;保存R0和R1寄存器(因为这两个寄存器再后面要用到)add r13, r13, #4 ;restore the sp_irq top to original irq topsub r14, r14, #4mov r0, r14 ;LR_irq(R14)减4并保存在R0mrs r1, spsrorr r1, r1, #0x80 ;将SPSR_irq的中断屏蔽位置‘1’(屏蔽中断),并保存再R1 中msr cpsr_cxsf, r1 ;将模式切换到中断前的模式;---------------------------------------------------------------------------------------------bic r1, r1, #0x80 ;将原先保存的SPSR_irq的R1的中断屏蔽位清零(允许中断)stmfd sp!, {r0}stmfd sp!, {r14}stmfd sp!, {r1} ;依次将R0,R14,R1的值压入中断前模式下的堆栈(当前R0,R14,R1中存放的分别是LR_irq-4,中断前模式下的LR,SPSR_irq)ldr r0, =IRQ_R1ldr r1, [r0]stmfd sp!, {r1}ldr r1, =IRQ_R0ldr r0, [r1]stmfd sp!, {r0}ldmfd sp!, {r0,r1} ;恢复原先保存的R0和R1stmfd sp!, {r0-r12} ;将r0--r12全部压入中断以前模式下的堆栈;; Get current task TCB addressIMPORT OSTCBCurLDR r4, =OSTCBCur;及时保存当前任务中断,因为可能会进行任务切换LDR r5, [r4]STR sp, [r5] ; store sp in preempted taskss TCB;-----------------------------IMPORT int_vector_handlerbl int_vector_handler ;跳转到中断源判断和中断处理程序;----------------------------- ;restore the registerldmfd sp!, {r0-r12} ;恢复原先保存的R0-R12ldmfd sp!, {r14}msr cpsr_cxsf, r14ldmfd sp!, {r14} ;将原先保存的SPSR_irq恢复到CPSR中ldmfd sp!, {pc}3、堆栈初始化函数OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) {unsignedint *stk;opt = opt; /* 'opt' is not used, prevent warning */stk = (unsigned int *)ptos; /* Load stack pointer *//* build a context for the new task */*--stk = (unsigned int) task; /* pc */*--stk = (unsigned int) task; /* lr */*--stk = (0x60000053); /* cpsr IRQ, FIQ disable*/*--stk = 0; /* r12 */*--stk = 0; /* r11 */*--stk = 0; /* r10 */*--stk = 0; /* r9 */*--stk = 0; /* r8 */*--stk = 0; /* r7 */*--stk = 0; /* r6 */*--stk = 0; /* r5 */*--stk = 0; /* r4 */*--stk = 0; /* r3 */*--stk = 0; /* r2 */*--stk = 0; /* r1 */*--stk = (unsigned int) pdata; /* r0 */// *--stk = (0x0); /* spsr IRQ, FIQ disable */return ((void *)stk);}4、timertick函数void Timer_IRQ_Service1(void){U32 dummyread;U8 y;dummyread = *(RP)TIMER_T1ISCR;/* timerflag = 1;*///OSIntNesting = OSIntNesting + 1;clear_reg( TIMER_T1CR, 0);//关闭通道1中断OSTimeTick ();set_reg( TIMER_T1CR, 0);//使能通道1中断OS_ENTER_CRITICAL();if ((OSIntNesting == 0) && (OSLockNesting == 0)) { /* Sched. only if all ISRs done & not locked */y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);if (OSPrioHighRdy != OSPrioCur) { /* No CtxSw if current task is highest rdy */OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];OSCtxSwCtr++; /* Increment context switch counter *///OS_TASK_SW(); /* Perform a context switch */OSIntCtxSw();}}OS_EXIT_CRITICAL();}第五步:对移植好的代码进行调试。
嵌入式实时操作系统uc/OSⅡ在MSP430F149上的移植应用
su c cde i etd n p l d Th sse o re o s tse a d a pi . e e ytm a o t h w y d l t k s f r ein ise d f te ta iin lfr a d a k ru d e o . d ps e a o mut a ot e d sg n ta o h r dt a o n b c go n mb d t is wa o id s f r d sg .1h y e ot  ̄ ei wa n _e wa ma e te ytm mo lrz d tC o ec me h s o c mig o h rd t n y a d o s p te ra—i a k s h sse duaie ,i a n v ro te h r o n fte ta ii a wa t ol n b o tu h e tme . l
维普资讯
科 黑江— — 龙— 技式实时操作系统 u/ SI在 cO I MS 4 0 9上 的移植 应 用 P 3F 4 1
李 锐
( 南京 邮 电 大 学 , 苏 南 京 2 0 o ) 江 10 0
摘 要 : 绍 了使 用 T 公 司 的超 低 功 耗 MS 4 0单 片 机 与 u/ S I 相 结 合 设 计 数 据 采 集 控 制 系统 的 方 法 , 于编 译 器 I 31A 版 本 详 细 讨 介 I P3 cO I 基 AR ,0 论 了 u/ S I在 MS 4 0 1 9上 的移 植 的 实现 过 程 , 出 了在 u / S I 的 移 植 过程 中 的 重 点 和 难 点 问 题 , 出 了 H/ S I在 MS 4 0上 移 植 的 一 c O I P 3F4 指 c O I 得 C 0 I P3
嵌入式操作系统uC_OS_在ARM上的移植研究
技术创新ARM 开发与应用您的论文得到两院院士关注嵌入式操作系统uC/OS-II 在ARM 上的移植研究Research of Porting Embedded μC/OS-II Operating System Based on ARM(南方医科大学)李玉刚LI Yu-gang摘要:随着ARM 技术的广泛应用,建立基于ARM 构架的嵌入式操作系统已成为当前研究的热点。
文中结合实例论述了基于ARM 内核的微处理器上的嵌入式μC/OS-II 操作系统的移植技术,介绍了μC/OS-II 系统主要特点,提出了移植条件及移植的实现方案过程,对编写启动代码进行了测试验证通过的整体设计。
关键词:ARM;嵌入式操作系统;移植;μC/OS –II 中图分类号:TP311文献标识码:AAbstract:With the applications of ARM technique ,building the embedded operating system based on ARM processor has been a hot point of research.Discusses the porting of μC/OS-II RTOS on ARM kernel architecture.Introduce primary characteristics of μC/OS-II system and presents the prerequisite and realization process of transplant .Finally ,explain the reason of program start code and validate through testing.Key words:ARM;embedded operating system;porting;μC/OS-II文章编号:1008-0570(2010)08-2-0097-021ARM 7微处理器体系结构和μC/OS-Ⅱ内核结构1.1ARM7微处理器体系结构90年代,ARM32位嵌人式RISC(精简指令集计算机)处理器扩展到世界范围,占据了低功耗、低成本和高性能的嵌入式系统应用领域的领先地位。
uC_OS_内核在基于FPGA的CPU上的移植
计算机技术应用uC /OS 2II 内核在基于FP G A 的CPU 上的移植李山山1,李耀锵1,刘敬晗2,汤志忠1(1.清华大学计算机教学实验中心,北京 100084;2.清华大学基础训练中心,北京 100084)摘 要:介绍了基于FP GA (field programmable gate arry )的CPU MiniArm 的指令系统、体系结构以及具体实现方法,讨论了将uC/OS 2II 内核移植到MiniArm 平台的关键技术,并详细描述了移植的具体实现过程,介绍了移植测试的方法并分析了测试结果,最后总结了移植操作系统到基于FP GA 的CPU 上的一般方法。
关键词:FP GA ;CPU ;uC/OS 2II ;移植中图分类号:TP311 文献标志码:B 文章编号:100224956(2010)0420087204T ransplanting uC/OS 2II kernel to FPGA 2based CPU MiniArmLi Shanshan 1,Li Yaoqiang 1,Liu Jinghan 2,Tang Zhizhong 1(boratory for Computer Education ,Tsinghua University ,Beijing 100084,China ;2.TheFundamental Industrial Training Center ,Tsinghua University ,Beijing 100084,China )Abstract :This article introduces FP GA 2based CPU called MiniArm ,mainly on its instruction set ,structure and detailed implementation ;discusses the key technology of transplanting uC/OS 2II kernel to MiniArm ,and the detailed process of the implement is introduced ;analyzes the test method and the result of the transplan 2ting ;and finally summarizes the general methods of transplanting operating system to FP GA 2based CPU.K ey w ords :FP GA ;CPU ;uC/OS 2II ;transplantation收稿日期:2009204222基金项目:国家自然科学基金资助(60173010)作者简介:李山山(1979—),男,山东省五莲县人,硕士,工程师,研究方向:计算机系统结构、计算机教学. 近年来,基于FP GA (field programmable gate ar 2ry )的CPU 设计得到了越来越广泛的重视和应用,但对一个完整计算机系统来说,单有硬件CPU 是远远不足的,运行于该CPU 之上的软件系统是不可或缺的,而操作系统是其中最关键的系统软件。
UCOS的移植
需要做的工作
用#define设置一个常量的值(OS_CPU.H) 声明10个数据类型(OS_CPU.H) 用#define声明三个宏(OS_CPU.H) 用C语言编写六个简单的函数(OS_CPU_C.C) 编写四个汇编语言函数(OS_CPU_A.ASM)
所有的移植实例都应放在用户硬盘的\SOFTWARE\µCOS-Ⅱ目录下。各个微处理器 或微控制器的移植源代码必须在以下两个或三个文件中找到:OS_CPU.H, OS_CPU_C.C,OS_CPU_A.ASM。汇编语言文件OS_CPU_A.ASM是可选择的,因 为某些C编译器允许用户在C语言中插入汇编语言,所以用户可以将所需的汇编语言 代码直接放到OS_CPU_C.C中。放置移植实例的目录决定于用户所用的处理器,例 如在下面的表中所示的放置不同移植实例的目录结构。注意,各个目录虽然针对完全 不同的目标处理器,但都包括了相同的文件名。 Intel/AMD 80186\SOFTWARE\uCOS-II\Ix86S \OS_CPU.H \OS_CPU_A.ASM \OS_CPU_C.C \SOFTWARE\uCOS-II\Ix86L \OS_CPU.H \OS_CPU_A.ASM \OS_CPU_C.C Motorola 68HC11\SOFTWARE\uCOS-II\68HC11 \OS_CPU.H \OS_CPU_A.ASM \OS_CPU_C.C
打开/关闭中断
在COS-II中,可以通过: OS_ENTER_CRITICAL() OS_EXIT_CRITICAL() 宏来控制系统关闭或者打开中断。这需 要处理器的支持。 在ARM7TDMI的处理器上,可以设置相应 的寄存器来关闭或者打开系统的所有中断。
处理器支持中断并且能产生定 时中断
uCOS-II的移植及使用
uC/OS-II 概述-性能特点
• 源代码公开 • 可移植(Portable) – 大部分代码用ANSI C写,与处理器无关,移植时不 需修改 – 少量与微处理器硬件相关的部分用C与汇编编写, 移植时需修改:
• OS_CPU.H //与硬件相关,移植时需修改 • OS_CPU_A.ASM //集中了所有与处理器相关的汇编语言 代码 • OS_CPU.C //集中了所有与处理器相关的汇编语言代码
uC/OS-II 概述--文件结构
应用软件 (用户代码) μC/OS-II (与处理器类型无关的代码) μC/OS-II配置文件 (与应用程序有关) OS_CFG.H INCLUDES.H
体系 结构
OS_CORE.C OS_FLAG.C OS_MBOX.C OS_MEM.C OS_MUTEX.C
OS_Q.C OS_SEM.C OS_TASK.C OS_TIME.C uC/OS-II.C uC/OS-II.H
任务控制块就相当于是一个任务的身份证,没 有任务控制块的任务是不能被系统承认和管理 的。
任务控制块的结构
typedef struct os_tcb { OS_STK *OSTCBStkPtr;
//指向当前任务堆栈栈顶的指针。每个任务的堆栈容量可以是任意的。
#if OS_TASK_CREATE_EXT_EN
为了有效的对中断进行控制,在任务的代码里可使用UC/OS-II定义的宏 OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来控制何时响应中断, 何时屏蔽中断。在运行这两个宏之间的代码时是不会响应中断的,这种受保 护的代码段叫临界段。
2.1.2 uC/OS-II的任务—任务控制块(TCB)
uC/OS-II 概述-性能特点
uC_OS和uClinux的比较
任务 , 分别对应优先级 0-63 . 其巾。为班同优先组.调
由薯的话也可自行归入文 件 系统的内窑 .
uCl i nux 则是继承了Li n ux 完誓的文件革统性能 .
IJ!工作的内在可 U 分为两部分 : 最高优先组任务的寻找
和任务j;1J 换 。 其耻而优先捏任务的寻找是通过建立就绪任务农来 实现的 . uC / OS 中的每 - 个任务都有独 立的 推枝空间 ,
2. 3
操作系统的移植
嵌入武操作系统移植的目的是指使操作系统能在某
制的体系例程描 写.
个微扯理器或由控制器上运行 o uC / 05 和luClinux 都是i!. 码公开的操作系统,且其结构化世讨由于把与处理器
•
平台层改的移植 . 如果恃移柏处理器是某种
uC l inux 己主持体系的 处理器,则由要在相关体革结构 目
uClinux 的进程调度世用了 Linu x 的传统 .
很方便地直持间站立件系统且内嵌 TCP / TP 协议 . 这为
6
卑'侃 ~ .. ,、‘·钝A 帽.,.-.
uClinux 开监同站接入世~提供了植和IJ.
其挝怔辑的代码也是特定于备个革统的.这主要在咀
由两种措作系统对立件系统的主持可知
由型较多立件处理的嵌入式军统巾,
理器的特点世讨的 - 种酷作系统 , 具有内嵌间站协皖、
完成简单功能的嵌入式革统 用软件实舰简单的控制环路 ,
的来 l恼 ,
般不需要出作军统,
主持多种立件军统 ,
等优势,
开监者可利用标准 L i n u x 先验知识
虫11 ,以前许多 M CS51 系列 1(1 片机组成的小草就就只是利
Jt 描译后目标文件可控制在儿百 K B :lii辑.
ucosii移植实验报告
一、实验目的●了解uC/OS-II内核的主要结构。
●掌握将uC/OS-II内核移植到Cortex-M3处理器上的基本方法。
二、实验环境与设备●硬件:Cortex-M3嵌入式开发平台、用于Cortex-M3的JTAG仿真器或者内嵌的JTAG仿真器、PC机Pentium100以上。
●软件:PC机操作系统win98、Win2000或WinXP、Keil for ARM或IARfor ARM集成开发环境、仿真器驱动程序、超级终端通讯程序等。
三、预备知识●掌握在Keil for ARM或IAR for ARM集成开发环境中编写和调试程序的基本过程。
●了解Cortex-M3处理器的结构。
●理解uC/OS-II系统结构。
四、实验内容●将uC/OS-II内核移植到Cortex-M3微处理器上。
●编写两个简单任务,在超级终端上观察两个任务的切换。
五、流程图六、实验代码修改后的Os_cpu.h#ifndef OS_CPU_H#define OS_CPU_H#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT#else#define OS_CPU_EXT extern#endiftypedef unsigned char BOOLEAN;typedef unsigned char INT8U; /* Unsigned 8 bit quantity*/typedef signed char INT8S; /* Signed 8 bit quantity */typedef unsigned short INT16U; /* Unsigned 16 bit quantity*/typedef signed short INT16S; /* Signed 16 bit quantity */typedef unsigned int INT32U; /* Unsigned 32 bit quantity */typedef signed int INT32S; /* Signed 32 bit quantity */typedef float FP32; /* Single precision floating point*/typedef double FP64; /* Double precision floating point */typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide */typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */#define OS_CRITICAL_METHOD 3u#if OS_CRITICAL_METHOD == 3u#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}#endif#define OS_STK_GROWTH 1u /* Stack grows from HIGH to LOW memory on ARM */#define OS_TASK_SW() OSCtxSw()#if OS_CRITICAL_METHOD == 3u /* See OS_CPU_A.ASM */OS_CPU_SR OS_CPU_SR_Save(void);void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);#endifvoid OSCtxSw(void);void OSIntCtxSw(void);void OSStartHighRdy(void);void OSPendSV(void);#endif修改后的Os_cpu_c.c#define OS_CPU_GLOBALS#include <ucos_ii.h>#include <includes.h>#if OS_TMR_EN > 0ustatic INT16U OSTmrCtr;#endif#if OS_CPU_HOOKS_EN > 0uvoid OSInitHookBegin (void){#if OS_TMR_EN > 0uOSTmrCtr = 0u;#endif}#endif#if OS_CPU_HOOKS_EN > 0uvoid OSInitHookEnd (void){}#endif#if OS_CPU_HOOKS_EN > 0uvoid OSTaskCreateHook (OS_TCB *ptcb){#if OS_APP_HOOKS_EN > 0uApp_TaskCreateHook(ptcb);#else(void)ptcb; /* Prevent compiler warning */#endif}#endif#if OS_CPU_HOOKS_EN > 0uvoid OSTaskDelHook (OS_TCB *ptcb){#if OS_APP_HOOKS_EN > 0uApp_TaskDelHook(ptcb);#else(void)ptcb; /* Prevent compiler warning */#endif}#endif#if OS_CPU_HOOKS_EN > 0uvoid OSTaskIdleHook (void){#if OS_APP_HOOKS_EN > 0uApp_TaskIdleHook();#endif}#endif#if OS_CPU_HOOKS_EN > 0uvoid OSTaskStatHook (void){#if OS_APP_HOOKS_EN > 0uApp_TaskStatHook();#endif}#endifOS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt){OS_STK *stk;(void)opt; /* 'opt' is not used, prevent warning*/stk = ptos; /* Load stack pointer *//* Registers stacked as if auto-saved on exception */*(stk) = (INT32U)0x01000000uL; /* xPSR */*(--stk)= (INT32U)task; /* Entry Point */*(--stk)= (INT32U)0xFFFFFFFEL; /* R14 (LR) (init value will *//* cause fault if ever used) */ *(--stk)= (INT32U)0x12121212uL;/* R12*/*(--stk)= (INT32U)0x03030303uL; /* R3 */*(--stk)= (INT32U)0x02020202uL /* R2 */*(--stk)=(INT32U)0x01010101uL; /* R1 */*(--stk)=(INT32U)p_arg; /* R0 : argument *//* Remaining registers saved on process stack */*(--stk)=(INT32U)0x11111111uL; /* R11 */*(--stk)=(INT32U)0x10101010uL; /* R10 */*(--stk)=(INT32U)0x09090909uL; /* R9 */*(--stk)=(INT32U)0x08080808uL; /* R8 */*(--stk)=(INT32U)0x07070707uL; /* R7 */*(--stk)=(INT32U)0x06060606uL; /* R6 */*(--stk)=(INT32U)0x05050505uL; /* R5 */*(--stk)=(INT32U)0x04040404uL; /* R4 */return (stk);}#if (OS_CPU_HOOKS_EN > 0u) && (OS_TASK_SW_HOOK_EN > 0u)void OSTaskSwHook (void){#if OS_APP_HOOKS_EN > 0uApp_TaskSwHook();#endif}#endif#if OS_CPU_HOOKS_EN > 0uvoid OSTCBInitHook (OS_TCB *ptcb){#if OS_APP_HOOKS_EN > 0uApp_TCBInitHook(ptcb);#else(void)ptcb; /* Prevent compiler warning */#endif}#endif#if (OS_CPU_HOOKS_EN > 0u) && (OS_TIME_TICK_HOOK_EN > 0u)void OSTimeTickHook (void){#if OS_APP_HOOKS_EN > 0uApp_TimeTickHook();#endif#if OS_TMR_EN > 0uOSTmrCtr++;if (OSTmrCtr >= (OS_TICKS_PER_SEC / OS_TMR_CFG_TICKS_PER_SEC)) { OSTmrCtr = 0;OSTmrSignal();}#endif}#endif修改后的Os_cpu_a.asmEXTERN OSRunningEXTERN OSPrioCurEXTERN OSPrioHighRdyEXTERN OSTCBCurEXTERN OSTCBHighRdyEXTERN OSIntExitEXTERN OSTaskSwHookEXPORT OS_CPU_SR_SaveEXPORT OS_CPU_SR_RestoreEXPORT OSStartHighRdyEXPORT OSCtxSwEXPORT OSIntCtxSwEXPORT OSPendSVNVIC_INT_CTRL EQU 0xE000ED04; Interrupt control state register.NVIC_SYSPRI14 EQU 0xE000ED22 System priority register (priority 14).NVIC_PENDSV_PRI EQU 0xFF; PendSV priority value (lowest).NVIC_PENDSVSET EQU 0x10000000; Value to trigger PendSV exception.PRESERVE8 ;The AAPCS requires that the stack-pointer be 8-byte aligned on entry to a conforming function.AREA UCOSII_ASM, CODE, READONLY THUMBOS_CPU_SR_SaveMRS R0, PRIMASK ; Set prio int mask to mask all (except faults)CPSID IBX LROS_CPU_SR_RestoreMSR PRIMASK, R0BX LROSStartHighRdyLDR R0, =NVIC_SYSPRI14; Set the PendSV exception priorityLDR R1, =NVIC_PENDSV_PRISTRB R1, [R0]MOV R0, #; Set the PSP to 0 for initial context switch callMSR PSP, R0LDR R0, =OSRunning ; OSRunning = TRUEMOV R1, #1STRB R1, [R0]LDR R0, =NVIC_INT_CTRL; Trigger the PendSV exception (causes context switch)LDR R1, =NVIC_PENDSVSETSTR R1, [R0]CPSIE I ; Enable interrupts at processor levelOSStartHangB OSStartHang; Should never get hereOSCtxSwLDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)LDR R1, =NVIC_PENDSVSETSTR R1, [R0]BX LROSIntCtxSwLDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)LDR R1, =NVIC_PENDSVSETSTR R1, [R0]BX LROSPendSVCPSID I ; Prevent interruption during context switchMRS R0, PSP ; PSP is process stack pointerCBZ R0, OSPendSV_nosave ; Skip register save the first timeSUB R0, R0, #0x20 ; Save remaining regs r4-11 on process stackSTM R0, {R4-R11}LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;LDR R1, [R1]STR R0, [R1] ; R0 is SP of process being switched out; At this point, entire context of process has been savedOSPendSV_nosavePUSH {R14} ; Save LR exc_return valueLDR R0, =OSTaskSwHook; OSTaskSwHook();BLX R0POP {R14}LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;LDR R1, =OSPrioHighRdyLDRB R2, [R1]STRB R2, [R0]LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;LDR R1, =OSTCBHighRdyLDR R2, [R1]STR R2, [R0]LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; LDM R0, {R4-R11}; Restore r4-11 from new process stackADDS R0, R0, #0x20MSR PSP, R0; Load PSP with new process SPORR LR, LR, #0x04 Ensure exception return uses process stackCPSIE IBX LR ; Exception return will restore remaining context ALIG主函数APP.C#include<includes.h>#include "utils/uartstdio.h"#include "lwip/sys.h"#define TASK1_PRIO 11#define TASK2_PRIO 3#define task1stck 1024#define task2stck 1024#include "systemInit.h"#define LED_PERIPH SYSCTL_PERIPH_GPIOF#define LED_PORT GPIO_PORTF_BASE#define LED_PIN GPIO_PIN_2#define LED_PINN GPIO_PIN_3void LED0_stack(void *p_arg){//jtagWait( );clockInit( );SysCtlPeriEnable(LED_PERIPH);GPIOPinTypeOut(LED_PORT, LED_PIN);for (;;){GPIOPinWrite(LED_PORT, LED_PIN, 0x00);OSTimeDly(OS_TICKS_PER_SEC / 4);GPIOPinWrite(LED_PORT, LED_PIN, 0xFF);OSTimeDly(OS_TICKS_PER_SEC / 4);}}void LED1_stack(void *p_arg){//jtagWait( );clockInit( );SysCtlPeriEnable(LED_PERIPH);GPIOPinTypeOut(LED_PORT, LED_PINN);for (;;){GPIOPinWrite(LED_PORT, LED_PINN, 0x00);OSTimeDly(OS_TICKS_PER_SEC / 4);zGPIOPinWrite(LED_PORT, LED_PINN, 0xFF);OSTimeDly(OS_TICKS_PER_SEC / 4);}}static void App_TaskStart (void *p_arg);int main (void){BSP_PreInit ();BSP_IntDisAll();OSInit();OSTaskCreateExt((void (*)(void *)) App_TaskStart,(void *) 0,(OS_STK *)&App_TaskStartStk[APP_CFG_TASK_START_STK_SIZE - 1], (INT8U ) APP_CFG_TASK_START_PRIO,(INT16U ) APP_CFG_TASK_START_PRIO,(OS_STK *)&App_TaskStartStk[0],(INT32U ) APP_CFG_TASK_START_STK_SIZE,(void *) 0,(INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));OSTaskCreate(LED0_stack,(void *)0,&App_TaskStartStk1[ APP_CFG_TASK_START_STK_SIZE -1],0);OSTaskCreate(LED1_stack,(void *)0,&App_TaskStartStk2[ APP_CFG_TASK_START_STK_SIZE -1],1);OSStart(); //4 os start}static void App_TaskStart (void *p_arg){(void)p_arg;BSP_PostInit();Tmr_TickInit ();#if (OS_TASK_STAT_EN > 0)OSStatInit(); #endiffor(;;){OSTimeDlyHMSM(0, 0, 2, 0); UARTprintf("\033[2JI am task1\n");}}。
UC/OS-Ⅱ操作系统在ARM处理器上的移植
UC/OS-Ⅱ操作系统在ARM处理器上的移植
朱华均
【期刊名称】《计算机工程》
【年(卷),期】2004(30)B12
【摘要】基于ARM处理器在设计时本身固有的硬件体系结构特点,使其对各操作系统的运行给予最充分的硬件支持。
该文论述了UC/OS-Ⅱ在ARM处理器上的移植方法和在移植过程中涉及的基本问题,以及由ARM处理器的七种模式所带来的移植问题。
【总页数】3页(P64-65,124)
【作者】朱华均
【作者单位】上海交通大学软件学院,上海200030
【正文语种】中文
【中图分类】TP316
【相关文献】
1.实时操作系统μC/OS-Ⅱ在ARM处理器LPC2104上的移植 [J], 刘迪
2.UC/OS-Ⅱ操作系统在ARM处理器上的移植 [J], 朱华均
3.μC/OS-Ⅱ操作系统在ARM处理器上的移植 [J], 王秀丽;麦继平
4.uc/OS-Ⅱ在ARM处理器上的移植 [J], 蒋利军;陈庆荣
5.μC/OS-Ⅱ嵌入式实时操作系统面向ARM处理器的移植 [J], 李娜;夏靖波;王航;冯奎胜
因版权原因,仅展示原文概要,查看原文内容请购买。
uCOS-II在arm上的移植
总结一下移植中浪费我时间的几个小错误吧,这完全是个人粗心导致的失误:
1、在os_cpu.h文件中需要用宏定义将OS_TASK_SW指向OSCtxSw函数,而我开始像以前一样直接将OSCtxSw函数与0号软终端链接起来,结果发现函数调用不成功。后来直接用宏定义将OS_TASK_SW define为OSCtxSw函数,初步调试通过,即验证OSCtxSw函数正确,但是到后来调用任务的时候却发现任务切换不正常,不得不重新将函数与中断结合起来,当然就不能还是0号中断了,而是改为一个比较保险的软终端,这个问题纠结了很长时间。
2)数据堆栈;
c51中,由于我们使用OS,采用的LARGE编译模式,所以数据堆栈的指针是“?C_XBP”, 栈的生长方向是向下的,栈空间分配在51的外部RAM(xdata)中。
3)C51中断中堆栈的保护;
研究中断中堆栈的保护的意义在于,因为uCOS中的任务切换,本身就是模拟一次中断的发生:保护Task1的CPU寄存器,SP切换到Task2的堆栈,弹出Task2的CPU寄存器。用C51写中断函数的时候,编译器会自动保护CPU的寄存器,所以中断返回时任务调度OSIntCtxSw(),就不用重新保护寄存器。
实时系统和前/后台系统;
前/后台系统:一个大循环,循环查询各种标志位。如果标志位置位,就执行相应的服务程序。标志位就是标志事件的发生,事件响应延时处于不可预测状态。最坏的情况是循环中所有其他的事件服务程序执行完,才响应当前事件。中断服务虽然能即时/优先响应,但是它们和主循环的通讯,也是通过置主循环中相应的标志位来完成的。
我主要想讲一下自己最近移植uCOS-II的心得,因为最近也在学习操作系统,所以这段日子对于uCOS-II的学习的确也让我对于操作系统有了一个实际深刻的认识。
uCOS-II嵌入式操作系统介绍与移植
OSStartHighRd
1、该函数是在OSStart函数中调用 2、负责从最高优先级任务的TCB中获得该任务的堆
栈指针sp,并依次将cpu现场恢复,这时系统就将 控制权交给用户创建的该任务进程,直到该任务被 阻塞或者被其他更高优先级的任务抢占cpu 3、该函数仅在多任务启动时被执行一次,用来启 动之前创建的第一个,也就是最高优先级的任务执 行
3、可从网站上获 得全部源码及其在各种体系结构平 台上的移植范例。
uC/OS-II特点
1、uC/OS-II内核具有可抢占的实时 多任务调度功能
2、提供了许多系统服务,如信号量、 消息队列、邮箱、内存管理、时间 函数等
3、这些功能可以根据不同的需求进 行裁减。
uC/OS-II的移植
ARM处理器相关宏定义
1、退出临界区
#defineOS_ENTER_CRITICAL() ARMDisableInt()
2、进入临界区
#defineOS_EXIT_CRITICAL() ARMEnableInt()
堆栈增长方向
1、堆栈由高地址向低地址增长,这个也 是和编译器有关的,当进行函数调用时, 入口参数和返回地址一般都会保存在当 前任务的堆栈中,编译器的编译选项和 由此生成的堆栈指令就会决定堆栈的增 长方向。
#define OS_STK_GROWTH 1
OS_CPU.c的移植
1、任务堆栈初始化 2、系统hook函数 3、中断级任务切换函数
任务堆栈初始化OSTaskStkInit
1、由OSTaskCreate或OSTaskCreateExt调用 2、用来初始化任务的堆栈并返回新的堆栈指针stk。
退出/进入临界区函数 ARMDisableInt/ARMEnableInt
基于Cortex_M3处理器的uC_OS_移植方法的研究_王宜结
基于Cortex-M3处理器的uC/OS-II移植方法的研究王宜结(淮南师范学院电气信息工程学院,安徽淮南232038)[摘要]Cortex-M3是ARM 公司2006年推出的第一款Cortex 处理器,主要针对32位微控制器市场设计的,性能优越。
uC/OS-II 是美国Jean brosse 设计的一款基于优先级的抢占式实时多任务操作系统,绝大部分代码是用高可移植性的ANSI C 编写,与目标处理器相关的代码用汇编语言编写。
详细剖析了把uC/OS-II 移植到Cortex-M3处理器的方法。
[关键词]Cortex-M3;uC/OS-II;操作系统移植[中图分类号]TP311[文献标识码]A [文章编号]1009-9530(2012)05-0117-031引言随着应用系统复杂程度的不断提高,程序编制也变得越来越难控制。
解决复杂问题的最好办法就把它分解成一个个相对简单的问题,即一个个单独的任务,分而治之。
UC/OS-II 是一个实时多任务操作系统,因其短小精悍又源代码开放,在一些小型系统中得到了较广泛的应用。
在MCU 上加载uC/OS-II 操作系统,再对每个问题编写相应的任务代码,就可以实现复杂的控制和应用。
2UC /OS-II 简介uC/OS-II 是基于优先级的抢占式实时多任务操作系统,最多可管理64个任务,可固化,可剪裁,具体高稳定性和可靠性。
它包含了实时内核、任务管理、时间管理、任务间通信同步(信号量,邮箱,消息队列)和内存管理等功能。
绝大部分代码用C 语言写成,与硬件相关部分用汇编语言编写,最鲜明的特点是源代码是公开免费的,便于移植和维护。
uC/OS-II 是面向中小型嵌入式系统的,包含全部功能模块的内核大约为10KB ,如果经过裁减只保留核心代码,则可压缩到3KB 左右。
RAM 的占用量与系统中的任务数及堆栈空间大小有关,堆栈的大小取决于任务的局部变量、缓冲区大小及可能的中断嵌套层数。
TMS320F28335的uC-OSⅡ移植
TMS320F28335的uC-OSⅡ移植TMS320F28335的uC-OSⅡ移植1、 uC-OSII 的原理uC-OSII 包括任务调度、时间管理、内存管理、资源管理(信号量、邮箱、消息队列)四大部分,没有文件系统、网络接口、输入输出界面。
它的移植只与4 个文件相关:汇编文件(OS_CPU_A.ASM)、处理器相关C 文件(OS_CPU.H、OS_CPU_C.C)和配置文件(OS_C FG.H)。
有64 个优先级,系统占用8 个,用户可创建56 个任务,不支持时间片轮转。
它的基本思路就是“近似地每时每刻总是让优先级最高的就绪任务处于运行状态”。
为了保证这一点,它在调用系统API 函数、中断结束、定时中断结束时总是执行调度算法。
原作者通过事先计算好数据,简化了运算量,通过精心设计就绪表结构,使得延时可预知。
任务的切换是通过模拟一次中断实现的。
uC-OSII 工作核心原理是:近似地让最高优先级的就绪任务处于运行状态。
操作系统将在下面情况中进行任务调度:调用API 函数( 用户主动调用), 中断( 系统占用的时间片中断OsTimeTick(),用户使用的中断)。
其整体整体思路如下。
(1)、在调用API 函数时,有可能引起阻塞,如果系统API 函数察觉到运行条件不满足,需要切换就调用OSSched()调度函数,这个过程是系统自动完成的,用户没有参与。
OSSched()判断是否切换,如果需要切换,则此函数调用OS_TASK_SW()。
这个函数模拟一次中断,好象程序被中断打断了,其实是OS 故意制造的假象,目的是为了任务切换。
既然是中断,那么返回地址(即紧邻OS_TASK_SW()的下一条汇编指令的PC 地址)就被自动压入堆栈,接着在中断程序里保存CPU寄存器(PUSHALL)……。
堆栈结构不是任意的,而是严格按照uC-OSII 规范处理的。
OS 每次切换都会保存和恢复全部现场信息(POPALL),然后用RETI 回到任务断点继续执行。
UCOSIIAVR移植全过程及心得
UCOSII AVR移植全过程及心得经过近一个星期的战斗,现在的ucosii终于成功的移植到了AVR单片机上,我发过帖子,觉得还是有很多朋友对这个比较感兴趣的,所以我把我记录的移植全过程及一些心得写出来与大家分享。
出于兴趣,本人也想再A VR单片机上跑个操作系统玩玩,大家都知道,对于这样的单片机而言,ucosii 当然是首选。
听说网上有现成的范例,偶用力搜搜搜,嘿嘿,结果搜到了两个例子,一个是8515的,另一个是103的,陶醉中…赶紧打开ICCAvr,编译…. Faint,出了一大堆错误,修改了半天也没弄好,没办法,还是自己移植吧。
先是买了邵贝贝翻译的那本第二版的书,躲在宿舍看了整整两天,先是完整的看一遍,从封面到封底,除80 86移植范例外一字不漏,嘿嘿,发现我看得时候基本都明白,看完了好像都忘的差不多了:(,不过没关系,关键是移植嘛,对操作系统的运行原理有一些感性认识就可以了;好,现在开始专攻移植部分,又仔细的看了一遍第13章。
准备工作做好了接下来开始动手!ucos的任务调度机制网上有很多“专著”,我就不罗嗦了,其移植原理也比较简单,主要就是寄存器的保护合恢复。
需要改写的有4个文件,OS_CPU.h,OS_CPU.c,OS_CPU_asm.s,OS_ CFG.h, 再这里合理的设计这些contex的结构是很关键的一步。
需要修改的函数主要有一个C函数OSTaskStkInit();和4个汇编函数,OSStartHighRdy();OSCtxSw();OSIntCtxS w();OSTickISR();一、误入歧途这是我开始设计的contex结构:OSTCB->SP——> |_________| SREG| R0| R1………….| R27| R30|___ R31____根据这样的结构,相应的移植程序如下:OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt){INT8U *stk;INT8U i;INT16U temp;opt = opt; /* 'opt' is not used, prevent warning */stk = (INT8U *)ptos; /* Load stack pointer */temp=(unsigned int)task;temp=*(const unsigned int*)temp; //////////////////////////////*stk-- =(unsigned char)(temp&0xff); //save PC low*stk--=(unsigned char)(temp>>8); //Pc highfor(i=0;i<12;i++) //32 General Purpose Registers{ //Form R31R30,R27 to R18*stk-- = 0;}*stk-- =(unsigned char)((unsigned int )pdata>>8); //pdata saves in R6,R17*stk-- =(unsigned char)((unsigned int)pdata&0xff);for(i=0;i<16;i++){*stk--=0; //From R15 to R0}*stk-- = 0x80; //SREG initial value,Interrupt opened.return ((OS_STK *)stk);}#define PUSH_R() asm("PUSH R31"); asm("PUSH R30"); asm("PUSH R27"); asm("PUSH R26"); asm("PUS H R25"); asm("PUSH R24"); asm("PUSH R23"); asm("PUSH R22"); asm("PUSH R21"); asm("PUSH R20"); asm("PUSH R19"); asm("PUSH R18"); asm("PUSH R17"); asm("PUSH R16"); asm("PUSH R15"); asm("P USH R14"); asm("PUSH R13"); asm("PUSH R12"); asm("PUSH R11"); asm("PUSH R10"); asm("PUSH R9 "); asm("PUSH R8"); asm("PUSH R7"); asm("PUSH R6"); asm("PUSH R5"); asm("PUSH R4"); asm("PUSH R3"); asm("PUSH R2"); asm("PUSH R1"); asm("PUSH R0")#define POP_R() asm("POP R0"); asm("POP R1"); asm("POP R2"); asm("POP R3"); asm("POP R4"); asm(" POP R5"); asm("POP R6"); asm("POP R7"); asm("POP R8"); asm("POP R9"); asm("POP R10"); asm("POP R11"); asm("POP R12"); asm("POP R13"); asm("POP R14"); asm("POP R15"); asm("POP R16"); asm("POP R17"); asm("POP R18"); asm("POP R19"); asm("POP R20"); asm("POP R21"); asm("POP R22"); asm("POP R23"); asm("POP R24"); asm("POP R25"); asm("POP R26"); asm("POP R27"); asm("POP R30"); asm("PO P R31")void OSStartHighRdy(void){unsigned char *stk_temp,*pdest;//The Middle SP V ariableunsigned char s0,s1;OSTaskSwHook();OSRunning=1; //set flagstk_temp=OSTCBHighRdy->OSTCBStkPtr;s0=(unsigned char)((unsigned int)stk_temp&0xff); //sp low 8bits1=(unsigned char)((unsigned int)stk_temp>>8); //sp high 8bitasm("OUT 0x3d, %s0\n""OUT 0x3e, %s1");asm("POP R0\n" //Restore SREG"OUT 0x3f, R0");POP_R(); //Restore R0--R31}/***************************************************/void OSCtxSw(void){unsigned char i,j;unsigned char *psrc,*next_sp;unsigned int temp;PUSH_R(); //save R31--R0asm("IN R0, 0x3f\n""PUSH R0"); //save SREGasm("IN %i, 0x3d\n""IN %j, 0x3e");temp=(j<<8)+i;OSTCBCur->OSTCBStkPtr=(unsigned char*)temp; //SA VE current task sp in TCBcur OSTaskSwHook();OSTCBCur=OSTCBHighRdy;OSPrioCur=OSPrioHighRdy;next_sp=OSTCBHighRdy->OSTCBStkPtr;i=(unsigned char)((unsigned int)next_sp&0xff);j=(unsigned char)((unsigned int)next_sp>>8);asm("OUT 0x3d, %i\n"//Get sp"OUT 0x3e,%j" );asm("POP %i \n" /////////Restore SREG"OUT 0x3f,%i" );POP_R(); ///////////Restore R}void OSIntCtxSw(void){unsigned char i,j;unsigned char*next_sp;OSTaskSwHook();OSTCBCur=OSTCBHighRdy;OSPrioCur=OSPrioHighRdy;next_sp=OSTCBHighRdy->OSTCBStkPtr;i=(unsigned char)((unsigned int)next_sp&0xff);j=(unsigned char)((unsigned int)next_sp>>8);asm("OUT 0x3d, %i\n"//Get sp"OUT 0x3e,%j" );asm("POP %i \n" /////////Restore SREG"OUT 0x3f,%i" );POP_R(); ///////////Restore R}/*************************************************/#pragma interrupt_handler OSTickISR:TIMER_INT_VECTOR#pragma ctask OSTickISRvoid OSTickISR(void){unsigned char i,j;unsigned int sptemp;PUSH_R(); //save R31--R0TCNT0 = 0xb2; //reload counter valueasm("IN R0, 0x3f\n""PUSH R0"); //save SREG///i=j=0; This is used ONLY TO AVOID THE W ARNING.OSIntNesting++;asm("IN %i,0x3d\n" //Get SP V alue"IN %j,0x3e");sptemp=(j<<8)+i;if(OSIntNesting==1){OSTCBCur->OSTCBStkPtr=(unsigned char*)sptemp;}OSTimeTick();OSIntExit();asm("POP %i\n" //Restore SREG"OUT 0x3f, %i");POP_R(); //Restore R0--R31}我写了个测试程序:其中自己建立了两个任务,LED()用于控制数码管的亮与暗,key_scan()用与判断是否按下了PA0,为了调试程序的方便,没有用OS提供的通讯机制,直接用了一个全局变量key_press;再任务k ey_scan里,当检测到按键按下时设置key_press=1,否则设置为0;而任务LED()则根据key_press的值控制L ED的亮与暗。
uCOS51移植心得
uCOS51 移植心得讨论1----uCOS51 高效内核前一段时间我参与了一个SNMP 网管板的项目我负责硬件设计和单板软件开发该板的硬件由MCS51+RTL8019AS 组成有64K FLASH 和64K SRAM 软件部分有操作系统和TCPIP 协议栈硬件比较简单用了一个月就搞定了协议栈我参考了老古开发板的部分程序又上网找了SNMP 源代码也很快完成了但是测试时发现当使用较低时钟频率的CPU 时为了降低成本由于ASN.1 编解码部分过于庞大而我的程序又是一个大循环AGENT 的响应速度受到严重影响用户界面也反应迟钝更坏的消息是公司为了适应市场需求还要在上面跑PPP 和HTTP 那样的话我就得用40MHz 的AT89C51RD2 或者人为的把程序断成几部分然后用状态机的方法在运行时再把它们连接起来不过我不想增加成本也不想把程序搞乱迫不得已只好使用操作系统说实在的一开始我也不是很有把握一来我不清楚51 的FLASH 是否装得下这么多代码二来我只做过OS 应用开发对于它的移植想都不敢想不过我在BBS 上搜索了一阵儿后还是有了一些头绪我找到了几个OS 的源代码我喜欢用现成的按照代码大小实时性使用人数众人口碑等标准最后选定了uCOS2 我感觉它的实时性有保障延时可预测代码据说可小到2K 网上讨论这个话题的人也比较多而且它的网站上有针对KEIL C51 的移植实例经过一番查找我得到了5 个版本其中3 个是用KEIL 编译的本来我想直接把OS代码嵌到应用程序中但后来发现没有一个可以直接使用有的无法用KEIL 直接编译有的需要修改DLL 在软件仿真下使用而我需要的是能在串口输入输出不需要修改任何无关软件能在软件仿真和硬件上运行的实时多任务操作系统没有办法我只好硬着头皮去改编我分析了自己的劣势1 KEIL 刚开始使用不太熟悉2 混合编程以前从没有作过3 时间紧迫要在1 个月内搞定而我的优势就是有5 个移植实例可供参考可以上网查资料一开始我用堆栈混合编程汇编ucos 等关键字在C51BBS 和老古论坛上检索相关信息并逐条阅读读过之后头脑中的思路逐渐清晰了我了解到在KEIL 的HLP 目录下有A51.PDF 和C51.PDF 非常全面的介绍了汇编和C51 是KEIL 的权威用户手册SP 初始化内存清0 等操作在STARTUP.A51 文件中实现用户可以改写它KEIL 的变量子程序等的分配信息可以在.M51 文件里查到KEIL 自己的论坛里有很多疑难问题的解答通过阅读并经过思考解决了堆栈起点堆栈空间大小的设定等关键问题论坛里的问题有些是我没有想到的这使我发现了自己的疏漏在网上获得大量信息后我开始阅读uCOSII 中文版一共读了3 遍第一遍是浏览了解到uCOSII 包括任务调度时间管理内存管理资源管理信号量邮箱消息队列四大部分没有文件系统网络接口输入输出界面它的移植只与 4 个文件相关汇编文件OS_CPU_A.ASM 处理器相关C 文件OS_CPU.H OS_CPU_C.C 和配置文件OS_CFG.H 有64 个优先级系统占用8 个用户可创建56 个任务不支持时间片轮转第二遍主要是把整个工作过程在头脑里过了一下不懂的地方有针对性地查书重点是思考工作原理和流程我发现其实它的思路挺简单的就是近似地每时每刻总是让优先级最高的就绪任务处于运行状态为了保证这一点它在调用系统API 函数中断结束定时中断结束时总是执行调度算法原作者通过事先计算好数据简化了运算量通过精心设计就绪表结构使得延时可预知任务的切换是通过模拟一次中断实现的第三遍重点看了移植部分的内容对照实例研究了代码的具体实现方法前期准备用了20 几天真正编写代码只用了1.5 天调试用了2 天具体过程如下(1)拷贝书后附赠光盘sourcecode 目录下的内容到C:\YY 下删除不必要的文件和EX1L.C 只剩下p187( uCOSII )上列出的文件(2)改写最简单的OS_CPU.H数据类型的设定见C51.PDF 第176 页注意BOOLEAN 要定义成unsigned char 类型因为bit类型为C51 特有不能用在结构体里EA=0 关中断EA=1 开中断这样定义即减少了程序行数又避免了退出临界区后关中断造成的死机MCS-51 堆栈从下往上增长(1=向下0=向上) OS_STK_GROWTH 定义为0#define OS_TASK_SW() OSCtxSw() 因为MCS-51 没有软中断指令所以用程序调用代替两者的堆栈格式相同RETI 指令复位中断系统RET 则没有实践表明对于MCS-51 用子程序调用入栈用中断返回指令RETI 出栈是没有问题的反之中断入栈RET出栈则不行总之对于入栈子程序调用与中断调用效果是一样的可以混用在没有中断发生的情况下复位中断系统也不会影响系统正常运行详见uC/OS-II 第八章193 页第12 行(3)改写OS_CPU_C.CTCB 结构体中OSTCBStkPtr 总是指向用户堆栈最低地址该地址空间内存放用户堆栈长度其上空间存放系统堆栈映像即用户堆栈空间大小=系统堆栈空间大小+1SP 总是先加1 再存数据因此SP 初始时指向系统堆栈起始地址(OSStack)减 1 处(OSStkStart) 很明显系统堆栈存储空间大小=SP-OSStkStart任务切换时先保存当前任务堆栈内容方法是用SP-OSStkStart 得出保存字节数将其写入用户堆栈最低地址内以用户堆栈最低地址为起址以OSStkStart 为系统堆栈起址由系统栈向用户栈拷贝数据循环SP-OSStkStart 次每次拷贝前先将各自栈指针增1其次恢复最高优先级任务系统堆栈方法是获得最高优先级任务用户堆栈最低地址从中取出长度以最高优先级任务用户堆栈最低地址为起址以OSStkStart 为系统堆栈起址由用户栈向系统栈拷贝数据循环长度数值指示的次数每次拷贝前先将各自栈指针增1用户堆栈初始化时从下向上依次保存用户堆栈长度15 PCL PCH PSWACC B DPL DPH R0 R1 R2 R3 R4 R5 R6 R7 不保存SP 任务切换时根据用户堆栈长度计算得出OSTaskStkInit 函数总是返回用户栈最低地址操作系统tick 时钟我使用了51 单片机的T0 定时器它的初始化代码用C 写在了本文件中最后还有几点必须注意的事项本来原则上我们不用修改与处理器无关的代码但是由于KEIL 编译器的特殊性这些代码仍要多处改动因为KEIL 缺省情况下编译的代码不可重入而多任务系统要求并发操作导致重入所以要在每个 C 函数及其声明后标注reentrant 关键字另外pdata data 在uCOS 中用做一些函数的形参但它同时又是KEIL 的关键字会导致编译错误我通过把pdata 改成ppdata data 改成ddata解决了此问题OSTCBCur OSTCBHighRdy OSRunning OSPrioCur OSPrioHighRdy 这几个变量在汇编程序中用到了为了使用Ri 访问而不用DPTR 应该用KEIL 扩展关键字IDATA 将它们定义在内部RAM 中(4)重写OS_CPU_A.ASMA51 宏汇编的大致结构如下NAME 模块名;与文件名无关;定义重定位段必须按照C51 格式定义汇编遵守C51 规范段名格式为?PR?函数名?模块名;声明引用全局变量和外部子程序注意关键字为EXTRN 没有E全局变量名直接引用无参数/无寄存器参数函数FUNC带寄存器参数函数_FUNC重入函数_?FUNC;分配堆栈空间只关心大小堆栈起点由keil 决定通过标号可以获得keil 分配的SP 起点切莫自己分配堆栈起点只要用DS 通知KEIL 预留堆栈空间即可?STACK段名与STARTUP.A51 中的段名相同这意味着KEIL 在LINK 时将把两个同名段拼在一起我预留了40H 个字节STARTUP.A51 预留了1 个字节LINK 完成后堆栈段总长为41H 查看yy.m51 知KEIL 将堆栈起点定在21H 长度41H 处于内部RAM 中;定义宏宏名MACRO 实体ENDM;子程序OSStartHighRdyOSCtxSwOSIntCtxSwOSTickISRSerialISREND ;声明汇编源文件结束一般指针占3 字节+0 类型+1 高8 位数据+2 低8 位数据详见C51.PDF 第178 页低位地址存高8 位值高位地址存低8 位值例如0x1234 基址+0:0x12 基址+1:0x34(5)移植串口驱动程序在此之前我写过基于中断的串口驱动程序包括打印字节/字/长字/字符串读串口初始化串口/缓冲区把它改成重入函数即可直接使用系统提供的显示函数是并发的它不是直接显示到串口而是先输出到显存用户不必担心IO 慢速操作影响程序运行串口输入也采用了同样的技术他使得用户在CPU 忙于处理其他任务时照样可以盲打输入命令(6)编写测试程序Demo(YY.C)Demo 程序创建了3 个任务A B C 优先级分别为2 3 4 A 每秒显示一次B每3 秒显示一次C 每6 秒显示一次从显示结果看显示3 个A 后显示1 个B 显示6个A 和2 个B 后显示1 个C 结果显然正确显示结果如下AAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeAAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeCCCCCC666666 is activeAAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeAAAAAA111111 is activeAAAAAA111111 is activeAAAAAA111111 is activeBBBBBB333333 is activeCCCCCC666666 is activeDemo 程序经Keil701 编译后代码量为7-8K 可直接在KeilC51 上仿真运行编译时要将OS_CPU_C.C UCOS_II.C OS_CPU_A.ASM YY.C 加入项目以上是我这次移植uCOS51 的一些心得写出来只是让准备在51 上运行操作系统的同行们少走弯路并增强使用信心我强烈推荐大家在自己的51 系统中使用uCOS 这个简单实用的自己的操作系统它的大小应该不是问题性能上的提高却是显著的但愿此文能对朋友们有所帮助错误在所难免希望各位大虾指正诸位高手们见笑了注全部源码可来信索要(asdjf@) 以下仅为关键代码部分文件名: OS_CPU_A.ASM$NOMOD51EA BIT 0A8H.7SP DA TA 081HB DA TA 0F0HACC DATA 0E0HDPH DA TA 083HDPL DATA 082HPSW DA TA 0D0HTR0 BIT 088H.4TH0 DATA 08CHTL0 DATA 08AHNAME OS_CPU_A ;模块名;定义重定位段?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE?PR?OSCtxSw?OS_CPU_A SEGMENT CODE?PR?OSIntCtxSw?OS_CPU_A SEGMENT CODE?PR?OSTickISR?OS_CPU_A SEGMENT CODE?PR?_?serial?OS_CPU_A SEGMENT CODE;声明引用全局变量和外部子程序EXTRN IDATA (OSTCBCur)EXTRN IDATA (OSTCBHighRdy)EXTRN IDATA (OSRunning)EXTRN IDATA (OSPrioCur)EXTRN IDATA (OSPrioHighRdy)EXTRN CODE (_?OSTaskSwHook)EXTRN CODE (_?serial)EXTRN CODE (_?OSIntEnter)EXTRN CODE (_?OSIntExit)EXTRN CODE (_?OSTimeTick);对外声明4 个不可重入函数PUBLIC OSStartHighRdyPUBLIC OSCtxSwPUBLIC OSIntCtxSwPUBLIC OSTickISR;PUBLIC SerialISR;分配堆栈空间只关心大小堆栈起点由keil 决定通过标号可以获得keil 分配的SP 起点?STACK SEGMENT IDATARSEG ?STACKDS 40HOSStkStart IDATA OSStack-1;定义压栈出栈宏PUSHALL MACROPUSH PSWPUSH ACCPUSH BPUSH DPLPUSH DPHMOV A,R0 ;R0-R7 入栈PUSH ACCMOV A,R1PUSH ACCMOV A,R2PUSH ACCMOV A,R3PUSH ACCMOV A,R4PUSH ACCMOV A,R5PUSH ACCMOV A,R6PUSH ACCMOV A,R7PUSH ACC;PUSH SP ;不必保存SP 任务切换时由相应程序调整ENDMPOPALL MACRO;POP ACC ;不必保存SP 任务切换时由相应程序调整POP ACC ;R0-R7 出栈MOV R7,APOP ACCMOV R6,APOP ACCMOV R5,APOP ACCMOV R4,APOP ACCMOV R3,APOP ACCMOV R2,APOP ACCMOV R1,AMOV R0,APOP DPHPOP DPLPOP BPOP ACCPOP PSWENDM;子程序;-------------------------------------------------------------------------RSEG ?PR?OSStartHighRdy?OS_CPU_AOSStartHighRdy:USING 0 ;上电后51 自动关中断此处不必用CLR EA 指令因为到此处还未开中断本程序退出后开中断LCALL _?OSTaskSwHookOSCtxSw_in:;OSTCBCur ===> DPTR 获得当前TCB 指针详见C51.PDF 第178 页MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur 指针低地址指针占3 字节+0 类型+1 高8 位数据+2 低8 位数据INC R0MOV DPH,@R0 ;全局变量OSTCBCur 在IDATA 中INC R0MOV DPL,@R0;OSTCBCur->OSTCBStkPtr ===> DPTR 获得用户堆栈指针INC DPTR ;指针占3 字节+0 类型+1 高8 位数据+2 低8 位数据MOVX A,@DPTR ;.OSTCBStkPtr 是void 指针MOV R0,AINC DPTRMOVX A,@DPTRMOV R1,AMOV DPH,R0MOV DPL,R1;*UserStkPtr ===> R5 用户堆栈起始地址内容(即用户堆栈长度放在此处) 详见文档说明指针用法详见C51.PDF 第178 页MOVX A,@DPTR ;用户堆栈中是unsigned char 类型数据MOV R5,A ;R5=用户堆栈长度;恢复现场堆栈内容MOV R0,#OSStkStartrestore_stack:INC DPTRINC R0MOVX A,@DPTRMOV @R0,ADJNZ R5,restore_stack;恢复堆栈指针SPMOV SP,R0;OSRunning=TRUEMOV R0,#LOW (OSRunning)MOV @R0,#01POPALLSETB EA ;开中断RETI;-------------------------------------------------------------------------RSEG ?PR?OSCtxSw?OS_CPU_AOSCtxSw:PUSHALLOSIntCtxSw_in:;获得堆栈长度和起址MOV A,SPCLR CSUBB A,#OSStkStartMOV R5,A ;获得堆栈长度;OSTCBCur ===> DPTR 获得当前TCB 指针详见C51.PDF 第178 页MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur 指针低地址指针占3 字节+0 类型+1 高8 位数据+2 低8 位数据INC R0MOV DPH,@R0 ;全局变量OSTCBCur 在IDATA 中INC R0MOV DPL,@R0;OSTCBCur->OSTCBStkPtr ===> DPTR 获得用户堆栈指针INC DPTR ;指针占3 字节+0 类型+1 高8 位数据+2 低8 位数据MOVX A,@DPTR ;.OSTCBStkPtr 是void 指针MOV R0,AINC DPTRMOVX A,@DPTRMOV R1,AMOV DPH,R0MOV DPL,R1;保存堆栈长度MOV A,R5MOVX @DPTR,AMOV R0,#OSStkStart ;获得堆栈起址save_stack:INC DPTRINC R0MOV A,@R0MOVX @DPTR,ADJNZ R5,save_stack;调用用户程序LCALL _?OSTaskSwHook;OSTCBCur = OSTCBHighRdyMOV R0,#OSTCBCurMOV R1,#OSTCBHighRdyMOV A,@R1MOV @R0,AINC R0INC R1MOV A,@R1MOV @R0,AINC R0INC R1MOV A,@R1MOV @R0,A;OSPrioCur = OSPrioHighRdy 使用这两个变量主要目的是为了使指针比较变为字节比较以便节省时间MOV R0,#OSPrioCurMOV R1,#OSPrioHighRdyMOV A,@R1MOV @R0,ALJMP OSCtxSw_in;-------------------------------------------------------------------------RSEG ?PR?OSIntCtxSw?OS_CPU_AOSIntCtxSw:;调整SP 指针去掉在调用OSIntExit(),OSIntCtxSw()过程中压入堆栈的多余内容;SP=SP-4MOV A,SPCLR CSUBB A,#4MOV SP,ALJMP OSIntCtxSw_in;-------------------------------------------------------------------------CSEG AT 000BH ;OSTickISRLJMP OSTickISR ;使用定时器0RSEG ?PR?OSTickISR?OS_CPU_AOSTickISR:USING 0PUSHALLCLR TR0MOV TH0,#70H ;定义Tick=50 次/秒(即0.02 秒/次)MOV TL0,#00H ;OS_CPU_C.C 和OS_TICKS_PER_SECSETB TR0LCALL _?OSIntEnterLCALL _?OSTimeTickLCALL _?OSIntExitPOPALLRETI;-------------------------------------------------------------------------CSEG AT 0023H ;串口中断LJMP SerialISR ;工作于系统态无任务切换RSEG ?PR?_?serial?OS_CPU_ASerialISR:USING 0PUSHALLCLR EALCALL _?serialSETB EAPOPALLRETI;-------------------------------------------------------------------------END;-------------------------------------------------------------------------文件名: OS_CPU_C.Cvoid *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos, INT16U opt) reentrant {OS_STK *stk;ppdata = ppdata;opt = opt; //opt 没被用到保留此语句防止告警产生stk = (OS_STK *)ptos; //用户堆栈最低有效地址*stk++ = 15; //用户堆栈长度*stk++ = (INT16U)task & 0xFF; //任务地址低8 位*stk++ = (INT16U)task >> 8; //任务地址高8 位*stk++ = 0x00; //PSW*stk++ = 0x0A; //ACC*stk++ = 0x0B; //B*stk++ = 0x00; //DPL*stk++ = 0x00; //DPH*stk++ = 0x00; //R0*stk++ = 0x01; //R1*stk++ = 0x02; //R2*stk++ = 0x03; //R3*stk++ = 0x04; //R4*stk++ = 0x05; //R5*stk++ = 0x06; //R6*stk++ = 0x07; //R7//不用保存SP 任务切换时根据用户堆栈长度计算得出return ((void *)ptos);}#if OS_CPU_HOOKS_ENvoid OSTaskCreateHook (OS_TCB *ptcb) reentrant{ptcb = ptcb; /* Prevent compiler warning*/}void OSTaskDelHook (OS_TCB *ptcb) reentrant{ptcb = ptcb; /* Prevent compiler warning*/}void OSTimeTickHook (void) reentrant{ }#endif//初始化定时器0void InitTimer0(void) reentrant{TMOD=TMOD&0xF0;TMOD=TMOD|0x01; //模式1(16 位定时器) 仅受TR0 控制TH0=0x70; //定义Tick=50 次/秒(即0.02 秒/次)TL0=0x00; //OS_CPU_A.ASM 和OS_TICKS_PER_SECET0=1; //允许T0 中断TR0=1;}文件名: YY.C#include <includes.h>#define MAX_STK_SIZE 64void TaskStartyya(void *yydata) reentrant;void TaskStartyyb(void *yydata) reentrant;void TaskStartyyc(void *yydata) reentrant;OS_STK TaskStartStkyya[MAX_STK_SIZE+1];//注意我在ASM 文件中设置?STACK 空间为40H 即64 不要超出范围OS_STK TaskStartStkyyb[MAX_STK_SIZE+1];//用户栈多一个字节存长度OS_STK TaskStartStkyyc[MAX_STK_SIZE+1];void main(void){OSInit();InitTimer0();InitSerial();InitSerialBuffer();OSTaskCreate(TaskStartyya, (void *)0, &TaskStartStkyya[0],2);OSTaskCreate(TaskStartyyb, (void *)0, &TaskStartStkyyb[0],3);OSTaskCreate(TaskStartyyc, (void *)0, &TaskStartStkyyc[0],4); OSStart();}void TaskStartyya(void *yydata) reentrant{yydata=yydata;clrscr();PrintStr("\n\t\t*******************************\n"); PrintStr("\t\t* Hello! The world. *\n");PrintStr("\t\t*******************************\n\n\n");for(;;){PrintStr("\tAAAAAA111111 is active.\n");OSTimeDly(OS_TICKS_PER_SEC);}}void TaskStartyyb(void *yydata) reentrant{yydata=yydata;for(;;){PrintStr("\tBBBBBB333333 is active.\n");OSTimeDly(3*OS_TICKS_PER_SEC);}}void TaskStartyyc(void *yydata) reentrant{yydata=yydata;for(;;){PrintStr("\tCCCCCC666666 is active.\n");OSTimeDly(6*OS_TICKS_PER_SEC);}}。
uCOS的内核移植课程设计
河海大学物联网工程学院课程设计报告题目uC/OS-II 的内核移植专业、学号自动化、 10625授课班号270401学生姓名指导教师金纪东完成时间2013.6.21课程设计(报告)任务书(理工科类)Ⅰ、课程设计(报告)题目:uC/OS-II 的内核移植Ⅱ、课程设计(论文)工作内容一、课程设计目标1、培养综合运用知识和独立开展实践创新的能力;2、掌握把 uC/OS-II 移植到 ARM7 处理器上的基本步骤及方法;3、掌握 uC/OS-II 系统中任务调度的过程,以及任务的管理和信号量的管理的函数和过程;4、在 uC/OS-II 系统上编写多任务应用程序。
二、研究方法及手段应用1、将任务分成若干模块,查阅相关论文资料;2、分模块调试和完成任务。
三、课程设计预期效果1、完成实验环境搭建;2、移植 UC/OS-II 到三星的 S3C44B0X(或者 LPC210X ) ARM7TDMI 处理器上;2.编写多任务应用程序:一个熄灭 D7、D8 灯的任务,一个点亮 D7 熄灭D8 的任务,一个熄灭D7 点亮 D8 的任务,三个任务轮流输出。
学生姓名:王聪专业年级:自动化2010级嵌入式系统是当今非常热门的研究领域,早期多以单片机为核心,应用领域非常广泛 .但单片机系统功能比较简单,速度较慢,难以适应现代技术的快速发展 .随着现场可编程逻辑阵列技术的日益成熟,基于片上可编程系统的嵌入式处理器越来越多地受到人们的关注 .特别是Altera 公司推出的Nios-II 嵌入式处理器软核,通过软件编程的方法可灵活地实现嵌入式的功能,并且针对进行性能优化,可大大提高系统性能 .它还具有片上调试功能,便于系统的设计和调试 .随着芯片技术的发展, SOPC成为嵌入式系统设计的一个发展趋势,不同于桌面操作系统,嵌入式操作系统需根据特定的嵌入式应用及不同的处理器而进行移植和裁剪。
本次课设主要研究了嵌入式操作系统中应用较为广泛的、源代码开放的uC/OS-II 在基于目前应用非常广泛的ARM7处理器体系结构上的移植,并在此基础上实现了简单的多任务应用程序的操作。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
—213—μC/OS 在龙芯处理器上的移植及性能分析程晓宇1,毕笃彦1,蔡 晔2(1. 空军工程大学工程学院信号与信息处理实验室,西安 710038;2. 中国科学院计算技术研究所微处理器中心,北京 100080) 摘 要:在以国产CPU 龙芯2E 为核心的PC104 Plus 处理器模块上移植嵌入式实时操作系统μC/OS-II ,对其实时性能进行评价。
阐述处理器相关函数的编写及与PMON 的整合等关键技术,讨论系统实时性能评价的一般方法,包括Rhealstone 方法、进程分派延迟时间法和三维表示法等。
在此基础上选择Rhealstone 方法中的2个指标对整个系统的实时性能进行分析。
实验结果表明,系统的实时性能可满足一般实时系统的需求。
关键词:实时操作系统;μC/OS-II 系统;龙芯Transplantation of μC/OS on Loongson Processorand Its Performance AnalysisCHENG Xiao-yu 1, BI Du-yan 1, CAI Ye 2(1. Signal and Information Processing Lab, Engineering Institute, Air Force Engineering University, Xi’an 710038; 2. Microprocessor Research Center, Institute of Computing Technology, Chinese Academy of Sciences, Beijing 100080)【Abstract 】The real-time operation system μC/OS-II is transplanted to Loongson 2E PC104 Plus CPU module. The process is described and three methods for real-time performance evaluation are discussed. Rhealstone benchmark method is chosen to measure and analyze real-time performance of the system. Experimental results show that μC/OS-II in Loongson 2E PC104 Plus CPU module can meet the requirement of general real-time applications.【Key words 】real-time operation system; μC/OS-II system; Loongson计 算 机 工 程Computer Engineering 第35卷 第1期V ol.35 No.1 2009年1月January 2009·工程应用技术与实现·文章编号:1000—3428(2009)01—0213—03文献标识码:A中图分类号:TP3911 概述随着信息化技术的迅速发展,嵌入式系统已广泛应用于通信、网络、工控等技术领域,它是以应用为中心,软硬件可裁减的,适应应用系统对功能、可靠性、成本、体积、功耗等综合性严格要求的专用计算机系统。
实时性是指系统能够在限定的时间内完成任务并对外部的异步事件作出及时响应。
绝大多数嵌入式应用对系统的实时性有很高的要求。
嵌入式微处理器和嵌入式操作系统是构成一个嵌入式系统的硬件和软件核心。
龙芯2E 处理器是我国自主研发的通用处理器,它具有高性能、低功耗等特点。
μC/OS 是一个开放源代码的嵌入式实时操作系统。
为了将龙芯应用于嵌入式系统,本文在龙芯2E PC104 Plus 处理器模块的基础上,移植 μC/OS-II 嵌入式实时操作系统,并对其实时性能进行测试。
2 μC/OS 实时内核及其可移植性μC/OS-II [1]是专为嵌入式系统设计的抢占式多任务内核。
它可以基于ROM 运行,具有内核精简、多任务管理功能相对完善、实时性能好、可裁剪、可固化、源码开放、可移植性强等特点。
μC/OS-II 采用抢占式的内核,如图1所示。
它最多可以管理60个任务,其性能和很多商业实时操作系统性能相当。
目前µC/OS-II 已经成功地移植到大多数微处理器和微控制器上。
要使µC/OS-Ⅱ能正常运行,处理器必须满足以下要求:(1)处理器的C 编译器能产生可重入代码;(2)用C 语言就可以打开和关闭中断;(3)处理器支持中断,并且能产生定时中断;(4)处理器支持能够容纳一定量数据的硬件堆栈;(5)处理器有将堆栈指针和其他CPU 寄存器读出和存储到堆栈或内图1 µC/OS 的可剥夺型内核3 龙芯2E PC104Plus 处理器模块龙芯2E [2]微处理器是一款实现64 位MIPS III 指令集的通用RISC 处理器。
其最高工作频率为1 GHz ,典型工作频率为800 MHz ,实测功耗为5 W~7 W ,综合性能已经达到高端奔腾III 处理器以及中低端奔腾IV 处理器的水平。
基于龙芯2E 芯片设计的PC104 Plus 处理器模块是一个小型化但功能完整的CPU 主板系统,系统框架如图2所示。
系统北桥使用Altera 的FPGA(Cyclone II EP2C15F484)实现,通过SYSAD64总线与龙芯2E 连接。
南桥选用了VIA 的VT82C686A ,可提供IDE 接口、音频接口、USB 接口、串并作者简介:程晓宇(1979-),男,博士研究生,主研方向:图像侦查与传输,实时操作系统;毕笃彦,教授、博士生导师;蔡 晔, 博士研究生收稿日期:2008-05-12 E-mail :ubwom@—214— 口和鼠标键盘接口以及ISA 总线接口。
南桥和PCI PLUS 总线接口均通过PCI 总线和系统北桥连接,PC104 ISA 总线由图2 龙芯2E PC104 PLUS 处理器模块系统结构4 移植的关键技术4.1 处理器相关的代码移植把μC/OS-II 移植到龙芯PC104 Plus 处理器模块的主要工作是编写体系结构相关的代码,由于μC/OS-II 良好的可移植性,须编写的代码主要包括图3中与处理器相关的3个文件。
4.1.1 处理器和编译器的设置OS_CPU.H 文件中定义了与编译器相关的数据类型,因为不同的微处理器有不同的字长,所以移植必须完成一系列类型定义以确保其在新的编译器上可以正确编译。
根据龙芯处理器的用户手册做出如下定义:typedef unsigned char BOOLEAN; typedef unsigned char INT8U; typedef signed char INT8S; typedef unsigned short INT16U; typedef signed short INT16S; typedef unsigned int INT32U; typedef signed int INT32S;另外,μC/OS-II 定义了3种保护临界段代码的方式,也在OS_CPU.H 中定义,在龙芯处理器移植中选用了第3种模式。
通过OSCPUSaveSR ()函数保存龙芯状态寄存器的值,并将其全局中断使能位置0,禁止所有中断以保护临界段代码。
LEAF(OSCPUSaveSR)mfc0 v0,COP_0_STATUS_REG and v1,v0,0xfffffffemtc0 v1,COP_0_STATUS_REG jr ra nopEND(OSCPUSaveSR)4.1.2 处理器相关函数的编写(1)OSStartHighRdy ()函数负责在多任务启动之后,从最高优先级任务的TCB 控制块中获得该任务的堆栈指针sp ,通过sp 依次将CPU 现场恢复,并且执行中断的返回,从而将系统控制权交给该任务的进程。
(2)OSCtxSw ()函数是任务级的任务切换函数,在任务中调用,通过执行一条软中断指令OS_TASK_SW ()实现任务切换,它首先保存现场,然后获取最高优先级任务堆栈指针,并从这个堆栈中恢复CPU 现场,从而实现任务切换。
(3)OSIntCtxSw ()函数是中断级的任务切换函数,实现了在中断退出后可以不返回被中断的任务,而直接使处于最高优先级的任务得到执行。
在编写中设了一个全局变量OSIntCtxSwFlag ,在Gen_EXC_Handler ()函数中会以此变量的值来实现真正的中断级任务切换。
(4)Gen_EXC_Handler ()函数是OSTickISR ()函数的替代。
它不仅完成原有OSTickISR ()函数对时钟中断的处理,还为以后其他中断的处理留出了接口,因此,它是一个用来处理例外的通用函数。
在这个例外处理函数中判断是发生了中断还是异常。
(5)若发生了中断,则调用C_INTHandler ()函数,进一步判断是否为时钟中断,若发生时钟中断,先调用μC/OS-II 中时钟节拍服务函数OSTimeTick ,并对龙芯中的count 清零,重置compare 寄存器,令compare 为OS_TICKS_PER_SEC ,这里定义为龙芯流水线频率的一半。
以上函数均由MIPS 汇编语言实现。
另外,用来初始化任务堆栈的OSTaskStkInit ()函数通过C 语言实现,它使堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。
4.2 与PMON 的整合PMON 是一个兼有BIOS 和bootloader 部分功能的开放源码软件,它支持多种文件系统,支持多种引导方式及处理器架构,具备强大的调试功能,多用于嵌入式系统。
基于龙芯的系统采用 PMON 作为类 BIOS 兼 bootloader 。
为了便于调试移植后的μC/OS-II ,将PMON 和μC/OS-II 整合在一起,借用PMON 的调试功能进行代码的调试和性能分析。
PMON 担任系统的初始化任务。
μC/OS-II 被整合在PMON 的main ()函数中,在系统初始化完成后接管控制权,OSStart ()函数执行后,开始进入μC/OS-II 的多任务实时调度阶段。
这样的结构避免了为μC/OS-II 再次编写繁琐的系统初始化代码,并且可有效利用PMON 的调试功能。
5 性能评价5.1 嵌入式实时系统性能评价实时性是指系统能够在限定的时间内完成任务并对外部的异步事件作出及时响应的能力。
对嵌入式实时系统的性能评价的方法很多,目前应用最多的主要有以下3种:(1)Rhealstone [3]为工业界的实时计算机提供了一个比较标准。