• BSP板机支持包、linux启动分析、ARM裸机编程


    一、BSP

    Board Support Package,板级支持包。它来源于嵌入式操作系统与硬件无关的设计思想,操作系统被设计为运行在虚拟的硬件平台上。对于具体的硬件平台,与硬件相关的代码都被封装在BSP中,由BSP向上提供虚拟的硬件平台,BSP与操作系统通过定义好的接口进行交互。

    在这里插入图片描述

    以前嵌入式芯片厂商,会提供双系统(WinCE与Linux)平台的板级开发包,详细如下:

    • OAL(OEM 适配层,OEM Adaptation Layer),是基于Windows CE平台用来引导系统核心映像和初始化、管理硬件。它是BSP驱动的一部分。
    • KITL(Kernel Independent Transport Layer)是基于Windows CE平台的一种软件技术,开发商基于它可以很容易地支持各种调试功能。
    • Device Drivers,设备驱动。
    • Configuration Files,配置文件。
    • Boot Loader,引导程序。

    BSP是所有与硬件相关的代码体的集合。一个成熟的商用操作系统,其被广泛应用的必要条件之一就是能够支持众多的硬件平台,并实现应用程序的硬件无关性。

    一般来说,这种无关性都是由操作系统实现的。但是对于嵌入式系统来说,它没有像PC机那样具有广泛使用的各种工业标准、统一的硬件结构。各种嵌入式系统各不同的应用需求就决定了它一般都选用各自定制的硬件环境,每种嵌入式系统从核心的处理器到外部芯片在硬件结构上都有很大的不同。这种诸多变化的硬件环境就决定了无法完全由操作系统来实现上层软件与底层硬件之间的无关性。因此各种商用实时操作系统,都采用了分层设计的方法,它将系统中与硬件直接相关的一层软件独立出来,称之为Board Support Package,简称为BSP。

    顾名思义,BSP是针对某个特定的单板而设计的。如果没有单板支持软件包,则操作系统就不能在单板上运行。并且它对于用户(指开发者)也是开放的,用户可以根据不同的硬件需求对其作改动或二次开发。BSP在嵌入式系统中的角色,很相似于在PC系统中的BIOS和驱动程序的地位。BSP的具体结构和组成根据不同的嵌入式操作系统而不同。BSP的开发要求设计人员具备软硬件方面的综合知识。BSP软件与其他软件的最大区别在于BSP软件有一整套模板和格式,开发人员必须严格遵守,不允许任意发挥。在BSP软件中,绝大部分文件的文件名和所要完成的功能都是固定的。所以,BSP软件的开发一般来说都是在一个基本成型的BSP软件上进行修改,以适应不同单板的需求.

    针对某类CPU的硬件单板,芯片厂商(如三星、高通、联发科、华为等)为嵌入式操作系统(如Linux、WinCE、vxWorks)提供有其DEMO板的BSP, 这些程序位于指定的目录之下。也就是我们所说的最小系统BSP。

    在这里插入图片描述

    uboot负责系统引导、kernel负责最终的系统运行、文件系统是 linux 在 soc 平台起来之后挂载的,该文件系统存储各应用程序、库文件等其他文件。

    总结:

    一般来说,我们在硬件系统设计好之后,都会先找到一个与自己系统相近 的DEMO板BSP相同的CPU),并以此为基础,开发自己单板的BSP。

    二、驱动

    驱动是 Linux 系统中设备和用户之间的桥梁,Linux 系统中,访问设备必须通过设备驱动进行操作,用户程序是不能直接操作设备的。

    在这里插入图片描述

    驱动程序运行与内核空间,用户程序只能通过内核提供的系统调用,由经 VFS 以及驱动程序才能访问和操作硬件,硬件设备传递的数据也必须经过驱动、VFS 和系统调用才能被用户程序接收。所以说,设备驱动是应用程序访问系统设备以及进行数据传递的桥梁和通道。

    驱动的基本要素

    Linux 设备驱动是具有入口和出口的一组方法的集合,各方法之间相互独立。

    在这里插入图片描述

    Linux 设备在内核中是用设备号进行区分的,而决定这些设备号的正是设备驱动程序。另外,在用户空间如何管理这些设备,这也是与驱动程序息息相关的。一个完整的设备驱动必须具备以下基本要素:

    1.驱动的入口和出口。驱动入口和出口部分的代码,并不与应用程序直接交互,仅仅只与内核模块管理子系统有交互。在加载内核的时候执行入口代码,卸载的时候执行出口代码。这部分代码与内核版本关系较大,严重依赖于驱动子系统的架构和实现。

    2.操作设备的各种方法。驱动程序实现了各种用于系统服务的各种方法,但是这些方法并不能主动执行,发挥相应的功能,只能被动的等待应用程序的系统调用,只有经过相应的系统调用,各方法才能发挥相应的功能,如应用程序执行 read()系统调用,内核才能执行驱动 xxx_read()方法的代码。这部分代码主要与硬件和所需要实现的操作相关。

    3.提供设备管理方法支持。包括设备号的分配和设备的注册等。这部分代码与内核版本以及最终所采用的设备管理方法相关系,如采用 udev,则驱动必须提供相应的支持代码。

    三、启动分析

    上电->uboot->加载Linux内核->挂载根文件系统->执行应用程序

    1.uboot

    uboot其实就是一个通用的引导程序——bootloader。

    boot,完成硬件的初始化,启动硬件平台

    loader,初始化硬件后,加载操作系统。

    支持各种硬件,例如支持ARMMIPS、X86、AVR32、RISC-V架构…

    支持各种操作系统,例如支持WinCE、Linux内核、安卓操作系统…

    2.uboot的作用

    1)第一阶段初始化,CPU的初始化,用汇编语言来编写,初始化cache、MMU、时钟、看门狗、DDR3、eMMC…

    2)第二阶段初始化,板级的初始化,一般来说用C语言来编写,初始化串口、网卡、usb、lcd…

    3)提供了很多工具,进入uboot命令行,使用uboot的命令

    4)加载操作系统

    3.uboot相关命令

    常用的和信息查询有关的命令有 3 个: bdinfoprintenvversion

    • bdinfo 命令用于查看开发板信息

    在这里插入图片描述

    • printenv or pri用于输出环境变量信息

    • version 用于查看 uboot 的版本号

    关键的内容:

    1)bootargs,启动参数
    bootargs=lcd=at070tn92 tp=gslx680-linux root=/dev/mmcblk0p2 rw rootfstype=ext4
    
    • 1

    lcd=at070tn92,液晶屏的型号,7英寸的800*480的屏幕
    tp=gslx680-linux,触摸屏的型号
    root=/dev/mmcblk0p2,根文件系统在哪里,告诉内核去哪里挂载根文件系统。
    mmcblk0p2
    mmcblk0,emmc电子硬盘0
    rw,该文件系统可以读,又可以写。
    rootfstype=ext4,该文件系统类型为ext4(ext2/ext3,fat32,ntfs)。

    p2,partion2,emmc电子硬盘0的分区2
    在这里插入图片描述

    2)启动命令
    bootcmd=ext4load mmc 2:1 0x48000000 uImage;bootm 0x48000000
    
    • 1

    以ext4文件系统去emmc第一个分区加载uImage linux内核镜像,加载到内存地址0x48000000;然后在该地址0x48000000启动linux内核。

    这条命令告诉uboot启动完之后,要干什么动作,通过bootcmd命令进行了解。

    3)修改启动延时时间
    #setenv bootdelay 3
    #saveenv
    Saving Environment to MMC...
    Writing to MMC(2)... done
    
    • 1
    • 2
    • 3
    • 4
    4)复位开发板
    reset
    
    • 1
    5)修改本地IP地址
    #setenv ipaddr 192.168.11.6
    #setenv gatewayip 192.168.11.1
    #setenv netmask 255.255.255.0
    #saveenv 
    
    • 1
    • 2
    • 3
    • 4
    6)验证网络的通畅
      ```uboot
      #ping 电脑IP地址              
      ```
    
    • 1
    • 2
    • 3

    #注意:开发板必须通过网线连接到电脑;电脑必须关闭防火墙;电脑不能主动ping开发板,因为uboot默认状态下是关闭了网卡。

    7)修改服务器IP地址
    #setenv serverip 192.168.11.3
    #saveenv
    
    • 1
    • 2
    8)删除对应的环境变量,例如删除sap变量
    #setenv sap 空格键
    #saveenv
    
    • 1
    • 2
    9)通过tftp下载文件到内存

    使用该命令的时候,要注意网络的配置,关闭电脑的防火墙!

    #tftp 内存地址 文件名              
    
    • 1
     GEC6818# tftp 0x40000000 led.bin
    Speed: 100, full duplex
    Using dwmac.c0060000 device
    TFTP from server 192.168.11.3; our IP address is 192.168.11.6
    Filename 'led.bin'.
    Load address: 0x40000000
    Loading: #
             261.7 KiB/s
    done
    Bytes transferred = 4572 (11dc hex)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    10)执行某地址存在的二进制文件
            ```uboot
            #go 内存地址              
            
            #go 0x40000000
            ## Starting application at 0x40000000 ...              
            ```
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    若想退出当前程序的执行,只能是复位或重新上电!

    11)help,支持的命令

    四、linux内核

    1、内核的作用

    1)进程的管理和进程的通信:进程的创建和删除、进程之间优先级抢占、进程的时间片轮转调度、进程间的通信。

    2)内存管理:内存分配算法,每个进程的内存空间由Linux进行分配。

    3)支持的文件系统,可以通过cat /proc/filesystems

    4)设备的管理,聚焦到linux驱动:字符设备、块设备、网络设备、中断、内核时钟。

    5)网络协议:TCP/IP。

    linux内核的官网
    在这里插入图片描述

    2.输出信息

    1)uboot加载内核

    ## Booting kernel from Legacy Image at 48000000 ...
    Image Name:   Linux-3.4.39-gec                                        //内核版本,3.4.39
    Image Type:   ARM Linux Kernel Image (uncompressed)
    Data Size:    5540912 Bytes = 5.3 MiB                                 //内核镜像的大小5.3MB
    Load Address: 40008000                                                //内核是存储在内存地址空间	0x40008000
    Entry Point:  40008000                                                //内核执行的入口地址		0x40008000
    Verifying Checksum ... OK                                             //校验镜像的内容是否完整
    Loading Kernel Image ... OK                                           //若校验成功,则启动内核
    Starting kernel ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2)linux内核启动

    [    0.000000] Booting Linux on physical CPU 0 //它只是用CPU0进行linux启动
    
    • 1

    3)告诉当前linux内核的版本、使用到的编译器、编译生成时间

    [    0.000000] Linux version 3.4.39-gec (llf@ubuntu) (gcc version 4.8 (GCC) ) #2 SMP PREEMPT Wed May 11 15:03:54 CST 2022
    
    • 1

    4)uboot传递给内核的信息,使用lcd、触摸屏是什么型号、串口的配置等信息

    [    0.000000] Kernel command line: console=ttySAC0,115200n8 androidboot.hardware=GEC6818 androidboot.console=ttySAC0 androidboot.serialno=0123456789abcdef initrd=0x49000000,0x1000000 lcd=at070tn92 tp=gslx680-linux root=/dev/mmcblk0p2 rw rootfstype=ext4
    
    • 1

    5)内存管理

    [    0.000000] Memory: 1024MB = 1024MB total
    [    0.000000] Memory: 810792k/810792k available, 237784k reserved, 272384K highmem
    [    0.000000] Virtual kernel memory layout:
    [    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    [    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    [    0.000000]     vmalloc : 0xef800000 - 0xfee00000   ( 246 MB)
    [    0.000000]     lowmem  : 0xc0000000 - 0xef600000   ( 758 MB)
    [    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
    [    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
    [    0.000000]       .text : 0xc0008000 - 0xc0a561c8   (10553 kB)
    [    0.000000]       .init : 0xc0a57000 - 0xc0a94100   ( 245 kB)
    [    0.000000]       .data : 0xc0a96000 - 0xc0b307b0   ( 618 kB)
    [    0.000000]        .bss : 0xc0b307d4 - 0xc0d10508   (1920 kB)
    [    0.000000]        .bss : 0xc0b307d4 - 0xc0d10508   (1920 kB)
    [    0.000000] SLUB: Genslabs=11, HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6)设备管理,初始化各种硬件(gpio、串口、i2c、网络硬件、usb…),加载各个硬件的驱动

    7)挂载根文件系统

    [    3.967000] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
    [    3.969000] VFS: Mounted root (ext4 filesystem) on device 179:2.
    [    3.976000] devtmpfs: mounted
    
    • 1
    • 2
    • 3

    8)执行脚本文件

    /etc/profile
    /etc/init.d/rcS
    
    • 1
    • 2

    9)进入命令行

    五、根文件系统

    1.根文件系统

    linux内核挂载的第一个文件系统,该根文件系统是挂载到根目录下的文件系统。rootfs,它是一个容器,也称之为一个“包”,里面包含:

    bin sbin usr etc lib home mnt proc var dev ......
    
    • 1

    1)linux的shell命令

    • /bin,一般的shell命令
    • /sbin,超级管理员就是root用户才能够使用的命令,这些命令很多时候跟硬件相关
    • /usr/bin,应用程序与工具
    • /usr/sbin,shell命令或工具
    2)/dev

    该目录包含应用程序访问硬件的接口,只有字符设备和块设备有设备文件,网络设备是没有设备文件。

    • lcd设备,/dev/fb0
    • 触摸屏设备,/dev/input/event0

    3)/etc

    包含系统的配置文件:用户名、密码、主机名、网络配置、系统

    4)/proc

    该目录虚拟文件系统目录,是系统内存的映射,实时反映linux系统的工作状态,可直接访问这个目录来获取系统信息。

    • 数字,PID进程编号与状态信息

    • version,linux系统的版本

    uname -r
    uname -a
    
    • 1
    • 2
    cd /proc
    cat version  #版本信息
    cat cpuinfo  #cpu信息
    cat meminfo  #linux内核所有内存状态信息
    cat devices  #devise文件
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5)库的路径

    • /lib
    • /usr/lib
    • /usr/local/lib

    6)/mnt

    系统管理员安装临时文件系统的安装点,系统提供这个目录是让用户临时挂载其他的文件系统。

    7)/var

    系统的工作日志或运行时需要改变数据文件的存放目录。

    8)/usr

    系统资源目录,Unix System Resource,即Unix系统资源的缩写。该目录是系统核心所在,包含了所有的共享文件。它是 unix 系统中最重要的目录之一,涵盖了二进制文件,各种文档,各种头文件,还有各种库文件;还有诸多程序,例如 ftp,telnet 等等。这是最庞大的目录,要用到的应用程序和文件几乎都在这个目录。

    • /usr/bin 众多的应用程序
    • /usr/sbin 超级用户的一些管理程序
    • /usr/doc linux文档
    • /usr/include linux下开发和编译应用程序所需要的头文件
    • /usr/lib 常用的动态链接库和软件包的配置文件
    • /usr/man 帮助文档
    • /usr/src 源代码,linux内核的源代码就放在/usr/src/linux里
    • /usr/local/bin 本地增加的命令
    • /usr/local/lib 本地增加的库

    9)/lost+found

    这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows下*.chk)就在这里

    10)/sys

    sysfs是一种基于ram文件系统(ramdisk 文件系统基于磁盘模拟技术,实际文件系统是ex2 ex3等)和proc一样。sysfs文件系统是一个类似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。其实,就是在用户态可以通过对sys文件系统的访问,来看内核态的一些驱动或者设备等,例如以下触摸屏设备驱动详细信息。

    [root@GEC6818 /sys/devices/virtual/rc/rc0/input1/event0]#cat uevent
    MAJOR=13
    MINOR=64
    DEVNAME=input/event0
    
    • 1
    • 2
    • 3
    • 4

    eg:

    • /sys/devices

    该目录下是全局设备结构体系,包含所有被发现的注册在各种总线上的各种物理设备。一般来说,所有的物理设备都按其在总线上的拓扑结构来显示,但有两个例外即platform devices和system devices。

    platform devices一般是挂在芯片内部的高速或者低速总线上的各种控制器和外设,它们能被CPU直接寻址;

    system devices不是外设,而是芯片内部的核心结构,比如CPU,timer等,它们一般没有相关的驱动,但是会有一些体系结构相关的代码来配置它们。

    /sys/devices是内核对系统中所有设备的分层次表达模型,也是/sys文件系统管理设备的最重要的目录结构。

    • /sys/dev

    该目录下存放主次设备号文件,其中分成字符设备、块设备的主次设备号码(major:minor)组成的文件名,该文件是链接文件并且链接到其真实的设备(/sys/devices)。

    • /sys/class

    该目录下包含所有注册在kernel里面的设备类型,这是按照设备功能分类的设备模型,每个设备类型表达具有一种功能的设备。每个设备类型子目录下都是这种设备类型的各种具体设备的符号链接,这些链接指向/sys/devices/下的具体设备。 设备类型和设备并没有一一对应的关系,一个物理设备可能具备多种设备类型(如何触摸屏包含了输入子系统设备模型、i2c设备模型、platform模型等);一个设备类型只表达具有一种功能的设备,比如:系统所有输入设备都会出现在/sys/class/input之下,而不论它们是以何种总线连接到系统的。

    • /sys/block

    该目录下的所有子目录代表着系统中当前被发现的所有块设备。

    • /sys/bus

    该目录下的每个子目录都是kernel支持并且已经注册了的总线类型。

    • /sys/fs

    按照设计,该目录使用来描述系统中所有的文件系统,包括文件系统本身和按照文件系统分类存放的已挂载点。

    • /sys/kernel

    这个目录下存放的是内核中所有可调整的参数。

    • /sys/module

    该目录下有系统中所有的模块信息,不论这些模块是以内联(inlined)方式编译到内核映像文件中还是编译为外模块(.ko文件),都可能出现在/sys/module中。

    linux内核启动完之后,会自动执行以下两个脚本文件:
    • /etc/init.d/rcS
    • /etc/profile

    六、ARM裸机编程

    • 在开发板找出硬件的丝印层,查看原理图
    • 分析原理图
    • 理解硬件的控制原理
    • 找到对应的库函数寄存器(CPU的数据手册,CPU的使用说明书)
    • 理解寄存器的控制流程
    • 根据地址访问寄存器
    • 实现硬件的控制

    点亮led

    //1.定义寄存器
    #define GPIOEOUT 		(*(volatile unsigned int *)0xC001E000)
    #define GPIOEOUTENB 	(*(volatile unsigned int *)0xC001E004)
    #define GPIOEALTFN0 	(*(volatile unsigned int *)0xC001E020)
    #define GPIOEALTFN1 	(*(volatile unsigned int *)0xC001E024)
    
    void delay(void)
    {
    	//思考为什么要加volatile
    	volatile unsigned int i=0x2000000;
    	
    	while(i--);
    }
    
    //2.c程序的入口,不使用标准的c库(使用标准C库,还得使用汇编配置堆和栈),同时入口函数名字为_start
    void _start(void)
    {
    	
    	//配置GPIOE13为输出模式
    	GPIOEALTFN0&=~(3<<26);	//GPIOE13的多功能配置[27:26]清零
    	
    	
    	//允许GPIOE13输出电平
    	GPIOEOUTENB|=1<<13;			
    	
    	while(1)
    	{
    		
    		//点亮
    		GPIOEOUT&=~(1<<13);
    		
    		//延时一会
    		delay();
    		
    		//熄灭
    		GPIOEOUT|=1<<13;
    		
    		//延时一会
    		delay();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    七、交叉编译器编译

    1.检查交叉编译器

    yyh@DESKTOP-L8EG6D3:/$ which arm-linux-gcc
    /usr/local/arm/5.4.0/usr/bin/arm-linux-gcc
    
    • 1
    • 2

    2.编译代码

    1)将led.c编译为目标文件led.o,-nostdlib且不使用标准c的库(使用标准C库,还得使用汇编配置堆和栈)

    arm-linux-gcc -o led.o led.c -nostdlib
    
    • 1

    2)将led.o链接到内存地址0x40000000,输出新的执行程序为led.elf

    arm-linux-ld -Ttext 0x40000000 -o led.elf led.o
    
    • 1

    3)由于uboot不是linux操作系统,它不具有运行应用程序的能力,需要转换为bin文件

    arm-linux-objcopy -O binary led.elf led.bin
    
    • 1

    八、下载led.bin到开发板执行

    1.使用uboot的tftp进行下载

    tftp 0x40000000 led.bin              
    
    • 1

    2.执行led.bin

    go 0x40000000  
    
    • 1

    参考

    (linux)BSP(板上支持包)概述 - 跑马灯的忧伤 - 博客园 (cnblogs.com)

    (1241条消息) BSP目录结构简介_David_Hu的博客-CSDN博客

    bsp是什么 - 嵌入式操作系统 - 电子发烧友网 (elecfans.com)

    (1241条消息) 史上最全的Uboot常用命令汇总(超全面!超详细!)收藏这一篇就够了_万里羊的博客-CSDN博客_uboat控制台指令大全

  • 相关阅读:
    Python入门之函数调用
    QGIS安装(以Windows系统为例)
    jquery中的contentType和processData参数解释
    线上MySQL的自增id用完了怎么办?
    由gomonkey引发的一些思考
    java计算机毕业设计网上宠物售卖平台源代码+数据库+系统+lw文档
    微软宣布 Windows 11 开始大范围推送
    JavaWeb学习笔记
    [ Linux Busybox ] flash_eraseall 命令解析
    Docker+K3S搭建集群
  • 原文地址:https://blog.csdn.net/qq_45698138/article/details/128195230