(linux)BSP板级支持包开发理解

1. 概述

嵌入式系统由硬件环境、嵌入式操作系统和应用程序组成,硬件环境是操作系统和应用程序运行的硬件平台,它随应用的不同而有不同的要求。硬件平台的多样性是嵌入式系统的主要特点,如何使嵌入式操作系统在不同的硬件平台上有效地运行,是嵌入式系统开发中需要解决的关键问题。解决的方法是在硬件平台和操作系统之间提供硬件相关层来屏蔽这些硬件的差异,给操作系统提供统一的运行环境,这种硬件相关层就是嵌入式系统中的板级支持包BSP(Board Support Package,简称BSP)。

2. BSP及其作用

BSP是嵌入式系统中介于硬件平台和操作系统之间的中间层软件,主要目的是为了屏蔽底层硬件的多样性,根据操作系统的要求完成对硬件的直接操作,向操作系统提供底层硬件信息并最终启动操作系统。BSP具有硬件相关性和操作系统相关性的特点,其主要作用包括:

  1. 初始化底层硬件,为操作系统提供底层硬件信息;
  2. 初始化相关硬件设备,主要是存储设备、通信设备;
  3. 检测系统硬件是否正常;
  4. 加载操作系统并启动系统运行。

3. 嵌入式Linux系统BSP的实现

BSP是相对于操作系统而言的,不同的操作系统有不同定义形式的BSP,要求BSP所实现的功能也有所不同。在嵌入式Linux系统中,主要是初始化底层硬件并引导操作系统;同时,BSP又是和硬件相关的,还要考虑对硬件的初始化操作。
在不同的开发阶段,因为核心和文件系统所处的位置不同,BSP所要完成的工作也有所不同:
在开发调试阶段,BSP要能够与主机通信并从主机下载核心;
在目标产品中,BSP要能够从非易失存储设备中加载核心。

3.1 开发调试阶段BSP的实现

开发初期由于调试系统的需要,BSP需把核心和文件系统从主机直接下载到目标板的内存中运行.
BSP要完成如下工作:
1. 硬件的初始化和配置
2. 通信设备的初始化
BSP需与主机通信,从主机下载核心和文件系统,因此要完成相应通信设备的初始化。与主机通信的设备一般是网卡和串口。
串口间通信要遵循一定的协议,包括数据格式、同步方式、传输速率、纠错方式等。对串口的初始化就是对这些协议进行设定,使通信双方处于相同的传输模式。在目标板上初始化串口是通过设置其寄存器实现的:设置串口的行控制寄存器确定串口接收数据的格式,设置串口的波特率产生寄存器确定串口接收数据的速率。设置串口的通信协议为:八个数据位、一个停止位,没有奇偶校验位,9600波特率。串口初始化后就可以从其数据接收寄 存器中读取数据。
对网卡初始化也是通过设置其寄存器实现的,设置控制寄存器,使网卡处于接收模式。用网卡与主机通信时,主机端的通信程序要知道目标板上网卡的MAC地址才能发送数据。因此,我们要把网卡的MAC地址设定为指定值。
从网卡的数据接收寄存器读取数据时要把数据包中的非数据信息(包的状态、长度、原地址、目的地址和类型)丢掉。
BSP从主机接收文件,因此必须要提供主机与BSP通信的程序。主机端的通信程序可用操作系统提供的系统调用直接设置串口的属性,使主机端串口的通信协议与目标板串口的通信协议一致。主机端的程序通过与目标板连接的串口线将数据写到目标板串口的数据寄存器中。用网卡时,用原始套接口对网卡进行写操作,把数据包发送到目标板上网卡的数据接收缓存寄存器中。
3. 从主机接收核心和文件系统,启动核心运行
系统加电时,BSP从位于0地址的非易失存储器FLASH中执行,和运行在主机上的程序通信,从串口或网卡的数据寄存器中读取数据,把核心和文件系统下载到内存中指定的位置,最后将CPU中的程序计数器PC置为核心在内存中的起始地址,实现核心启动。但是,程序在FLASH中执行时不能对变量进行写操作,为了使程序能正确执行,BSP必须将自己重定位(即把自己搬运到)到内存中,并且在进入c语言函数执行前要设置好堆栈指针。
其主要实现过程的伪码如下:

    硬件(cup、内存等)初始化;
    通信设备(网卡、串口)初始化;
    将自己重定位到内存中;
    设置系统的堆栈指针;
    跳转到从串口读取核心和文件系统的函数;
    从串口读取核心和文件系统的函数(void)
    {
        while(核心没读取完){
            while(串口的接收数据寄存器为空)(等待);
            从串口的数据寄存器读取数据到内存中;
            核心大小减去已读取的大小,确定核心是否读取完;
            if(核心读取完){
                -asm{mov pc,一核心在内存中的起始地址;}
        }
    }

3.2. 目标产品中BSP的实现

3.2.1 BSP独立实现

把核心和文件系统直接从主机下载到内存中运行,只适用于开发调试阶段。目标产品中核心和文件系统烧写在非易失性存储设备上,因此BSP要从这些设备中加载并启动核心。此时,BSP不需要与主机通信,可以将其单独实现在产品中。将BSP单独实现时,可以根据需要向其中灵活地添加多种功能:启动核心前检测内存是否能被正确读写,通过判断网卡、声卡等硬件的属性寄存器确定硬件设备是否正常等。
此时,BSP要完成的工作如下:

  1. 初始化硬件及存储设备。
  2. 测试硬件设备是否正常。
  3. 从相应的存储设备中加载核心到内存中,并启动核心.

硬件的初始化和配置与前面相同,主要完成CPU和内存的初始化。此时,BSP要从存储设备中加载并启动核心,因此要对存储设备(一般是FLASH或CF卡)进行初始化,使其能被正确寻址。BSP中读取核心的代码与具体的操作系统及文件格式无关,不能从文件系统层把核心作为一个文件读进来,只能从硬件接口来实现具体的操作,把核心从存储设备读入内存,然后把核心的开头当作一段程序的起点,使CPU转入核心执行.
非易失性存储器FLASH和内存统一寻址,对它的访问和访问内存是一样的,可以利用寄存器将核心直接从FALSH读取到内存。CF卡相对内存来说属于外设,对其进行读取操作是通过控制其寄存器(数据寄存器、状态与控制寄存器)来实现的,向其控制寄存器发布ATA命令OA何处读取,读取数据的大小等)后,判断其状态寄存器是否准备好,才能从其数据寄存器中读取数据到内存中。把核心从非易失性存储设备读到内存中后,将CPU中的程序计数器PC置为核心在内存中的起始地址,实现系统的启动。
对应的伪码如下:

硬件(cup、内存等)初始化;
存储设备(FLASH、CF卡)初始化;
测试硬件设备是否正常;
根据CF卡的属性寄存器判断CF卡是否存在;
如果存在,跳转到从CF卡加载核心到内存的函数;
如果不存在,直接将核心从FLASH加载到内存中;
mov pc,一核心在内存中的起始地址;
从CF卡加载核心到内存的函数(void)
{
    while(核心没加载完){
        向CF卡发布ATA命令,确定从CF卡的哪一块开始读,
        读多少块
        while(CF卡的状态没准备好){等待;}
        从CF卡的数据寄存器读数据到内存中;
        核心大小减去所读的块数乘以块大小;
        if(核心加载完){
            -asm{mow pc,=核心在内存中的起始地址;}
    }
}

3.2.2 在核心中实现BSP

BSP单独实现易于修改,当硬件改变时,只需要对相关硬件的初始化代码进行修改并重新编译。但是,对于嵌入式系统的存储介质FLASH,有些文件系统对它的分区有字节对齐性的要求,也就是说分区必须是特定大小或特定大小的倍数才能有写访问权限,如果把BSP单独写在一个分区中会造成存储空间的浪费。实质上,BSP是属于操作系统的一部分且和操作系统绑定在一起运行,在开发板硬件固定的情况下,可以将其实现在Linux核心中。在核心中实现BSP时,BSP应能向核心提供必要的底层硬件信息,实现核心从非易失性存储器FLASH到内存的加载和启动。
在嵌入式系统的存储介质FLASH中没有所谓的引导扇区,相应的嵌入式Linux内核映象zImage也没有如PC机上的引导扇区代码bootsect及辅助代码setup,而是由head.o、misc.o、head-xscale.o和piggy.o几个文件顺序连接而成。其中,head.o是由/arch/arm/boot/compressed/head.S汇编而成,是核心最先执行的代码,主要作用是用misc.o解压缩核心并使CPU转到核心解压缩后所在的内存地址执行。head-xscale.o是体系结构相关的代码。piggy.o是系统启动后保留在内存中的全部有用程序[3],也就是head.o要解压缩的代码。由以上分析可知,嵌入式Linux的内核不能自启动,要启动核必须满足以下两个条件:

  1. 系统硬件已被正确初始化;
  2. 核心在内存中,并且CPU中的程序计数器被置为核心在内存中的起始地址。

在核心中实现BSP时,BSP必须位于核心代码的最前面,即将其实现在head.S文件的最前面,完成如PC 机上的BIOS、bootsect和setup的功能。同时,要保证核心在加载到内存后必须能跳转到和没有BSP时核心中相同的地方执行。重新编译核心后,就将BSP实现在核心映象zImage中的开始代码中。把核心烧到FLASH的0地址,系统启动时首先执行上述代码,将核心加载到内存中执行,实现核心的自启动。

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
一.什么是装箱?什么是拆箱? 在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料。在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行:   1 Integer i = new   Integer( 10 ); 而在从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了:   1 Integer i = 10 ;

Redis与Java - 数据结构 - 2016-07-24 14:07:41

Redis与Java 标签 : Java与NoSQL Redis( REmote DIctionary Server ) is an open source (BSD licensed), in-memory data structure store, used as database , cache and message broker . It supports data structures such as strings , hashes , lists , sets , sorted sets
0x00 实验背景 Server:选用腾讯云的云主机  Ubuntu Server 14.04.1 LTS 64位 Client-1:Acer笔记本 Win7 x64系统 Client-2:安卓机小米4  Android 6.0系统(MIUI8)   0x01  OpenVPN的背景知识 **** **** 以下内容摘自维基百科**** **** OpenVPN是一个用于创建虚拟专用网络加密通道的软件包,最早由James Yonan编写。OpenVPN允许创建的VPN使用公开密钥、电子证书、或者用户名/密

逐步深入TCP/IP协议栈 - 2016-07-24 14:07:36

一、关于应用层用户数据的历程,见下图:                                                                             TCP/IP数据包的封装 过程: 应用层将数据通过协议栈逐层向下传递,其下的每层接到来自上层的数据时,根据每层的协议都要在其数据 的前端添加首部信息进行封装。不同的协议层对数据包有不同 的称谓,在传输层叫做数据段,在网络层叫做数据报, 在链路层叫做数据帧。在经过链路层时,数据已经封装成帧并递交给物理层的传输介质上,到

Java事务--JTA原理 - 2016-07-23 19:07:54

        上一篇文章介绍了JDBC事务,JDBC可以处理单数据源的事务,满足大部分事务处理的需求,但是JDBC事务不能解决多数据源和分布式事务问题,Java平台给我们提供了解决方案--JTA。本文将探讨JTA的一些细节。          一 分布式事务          通常把一个数据库内部的事务处理,如对多个表的操作,作为本地事务看待。数据库和JDBC的事务处理对象是本地事务,而分布式事务处理的对象是全局事务。          所谓全局事务,是指分布式事务处理环境中,多个数据库可能需要共同完成
LINUX下SVN安装,配置,web目录同步 注: 各服务器运行环境可能有所不同,操作过程中可能出现其他问题,自行查阅资料解决 SVN的具体使用方法很多,本文档只是使用了SVN最简单的用法,感兴趣的同学可以查阅相关资料。 一、 安装subversion 首先输入rpm -qa | grep subversion 查看SVN是否已经安装过 如果输出类似如下结果,则说明已经安装:subversion-1.6.11-7.el6.x86_64 执行 yum -y install subversion 安装SVN
一、目录结构 首先是目录结构如图: 二、pom.xml文件 project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" modelVersion4.0.0/modelVe

Linux内核之进程管理 - 2016-07-23 19:07:13

进程: 进程就是处于执行期的程序以及它包含的资源总和。 线程是进程中的活动对象,每个线程拥有一个独立的程序计数器、进程栈和一组进程寄存器。 内核调度的是线程,而不是进程。 进程描述符: 内核的进程描述符为 task_struct 结构体,定义在linux/sched.h,进程描述符包含了一个进程的所有信息。包括:进程标识符、进程当前状态、栈地址空间、内存地址空间、文件系统、打开的文件、信号量等。 内核把进程的列表存放在叫做 任务列表(task list) 的双向循环链表,链表中每一项都是类型为task_s

SSH权限管理控制到按钮 - 2016-07-23 19:07:11

数据库设计 我的设计如下: 用户:fu_admin 角色:sys_role 权限:sys_purview 用户-角色:sys_user_role 角色-权限:sys_role_purview 标准的权限管理系统设计为以上5张表。 注:用户、用户-角色我就不做说明了,这两个是很简单的两块,用户的crud,以及为用户分配角色(多对多的关系)稍微琢磨一下就清楚了, 下面都是针对为角色分配权限的实现 后台实现 展示层采用ztree树 roleList.jsp !DOCTYPE html PUBLIC "-//W3

docker容器扫盲 - 2016-07-23 18:07:08

Centos 6.5 安装和使用docker 基于本人一贯的习惯,关于“某某某是什么”这样的问题,请百度吧,会有更专业的人士,会比我说的更详细更深,这里我只给出本人亲历的安装和使用过程。 1.安装 先检查服务器环境,docker要求操作系统CentOS6以上,kernel 版本必须2.6.32-431或更高,即=CentOS 6.5,运行docker时实际提示3.8.0及以上,必须64bit,32bit不支持docker。 [root @201 ~] # uname -r 2.6 .32 - 642.1