μC/OS-II在S3C44BOX处理器上的移植
摘要:介绍实时操作系统μC/OS-II的特点和内核结构,给出μC/OS-II在Samsung嵌入式S3C44BOX ARM7微处理器上的移植的步骤及详细相关代码,同时阐述μC/OS-II在应用中应注意的问题。
关键词:μC/OS-II S3C44BOX 移植 实时操作系统
μC/OS-II功能强大,支持56个用户任务,其内核为占先式,支持信号量、邮箱、消息队列等多种常用的进程间通信机制,现已成功应用到众多商业嵌入式系统中,是一个成熟稳定的实时内核。与大多商用RTOS不同的是,μC/OS-II公开所有的源代码,90%的代码使用标准的ANSI C语言书写,程序可读性强、移植性好;同时它可免费获得,即使商业应用也只收取少量的许可费用。因此,对μC/OS-II实时操作系统的学习研究、开发、应用具有重要意义。
Samsung S3C44B0X微处理器是三星公司专为手持设备和其它嵌入式应用提供的高性价比的微控制器解决方案。它使用ARM公司的16位/32位RISC结构,内核是ARM7TDMI,工作在66MHz,片上集成了以下部件:8K Cache、外部存储器控制器、LCD控制器、4个DMA通道、2个UART、1个多主I2C总线控制器、1个I2C总线控制器,以及5通道PWM定时器和1个内部定时器、8通道12位ADC等,能够与常用的外围设备实现无缝连接,功能强大。目前,国内应用较为广泛。
javascript:window.open(this.src);" style="cursor:pointer;"/>
1 μC/OS-II实时操作系统结构
图1说明了μC/OS-II的软硬件体系结构。应用程序处于整个系统的顶层,每个任务都可以认为自已独占了CPU,因而可以设计成为一个无限循环。μC/OS-II处理器无关的代码提供了μC/OS-II的系统服务,应用程序可以使用这些API函数进行内存管理、任务间通信及创建、删除任务等。
大部分的μC/OS-II代码是使用ANSI C语言书写的,因此μC/OS-II的可移植性好,然而仍需要使用C和汇编语言写一些处理器相关代码。μC/OS-II的移植需要满足以下要求:
①处理器的C编译器可以产生可重入代码;
②可以使用C调用进入和退出临界区代码;
③处理器必须支持硬件中断,并且需要一个定时中断源;
④ 处理器需要能够容纳一定数据的硬件堆栈;
⑤处理器需要有能够在CPU寄存器与内核和堆栈交换数据的指令。
S3C44B0X处理器完全满足上述要求。
2 实时内核μC/OS-II在S3C44B0X上的移植
我们使用ARM SDT编译器,移植μC/OS-II主要包括以下几个步骤。
(1)设置OS_CPU.H中与处理器和编译器相关的代码
*************************************************
与编译器相关的数据类型
*************************************************
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 long INT32U; /*32位无符号整数*/
typedef signed long INT32S; /*32位有符号整数*/
typedef float FP32; /*单精度浮点数*/
typedef double FP64; /*双精度浮点数*/
typedef unsigned int OS_STK;/*堆栈入口宽度为16位*/与ARM处理器相关的代码:
#define OS_ENTER_CRITICAL () ARMEnableInt() /*开启中断*/
#define OS_STK_GROWTH 1 /*堆栈由高地址向低地址增长*/
(2)用C语言编写6个操作系统相关的函数(OS_CPU_C.C)
void OSTaskStkInit(void(task)(void *pd),void *pdata,void *ptos,INT16U opt)
{ unsigned int *stk;
opt =opt; /*因“opt”变量没有用到,防止编译器产生警告*/
stk =(unsigned int *)ptos; /*装载堆栈指针*/
/*为新任务创建上下文*/
*--stk=(unsigned int)task; /*lr*/
*--stk=(unsigned int)task /*pc*/
*--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*/
*--stk=0; /*r2*/
*--stk=0; /*r1*/
*--stk=(unsigned int)pdata; /*r0*/
*--stk=(SVC32MODE0x0); /*cpsr IRQ,
*--stk=(SVC32MODE0x0); /*spsr IRQ,关闭FIQ*/
return((void*)stk);
}
后5个函数是钩子函数,可以不加代码:
void OSTaskCreateHook(OS_TCB *ptcb)
void OSTaksDelHool (OS_TCB *ptcb)
void OSTaskSwHook(void)
void OSTaskStatHook(void)
(3)用汇编语言编写4个与处理器相关的函数(OS_CPU.ASM)
OSStartHighRdy() ;运行优先级最高的就绪任务
LDR r4,addr_OSTCBCur ;得到当前任务的TCB地址
LDR r5,addr_OSTCBHighRdy ;得到高优先级任务的TCB地址
LDR r5,addr_OSTCBHighRdy ;得到高优先级任务的TCB地址
LDR r5,[r5] ;得到堆栈指针
LDR sp,[r5] ;切换到新的堆栈
STR r5,[r4] ;设置新的当前任务的TCB地址
LDMFD sp!,{r4}
MSR CPSR_cxsf,r4
LDMFD sp!,{r0-r12,lr,pc} ;开始新的任务
END
OSCtxsw() 任务级的任务切换函数
STMFD sp!,{lr} ;保存PC指针
STMFD sp!,{lr} ;保存lr指针
STMFD sp!,{r0-r12} ;保存寄存器文件和返回地址
MRS r4,CPSR
STMFD sp!,{r4} ;保存当前PSR
MRS r4,SPSR
STMFD sp!,{r4}
;OSPrioCur=OSPrioHighRdy
LDR r4,addr_OSPrioCur
LDR r5,addr_OS