1、1嵌入式系统设计与实例开发嵌入式系统设计与实例开发ARMARM与与 C/OS-C/OS-第五讲第五讲 C/OS-C/OS-移植分析和系统初始化移植分析和系统初始化北京航空航天大学北京航空航天大学嵌入式机电控制研究室嵌入式机电控制研究室2提提 要要嵌入式系统的初始化嵌入式系统的初始化 C/OS-移植分析移植分析3初始化程序的下载执行MPUBOOT ROMRAM下载工具串口JTAG网口目标机目标机宿主机宿主机1 1)通过编程器将可执行目标文件烧写到)通过编程器将可执行目标文件烧写到BootROMBootROM(ROMROM、EPROMEPROM、FLASHFLASH)等;等;2 2)通过串行口和网
2、口下载执行目标文件,)通过串行口和网口下载执行目标文件,要求宿主机系统上有数据传输工具程序、目要求宿主机系统上有数据传输工具程序、目标机装载器、嵌入式监视器或目标机系统上标机装载器、嵌入式监视器或目标机系统上的调试代理;的调试代理;3 3)通过)通过JTAGJTAG或或BDMBDM接口下载。接口下载。4嵌入式系统的初始化过程复位向量最小硬件初始化其余硬件初始化RTOS初始化RTOS部件初始化启动RTOS启动应用程序1234567硬件初始化RTOS初始化软件初始化最小启动代码BSPRTOS应用程序5嵌入式系统的初始化过程复位向量最小硬件初始化其余硬件初始化123最小启动代码BSP硬件初始化阶段硬
3、件初始化阶段1.复位向量复位向量 ENTRY b ResetHandler ;for debug b HandlerUndef ;handlerUndef b HandlerSWI ;SWI interrupt handler b HandlerPabort;handlerPAbort b HandlerDabort;handlerDAbort b.;handlerReserved b HandlerIRQ b HandlerFIQ6嵌入式系统的初始化过程(2)复位向量最小硬件初始化其余硬件初始化123最小启动代码BSP硬件初始化阶段硬件初始化阶段2.2.最小硬件初始化最小硬件初始化1 1)设
4、置适当的寄存器,使嵌入式处理)设置适当的寄存器,使嵌入式处理器处于一个已知的状态:器处于一个已知的状态:l获得获得CPUCPU的类型。的类型。l获得或设置获得或设置CPUCPU的时钟频率。的时钟频率。2 2)禁止中断和高速缓存。)禁止中断和高速缓存。3 3)初始化内存控制器、内存芯片和高)初始化内存控制器、内存芯片和高速缓存单元,包括:速缓存单元,包括:l得到内存的开始地址。得到内存的开始地址。l得到内存的大小。得到内存的大小。l如果有要求,则还需要进行主存如果有要求,则还需要进行主存测试测试7嵌入式系统的初始化过程(3)复位向量最小硬件初始化其余硬件初始化123最小启动代码BSP硬件初始化阶
5、段硬件初始化阶段3.3.其余硬件初始化其余硬件初始化引导代码调用合适的函数对目标机系统引导代码调用合适的函数对目标机系统上的全部硬件部件进行初始化,包括:上的全部硬件部件进行初始化,包括:l建立执行处理程序。建立执行处理程序。l初始化中断处理程序。初始化中断处理程序。l初始化总线接口。初始化总线接口。l初始化板级外设得到内存的开始初始化板级外设得到内存的开始地址。地址。8嵌入式系统的初始化过程(4)RTOS初始化阶段初始化阶段4.4.RTOSRTOS初始化初始化1 1)RTOSRTOS初始化初始化2 2)RTOSRTOS对象和服务初始化对象和服务初始化l任务任务l信号量信号量l定时器定时器l中
6、断中断l内存管理内存管理3 3)RTOSRTOS任务堆栈初始化任务堆栈初始化4 4)RTOSRTOS扩展部件初始化扩展部件初始化5 5)启动)启动RTOSRTOSRTOS初始化RTOS部件初始化启动RTOS456RTOS初始化RTOS9嵌入式系统的初始化过程(5)应用程序初始化阶段应用程序初始化阶段5.5.应用程序初始化应用程序初始化启动应用程序7软件初始化应用程序10ARM7TDMI系统初始化的一般过程启动(系统上电启动(系统上电/复位)复位)从程序入口点从程序入口点关闭中断关闭中断初始化时钟等硬件相关寄存器初始化时钟等硬件相关寄存器初始化存储器系统初始化存储器系统初始化初始化C C所需要的
7、存储器空间所需要的存储器空间调用调用C C入口函数入口函数11一、设置程序入口指针l上电复位后直接到程序入口点执行,入口点一般为一个跳转表,跳上电复位后直接到程序入口点执行,入口点一般为一个跳转表,跳转到复位处理程序处开始执行转到复位处理程序处开始执行ARM7TDMIARM7TDMI系统的初始化。系统的初始化。l启动程序首先必须定义入口指针,而且整个应用程序只有一个入口启动程序首先必须定义入口指针,而且整个应用程序只有一个入口指针。指针。例:例:AREA Boot,CODE,READONLYAREA Boot,CODE,READONLY ENTRY /ENTRY /*设置程序入口指针设置程序入
8、口指针*/12二、设置中断向量lARMARM要求中断向量必须设置在从要求中断向量必须设置在从OX00000000OX00000000地址开始,连续地址开始,连续8 8*4 4字节字节的地址空间。的地址空间。l向量表包含一系列跳转指令,跳转到相应的中断服务程序。向量表包含一系列跳转指令,跳转到相应的中断服务程序。l对各未用中断,使其指向一个含返回指令的哑函数,以防止错误中对各未用中断,使其指向一个含返回指令的哑函数,以防止错误中断引起系统的混乱。断引起系统的混乱。13中断向量表FIQ0 x1C外部快速中断IRQ0 x18一般外部中断(Reserved)0 x14保留Data Abort0 x10
9、数据异常Frefetch Abort0 x0C预取指异常Software int0 x08软件中断Undef0 x04未定义指令中断Reset0 x00复位中断14中断向量表的程序AREA Boot,CODE,READONLYAREA Boot,CODE,READONLYENTRYENTRYB Reset_handlerB Reset_handlerB B UndefUndef_Handler_HandlerB SWI_HandlerB SWI_HandlerB B PreAbortPreAbort_Handler_HandlerB .;for reserved interrupt,stop
10、hereB .;for reserved interrupt,stop hereB IRQ_handlerB IRQ_handlerB FIQ_handlerB FIQ_handler15三、初始化时钟和设置相关的寄存器 通过设置时钟控制器来确定通过设置时钟控制器来确定CPUCPU的工作频率,设置中断控制寄存的工作频率,设置中断控制寄存器屏蔽中断。器屏蔽中断。16四、初始化存储器系统参考芯片手册,设置与内存映射相关的寄存器。参考芯片手册,设置与内存映射相关的寄存器。17五、初始化堆栈lARMARM处理器有好几种运行状态(模式),各种状态都需要有自己的处理器有好几种运行状态(模式),各种状态都需
11、要有自己的堆栈,所以需要分别为这些堆栈分配空间并设置好各自的堆栈指堆栈,所以需要分别为这些堆栈分配空间并设置好各自的堆栈指针。针。l如果系统使用了如果系统使用了DRAMDRAM或其他外设,需要设置一些寄存器,以确定或其他外设,需要设置一些寄存器,以确定其刷新频率、数据总线宽度等信息。有的系统还需设置一些寄存其刷新频率、数据总线宽度等信息。有的系统还需设置一些寄存器来控制器来控制SDRAMSDRAM、USBUSB、网络接口等。网络接口等。18六、初始化C环境l在目标文件中,代码、数据放在不同的段中。源文件编译链接生成在目标文件中,代码、数据放在不同的段中。源文件编译链接生成含含.datadata
12、、.text.text段的目标文件,且链接器生成的段的目标文件,且链接器生成的.datadata段是以系统段是以系统RAMRAM为参考地址。为参考地址。l故在系统启动时需要复制故在系统启动时需要复制ROMROM或或FLASHFLASH中的中的.datadata段到段到RAMRAM,以完成对以完成对RAMRAM的初始化。在初始化期间应将系统需要读写的数据和变量从的初始化。在初始化期间应将系统需要读写的数据和变量从ROMROM复制到复制到RAMRAM里运行。里运行。19链接器产生的符号表 符号由链接器自动产生,只读段(符号由链接器自动产生,只读段(read-only ROread-only RO)
13、就是代码段,读就是代码段,读写段(写段(read-write RWread-write RW)是已经初始化的全局变量,而零初始化段是已经初始化的全局变量,而零初始化段(zero-initialized section ZIzero-initialized section ZI)中存放未初始化的全局变量。中存放未初始化的全局变量。20初始化C环境(2)lC C环境初始化,就是利用上述符号初始化环境初始化,就是利用上述符号初始化RWRW和和ZIZI段以使后面使用的段以使后面使用的全局变量的全局变量的C C程序正常运行。程序正常运行。l这里有两个循环,第一个循环把预初始化的数据段(位于代码段这里有两
14、个循环,第一个循环把预初始化的数据段(位于代码段的后面)复制到的后面)复制到RAMRAM中,另一个循环把未初始化的数据段中,另一个循环把未初始化的数据段ZIZI初始化初始化为为0 0,也就是实现把从,也就是实现把从ROMROM中的中的.datadata段复制到段复制到RAMRAM,对对ZIZI段内的数段内的数据初始化为据初始化为0 0,以完成对,以完成对C C环境的初始化。环境的初始化。21ROM地址的重映射(remap)0 x0200(boot code)0 x0100(Reset_handler)B Reset_Handler0 x0000Flash(remap)0 x0204(boot
15、code)0 x0200(Reset_handler)B Reset_Handler0 x0000RAM22初始化C环境(3)23七、呼叫C程序l对对mainmain函数的调用进入函数的调用进入 C/OS C/OS 的入口,通过这个入口就进入的入口,通过这个入口就进入 C/OS C/OS 的主函数,启动对的主函数,启动对 C/OS C/OS 的初始化。的初始化。l例例 IMPORT MainIMPORT Main b Main ;C Entry b Main ;C Entry24C/OS 系统的初始化l完成了前面的硬件初始化和运行环境的相关设置后,进入完成了前面的硬件初始化和运行环境的相关设置
16、后,进入Main()Main(),Main()Main()是是 C/OS C/OS 的入口函数,启动对的入口函数,启动对 C/OS C/OS 的初始化的初始化。25ARM7的硬件抽象层uHALC/OS lARMARM公司为操作系统的开发提供了一个硬件抽象层公司为操作系统的开发提供了一个硬件抽象层HALHAL,称为称为uHALuHAL。l从结构上看,从结构上看,uHALuHAL是一组库程序,需要说明的是,是一组库程序,需要说明的是,uHALuHAL并不是专门并不是专门为为 C/OS C/OS 准备的,甚至也不是专为操作系统内核准备的。准备的,甚至也不是专为操作系统内核准备的。luHALuHAL只
17、是个针对只是个针对ARMARM核的函数库。核的函数库。l C/OS C/OS 是是建立在建立在uHALuHAL的基础之上的。的基础之上的。26C/OS 系统的初始化(2)27ARMTargetInit()函数结构ARMTargetInitARMTargetInit()()调调uHALuHAL打印接口打印系统信息打印接口打印系统信息调用调用uHALuHAL函数禁止所有中断函数禁止所有中断调用调用uHALuHAL函数对中断初始化函数对中断初始化uHALuHAL函数对函数对ARMARM计数器初始化计数器初始化结束结束28uHAL的功能luHALuHAL的作用之一是在操作系统本身进入正常运行之前,为系
18、统提供基的作用之一是在操作系统本身进入正常运行之前,为系统提供基本的输入输出手段,例如本的输入输出手段,例如uHALruHALr_ _printfprintf()()等等。luHALuHAL还要为操作系统的运行准备一个基本的运行环境,具体包括下列还要为操作系统的运行准备一个基本的运行环境,具体包括下列各种初始化:各种初始化:通过通过uHALuHAL_ _ResetMMUResetMMU()(),将将MMUMMU设置在一个确定的初始状态。设置在一个确定的初始状态。通过通过ARMDisableARMDisable()()关闭中断。关闭中断。通过通过uHALuHAL_ _InitInterrupts
19、InitInterrupts()()设置中断向量处理程序。设置中断向量处理程序。通过通过uHALuHAL_ _InitTimerInitTimer()()对对系统使用的计数器进行初始系统使用的计数器进行初始 化。化。29ARMTargetStart()的分析 创建了任务之后创建了任务之后,ARMTargetStartARMTargetStart()()调用调用uHALruHALr_ _InstallSystemTimerInstallSystemTimer()()创建一个系统时钟,为时钟中断做好准备。创建一个系统时钟,为时钟中断做好准备。30提提 要要嵌入式系统的初始化嵌入式系统的初始化 C/
20、OS-移植分析移植分析31操作系统移植的概念l所谓操作系统的移植,是指使一个实时操作系统能够在某个微处理所谓操作系统的移植,是指使一个实时操作系统能够在某个微处理器平台上运行。器平台上运行。l COS-IICOS-II的主要代码都是由标准的的主要代码都是由标准的C C语言写成的,移植方便。语言写成的,移植方便。l移植的主要工作是修改部分与处理器硬件相关的代码。移植的主要工作是修改部分与处理器硬件相关的代码。32移植的层次操作系统的移植大体可以分为两个层次:操作系统的移植大体可以分为两个层次:l跨体系结构的移植。跨体系结构的移植。l针对特定处理器的移植。针对特定处理器的移植。33移植COS-II
21、满足的条件 l处理器的处理器的C C编译器能产生可重入代码。编译器能产生可重入代码。l在程序中可以打开或者关闭中断。在程序中可以打开或者关闭中断。l处理器支持中断,并且能产生定时中断(通常处理器支持中断,并且能产生定时中断(通常在在10-10010-100HzHz之间)。之间)。l处理器支持能够容纳一定量数据的硬件堆栈。处理器支持能够容纳一定量数据的硬件堆栈。l处理器有将堆栈指针和其他处理器有将堆栈指针和其他CPUCPU寄存器存储和读出到堆栈(或者内寄存器存储和读出到堆栈(或者内存)的指令。存)的指令。34什么是可重入代码 l可重入的代码指的是一段代码(比如:一个函数)可以被多个任可重入的代码
22、指的是一段代码(比如:一个函数)可以被多个任务同时调用,而不必担心会破坏数据。务同时调用,而不必担心会破坏数据。l也就是说,可重入型函数在任何时候都可以被中断执行,过一段也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。的任务重新调用,影响函数中的数据。35可重入代码举例程序程序1 1:可重入型函数:可重入型函数void swap(void swap(intint *x,x,intint *y)y)intint temp;temp;temp=t
23、emp=*x;x;*x=x=*y;y;*y=temp;y=temp;36非可重入代码举例程序程序2 2:非可重入型函数:非可重入型函数intint temp;temp;void swap(void swap(intint *x,x,intint *y)y)temp=temp=*x;x;*x=x=*y;y;*y=temp;y=temp;返回37不可重入函数被中断破坏38如何使函数具有可重入性 使使Swap()Swap()函数具有可重入性:函数具有可重入性:l把把TempTemp定义为局部变量。定义为局部变量。l调用调用Swap()Swap()函数之前关中断,调动后再开中断。函数之前关中断,调动后
24、再开中断。l用信号量禁止该函数在使用过程中被再次调用。用信号量禁止该函数在使用过程中被再次调用。39打开/关闭中断 在在 COS-IICOS-II中,可以通过:中,可以通过:OS_ENTER_CRITICAL()OS_ENTER_CRITICAL()OS_EXIT_CRITICAL()OS_EXIT_CRITICAL()宏来控制系统关闭或者打开中断。这需要处理器的支持。宏来控制系统关闭或者打开中断。这需要处理器的支持。在在ARM7TDMIARM7TDMI的处理器上,可以设置相应的寄存器来关闭或者打开的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。系统的所有中断。40处理器支持中断
25、并且能产生定时中断 l COS-IICOS-II是通过处理器产生的定时器的中断来实现多任务之间是通过处理器产生的定时器的中断来实现多任务之间的调度的。的调度的。lARM7TDMIARM7TDMI的处理器上可以产生定时器中断。的处理器上可以产生定时器中断。41处理器支持硬件堆栈 l COS-IICOS-II进行任务调度的时候,会把当前任务的进行任务调度的时候,会把当前任务的CPUCPU寄存器存放到寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是作寄存器,继续运行另一
26、个任务。所以,寄存器的入栈和出栈是 COS-IICOS-II多任务调度的基础。多任务调度的基础。lARM7ARM7处理器中有专门的指令处理堆栈,可以灵活的使用堆栈。处理器中有专门的指令处理堆栈,可以灵活的使用堆栈。42移植对开发工具的要求 l移植移植 COS-IICOS-II需要一个标准的需要一个标准的C C交叉编译器。交叉编译器。l由于移植时需要对由于移植时需要对CPUCPU的寄存器进行操作,所以需要的寄存器进行操作,所以需要C C交叉编译器能交叉编译器能够支持汇编语言程序。够支持汇编语言程序。l嵌入式嵌入式C C编译器一般都包括汇编器、链接器和定位器。链接器是用来编译器一般都包括汇编器、链
27、接器和定位器。链接器是用来将不同的模块(编译或汇编过的文件)链接成目标文件;定位器则将不同的模块(编译或汇编过的文件)链接成目标文件;定位器则允许将代码和数据放置在目标处理器的指定内存空间中。允许将代码和数据放置在目标处理器的指定内存空间中。43移植C/OS-II要点(1)开关中断的方式。推荐使用开关中断的方式。推荐使用method3method3#if OS_CRITICAL_METHOD=3#if OS_CRITICAL_METHOD=3OS_CPU_SR OS_CPU_SR cpucpu_ _srsr;#endifendif OS_ENTER_CRITICAL();OS_ENTER_CR
28、ITICAL();OS_EXIT_CRITICAL();OS_EXIT_CRITICAL();44使用method3方式的开关中断#define OS_ENTER_CRITICAL()cpu_sr=INTS_OFF();#define OS_EXIT_CRITICAL()if(cpu_sr=0)INTS_ON();45ARM的中断模式l设备的中断在设备的中断在ARMARM中被映射到了两个异常中断中中被映射到了两个异常中断中FIQFIQ和和IRQIRQ。l通过控制通过控制CPSRCPSR中的对应数据位,可以开启或者关闭中断。中的对应数据位,可以开启或者关闭中断。为了方便和统一为了方便和统一 C/
29、OS-IIC/OS-II系统中断的处理,只使用了系统中断的处理,只使用了IRQIRQ模式的模式的中断。中断。46移植C/OS-II要点(2)系统中断的处理 所有中断的调用都需要经过系统的接管。中断处理函数调用前后所有中断的调用都需要经过系统的接管。中断处理函数调用前后需要通知系统。例如:需要通知系统。例如:OSIntEnter();yourInterruptFun();OSIntExit();47OSIntExit的意义的意义48ARM的工作模式lARMARM处理器有处理器有7 7种操作模式种操作模式:l用户模式用户模式(usrusr)正常的程序执行模式。正常的程序执行模式。l快速中断模式快速
30、中断模式(fiqfiq)支持高速数据传输或通道处理。支持高速数据传输或通道处理。l中断模式中断模式(irqirq)用于通用中断处理。用于通用中断处理。l管理员模式管理员模式(svc)(svc)操作系统的保护模式操作系统的保护模式。l中止模式中止模式(abtabt)支持虚拟内存和支持虚拟内存和/或内存保护等异常。或内存保护等异常。l系统模式系统模式(sys)(sys)支持操作系统的特殊用户模式支持操作系统的特殊用户模式(运行操作系统任务)。运行操作系统任务)。l未定义模式未定义模式(und)(und)支持硬件协处理器的软件仿真。支持硬件协处理器的软件仿真。l除了用户模式外,其他模式均可视为特权模
31、式除了用户模式外,其他模式均可视为特权模式49ARM的寄存器(1)l3737个寄存器:个寄存器:u31 31 个通用个通用3232位寄存器,包括程序计数器位寄存器,包括程序计数器PCPC。u6 6 个状态寄存器。个状态寄存器。u1515个通用寄存器个通用寄存器 (R0 to R14),(R0 to R14),以及以及2 2个状态寄存器和程序计数器(个状态寄存器和程序计数器(PCPC)在任何时候都中可见的。在任何时候都中可见的。l可见的寄存器取决于处理器的模式,不同的模式映射了不同的工可见的寄存器取决于处理器的模式,不同的模式映射了不同的工作寄存器。作寄存器。50ARM寄存器的组织注注:表明用户
32、或系统模式使用的正常寄存器已经被异常表明用户或系统模式使用的正常寄存器已经被异常模式指定的另一个寄存器取代模式指定的另一个寄存器取代51ARM的寄存器(2)lR0 R0 到到 R15 R15 可以直接访问。可以直接访问。lR0 R0 到到 R14 R14 是通用寄存器。是通用寄存器。lR13:R13:堆栈指针堆栈指针 (sp)(sp)(通常通常)。l每种处理器模式都有单独的堆栈。lR14:R14:链接寄存器链接寄存器(lrlr)。lR15R15:程序计数器程序计数器 (PC)(PC)。lCPSR CPSR:当前程序状态寄存器,包括代码标志状态和当前模式位。当前程序状态寄存器,包括代码标志状态和
33、当前模式位。l5 5个个SPSRSPSR(程序状态保存寄存器程序状态保存寄存器):):当异常发生时保存当异常发生时保存CPSRCPSR状态。状态。52C/OS-II在ARM上的任务切换l任务级的任务切换;任务级的任务切换;l中断级的任务切换。中断级的任务切换。53中断处理过程54OSIntExit()void OSIntExit(void)OS_ENTER_CRITICAL();(1)if(-OSIntNesting|OSLockNesting)=0)(2)OSIntExitY =OSUnMapTblOSRdyGrp;(3)OSPrioHighRdy=(INT8U)(OSIntExitY OS
34、TCBStkPtr=Stack pointer;调用用户定义的调用用户定义的OSTaskSwHook();OSTCBCur =OSTCBHighRdy;OSPrioCur=OSPrioHighRdy;得到需要恢复的任务的堆栈指针得到需要恢复的任务的堆栈指针:Stack pointer=OSTCBHighRdy-OSTCBStkPtr;将所有处理器寄存器从新任务的堆栈中恢复出来将所有处理器寄存器从新任务的堆栈中恢复出来;执行中断返回指令执行中断返回指令;77OS_TASK_SW();任务级的任务切换函数(1)OS_TASK_SWSTMFDsp!,lr;保存保存 pcSTMFDsp!,lr;保存保
35、存 lrSTMFDsp!,r0-r12;保存寄存器和返回地址保存寄存器和返回地址MRS r4,CPSRSTMFDsp!,r4;保存当前的保存当前的PSRMRS r4,SPSRSTMFDsp!,r4;保存保存SPSR;OSPrioCur=OSPrioHighRdyLDR r4,addr_OSPrioCurLDR r5,addr_OSPrioHighRdyLDRBr6,r5STRBr6,r478OS_TASK_SW():任务级的任务切换函数(2);得到当前任务得到当前任务TCB地址地址LDRr4,addr_OSTCBCurLDRr5,r4STRsp,r5;保存保存sp在被占先的任务的在被占先的任务
36、的 TCB;得到最高优先级任务得到最高优先级任务TCB地址地址LDRr6,addr_OSTCBHighRdyLDRr6,r6LDRsp,r6;得到新任务堆栈指针得到新任务堆栈指针;OSTCBCur=OSTCBHighRdySTRr6,r4;设置新的当前任务的设置新的当前任务的TCB地址地址 ;保存任务方式寄存器保存任务方式寄存器 LDMFDsp!,r4MSRSPSR,r4LDMFDsp!,r4MSRCPSR,r4 ;返回到新任务的上下文返回到新任务的上下文LDMFDsp!,r0-r12,lr,pc79中断服务中断服务80关于栈指针调整81栈指针调整栈指针调整 调整堆栈指针(加一个数在堆栈指针上
37、)来完成的。加在堆栈调整堆栈指针(加一个数在堆栈指针上)来完成的。加在堆栈指针上的数必须是明确的,而这个数主要依赖于移植的目标处理器指针上的数必须是明确的,而这个数主要依赖于移植的目标处理器(地址空间可能是地址空间可能是1616,3232或或6464位位),所用的编译器,编译器选项,内存,所用的编译器,编译器选项,内存模式等等。另外,处理器状态字可能是模式等等。另外,处理器状态字可能是8 8,1616,3232甚至甚至6464位宽,并且位宽,并且OSIntExitOSIntExit()()可能会分配局部变量。有些处理器允许用户直接增加常可能会分配局部变量。有些处理器允许用户直接增加常量到堆栈指
38、针中,而有些则不允许。在后一种情况下,可以通过简量到堆栈指针中,而有些则不允许。在后一种情况下,可以通过简单的执行一定数量的单的执行一定数量的poppop(出栈)指令来实现相同的功能。一旦堆栈出栈)指令来实现相同的功能。一旦堆栈指针完成调整,新的堆栈指针会被保存到被切换出去的任务的指针完成调整,新的堆栈指针会被保存到被切换出去的任务的OS_TCBOS_TCB中中 。82OSIntCtxSW的实现83OSIntCtxSwOSIntCtxSw()()的原型的原型void OSIntCtxSw(void)调整堆栈指针来去掉在调用:调整堆栈指针来去掉在调用:OSIntExit(),OSIntCtxSw
39、()过程中压入堆栈的多余内容过程中压入堆栈的多余内容;将当前任务堆栈指针保存到当前任务的将当前任务堆栈指针保存到当前任务的OS_TCB中中:OSTCBCur-OSTCBStkPtr=堆栈指针堆栈指针;调用用户定义的调用用户定义的OSTaskSwHook();OSTCBCur =OSTCBHighRdy;OSPrioCur=OSPrioHighRdy;得到需要恢复的任务的堆栈指针得到需要恢复的任务的堆栈指针:堆栈指针堆栈指针=OSTCBHighRdy-OSTCBStkPtr;将所有处理器寄存器从新任务的堆栈中恢复出来将所有处理器寄存器从新任务的堆栈中恢复出来;执行中断返回指令执行中断返回指令;8
40、4OSIntCtxSW();中断级的任务切换函数(1)OSIntCtxSwadd r7,sp,#16 ;保存寄存器指针保存寄存器指针LDRsp,=IRQStack;FIQ_STACK mrs r1,SPSR ;得到暂停的得到暂停的 PSRorr r1,r1,#0 xC0 ;关闭关闭 IRQ,FIQ.msr CPSR_cxsf,r1 ;转换模式转换模式(应该是应该是 SVC_MODE)ldr r0,r7,#52 ;从从IRQ堆栈中得到堆栈中得到IRQs LR(任务任务 PC)sub r0,r0,#4 ;当前当前PC地址是地址是(saved_LR-4)STMFDsp!,r0 ;保存任务保存任务 P
41、CSTMFDsp!,lr ;保存保存 LRmov lr,r7 ;保存保存 FIQ 堆栈堆栈 ptr in LR(转到转到 nuke r7)ldmfd lr!,r0-r12 ;从从FIQ堆栈中得到保存的寄存器堆栈中得到保存的寄存器STMFDsp!,r0-r12 ;在任务堆栈中保存寄存器在任务堆栈中保存寄存器 85OSIntCtxSW();中断级的任务切换函数(2);在任务堆栈上保存在任务堆栈上保存PSR 和任务和任务 PSRMRS r4,CPSRbic r4,r4,#0 xC0 ;使中断位处于使能态使中断位处于使能态STMFDsp!,r4;保存任务当前保存任务当前 PSRMRS r4,SPSRS
42、TMFDsp!,r4;SPSR;OSPrioCur=OSPrioHighRdy /改变当前程序改变当前程序LDRr4,addr_OSPrioCurLDRr5,addr_OSPrioHighRdyLDRBr6,r5STRB r6,r4;得到被占先的任务得到被占先的任务TCBLDRr4,addr_OSTCBCurLDRr5,r4STRsp,r5;保存保存sp 在被占先的任务的在被占先的任务的 TCB86OSIntCtxSW();中断级的任务切换函数(3);得到新任务得到新任务 TCB 地址地址LDR r6,addr_OSTCBHighRdyLDR r6,r6LDR sp,r6;得到新任务堆栈指针得
43、到新任务堆栈指针;OSTCBCur=OSTCBHighRdySTR r6,r4 ;设置新的当前任务的设置新的当前任务的TCB地址地址LDMFDsp!,r4MSR SPSR,r4LDMFDsp!,r4BIC r4,r4,#0 xC0 ;必须退出新任务通过允许中断必须退出新任务通过允许中断MSR CPSR,r4LDMFDsp!,r0-r12,lr,pc87测试C/OS-II(1)/*任务定义任务定义*/OS_STK SYS_Task_StackSTACKSIZE=0,;/system task刷新任务刷新任务堆栈堆栈#define SYS_Task_Prio1void SYS_Task(void*
44、Id);OS_STK Task1_StackSTACKSIZE=0,;void Task1(void*Id);#define Task1_Prio 12OS_STK Task2_StackSTACKSIZE=0,;void Task2(void*Id);#define Task2_Prio 1388测试C/OS-II(2)int Main(int argc,char*argv)ARMTargetInit();/do target(uHAL based ARM system)initialisation/OSInit();OSTaskCreate(SYS_Task,(void*)0,(OS_ST
45、K*)&SYS_Task_StackSTACKSIZE-1,SYS_Task_Prio);OSTaskCreate(Task2,(void*)0,(OS_STK*)&Task2_StackSTACKSIZE-1,Task2_Prio);OSTaskCreate(Task1,(void*)0,(OS_STK*)&Task1_StackSTACKSIZE-1,Task1_Prio );OSStart();/start the game/never reached/return 0;/89测试C/OS-II(3)void Task1(void*Id)for(;)Uart_Printf(run tas
46、k1n);OSTimeDly(1000);void Task2(void*Id)for(;)Uart_Printf(run task2n);OSTimeDly(2000);void SYS_Task(void*Id)uHALr_InstallSystemTimer();Uart_Printf(start system task.n);for(;)OSTimeDly(10000);90关于移植关于移植相对于其他的嵌入式操作系统,相对于其他的嵌入式操作系统,C/OS-IIC/OS-II的移植虽然是一的移植虽然是一个很简单的过程,但是,对于不熟悉个很简单的过程,但是,对于不熟悉 C/OS-IIC/O
47、S-II的开发者,移植还的开发者,移植还是有一定难度的。是有一定难度的。91移植要点移植要点l定义函数定义函数OS_ENTER_CRITICALOS_ENTER_CRITICAL和和OS_ENTER_CRITICALOS_ENTER_CRITICAL。l定义函数定义函数OS_TASK_SWOS_TASK_SW执行任务切换。执行任务切换。l定义函数定义函数OSCtxSwOSCtxSw实现用户级上下文切换,用纯汇编实现。实现用户级上下文切换,用纯汇编实现。l定义函数定义函数OSIntCtxSwOSIntCtxSw实现中断级任务切换,用纯汇编实现。实现中断级任务切换,用纯汇编实现。l定义函数定义函数
48、OSTickISROSTickISR。l定义定义OSTaskStkInitOSTaskStkInit来初始化任务的堆栈。来初始化任务的堆栈。92C/OS 的完善l固定的基于优先级的调度,不支持时间片,使用起来不方便。一固定的基于优先级的调度,不支持时间片,使用起来不方便。一个任务的基础上增加一个基于时间片的微型调度核。个任务的基础上增加一个基于时间片的微型调度核。l系统时钟中断,没有提供用户使用定时器,可以借鉴系统时钟中断,没有提供用户使用定时器,可以借鉴LinuxLinux的定的定时器加以修改。时器加以修改。l在对临界资源的访问上使用关闭中断实现,没有使用在对临界资源的访问上使用关闭中断实现,没有使用CPUCPU提供的提供的硬件指令,例如测试并置位。硬件指令,例如测试并置位。l只是一个实时多任务内核,没有图形用户接口(只是一个实时多任务内核,没有图形用户接口(GUIGUI)、)、文件系文件系统(统(FSFS)和和TCP/IPTCP/IP协议栈。协议栈。93