嵌入式系统初始化与操作系统的移植.ppt

上传人:牧羊曲112 文档编号:6414976 上传时间:2023-10-28 格式:PPT 页数:130 大小:1.65MB
返回 下载 相关 举报
嵌入式系统初始化与操作系统的移植.ppt_第1页
第1页 / 共130页
嵌入式系统初始化与操作系统的移植.ppt_第2页
第2页 / 共130页
嵌入式系统初始化与操作系统的移植.ppt_第3页
第3页 / 共130页
嵌入式系统初始化与操作系统的移植.ppt_第4页
第4页 / 共130页
嵌入式系统初始化与操作系统的移植.ppt_第5页
第5页 / 共130页
点击查看更多>>
资源描述

《嵌入式系统初始化与操作系统的移植.ppt》由会员分享,可在线阅读,更多相关《嵌入式系统初始化与操作系统的移植.ppt(130页珍藏版)》请在三一办公上搜索。

1、嵌入式系统设计与实例开发基于32位微处理器与实时操作系统第六讲系统初始化分析与C/OS-移植,本节提要,1,嵌入式系统的初始化,2,C/OS-的移植,初始化程序的下载执行,目标机,宿主机,1)通过编程器将可执行目标文件烧写到BootROM(ROM、EPROM、FLASH)等;2)通过串行口和网口下载执行目标文件,要求宿主机系统上有数据传输工具程序、目标机装载器、嵌入式监视器或目标机系统上的调试代理。3)通过JTAG或BDM接口下载;,MPU,BOOT ROM,RAM,下载工具,串口,JTAG,网口,嵌入式系统的初始化过程,嵌入式系统的初始化过程(1),硬件初始化阶段,1、复位向量 ENTRY

2、b ResetHandler;for debug b HandlerUndef;handlerUndef b HandlerSWI;SWI interrupt handler b HandlerPabort;handlerPAbort b HandlerDabort;handlerDAbort b.;handlerReserved b HandlerIRQ b HandlerFIQ,嵌入式系统的初始化过程(2),硬件初始化阶段,2、最小硬件初始化,1)设置适当的寄存器,使嵌入式处理器处于一个已知的状态:获得CPU的类型;获得或设置CPU的时钟频率。2)禁止中断和高速缓存3)初始化内存控制器、内

3、存芯片和高速缓存单元,包括:得到内存的开始地址;得到内存的大小;如果有要求,则还需要进行主存测试;,嵌入式系统的初始化过程(3),硬件初始化阶段,3、其余硬件初始化,1)引导代码调用合适的函数对目标机系统上的全部硬件部件进行初始化,包括:建立执行处理程序初始化中断处理程序初始化总线接口初始化板级外设得到内存的开始地址;,嵌入式系统的初始化过程(4),RTOS初始化阶段,4、RTOS初始化,1)RTOS初始化2)RTOS对象和服务初始化任务信号量定时器中断内存管理3)RTOS任务堆栈初始化4)RTOS扩展部件初始化5)启动RTOS,嵌入式系统的初始化过程(5),应用程序初始化阶段,5、应用程序初

4、始化,ARM系统初始化的一般过程,启动(系统上电/复位),从程序入口点,初始化时钟等硬件相关寄存器1、设定PLL2、关中断3、设置其它寄存器,初始化存储器系统Flash及SDRAM参数设置,初始化C所需要的存储器空间,调用C入口函数,堆栈初始化,一、设置程序入口指针,上电复位后直接到程序入口点执行,入口点一般为一个跳转表,跳转到复位处理程序处开始执行ARM系统的初始化;启动程序首先必须定义入口指针,而且整个应用程序只有一个入口指针例:AREA Boot,CODE,READONLY ENTRY/*设置程序入口指针*/,二、设置中断向量,ARM要求中断向量必须设置在从OX00000000地址开始,

5、连续8*4字节的地址空间;向量表包含一系列跳转指令,跳转到相应的中断服务程序;对各未用中断,使其指向一个含返回指令的哑函数,以防止错误中断引起系统的混乱;,中断向量表,中断向量表的程序,AREA Boot,CODE,READONLYENTRYB Reset_handlerB Undef_HandlerB SWI_HandlerB PreAbort_HandlerB.;for reserved interrupt,stop hereB IRQ_handlerB FIQ_handler,三、初始化时钟和设置相关的寄存器,通过设置时钟控制器来确定CPU的工作频率,设置中断控制寄存器屏蔽中断设置”看门

6、狗”控制寄存器,关闭”看门狗”关闭Cache,四、初始化存储器系统,存储器类型和时序配置(参考芯片手册,设置与内存映射相关的寄存器)一个复杂的系统可能存在多种存储器类型的接口,需要根据实际的系统设计对此加以正确配置。对同一种存储器类型来说,也因为访问速度的差异,需要不同的时序设置。通常Flash 和SRAM 同属于静态存储器类型,可以合用同一个存储器端口;而DRAM 因为动态刷新和地址线复用等特性,通常配有专用的存储器端口。存储器端口的接口时序优化是非常重要的,影响到整个系统的性能。因为一般系统运行的速度瓶颈都存在于存储器访问,所以存储器访问时序应尽可能地快;但同时又要考虑由此带来的稳定性问题

7、。只有根据具体选定的芯片,进行多次的测试之后,才能确定最佳的时序配置。,存储器地址分布,有些系统具有非常灵活的存储器地址分配特性,进行存储器初始化设计的时候一定要根据应用程序的具体要求来完成地址分配。一种典型的情况是启动ROM 的地址重映射(remap)。当一个系统上电后程序将自动从0 地址处开始执行,因此在系统的初始状态,必须保证在0 地址处存在正确的代码,即要求0 地址开始处的存储器是非易性的ROM 或Flash 等。但是因为ROM 或Flash 的访问速度相对较慢,每次中断发生后都要从读取ROM 或Flash 上面的向量表开始,影响了中断响应速度。因此有的系统便提供一种灵活的地址重映射方

8、法,可以把0 地址重新指向到RAM 中去。在这种地址映射的变化过程当中,程序员需要仔细考虑的是程序的执行流程不能被这种变化所打断。,ROM地址的重映射,ROM地址重映射的实现,mov r8,#RAM_BASE_BOOT/RAM_BASE_BOOT是重映射前内部RAM区地址 add r9,pc#VectorTale/VectorTale是异常向量表入口ldmia r9!,r0-r7/读8个异常向量 stmia r8!,r0-r7/保存8个异常向量到RAM区ldmia r9!,r0-r4/读5个异常处理程序绝对地址stmia r8!,r0-r4/保存5个异常处理程序绝对地址到RAM区,为保证重映射

9、之后提供正确的中断入口地址,在重映射之前就必须把中断和异常向量表拷贝到内部RAM中。其程序实现如下:,五、初始化堆栈,ARM处理器有好几种运行状态(模式),各种状态都需要有自己的堆栈,所以需要分别为这些堆栈分配空间并设置好各自的堆栈指针每一种状态的堆栈指针寄存器(SP)都是独立的(System 和User 模式使用相同的SP 寄存器)。因此对程序中需要用到的每一种模式都要给SP 寄存器定义一个堆栈地址。方法是改变状态寄存器CPSR内的状态位,使处理器切换到不同的状态,然后给SP 赋值。(注意不要切换到User模式进行User 模式的堆栈设置,因为进入User 模式后就不能再操作CPSR 回到别

10、的模式了。可能会对接下去的程序执行造成影响。)一般堆栈的大小要根据需要而定,但是要尽可能给堆栈分配快速和高带宽的存储器。堆栈性能的提高对系统整体性能的影响是非常明显的。,堆栈初始化代码示例,MRS R0,CPSR;CPSR-R0BIC R0,R0,#MODEMASK;安全起见,屏蔽模式位以外的其它位ORR R1,R0,#IRQMODE;把设置模式位设置成需要的模式(IRQ)MSR CPSR_cxsf,R1;转到IRQ 模式LDR SP,=UndefStack;设置SP_irqORR R1,R0,#FIQMODEMSR CPSR_cxsf,R1;FIQModeLDR SP,=FIQStackOR

11、R R1,R0,#SVCMODEMSR CPSR_cxsf,R1;SVCModeLDR SP,=SVCStack,六、初始化C环境,在目标文件中,代码、数据放在不同的段中。源文件编译链接生成含.data、.text段的目标文件,且链接器生成的.data段是以系统RAM为参考地址故在系统启动时需要拷贝ROM或FLASH中的.data段到RAM,以完成对RAM的初始化。在初始化期间应将系统需要读写的数据和变量从ROM拷贝到RAM里运行,了解连接器的功能,将许多放在不同文件中的目标码,连接成一个可执行文件;计算及分配位于不同节区(Session)的程序或数据。一个程序可分为程序段(Read-Only

12、,RO)、数据段(Read-Write,RW)、零初始化段(Zero-Initialized,ZI);编译器仅将程序转成机器码,不会处理与内存地址有关的部分,这部分工作由连接器完成;连接器可以产生除二进制外的其它文件的格式。连接器主要用于处理内存分配问题,链接器产生的符号表,符号由链接器自动产生,只读段(read-only RO)就是代码段,读写段(read-write RW)是已经初始化的全局变量,而零初始化段(zero-initialized section ZI)中存放未初始化的全局变量;,初始化应用程序执行环境,映像一开始总是存储在ROM/Flash 里面的,其RO 部分既可以在ROM

13、/Flash里面执行,也可以转移到速度更快的RAM 中去;而RW 和ZI 这两部分必须是需要转移到可写的RAM 里去的。所谓应用程序执行环境的初始化,就是完成必要的从ROM 到RAM 的数据传输和内容清零。,初始化C环境(2),C环境初始化,就是利用上述符号初始化RW和ZI段,以使后面使用的全局变量的C程序正常运行;这里有两个循环,第一个循环把预初始化的数据段RW(位于代码段的后面)复制到RAM中;另一个循环把未初始化的数据段ZI初始化为0,也就是实现把从ROM中的.data段拷贝到RAM,对ZI段内的数据初始化为0,以完成对C环境的实始化;,初始化C环境(3),改变处理器模式,除用户模式以外

14、,其他6 种模式都是特权模式。因为在初始化过程中许多操作需要在特权模式下才能进行(比如CPSR 的修改),所以要特别注意不能过早地进入用户模式。一般地,在初始化过程中会经历以下一些模式变化:,七、呼叫C程序,对main函数的调用进入uc/OS的入口,通过这个入口就进入uC/OS的主函数,启动对uC/OS的初始化例 IMPORT Main b Main;C Entry,ARM9系统初始化,1、关WATCH DOG 2、禁止所有中断 3、初始化系统时钟 4、初始化内存控制寄存器5、检查是否从掉电模式唤醒 6、点亮所有LED 7、初始化UART08、将vivi所有代码从nand flash复制到SD

15、RAM中 9、跳到init/main.c中的main函数,uC/OS系统的初始化,完成了前面的硬件初始化和运行环境的相关设置后,进入Main(),Main()是uC/OS的入口函数,启动对uC/OS的初始化,ARM的硬件抽象层uHALuC/OS,ARM公司为操作系统的开发提供了一个硬件抽象层HAL,称为uHAL;从结构上看,uHAL是一组库程序,需要说明的是,uHAL并不是专门为uC/OS准备的,甚至也不是专为操作系统内核准备的;uHAL只是个针对ARM核的函数库;uC/OS是建立在uHAL的基础之上的;,uC/OS系统的初始化(2),ARMTargetInit()函数结构,ARMTarget

16、Init(),调uHAL打印接口打印系统信息,调用uHAL函数禁止所有中断,调用uHAL函数对中断初始化,uHAL函数对ARM计数器初始化,结束,uHAL的功能,uHAL的作用之一是在操作系统本身进入正常运行之前,为系统提供基本的输入输出手段,例如uHALr_printf()等;uHAL还要为操作系统的运行准备一个基本的运行环境,具体包括下列各种初始化:通过uHAL_ResetMMU(),将MMU设置在一个确定的初始状态;通过ARMDisable()关闭中断;通过uHAL_InitInterrupts()设置中断向量处理程序;通过uHAL_InitTimer()对系统使用的计数器进行初始化,A

17、RMTargetStart()的分析,创建了任务之后,ARMTargetStart()调用uHALr_InstallSystemTimer()创建一个系统时钟,为时钟中断做好准备;,C/OS-II BSP编写,BSP(板级支持包)是介于底层硬件和操作系统之间的软件层次,它完成系统上电后最初的硬件和软件初始化,并对底层硬件进行封装,使得操作系统不再面对具体的操作。BSP的特点:硬件相关性:因为嵌入式实时系统的硬件环境具有应用相关性,所以,作为高层软件与硬件之间的接口,BSP必须为操作系统提供操作和控制具体硬件的方法。操作系统相关性:不同的操作系统具有各自的软件层次结构,因此,不同的操作系统具有特

18、定的硬件接口形式。,BSP的功能,嵌入式系统初始化 A、片级初始化 B、板级初始化 C、系统级初始化硬件相关的设备驱动程序,嵌入式系统始化,1)片级初始化:主要完成微处理器的初始化,包括设置微处理器的核心寄存器和控制寄存器,微处理器核心工作模式以及其局部总线模式等。片级初始化把微处理器从上电时的缺省状态逐步设置成为系统所要求的工作状态。这是一个纯硬件的初始化过程2)板级初始化:完成微处理器以外的其他硬件设备的初始化。除此之外,还要设置某些软件的数据结构和参数,为随后的系统级初始化和应用程序的运行建立硬件和软件环境。这是一个同时包含软硬件两部分在内的初始化过程。3)系统级初始化:这是一个以软件初

19、始化为主的过程,主要进行操作系统初始化。BSP将控制转交给操作系统,由操作系统进行余下的初始化操作。包括加载和初始化与硬件无关的设备驱动程序,建立系统内存区,加载并初始化其他系统软件模块,比如网络系统、文件系统等;最后,操作系统创建应用程序环境并将控制转交给应用程序的入口,嵌入式系统初始化过程及BSP功能,完成硬件相关的设备驱动,1)BSP另一个主要功能是硬件相关的设备驱动。与初始化过程相反,硬件相关的设备驱动程序的初始化和使用通常是一个从高层到底层的过程。尽管BSP 中包含硬件相关的设备驱动程序,但是这些设备驱动程序通常不直接由BSP使用,而是在系统初始化过程中由BSP 把它们与操作系统中通

20、用的设备驱动程序关联起来,并在随后的应用中由通用的设备驱动程序调用,实现对硬件设备的操作。2)设计与硬件相关的驱动程序是BSP设计中另一个关键环节,系统调用通用设备驱动程序与BSP的关系,设计BSP的方法,一、以典型的BSP做为参考二、参照操作系统或芯片厂商提供的BSP模板,C/OS-II BSP for ARM,C/OS-II编写一个简单的BSP。它首先设置CPU内部寄存器和系统堆栈,并初始化堆栈指针,建立程序的运行和调用环境;然后可以方便地使用C语言设置ARM片选地址(CS0CS7)、GPIO以及SDRAM控制器,初始化串口(UART0)作为默认打印口,并向操作系统提供一些硬件相关例程和函

21、数如dprintf(),以方便调试;在CPU、板级和程序自身初始化完成后,就可以把CPU的控制权交给操作系统了,本节提要,1,2,嵌入式系统的初始化(软件),系统硬件接口与初始化,3,C/OS-的移植,操作系统移植的概念,所谓操作系统的移植,是指使一个实时操作系统能够在某个微处理器平台上运行。COS-II的主要代码都是由标准的C语言写成的,移植方便。移植的主要工作是修改部分与处理器硬件相关的代码。,移植的层次,操作系统的移植大体可以分为两个层次:跨体系结构的移植针对特定处理器的移植,移植COS-II满足的条件,处理器的C编译器能产生可重入代码 在程序中可以打开或者关闭中断 处理器支持中断,并且

22、能产生定时中断(通常在10100Hz之间)处理器支持能够容纳一定量数据的硬件堆栈 处理器有将堆栈指针和其他CPU寄存器存储和读出到堆栈(或者内存)的指令,什么是可重入代码,可重入的代码指的是一段代码(比如:一个函数)可以被多个任务同时调用,而不必担心会破坏数据。也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。,可重入代码举例,程序1:可重入型函数void swap(int*x,int*y)int temp;temp=*x;*x=*y;*y=temp;,非可重入代码举例,程序2:非可重入型函数int

23、 temp;void swap(int*x,int*y)temp=*x;*x=*y;*y=temp;,返回,不可重入函数被中断破坏,如何使函数具有可重入性,使Swap()函数具有可重入性:把Temp定义为局部变量;调用Swap()函数之前关中断,调动后再开中断;用信号量禁止该函数在使用过程中被再次调用;,打开/关闭中断,在COS-II中,可以通过:OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()宏来控制系统关闭或者打开中断。这需要处理器的支持。在ARM9的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。,处理器支持中断并且能产生定时中断,COS-II是通过

24、处理器产生的定时器的中断来实现多任务之间的调度的。ARM9的处理器上可以产生定时器中断。,处理器支持硬件堆栈,COS-II进行任务调度的时候,会把当前任务的CPU寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是COS-II多任务调度的基础。ARM9处理器中有专门的指令处理堆栈,可以灵活的使用堆栈。,移植对开发工具的要求,移植COS-II需要一个标准的C交叉编译器;由于移植时需要对CPU的寄存器进行操作,所以需要C交叉编译器能够支持汇编语言程序;嵌入式C编译器一般都包括汇编器、链接器和定位器。链接器是用来将不同的模块(编

25、译或汇编过的文件)链接成目标文件;定位器则允许将代码和数据放置在目标处理器的指定内存空间中;,移植uCOS-II要点(1),开关中断的方式。推荐使用method3#if OS_CRITICAL_METHOD=3OS_CPU_SR cpu_sr;#endif OS_ENTER_CRITICAL();OS_EXIT_CRITICAL();,使用method3方式的开关中断,#define OS_ENTER_CRITICAL()cpu_sr=INTS_OFF();#define OS_EXIT_CRITICAL()if(cpu_sr=0)INTS_ON();,ARM的中断模式,设备的中断在ARM中被

26、映射到了两个异常中FIQ和IRQ通过控制CPSR中的对应数据位,可以开启或者关闭中断为了方便和统一uCOS-II系统中断的处理,只使用了IRQ模式的中断。,移植uCOS-II要点(2)系统中断的处理,所有中断的调用都需要经过系统的接管。中断处理函数调用前后需要通知系统。例如:OSIntEnter();yourInterruptFun();OSIntExit();,OSIntExit的意义,ARM的工作模式,ARM处理器有7种操作模式:用户模式(usr)-正常的程序执行模式快速中断模式(fiq)-支持高速数据传输或通道处理中断模式(irq)-用于通用中断处理管理员模式(svc)-操作系统的保护模

27、式.中止模式(abt)-支持虚拟内存和/或内存保护等异常系统模式(sys)-支持操作系统的特殊用户模式(运行操作系统任务)未定义模式(und)-支持硬件协处理器的软件仿真 除了用户模式外,其他模式均可视为特权模式,ARM的寄存器(1),37个寄存器31 个通用32位寄存器,包括程序计数器PC6 个状态寄存器15个通用寄存器(R0 to R14),以及2个状态寄存器和程序计数器(PC)在任何时候都中可见的可见的寄存器取决于处理器的模式,不同的模式映射了不同的工作寄存器,ARM寄存器的组织,注:表明用户或系统模式使用的正常寄存器已经被异常模式指定的另一个寄存器取代,ARM的寄存器(2),R0 到

28、R15 可以直接访问R0 到 R14 是通用寄存器R13:堆栈指针(sp)(通常)每种处理器模式都有单独的堆栈R14:链接寄存器(lr)R15:程序计数器(PC)CPSR 当前程序状态寄存器,包括代码标志状态和当前模式位5个SPSR-(程序状态保存寄存器)当异常发生时保存CPSR状态,uCOS-II在ARM上的任务切换,任务级的任务切换中断级的任务切换,中断处理过程,OSIntExit(),void OSIntExit(void)OS_ENTER_CRITICAL();(1)if(-OSIntNesting|OSLockNesting)=0)(2)OSIntExitY=OSUnMapTblOS

29、RdyGrp;(3)OSPrioHighRdy=(INT8U)(OSIntExitY 3)+OSUnMapTblOSRdyTblOSIntExitY);if(OSPrioHighRdy!=OSPrioCur)OSTCBHighRdy=OSTCBPrioTblOSPrioHighRdy;OSCtxSwCtr+;OSIntCtxSw();(4)OS_EXIT_CRITICAL();,OSIntExit的关键OSIntCtxSw,实现中断级的任务切换ARM在栈指针调整过程中的优势,移植uCOS-II要点(3)Thumb带来的问题,很多ARM内核集成了16位thumb指令集Thumb可以在一定程度上节

30、省代码空间,提高系统效率Thumb会给中断级的任务切换带来麻烦CPSR中的T位不能直接操作Thumb状态将导致CPSR恢复以后的指令不能运行解决办法:对Thumb的使用必须保证原子操作专门对任务切换中Thumb的情况作处理建议,小心使用C编译器。尽量不使用Thumb。,移植uCOS-II的要点(4)何时启动系统定时器,如果在OSStart之前启动定时器,则系统可能无法正确执行完OSStartHighRdyOSStart函数直接调用OSStartHighRdy去执行最高优先级的任务,OSStart不返回。系统定时器应该在系统的最高优先级任务中启动使用OSRunning变量来控制操作系统的运行在我

31、们的移植版本中,使用了uCOS-II中的保留任务1作为系统任务。负责启动定时器,例:C/OS-II在ARM上的移植,设置OS_CPU.H中与处理器和编译器相关的代码 用C语言编写六个操作系统相关的函数(OS_CPU_C.C)用汇编语言编写四个与处理器相关的函数(OS_CPU.ASM),设置与处理器和编译器相关的代码,OS_CPU.H中定义了与编译器相关的数据类型。比如:INT8U、INT8S等。与 ARM处理器相关的代码,使用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()宏开启关闭中断设置堆栈的增长方向:堆栈由高地址向低地址增长,设置includes.h,type

32、def unsigned char BOOLEAN;typedef unsigned char INT8U;typedef signed char INT8S;typedef unsigned int INT16U;typedef signed int INT16S;typedef unsigned long INT32U;typedef signed long INT32S;typedef float FP32;typedef double FP64;typedef unsigned long OS_STK;typedef unsigned long OS_CPU_SR;extern int

33、 INTS_OFF(void);extern void INTS_ON(void);#define OS_ENTER_CRITICAL()cpu_sr=INTS_OFF();#define OS_EXIT_CRITICAL()if(cpu_sr=0)INTS_ON();#define OS_STK_GROWTH 1/*从高向低*/,程序状态寄存器,条件位:N=1-结果为负,0-结果为正或0Z=1-结果为0,0-结果不为0C=1-进位,0-借位V=1-结果溢出,0结果没溢出Q 位:仅ARM 5TE/J架构支持指示增强型DSP指令是否溢出J 位仅ARM 5TE/J架构支持J=1:处理器处于Jaze

34、lle状态,中断禁止位:I=1:禁止 IRQ.F=1:禁止 FIQ.T Bit仅ARM xT架构支持T=0:处理器处于 ARM 状态T=1:处理器处于 Thumb 状态Mode位(处理器模式位):0b10000User0b10001FIQ0b10010IRQ0b10011Supervisor0b10111Abort0b11011Undefined0b11111System,打开/关闭中断,EXPORT INTS_OFFEXPORT INTS_ONINTS_OFF mrs r0,cpsr;current CSR mov r1,r0;make a copy for masking orr r1,r

35、1,#0 xC0;mask off int bits msr CPSR_cxsf,r1;disable ints and r0,r0,#0 x80;return IRQ bit mov pc,lr;returnINTS_ON mrs r0,cpsr;current CSR bic r0,r0,#0 x80;mask on ints msr CPSR_cxsf,r0;enable ints mov pc,lr;return,7,0,31,7,0,31,7,0,31,设置OS_STK_GROWTH,绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是某些处理器是用另外一种方式工作的。C/OS-被

36、设计成两种情况都可以处理,只要在结构常量OS_STK_GROWTH中指定堆栈的生长方式就可以了。置OS_STK_GROWTH为0表示堆栈从下往上长。置OS_STK_GROWTH为1表示堆栈从上往下长。,用C语言编写六个操作系统相关的函数,void*OSTaskStkInit(void(*task)(void*pd),void*pdata,void*ptos,INT16U opt)void OSTaskCreateHook(OS_TCB*ptcb)void OSTaskDelHook(OS_TCB*ptcb)void OSTaskSwHook(void)void OSTaskStatHook(v

37、oid)void OSTimeTickHook(void)后5个函数为接口函数,可以不加代码,OSTaskStkInit,OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInit()来初始化任务的堆栈结构。因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。下图显示了OSTaskStkInt()放到正被建立的任务堆栈中的内容。这里我们定义了堆栈是从上往下长的。在用户建立任务的时候,用户传递任务的地址、pdata指针、任务的堆栈栈顶和任务的优先级给OSTaskCreate()和OSTaskCreateExt()。一旦用户初始化了堆栈,

38、OSTaskStkInit()就需要返回堆栈指针所指的地址。OSTaskCreate()和OSTaskCreateExt()会获得该地址并将它保存到任务控制块(OS_TCB)中。,堆栈初始化,ARM系统的堆栈初始化,堆栈指针SP,堆栈增长方向,OSTaskStkInit,OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT16U opt)unsigned int*stk;stk=(unsigned int*)ptos;/*Load stack pointer*/USE_ARG(opt);opt+;/*build

39、 a stack for the new task*/*-stk=(unsigned int)task;/*pc*/*-stk=(unsigned int)task;/*lr*/*-stk=12;/*r12*/*-stk=11;/*r11*/*-stk=10;/*r10*/*-stk=9;/*r9*/*-stk=8;/*r8*/*-stk=7;/*r7*/*-stk=6;/*r6*/*-stk=5;/*r5*/*-stk=4;/*r4*/*-stk=3;/*r3*/*-stk=2;/*r2*/*-stk=1;/*r1*/*-stk=(unsigned int)pdata;/*r0*/*-stk

40、=(SUPMODE);/*cpsr*/*-stk=(SUPMODE);/*spsr*/return(OS_STK*)stk);,OSTaskCreateHook,当用OSTaskCreate()和OSTaskCreateExt()建立任务的时候就会调用OSTaskCreateHook()。该函数允许用户或使用移植实例的用户扩展C/OS-功能。当C/OS-设置完了自己的内部结构后,会在调用任务调度程序之前调用OSTaskCreateHook()。该函数被调用的时候中断是禁止的。因此用户应尽量减少该函数中的代码以缩短中断的响应时间。当OSTaskCreateHook()被调用的时候,它会收到指向已

41、建立任务的OS_TCB的指针,这样它就可以访问所有的结构成员了。函数原型:void OSTaskCreateHook(OS_TCB*ptcb)ptcb=ptcb;,OSTaskDelHook,当任务被删除的时候就会调用OSTaskDelHook()。该函数在把任务从C/OS-的内部任务链表中删除之前被调用。当OSTaskDelHook()被调用的时候,它会收到指向正被删除任务的OS_TCB的指针,这样它就可以访问所有的结构成员了。OSTaskDelHook()可以来检验TCB扩展是否被建立(一个非空指针),并进行一些清除操作。函数原型:void OSTaskDelHook(OS_TCB*ptc

42、b)ptcb=ptcb;,OSTaskSwHook,当发生任务切换的时候就会调用OSTaskSwHook()。OSTaskSwHook()可以直接访问OSTCBCur和OSTCBHighRdy,因为它们是全局变量。OSTCBCur指向被切换出去的任务OS_TCB,而OSTCBHighRdy指向新任务OS_TCB。注意在调用OSTaskSwHook()期间中断一直是被禁止的。因此用户应尽量减少该函数中的代码以缩短中断的响应时间。函数原型:void OSTaskSwHook(void)#if 0 if(OSRunning=TRUE)/*保存拟被挂起任务的寄存器;/*恢复拟被运行任务的寄存器;#en

43、dif,OSTaskStatHook,OSTaskStatHook()每秒钟都会被OSTaskStat()调用一次。用户可以用OSTaskStatHook()来扩展统计功能。例如,用户可以保持并显示每个任务的执行时间,每个任务所用的CPU份额,以及每个任务执行的频率等。函数原型:void OSTaskStatHook(void),OSTimeTickHook,OSTimeTickHook()在每个时钟节拍都会被OSTaskTick()调用。实际上,OSTimeTickHook()是在节拍被C/OS-真正处理,并通知用户的移植实例或应用程序之前被调用的。函数原型:void OSTimeTickH

44、ook(void),用汇编语言编写四个与处理器相关的函数,OSStartHighRdy()OSCtxSw()OSIntCtxSw()OSTickISR(),数据结构,低优先级任务 OS_TCB,OSTCBCur(1),存贮器低地址,存贮器高地址,堆栈方向,SP,R1,R2,R3,R4,PC,PSW,存贮器低地址,存贮器高地址,高优先级任务 OS_TCB,OSTCBHighRdy(3),(2),CPU,(4),(5),OSStartHighRdy():运行优先级最高的就绪任务,OSStartHighRdyLDRr4,addr_OSTCBCur;得到当前任务TCB地址LDRr5,addr_OSTC

45、BHighRdy;得到最高优先级任务TCB地址LDRr5,r5;获得最高优先级任务堆栈栈顶指针LDRsp,r5;转移到新的堆栈中STRr5,r4;设置新的当前任务TCB地址LDMFDsp!,r4;装载备份程序状态寄存器MSRSPSR,r4LDMFDsp!,r4;装载程序状态寄存器MSRCPSR,r4;CPSR 处于 SVC32Mode摸式LDMFDsp!,r0-r12,lr,pc;运行新的任务,OSCtxSw()的原型,OS_TASK_SW();任务级的任务切换函数(1),OS_TASK_SWSTMFDsp!,lr;保存 pcSTMFDsp!,lr;保存 lrSTMFDsp!,r0-r12;保

46、存寄存器和返回地址MRS r4,CPSRSTMFDsp!,r4;保存当前的PSRMRS r4,SPSRSTMFDsp!,r4;保存SPSR;OSPrioCur=OSPrioHighRdyLDR r4,addr_OSPrioCurLDR r5,addr_OSPrioHighRdyLDRBr6,r5STRBr6,r4,OS_TASK_SW():任务级的任务切换函数(2),;得到当前任务TCB地址LDRr4,addr_OSTCBCurLDRr5,r4STRsp,r5;保存sp在被占先的任务的 TCB;得到最高优先级任务TCB地址LDRr6,addr_OSTCBHighRdyLDRr6,r6LDRsp

47、,r6;得到新任务堆栈指针;OSTCBCur=OSTCBHighRdySTRr6,r4;设置新的当前任务的TCB地址;保存任务方式寄存器 LDMFDsp!,r4MSRSPSR,r4LDMFDsp!,r4MSRCPSR,r4;返回到新任务的上下文LDMFDsp!,r0-r12,lr,pc,中断服务,中断服务程序,关于栈指针调整,栈指针调整,调整堆栈指针(加一个数在堆栈指针上)来完成的。加在堆栈指针上的数必须是明确的,而这个数主要依赖于移植的目标处理器(地址空间可能是16,32或64位),所用的编译器,编译器选项,内存模式等等。另外,处理器状态字可能是8,16,32甚至64位宽,并且OSIntEx

48、it()可能会分配局部变量。有些处理器允许用户直接增加常量到堆栈指针中,而有些则不允许。在后一种情况下,可以通过简单的执行一定数量的pop(出栈)指令来实现相同的功能。一旦堆栈指针完成调整,新的堆栈指针会被保存到被切换出去的任务的OS_TCB中,OSIntCtxSW的实现,OSIntCtxSw()的原型,OSIntCtxSW();中断级的任务切换函数(1),OSIntCtxSwLDRsp,=IRQStack;FIQ_STACK Sub r7,sp,#4mrs r1,SPSR;得到暂停的 PSRorr r1,r1,#0 xC0;关闭 IRQ,FIQ.msr CPSR_cxsf,r1;转换模式(应

49、该是 SVC_MODE)ldr r0,r7;从IRQ堆栈中得到IRQs LR(任务 PC)sub r0,r0,#4;当前PC地址是(saved_LR-4)STMFDsp!,r0;保存任务 PCSTMFDsp!,lr;保存 LRsub lr,r7,#52;保存 FIQ 堆栈 ptr in LR(转到 nuke r7)ldmfd lr!,r0-r12;从FIQ堆栈中得到保存的寄存器STMFDsp!,r0-r12;在任务堆栈中保存寄存器,OSIntCtxSW();中断级的任务切换函数(2),;在任务堆栈上保存PSR 和任务 PSRMRSr4,CPSRbic r4,r4,#0 xC0;使中断位处于使能

50、态STMFDsp!,r4;保存任务当前 PSRMRSr4,SPSRSTMFDsp!,r4;SPSR;OSPrioCur=OSPrioHighRdy/改变当前程序LDRr4,addr_OSPrioCurLDRr5,addr_OSPrioHighRdyLDRBr6,r5STRBr6,r4;得到被占先的任务TCBLDRr4,addr_OSTCBCurLDRr5,r4STRsp,r5;保存sp 在被占先的任务的 TCB,OSIntCtxSW();中断级的任务切换函数(3),;得到新任务 TCB 地址LDRr6,addr_OSTCBHighRdyLDRr6,r6LDRsp,r6;得到新任务堆栈指针;OS

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号