五、ucos-II的移植-智能嵌入技术开发与实践-佟国香-清华大学出版社_第1页
五、ucos-II的移植-智能嵌入技术开发与实践-佟国香-清华大学出版社_第2页
五、ucos-II的移植-智能嵌入技术开发与实践-佟国香-清华大学出版社_第3页
五、ucos-II的移植-智能嵌入技术开发与实践-佟国香-清华大学出版社_第4页
五、ucos-II的移植-智能嵌入技术开发与实践-佟国香-清华大学出版社_第5页
已阅读5页,还剩84页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

嵌入式系统设计与实例开发——ARM与C/OS-Ⅱ第五讲实时嵌入式操作系统C/OS-Ⅱ的移植移植:程序或应用软件从一个系统平台移动另一个系统平台,其功能、结构、执行结果保持不变。移植的目的:1、硬件平台的升级2、实现软件重用3、实现软件/硬件并行设计移植的要求:1、移植对象具有硬件无关性2、移植对象具有系统无关性3、移植对象采用标准语言编程一、移植的概念和目的二、嵌入式操作系统的移植——μC/OS-IIμC/OS-II的软硬件体系结构μC/OS-II的移植需要满足的要求μC/OS-II移植的主要工作BSP的概念及应用2.1μC/OS-II的软硬件体系结构

2.2μC/OS-II的移植需要满足以下要求(1)处理器的C编译器可以产生可重入代码;(2)可以使用C调用进入和退出CriticalCode(临界区代码);(3)处理器必须支持硬件中断,并且需要一个定时中断源;(4)处理器需要能够容纳一定数据的硬件堆栈;(5)处理器需要有能够在CPU寄存器与内存和堆栈交换数据的指令。

打开/关闭中断在

COS-II中,可以通过:OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()宏来控制系统关闭或者打开中断。这需要处理器的支持。在处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。处理器支持中断并且

能产生定时中断

COS-II是通过处理器产生的定时器的中断来实现多任务之间的调度的。CortexM3可以产生定时器中断。本系统工作在80MHz的主频下,PCLK0=PCLK1=PCLK2=40MHz.定时器的中断的频率为50Hz。也就是系统的响应时间为20ms。处理器支持硬件堆栈

COS-II进行任务调度的时候,会把当前任务的CPU寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是

COS-II多任务调度的基础。处理器中有专门的指令处理堆栈,可以灵活的使用堆栈。移植

COS-II满足的条件处理器的C编译器能产生可重入代码在程序中可以打开或者关闭中断处理器支持中断,并且能产生定时中断(通常在10—1000Hz之间)本系统选择50Hz。处理器支持能够容纳一定量数据的硬件堆栈处理器有将堆栈指针和其他CPU寄存器存储和读出到堆栈(或者内存)的指令2.3μC/OS-II移植的主要工作处理器和编译器相关代码μC/OS-II的BSP的编写

移植文件及目录示例可以采用如下目录结构存放移植的文件:所有的移植实例放在用户硬盘的\SOFTWARE\μCOS-Ⅱ目录下。各个微处理器或微控制器的移植源代码必须在以下两个或三个文件中找到:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM。汇编语言文件OS_CPU_A.ASM是可选择的,因为某些C编译器允许用户在C语言中插入汇编语言,所以用户可以将所需的汇编语言代码直接放到OS_CPU_C.C中。放置移植实例的目录决定于用户所用的处理器,例如在下面的表中所示的放置不同移植实例的目录结构。注意,各个目录虽然针对完全不同的目标处理器,但都包括了相同的文件名。Intel/AMD80186\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.CMotorola68HC11\SOFTWARE\uCOS-II\68HC11\OS_CPU.H\OS_CPU_A.ASM\OS_CPU_C.C

COS-II在ARM7上的移植 所谓移植,是指使一个实时操作系统能够在某个微处理器平台上运行。

COS-II的主要代码都是由标准的C语言写成的,移植方便。但仍需要用C和汇编语言写一些与处理器相关的代码,这是因为μC/OS-Ⅱ在读写处理器寄存器时只能通过汇编语言来实现。移植工作uC/OS-II实际上可以简单地看作是一个多任务的调度器,在这个任务调度器之上完善并添加了和多任务操作系统相关的一些系统服务,如信号量、邮箱等。它的90%的代码都是用C语言写的,因此只要有相应的C语言编译器,基本上就可以直接移植到特定处理器上,这也是uC/OS-II具有良好的可移植性的原因。移植工作的绝大部分都集中在多任务切换的实现上,因为这部分代码主要是用来保存和恢复处理器现场(即相关寄存器),因此不能用C语言,只能使用特定的处理器汇编语言完成。uC/OS-II的全部源代码量大约是6000-7000行,一共有15个文件。将uC/OS-II移植到ARM处理器上,需要完成的工作也非常简单,只需要修改三个和ARM体系结构相关的文件,代码量大约是500行。移植工作 如果处理器和编译器满足了μC/OS-Ⅱ的要求,并且已经有了必要工具。移植工作包括以下几个内容:(1)用#define设置一些常量的值(OS_CPU.H)(2)声明10个数据类型(OS_CPU.H)(3)用#define声明三个宏(OS_CPU.H)(4)用C语言编写六个简单的函数(OS_CPU_C.C)(5)编写四个汇编语言函数(OS_CPU_A.ASM)1、OS_CPU.H

(1)数据类型定义

这部分的修改是和所用的编译器相关的,不同的编译器会使用不同的字节长度来表示同一数据类型,比如int,同样在x86平台上,如果用GNU的gcc编译器,则编译为4bytes,而使用MSVC++则编译为2bytes。我们这里使用的是GNU的arm-elf-gcc,这是一个免费并且开放源码的编译器。相关的数据类型的定义如下:程序清单 OS_CPU.H.#ifdefOS_CPU_GLOBALS#defineOS_CPU_EXT#else#defineOS_CPU_EXTextern#endif1、OS_CPU.H

/**************数据类型*****************************(与编译器相关)**/***************************************************typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;/*无符号8位整数*/typedefsignedcharINT8S;/*有符号8位整数*/typedefunsignedintINT16U;/*无符号16位整数*/typedefsignedintINT16S;/*有符号16位整数*/typedefunsignedlongINT32U;/*无符号32位整数*/typedefsignedlongINT32S;/*有符号32位整数*/typedeffloatFP32;/*单精度浮点数*/typedefdoubleFP64;/*双精度浮点数*/1、OS_CPU.H

堆栈单位

因为处理器现场的寄存器在任务切换时都将会保存在当前运行任务的堆栈中,所以OS_STK数据类型应该是和处理器的寄存器长度一致的。typedefunsignedintOS_STK;/*堆栈入口宽度为16位*/堆栈增长方向

堆栈由高地址向低地址增长,这个也是和编译器有关的,当进行函数调用时,入口参数和返回地址一般都会保存在当前任务的堆栈中,编译器的编译选项和由此生成的堆栈指令就会决定堆栈的增长方向。#defineOS_STK_GROWTH1/*定义堆栈的增长方向 :1=向下,0=向上*/1、OS_CPU.H

(2)宏定义 包括开关中断的宏定义,以及进行任务切换的宏定义。/****************与处理器相关的代码*******************/#defineOS_ENTER_CRITICAL()???/*禁止中断*/#defineOS_EXIT_CRITICAL()???/*允许中断*/#defineOS_TASK_SW()??? 1、OS_CPU.H

OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()

方法1 执行这两个宏的第一个也是最简单的方法是在OS_ENTER_CRITICAL()中调用处理器指令来禁止中断,以及在OS_EXIT_CRITICAL()中调用允许中断指令。1、OS_CPU.H

缺点:如果在禁止中断的情况下调用μC/OS-Ⅱ函数,从μC/OS-Ⅱ函数返回的时候要求中断状态还是禁止时的状态。在这种情况下,这种执行方法可能是不够的。方法2 执行OS_ENTER_CRITICAL()的第二个方法是先将中断禁止状态保存到堆栈中,然后禁止中断。而执行OS_EXIT_CRITICAL()的时候只是从堆栈中恢复中断状态。如果用这个方法的话,不管用户是在中断禁止还是允许的情况下调用μC/OS-Ⅱ服务,在整个调用过程中都不会改变中断状态。1、OS_CPU.H

举例:方法1:#defineOS_ENTER_CRITICAL()asmCLI#defineOS_EXIT_CRITICAL()asmSTI CLI和SCI指令都会在两个时钟周期内被马上执行(总共为四个周期)。为了保持中断状态,用户需要用下面的方法来执行宏:1、OS_CPU.H

方法2:#defineOS_ENTER_CRITICAL()asmPUSHF;CLI#defineOS_EXIT_CRITICAL()asmPOPF 在这种情况下,OS_ENTER_CRITICAL()需要12个时钟周期,而OS_EXIT_CRITICAL()需要另外的8个时钟周期(总共有20个周期)。1、OS_CPU.H

(3)OS_STK_GROWTH 绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是某些处理器是用另外一种方式工作的。μC/OS-Ⅱ被设计成两种情况都可以处理,只要在结构常量OS_STK_GROWTH中指定堆栈的生长方式(如下所示)就可以了 置OS_STK_GROWTH为0表示堆栈从下往上长。 置OS_STK_GROWTH为1表示堆栈从上往下长。1、OS_CPU.H

(4)OS_TASK_SW() OS_TASK_SW()是一个宏,它是在μC/OS-Ⅱ从低优先级任务切换到最高优先级任务时被调用的。OS_TASK_SW()总是在任务级代码中被调用的。另一个函数OSIntExit()被用来在ISR使得更高优先级任务处于就绪状态时,执行任务切换功能。任务切换只是简单的将处理器寄存器保存到将被挂起的任务的堆栈中,并将更高优先级的任务从堆栈中恢复出来。#defineOS_TASK_SW()OSCtxSw()2、OS_CPU_C.C

2、OS_CPU_C.C

μC/OS-Ⅱ的移植实例要求用户编写六个简单的C函数: OSTaskStkInit() OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskStatHook() OSTimeTickHook() 唯一必要的函数是OSTaskStkInit(),其它五个函数必须声明但没必要包含代码。2、OS_CPU_C.C

任务堆栈初始化

这里涉及到任务初始化时的一个堆栈设计,也就是在堆栈增长方向上如何定义每个需要保存的寄存器位置,在ARM体系结构下,任务堆栈空间由高至低依次将保存着pc、lr、r12、r11、r10、…r1、r0、CPSR、SPSR。低地址pc lr R12 R11 … ... R1 R0 CPSR SPSR 增长方向高地址2、OS_CPU_C.C

2、OS_CPU_C.C

这里需要说明两点:一是当前任务堆栈初始化完成后,OSTaskStkInit返回新的堆栈指针stk,在OSTaskCreate()执行时将会调用OSTaskStkInit的初始化过程,然后通过OSTCBInit()函数调用,将返回的sp指针保存到该任务的TCB块中。二是初始状态的堆栈其实是模拟了一次中断发生后的堆栈结构,因为任务被创建后并不是直接就获得执行的,而是通过OSSched()函数进行调度分配,满足执行条件后才能获得执行的。为了使这个调度简单一致,就预先将该任务的pc指针和返回地址lr都指向函数入口,以便被调度时从堆栈中恢复刚开始运行时的处理器现场。2、OS_CPU_C.C

系统hook函数

此外,在这个文件里面还需要实现几个操作系统规定的hook函数,如下:OSSTaskCreateHook()OSTaskDelHook()OSTaskSwHook()OSTaskStatHook()OSTimeTickHook() 如果没有特殊需求,则只需要简单地将它们都实现为空函数就可以了。3、OS_CPU_A.ASM

μC/OS-Ⅱ的移植实例要求用户编写四个简单的汇编语言函数: OSStartHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR() 如果用户的编译器支持插入汇编语言代码的话,用户就可以将所有与处理器相关的代码放到OS_CPU_C.C文件中,而不必再拥有一些分散的汇编语言文件。3、OS_CPU_A.ASM

(1)OSStartHighRdy()

此函数是在OSStart()多任务启动之后,负责从最高优先级任务的TCB控制块中获得该任务的堆栈指针sp,通过sp依次将cpu现场恢复,这时系统就将控制权交给用户创建的该任务进程,直到该任务被阻塞或者被其他更高优先级的任务抢占cpu。该函数仅仅在多任务启动时被执行一次,用来启动第一个,也就是最高优先级的任务执行,之后多任务的调度和切换就是由OSCtxSw()函数来实现。3、OS_CPU_A.ASM

voidOSStartHighRdy(void){CalluserdefinableOSTaskSwHook();Getthestackpointerofthetasktoresume:Stackpointer=OSTCBHighRdy->OSTCBStkPtr;OSRunning=TRUE;Restoreallprocessorregistersfromthenewtask'sstack;Executeareturnfrominterruptinstruction;} OSStartHighRdy()必须调用OSTaskSwHook(),OSTaskSwHook()可以通过检查OSRunning来知道是OSStartHighRdy()在调用它(OSRunning为FALSE)还是正常的任务切换在调用它(OSRunning为TRUE).3、OS_CPU_A.ASM

(2)OSCtxSw()

任务级的上下文切换,它是当任务因为被阻塞而主动请求cpu调度时被执行,由于此时的任务切换都是在非异常模式下进行的,因此区别于中断级别的任务切换。它的工作是先将当前任务的cpu现场保存到该任务堆栈中,然后获得最高优先级任务的堆栈指针,从该堆栈中恢复此任务的cpu现场,使之继续执行。这样就完成了一次任务切换。3、OS_CPU_A.ASM

voidOSCtxSw(void){

保存处理器寄存器;

将当前任务的堆栈指针保存到当前任务的OS_TCB中:OSTCBCur->OSTCBStkPtr=Stackpointer;

调用用户定义的OSTaskSwHook();OSTCBCur=OSTCBHighRdy; OSPrioCur=OSPrioHighRdy;得到需要恢复的任务的堆栈指针:Stackpointer=OSTCBHighRdy->OSTCBStkPtr;

将所有处理器寄存器从新任务的堆栈中恢复出来;

执行中断返回指令;}3、OS_CPU_A.ASM

(3)OSIntCtxSw()

中断级的任务切换,它是在时钟中断ISR(中断服务例程)中发现有高优先级任务等待的时钟信号到来,则需要在中断退出后并不返回被中断任务,而是直接调度就绪的高优先级任务执行。这样做的目的主要是能够尽快地让高优先级的任务得到响应,保证系统的实时性能。它的原理基本上与任务级的切换相同,但是由于进入中断时已经保存过了被中断任务的cpu现场,因此这里就不用再进行类似的操作,只需要对堆栈指针做相应的调整。3、OS_CPU_A.ASM

voidOSIntCtxSw(void){

调整堆栈指针来去掉在调用:OSIntExit(),OSIntCtxSw()过程中压入堆栈的多余内容;

将当前任务堆栈指针保存到当前任务的OS_TCB中:OSTCBCur->OSTCBStkPtr=堆栈指针;

调用用户定义的OSTaskSwHook();OSTCBCur=OSTCBHighRdy;OSPrioCur=OSPrioHighRdy;

得到需要恢复的任务的堆栈指针:

堆栈指针=OSTCBHighRdy->OSTCBStkPtr;

将所有处理器寄存器从新任务的堆栈中恢复出来;

执行中断返回指令;}3、OS_CPU_A.ASM

(4)OSTickISR()

时钟中断处理函数,它的主要任务是负责处理时钟中断,调用系统实现的OSTimeTick函数,如果有等待时钟信号的高优先级任务,则需要在中断级别上调度其执行。其他相关的两个函数是OSIntEnter()和OSIntExit(),都需要在ISR中执行。 用户必须在开始多任务调度后(即调用OSStart()后)允许时钟节拍中断。3、OS_CPU_A.ASM

3、OS_CPU_A.ASM

voidOSTickISR(void){保存处理器寄存器;调用OSIntEnter()或者直接将OSIntNesting加1;调用OSTimeTick();调用OSIntExit();恢复处理器寄存器;执行中断返回指令;}(5)ARMEnableInt()&ARMDisableInt() 分别是退出临界区和进入临界区的宏指令实现。主要用于在进入临界区之前关闭中断,在退出临界区的时候恢复原来的中断状态。它的实现比较简单,可以采用方法1直接开关中断来实现,也可以采用方法2通过保存关闭/恢复中断屏蔽位来实现。例:C/OS-II在S3C44B0X上的移植设置OS_CPU.H中与处理器和编译器相关的代码用C语言编写六个操作系统相关的函数(OS_CPU_C.C)用汇编语言编写四个与处理器相关的函数(OS_CPU.ASM)设置与处理器和编译器相关的代码OS_CPU.H中定义了与编译器相关的数据类型。比如:INT8U、INT8S等。与ARM处理器相关的代码,使用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()宏开启/关闭中断设施堆栈的增长方向:堆栈由高地址向低地址增长用C语言编写六个操作系统相关的函数void*OSTaskStkInit(void(*task)(void*pd),void*pdata,void*ptos,INT16Uopt)voidOSTaskCreateHook(OS_TCB*ptcb)voidOSTaskDelHook(OS_TCB*ptcb)voidOSTaskSwHook(void)voidOSTaskStatHook(void)voidOSTimeTickHook(void)后5个函数为钩子函数,可以不加代码用汇编语言编写四个

与处理器相关的函数OSStartHighRdy()OSCtxSw()OSIntCtxSw()OSTickISR()关于移植相对于其他的嵌入式操作系统,uCOS-II的移植虽然是一个很简单的过程,但是,对于不熟悉uCOS-II的开发者,移植还是有一定难度的。2.4μC/OS-IIBSP编写

BSP(板级支持包)是介于底层硬件和操作系统之间的软件层次,它完成系统上电后最初的硬件和软件初始化,并对底层硬件进行封装,使得操作系统不再面对具体的操作。BSP的特点:硬件相关性:因为嵌入式实时系统的硬件环境具有应用相关性,所以,作为高层软件与硬件之间的接口,BSP必须为操作系统提供操作和控制具体硬件的方法。操作系统相关性:不同的操作系统具有各自的软件层次结构,因此,不同的操作系统具有特定的硬件接口形式。BSP的功能操作系统初始化A、片级初始化B、板级初始化C、系统级初始化硬件相关的设备驱动程序嵌入式系统初始化过程及BSP功能系统调用通用设备驱动程序与BSP的关系设计BSP的方法一、以典型的BSP做为参考二、参照操作系统或芯片厂商提供的BSP模板μC/OS-II

BSPforARMμC/OS-II编写一个简单的BSP。它首先设置CPU内部寄存器和系统堆栈,并初始化堆栈指针,建立程序的运行和调用环境;然后可以方便地使用C语言设置ARM片选地址(CS0~CS7)、GPIO以及SDRAM控制器,初始化串口(UART0)作为默认打印口,并向操作系统提供一些硬件相关例程和函数如dprintf(),以方便调试;在CPU、板级和程序自身初始化完成后,就可以把CPU的控制权交给操作系统了

二、向嵌入式平台移植软件

大部分嵌入式开发人员选用的软件开发模式是先在PC机上编写软件,再进行软件的移植工作。在PC机上编写软件时,要注意软件的可移植性。1、选用具有较高移植性的编程语言(如C语言)2、尽量少调用操作系统函数3、注意屏蔽不同硬件平台带来的字节顺序、字节对齐等问题。

字节顺序

字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。 (1)小端字节序:指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处; (2)大端字节序:是高字节数据存放在低地址处,低字节数据存放在高地址处。 基于X86平台的PC机是小端字节序的,而有的嵌入式平台则是大端字节序的。因而对int、uint16、uint32等多于1字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。

字节对齐[1]有的嵌入式处理器的寻址方式决定了:在内存中占2字节的int16、uint16等类型数据只能存放在偶数内存地址处,占4字节的int32、uint32等类型数据只能存放在4的整数倍的内存地址处;占8字节的类型数据只能存放在8的整数倍的内存地址处;而在内存中只占1字节的类型数据可以存放在任意地址处。

字节对齐[1]由于这些限制,在这些平台上编程时有很大的不同。首先,结构体成员之间会有空洞,比如这样一个结构:

typedefstructtest{

chara;

uint16b;

}TEST

字节对齐[2]对于结构TEST:在单字节对齐的平台上占内存三个字节,而在以上所述的嵌入式平台上有可能占三个或四个字节,视成员a的存储地址而定。

字节对齐[2]当a存储地址为奇数时,该结构占三个字节,在a与b之间不存在一个字节的空洞。当a存储地址为偶数时,该结构占四个字节,在a与b之间存在一个字节的空洞。对于通信双方都是对结构成员操作的,这种情况不会出错,但如果有一方是逐字节读取内容的(通信协议大都如此),就会错误地读到其它字节的内容。

字节对齐[2]其次,若对内存中数据以强制类型转换的方式读取,字节对齐的不同会引起数据读取的错误。因为:(1)假如指针指在奇数内存地址处,(2)我们想取得占内存两个字节的数据存放在uint16型的变量中,则:强制类型转换的结果是取得了该指针所指地址与第一个字节的数据,第二个数据没有被读取。

由于位段的空间分配方向因硬件平台的不同而不同(1)对X86平台,位段是从右向左分配的;(2)而一些嵌入式平台,位段是从左向右分配的。则: 分配顺序的不同导致了数据存取的错误。解决这一问题的一种方法

是采用条件编译的方式,针对不同的平台定义顺序不同的位段;也可以在前面所述的两个函数中加上对位段的处理。

代码优化的问题嵌入式系统对应用软件的质量要求更高,因而在嵌入式开发中尤其须注意对代码进行优化,尽可能地提高代码的效率,减少代码的大小。虽然现代C和C++编译器都提供了一定程度的代码优化,但大部分由编译器执行的优化技术仅涉及执行速度和代码大小的平衡,不可能使程序既快又小因而必须在编写嵌入式软件时采取必要的措施。

(1)提高代码的效率

①switch-case语句。在程序中经常会使用switch-case语句,每一个由机器语言实现的测试和跳转仅仅是为了决定下一步要做什么,就浪费了处理器时间。为了提高速度,可以把具体的情况按照它们发生的相对频率排序。即把最可能发生的情况放在第一,最不可能发生的情况放在最后,这样会减少平均的代码执行时间。

全局变量。使用全局变量比向函数传递参数更加有效率,这样做去除了函数调用前参数入栈和函数完成后参数出栈的需要。当然,使用全局变量会对程序有一些负作用。

(2)减小代码的大小

嵌入式系统编程应避免使用标准库例程,因为很多大的库例程设法处理所有可能的情况,所以占用了庞大的内存空间,因而应尽可能地减少使用标准库例程。

(3)避免内存泄漏

用户内存空间(堆)为RAM中全局数据和任务堆栈空间都分配后的剩余空间,为了使程序能有足够的内存运行,必须在申请的内存不用后及时地将其释放,以确保再次申请时能有空间。如果程序中存在内存泄漏(即申请内存后没有及时释放)的情况,程序最终会因为没有足够的内存空间而无法运行。

ucos-II在FM3上的移植开发板开发板资源(1)微控制器MB9BF506R2xUART通道(母头DB9接口)2x高速CAN通道(2针接插件)1xUSB主机接口(Type-AUSB接口)1xUSB设备接口(Type-BUSB接口)32Mx8bitNandFlash(K9F5608U0D)高精度I2C接口的实时时钟模块(RX-8025T)开发板资源(2)128x64点阵LCD3个用户LED4个用户按键、1个复位键1个电位计(可以调节AD输入电压)120针的测试焊盘(MCU所有引脚)5V和3V供电的电压选择支持USB,JTAG和外部15V电源供电板上标准20针JTAG接口支持IAR和Keil的调试工具ucos-II软硬件相关架构ucos-II在FM3上的移植三个处理器相关的代码:用#define设置1个常数、声明10个数据类型、用#define定义3个宏(OS_CPU.H)编写5个汇编语言函数(OS_CPU_A.ASM)编写2个c函数(OS_CPU_C.C)修改OS_CPU.H设置一个常量/*StackgrowsfromHIGHtoLOWmemoryonARM*/#defineOS_STK_GROWTH1修改OS_CPU.H声明10个数据类型typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;/*Unsigned8bitquantity*/typedefsignedcharINT8S;/*Signed8bitquantity*/typedefunsignedshortINT16U;/*Unsigned16bitquantity*/typedefsignedshortINT16S;/*Signed16bitquantity*/typedefunsignedintINT32U;/*Unsigned32bitquantity*/typedefsignedintINT32S;/*Signed32bitquantity*/(1)typedeffloatFP32;/*Singleprecisionfloatingpoint*/typedefdoubleFP64;/*Doubleprecisionfloatingpoint*/typedefunsignedintOS_STK;/*Eachstackentryis32-bitwide*/(2)typedefunsignedintOS_CPU_SR;/*DefinesizeofCPUstatusregister(PSR=32bits)*/(3)修改OS_CPU.H(1)因为ARMCotex-M3是32位微处理器,所以定义unsignedshort和signedshort为INT16S和INT16U,定义int和signedint为INT32U和INT32S.(2)因为微处理器堆栈是32位结构,因此定义OS_STK的类型为unsignedint(3)因为CPU状态寄存器是32位,所以定义OS_CPU_SR为unsignedint类型修改OS_CPU.H定义3个宏#defineOS_CRITICAL_METHOD3#ifOS_CRITICAL_METHOD==3#defineOS_ENTER_CRITICAL(){cpu_sr=OS_CPU_SR_Save();}#defineOS_EXIT_CRITICAL(){OS_CPU_SR_Restore(cpu_sr);}(1)#endif#defineOS_TASK_SW()OSCtxSw()(2)修改OS_CPU.H(1)为隐藏编译器相关的实现方法,μC/OS-II定义了两个开关中断的宏:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL().方法3是采用中断状态预处理的方法开关中断。通常在本地变量'cpu_sr'中保存中断禁止标志的状态,然后通过拷贝'cpu_sr到CPU状态寄存器来控制中断管理.(2)μC/OS-II在任务切换时需要从就绪任务的堆栈中恢复所有的微处理器寄存器,然后执行中断返回指令。因此,为实现上下文切换,需要编写OS_TASK_SW()函数以模拟一次中断的发生,OS_TASK_SW()定义为OSCtxSw,OSCtxSw是用汇编语言编写的代码,在软件中断中调用。修改OS_CPU_A.ASM需要编写5个汇编语言函数OSStartHighRdy()OSCtxSw()OSIntCtxSw()OS_CPU_SR_Save()和OS_CPU_SR_Restore()OS_CPU_PendSVHandler修改OS_CPU_A.ASM编写OSStartHighRdy()*********************************************************************************************************LDRR0,=NVIC_SYSPRI14 ;SetthePendSVexceptionpriority(1)LDRR1,=NVIC_PENDSV_PRISTRBR1,[R0]MOVSR0,#0 ;SetthePSPto0forinitialcontextswitchcall(2)MSRPSP,R0LDRR0,=OSRunning;OSRunning=TRUE (3)MOVSR1,#1STRBR1,[R0]LDRR0,=NVIC_INT_CTRL ;TriggerthePendSVexception(causescontextswitch)LDRR1,=NVIC_PENDSVSETSTRR1,[R0]CPSIEI ;Enableinterruptsatprocessorlevel(4)OSStartHangBOSStartHang ;Shouldnevergethere修改OS_CPU_A.ASM(1)这个函数由OSStart()执行以启动最高优先级任务,设置PendSV中断优先级为最低以确保它不会打断用户的中断。(2)设置PSP=0,告诉上下文切换函数这是第一次运行。(3)设置OSRunning=TRUE以启动多任务调度(4)PendSV中断只有在被允许后才获得响应。修改OS_CPU_A.ASM编写OSCtxSw()*********************************************************************************************LDRR0,=NVIC_INT_CTRL;触发PendSV中断(引起上下文切换)(1)LDRR1,=NVIC_PENDSVSETSTRR1,[R0]BXLR(1)当OS执行上下文切换时调用OSCtxSw().这个函数将触发PendSV中断,实际的切换在该中断中执行。修改OS_CPU_A.ASM编写OSIntCtxSw()*******************************************************************************************LDRR0,=NVIC_INT_CTRL;触发PendSV中断(引起上下文切换)(1)LDRR1,=NVIC_PENDSVSETSTRR1,[R0]BXLR(1)从中断返回时,如果需要上下文切换OSIntExit()调用将调用OSIntCtxSw().这个函数只是简单的触发PendSV中断,如果没有中断嵌套且中断被允许的情况下,将响应PendSV中断.修改OS_CPU_A.ASM编写OS_CPU_SR_Save()和OS_CPU_SR_Restore()*******************************************************************************************OS_CPU_SR_SaveMRSR0,PRIMASK ;屏蔽所有中断,并保存PRIMASK的值CPSIDIBXLROS_CPU_SR_RestoreMSRPRIMASK,R0 ;恢复PRIMASK的值BXLR修改OS_CPU_A.ASM编写OS_CPU_PendSVHandler*******************************************************************************************

PendSV中断用于引起上下文切换。任何中断发生时Cortex-M3都自动保存了一半的微处理器寄存器,并且在返回时自动恢复这些寄存器,所以移植时只需要保存R4-R11,并固定堆栈指针。也就是说,无论是从一个线程启动或发生因中断或异常,上下文保存和恢复是相同的。修改OS_CPU_A.ASM编写OS_CPU_PendSVHandler**********************************************************************代码如下:CPSIDI ;上下文切换时关中断MRSR0,PSP ;PSP是堆栈指针CBZR0,OS_CPU_PendSVHandler_nosave;第一次发生需要保存堆栈指针SUBSR0,R0,#0x20 ;在堆栈中保存r4-11

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论