导航: 老古网老古论坛XMOS公共讨论区XMOS开源项目区单片机程序设计嵌入式系统广告区域
→发表看法:[xyg2003]19bytes!玩转嵌入式rtos―r&



No.68425
作者:xyg2003
邮件:xyg345@163.net
ID:27898
登陆:7次
文章数:2篇
最后登陆IP:218.13.198.2
最后登陆:2005/12/1 19:31:32
注册:2004/11/19 20:42:52
财富:141
发帖时间:2004/12/8 20:24:17
发贴者IP:220.194.195.129
标题:xyg2003:19bytes!玩转嵌入式rtos―r&s在mcs51上的移植
摘要:No.6842519bytes!玩转嵌入式rtos―r&s在mcs51上的移植 19bytes!玩转嵌入式rtos―r&s在mcs51上的移植
阮海深 2004-12-8 修订

r&s是一款层次清晰的嵌入式内核,努力追求稳定与快速;r&s主体部分是严格按照ansi c标准语法构建的,幸运的是,当前流行的处理器都有支持的标准c编译环境,只需改动少量与处理器相关代码,即可很容易将r&s移植到具体的处理器上;本文通过在mcs51的移植实例,探讨r&s的一般移植思路。

一 r&s的文件结构
1 \arch,依赖于具体体系结构部分,包括中断、时钟服务、处理器栈指针切换,是移植的重点;
2 \example,演示例子;
3 \inc,内核头文件,包括默认的配置文件config.h;
4 \kernel,基本内核模块,不依赖具体处理器部分代码;
5 \ipc,任务间通讯支持,包括二值信号量、信号量、互斥锁、邮箱、消息队列;
6 \lib,用户支持库,基本IO,文件系统,网络支持…(待完善);

二 移植
r&s的移植过程是非常简单的,实际上只需重新实现5个函数和几个常数宏定义,移植涉及到文件均在目录\arch下:
¨ basetype.h
¨ intr.h
¨ trace.h
¨ misc.c
¨ context.asm
¨ trace.c
共3个头文件与3个源文件,其中1个asm文件。
basetype.h包含了关于cpu位宽、栈的增长方向、存储字节序以及基本数据类型描述。
intr.h、misc.c、context.asm定义了临界段相关的宏、任务上下文切换、以及系统时钟中断服务,涉及到以下项修改:
¨ 临界段控制宏CRITICAL_ENTER、CRITICAL_EXIT与中断控制宏DISABLE_IRQ、ENABLE_IRQ定义
¨ 任务栈初始化 __stack_init、__entry_init
¨ 任务栈指针切换 __switch_start、__switch_to
¨ 系统时钟服务 __timer_irs
trace.h、trace.c是用户接口输出支持,包括对__ASSERT的实现。提供对r&s的DEBUG版本、字符输出lib/pintk等相关的支持。对于没有用户接口硬件支持的系统,可以省略这两个文件。

1 修改basetype.h相关内容

#define ARCH_CPU_BITS       8  //cpu位宽
#define ARCH_STACK_GROW   UPWARDS  //栈增长方向
#define ARCH_MM_BYTEORDER  BIG_ENDIAN  //字节序模式:大头模式,即低地址高字节

//以下是基本数据类型
#define __arch_u8       char
#define __arch_u16      short
#define __arch_u32      long
#define __arch_u64      long long

//重定义SP指针和基本类型修饰(可选内容)
#define __sp            char idata *
#define __const_        code
#define __p_            data

2 移植intr.h、misc.c、context.asm

1) 临界段宏CRITICAL_ENTER,CRITICAL_EXIT定义

DISABLE_IRQ、ENABLE_IRQ分别定义中断开关控制。
宏CRITICAL_ENTER,CRITICAL_EXIT定义了系统临界段代码保护,一般是通过开、关中断实现。在提供内嵌汇编语句的编译器中,可以很方便定义插入汇编指令来开、关中断;在c51中,可以直接使用c语法来操作51的特殊寄存器,非常方便。
这里我们通过简单的进入临界段CRITICAL_ENTER,关闭中断EA=0,退出临界段CRITICAL_EXIT打开中断EA=1实现。注意,这种模式要避免临界段的嵌套。在稍微复杂的应用,进入临界段要先将中断状态保存到堆栈中,然后关闭中断,退出临界段时,从堆栈中恢复中断状态。
#define DISABLE_IRQ       EA = 0
#define ENABLE_IRQ        EA = 1
#define CRITICAL_ENTER   EA=0
#define CRITICAL_EXIT     EA=1

2) 任务栈初始化 __stack_init、__entry_init 

初始化任务栈,实际上是模拟函数调用过程,给任务以假象--哦,我是从这个地方中断的,现在我应该回到那继续!我们利用任务的入口地址entry初始化一个假想栈,这样任务就可以从返回到入口开始工作。
实际上,r&s没有让任务马上进入任务入口函数entry运行,在任务开始前,总该做点什么,这个工作交给了__entry_init,很多时候,只需在__entry_init为每个任务简单的打开中断。
static void __entry_init(void)
{
    ENABLE_IRQ;  //在任务开始前,我们首先打开中断
} //返回entry
现在利用__stack_init构造一个初始化任务栈,使得任务能够最终返回到入口entry开始。
struct reg_context  //构造一个初始化任务栈
{
u8 entry_l;
u8 entry_h;
u8 eninit_l;
u8 eninit_h;
u8 arg;
};
typedef struct regs_context regs_t;

u8* __stack_init(entry_t entry, arg_t arg, sp_t stack_base)
{
regs_t* regs;
regs = (regs_t*) stack_base;  //regs指向任务栈基地址

regs->  entry_l = (u8)entry;        //任务入口地址低位
regs->  entry_h = (u16)entry >  >   8;  //任务入口地址高位
regs->  eninit_l = (u8)__entry_init;       //任务初始化地址(低位)
regs->  eninit_h = (u16)__entry_init >  >   8;  //任务初始化地址(高位)
regs->  arg     = (u8)arg; //任务入口参数

return  (u8*)regs + 3;           //返回指向任务初始化函数的栈
}
这里有个问题,标准的c编译器都是支持栈传递函数参数的,但在c51中,函数调用默认是寄存器传递。所以,任务入口参数arg并没有真正传入到任务中,解决这个问题并不难,你得查看编译器手册,知道参数是通过那个寄存器传送的,然后在__entry_init中提取arg内容复制到参数寄存器就可以了。

3) 栈切换实现__switch_start、__switch_to

任务栈指针切换实现__switch_start、__switch_to也非常简单;任务栈初始化的构造和任务栈指针切换一定要严格对应一致的。
__switch_start功能是在r&s启动多任务时候,将处理器栈指针SP指向第一个任务栈过程。
void __switch_start(sp_t next_sp)
{
SP = next_sp;  //将SP指向第一个任务栈地址
}   //这里隐含了一条return语句,将返回到第一个用户任务
__switch_to工作是在r&s进行任务切换时,保存SP到当前任务栈,然后把栈指针SP指向新的任务栈。实现如下:
void __switch_to(sp_t* pcurrent_sp, sp_t next_sp)
{
*pcurrent_sp = (sp_t)SP;  //保存当前任务栈地址
SP = next_sp;  //SP指向新的任务栈
}   //这里隐含了一条return语句,将返回到新的用户任务

4) 系统时钟服务void __timer_irs (void)

系统时钟服务为r&s提供一个周期的时钟节拍,实现延时和超时控制等操作,时钟节拍一般取10~100Hz。r&s的延时精度取决于时钟节拍的精度,可以利用处理器内含定时器或外置专门的定时芯片实现系统节拍,在对定时要求精度很高的场合,可使用自循环的硬件定时器获得,典型的r&s中断处理流程如下:
关中断;(可选)
任务调度锁定_sched_lock++(可选)
保存现场;
模拟一次中断
开中断;(可选)
任务调度解锁_sched_lock--(可选)
切换任务
恢复现场;
返回
_sched_lock是一字节的无符号整数,只有当_sched_lock值为0时,才允许r&s调度器进行任务切换;如果允许中断嵌套,你需要在中断中锁住r&s调度器,避免在中断嵌套中发生任务调度;如果不允许中断嵌套,那么_sched_lock是不必的。根据_sched_lock可以算出r&s允许达255层深的中断嵌套。
 
CSEG    AT     000BH
        INC     #_sched_lock
        LJMP    IT0_IRS

CSEG    AT     0100H
;*==============================================*/
IT0_IRS:   ;中断入口
        PUSH    ACC   ;保存现场 
        PUSH    B
        PUSH    PSW
        PUSH    DPH
        PUSH    DPL
        PUSH    00H
        PUSH    01H
        PUSH    02H
        PUSH    03H
        PUSH    04H
        PUSH    05H
        PUSH    06H
        PUSH    07H
;------------------------------------------------------- ;模拟中断
        MOV     A, #LOW  IT0_OUT
        PUSH    ACC
        MOV     A, #HIGH IT0_OUT
        PUSH    ACC
        LCALL   __do_tick               ;中断处理
        MOV     TH0,#T0H_COUNTER   ;刷新定时器 
        MOV     TL0,#T0L_COUNTER    ;
        RETI       ;中断返回
;-------------------------------------------------------
IT0_OUT:
        DEC     #_sched_lock
        LCALL   __schedule     ;任务切换
        ......

>>返回讨论的主题



  发表回复
用户名   *您没有注册?
密码   *
验证码   * .
标题   *
心情
随便说说    我回答你    最新发现    得意的笑   
气死我了    真是没劲    坚决同意    表示反对   
大家过来    好奇怪哟    懒得理它    大家小心   
文件上传
内容


字体:      字体大小:    颜色:
粗体 斜体 下划线 居中 超级连接 Email连接 图片 Flash图片 Shockwave文件 realplay视频文件 Media Player视频文件 QuickTime视频文件 引用 飞行字 移动字 发光字 阴影字 查看更多的心情图标 背景音乐
点击加入表情
                         
选项
有回复时用短消息通知您?

   




老古网执行:31毫秒 最大:136338毫秒 查询6次