加入收藏 | 设为首页 | 会员中心 | 我要投稿 | RSSRSS-巴斯仪表网
您当前的位置:首页 > 电子发烧 > 单片机学习

uC/OS-II 在S3C44B0X 处理器上的移植

时间:2013-09-03  来源:123485.com  作者:9stone

    嵌入式实时操作系统RTOS 与通用操作系统相比较, 它具有实时性、可裁减、低资源占用等特点。而与传统的嵌入式设计方法相比, 实时多任务内核的运用允许程序员将具体的应用程序模块化, 更易于项目的开发。

1 uC/OS-II的简介
    目前市场上的商用嵌入式操作系统, 如Vxworks、PSOS 和Windows CE 等已经十分成熟, 提供有力的开发和调试工具, 但开发成本昂贵, 实时嵌入式操作系统uCOS-II 是基于优先级的抢占式实时多任务操作系统, 包含了实时内核、任务管理、时间管理、任务间通信同步( 信号量, 邮箱, 消息队列) 和内存管理等功能。绝大部分代码用C 语言写成, 与硬件相关部分用汇编语言编写。
    uC/OS-II是面向中小型嵌入式系统的。包含全部功能模块的内核大约为10KB, 如果经过裁减只保留核心代码, 则可压缩到3KB 左右。RAM的应用量与系统中的任务数有关, 任务的堆栈要占用大量的RAM空间, 堆栈的大小取决于任务的局部变量、缓冲区大小及可能的中断嵌套层数。应用程序的精度由系统的时钟节拍决定, uC/OS-II要用户提供周期性的时钟信号源, 用于实现时间延时和确认超时。
    uC/OS-II的工作原理如下: 首先把CPU 初始化, 再进行操作系统初始化。主要完成任务控制块(TCB) 初始化、TCB 优先级表初始化、TCB 链表初始化、事件控制块ECB 链表初始化和空任务的创建等; 然后开始创建新任务, 并可在新创建的任务中再创建其它的新任务; 最后调用OSSTART() 函数启动多任务调度。在多任务调度开始后, 启动时钟节拍源开始计时, 此节拍源给系统提供周期性的时钟中断信号, 实现延时和超时确认。当时钟中断来临时, 系统把正在执行的任务挂起, 保护现场, 进行中断处理, 判断有无任务延时到期, 若有则使该任务进入就绪态, 并把所有进入就绪态的任务的优先级进行比较, 通过任务切换去执行最高优先级的任务。若没有别的任务进入就绪态, 则恢复现场继续执行原
任务。另一种的调度方式是任务级的调度, 是通过发软中断命令或依靠处理器在任务执行中调度。如任务要等待信号量或一个正在执行的任务被悬挂起来时, 就需要在此任务中调度, 找出目前处于就绪态的优先级最高的任务去执行。当没有任何任务进入就绪态时, 就去执行新任务。

2 uC/OS-II的移植
    本文是以三星公司的S3C44B0X 微处理器作为基础, 在S3C44B0X 微处理器上实现移植。S3C44B0X 是ARM CPU 嵌入式控制器总线结构, 特别适用于低成本、低功耗的应用。其CPU 采用ARM公司的ARM7 TDMI RISC 结构。ARM7 TDMI 系统扩充包括thumb 协处理器和32 位乘法器等。
    要实现uC/OS-II的移植, 最关键的就是要修改与处理器类型有关部分的代码, 也就是进行以下几项工作:
(1)修改OS_CPU.H 文件
(2)修改OS_CPU_C.C 文件
(3)修改OS_CPU_A.ASM文件

2.1 OS_CPU.H 文件
    OS_CPU.H 文件包括了用#define 语句定义的、与处理器相关的常数、宏以及类型。
2.1.1 数据类型
定义ARM中的数据类型
#define unsigned char BOOLEAN;
#define unsigned char INT8U; /*8 位无符号整数*/
#define signed char INT8S; /*8 位有符号整数*/
#define unsigned int INT16U; /*16 位无符号整数*/
#define signed int INT16S; /*16 位有符号整数*/
#define unsigned long INT32U; /*32 位无符号整数*/
#define signed long INT32S; /*32 位有符号整数*/
#define float FP32; /* 单精度浮点数*/
#define double FP64; /* 双精度浮点数*/
typedef unsigned int OS_STK; /* 堆栈入口宽度为16 位*/

2.1.2 代码临界区
    RTOS 在进入系统临界区前必须关闭中断, 退出临界区后再开中断。uC/OS-II定义了两个宏来开关中断: OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL( ) 。
为实现开关中断, 宏定义为:
#define OS_ENTER_CRITICAL( ) ARMDisableInt()
/* 关闭中断*/
#define OS_EXIT_CRITICAL( ) ARMEnableInt()
/* 开启中断*/

2.1.3 栈增长方向
    在uC/OS-II中, 用OS_STK_GROWTH 来设置堆栈的增长方向, OS_STK_GROWTH 为0 表示堆栈从低地址向高地址增长;OS_STK_GROWTH 为1 表示堆栈从高地址向低地址增长, 其宏定义为:
#define OS_STK_GROWTH 1;
/* 堆栈从高地址向低地址增长*/
#define OS_STK_GROWTH 0;
/* 堆栈从低地址向高地址增长*/

2.2 OS_CPU_C.C 文件
    在此文件中, 要求我们必须编写10 个简单的C 函数, 唯一必要的函数是OsTaskStkInt()函数。其他9 个函数必须声明, 但可以不包含任何代码。OsTaskStkInt()由任务创建函数OSTaskCreate()或OSTaskCreateEXT()调用, 用来初始化任务的堆栈。
Void OSTaskStkInt (void (*task) (void *pd),void *pdata,void *ptos, INT16U opt)
{unsigned int *stk;
stk=(unsigned int*)ptos; /* 装载堆栈指针*/
*-- stk=(unsigned int) task; /*pc*/
*-- stk=(unsigned int) task; /*lr*/
*-- stk=0; /*r1- r12*/
*-- stk=(unsigned int) pdata; /*r0*/
*-- stk=(SVC32MODE/0x0); /*cpsr IRQ,关闭FIQ*/
*-- stk=(SVC32MODE/0x0); /*spsr IRQ,关闭FIQ*/
return ((void*)stk);}
void OStaskCreateHook ()
void OStaskDelHook ()
void OStaskSwHook ()
void OStaskStatHook ()
void OSTimeTickHook ()
void OStaskIdleHook ()
void OStaskHookBegin ()
void OStaskHookend ()

2.3 OS_CPU_A.ASM文件
    在此文件中需改写4 个简单汇编语言函数: OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()和OSTickISR()。
2.3.1 OSStartHighRdy()函数
    该函数由Osstart()函数调用, 功能是运行优先级最高的就绪任务, 代码为:
LDR r4,addr_OSTCBCur; /* 得到当前任务的TCB 地址*/
LDR r5,addr_OSTCBHighRdy;
/* 得到高优先级任务的TCB 地址*/
LDR r5,[r5]; /* 得到堆栈指针*/
LDR sp,[r5]; /* 切换到新的堆栈*/
STR r5,[r4]; /* 设置新的当前任务的TCB 地址*/
LDMFD sp! , {r4}; /* 从栈顶得到新的声明*/
LDMFD sp! , {r0- r12,lr,pc}; /* 恢复任务环境*/
RETI ; /* 中断返回, 开始新的任务*/

2.3.2 OSCtxSw()函数
    OSCtxSw()函数是一个任务级的任务切换函数。软中断向量指向此函数。在uC/OS-II中, 如果任务调用了某个函数, 而该函数的执行结果可能造成系统任务的重新调度, 则在函数的末尾会调用OSSched(),OSSched()查找当前就绪最高优先级的任务, 如果不是当前任务, 则找该任务的TCB 地址, 并复制到变量OSTcbHigh-Rdy()中, 然后通过宏OS_TASK_SW( ) 执行软中断调用OSCtxSw()进行任务切换。变量OSTCBCur 始终包含指向当前运行任务TCB的指针, 代码如下:
STMFD sp! ,{lr}; /* 保存PC 指针*/
STMFD sp! ,{r0- r12}; /* 保存寄存器文件和RET 地址*/
STMFD sp! ,{r4}; /* 保存当前PSR*/
LDR r4,addr_OSTCBCur; /* 得到当前任务的TCB 地址*/
STR sp,[r5]; /* 保存栈指针在占先任务的TCB 上*/
LDR r6,addr_OSTCBHighRdy;
/* 取得高优先级任务的TCB 地址*/
LDR sp,[r6]; /* 得到新任务的堆栈指针*/
LDMFD sp!,{r4} ; /* 设置当前新任务的TCB 地址*/

2.3.3 OSIntCtxSw()函数
    OSIntCtxSw()函数进行中断级任务切换。中断可能引起任务切换, 在中断服务程序的最后会调用OSIntExit()函数检查任务就绪状态, 如果需要任务切换则调用OSIntCtxSw()函数。其代码如下:
LDMIA sp! ,{a1- v1,lr}
SUBS pc,lr,#4
MOV r12,lr
MRS lr,SPSR
AND lr,lr,#0xFFFFFFE0
MSR CPSR_cxsf,lr

2.3.4 OSTickISR()函数
    OSTickISR()是中断处理函数, 其主要任务是处理时钟中断,调用系统实现的OSTimeTick()函数, 如果有等待时钟信号的高优先级任务, 则需要在中断级别上调度执行。其代码如下:
ORR r0,r0,#0x80; /* 设置中断禁止标志*/
MSR CPSR_cxsf,r0; /* 中断结束*/
LDR r0,=I_ISPC
LDR r1,=BIT_TIMER0
LDREQ pc,=_CON_SW

3 结束语
    嵌入式实时操作系统RTOS 的使用使得应用程序的设计过程大为简化。并且程序的可读性、可靠性、可扩展性有很大的改善。本文从实际出发, 论述了uC/OS-II 操作系统在ARM处理器移植。经过移植后的操作系统经过测试, 运行稳定, 并达到了实时系统的要求。


分享到:
来顶一下
返回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
栏目导航->单片机学习
  • 电子应用基础
  • 电源技术
  • 无线传输技术
  • 信号处理
  • PCB设计
  • EDA技术
  • 单片机学习
  • 电子工具设备
  • 技术文章
  • 精彩拆解欣赏
  • 推荐资讯
    使用普通运放的仪表放大器
    使用普通运放的仪表放
    3V与5V混合系统中逻辑器接口问题
    3V与5V混合系统中逻辑
    数字PID控制及其改进算法的应用
    数字PID控制及其改进
    恶劣环境下的高性价比AD信号处理数据采集系统
    恶劣环境下的高性价比
    栏目更新
    栏目热门