UCOS移植技巧

合集下载

uCOS51移植心得

uCOS51移植心得

uCOS51移植心得
移植uCOS-III到8051平台需要做以下几个步骤:
1.选择适合的uCOS版本:由于8051平台资源有限,需要选择适合的uCOS版本。

一般来说,uCOS-II更适合8051平台,因为它的代码量较小,资源要求较低。

2.编写硬件抽象层(HAL):8051平台的硬件资源和处理能力较弱,需要在uCOS上面进行硬件抽象,提供与8051硬件相关的接口函数。

这些接口函数包括时钟、中断、任务切换等操作。

3.适配任务堆栈:uCOS需要为每个任务分配一块堆栈空间,因此需要针对8051的内存结构进行适配,保证每个任务的堆栈空间不会超出8051的寄存器能力。

4.适配时钟节拍:uCOS需要一个定时器来提供时钟节拍,因此需要适配8051的定时器,并编写中断处理函数来触发uCOS的任务调度。

5.适配中断处理:8051的中断机制与其他平台有所不同,需要编写中断处理函数来处理8051的中断事件,并将其与uCOS的任务调度结合起来。

6.测试和调试:移植完成后,需要进行测试和调试,验证移植的正确性和稳定性。

在移植过程中,需要具备8051平台的硬件知识和uCOS的软件知识,同时需要具备较强的调试能力,以确保移植的成功和稳定性。

ucosiii移植原理

ucosiii移植原理

ucosiii移植原理
uCOSIII(MicroC/OS-III)是一款开源的实时操作系统(RTOS),适用于各种嵌入式系统和实时应用。

uCOSIII的移植原理主要包括以下几个方面:
1. 硬件抽象层(HAL):首先,需要针对特定硬件平台(如STM32、ARM、AVR等)编写硬件抽象层代码。

硬件抽象层的作用是将硬件平台的特性和接口抽象成统一的、易于操作的接口,以便于上层应用程序和实时操作系统进行调用。

2. 移植uCOSIII内核:将uCOSIII内核代码移植到目标硬件平台,主要包括以下几个步骤:
a. 配置uCOSIII内核:根据目标硬件平台的特性,配置uCOSIII内核的参数,如内存大小、任务数量等。

b. 修改内核代码:根据目标硬件平台的实际情况,修改内核代码,以适应不同硬件平台的需求。

这可能包括:修改内存管理代码、时钟管理代码、中断处理代码等。

c. 编写初始化代码:编写初始化代码,用于在系统启动时初始化
内核及其相关组件。

3. 移植uCOSIII的应用实例:根据项目需求,编写基于uCOSIII的应用实例。

这可能包括:编写驱动程序、编写通信协议、编写应用程序等。

4. 集成测试:将编写好的硬件抽象层、内核及应用实例集成到一起,进行系统测试和调试,确保整个系统的稳定性和可靠性。

5. 优化与调试:根据实际运行情况,对系统进行优化和调试,以提高系统的性能和资源利用率。

总之,uCOSIII的移植原理主要包括硬件抽象层的编写、uCOSIII内核的移植、应用实例的编写、集成测试以及优化与调试。

通过这些步骤,可以将uCOSIII成功移植到不同的硬件平台,并应用于各种实时系统。

Ucos移植方法一(详细篇)

Ucos移植方法一(详细篇)

Ucos移植方法一(详细篇)首先要有正确的硬件电路,包括:1.用9针串口线将PC机和9200底版连接好,注意串口线要插在标号为“P1”的串口上;2.插好9200核心板,“J2”插在靠近C18这边;3.其它跳线配置为:J13,J16要插好,JP1插在靠近C14这边,J12插在靠近C22这边;上电后超级终端的现象为:提醒:在测试状态下,上图中内核默认自动运行时间是3S,所以您要在板启动后按一下任意键,防止进入自动运行状态。

在Uboot>后输入:load 20000000后按回车现象如下:点击右键选择要下载的bin文件,过程如下图(文件目录:AT91RM9200-uCos/MainFun/basic.bin)然后点击“发送”,发送过程如下图发送完后入下图所示,在Uboot >后输入“go 20000000”后按回车,运行过程如下图这就是在超级终端上显示的效果,要说明的是,上图中红色框里的数字是连续输出的,直到关闭电源后就不连续输出。

而且在停止运行后一定要先复位在接着运行...................Ucos移植方法二其实上面是将源程序编译后的bin文件直接下载到RAM中运行的,现在利用JTAG/ICE来进行仿真,必备的条件如下:1.9针串口插在底版上标号为“P1”的串口插座上,25针并口线一头插在PC机并口,另一头插在JTAG/ICE转换器上,JTAG/ICE转换器的排线一头插在底版上标号为“J22”20Pins槽上,另一头插在JTAG/ICE转换器的的右边即靠近SN74HC244 10脚这边;2.将底版上标号为“J23”的跳线跳到靠近J5这边;3.核心板上标号“J2”的跳线跳到靠近“C18”的这边;4.底版上其它跳线配置为:J13,J16要插好,JP1插在靠近C14这边,J12插在靠近C22这边;5.9V电源线(最好用我公司提供的专用产品)插在标号为“JACK1”的DC插座上。

当您上电后ARM9调试代理软件9200超级终端的显示内容和电路板上的现象如下图所示的话就说明连接正确:⑴.底版核心板的现象为:电源指示灯(D8)核心板指示灯(LED1)亮着,网口指示灯(D5~D7)同时闪烁一下;⑵.ARM9调试代理软件9200超级终端的显示内容:利用ARM Developer Suite V 1.2软件将源程序汇编和编译(会生成一个bin 文件),如下图 文件目录为:AT91RM9200-uCos /MainFun / basic.mcp同时在超级终端里显示的内容如下图:这就是在超级终端上显示的效果,要说明的是,上图中红色框里的数字是连续输出的,直到关闭电源后就不连续输出。

ucos_II移植总结

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();}第五步:对移植好的代码进行调试。

Cortex-M3移植ucos总结

Cortex-M3移植ucos总结

Cortex-M3移植总结Cortex-M3内核浅谈在移植之前需要稍微了解Cortex-M3内核,主要需要了解一下几个内容:1Cortex-M3中的上下文切换主要使用PendSV异常来实现a)为什么可以通过PendSV异常能实现任务切换?答:因为我们使用的是systick异常来提供系统时钟,假设现在正在响应一个中断,此时一个systick异常产生,那么当前正在进行的中断必须被停止,转而去执行systick异常,而执行systick异常会产生任务切换的动作,这样便会使原中断请求被延迟,这在实时操作系统中是不允许的,另一个原因是:如果OS在中断活跃期尝试切入线程模式,将会触犯用法fault异常(因为在处理中断服务程序时处于特权级处理者模式,而应用程序是处于用户级的线程模式,从特权级处理者模式切换到线程模式会产生用法fault异常)。

而通过引入PendSV异常便可避免上述两个问题的产生,其执行过程为:当执行任务切换时会挂起一个PendSV异常,并把PendSV异常优先级置为最低,也就是说,当一个系统正在处理一个异常服务程序时产生了systick异常,那么当前中断被抢断,转而执行systick异常,而systick会执行上下文切换,由于引入了PendSV异常,所以上下文切换就是产生一个PendSV异常,并且将其优先级置为最低(255),然后退出systick,返回到被中断的ISR继续执行,执行完ISR后,由于PendSV异常被挂起,便进入PendSV异常,在PendSV异常服务中执行任务切换,这样便解决了中断被延迟的状况,以及防止了从中断活跃期切入线程模式。

详细解释见《Cortex-M3权威指南》P123其执行过程如下图所示:2中断响应序列(见《Cortex-M3权威指南》P135)需要了解Cortex-M3响应中断的所执行的三个动作1.入栈:把8个寄存器的值压入栈2.取向量:从向量表中找出对应的中断服务程序入口地址3.选择堆栈指针MSP/PSP,更新堆栈指针SP,更新链接寄存器LR,更新程序计数器PC对于移植需要特别注意的是第一个过程:入栈。

UCOSII移植过程及心得

UCOSII移植过程及心得

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任务断点LRR12R11R10R9R8R7R6R5R4R3R2R1R0CPSR还有一个栈指针SP,这个保存在任务控制块中。

UCOS的移植教程

UCOS的移植教程

移植UCOS-II 移植的概念移植的条件移植需要修改的文件所谓移植:就是使一个实时内核能在某个微处理器或微控制器上运行。

为了方便移植,大部分的µC/OS-Ⅱ代码是用C 语言写的;但仍需要用C和汇编语言写一些与处理器相关的代码,这是因为µC/OS-Ⅱ在读写处理器寄存器时只能通过汇编语言来实现。

由于µC/OS-Ⅱ在设计时就已经充分考虑了可移植性,所以µC/OS-Ⅱ的移植相对来说是比较容易的。

移植的一般性问题(条件)1.处理器的C编译器能产生可重入代码。

2.用C语言就可以打开和关闭中断。

3.处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。

4.处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。

5.处理器有将堆栈指针和其它CPU寄存器读出和存储到堆栈或内存中的指令。

什么是可重入代码●可重入的代码指的是一段代码(比如:一个函数)可以被多个任务同时调用,而不必担心会破坏数据。

●也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。

可重入代码举例程序1:可重入型函数void swap(int *x, int *y) {int temp;temp=*x;*x=*y;*y=temp;}非可重入代码举例程序2:非可重入型函数int temp;void swap(int *x, int *y){temp=*x;*x=*y;*y=temp;}返回打开/关闭中断在 COS-II中,可以通过:OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()宏来控制系统关闭或者打开中断。

这需要处理器的支持。

在ARM7TDMI的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。

处理器支持中断并且能产生定时中断● COS-II是通过处理器产生的定时器的中断来实现多任务之间的调度的。

UCOS移植

UCOS移植

关于ucos的移植移植流程主要如下:一,准备工作1,下载UCOS的源代码:这些资料网上都有很多,可自行下载。

(见上传的名为Ucos-II源代码的压缩文件)2,下载stm32固件:这里我们采用火牛开发板中自带的v3.4函数库。

(见上传的名为STM32固件库的压缩文件)3,了解ucos的内核结构:ucos的内核结构如下图所示现在介绍各个方框内的部分。

从上往下看,可以看到应用程序在整个μC/OS-II 的构架的最上方。

这样非常方便应用程序的编写。

中间层左边方框内的这些代码是与处理器及其他硬件都无关的代码。

中间层右边方框里列出的实际上是两个头文件。

最下面的一个方框列出的是与处理器相关的代码,这部分是移植的主要部分,主要修改这三个文件。

二,建立工程首先,在电脑中的合适位置,建立一个文件夹,作为工程所有文件存放文件夹(如myproject)。

1,在myproject文件夹下新建一文件夹,命名为Libraries,用于存放STM32的库函数,把准备工作中下载的Stm32的库函数复制到此文件夹下。

2,myprojec文件夹下新建另外一个文件夹,命名为uCOS-II,然后将ucos的源代码复制到此文件夹下,并且这些文件都不需要修改。

3,然后在myproject文件夹下新建一文件夹,命名为Ports,然后将需要修改的三个文件(os_cpu_c.c,os_cpu.h,os_cpu_a.asm)拷贝到此文件夹下。

4,然后在myproject文件夹下新建一文件夹,命名为App,此文件夹放工程文件和主程序(main)。

这样工程基本建成,然后就是函数修改部分。

三,移植修改移植μC/OS-II 只需要修改OS_CPU.H,OS_CPU_A.ASM 和OS_CPU_C.C 这三个文件,现在逐步介绍这三个文件中需要修改的部分。

1,内核头文件(OS_CPU.H)在OS_CPU.H 中,主要声明了一些与微处理器相关的常量、宏和typedef。

UCOS移植过程

UCOS移植过程

Uc/OS移植过程1、UCOS源码的准备.从网站/page/home。

2、源代码分为三个部分:A和平台无关的源码;B和硬件密切相关部分(操作CPU寄存器); C一个配置文件OS_CFG.H(根据该配置文件决定程序的任务数量,所使用的函数等)。

根据它们的功能可以将它们分放在三个地方:A单独放在一个文件夹中OS_CORE,将此部分属性设置为只读,无需修改该部分代码,在MDK工程管理中单独用一个文件夹存放;B部分和硬件平台相关部分,放在另一个文件夹中命名为UCOS/PORT,该部分包含三个文件OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C;C部分OS_CFG.H该文件可以放在用户应用程序文件夹,该配置文件用于配置应用程序要使用内核的那些函数,使用多少个任务等。

3、按照普通工程建立的方法建立MDK工程,只不过要加入步骤2的两个文件夹。

4、修改文件OS_CPU.H#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT#else#define OS_CPU_EXT extern#endifTypedef unsigned char BOOLEANTypedef unsigned char INT8UTypedef unsigned char INT8STypedef unsigned short INT16UTypedef unsigned short INT32UTypedef unsigned int INT32UTypedef unsigned int INT32STypedef float FP32Typedef double FP64定义任务堆栈数据类型,每个任务都有自己的任务栈,因STM32是32位的,所以定义为unsgned intTypedef unsigned int OS_STK定义CPU状态寄存器的类型,因CM3的状态寄存器(Xpsr)是32位的,所以Typedef unsigned int OS_CPU_SR#define OS_CRITICAL_METHOD 3#if OS_CRITICAL_METHOD==3进入中断的处理#define OS_ENTER_CRITICAL() {cpu_sr=OS_CPU_SR_Save();}出中断的处理#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);} #endif定义CPU状态寄存器的保存方法,即使用临界代码的方法一共有三种(1、OS_CRITICAL_METHOD==1 。

UCOS-II在51单片机上的移植

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。

ucos-ii(2.91)在LPC17xx上移植个人总结

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在S08AW60上的移植

ucos在S08AW60上的移植

ucos在S08AW60上的移植Ucos2.86系统在S08AW60上的移植1打开CodeWorrior6.3新建工程,点击Create New Project点击完成,一个新的工程文件就建立好了。

2将新建的空工程编译并下载到单片机中,然后退回到编程界面此步很重要,不要忽略3将下载好的Ucos 解压后拷贝到你的工程sources 文件夹下4Ucos 解压后的文件夹因为S08AW60RAM 有限,下载的Ucos 版本不要过高5将鼠标置于Ucos2.86文件夹上,右键单击后在出现的菜单中选择Add files,找到工程文件夹下的sources文件,打开里面的Ucos2.86文件夹后,找到并将ucos_ii.c和ucos_ii.h添加进来新建PORT文件夹如下图所示6新建Includes.h os_cfg.h os_cpu.h os_cpu_c.c四个文件,保存在工程下的sources文件夹下并添加到PORT中至此为止,ucos框架基本建立完成,下面,构建一下用户程序框架建立sci.c key.c key.h led.c led.h空文件如上图所示7将一下程序拷入到各个空文件中Main.c*************************************************************** ******************* #include/*for EnableInterrupts macro*/ #include"derivative.h"/*include peripheral declarations*/#include"includes.h"#include"LED.h"#include"key.h"int i,j;typedef unsigned char TASKDATA;//定义新的类型名#define TASK_STK_SIZE50//定义堆栈大小OS_STK Task1Stk[TASK_STK_SIZE];//声明3个任务数组OS_STK Task3Stk[TASK_STK_SIZE];OS_STK Task2Stk[TASK_STK_SIZE];OS_STK Task4Stk[TASK_STK_SIZE];OS_STK TaskStartStk[TASK_STK_SIZE];OS_EVENT*Semprintp;//声明一个信号量INT8U err;TASKDATA TaskStartData;TASKDATA Task1Data;TASKDATA Task2Data;TASKDATA Task3Data;TASKDATA Task4Data;void mcuinit(void);//cpu初始化void sciinit(void);void LED_Init(void);//串口初始化void outchar(unsigned char data);//以查询方式从串口发送一个字符void sendstr(unsigned char*p);//从串口发送字符串//声明3个任务函数void Task1(TASKDATA*pdata);void Task2(TASKDATA*pdata);void Task3(TASKDATA*pdata);void Task4(TASKDATA*pdata);void TaskStart(TASKDATA*pdata);//主函数int main(void){EnableInterrupts;mcuinit();sciinit();InitTimer();outchar('@');OSInit();LED_Init();KEY_Init();Semprintp=OSSemCreate(1);OSTaskCreate(Task1,(void*)0,(void*)&Task1Stk[TASK_STK_SIZ E-1],11);OSTaskCreate(Task2,(void*)0,(void*)&Task2Stk[TASK_STK_SIZE-1],9);OSTaskCreate(Task4,(void*)0,(void*)&Task4Stk[TASK_STK_SIZE-1],12);OSTaskCreate(Task3,(void*)0,(void*)&Task3Stk[TASK_STK_SIZ E-1],6);OSTaskCreate(TaskStart,(void*)0,(void*)&TaskStartStk[TASK_ STK_SIZE-1],5);//task是指向任务代码的指针?//Pdata指向一个数据结构,该结构用来在建立任务时向任务传递参数//ptos为指向任务堆栈栈顶的指针。

小白30分钟学会移植操作系统-UCOS系列一

小白30分钟学会移植操作系统-UCOS系列一

小白30分钟学会移植操作系统-UCOS系列一在开始前,给大家一个问题:为什么我们需要操作系统?就像最开始学C编程时,老师告诉我们,指针很重要,那时你肯定有一个大的疑问,指针到底有什么好?心里一直犯嘀咕着:不用指针不一样把程序编出来了?现在想想看c语言没了指针,是不是寸步难行呢。

回到正题,我们到底为什么需要操作系统?这一篇,主要讲解理论层面的知识,忍住,看下去。

后续将会进行傻瓜式移植操作系统的教程。

准你能学会。

前言:首先比较主流的操作系统有UCOSII、FREERTOS、LINUX等,UCOSII的资料相对比其余的两个操作系统的资料是多很多的。

在这里选择 UCOSII/UCOSIII 来讲解。

1、操作系统的作用操作系统是计算机硬件系统与应用程序之间的接口,应用程序设计人员只是以操作系统层为基础使用计算机系统,所以程序设计人员看到和使用的只是一些由计算机操作系统所提供的函数API,至于操作系统的这些底层函数是怎么实现的,作为一个应用开发人员是不需要管的。

2、嵌入式系统的特点(1)专用性强:嵌入式系统通常是面向某个特定的应用的,所以嵌入式系统的硬件是特定用户群来设计的(2)可以裁剪:Linux系统有很多网络协议栈之类的,有些做个数码相框的,没有必要的话,那么直接把那段源码去掉也是可以的(3)实时性与可靠性:所谓的实时性不是指,你代码写的东西必须要马上执行,而是你写的代码可以在合适的时间中执行,因为操作系统有很多机制,比如资源的抢占,优先级低的任务是不可能实现。

【重点理解实时性】3、嵌入式实时操作系统的基本功能:(1)内存管理:内存管理主要是动态内存的管理,当应用程序需要使用内存的时候,可以利用操作系统所提供内存分配函数来获得足够的内存空间。

动态内存就是指malloc、free函数的分配,就是从堆里面拿内存,因为我们本来嵌入式系统的内存分配就比较少,所以这里很关键。

(2)多任务管理:裸机就是一个单任务的前后台的程序,就是一个任务加上中断的机器的实现方法。

uCOS-II在嵌入式平台的移植技巧

uCOS-II在嵌入式平台的移植技巧
#define O S _ E N T E R _ C R I T I C A L () Disable_int()
#define OS_EXIT_CRITICAL() Enable_int()
Disable_int和Enable_int是用汇编 语言编写的两个函数。在这里使用了控 制状态寄存器( C S R ) 的一个特性—— C S R 中除了控制全局中断的 G I E 位之 外,还有一个 PGIE 位,可用于保存之前
└─ TI_C6711 // 系统核心
=(OS_STK*)
├─ CCS // 开发工具
DSP_C6x_GetCurrentSP(); // 服务

OS_CPU.H
函数


// 获取当前 SP 的值
OS_CPU_A.ASM
// 允许中断嵌套 则在此处开中断

----
S T W B4,*+SP(4) / /
a=0
NOP 2
//-----
-----
B IRP // 中断返回 L D W *++SP(8),B4/ / 出栈 NOP 4 与前一段代码相比,对于中断函数 的编译,有两点不同: ● 函数的返回地址不再使用B3 寄存 器,相应地也无需将 B3 入栈。(IRP 寄 存器能自动保存中断发生时的程序地址) ● 编译器会自动统计中断函数所用 到的寄存器,从而在中断一开始将他们 全部入栈保护——例如上述程序段中, 只用到了 B4 寄存器。
函数

(类似 80x86 版本的 PC.C 和 PC.H) C 语言开发工具
在 C C S 中编译后生成的 A S M 代码
系统核心
无论所使用的系统核心是什么,C 为:
无 论 项 目 所 采 用 的 系 统 核 心 是 语言开发工具对于μC/OS-II 是必不可

uCOS-II在arm上的移植

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在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-ii在pc上的移植

ucos-ii在pc上的移植

ucos-ii在pc上的移植一、安装工作1.安装Borland C++。

我安装的是BC4.5。

2.安装TASM5.0汇编编译器。

(注意解压后放在哪了)3.右键单击我的电脑--->属性--->高级--->环境变量--->弹出“环境变量”对话框。

4.在“用户变量”列表中找到path,在变量值末尾添加“;C:\TASM\BIN;”二、uCOS/II 相关文件说明1.CPU移植相关程序OS_CPU_A.ASMOS_CPU_C.COS_CPU.H2.uCOS-II核心程序uCOS_II.HuCOS_II.COS_CORE.COS_TASK.COS_TIME.COS_FLAG.COS_MBOX.COS_MEM.COS_MUTEX.COS_Q.COS_SEM.C3.PC相关程序PC.CPC.H4.实验程序INCLUDES.HOS_CFG.HTEST.C5.需要编译的程序有五个,如下实验程序:TEST.CCPU程序:OS_CPU_C.C、OS_CPU_A.ASM(CPU汇编程序)uCOS_II程序:uCOS_II.CPC机程序:PC.C三、准备工作为了尽量不改动原来的文件,我只进行文件夹移动。

我把测试的工程建在F:\ucos-tst\project,ucos-tst下还有其他三个文件夹:1.F:\ucos-tst\source (放置实验程序INCLUDES.H OS_CFG.H TEST.C)2.F:\ucos-tst\obj (放置工程临时文件)3.F:\ucos-tst\final (放置可执行文件)将SOFTWARE 复制到F盘目录下SOFTWARE 提供CPU程序、uCOS-II核心程序、PC相关程序。

之所以要放在F盘下是因为includes.h 中有这么一句#include"\software\ucos-ii\ix86l\bc31\os_cpu.h",这句的意思是在当前盘符下查找文件夹software 中的内容。

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
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C/OS-II实时操作系统在嵌入式平台上进行移植的一般方法和技巧清华大学曾鸣引言实时操作系统的使用,能够简化嵌入式系统的应用开发,有效地确保稳定性和可靠性,便于维护和二次开发。

µC/OS-II是一个基于抢占式的实时多任务内核,可固化、可剪裁、具有高稳定性和可靠性,除此以外,µC/OS-II的鲜明特点就是源码公开,便于移植和维护。

在µC/OS-II官方的主页上可以查找到一个比较全面的移植范例列表。

但是,在实际的开发项目中,仍然没有针对项目所采用芯片或开发工具的合适版本。

那么,不妨自己根据需要进行移植。

本文则以在TMS320C6711 DSP上的移植过程为例,分析了µC/OS-II在嵌入式开发平台上进行移植的一般方法和技巧。

µC/OS-II移植的基本步骤在选定了系统平台和开发工具之后,进行µC/OS-II的移植工作,一般需要遵循以下的几个步骤:●深入了解所采用的系统核心●分析所采用的C语言开发工具的特点●编写移植代码●进行移植的测试●针对项目的开发平台,封装服务函数(类似80x86版本的PC.C和PC.H)系统核心无论项目所采用的系统核心是MCU、DSP、MPU,进行µC/OS-II的移植时,所需要关注的细节都是相近的。

首先,是芯片的中断处理机制,如何开启、屏蔽中断,可否保存前一次中断状态等。

还有,芯片是否有软中断或是陷阱指令,又是如何触发的。

此外,还需关注系统对于存储器的使用机制,诸如内存的地址空间,堆栈的增长方向,有无批量压栈的指令等。

在本例中,使用的是TMS320C6711 DSP。

这是TI公司6000系列中的一款浮点型号,由于其时钟频率非常高,且采用了超常指令字(VLIW)结构、类RISC指令集、多级流水等技术,所以运算性能相当强大,在通信设备、图像处理、医疗仪器等方面都有着广泛的应用。

在C6711中,中断有3种类型,即复位、不可屏蔽中断(NMI)和可屏蔽中断(INT4-INT15)。

可屏蔽中断由CSR寄存器控制全局使能,此外也可用IER寄存器分别置位使能。

而在C6711中并没有软中断机制,所以µC/OS-II的任务切换需要编写一个专门的函数实现。

此外,C6711也没有专门的中断返回指令、批量压栈指令,所以相应的任务切换代码均需编程完成。

由于采用了类RISC核心,C6711的内核结构中,只有A0-A15和B0-B15这两组32bit的通用寄存器。

C语言开发工具无论所使用的系统核心是什么,C语言开发工具对于µC/OS-II是必不可少的。

最简单的信息可以从开发工具的手册中查找,比如:C语言各种数据类型分别编译为多少字节;是否支持嵌入式汇编,格式要求怎样;是否支持“interrupt”非标准关键字声明的中断函数;是否支持汇编代码列表(list)功能,等等。

上述的这样一些特性,会给嵌入式的开发带来很多便利。

TI的C语言开发工具CCS for C6000就包含上述的所有功能。

而在此基础上,可以进一步地弄清开发工具的一些技术细节,以便进行之后真正的移植工作。

首先,开启C编译器的“汇编代码列表(list)”功能,这样编译器就会为每个C语言源文件生成其对应的汇编代码文件。

在CCS开发环境中的方法是:在菜单“/Project/Build options”的“Feedback”栏中选择“Interlisting:Opt/C and ASM(-s)”;或者,也可以直接在CCS的C编译命令行中加上“-s”参数。

然后分别编写几个简单的函数进行编译,比较C源代码和编译生成的汇编代码。

例如:void FUNC_TEMP (void){Func_tmp2(); //调用任一个函数}在CCS中编译后生成的ASM代码为:.asg B15, SP // 宏定义_FUNC_TEMP:STW B3,*SP--(8) // 入栈NOP 2CALL _ Func_tmp2 //-----------MVKL BACK, B3 // 函数调用MVKH BACK, B3 //-----------NOP 3BACK: LDW *++SP(8),B3 // 出栈NOP 4RET B3 // 函数返回NOP 5由此可见,在CCS编译器的规则中,B15寄存器被用作堆栈指针,使用通用存取指令进行栈操作,而且堆栈指针必须以8字节为单位改变。

此外,B3寄存器被用来保存函数调用时的返回地址,在函数执行之前需要入栈保护,直到函数返回前再出栈。

当然,CCS的C编译器对于每个通用寄存器都有约定的用途,但对于µC/OS-II的移植来说,了解以上信息就足够了。

最后,再编写一个用“interrupt”关键字声明的函数:interrupt void ISR_TEMP (void){int a;a=0;}生成的ASM代码为:_ISR_TEMP:STW B4,*SP--(8) // 入栈NOP 2ZERO B4 //---------STW B4,*+SP(4) // a=0NOP 2 //----------B IRP // 中断返回LDW *++SP(8),B4 // 出栈NOP 4与前一段代码相比,对于中断函数的编译,有两点不同:●函数的返回地址不再使用B3寄存器,相应地也无需将B3入栈。

(IRP寄存器能自动保存中断发生时的程序地址)●编译器会自动统计中断函数所用到的寄存器,从而在中断一开始将他们全部入栈保护——例如上述程序段中,只用到了B4寄存器。

编写移植代码在深入了解了系统核心与开发工具的基础上,真正编写移植代码的工作就相对比较简单了。

µC/OS-II自身的代码绝大部分都是用ANSI C编写的,而且代码的层次结构十分干净,与平台相关的移植代码仅仅存在于OS_CPU_A.ASM、OS_CPU_C.C以及OS_CPU.H这三个文件当中。

在移植的时候,结合前面两个步骤中已经掌握的信息,基本上按照《嵌入式实时操作系统µC/OS-II》一书的相关章节的指导来做就可以了。

但是,由于系统核心、开发工具的千差万别,在实际项目中,一般都会有一些处理方法上的不同,需要特别注意。

以C6711的移植为例:●中断的开启和屏蔽的两个宏定义为:#define OS_ENTER_CRITICAL() Disable_int()#define OS_EXIT_CRITICAL() Enable_int()Disable_int和Enable_int是用汇编语言编写的两个函数。

在这里使用了控制状态寄存器(CSR)的一个特性——CSR中除了控制全局中断的GIE位之外,还有一个PGIE位,可用于保存之前的GIE状态。

因此在Disable_int中先将GIE的值写入PGIE,然后再将GIE写0,屏蔽中断。

而在Enable_int中则从PGIE读出值,写入GIE,从而回复到之前的中断设置。

这样,就可以避免使用这两个宏而意外改变了系统的中断状态——此外,也没有使用堆栈或局部变量,比原作者推荐的方法要好。

●任务的切换:前文说过,C6711中没有软中断机制,所以任务的切换需要用汇编语言自行编写一个函数_OSCtxSw来实现,并且#define OS_TASK_SW() OSCtxSw()在C6711中需要入栈保护的寄存器包括A0-A15、B0-B15、CSR、IER、IRP和AMR,这些再加上当前的程序地址构成一个存储帧,需要入栈保存。

_OSCtxSw函数中,需要像发生了一次中断那样,将上述存储帧入栈,然后获取被激活任务的TCB指针,将其存储帧的内容弹出,从而完成任务切换。

需要特别注意的是,在这里OS_TASK_SW是作为函数调用的,所以如前文所述,调用时的当前程序地址是保存在B3寄存器中的,这也就是任务重新激活时的返回地址。

●中断的编写:如前文所述,如果用“interrupt”关键字声明函数,CCS在编译时,会自动将该函数中使用到的寄存器入栈、出栈保护。

但是,这会导致各种中断发生时,出入栈的内容各不相同。

这对于µC/OS-II是会引起严重错误的。

因为µC/OS-II要求中断发生时的入栈操作使用和发生任务切换时完全一样的存储帧结构。

因此,在移植时、基于µC/OS-II进行开发时,都不应当使用“interrupt”关键字,而应用如下结构编写中断函数:void OSTickISR (void){DSP_C6x_Save(); // 服务函数,入栈OSIntEnter();if (OSIntNesting == 1) // v2.51版本新增加{OSTCBCur->OSTCBStkPtr=(OS_STK*) DSP_C6x_GetCurrentSP(); // 服务函数} // 获取当前SP的值// 允许中断嵌套则在此处开中断OSTimeTick();OSIntExit();DSP_C6x_Resume(); // 服务函数,出栈}DSP_C6x_Save和DSP_C6x_Resume是两个服务函数,分别完成中断的出、入栈操作。

它们与OS_TASK_SW函数的区别在于:中断发生时的当前程序地址是自动保存在IRP寄存器的,应将其作为任务返回地址,而不再是B3。

此外,DSP_C6x_Resume是一个永远不会返回的函数,在将所有内容出栈后,它就直接跳转回到中断发生前的程序地址处,继续执行。

进行移植的测试在编写完了所有的移植代码之后,就可以编写几个简单的任务程序进行测试了,大体上可以分三个步骤来进行,相关资料比较详尽,这里就不多作赘述了。

封装服务函数最后这个步骤,往往是容易被忽视的,但对于保持项目代码的简洁、易维护有很重要的意义。

µC/OS-II的原作者强烈建议将源代码分路径进行存储,例如本文例子中的所有源代码就应按如下路径结构存储:\uCOS-II├─SOURCE // 平台无关代码│ OS_CORE.C│ ......└─TI_C6711 // 系统核心├─CCS // 开发工具│ OS_CPU.H│ OS_CPU_A.ASM│ OS_CPU_C.C│├─ DSP_C6x_Service // 服务函数│ DSP_C6x_ Service.H│ DSP_C6x_ Service.ASM│└─ TEST // 具体的开发项目代码OS_CFG.HINCLUDES.HTEST.C ......如上,DSP_C6x_Service中的服务函数,类似于原作者提供的80x86版本中的PC.C和PC.H文件。

在本文的例子中,服务函数则包括了上文提及的中断相关函数,以及系统初始化函数DSP_C6x_SystemInit()和时钟初始化函数DSP_C6x_TimerInit()等。

相关文档
最新文档