1实时嵌入式操作系统艾云峰aiyunfeng@gmail.comCollegeofComputing&CommunicationEngineeringReal-timeEmbeddedOperatingSystem2UC/OS-II的移植移植指的是什么?使一个实时内核能在其它的微处理器或微控制器上运行UC/OS-II要在新的处理上运行,用户必须移植:UC/OS-II内核规定了一些和底层处理器相关的函数的函数原型及实现规定。在某个处理器上的移植工作必须把具体实现添加到UC/OS-II的源代码中UC/OS-II内核规定了在某处理器上使用UC/OS-II内核时,实现中断服务程序必须遵守的规定;在某个处理器上的移植工作中,实现中断服务程序必须满足这个规定UC/OS-II规定了在某处理器上使用UC/OS-II时,必须提供一个时钟中断服务函数;并对该函数的具体实现做了规定。在某个处理器上的移植工作中,必须提供这个时钟中断服务函数,并满足UC/OS-II的规定3主要内容某处理器能运行UC/OS-II所必须满足的条件UC/OS-II内核源代码文件组成移植工作的主要内容OS_CPU.HOS_CPU_A.ASMOS_CPU_A.C4移植必须满足的条件(1)必须明白的问题:uc/os-II操作系统并不是能够移植到任何处理器上面,只有处理器及其编译器满足一定条件时才能把uc/os-II移植到该处理器上面要使UC/OS-II正常运行,处理器必须满足以下条件:处理器支持中断,并且能产生定时中断(通常为0~100Hz)uc/os-II是通过处理器产生的定时器中断来实现多任务之间的调度的。处理器能支持一定数量的数据存储硬件堆栈(可能是几千字节)对于一些只有10根地址线的8位控制器,芯片最多可访问1KB存储单元。在这样的条件下移植是比较困难的。5移植必须满足的条件(2)在C程序中就可以开/关中断在uc/os-II中,可以通过OS_ENTER_CRITICAL()或者OS_EXIT_CRITICAL()宏来控制系统关闭或者打开中断。这需要处理器的支持,在ARM7TDMI的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。处理器有将堆栈指针以及其他CPU寄存器的内容读出、并存储到堆栈或内存中去的指令Uc/os-II进行任务调度的时候,会把当前任务的CPU寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是uc/os-II多任务调度的基础。6UC/OS-II内核源代码文件组成(1)OS_CORE.COS_FLAG.COS_MBOX.COS_MME.COS_MUTEX.COS_Q.COS_SEM.COS_TASK.COS_TIME.CuCOS_II.CuCOS_II.HOS_CFG.HINCLUDES.HOS_CPU.HOS_CPU_A.ASMOS_CPU_C.CUC/OS-II(与处理器无关代码)UC/OS-II配置(与应用相关)UC/OS-II移植(处理器相关代码)应用程序(用户代码)CPU定时器软件硬件7UC/OS-II内核源代码文件组成(2)核心代码部分:这部分代码与处理器无关,包括10个源代码文件和1个头文件。这10个源代码文件负责的功能分别是内核管理、事件标志组管理、消息管理、存储管理、互斥信号量管理、消息队列管理、信号量管理、任务调度和定时管理。配置代码部分:包括两个头文件,用来配置UC/OS-II,对其进行裁剪。处理器相关的移植代码部分:这部分包括一个头文件、一个汇编文件和一个c代码文件。在移植过程中,用户所需要关注的就是这部分文件。8移植工作的主要内容用#define设置一个常量的值(OS_CPU.H)声明10个数据类型(OS_CPU.H)用#define声明三个宏(OS_CPU.H)用C语言编写10个简单的函数(OS_CPU_C.C)编写四个汇编语言函数(OS_CPU_A.ASM)9OS_CPU.H中应修改的内容(1)-数据类型定义与编译器相关的数据类型typedefxxxBOOLEAN;typedefxxxINT8U;typedefxxxINT8S;typedefxxxINT16U;typedefxxxINT16S;typedefxxxINT32U;typedefxxxINT32S;typedefxxxFP32;typedefxxxFP64;原因:UC/OS-II代码中从不使用C语言中的short、int等数据类型。而是使用如左栏所示的INT8U、INT16S等数据类型以INT8U等形式定义的变量的长度在内核中是固定的。把UC/OS-II移植到某处理器时,必须查阅其编译器的手册,正确的定义诸如INT8U、INT16S等UCOS使用的数据类型。10OS_CPU.H中应修改的内容(2)-堆栈及状态寄存器类型正确定义处理器任务堆栈的数据类型typedefxxxOS_STK;定义堆栈增长的类型#defineOS_STK_GROWTHx0表示堆栈从低地址向高地址增长1表示堆栈从高地址向低地址增长正确定义处理器CPU程序状态寄存器的数据类型typedefxxxOS_CPU_SR;11OS_CPU.H中应修改的内容(3)-开/关中断宏定义两个宏及1个变量#defineOS_CRITICAL_METHOD?#defineOS_ENTER_CRITICAL()?#defineOS_EXIT_CRITICAL()?正确的定义上述宏需要了解三种开/关中断的方式,分别是直接调用处理器指令关中断/开中断方式关中断前把中断状态保存到堆栈中,然后关中断;OS_EXIT_CRITICAL从堆栈中恢复保存的中断开/关状态关中断前把中断状态保存到变量中,然后关中断;OS_EXIT_CRITICAL从保存的变量中恢复原先中断开/关状态12OS_CPU.H中应修改的内容(4)-实现任务切换的宏定义实现任务级之间任务切换的宏:#defineOS_TASK_SW()xxx两种实现方式:提供软件中断的CPU,可定义成软中断指令如SWI0x1。软件中断的中断向量地址必须指向OSCtxSw()。不提供软件中断的CPU,可将OS_TASK_SW()直接定义成OSCtxSW()。OS_TASK_SW()是一个宏,它是在μC/OS-Ⅱ从低优先级任务切换到最高优先级任务时被调用的。OS_TASK_SW()总是在任务级代码中被调用的。13OS_CPU_A.ASM中应修改的内容(1)-OSCtxSW()原理:任务的切换可通过保存当前任务的上下文和恢复要执行任务的上下文动作来完成。该动作由OSCtxSW()来完成上下文:任务执行时所有CPU寄存器的内容上下文保存在任务的堆栈中,堆栈指针保存在任务的任务控制块中OSCtxSW()的示意性代码:14任务切换的实现分析假定在某个CPU上运行,该CPU有7个寄存器1个堆栈指针(SP)1个程序计数器(PC)1个处理器状态寄存器(PSW)4个通用寄存器(R1~R4)情景:假定某个时刻1个任务正在调用OSSched()函数,而此时另外一个高优先级任务正处于就绪状态。路线:OSSched()-OS_TASK_SW()-OSCtxSw新的任务15调用OS_TASK_SW前的数据结构保存当前任务的context装入要运行的任务的context16OS_CPU_A.ASM中应实现的内容-OSStartHighRdy该函数的调用及功能:该函数由OSStart函数调用。OSStart函数负责使就绪状态的任务开始运行,其中OSStartHighRdy负责获取新任务的堆栈指针,并从堆栈指针中恢复新任务的所有处理器寄存器重大问题:任务刚刚创建后,堆栈是如何设置的?怎样把任务运行的第一条指令的地址存入到堆栈的呢?OSStartHighRdy的示意性代码:17OS_CPU_A.ASM中应实现的内容-OSTickISRμC/OS-Ⅱ要求用户提供一个时钟资源来实现时间的延时和超时功能。时钟节拍应该每秒钟发生10-100次。为了完成该任务,可以使用硬件时钟,也可以从交流电中获得50/60Hz的时钟频率用户必须在开始多任务调度后(即调用OSStart()后)允许时钟节拍中断。换句话说,就是用户应该在OSStart()运行后,μC/OS-Ⅱ启动运行的第一个任务中初始化节拍中断。通常所犯的错误是在调用OSInit()和OSStart()之间允许时钟节拍中断。可能在μC/OS-Ⅱ开始执行第一个任务前时钟节拍中断就发生了。在这种情况下,μC/OS-Ⅱ的运行状态不确定,用户的应用程序也可能会崩溃。18OS_CPU_A.ASM中应实现的内容-OSTickISR时钟节拍ISR的原型如图所示。这些代码必须写在汇编语言中,因为用户不能直接从C语言中访问CPU寄存器。如果用户的处理器可以通过单条指令来增加OSIntNesting,那么用户就没必要调用OSIntEnter()了。增加OSIntNesting要比通过函数调用和返回快得多。OSIntEnter()只增加OSIntNesting,并且作为临界段代码中受到保护。19OS_CPU_A.ASM中应实现的内容-OSIntCtxSw下节课结合ARM来分析20OS_CPU_C.C中要实现的内容-OSTaskStkInt()该函数的调用及功能:OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInt()来初始化任务的堆栈结构。堆栈初始化之后,就像该任务刚刚被切换出来一样。21AnyQuestions?