1 RTEMS体系结构
RTEMS采用微内核基础上的层次化结构,如图l所示。这种结构只把那些绝对必需的系统功能置于内核之中(如中断管理、上下文切换、内存访问管理、时间管理、线程及线程间的通信与同步管理等),而把那些并非必需的系统功能(如文件系统、网络、远程过程调用等)置于微内核之上在用户模式下运行。
RTEMS的板级支持包是启动代码、连接器脚本和编译规范文件(specs)和设备驱动程序的集合[2],它们针对不同目标机的硬件环境剪裁RTEMS。
2 RTEMS启动过程
处理器加电或复位时,基于RTEMS的应用程序初始化或者重新初始化[3]。BSP中的启动代码负责为RTEMS应用程序建立运行环境。
RTEMS启动过程的顺序如下:
① 执行BSP中的启动代码;
② 调用rtems_initialize_executive;
③ 局部和全局应用程序的初始化。
处理器复位时,首先执行BSP的启动代码。BSP必须将所有的硬件初始化为一个静止状态,然后操作系统才能初始化。rtems_initialize_executive指令不返回启动代码,它将导致最高优先级的初始化任务开始执行。初始化任务用于完成局部或全局依赖于RTEMS的应用程序初始化。
3 BSP开发过程
下面以SPARC微处理器ERC32为例,说明RTEMSBSP的开发步骤:
①建立开发环境。开发模式采用宿主机/目标机模式。宿主机运行环境采用Linux系统,目标机为ERC32。宿主机和目标机通过串口连接。交叉开发工具采用添加了RTEMS补丁的GNU工具链(GCC,GDB,Newlib,binary utilities)。
② 选择BSP模板。通常是根据操作系统提供的BSP模板,选择与应用硬件环境最为相似的参考设计,针对具体的目标机对参考BSP进行必要的修改和增删,以形成自己的BSP。选择一个适当的BSP模板可以达到事半功倍的效果。
③建立新bsp目录。将模板BSP整个目录拷贝到适当的目录下(如libbsp/),重命名为mybsp。
④ 建立bsp配置文件。拷贝任意一个BSP.cfg,重命名为mybsp.cfg,修改相关的体系结构定义,如:RTEMS_CPU_MODEL,RTEMS_BSP,CPU_CFLAGS和制定make_exe规则。
⑤修改makefile文件。对mybsp-bsp中每一个Makefile.in文件,运行acpolish,并检查运行的结果,例如:
cd /mybsp - bsp/some_subdir
/path_to_SACOS/t00ls/update/acpolish<Makefile.old>Makefile.new
再次运行acpolish:
/path_to_SACOS/tools/update/acpolish<Makefile.new>Makefile.in
将Makefile.new和Makefile.in进行比较。如果不相同,则重新编辑Makefile.new,多次运行acpolish,直到连续两次产生的Makefile.in相同。
⑥ 修改启动代码。建立自陷表、基本的CPU初始化、设置中断堆栈等。
⑦ 配置RTEMS。设置RTEMS相关全局变量和常量、RTEMS配置表、CPU依赖信息表、系统初始化任务表,以及用户初始化任务表等,除完成相关的系统功能之外,提供板上外设的设备驱动程序。
⑧调试和测试。建立RTEMS执行映像,利用串口下载可执行映像到目标机,测试BSP的正确性。
3.1 启动代码实现
BSP的启动代码主要包含在五个文件中。它们是Start.s、boardinit.S、bootcard.c、bspstart.C和main.C。
Start.s包含了用于硬件初始化的汇编语言代码,它是RTEMS的引导ROM入口。入口点SYM(start)是目标机上电后执行的第一段程序。SYM(start)的工作是完成将控制转移到C程序boot_card()所需要的最少的设置,如初始化堆栈和禁止外部中断等。它的具体操作包括:
①定义自陷表。这个自陷表是SPARC V7体系共有的,可从参考BSP中复制。
②初始化处理器。
a)初始化自陷基地址寄存器TBR,即将自陷表地址写入TBR;
b)初始化处理器状态寄存器PSR,设置系统为最高优先级运行模式,禁止所有可屏蔽中断;
c)设置窗口无效寄存器WIM;
d)初始化堆栈,设置堆栈指针。
③调用SYM(_bsp_board_init)(在boardinit.S中定义,这些代码是目标板专用的),初始化MEC系统寄存器,初始化定时器。
④将已初始化数据从ROM拷贝到RAM,未初始化内存清零。
⑤初始化环境变量和参数,调用C程序boot_card()。
boot_card()完成RTEMS的基本配置,如设置RTEMS配置表、CPU依赖信息表的相关入口等。它调用bsp_start()完成目标板特定的系统配置,调用内核初始化函数完成RTEMS系统的初始化。boot_card()的具体操作包括:
①定义和声明RTEMS全局变量。
extern rtems_configuration_table Configuration;
extern rtems_.configuration_.table BSP_Configuration;
extern rtems_cpu_table Cpu_table;
rtems_api_configuration_table BSP_RTEMS_Configura-tion;
rtems_interrupt_level bsp_isr_level;
②初始化CPU依赖信息表的所有人口为缺省值,除了下列两项,其余都为NULL。
Cpu_table.do_zero_of_workspace =TRUE;
Cpu_table.interrupt_stack_size =RTEMS_MINIMUM_STACK_SIZE;
③ 调用bsp_start(),根据目标机环境重新配置RTEMS,为系统初始化任务建立标准C支持环境。
④ 调用内核初始化函数rtems_initialize_executive_ early(),初始化RTEMS和设备驱动程序。
⑤调用c_rtems_main(),创建并启动多任务,运行用户应用程序,直到调用rtems_shutdown_executive()退出RTEMS,才将控制返回BSP。
bsp_start()根据目标机环境重新配置RTEMS,为调用操作系统初始化函数准备一个合适的软硬件环境。它的具体操作是:
①定义RTEMS全局变量。
unsigned char*work_space_start;
rtems_configuration_table BSP_Configuration;
rtems_cpu_table Cpu_table;
②修改CPU依赖信息表,为RTEMS系统初始化任务建立支持环境。
/*在执行系统初始化任务之前,设置存堆的开始地址和大小,建立C支持库*/
Cpu_table.pretasking_hook=bsp_pretasking_hook;
/*在驱动程序初始化之后注册设备名,打开标准输人、标准输出和标准错误文件*/
Cpu_table.postdriver_hook=bsp_postdriver_hook;
Cpu_table.do_zero_of_workspace=TRUE;
/*设置中断堆栈的大小(16*1024)*/
Cpu_table.interrupt_stack_size=ONFIGURE_INTER-RUPT_STACK_MEMORY;
③检查并设置工作区起始地址。
BSP_Configuration.work_space_start=work_space_start;
④设置时钟嘀嗒频率。
CPU_SPARC_CLICKS_PER_TICK=BSP_Configuration.microseconds_per_tick;
⑤结束返回boot_card()。
图2描述了RTEMS系统初始化函数之间的调用关系。
3.2设备驱动程序实现
设备驱动程序的工作方式有轮询和中断两种。无论采用哪一种方式,设备驱动程序的基本流程都是相同的。下面以时钟设备驱动程序为例,简单说明编写RTEMS设备驱动程序的基本框架。
本文关键字:开发 嵌入式系统-技术,单片机-工控设备 - 嵌入式系统-技术