原文地址:http://blog.sina.com.cn/s/blog_54f82cc201012jvi.html
[Linux BSP]嵌入式Linux BSP的设计与实现
(2012-08-29 14:04:52)转载▼
1. 引言
嵌入式系统由硬件环境、嵌入式操作系统和应用程序组成,硬件环境是操作系统和应用程序运行的硬件平台,它随应用的不同而有不同的要求。硬件平台的多样性是嵌入式系统的主要特点,如何使嵌入式操作系统在不同的硬件平台上有效地运行,是嵌入式系统开发中需要解决的关键问题。解决的方法是在硬件平台和操作系统之间提供硬件相关层来屏蔽这些硬件的差异,给操作系统提供统一的运行环境,这种硬件相关层就是嵌入式系统中的板级支持包BSP(BoardSupportPackage,简称BSP)。本文以PXA250处理器为硬件环境,研究了在嵌入式Linux系统中不同开发阶段BSP的设计与实现。
2. BSP及其作用
BSP是嵌入式系统中介于硬件平台和操作系统之间的中间层软件,主要目的是为了屏蔽底层硬件的多样性,根据操作系统的要求完成对硬件的直接操作,向操作系统提供底层硬件信息并最终启动操作系统。BSP具有硬件相关性和操作系统相关性的特点,其主要作用包括:
(1)初始化底层硬件,为操作系统提供底层硬件信息;
(2)初始化相关硬件设备,主要是存储设备、通信设备;
(3)检测系统硬件是否正常;
(4)加载操作系统并启动系统运行。
3. 嵌入式Linux系统BSP的实现
BSP是相对于操作系统而言的,不同的操作系统有不同定义形式的BSP,要求BSP所实现的功能也有所不同。在嵌入式Linux系统中,主要是初始化底层硬件并引导操作系统;同时,BSP又是和硬件相关的,还要考虑对硬件的初始化操作。在基于PXA250的系统中,这些初始化操作主要是对cPU、内存、中断等相关的寄存器及PXA25O的协处理器进行正确的配置。在不同的开发阶段,因为核心和文件系统所处的位置不同,BSP所要完成的工作也有所不同:在开发调试阶段,BSP要能够与主机通信并从主机下载核心;在目标产品中,BSP要能够从非易失存储设备中加载核心。
3.1. 开发调试阶段BSP的实现
开发初期由于调试系统的需要,BSP需把核心和文件系统从主机直接下载到目标板的内存中运行,其开发环境如图1所示。
与BSP通信操作系统及上层应用程序
BSP的程序P
硬件层
图1嵌入式系统开发调试环境
由图1中BSP所处的位置可知,BSP要完成如下工作:
(1)硬件的初始化和配置。
①设置PXA250的协处理器,将内存管理单元(MMU)关掉,清空读、写缓冲和TLB。
②设置CPU的核心寄存器和各种控制寄存器,将CPU从加电时的缺省状态设置为系统所要求的工作状态叫。
③设置内存配置寄存器和内存刷新寄存器,确定内存的大小和刷新频率[】]。
(2)通信设备的初始化。
BSP需与主机通信,从主机下载核心和文件系统,因此要完成相应通信设备的初始化。与主机通信的设备一般是网卡和串口。串口间通信要遵循一定的协议,包括数据格式、同步方式、传输速率、纠错方式等。对串口的初始化就是对这些协议进行设定,使通信双方处于相同的传输模式。在目标板上初始化串口是通过设置其寄存器实现的:设置串口的行控制寄存器确定串口接收数据的格式,设置串口的波特率产生寄存器确定串口接收数据的速率。设置串口的通信协议为:八个数据位、一个停止位,没有奇偶校验位,9 600波特率。串口初始化后就可以从其数据接收寄 存器中读取数据。
对网卡初始化也是通过设置其寄存器实现的,设置控制寄存器,使网卡处于接收模式。用网卡与主机通信时,主机端的通信程序要知道目标板上网卡的MAC地址才能发送数据。因此,我们要把网卡的MAC地址设定为指定值。
从网卡的数据接收寄存器读取数据时要把数据包中的非数据信息(包的状态、长度、原地址、目的地址和类型)丢掉。
BSP从主机接收文件,因此必须要提供主机与BSP通信的程序。主机端的通信程序可用操作系统提供的系统调用直接设置串口的属性,使主机端串口的通信协议与目标板串口的通信协议一致。主机端的程序通过与目标板连接的串口线将数据写到目标板串口的数据寄存器中。用网卡时,用原始套接口对网卡进行写操作,把数据包发送到目标板上网卡的数据接收缓存寄存器中。
(3)从主机接收核心和文件系统,启动核心运行。
系统加电时,BSP从位于0地址的非易失存储器FLASH中执行,和运行在主机上的程序通信,从串口或网卡的数据寄存器中读取数据,把核心和文件系统下载到内存中指定的位置,最后将CPU中的程序计数器PC置为核心在内存中的起始地址,实现核心启动。但是,程序在FLASH中执行时不能对变量进行写操作,为了使程序能正确执行,BSP必须将自己重定位(即把自己搬运到)到内存中,并且在进入c语言函数执行前要设置好堆栈指针。
其主要实现过程的伪码如下:
硬件(cup、内存等)初始化;
通信设备(网卡、串口)初始化;
将自己重定位到内存中;
设置系统的堆栈指针;
跳转到从串口读取核心和文件系统的函数;
从串口读取核心和文件系统的函数(void)
{
while(核心没读取完){
while(串口的接收数据寄存器为空)(等待);
从串口的数据寄存器读取数据到内存中;
核心大小减去已读取的大小,确定核心是否读取完;
if(核心读取完){