💘ARM Embedded System,欢迎关注我的Gitee
文章目录
💦搭建嵌入式Linux交叉开发环境
构建一个Linux系统,需仔细考虑下面几点。
(1)选择嵌入式Linux发行版。
(2)熟悉开发环境和工具。
(3)熟悉Linux内核。
(4)熟悉目标板引导方式。
(5)熟悉Linux根文件系统。
(6)理解Linux内存模型。
(7)理解Linux调度机制和进程线程编程。
💦嵌入式交叉编译环境搭建
搭建交叉编译环境是嵌入式开发的第一步,也是关键的一步。不同的体系结构、不同的操作内容甚至是不同版本的内核,都会用到不同的交叉编译器。
交叉编译器完整的安装一般涉及到多个软件的安装(可以从ftp://gcc.gnu.org/pub/下载),包括binutils、gcc、glibc、glibc-linuxthreads等软件。其中,binutils主要用于生成一些辅助工具,如readelf、objcopy、objdump、as、ld等;gcc是用来生成交叉编译器的,主要生成arm-linux-gcc交叉编译工具(应该说,生成此工具后已经搭建起了交叉编译环境,可以编译Linux内核了,但由于没有提供标准用户函数库,用户程序还无法编译);glibc主要是提供用户程序所使用的一些基本的函数库,glibc-linuxthreads是线程相关函数库。这样,交叉编译环境就完全搭建起来了。
现在嵌入式平台社区或厂商一般会提供在各种平台上测试通过的交叉编译器,而且也有很多把以上安装步骤全部写入脚本文件或者以发行包的形式提供,这样就大大方便了用户的使用。
💦主机交叉开发环境的配置(Windows)
配置控制台程序
Windows操作系统中有超级终端(HyperTerminal)工具;Linux/Unix操作系统有minicom(使用“minicom”命令启动该软件)等工具
配置TFTP服务
tftp是一个传输文件的简单协议,它基于UDP协议而实现。此协议设计的时候是进行小文件传输的
tftp传输中有3种模式。
netascii:8位的ASCII码形式。
octet:8位源数据类型。
mail:这种模式已经不再支持,它将返回的数据直接返回给用户,而不是保存为文件。
Linux下TFTP服务配置
tftp是一个传输文件的简单协议,它基于UDP协议而实现。此协议设计的时候是进行小文件传输的
vim /etc/xinetd.d/tftp
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /tftpboot
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
启动TFTP服务
$ /etc/init.d/xinetd start
关闭TFTP服务
$ /etc/init.d/xinetd stop
重启TFTP服务
$ /etc/init.d/xinetd restart
查看TFTP状态
$ netstat –au | grep tftp
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 *:tftp *:*
Windows下TFTP服务配置
在Windows下配置tftp服务需要安装使用tftp服务器软件,常见的可使用tftpd32,网上有很多下载该软件的地方,读者可以自行下载。要注意的是,windows下该软件是tftp的服务器端,而目标板上则是tftp的客户端。
NFS文件系统
NFS为Network FileSystem的简称,最早是由Sun公司提出发展起来的,其目的就是让不同的机器、不同的操作系统之间可以彼此共享文件。
NFS的使用分为服务器端和客户端,其中服务器端提供要共享的文件,而客户端则通过挂载“mount”这一动作来实现对共享文件的访问操作。在嵌入式开发中,通常NFS服务端在宿主机上运行,而客户端在目标板上运行。
NFS服务器端是通过读入它的配置文件“/etc/ exports”来决定所共享的文件目录的.
NFS配置
配置文件:/etc/exports
配置文件每一行格式:
[共享的目录] [客户端主机名称或IP]([参数1,参数2…])
NFS配置文件常用参数:
NFS配置文件举例:
cat /etc/exports
/home/david/project *(rw,sync,no_root_squash)
NFS服务启动
设置NFS服务在每次系统引导时自动开启:
# /sbin/chkconfig nfs on
(在Ubuntu中应该输入/sbin/chkconfig nfs-kernel-server on
)
在PC机中的串口调试助手之类的软件中:
#mount 192.168.1.180:/tftpboot/ /mnt
#cd /mnt
#./serial
注意:192.168.1.180为fedora的ip地址,如果mount失败,先试着ping一下是否实验箱和电脑能够连通,再在虚拟机里吧fedora的nfs重启下,service nfs restart,在配置ip后mount;还不行的话,实验一下
mount -t nfs -o intr,nolock,rsize=1024,wsize=1024 192.168.1.180:/tftpboot /mnt/
💦Bootloader
对于计算机系统来说,从开机上电到操作系统启动需要一个引导过程。嵌入式Linux系统同样离不开引导程序,这个引导程序就叫作Bootloader。
Bootloader是在操作系统运行之前执行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。
对于嵌入式系统,Bootloader是基于特定硬件平台来实现的。因此,几乎不可能为所有的嵌入式系统建立一个通用的Bootloader,不同的处理器架构都有不同的Bootloader。
💦Bootloader的种类
💦U-Boot的编译和使用
最早,DENX软件工程中心的Wolfgang Denk基于8xxrom的源码创建了PPCBOOT工程,并且不断添加处理器的支持。后来,Sysgo Gmbh把PPCBOOT移植到ARM平台上,创建了ARMBOOT工程。然后以PPCBOOT工程和ARMBOOT工程为基础,创建了U-Boot工程。
💦U-Boot编译
U-Boot目录可以分为三类:
与处理器体系结构或者开发板硬件直接相关。
一些通用的函数或驱动。
U-Boot的应用程序、工具或者文件。
💦U-Boot目录结构
💦Bootloader简介
1、board中存放于开发板相关的配置文件,每一个开发板都以子文件夹的形式出现。 (\board\)
2、Commom文件夹实现u-boot行下支持的命令,每一个命令对应一个源码文件。
3、cpu中存放特定cpu架构相关的目录,每一款cpu架构都对应了一个子目录。(\cpu\)
4、Doc是文档目录,有u-boot非常完善的文档。
5、Drivers中是u-boot支持的各种设备的驱动程序。
6、Fs是支持的文件系统,其中最常用的是JFFS2文件系统。
7、Include文件夹是u-boot使用的头文件,还有各种硬件平台支持的汇编文件,系统配置文件和文件系统支持的文件。
8、Net是与网络协议相关的代码,bootp协议、TFTP协议、NFS文件系统得实现。
9、Tools是生成U-boot的工具。
对u-boot的目录有了一些了解后,分析启动代码的过程就比较方便,其中比较重要的目录就是/board、/cpu、/drivers和/include目录,如果想实现u-boot在一个平台上的移植,就要对这些目录进行深入的分析。
💦U-Boot生成镜像文件
U-Boot的源码是通过gcc和Makefile组织编译的。顶层目录下的Makefile首先可以设置开发板的定义,然后递归地调用各级子目录下的Makefile,最后把编译过的程序链接成U-Boot映像。
顶层目录下的 Makefile
它负责u-boot整体配置编译。每一种开发板在Makefile都需要有板子配置的定义。
配置u-boot
编译: make
启动时,首先检查系统配置,上述结果中可以知道,该系统的CPU为S5PV210,RAM配置为1GB,flash配置为1024M。然后开始进入命令行界面(以提示符“SMDK210 #表示”),在该命令行界面中用户可以输入操作命令。
💦主要功能与作用
硬件设备初始化
主要是初始化CPU片内外设硬件控制器。
通常的硬件初始化工作:
关闭处理器内部指令/数据cache等
关闭中断
关闭看门狗
配置PLL
配置内存
初始化各工作模式的堆栈
配置中断
拷贝RW段,初始化ZI段
硬件设备初始化
一般SDRAM控制器只在bootloader中初始化,进入kernel后不再初始化。
提供一个控制台及一个指令集在操作系统运行前操控硬件设备
操作系统代码搬运 :
Bootloader,为引导加载程序,是嵌入式系统加电后运行的第一段代码,相当于PC机的BIOS。
Bootloader的位置:通常固化在硬件上的某个固态存储设备上,加电后自启动。
💦U-boot启动流程
运行两个阶段
U-Boot代码一般分为stage1和stage2两大部分。stage1依赖于cpu体系结构如设备初始化代码,常用汇编语言编写以达到短小精悍,提高系统运行效率的目的。它主要包括cpu/arm目录下的start.s。stage2一般采用C语言编写实现复杂功能,这样代码则具有更好的可读性和可移植性,主要包括lib lib_arm/board.c文件和common/main.c文件中main_loop函数等。
U-Boot启动代码流程图
汇编代码入口cpu/armXX/start.S
- 单板上电或者复位的时候 CPU从固定地址读指令,而硬件设计时此地址分配给装有bootloader.bin的ROM或者FLASH。
- 汇编代码段:将cpu设置为svc(管理模式)模式;屏蔽所有irq ;初始化cache和MMU;初始化SDRAM控制器
-初始化堆栈,把bootloader自身代码从FLASH拷贝到SDRAM,并跳到SDRAM去运行。
lib_arm/board.c
- 进入SDRAM之后开始运行C语言相关的代码,其入口点是函数start_armboot (void)
- 进一步初始化:
init_sequence[]数组保存着基本的初始化函数指针
init_fnc_t init_sequence[] = {
cpu_init, / 基本的处理器相关配置 – cpu/arm920t/cpu.c /
board_init, / 基本的板级相关配置 – board/smdk2410/smdk2410.c / borad/smdkv210
interrupt_init, / 初始化例外处理 – cpu/arm920t/s3c24x0/interrupt.c /
env_init, / 初始化环境变量 – common/cmd_flash.c /
init_baudrate, / 初始化波特率设置 – lib_arm/board.c /
serial_init, / 串口通讯设置 – cpu/arm920t/s3c24x0/serial.c /
console_init_f, / 控制台初始化阶段1 – common/console.c / display_banner, / 打印u-boot信息 – lib_arm/board.c /
dram_init, / 配置可用的RAM – board/smdk2410/smdk2410.c /
display_dram_config, / 显示RAM的配置大小 – lib_arm/board.c */
NULL,
};
- 读取串口,如没有打断则启动kernel,否则进入循环:
for (;😉 {
main_loop ();
}
主循环
启动kernel(MDU)
- 从flash读取MSP firmware并load到sdram的低16M
-从flash读取kernel image并拷贝到sdram高端地址相应的地方
- 把kernel command line保存到SDRAM 16M之后0x100
- ARM0跳到MSP firmware入口点运行初始化,并reset ARM1
- ARM1 reset后解压kernel image并开始运行kernel