要保证ucos II移植到微处理器后能正确运行;处理器需具备如下特性:
1) 处理器的c编译器支持可重入函数
可重入的代码指的是一段代码(如一个函数)可以被多个任务同时调用,而不必担心会破坏数据。也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。下面的两个例子可以比较可重入型函数和非可重入型函数:
程序1:可重入型函数
- void swap(int *x, int *y)
- {
- int temp;
- temp=*x;
- *x=*y;
- *y=temp;
- }
程序2:非可重入型函数
- void swap(int *x, int *y)
- {
- int temp;
- temp=*x;
- *x=*y;
- *y=temp;
- }
程序1 中使用的是局部变量temp 作为变量。通常的C 编译器,把局部变量分配在栈中。
所以,多次调用同一个函数,可以保证每次的temp 互不受影响。而程序2 中temp 定义的是全局变量,多次调用函数的时候,必然受到影响。代码的可重入性是保证完成多任务的基础,除了在C 程序中使用局部变量以外,还需要C 编译器的支持。笔者使用的是ARM SDT 以及ADS 的集成开发环境,均可以生成可重入的代码。
2)在程序中可以打开和关闭中断
在ucos II中,可以通过OS_ENTER_CRITICAL()或者OS_EXIT_CRITICAL()宏来控制
系统关闭或者打开中断。这需要处理器的支持,在ARM7TDMI 的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。
3)处理器支持中断,并且能产生定时器中断(ucos Ⅱ是通过定时器中断来实现多任务的调度,即时间片的产生 )ucos II 是通过处理器产生的定时器的中断来实现多任务之间的调度的。在ARM7TDMI 的处理器上可以产生定时器中断。
4)处理器要具有一定的硬件堆栈数量
5)处理器要有将堆栈指针和其他cpu寄存器存储和读出堆栈(或者内存)的指令(如51的pop,push指令)。
ucos Ⅱ进行任务调度的时候,会把当前任务的CPU 寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是ucos II多任务调度的基础。
ARM7TDMI 处理器完全满足上述要求。
接下来将介绍如何把ucos Ⅱ移植到Samsung公司的一款ARM7TDMI 的嵌入式处理器——S3C44B0X 上。
ucos II中与处理器有关的代码:os_cpu.h os_cpu_a.asm os_cpu_c.c
ucos II的设置 : os_cfg.h inludes.h
ucos II在S3C44b0上的移植
1)设置inludes.h中与处理器及编译器有关的代码
FOR ADS
- /**********************************************************************************************************
- * uC/OS-II
- * The Real-Time Kernel
- *
- * (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
- * All Rights Reserved
- *
- * MASTER INCLUDE FILE
- *********************************************************************************************************
- */
- #include "os_cpu.h"
- #include "os_cfg.h"
- #include "ucos_ii.h"
这里未做处理 取默认的数据类型。
FOR SDT
- /*
- *********************************************************************************************************
- * uC/OS-II
- * The Real-Time Kernel
- *
- * (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
- * All Rights Reserved
- *
- * MASTER INCLUDE FILE
- **********************************************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "os_cpu.h"
- #include "os_cfg.h"
- #include "ucos_ii.h"
- #ifdef EX3_GLOBALS
- #define EX3_EXT
- #else
- #define EX3_EXT extern
- #endif
- /*
- *********************************************************************************************************
- * DATA TYPES
- *********************************************************************************************************
- */
- typedef struct {
- char TaskName[30];
- INT16U TaskCtr;
- INT16U TaskExecTime;
- INT32U TaskTotExecTime;
- } TASK_USER_DATA;
- /*
- *********************************************************************************************************
- * VARIABLES
- *********************************************************************************************************
- */
- EX3_EXT TASK_USER_DATA TaskUserData[10];
- /*
- *********************************************************************************************************
- * FUNCTION PROTOTYPES
- *********************************************************************************************************
- */
- void DispTaskStat(INT8U id);
********************************************************************************
其他人的应用修改事例:
- #define INT8U unsigned char
- #define INT16U unsigned short
- #define INT32U unsigned long
- #define OS_STK unsigned long
- #define BOOLEAN int
- #define OS_CPU_SR unsigned long
- #define INT8S char
- extern int INTS_OFF(void);
- extern void INTS_ON(void);
- #define OS_ENTER_CRITICAL() { cpu_sr = INTS_OFF(); }
- #define OS_EXIT_CRITICAL() { if(cpu_sr == 0) INTS_ON(); }
- #define OS_STK_GROWTH 1
- #define STACKSIZE 256
因为不同的微处理器有不同的字长,所以ucos Ⅱ的移植包括了一系列的类型定义以确
保其可移植性。尤其是ucos Ⅱ代码从不使用C 的short,int 和long 等数据类型,因为它们是与编译器相关的,不可移植。相反的,我们定义的整形数据结构既是可移植的又是直观的。为了方便,虽然ucos Ⅱ不是用浮点数据,但我们还是定义了浮点数据类型。
例如,INT16U 数据类型总是代表16 位的无符号整数。现在,ucos Ⅱ和用户的应用程序就可以估计出声明为该数据类型的变量的取值范围是0~65535。将ucos Ⅱ移植到32 位的处理器上也就意味着INT16U 实际被声明为无符号短整形数据结构而不是无符号整数数据结构。但是,μC/OS-Ⅱ所处理的仍然是INT16U。用户必须将任务堆栈的数据类型告诉给μC/OS-Ⅱ。这个过程是通过为OS_STK 声明正确的C 数据类型来完成的。我们的处理器上的堆栈成员是16 位的,所以将OS_TSK 声明为无符号整形数据类型。所有的任务堆栈都必须用OS_TSK 声明数据类型。
2)OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()
与所有的实时内核一样,μC/OS-Ⅱ需要先禁止中断再访问代码的临界区,并且在访问完
毕后重新允许中断。这就使得μC/OS-Ⅱ能够保护临界区代码免受多任务或中断服务例程
(ISR)的破坏。在S3C44B0X 上是通过两个函数(OS_CPU_A.S)实现开关中断的。
- INTS_OFF
- mrs r0, cpsr ; 当前CSR
- mov r1, r0 ; 复制屏蔽
- orr r1, r1, #0xC0 ; 屏蔽中断位
- msr CPSR, r1 ; 关中断(IRQ and FIQ)
- and r0, r0, #0x80 ; 从初始CSR 返回FIQ 位
- mov pc,lr ; 返回
- INTS_ON
- mrs r0, cpsr ; 当前CSR
- bic r0, r0, #0xC0 ; 屏蔽中断
- msr CPSR, r0 ; 开中断(IRQ and FIQ)
- mov pc,lr ; 返回