摘要:本文简介了一种实时多任务内核μC/OS-Ⅱ。并根据S3C44B0X芯片的硬件特性,给出了一种把μC/OS-Ⅱ移植到S3C44B0X上的方案。 关键词:实时多任务内核;μC/OS-Ⅱ;S3C44B0X;移植
嵌入式实时多任务内核又叫做实时操作系统RTOS(Real-Time Operating System)。与通用操作系统相比较,它具有可裁减、低资源占用、低功耗等特点。而与传统的嵌入式设计方法相比,实时多任务内核的运用允许程序员将具体的应用程序模块化,更易于项目的开发。 目前约有上百家RTOS生产商,提供面向8位、16位、32位以及64位微处理器的RTOS产品。本文介绍一种免费的实时内核μC/OS-Ⅱ,并给出一种将其植入S3C44B0X的方案。
1. μC/OS-Ⅱ简介
嵌入式实时操作系统μC/OS-Ⅱ是基于优先级的抢占式实时多任务操作系统。它包含实时内核、任务管理、时间管理、任务间通信同步(信号量,邮箱,消息队列)和内存管理等功能。绝大部分代码用C语言写成,与硬件相关部分用汇编语言编写,而且它的源代码是公开免费的。 μC/OS-Ⅱ是面向中小型嵌入式系统的。包含全部功能模块的内核大约为10KB,如果经过裁减只保留核心代码,则可压缩到3KB左右。RAM的应用量与系统中的任务数有关,任务的堆栈要占用大量的RAM空间,堆栈的大小取决于任务的局部变量、缓冲区大小及可能的中断嵌套层数。应用程序的精度由系统的时钟节拍决定,μC/OS-Ⅱ要用户提供周期性的时钟信号源,用于实现时间延时和确认超时。 μC/OS-Ⅱ内核的工作原理如下:首先把CPU初始化,再进行操作系统初始化。主要完成任务控制块(TCB)初始化、TCB优先级表初始化、TCB链表初始化、事件控制块ECB链表初始化和空任务的创建等;然后开始创建新任务,并可在新创建的任务中再创建其它的新任务;最后调用OSSTART()函数启动多任务调度。在多任务调度开始后,启动时钟节拍源开始计时,此节拍源给系统提供周期性的时钟中断信号,实现延时和超时确认。当时钟中断来临时,系统把正在执行的任务挂起,保护现场,进行中断处理,判断有无任务延时到期,若有则使该任务进入就绪态,并把所有进入就绪态的任务的优先级进行比较,通过任务切换去执行最高优先级的任务。若没有别的任务进入就绪态,则恢复现场继续执行原任务。另一种的调度方式是任务级的调度,是通过发软中断命令或依靠处理器在任务执行中调度。如任务要等待信号量或一个正在执行的任务被悬挂起来时,就需要在此任务中调度,找出目前处于就绪态的优先级最高的任务去执行。当没有任何任务进入就绪态时,就去执行新任务。
2. S3C44B0X介绍
SAMSUNG(三星)S3C44B0X 微处理器采用0.25μm CMOS工艺和SAMBA11总线结构(SAMSUNG ARM CPU嵌入式控制器总线结构),特别适用于低成本、低功耗的应用。其CPU采用ARM公司的ARM7TDMI RISC结构。ARM7TDMI系统扩充包括thumb协处理器、片上ICE中断调试支持和32位乘法器。S3C44B0X通过在ARM7TDMI内容基础上扩展一系列完整的通用外围器件。其特点如下:
- 采用ARM7TDMI内核,I/O电压3.3V,内核电压2.5V;
- 内置锁相环(PLL),系统工作主频66MHZ;
- 4种工作模式(正常、慢速、闲置和停止),可以实现电源管理以降低系统功耗;
- 8KB的系统高速缓存(CACHE),极大地提高了系统的运行速度;
- 支持8个MEMORY BANK,最大外部存储空间达256MB,并支持SDRAM;
- 内置彩色LCD控制器;
- 2路异步串口(UART);
- 71个通用I/O口,包括8个外部中断源;
- 8路10位A/D转换器;
- 实时时钟(RTC)和看门狗电路(WATCHDOG);
3. μC/OS-Ⅱ的移植
要实现μC/OS-Ⅱ的移植,需要进行以下几项工作: (1) 在OS_CPU.H中设置一个常量值; (2) 在OS_CPU.H中声明10个数据类型; (3) 在OS_CPU.H中声明3个宏定义; (4) 在OS_CPU_C.C中编写6个简单函数; (5) 在OS_CPU_A.ASM中改写4个汇编语言函数; 3.1 OS_CPU.H文件 3.1.1 数据类型 定义S3C44B0X中的数据类型 #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; /*双精度浮点数*/ S3C44B0X中的堆栈数据类型为16位,定义为: typedef unsigned int OS_STK; 在S3C44B0X中所有堆栈必需用OS_STK声明; 3.1.2 代码临界区 RTOS在进入系统临界区前必须关闭中断,退出临界区后再开中断。μC/OS-Ⅱ定义了两个宏来开关中断:OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL()。 为实现开关中断,宏定义为: #define OS_ENTER_CRITICAL() ARMDisableInt() /*关闭中断*/ #define OS_EXIT_CRITICAL() ARMEnableInt() /*开启中断*/ 3.1.3 堆栈增长方向 在μC/OS-Ⅱ中,用OS_STK_GROWTH来设置堆栈的增长方向,OS_STK_GROWTH为0表示堆栈从低地址向高地址增长;OS_STK_GROWTH为1表示堆栈从高地址向低地址增长;S3C44B0X中,堆栈是由高向低递减的,因此定义宏: #define OS_STK_GROWTH 1; 3.2 OS_CPU_C.C 在此文件中,实际只需修改OsTaskStkInt()函数。OsTaskStkInt()由任务创建函数OSTaskCreate()或OSTaskCreateEXT()调用,用来初始化任务的堆栈。OsTaskStkInt()与调用它的函数由3个参数进行传递:任务代码起始地址(task),参数指针(pdata),任务堆栈顶地址(ptos)。 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 (OS_TCB *ptcb) void OStaskDelHook (OS_TCB *ptcb) void OStaskSwHook (void) void OStaskStatHook (void) void OSTimeTickHook (void) 后5个函数为钩子函数,可以不加代码。 3.3 OS_CPU_A.ASM文件 在此文件中需改写4个函数:OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()和OSTickISR()。由于篇幅所限,避免流水线冲突的空指令已省略。 3.3.1 OSStartHighRdy()函数 该函数由Osstart()函数调用,功能是运行优先级最高的就绪任务。其过程为:获得优先级最高任务的TCB地址-设置堆栈指针-恢复任务环境-中断返回-运行新任务。 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 ; /*中断返回,开始新的任务*/ 3.3.2 OSCtxSw()函数 OSCtxSw()函数是一个任务级的任务切换函数。软中断向量指向此函数。在μC/OS-Ⅱ中,如果任务调用了某个函数,而该函数的执行结果可能造成系统任务的重新调度,则在函数的末尾会调用OSSched(),OSSched()查找当前就绪最高优先级的任务,如果不是当前任务,则找该任务的TCB地址,并复制到变量OSTcbHighRdy()中,然后通过宏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地址*/ 3.3.3 OSIntCtxSw()函数 OSIntCtxSw()函数进行中断级任务切换。中断可能引起任务切换,在中断服务程序的最后会调用OSIntExit()函数检查任务就绪状态,如果需要任务切换则调用OSIntCtxSw()函数。值得注意的是,产生中断后,CPU寄存器会被自动保存,所以,在此函数中不再进行环境保存。 LDMIA sp!,{a1-v1,lr} SUBS pc,lr,#4 MOV r12,lr MRS lr,SPSR AND lr,lr,#0xFFFFFFE0 MSR CPSR_cxsf,lr 3.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
4. 结束语
RTOS的使用使得应用程序的设计过程大为简化。并且程序的可读性、可靠性、可扩展性有很大的改善。本文从实际出发,给出一种免费RTOS内核μC/OS-Ⅱ在ARM单片机S3C44B0X上的移植方案,并在实际应用中实现。
参考文献:
[1] S3C44B0X MICROPROCESSOR Datasheet. Samsung Electronics Aug 2001. [2] JEAN J.LABROSSE著,邵贝贝译.μC/OS-Ⅱ源码公开的实时嵌入式操作系统.中国电力出版社,2001.
|