1、嵌入式系统设计课程报告UCOS移植嵌入式系统设计课程报告题目:C/OS-II在ES44B0实验平台上的的移植姓名:郭卫平学号:0905030314所在院(系):计算机科学与工程学院专业班级:信息安全专业2009级 班开课学期:2012-2013-1学期任课教师:胡勇华1. 课题名称及其描述C/OS-II在ES44B0实验平台上的的移植2. 分析和总体设计要使C/OS-II正常运行,处理器必须满足以下要求: 处理器的C编译器能产生可重入型代码; 处理器支持中断,并且能产生定时中断(通常为10100 Hz); 用C语言开/关中断; 处理器能支持一定数量的数据存储硬件堆栈; 处理器有将堆栈指针以及其
2、它CPU寄存器的内容读出、并存储到堆栈或内存中去的指令。SDT和ADS均能产生可重入代码;s3c44b0处理器支持中断,并有6个定时器,其中5个还具有PWM功能,全部可配置为基于中断;SDT和ADS均支持C语言内嵌汇编,可方便实现中断开/关;足够数量的硬件堆栈,并且THUMB状态下有push、pop,ARM状态下有LDM、STM指令用于保存和恢复现场。综上可知,C/OS-II完全可以移植到s3c44b0上。S3C44B0处理器核具有SVC、USR、ABT、UND、IRQ、FIQ、SYS七种模式,其中除用户模式外其它均为特权模式。其中管理、中止、未定义、中断和快中断模式与相应异常相联系,任务使用
3、这些模式不太适合。系统模式除了是特权模式外,其它与用户模式一样,因而可选为任务使用的模式只有用户模式和系统模式。为了尽量减少任务代码错误对整个程序的影响,缺省的任务模式定为用户模式,可选为系统模式,同时提供接口使任务可以在这两种模式间切换。另外,为了保护操作系统,还需要使用SVC模式。SWI做为操作系统底层调用的接口。这使底层接口函数与处理器状态无关,同时在任务调用相应的函数不需要知道函数位置,使用不同的功能号区分不同的函数。S3c44b0处理器是ARM7TDMI内核,带T变量,具有两个指令集:标准32位ARM指令集和16位Thumb指令集,两种指令集有不同的应用范围。为了最大限度地支持芯片特
4、性,任务应当可以使用任意一个指令集并可以自由切换,而且不同的任务应当可以使用不同的指令集。3. 详细设计与实现C/OS-II硬件软件体系结构C/OS-II处理器相关代码编写Os_cpu.h的编写Os_cpu.h中除了定义与编译器无关的数据类型、以及与处理器相关的C/OS-II函数声明、常量和宏。OS_STK是堆栈类型,实际上是整数类型,在后面用来定义堆栈和堆栈指针。由于堆栈是32位的,所以把OS_STK定义为unsigned int类型,即四个字节。C/OS-II使用结构常量OS_STK_GROWTH中指定堆栈的生长方式:置OS_STK_GROWTH为0表示堆栈从下往上长;置OS_STK_GR
5、OWTH为1表示堆栈从上(高地址)往下(低地址)长。虽然ARM处理器核同时支持两种方式,但ADS的C语言编译器仅支持从上往下长,所以必须让OS_STK_GROWTH的值为1。用定义(#define)常数OS_CRITICAL_METHOD可以选择具体使用哪种开关中断方法。当OS_CRITICAL_METHOD=1时,如果调用C/OS-II功能函数时,中断是关掉的,则从C/OS-II函数返回时,中断就打开了。若调用C/OS-II功能函数之前已将中断关掉,那么用户往往希望从C/OS-II函数返回时,中断仍然是关着的。这时,这种方法就不妥当。但对于有些处理器,这可能是唯一选择。第二种方法是在堆栈中保
6、存中断的开/关状态,然后再关中断。第三种方法是把当前处理器的状态字(PSW)保存在C函数的局部变量中(如OS_CPU_SR)。关中断时保存,开中断时恢复。在本移植方案中,我们选择第二种方法。当然对于第三开关中断的方法,ARM处理器也是支持的。Os_cpu_c.c的编写C/OS-II源代码中已经给出os_cpu_c.c模板。首先,要修改其中的OSTaskStkInit( )函数即可。该函数对任务堆栈进行初始化。堆栈内容从栈底到栈顶依次为PC(R14)、LR(R13)、R12R0、OsEnterSum。其中,OsEnterSum用于保存该任务关中断的次数,它在调用OS_ENTER_CRITICAL
7、( )时加1,在调用OS_EXIT_CRITICAL( )时减1。这样每个任务都可以独立控制本任务的中断允许状态,而不会影响其它任务的中断允许状态。因此关中断和开中断就可以嵌套。其次,如果必要,填充钩子函数。模板文件中共有8个带“HOOK”字符串的函数,称为钩子函数。这些函数都有对应的缺省“HOOK的C/OS-II调用与之对应。所谓必要是指有些用户可能希望扩展这些C/OS-II调用的功能。如果简单地修改这些调用无疑会破坏C/OS-II系统源代码,而通过HOOK函数既能保护系统源代码又使代码更加简洁。当然,要把HOOK函数编译进目标代码中,还应该在OS_CFG.H中打开OS_CPU_HOOKS_
8、EN宏。最后,对于本移植方案,还在本文件中添加了三个函数。OSStartHighRdy():最终将调用os_cpu_s.s中的_OSStartHighRdy函数;_TaskIsARM():将处理器切换到ARM状态,准备执行ARM指令任务;_TaskIsTHUMB()将处理器切换到THUMB状态,准备执行THUMB指令任务。Os_cpu_s.s的编写定义软件中断汇编接口函数SoftwareInterrupt和软件中断服务程序。软件中断服务程序有多个,当被SoftwareInterrupt调用时通过软件中断号区分。中断号的区分如下:软件中断服务程序及其它相关函数的实现见附录。C/OS-II系统配置
9、主要是修改OS_CFG.H文件。通过这个文件,可以实现对C/OS-II进行裁减和相关优化。这里使用默认设置(调试时将会修改这个文件,禁止统计功能以方便调试)。关于INCLUDES.HC/OS-II要求所有.C文件的都要包含头文件includes.h,这样使得用户项目中的每个.C文件不用分别去考虑它实际上需要哪些头文件。代价是它可能会包含一些实际不相关的头文件,这意味着每个文件的编译时间可能会增加。另外,考虑到手动地在每个.C文件中包含需要的头文件有助于熟悉C/OS-II移植工程的代码结构和调用关系,所以,移植中决定不使用包含includes.h的方式。启动代码修改将软件中断异常时,PC指到0x
10、08处执行。在该处安排跳转指令,以跳到SoftwareInterrupt执行。代码详见附录。定时器初始化C/OS-II要求定时中断频率为10100Hz,通过查看s3c44b0手册:OneTickTime = (prescaler value + 1)*(divider value)*(rTCNTB0-rTCMPB0)MCLK。本移植方案使用Timer0做为系统时钟,设置预分频值为0x16,置分频值为2,MCLK设为48MHz,所以得到OneTickTime 26Hz。代码见附录。4. 运行与测试测试ADS(编译器、汇编器、及链接器)是否正常工作由于移植时恰好将汇编文件后辍名命名为.s,这正好是
11、ADS支持的后辍名,不用做修改。去除掉一些语法误后,ADS没有报错,几本确定ADS能正常工作。处理器相关函数验证验证OSTaskStkInit()和OSStartHighRdy()函数编写一个测试文件test.c,用于测试。代码见附录。其次,为了方便测试,禁止统计任务。修改OS_CFG.H文件,设置OS_TASK_STAT_EN为0。只让空闲任务工作,并单步执行,直到uC/OS-II切换到OS_TaskIdle()。单步时跳过OSInit()函数,单步进入OSStart()函数。 一直单步运行到调用OSStartHighRdy(),然后单步进入OSStartHighRdy(),接着高调用_OS
12、StartHighRdy()。最后切换到汇编语言模式下,因为_OSStartHighRdy()是用汇编语句实现的。_OSStartRdy()会开始运行第1个任务;而此时并没有任何应用任务.只有OS_TaskIdle()可以运行。调试器在OS_TaskIdle()循环中运行,且在无限循环中执行数次次,并没有出现任务问题,说明OSTaskStkInit()和OSStartHighRdy()函数是成功的。验证OSCtxSw()函数在test.c中增加如下语句#define MainTaskPrio 5 /定义优先级为5OS_STK MainTaskStkMainTaskStkLengh;void M
13、ainTask(void *pdata) /Main Task create taks0 and task1 while(1) /OSTimeDly(1); 然后在Main()中,OSInit ()和OSStart ()之间增加下语句OSTaskCreate (MainTask,(void *)0, &MainTaskStkMainTaskStkLengh - 1, MainTaskPrio); 这样就在C/OS-II添加了一个应用任务。单步执行,直到_OSStartRdy()开始运行第1个任务,由于MainTask比空闲任务优先级高,所以应该先被执行。然后一直执行while死循环。结果在预期
14、之内。至此OSCtxSw()验证通过。验证OSIntCtxSw()和OSTickISR()函数这两个函数的调试都需要涉及到中断,需要硬件调试工具的支持,由于缺少必要的JTAG调试工具没有进行验证。最后进行了增加应用程序后的的测试,测试结果如下图:5. 附录:主要源代码test.c#include bspinit.h#include void Main(void) /板级初始化 Bsp_Init(); /初始化uC/OS OSInit();OSStart();Os_cpu.h#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT#else#define OS_CPU_EX
15、T extern#endif/* 定义与编译器无关的数据类型*/typedef unsigned char BOOLEAN; /* 布尔变量 */typedef unsigned char INT8U; /* 无符号8位整型变量 */typedef signed char INT8S; /* 有符号8位整型变量 */typedef unsigned short INT16U; /* 无符号16位整型变量 */typedef signed short INT16S; /* 有符号16位整型变量 */typedef unsigned int INT32U; /* 无符号32位整型变量 */type
16、def signed int INT32S; /* 有符号32位整型变量 */typedef float FP32; /* 单精度浮点数(32位长度) */typedef double FP64; /* 双精度浮点数(64位长度) */typedef INT32U OS_STK; /* 堆栈是32位宽度 */* 以下是兼容UC/OS V1.XX的数据类型,在uC/OS-II没有使用 */#define BYTE INT8S#define UBYTE INT8U#define WORD INT16S#define UWORD INT16U#define LONG INT32S#define UL
17、ONG INT32U/* * 与S3C44B0体系结构相关的一些定义*/#define OS_CRITICAL_METHOD 2 /* 选择开、关中断的方式 */_swi(0x00) void OsSwiHandle1(int Handle);_swi(0x01) void *OsSwiHandle2(int Handle, int Index);#define OS_TASK_SW() OsSwiHandle1(0) /* 任务级任务切换函数 */#define _OSStartHighRdy() OsSwiHandle1(6) /* 运行优先级最高的任务 */#define OS_ENTE
18、R_CRITICAL() OsSwiHandle1(1) /* 关中断 */#define OS_EXIT_CRITICAL() OsSwiHandle1(2) /* 开中断 */#define GetOSFunctionAddr(Index) OsSwiHandle2(10, Index) /* 获取系统服务函数入口 */#define GetUsrFunctionAddr(Index) OsSwiHandle2(11, Index) /* 获取自定义服务函数入口 */#define OSISRBegin() OsSwiHandle1(3) /* 中断开始处理 */#define OSISR
19、NeedSwap() OsSwiHandle1(9) /* 判断中断是否需要切换 */#define ChangeToSYSMode() OsSwiHandle1(4) /* 任务切换到系统模式 */#define ChangeToUSRMode() OsSwiHandle1(5) /* 任务切换到用户模式 */#define TaskIsARM(prio) OsSwiHandle2(7, prio) /* 任务代码是ARM代码 */#define TaskIsTHUMB(prio) OsSwiHandle2(8, prio) /* 任务代码是THUMB */#define OS_STK_GR
20、OWTH 1 /* 堆栈是从上往下长的 */#define USR32Mode 0x10 /* 用户模式 */#define SYS32Mode 0x1f /* 系统模式 */#define NoInt 0x80#ifndef USER_USING_MODE#define USER_USING_MODE USR32Mode /* 任务缺省模式 */#endif#ifndef OS_SELF_EN#define OS_SELF_EN 0 /* 允许返回OS与任务分别编译、固化*/ #endifOS_CPU_EXT INT32U OsEnterSum; /* 关中断计数器(开关中断的信号量) */
21、* End Of File*/Os_cpu_c.c/* *-文件信息-*文 件 名: os_cpu_c.c*描 述: COS-II在lpc210x上的移植代码C语言部分,包括任务堆栈初始化代码和钩子函数等* 用ads1.2编译,必须使用ARM方式编译*/#define OS_CPU_GLOBALS#include config.h#if OS_SELF_EN = 0 int const _OSFunctionAddr1 = 0;int const _UsrFunctionAddr1 = 0;#endif/* 函数名称: OSTaskStkInit* 功能描述: 任务堆栈初始化代码,本函数调用失
22、败会使系统崩溃* 输入: task : 任务开始执行的地址* pdata :传递给任务的参数* ptos :任务的堆栈开始位置* opt :附加参数,当前版本对于本函数无用,具体意义参见OSTaskCreateExt()的opt参数* 输出: 栈顶指针位置* 全局变量:* 调用模块: */OS_STK *OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) OS_STK *stk; opt = opt; /* opt 没有使用。作用是避免编译器警告 */ stk = ptos; /* 获取堆栈
23、指针 */ /* 建立任务环境,ADS1.2使用满递减堆栈 */ *stk = (OS_STK) task; /* pc */ *-stk = (OS_STK) task; /* lr */ *-stk = 0; /* r12 */ *-stk = 0; /* r11 */ *-stk = 0; /* r10 */ *-stk = 0; /* r9 */ *-stk = 0; /* r8 */ *-stk = 0; /* r7 */ *-stk = 0; /* r6 */ *-stk = 0; /* r5 */ *-stk = 0; /* r4 */ *-stk = 0; /* r3 */ *
24、-stk = 0; /* r2 */ *-stk = 0; /* r1 */ *-stk = (unsigned int) pdata; /* r0,第一个参数使用R0传递 */ *-stk = (USER_USING_MODE|0x00); /* spsr,允许 IRQ, FIQ 中断 */ *-stk = 0; /* 关中断计数器OsEnterSum; */ return (stk);/* 函数名称: OSStartHighRdy* 功能描述: uC/OS-II启动时使用OSStartHighRdy运行第一个任务,* 实质是产生swi 1指令* 输入: 无* 输出 : 无* 全局变量: 无
25、* 调用模块: 无* *-*/void OSStartHighRdy(void) _OSStartHighRdy();/* 函数名称: _TaskIsARM* 功能描述: 任务代码是ARM代码* 输入: 无* 输出 : 无* 全局变量: 无* 调用模块: 无* */void _TaskIsARM(INT8U prio) OS_TCB *ptcb; if (prio OSTCBStkPtr1 &= (1 5); /* 函数名称: _TaskIsARM* 功能描述: 任务是THUMB代码* 输入: 无* 输出 : 无* 全局变量: 无* 调用模块: 无* */void _TaskIsTHUMB(I
26、NT8U prio) OS_TCB *ptcb; if (prio OSTCBStkPtr1 |= (1 5); /* 以下为一些钩子函数,全部为空函数。具体说明请看相关资料 */#if OS_CPU_HOOKS_EN/* OS INITIALIZATION HOOK* (BEGINNING)* Description: This function is called by OSInit() at the beginning of OSInit().* Arguments : none* Note(s) : 1) Interrupts should be disabled during this call.*