嵌入式系统-—基于32位微处理器与实时操作系统 Chap9.ppt
嵌入式系统-基于32位微处理器与实时操作系统 Chap9 Still waters run deep.流静水深流静水深,人静心深人静心深 Where there is life,there is hope。有生命必有希望。有生命必有希望主要内容n移植规划移植规划nC/OS-II的移植的移植n嵌入式系统的初始化嵌入式系统的初始化 移植规划-概述 所谓“移植”,就是使一个实时内核能在其它的微处理器或微控制器上运行。尽管大部分C/OS-II的代码是用C语言编写的,但是在编写与处理器硬件相关的代码时还是不得不使用汇编语言。移植的主要工作就是编写这些与处理器硬件相关的代码。操作系统的移植大体可以分为两个层次:n跨体系结构的移植n针对特定处理器的移植 移植规划 在移植前针对所使用的微处理器进行规划,主要有以下几个方面的考虑:n 编译器的选择n 任务模式的选择n 支持的指令集 移植规划(续)编译器的选择n针对ARM处理器核的C语言编译器有很多,如SDT、ADS、IAR、TASKING和GCC等n目前在国内最流行的是ADS、SDT和GCCnSDT和ADS均为ARM公司自己开发,ADS为SDT的升级版,以后ARM公司不再支持SDT,故不选择SDT。GCC虽然支持广泛,很多开发套件使用它作为编译器,但是与ADS比较其编译效率较低,这对充分发挥芯片性能不利n考虑使用ADS编译程序和调试ARMARM的工作模式的工作模式nARMARM处理器有处理器有7 7种操作模式种操作模式:n用户模式用户模式(usr)(usr)n -正常的程序执行模式正常的程序执行模式n快速中断模式快速中断模式(fiq)(fiq)-支持高速数据传输或通道处理支持高速数据传输或通道处理n中断模式中断模式(irq)irq)-用于通用中断处理用于通用中断处理n管理员模式管理员模式(svc)(svc)-操作系统的保护模式操作系统的保护模式.n中止模式中止模式(abt)(abt)-支持虚拟内存和支持虚拟内存和/或内存保护等异常或内存保护等异常n系统模式系统模式(sys)(sys)-支持操作系统的特殊用户模式支持操作系统的特殊用户模式(运行操作系统任务)运行操作系统任务)n未定义模式未定义模式(und)(und)-支持硬件协处理器的软件仿真支持硬件协处理器的软件仿真 n除了用户模式外,其他模式均可视为特权模式除了用户模式外,其他模式均可视为特权模式 移植规划(续)n任务模式的取舍 ARM7处理器核具有上述七种模式,其中除用户模式外其它均为特权模式。其中管理、中止、未定义、中断和快中断模式与相应异常相联系,任务使用这些模式不太适合。系统模式除了是特权模式外,其它与用户模式一样,因而可选为任务使用的模式只有用户模式和系统模式。为了尽量减少任务代码错误对整个程序的影响,缺省的任务模式定为用户模式,可选为系统模式,同时提供接口使任务可以在这两种模式间切换。移植规划(续)n支持的指令集带T变量的ARM7处理器核具有两个指令集:n标准32位ARM指令集n16位Thumb指令集 两种指令集有不同的应用范围。n为了最大限度地支持芯片的特性,任务应当可以使用任意一个指令集并可以自由切换,而且不同的任务应当可以使用不同的指令集移植C/OS-IIn概述 要移植一个操作系统到一个特定的CPU体系结构并不是一件很容易的事情,它对移植者有以下要求:1 对目标体系结构要有很深了解;2 对OS原理要有较深入的了解;3 对所使用的编译器要有较深入的了解;4 对需要移植的操作系统要有相当的了解;5 对具体使用的芯片也要一定的了解 要移植一个操作系统到一个特定的CPU体系结构上并不是一件很容易的事情,它对移植者有以下要求:1 对目标体系结构要有很深了解;2 对OS原理要有较深入的了解;3 对所使用的编译器要有较深入的了解;4 对需要移植的操作系统要有相当的了解;5 对具体使用的芯片也要一定的了解。概述 要移植一个操作系统到一个特定的CPU体系结构上并不是一件很容易的事情,它对移植者有以下要求:1 对目标体系结构要有很深了解;2 对OS原理要有较深入的了解;3 对所使用的编译器要有较深入的了解;4 对需要移植的操作系统要有相当的了解;5 对具体使用的芯片也要一定的了解。参考ARM公司的ARM体系结构文档参考嵌入式实时操作系统C/OS-II 一书参考ADS软件自带的编译器和连接器手册参考嵌入式实时操作系统C/OS-II 一书参考具体芯片的数据手册和使用手册因为第4点的影响是全局性的,它决定移植代码的框架和功能。所以重点介绍第4点。主要内容主要内容n移植规划移植规划nC/OS-II的移植的移植n嵌入式系统的初始化嵌入式系统的初始化 C/OSC/OS-II-II的文件结构的文件结构 C/OS-II移植应用程序(用户代码)C/OS-II(与处理器无关代码)OS_CORE.cOS_FLAG.c.C/OS-II配置(与应用相关)OS_CFG.HINCLUDES.H C/OS-II移植(与处理器相关代码)CPU定时器 硬件软件C/OS-II硬件软件体系结构用于产生系统时钟移植时需要编写的代码移植移植 C/OS-II满足的条件满足的条件 n处理器的C编译器能产生可重入代码 n在程序中可以打开或者关闭中断 n处理器支持中断,并且能产生定时中断(通常在10100Hz之间)n处理器支持能够容纳一定量数据的硬件堆栈(通常是几千字节)n处理器有将堆栈指针和其他CPU寄存器的内容存储和读出到堆栈(或者内存)的指令 什么是可重入代码什么是可重入代码 n可重入的代码指的是一段可以被多个任务同时调用,而不必担心会破坏数据的代码(比如:一个函数)n即:可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,而影响函数中的数据 可重入代码举例可重入代码举例程序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;不可重入函数被中断破坏不可重入函数被中断破坏如何使函数具有可重入性如何使函数具有可重入性 使Swap()函数具有可重入性的条件:n把Temp定义为局部变量n调用Swap()函数之前关中断,调用 后再开中断n用信号量禁止该函数在使用过程中 被再次调用 概述 根据C/OS-II的要求,移植C/OS-II到一个新的体系结构上需要提供2个或3个文件:OS_CPU.H(C语言头文件)OS_CPU_C.C(C程序源文件)OS_CPU_A.ASM(汇编程序源文件)其中OS_CPU_A.ASM在某些情况下不需要,但极其罕见。不需要OS_CPU_A.ASM的必须满足以下苛刻条件:1.可以直接使用C语言开关中断;2.可以直接使用C语言编写中断服务程序;3.可以直接使用C语言操作堆栈指针;4.可以直接使用C语言保存CPU的所有寄存器。移植需要编写的文件 概述移植内容类型所属文件描述BOOLEAN、INT8U、INT8S、数据类型OS_CPU.H与编译器无关的数据类型OS_STK数据类型OS_CPU.H堆栈的数据类型OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()宏OS_CPU.H开关中断的代码OS_STK_GROWTH常量OS_CPU.H定义堆栈的增长方向OS_TASK_SW函数OS_CPU.H任务切换时执行的代码OSTaskStkInit()函数OS_CPU_C.C任务堆栈初始化函数OSInitHookBegin()、OSInitHookEnd()、函数OS_CPU_C.CC/OS-II在执行某些操作时调用的用户函数,一般为空OSStartHighRdy()函数*OS_CPU_A.ASM进入多任务环境时运行优先级最高的任务,OSIntCtxSw()函数*OS_CPU_A.ASM中断退出时的任务切换函数OSTickISR()中断服务程序*OS_CPU_A.ASM时钟节拍中断服务程序 实际上,还有一个文件很重要,它就是IRQ.INC,它定义了一个汇编宏,它是C/OS-II for ARM7通用的中断服务程序的汇编与C函数接口代码接口代码。时钟节拍中断服务程序也没有移植,因为其与芯片和应用都强烈相关,需要用户自己编写,不过可以通过IRQ.INC简化用户代码的编写。移植代码包括的主要内容关于头文件includes.h和config.hn C/OS-II要求所有.C文件的都要包含头文件includes.h,这样使得用户项目中的每个.C文件不用分别去考虑它实际上需要哪些头文件。n 使用INCLUDES.H的缺点是它可能会包含一些实际不相关的头文件,这意味着每个文件的编译时间可能会增加,但却增强了代码的可移植性。在移植中另外增加了一个头文件config.h,要求所有用户程序必须包含config.h,在config.h中包含includes.h和特定的头文件和配置项。而C/OS-II的系统文件依然只是包含includes.h,即C/OS-II的系统文件完全不必改动。所有的配置改变包括头文件的增减均在config.h中进行,而includes.h定下来后不必改动(C/OS-II的系统文件需要包含的东西是固定的)。这样,C/OS-II的系统文件需要编译的次数大大减少,编译时间随之减少。congfig.hUC/OS内核文件Includes.h用户程序设置与处理器和编译器相关的代码设置与处理器和编译器相关的代码nOS_CPU.H中定义了与编译器相关的数据类型。比如:INT8U、INT8S等。n与 ARM处理器相关的代码,使用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()宏开启关闭中断n设置堆栈的增长方向:堆栈由高地址向低地址增长 编写OS_CPU.H C/OS-II使用结构常量OS_STK_GROWTH中指定堆栈的生长方式:置OS_STK_GROWTH为0表示堆栈从下往上长。置OS_STK_GROWTH为1表示堆栈从上(高地址)(高地址)往下(低地址)(低地址)长。虽然ARM处理器核对于两种方式均支持,但ADS的C语言编译器仅支持一种方式,即从上往下长,并且必须是满递减堆栈,所以OS_STK_GROWTH的值为1。#define OS_STK_GROWTH 1 堆栈生长方式 编写OS_CPU.H C/OS-II不使用C语言中的short、int、long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性与处理器类型有关,隐含着不可移植性。代之以移植性强的整数数据类型,这样,既直观又可移植,不过这就成了必须移植的代码。根据ADS编译器的特性,这些代码如下程序清单所示(与编译有关)。typedefunsigned char BOOLEAN;typedefunsigned char INT8U;typedefsigned char INT8S;typedefunsigned short INT16U;typedefsigned short INT16S;typedefunsigned int INT32U;typedefsigned int INT32S;typedeffloat FP32;typedefdouble FP64;typedefINT32U OS_STK;不依赖于编译的数据类型设置设置includes.htypedef 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 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 /*从高向低*/程序状态寄存器程序状态寄存器(CPSR)n 条件位条件位:nN=1-结果为负,0-结果为正或0nZ=1-结果为0,0-结果不为0nC=1-进位,0-借位nV=1-结果溢出,0结果没溢出nQ Q 位位:n仅ARM 5TE/J架构支持n指示增强型DSP指令是否溢出nJ J 位位n仅ARM 5TE/J架构支持nJ=1:处理器处于Jazelle状态n中断禁止位中断禁止位:nI =1:禁止 IRQ.nF=1:禁止 FIQ.nT BitT Bitn仅ARM xT架构支持nT=0:处理器处于 ARM 状态nT=1:处理器处于 Thumb 状态nModeMode位位(处理器模式位处理器模式位):):n0b10000Usern0b10001FIQn0b10010IRQn0b10011Supervisorn0b10111Abortn0b11011Undefinedn0b11111System2731N Z C V Q2867I F T mode1623 815 54024fsxc U n d e f i n e dJ 编写OS_CPU.H C/OS-II运行时,处理器可能处于的模式如下图所示:使用软中断SWI作底层接口Thumb指令集ARM指令集用户模式系统模式用户任务使用的处理器模式ARM7内核具有的指令集ARM指令用户模式ARM指令系统模式Thumb指令系统模式Thumb指令用户模式 编写OS_CPU.H 为了使底层接口函数与处理器状态无关,同时在任务调用相应的函数不需要知道函数位置,在移植中使用软中断指令SWI作为底层接口,使用不同的功能号区分不同的函数。软中断功能号分配如下表所示,未列出的为保留功能。使用软中断SWI作底层接口功能号接口函数简介0 x00void OS_TASK_SW(void)任务级任务切换函数0 x01_OSStartHighRdy(void)运行优先级最高的任务,由OSStartHighRdy产生0 x02void OS_ENTER_CRITICAL(void)关中断0 x03Void OS_EXIT_CRITICAL(void)开中断0 x80Void ChangeToSYSMode(void)任务切换到系统模式0 x81Void ChangeToUSRMode(void)任务切换到用户模式0 x82Void TaskIsARM(INT8U prio)任务代码是ARM代码0 x83Void TaskIsTHUMB(INT8U prio)任务代码是THUMB代码 编写OS_CPU.H 用软中断作为操作系统的底层接口就需要在C语言中使用SWI(SoftWare Interrupt)指令。在ADS中,有一个关键字_swi,用它声明一个不存在的函数,则调用这个函数就在调用这个函数的地方插入一条SWI指令,并且可以指定功能号。同时,这个函数也可以有参数和返回值,其传递规则与一般函数相同。使用软中断SWI作底层接口/*任务级任务切换函数*/_swi(0 x00)void OS_TASK_SW(void);/*运行优先级最高的任务 */_swi(0 x01)void _OSStartHighRdy(void);/*关中断 */_swi(0 x02)void OS_ENTER_CRITICAL(void);/*开中断 */_swi(0 x03)void OS_EXIT_CRITICAL(void);/*任务切换到系统模式 */_swi(0 x80)void ChangeToSYSMode(void);/*任务切换到用户模式 */_swi(0 x81)void ChangeToUSRMode(void);/*任务代码是ARM代码 */_swi(0 x82)void TaskIsARM(INT8U prio);/*任务代码是THUMB代码*/_swi(0 x83)void TaskIsTHUMB(INT8U prio);程序中调用软中断时使用的函数名软件中断号该调用不返回参数编写OS_CPU_C.CnC/OS-IIC/OS-II的移植要求用户编写的移植要求用户编写1010个个C C函数:函数:nOSTaskStkInitOSTaskStkInit():():OSTaskCreat OSTaskCreat()和()和OSTaskCreatExtOSTaskCreatExt()通过调用()通过调用 本函数,初始化任务的栈结构本函数,初始化任务的栈结构nOSTaskCreateHookOSTaskCreateHook():每当添加任务时由():每当添加任务时由OS_TCBInit()OS_TCBInit()函数调用函数调用nOSTaskDelHookOSTaskDelHook():():任务被删除后由任务被删除后由OSTaskDelOSTaskDel()调用()调用nOSTaskSwHookOSTaskSwHook():():任务切换时两种情况均会调用该函数任务切换时两种情况均会调用该函数nOSTaskIdleHookOSTaskIdleHook():():OSTaskIdleOSTaskIdle()函数可调用该函数实现()函数可调用该函数实现CPUCPU低功耗模式低功耗模式nOSTimeTickHookOSTimeTickHook():本函数在每个时钟节拍都会被():本函数在每个时钟节拍都会被OSTimeTickOSTimeTick()调用()调用nOSInitHookBeginOSInitHookBegin():进入():进入OSInitOSInit()函数后本函数会立即被调用()函数后本函数会立即被调用nOSInitHookEndOSInitHookEnd():():OSInit OSInit()函数返回之前被调用()函数返回之前被调用nOSTCBInitHookOSTCBInitHook():():OS_TCBInit()OS_TCBInit()在调用在调用OSTaskCreateHookOSTaskCreateHook()之前将先()之前将先 调用本函数调用本函数n唯一必要的函数是唯一必要的函数是OStaskStkInitOStaskStkInit(),其他(),其他9 9个函数必须声明,但不一定个函数必须声明,但不一定要包含任何代码要包含任何代码编写OS_CPU_C.C 该函数用于初始化任务堆栈,使任务的堆栈看起来就像刚发生中断一样。即任务被执行时,就像从中断返回一样。在编写此函数之前,必须先确定任务的堆栈结构。而任务的堆栈结构是与CPU的体系结构、编译器有密切的关联。本移植的堆栈结构如下图所示。OSTaskStkInit()任务入栈的其它数据LRR12R11R10R9R8.栈底 任务环境开始 SPPCR2R1R0OSEnterSum空闲空间编写OS_CPU_C.COSTaskStkInit()OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT16U opt)OS_STK*stk;opt =opt;stk =ptos;*stk=(OS_STK)task;*-stk=(OS_STK)task;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=(unsigned int)pdata;*-stk=(USER_USING_MODE|0 x00);*-stk=0;return(stk);入栈的数据任务入栈的其它数据LRR12R11R10R9R8.栈底 任务环境开始 SPPCR2R1R0OSEnterSum空闲空间编写OS_CPU_C.COSTaskStkInit()OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT16U opt)OS_STK*stk;opt =opt;stk =ptos;*stk=(OS_STK)task;*-stk=(OS_STK)task;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=0;*-stk=(unsigned int)pdata;*-stk=(USER_USING_MODE|0 x00);*-stk=0;return(stk);该数据比较特别,它用于保存该任务关中断的次数,它在调用OS_ENTER_CRITICAL()时加1,在调用OS_EXIT_CRITICAL()时减1。这样每个任务都可以独立控制本任务的中断允许状态,而不会影响其它任务的中断允许状态。因此关中断和开中断就可以嵌套。编写OS_CPU_C.C软件中断异常服务程序 操作系统与硬件相关的底层函数使用软件中断作为接口,如下表所示。n 移植代码中一个重要的工作就是为这些软件中断编写服务程序功能号接口函数简介0 x00void OS_TASK_SW(void)任务级任务切换函数0 x01_OSStartHighRdy(void)运行优先级最高的任务,由OSStartHighRdy产生0 x02void OS_ENTER_CRITICAL(void)关中断0 x03Void OS_EXIT_CRITICAL(void)开中断0 x80Void ChangeToSYSMode(void)任务切换到系统模式0 x81Void ChangeToUSRMode(void)任务切换到用户模式0 x82Void TaskIsARM(INT8U prio)任务代码是ARM代码0 x83Void TaskIsTHUMB(INT8U prio)任务代码是THUMB代码编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码功能号接口函数简介0 x00void OS_TASK_SW(void)任务级任务切换函数0 x01_OSStartHighRdy(void)运行优先级最高的任务,由OSStartHighRdy产生0 x02void OS_ENTER_CRITICAL(void)关中断0 x03Void OS_EXIT_CRITICAL(void)开中断0 x80Void ChangeToSYSMode(void)任务切换到系统模式0 x81Void ChangeToUSRMode(void)任务切换到用户模式0 x82Void TaskIsARM(INT8U prio)任务代码是ARM代码0 x83Void TaskIsTHUMB(INT8U prio)任务代码是THUMB代码void SWI_Exception(int SWI_Num,int*Regs)OS_TCB *ptcb;switch(SWI_Num)case 0 x02:/关中断 .case 0 x03:/开中断 .case 0 x80:/任务切换到系统模式 .case 0 x81:/任务切换到用户模式 .case 0 x82:/任务代码是ARM代码 .case 0 x83:/任务代码是Thumb代码 .default:这两个软件中断使用汇编代码完成编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码 C/OS-II的启动多任务环境的函数叫做OSStart(),用户在调用OSStart()之前,必须已经建立了一个或更多任务。OSStart()最终调用函数OSStartHighRdy()运行多任务启动前优先级最高的任务。void OSStartHighRdy(void)_OSStartHighRdy();该函数在Os_cpu_a.s文件中实现。编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码 关中断和开中断是为了保护临界段代码。这些代码与处理器有关,是需要移植的代码。在ARM处理器核中关中断和开中断时通过改变程序状态寄存器CPSR中的相应控制位实现。由于使用了软件中断,程序状态寄存器CPSR保存到程序状态保存寄存器SPSR中,软件中断退出时会将SPSR恢复到CPSR中,所以程序只要改变程序状态保存寄存器SPSR中的相应的控制位就可以了。编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码void SWI_Exception(int SWI_Num,int*Regs).case 0 x02:/关中断 _asm MRS R0,SPSR ORR R0,R0,#NoInt MSR SPSR_c,R0 OsEnterSum+;break;case 0 x03:/开中断 if(-OsEnterSum=0)_asm MRS R0,SPSR BIC R0,R0,#NoInt MSR SPSR_c,R0 break;.每关闭一次中断,中断关闭计数器加1每调用一次开中断函数,该计数器减1,为0时允许打开中断关闭中断打开中断编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码 它们可以在任何情况下使用。它们改变程序状态保留寄存器程序状态保留寄存器SPSRSPSR的相应位段,而程序状态保留寄存器会在软件中断退出时复制到程序状态寄存程序状态寄存器器CPSRCPSR,任务的处理器模式就改变了。编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码void SWI_Exception(int SWI_Num,int*Regs).case 0 x80:/任务切换到系统模式 _asm MRS R0,SPSR BIC R0,R0,#0 x1f ORR R0,R0,#SYS32Mode MSR SPSR_c,R0 break;case 0 x81:/任务切换到用户模式 _asm MRS R0,SPSR BIC R0,R0,#0 x1f ORR R0,R0,#USR32Mode MSR SPSR_c,R0 break;.使用内嵌汇编将处理器模式切换到用户模式使用内嵌汇编将处理器模式切换到系统模式编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码 任务可以使用ARM的两种指令集的任意一种运行,但是任务建立时默认的只是一种指令集。如果任务使用的第一条指令与默认的指令集不同,则程序运行错误。所以增加两个函数TaskIsARM()和TaskIsTHUMB()用于改变任务建立时用于改变任务建立时默认的指令集。默认的指令集。它们都有唯一的参数:需要改变的任务的优先级,值得注意的是,这两个函数必须在相应的任务建立后但还没有运行时调用。编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码 .case 0 x82:/任务代码是ARM代码 if(Regs0 OSTCBStkPtr1&=(1 5);break;case 0 x83:/任务代码是Thumb代码 if(Regs0 OSTCBStkPtr1|=(1 5);break;.被设置的任务号一定不能大于最低优先级任务获取指定任务的任务控制块的地址修改任务堆栈中CPSR的值,在任务重新运行时,切换到ARM指令方式修改任务堆栈中CPSR的值,在任务重新运行时,切换到Thumb指令方式CPSR:程序状态寄存器程序状态寄存器编写OS_CPU_C.C软件中断异常服务程序功能号简介0 x00任务级任务切换函数0 x01运行优先级最高的任务,由OSStartHighRdy产生0 x02关中断0 x03开中断0 x80任务切换到系统模式0 x81任务切换到用户模式0 x82任务代码是ARM代码0 x83任务代码是THUMB代码注意:这两个函数必须在相应的任务建立后但还没有运行时调用。如果在低优先级的任务中创建高优先级的任务就十分危险了。此时,解决的方法有三种:(1)高优先级任务使用默认的指令集;(2)改变函数OSTaskCreateHook()使任务默认不是处于就绪状态,建立任务后调用函数OSTaskResume()来使任务进入就绪状态;(3)建立任务时禁止任务切换,调用函数 TaskIsARM()或TaskIsTHUMB()后再允许任务切换。编写OS_CPU_C.C 在Os_cpu_c.c文件中还有许多Hook()函数,它们在某个特定的系统动作时被调用,允许执行函数中的用户代码。这些函数默认是空函数,用户根据实际情况添加相关代码。它们分别如下表所示。Hook()函数函数名被执行条件OSInitHookBegin()在开始执行OSInit()函数时被执行OSInitHookEnd()在OSInit()函数结束时被执行OSTaskCreateHook()在任务建立时被调用OSTaskDelHook()在任务删除时被调用OSTaskSwHook()在进行任务切换时被调用OSTaskStatHook()被统计任务调用,每秒执行一次OSTCBInitHook()在建立所有的TCB后,由OSTCBInit函数调用OSTimeTickHook()每个时钟节拍产生后被调用OSTaskIdleHook()由空闲任务调用 移植C/OS-IIn编写OS_CPU_A.ASM在OS_CPU_A.ASM文件中有:n软件中断的汇编接口程序n任务切换程序nOS启动时运行就绪最高优先级任务的程序OS_CPU_A.ASMnC/OS-II的移植要求用户编写4个汇编语言函数:nOSStartHighRdy()nOSCtxSw()nOSIntCtxSw()nOSTickISR()n如果编译器支持插入行汇编代码,就可以将所有与处理器相关的代码放到OS_CPU_C.C文件中,而不必再有单独的汇编语言文件 编写OS_CPU_A.ASM 在调用软中断之后,处理器切换到ARM指令和管理模式下工作。在执行软件中断服务函数之前,要提取中断号和其它入口参数,这些通过软件中断接口程序完成。软件中断汇编接口SoftwareInterrupt LDR SP,StackSvc STMFD SP!,R0-R3,R12,LR MOV R1,SP MRS R3,SPSR TST R3,#T_bit LDRNEH R0,LR,#-2 BICNE R0,R0,#0 xff00 LDREQ R0,LR,#-4 BICEQ R0,R0,#0 xFF000000 CMP R0,#1 LDRLO PC,=OSIntCtxSw LDREQ PC,=_OSStartHighRdy BL SWI_Exception LDMFD SP!,R0-R3,R12,PC 保护被中断的现场将要用到的寄存器压栈判断中断前的指令集类型从产生软件中断的指令中提取中断号ARMThumb根据不同的中断号执行不同的程序返回被中断的任务中断号执行程序0进行任务切换1启动多任务环境,运行就绪的最高优先级任务其它软件中断服务函数 编写OS_CPU_A.ASM C/OS-II是抢占式实时操作系统,得到运行的始终是就绪条件下最高优先级的任务。当处于运行状态的任务因为某种原因进入就绪态,或者有其它更高优先级的任务进入就绪态,操作系统内核就要运行别的就绪任务,这时需要进行任务切换。任务切换代码编写OS_CPU_A.ASM 任务切换代码任务切换可能发生的情况有两种任务切换可能发生的情况有两种:1.当前运行的任务主动交出CPU控制权,通常发生在等待某个事件或是调用系统延时。调用函数OS_TASK_SW()2.发生中断,使更高优先级的任务进入就绪状态,内核剥夺当前任务的运行资格。即发生在中断退出时。调用函数OSIntCtxSw()SPSR:程序状态保留寄存器程序状态保留寄存器CPSR:当前当前程序状态寄存器程序状态寄存器 编写OS_CPU_A.ASM 虽然OS_TASK_SW()和OSIntCtxSw()的执行条件不同,但是它们的功能相同,只要稍作处理就可以它们共用一段任务切换代码。这些处理就是保证在执行任务切换前两者的任务现场是一致的。共同执行的任务切换代码是“OSIntCtxSw”其中OS_TASK_SW()是通过软件中断软件中断0完成的,通过前面的分析,可以知道执行任务切换时的现场环境如下所示,同时R3中保存着SPSR,它是任务中断前CPSR的备份。任务切换代码任务入栈的其它数据LRR12R3R2R1R0空闲空间 栈底 任务环境开始 SP 编写OS_CPU_A.ASMOSIntCtxSw保存当前任务的寄存器组及其它修改当前任务的TCB堆栈指针用将要运行任务的优先级和TCB指针更新OSPrioHighRdy和OSTCBCur恢复新任务的寄存器组及其它运行新任务流程图 编写OS_CPU_A.ASMOSIntCtxSw保存当前任务的寄存器组及其它修改当前任务的TCB堆栈指针用将要运行任务的优先级和TCB指针更新OSPrioHighRdy和OSTCBCur恢复新任务的寄存器组及其它运行新任务流程图OSIntCtxSw ;下面为保存任务环境 LDR R2,SP,#20 ;获取PC LDR R12,SP,#16 ;获取R12 MRS R0,CPSR ;保存LR,PC及R4-R12 MSR CPSR_c,#(NoInt|SYS32Mode)MOV R1