UCOSII移植过程及心得
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();}第五步:对移植好的代码进行调试。
uCOSII移植到STM32的心得随笔
#include <includes.h>
/*
*******************************************************************************
**************************
*
LOCAL DEFINES
*******************************************************************************
都复制到 RVMDK 文件夹下,在 ucosII_STM32_Test 文件夹下建立一个文件夹 STM32LIB,把
Software\CPU\ST\STM32 文件夹下的两个文件夹 inc,src 都复制到 STM32LIB 下,这两个是 STM32 的固件库,分别是 h 文件和 C 文件,为了方便我直接把 STM32 这文件夹拷过去了(主 要 是 inc , src 这 两 个 文 件 夹 ), 差 点 还 漏 了 一 步 , 把 BSP 文 件 夹 下 的 文 件
/* Start multitasking
return (0); }
/*
*******************************************************************************
**************************
*
App_TaskStart()
*
* Description : The startup task. The uC/OS-II ticker should only be initialize once multitasking
关于UCOS-Ⅱ的移植
关于UC/OS-II的移植网上介绍的已经很多了,比较流行的几款处理器(例如ARM)在网上都可以直接下载移植好的代码。
由于最近选修了一门嵌入式系统的课,用的处理器是EPSON公司的S1C33系列,做实验的时候要进行操作系统的移植,这个周末花了一天半的时间学习了一下,因为毕业设计的时候做过ARM 上的移植,于是将两者比较了一下,给出一般的移植要点。
由于将来实验还要设计到GUI的移植以及文件系统的移植和网络协议的移植,我会将自己的学习笔记都记录下来。
大家下载到源码后,针对Intel 80x86的代码在uCOS-II\Ix86L目录下。
代码是80x86实模式,且在编译器大模式下编译的。
移植部分的代码可在下述文件中找到:OS_CPU.H, OS_CPU_C.C, 和OS_CPU_A.ASM。
大家可以参考这个例子,对它进行修改。
INCLUDES.H 是主头文件,在所有后缀名为.C的文件的开始都包含INCLUDES.H文件。
使用INCLUDES.H 的好处是所有的.C文件都只包含一个头文件,程序简洁,可读性强。
缺点是.C文件可能会包含一些它并不需要的头文件,额外的增加编译时间。
与优点相比,多一些编译时间还是可以接受的。
用户可以改写INCLUDES.H文件,增加自己的头文件,但必须加在文件末尾。
//////////////////////////////////////////////////////////一、(1)OS_CPU.H文件的移植(针对S1C33209)//////////////////////////////////////////////////////////OS_CPU.H 文件中包含与处理器相关的常量,宏和结构体的定义。
#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT //全局变量#else#define OS_CPU_EXT extern#endif//////////////////////////////////////////////////////////由于不同的处理器有不同的字长,µC/OS-II的移植需要重新定义一系列的数据结构。
ucosii移植stm32总结
UCOS-II在51单片机上的移植
UCOS-II在51单片机上的移植做操作系统的移植首先明白什么是移植,操作系统是一种鱼硬件(处理器)相关的软件,根据某一种处理器来设计的操作系统通常不能运行在那其他处理器。
所谓的移植是指修改操作系统,然后加载到一个处理器上。
本文只讲解步骤,至于理论知识,需要大家自己学习。
步骤:1,在UCOS-II的官网上下载,操作系统。
2,在网上找到或者自己建三四个文件:OS_CPU_A.ASSMOS_CPU.HOS_CPU_C.COS_CFG.H以上文件需要修改3,移植源码的编写和修改❖OS_CPU.H1)定义与编译器有关的数据类型typedef unsigned char BOOLEAN; /* 不能使用bit定义,结构中无法使用*/typedef unsigned char INT8U; /* 无符号8位数*/typedef unsigned char INT8S; /* 有符号8位数*/typedef unsigned int INT16U; /* 无符号16位数*/typedef signed int INT16S; /* 有符号16位数*/typedef unsigned long INT32U; /* 无符号32位数*/typedef signed long INT32S; /* 有符号32位数*/typedef float FP32; /* 单精度浮点数*/typedef double FP64; /* 双精度浮点数*/typedef unsigned char OS_STK; /* 定义堆栈入口宽度为8位*/typedef unsigned char OS_CPU_SR; /* 定义CPU状态字的宽度为8位*/2)定义堆栈增长方向#define OS_STK_GROWTH 0 /* MCS-51堆栈从下往上增长,1=向下,0=向上*/3)定义任务级的任务切换宏#define OS_TASK_SW() OSCtxSw() /* 任务级的任务切换宏*/4)定义临界段宏:#define OS_ENTER_CRITICAL() EA=0#define OS_EXIT_CRITICAL() EA=1❖OS_CPU_C.C①初始化任务栈void *OSTaskStkInit(void(*task)(void *pd), void *ppdata, void *ptos, INT16U opt) REENTRANT{O S_STK *stk;p pdata=ppdata; //pata data 为52文件关键字o pt =opt; /* opt没被用到,保留此语句防止警告产生 */s tk =(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,任务切换时根据用户堆栈长度计算得出*/*stk++=(INT16U)(ptos+MAX_STK_SIZE) >> 8; /* ?C_XBP 仿真堆栈指针高8位 */*stk++=(INT16U)(ptos+MAX_STK_SIZE) & 0xFF; /* ?C_XBP 仿真堆栈低8位*/r eturn ((void *)ptos); /* 返回最低地址,这里不用弹出栈顶指针是为了提高计算效率 */}②初始化定时器void InitTimer0(void) REENTRANT{TMOD=TMOD&0xF0; //屏蔽高四位TMOD=TMOD|0x01; /* 模式1(16位定时器),仅受TR0控制 */ TH0=TIMER_20MS_TH0;TL0=TIMER_20MS_TL0;E A=0; /* EA和ET0,51上电缺省值为0,EA将在OSStartHighRdy()中打开*/ET0=0; /* 满足在OSStart()前不产生时钟中断的要求,系统启动后第一时间开定时器T0中断 */TR0=1;}❖OS_CPU_A.ASM编写4个函数OSStartHighRdy()OSCtxSw()OSIntCtxSw()OSTickISR()❖OS_CFG.H主要为参数和使能的宏定义#define MAX_STK_SIZE 1024 /* 最大堆栈大小为1k*/#define OS_MAX_EVENTS 5 /* 应用程序中事件控制块的最大数量(必须大于零)*/#define OS_MAX_FLAGS 2 /* 应用程序中事件标志组的最大数目(必须大于零)*/#define OS_MAX_MEM_PART 5 /* 内存分区的最大数目(必须大于零)*/#define OS_MAX_QS 2 /* 应用程序中队列控制块的最大数目(必须大于零)*/#define OS_MAX_TASKS 11 /* 应用程序中任务的最大数目(必须大于2)*/#define TASK_START_PRIO 2 /* 应用程序开始优先级*/#define OS_LOWEST_PRIO 12 /* 定义可分配的最低优先级(必须大于63)*/#define TASK_STK_SIZE 512 /* 默认任务堆栈大小*/#define OS_TICKS_PER_SEC 50 /* 设置每秒节拍数*/#define TIMER_20MS_TH0 0x70 /* CPU=22.1184MHz, OS_TICKS_PER_SEC=50, TH0=0x70 */#define TIMER_20MS_TL0 0x00 /* CPU=22.1184MHz, OS_TICKS_PER_SEC=50, TL0=0x00 */晶振频率为22.1184MHz时才有OS_TICKS_PER_SEC=50,OS_TICKS_PER_SEC=50。
uC-OS II在ARM 上的移植体会
uC-OS II在ARM 上的移植体会移植uC/OS-II的绝大部分工作都集中在os_cpu_a.s文件的移植,这个文件的实现集中体现了所要移植到处理器的体系结构和uC/OS-II的移植原理;在这个文件里,最困难的工作又集中体现在OSIntCtxSw和OSTickISR这两个函数的实现上。
这是因为这两个函数的实现是和移植者的移植思路以及相关硬件定时器、中断寄存器的设置有关。
在实际的移植工作中,这两个地方也比较容易出错。
OSIntCtxSw最重要的作用就是它完成了在中断ISR中直接进行任务切换,从而提高了实时响应的速度。
它发生的时机是在ISR执行到OSIntExit时,如果发现有高优先级的任务因为等待的time tick到来获得了执行的条件,这样就可以马上被调度执行,而不用返回被中断的那个任务之后再进行任务切换,因为那样的话就不够实时了。
实现OSIntCtxSw的方法大致也有两种情况:一种是通过调整sp堆栈指针的方法,根据所用的编译器对于函数嵌套的处理,通过精确计算出所需要调整的sp位置来使得进入中断时所作的保存现场的工作可以被重用。
这种方法的好处是直接在函数嵌套内部发生任务切换,使得高优先级的任务能够最快的被调度执行。
但是这个办法需要和具体的编译器以及编译参数的设置相关,需要较多技巧。
另一种是设置需要切换标志位的方法,在OSIntCtxSw 里面不发生切换,而是设置一个需要切换的标志,等函数嵌套从进入OsIntExit =>OS_ENTER_CRITICAL() => OSIntCtxSw()=>OS_EXIT_CRITICAL() => OSIntExit退出后,再根据标志位来判断是否需要进行中断级的任务切换。
这种方法的好处是不需要考虑编译器的因素。
也不用做计算,但是从实时响应上不是最快,不过刚开始学习这种方法比较容易理解,实现起来也简单。
在中断态下进行任务切换,需要特别说明的一个问题是如何获得被中断任务的lr_svc。
uCOS-II移植总结
u C/OS-II移植总结RTOS移植牵涉到软件平台—编译器、硬件平台—CPU,移植前需要了解CPU及编译器的一些基本特点。
1、编译器a、堆栈运行原理本次移植的软件平台为CodeVision编译器,它的堆栈由两部分组成:硬件堆栈(HardStack)用来保存中断及函数调用的返回地址,它的大小将影响函数调用嵌套的深度,实际大小应根据中断及函数嵌套的深度来决定,并留有一定的裕度。
硬件堆栈由CPU中的指针SP实现。
软件堆栈(SoftStack)用来分配局部变量及传递参数。
在此次移植中,由CPU中的Y指针模拟实现。
b、堆栈指针所指向的单元是否为可用单元大多数编译器生成的代码,其堆栈指针所指向的单元为可用单元,也就是说在将数据压入堆栈前不用再调整堆栈指针,堆栈指针在上一次使用完后已经调整好了。
前面所说的硬件堆栈(HardStack)即为这种类型。
还有一种堆栈,其指针所指向的单元为不可用单元,在向堆栈压入数据前需调整堆栈指针,软件堆栈(SoftStack)即为这种类型。
软件堆栈设计为这种形式完全是为了适应A VR指令和软件堆栈增长方向与硬件堆栈增长方向相同。
软件堆栈(SoftStack)由Y指针模拟实现,但在A VR的指令集中只有:LD Rd,Y+ LD Rd,–Y ST Y+,Rr ST –Y,Rr要实现向下增长的堆栈就只能使用ST –Y,Rr和LD Rd,Y+。
指针指向的单元已压入数据,因此使用前需调整指针,而ST –Y,Rr正好能完成这个动作。
c、多字节变量在宽度为单字节的存储器中的分配规则多字节变量指定义为int、long int、float、double等类型的变量。
在CodeVision编译器遵循的原则是:变量低字节部分分配在内存的低地址单元,变量高字节部分分配在内存高地址单元。
如:int a a为双字节变量,其低字节保存在内存的0x24H,则高字节保存在内存的0x25H。
了解这些变量在内存中存储形式是为了能够在在线汇编中正确操作它们。
uCOS II 移植笔记
uC/OS II 移植笔记2009.2.28其实之前很早就看过uC/OS II这个操作系统。
而且当时也看了一些材料。
但是后来自己头脑发昏,以为搞嵌入式就一定要搞Linux或winCE,再加个TCP/IP之类的才是。
最后吃力不讨好。
反而自信心受重挫。
最终呢,还是回归原始,回归最简单,最本质的那些东西。
这次呢,打算把uC/OS II这个操作系统移植到周立功公司的EASYARM2104上面。
为什么会有这样的想法呢。
其实本来是想自己实现一个操作系统的。
一个简单的内核也行。
也是呢,找了一大堆的编写操作系统的资料,还有一些国内外开源的嵌入式实时操作系统。
所以,当时我们科研小组在做第二次报告的时候,我选的题目就是FDGKos的设计。
我做完报告之后,吴老师说,我之前很多的师兄都有想实现一个系统的想法,但是,谈何容易呢。
它要求一个人有很高的编程水平,及对硬件、操作系统原理十分了解才行。
我后来反复的思考了吴老师说的这几句话。
也不是没有道理的。
那好。
我不一步到位。
我先把uC/OS II在LPC2104上面玩转了再说。
开始干活了才知道。
原来一切都没有自己想象的那么容易。
我很快了,花了几天时间,把绍贝贝学生翻译的那本书给啃了一遍。
然后迫不及待的想运行起来。
要运行起来,当然得先移植才行啊。
这移植的工作量也不小啊。
我想啊,没事,也当一次练兵的机会。
周立功写的书里面有移植笔记,我先按着他的笔记,把代码敲进去。
写入flash运行之后发现,我这程序,在系统初始化之后,创建了两个任务,但是这些任务只有刚开始执行以下,碰到有OSTimeDly()函数的时候,一调度,就没有办法回到那两个任务里面来。
而是一直执行空闲任务。
如果任务里面延迟函数用周立功写的DelayNS()函数的话,有没有问题。
这个问题一直困惑了我好久,也一直没有办法解决。
代码了一遍又一遍,代码也读了一遍又一遍。
最后火了。
直接建立一个ucos for lpc210x的工程模板。
ucos-ii(2.91)在LPC17xx上移植个人总结
Ucos-ii移植到LPC1752总结前言个人移植后觉得应该自己总结下,回忆下整个移植过程,于是有了一下内容。
本来是个人笔记,突然想分享给大家,所以有很多不足,内容仅供参考。
本文主要讨论移植,移植前一定要保证1752在没有操作系统的情况下能正常运行各个功能,具体请参照其他相关文档,这里不做探讨。
这里只是个人移植过程中遇到的情况及处理办法,粗略总结仅供参考。
Ucos 详情参考邵贝贝翻译作品。
注:本文仅适用于初学者,高手请绕道,初学者需对芯片和编译工具有基本的了解一、准备工作1、下载芯片驱动在lpcware官方网站下载1752的底层驱动,里面有现成的系统初始化配置函数及相关GPIO的操作接口函数。
当然这些也可以自己写。
2、下载ucos代码在ucos官方网站下载操作系统源文件(source),然后在官方网站(/page/home)找到LPC17xx相关的接口代码。
下载代码需要注册。
(/page/downloads/ports/nxp)图1开始移植1、建立工程首先建立工程,我使用的是keil,工程建立后将芯片的驱动文件添加并编译,先不移植看芯片是否能正常工作(最简单就是用一个led闪烁来指示芯片是否正常工作)。
能正常工作后再进行下一步操作(这样以后出问题就知道是系统原因还是芯片原因)。
这里具体操作不做探讨,因为这不属于移植的部分,是对芯片的基本操作。
2、移植ucos-ii将下载的ucos代码添加进工程,在source中将里面的文件全部添加进工程,而接口只需将Micrium\Software\uCOS-II\Ports\ARM-Cortex-M3\Generic\IAR里面的几个文件添加进去即可。
将#include <app_cfg.h>注释掉,因为我们在主程序里面定义堆栈。
并且将ucos-ii.h里面的os_cfg.h改为os_cfg_r.h因为不同版本命名不一样。
如图2所示图 22.1.1修改os_cpu_a.asm文件因为我们使用的是keil,所以需要建里面的public改为EXPORT如下图所示。
uCOS移植(uCOS-II在Microblaze上的移植)
随着集成电路设计与制造技术的发展,FPGA芯片的容量越来越大、性能越来越高,用FPGA构建片上系统成为现实,基于FPGA的嵌入式系统与SOPC(System On a Programmable Chip)设计技术将逐渐成为系统设计的主流技术,正获得越来越广泛地研究。
Microblaze是Xilinx公司一款针对FPGA器件进行了优化设计的软处理器核,有不错的性能且价格低廉,且支持Xilinx全系列的FPGA器件,应该有着广阔的发展前景。
μC/OS-II 是Jean Labrosse先生于1998年推出的一个优秀的开放源码的实时操作系统,具有移植方便、执行效率高、占用空间小、实时性强和可靠性高等优点。
采用μC/OS-II+Microblaze的应用平台对中小嵌入式系统应用来说是十分适合的。
本文基于μC/OS-II在Microblaze上的移植与基于该系统的应用研究,记录移植和使用过程的心得、体会,内容可能会有些零散,希望对有类似应用的朋友有些帮助,也欢迎大家来交流与讨论。
一、主要参考资料①μC/OS-II学习主要参考邵贝贝教授译的《嵌入式实时操作系统μC/OS-II(第2版)》下面是CHINA-PUB的介绍/12618网上也有该书第一版的电子书可以找来学习。
② Micrium公司的Micrium-uCOS-II-V286.ZIP,包括代码与文档,可以从获得。
③ Micrium公司的μC/OS-II and the Xilinx MicroBlaze Processor Application Note可以从获得。
④ Xilinx公司EDK相关文档:/ise/embedded/edk_docs.htm⑤ISE、EDK软件的帮助文档,包括MicroBlaze Processor Reference Guide (mb_ref_guide.pdf)。
⑥ EDK的基本使用可以参考:Xilinx官方的6个EDK实验(中文版).pdf百度文库上有/view/e92e71d184254b35eefd3425.html二、操作系统的配置选项问题在进行Software Platform配置时,一般安装了EDK软件后,操作系统与库设置时可选择的标准选项只有两个:Standalone和Xilkernel。
uCOSii的移植过程详解
uCOSii的移植过程详解
C/ OS 是一种多任务实时操作系统。
内核源代码公开、短小精干、可裁剪、执行时间可确定, 可移植性较强, 非常适用于一些中小型嵌入式系统开发。
uC/OS 可以移植到8~ 64 位的不同类型、不同规模的嵌入式系统, 并能在大部分的8 位、16 位、32 位, 甚至64 位的微处理器和DSP上运行[ 1] 。
MCF52235是飞思卡尔公司Co ldf ire 系列32 位单片机解决方案的嵌入式微控制器, 采用的是V2 版本的RISC 内核。
MCF52235 内部有32 KB SRAM 和256 KB FLASH, 并且集成了标准的Coldfire外围设备, 包括三个适合中长距离通信的SCI, 一个I2 C 和一个用于系统内部和外围设备通信的Q SPI。
在60Hz的核心频率下, MCF52235 的处理能力为56 MIPS, 具备较高的性能价格比[ 24] 。
MCF52235 对于移植C/ OS 来说有足够的
RAM 和FLASH, 且有较快的处理速度和较低的成本,所以对于嵌入式应用系统的开发来说, 嵌入C/ OS到MCF52235 微控制器是一个不错的选择。
uC/ OS 的体系结构要实现C/ OS 向MCF52235 的移植, 需要做两方面的工作: 一是重新定义内核的大小和功能; 二是为内核编写与硬件相关的代码。
C/ OS 的文件结构如图1 所示。
可以看到, C/ OS 与CPU 类型无关的C 代码文件COS . C 包括很多文件, 它们是C/ OS 的内核和很多功能函数, 其中前。
ucos ii移植过程详解
uCOS-II移值过程实例讲解我将uCOS-II 移植到了EPONS 的C33209的平台上,接下来我就基于我移植好的代码讲解如何将uCOS-II从一种MCU移植到另一种MCU。
首先介绍uCOS-II的文件,如下表:ucos_ii.hos_cfg.hos_cpu.hos_core.cos_dbg_r.cos_flag.cos_mbox.cos_mem.cos_mutex.cos_q.cos_sem.cos_task.cos_time.cucos_ii.cos_cpu_c.cos_cpu_a.asm其中我们和硬件平台相关的文件的文件名被加粗了,也就是说若要将uCOS-II移植到新的平台上只要关心被以上四个文件就行了。
当然你也可以根据需要再添加你自己的和平台相关的文件,事实上我也是这么做的。
在我移植的例子中就添加了四个和平台相关的文件,文件如下表:crt0.cdrv_rtc.cvector.cext.scrt0.c是用来初始化系统的比如说MCU的一些特殊寄存器、设置外围的总线接口,等。
drv_rtc.c是用来初始化系统中的一个RTC的,这个RTC可以为内核提供必要的基于时间片调度的时基。
同时提供了对RTC开始和停止的操作函数。
在我的例子中RTC会每秒产生32次中断。
vector.c顾名思义,它是系统上电后为系统提供矢量入口表的文件,当然也包括中断向量表。
ext.s是为uc/OS-II 提供OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()函数的具体实现以及在用户程序的中断函数出入时要调用的状态保护和状态恢复函数OS_SA VEALL ()和OS_RESTOREALL ()。
前面两个函数的功能是:OS_ENTER_CRITICAL()屏蔽中断;OS_EXIT_CRITICAL()恢复原来的中断使能状态。
1. os_cpu_a.asm的说明要想顺利的移植首先要了解uCOS-II的一些基本概念。
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在STM32上的移植步骤
uCOS-II在STM32上的移植步骤前言:说点废话,网上有很多关于uCOS-ii 移植的文章,好多都是千篇一律,理论性很强,分析了一大堆虚头巴脑的东西,真想问他们,你确定你分析的这些东西是需要你做的工作吗?实操性严重欠缺。
这方面我也走了很多弯路,下面就将自己的移植过程一步步的记录下来,也给大家做做参考。
首先,简单总结一下移植的大概过程:(1)去uC/OS-ii 官网下载你要移植芯片CPU 的相关案例,不一定完全对应,那就找相应系列吧。
(2)编程环境一般有两种,分别是IAR 和MDK,这个根据你自己的编程环境进行下载。
(3)本案例需要将uC/OS-II 移植到STM32F103ZET6 上,而我使用的编程环境是MDK,很遗憾,官网上提供的案例是基于IAR 的,所以要基于IAR 的案例进行更改。
(4)使用MDK 创建一个无操作系统的最简单程序,确保这个程序能够使用,这样做的目的是为了一步步的排查错误,假如无操作系统时,都有错误,移植过程中也肯定会有编译错误,那么在排查错误的时候也就增加了难度,不会写物操作系统的简单程序怎么办。
那就不要往下看了。
(5)移植的最大的改动主要有两部分,一个是一些头文件的增减,另外一个就是向量表中PendSV_Handler 和SysTick_Handler 的修改。
这里我要吐槽一下,网上说了一大堆关于什么OS_CPU.H 的更改还有各种函数的的分析,这都是扯淡。
这些根本就不用移植者去修改,官网提供的案例都已经提供了,除非你选择移植的CPU 是比较偏的,那么这些东西需要移植者自己去编写。
好了,下面就开始详细的记录怎么去移植。
一、创建一个无操作系统的简单裸板系统1.创建源文件工程文件夹,如下图所示:其中文件夹CMSIS 为内核的接口,包含的文件如下图文件夹STM32_StdPeriph 为固件驱动文件夹,这个把STM32 的固件全都添加进去即可。
文件夹User 为其他文件,如下图所示:文件夹Output 和。
嵌入式实时操作系统UCOSⅡ的移植
3应用软件的编写
在操作系统移植成功后,主要的工作便是应用 软件的编写。应用软件可以使用C语言,也可使用 C语言与汇编语言混合编程,在对时间要求比较高 的地方使用汇编语言。在使用C和汇编语言混合编 程的应用软件中,采用C语言和汇编语言分别编译 的方法。由于uc/0s—II的进程调度是基于优先级 的,所以根据控制系统的要求将应用软件分成多个 任务,并分配不同的优先级。这样,应用软件便在 操作系统的调度下运行。多任务运行使CPU的利用 率得到最大的发挥,并使应用程序模块化,以及使 应用程序更容易设计和维护。下面仅给出RS一485发 送中断程序流程图图l。
作系统固有的函数内容,只需直接调用即可。 2.3.3中断任务级切换函数OSIntCtxSw()
UC/OS—II中,中断的产生可能会引起任务的切 换,在中断服务程序的最后会调用0SIntExit()检查
任务就绪状态。如果需要进行任务切换,将调用 OSIntCtxSw0。 2.3.4多任务启动函数中调用的OSStartHighRdy()
/*任务创建扩展外挂函数
4/
void OSTaskSwHook(void)f}
/+任务切换扩展外挂函数
4/
void OSTaskDelHook(OS—TCB+ptcb){)
/4任务删除扩展外挂函数
+/
void OSTaskStatHook(void){}
/+统计任务扩展外挂函数
+/
void OSTimeTickHook(void){) /+时钟节拍创建扩展外挂函数+/
(1)硬件进入中断处理:全局中断使能位置1, 返回地址压栈(系统自动完成);
32四万方圆数据2005年2期
(2)寄存器值压入当前任务堆栈,如:C a ll I¥¥SAVE:
实验二 uCOS-II在windows下的移植
实验二uCOS-II在windows下的移植
一:实验目的:
1.掌握uCOS-II在windows下的移植。
二:实验内容:
完成实验环境搭建,并且将uCOS-II移植到d盘下。
三:实验步骤:
1.可以将该工程所需的五个文件:OS_CPU_A.ASM,OS_CPU_C.C,PC.C,TEST.C,Ucos_II.C
放到一个独立的文件夹中,添加的时候便于添加。
2.按照实验一的步骤建立工程
添加所需要的文件:
3.若是将工程建到同software文件夹同一磁盘,但并未如之前一样放到“software\uCOS-II\EX1_x86L\BC45\source\”路径下,在编译运行时会提醒:“unable to open includes.h”和“unable to open os_cfg.h”,解决方法如下:
方法一:将#include “includes.h”改为
“#include “..\SOFTWARE\uCOS-II\EX1_x86L\BC45\SOURCE\includes.h””
将#include “os_cfg.h”改为
“#include “..\SOFTWARE\uCOS-II\EX1_x86L\BC45\SOURCE\os_cfg.h””
方法二:将“..\SOFTWARE\uCOS-II\EX1_x86L\BC45\SOURCE\”路径下的“includes.h”和“os_cfg.h”复制到工程所在的目录之下。
3.运行程序:。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
UCOSII V2.86在LPC2378上的移植
(编译器ADS1.2)
忙了几天,终于移植成功了。
移植UCOS需要准备一些东西,首先当然是OS源代码,再就是选定编译器,需要弄清一下几点:
1、UCOS需要移植的内容
2、编译器的特性(在这里主要是ATPCS)
3、处理器的特性(这里主要注意ARM7的模式)
以下先简要说一下这几点,为后面的程序说明做准备
首先说说第一点,UCOS需要移植的内容。
1、数据类型的定义,这个根据平台来处理。
具体代码如下:
2、任务切换函数,就是两个任务环境之间的切换。
3、处理临界代码前要关闭中断,之后再打开,这个实现的方法与平台关系很大。
4、栈的初始化,栈中保存的是任务的运行环境,不同的处理器中的寄存器自然是不一样的。
5、还有一个和任务切换差不多的,这个函数只运行一次,就是将第一个运行的任务的运行环境复制到CPU中。
再说说编译器的特性,ATPCS规定(想要详细一些的可以看看ADS 的帮助文档):R0-R3用来传递参数,R4-R12用来处理局部变量。
这个在处理汇编和C的接口时十分重要。
最后是CPU的特性。
ARM7有7种模式,但是有些模式对于UCOS在ARM7上的运行用处不大,经过综合考虑,可以只使用四种模式:SVC:运行OS代码和用户代码
SYS:用于IRQ的嵌套处理,(暂时还未实现)
IRQ:处理中断,处于OS的控制范围内
FIQ:独立于操作系统,处理快速中断
有了上面的说明,下面可以具体讨论了,因为网页中显示代码及注释不方便,所以把它们放在了附件中。
标题中前面是内容,括号内是涉及到的需要移植的函数
1、任务栈(OSTaskStkInit)
任务栈相当于CPU的一个备份,可以这样认为,当运行一个任务时,将栈中的数据复制到CPU中,由于某种原因停止运行一个任务时将CPU复制到任务栈中。
ARM7的CPU需要保存的寄存器如下:
PC任务断点
LR
R12
R11
R10
R9
R8
R7
R6
R5
R4
R3
R2
R1
R0
CPSR
还有一个栈指针SP,这个保存在任务控制块中。
2、任务开始(OSStartHighRdy)
(1)这个函数很简单,有如下几步
(2)通知OS已经运行
(3)调用OSTaskSwHook,是一个钩子函数
(4)将就绪的优先级最高的任务的数据复制到CPU中,这个过程有个顺序,一般是先将SP恢复,再将CPSR复制到SPSR中,然后使用LDMFD SP!,{R0-R12,LR,PC}^一次性复制所有。
3、任务切换(OS_TASK_SW OSIntCtxSw)
这里涉及到两个函数,为什么会有两个呢,这个与任务切换时CPU 所处的状态有关。
当一个任务正在执行时,需要切换任务(此时处在SVC模式),之需要简单地保存前一个任务的环境,并恢复后一个任务
的环境至CPU即可,使用的是OS_TASK_SW()。
但是由于中断导致的任务切换就有些麻烦(自己在这块儿耽误了很久),此时需要保存的任务环境一部分保存在IRQ独有的寄存器中(其中包括任务的断点,任务的CPSR),一部分保存在SVC的寄存器中,还有一部分保存在IRQ 的栈中,此时调用OSIntCtxSw()。
OSIntCtxSw()和IRQ的处理方式有关。
OS_TASK_SW()要做的事情是
(1)保存任务的断点,此时还在在LR中
(2)保存R0-R12
(3)保存CPSR
(4)保存SP
(5)调用OSTaskSwHook
(6)OSPrioHighRdy->OSPrioCur
(7)OSTCBHighRdy->OSTCBCur
(8)恢复SP
(9)恢复CPRS至SPRS
(10)使用LDMFD SP!,{R0-R12,LR,PC}^恢复所有
OSIntCtxSw()
此函数被调用前,需要准备一些东西,也就是我们要自己用汇编写IRQ的入口函数IRQ_Handler,此时IRQ的服务程序就不用加__irq 了。
IRQ_Handler要做的事情是
(1)LR-4,获得任务的断点,并保存环境R0-R3,R12,LR
(2)调用OSIntEnter(),通知OS进入中断
(3)执行中断服务程序,用C编写,是普通函数
(4)调用OSIntExit(),判断执行完中断服务程序后是否需要切换任务。
这里需要注意一下:OSIntExit()中本来还要调用OSIntCtxSw()来执行切换的,这里改写了OSIntExit()这个函数,将里面的调用OSIntCtxSw()改为OSIntCtxSwFlag=1。
OSIntCtxSwFlag是自己定义的一个标志,置1表示需要切换任务。
(5)判断OSIntCtxSwFlag是否为1
(6)如果OSIntCtxSwFlag=1,跳转至OSIntCtxSw()
(7)如果OSIntCtxSwFlag=0,接着往下执行
(8)恢复环境R0-R3,R12,LR SPSR至CPSR,回到SVC模式
OSIntCtxSw()要做的事情是
(1)OSIntCtxSwFlag清零
(2)保存任务环境,这个有点复杂,具体可以看一下程序
(3)在执行(2)的同时还用调整IRQ的SP,使得看起来就像没用发生过中断
(4)调用OSTaskSwHook
(5)OSPrioHighRdy->OSPrioCur
(6)OSTCBHighRdy->OSTCBCur
(7)恢复SP
(8)恢复CPRS至SPRS
(9)使用LDMFD SP!,{R0-R12,LR,PC}^恢复所有
4、开、关中断
UCOS中可以使用3中方式。
第一种简单,但是会产生问题,一般不用;第二种需要执行CPSR的进栈出栈操作,这样同样会用潜在的问题,任务切换后,PC就改变了,转向了新的任务,后面的代码就可能不会执行,假如不知道任务切换前关中断的次数,那么就不知道压栈的次数,那么任务切换函数就不好写了。
第三种比较适合ARM7,关中断时先将CPSR保存在局部变量中,再关中断;开中断则只是简单的将局部变量恢复至CPSR即可,可以和好地解决开关中断的嵌套。
这个代码比较少,可以贴在这里:
#define OS_ENTER_CRITICAL(){cpu_sr=OSSaveCPSR();}
#define OS_EXIT_CRITICAL(){OSRestoreCPSR(cpu_sr);}
OSSaveCPSR
MRS R0,CPSR
ORR R1,R0,#NoInt
MSR CPSR_c,R1
MOV PC,LR
OSRestoreCPSR
MSR CPSR_c,R0
MOV PC,LR
参数使用R0传递
好了,就先写到这里了,基本问题解决了,剩下的任务就是处理一下中断的嵌套,再看看有没有什么BUG,移植代码就在附件里。