第一章 嵌入式Linux的组成
嵌入式Linxu系统,就相当于一套完整的PC软件系统。
u-boot用来加载Linxu内核到内存,包括内核初始化所需的脚本和服务,内核运行所需的库。
内核运行第一个挂载的系统就是rootfs(根文件系统),根文件系统系统了根目录“/”。
第二章 IMX6ULL Pro开发板基本操作
2.1 基本介绍
MX6U芯片,ARM Cortex A7内核。
此处仅供学习,不针对某芯片,基本操作章节仅提供类似参考。
2.1.1 开发环境
Ubuntu开发环境,可使用搭建好开发环境的Docker系统镜像。
2.1.2 核心软件
交叉编译工具链,arrch64-linux-gnu-gcc,由 Linaro 公司基于 GCC 推出的的 ARM 交叉编译工具。
引导程序,uboot
linux内核,rk356x-linux,不同板子有不同的适应内核,联系厂家。
2.1.3 文件系统
Busybox,集成了常用linux命令和工具的工具箱。
Buildroot,嵌入式系统构建工具,可以根据配置文件自动构建交叉编译工具链、内核镜像、根文件系统以及各种用户空间软件包。
Yocto,一个帮助用户定制Linux系统的开源项目。
像交叉编译工具链`arm-buildroot-linux-gnueabihf-gcc`就是 Buildroot 提供的交叉编译工具链中的一个组件,用于在主机系统上编译针对 ARM 架构的软件。
2.1.4 文件挂载到目录树
使用MobaXterm软件可以通过串口打开板子的内核。进行调试、发送、接收板子的数据、查看板子的文件系统。
开发板可以通过NFS将目录挂载到开发环境的文件系统上。
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/nfs /mnt
mount 是挂载命令。
-t nfs 指定要挂载的文件系统类型为 nfs。
-o 用于传递挂载选项。
nolock 表示禁用文件锁定机制。
vers=3 表示使用 NFS 协议的版本 3。
ip:/home/nfs 是 NFS 服务器的 IP 地址和共享目录的路径。
/mnt 是本地目录。
挂载成功以后,通过板子访问/mnt和通过ubuntu访问/home/nfs其实访问的就是一个目录。
2.1.5 文件传递
FileZilla 软件、TFTP 软件都可以在开发板、Ubuntu、Windos三者间互传文件。
2.2 开发环境配置
2.2.1 下载BSP
不同开发板有不同的板级支持包(BSP)。
BSP 包含了针对该硬件平台的驱动程序、引导加载程序、操作系统内核配置、文件系统等必要的软件组件,以便支持该硬件平台上的软件运行。
repo工具可用于管理多个git仓库。如果BSP需要使用git下载,则需要先配置好repo工具。
其实就是把板子支持的Linux内核下载下来了。
2.2.2 配置交叉编译工具链
交叉编译工具链用来在ubuntu主机上编译应用程序,编译后的文件可在arm等平台运行。
修改用户目录下的 shell 配置文件,`.bashrc`。配置环境变量。
设置交叉编译工具主要是设置 ARCH,CROSS_COMPILE,PATH 三个环境变量。交叉编译工具的目标平台的架构,可执行文件路径,交叉编译工具的前缀。
//环境变量 ARCH ,用来指定目标平台的架构
export ARCH=arm //环境变量 CROSS_COMPILE ,用来指定交叉编译工具的前缀
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-//将交叉编译工具的路径添加到环境变量PATH目录中,shell中使用可执行文件名,会在PATH中找
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
`.bashrc` 文件是用于配置 shell 的初始化文件,位于用户的主目录下(`~/.bashrc`)。
当用户登录时或启动一个新的交互式 Bash shell 时,`.bashrc` 文件会被执行,用于设置环境变量、定义别名、配置 shell 行为等。
如果只在命令行运行 export 来设置环境变量,则只对当前终端有效。
测试环境变量是否配置成功,可使用 echo $变量名 来查看shell打印的内容。也可以使用工具链名 -v 来查看工具链版本号。
第三章 开发板第一个APP实验
.c文件写好,需要编译后在ubuntu上运行,或者交叉编译后到ARM开发板上运行。
gcc 编译后机器指令是x86的,只能在PC上运行。
使用配置好的交叉编译工具arm-buildroot-linux-gnueabihf-gcc编译.c文件,生成可执行文件,就可以把可执行文件放到nfs挂载的文件夹下,然后板子用shell命令直接执行。
第四章 开发板第一个驱动实验
4.1 前提
编译驱动程序之前要先编译内核。 因为驱动程序要用到内核文件。比如驱动程序中包含的头文件,#include <asm/io.h>,其中的asm是一个符号链接,指向特定架构的汇编语言头文件目录,需要在编译内核时生成。
编译驱动时用的内核和开发板上的内核要一致。开发板上运行的内核是出厂时烧录的,编译驱动时的内核和驱动运行时的内核不一致会导致问题,因此要把自己编译出来的内核放到板子上去,代替原来的内核。
板子上的内核更换后,其他驱动也要换。因此在编译第一个驱动程序之前,要先编译内核、模块,并且放到板子上去。
4.2 编译内核
不同开发板对应不同的厂商配置文件,位于arch/arm/configs目录。
make mrproper //清理内核源代码目录,删除生成的配置文件、编译生成的文件等临时文件
make 100ask_imx6ull_defconfig//是一个用于生成特定于 100ask 公司的 i.MX6ULL 处理器的默认配置的命令,是内核编译中的一部分。
make zImage -j4//命令会编译 Linux 内核并生成 zImage 格式的内核镜像文件,同时使用 4 个并行任务来加速编译过程。
make dtbs//命令的作用是编译设备树源文件(通常是以 `.dts` 或 `.dtsi` 后缀结尾的文件),生成设备树二进制文件(`.dtb` 文件),以便在内核启动时使用。
编译完成后,在 arhc/arm/boot 目录下生成 zImage 内核镜像文件,在 arhc/arm/boot/dts 目录下生成设备树的二进制文件 100ask_imx6ull-14x14.dtb。
编译得到的内核镜像和设备树文件拷贝到挂载文件夹nfs_rootfs下备用。
4.3 编译安装内核模块
4.3.1 编译内核模块
//在内核源码文件夹下执行
//编译所有内核模块的源代码,生成.ko文件保存在内核lib文件夹下
make modules
4.3.2 安装内核模块到ubuntu目录中备用
//在内核源码文件夹下执行
//make用于编译模块 modules_install安装模块到指定目录
make ARCH=arm ARCH=ARM INSTALL_MOD_PATH=/home/nfs_rootfs modules_install
tree命令可以查看目录结构,需要apt install安装。
4.4 安装内核和模块到开发板上
将内核镜像zImage文件、设备树dtb文件,和模块文件lib/module复制到挂载的文件夹下,就等于复制到了开发板上。最后重启开发板,就会自动使用新的zImage、dtb、驱动模块了。
4.5 编译led驱动
编译驱动要使用makefile,来帮助执行shell指令。
make 命令会直接执行目录下的Makefile文件。
编译完成后生成led.ko。
4.6 在开发板安装驱动模块
//echo > 指令可以将字符串写入文件,用来关闭cpu状态灯,之后才能对使用驱动对其操作。(有些板子可能状态等已经关了)。
echo none > /sys/class/leds/cpu/trigger
在开发板串口终端上执行 'insmod 模块名' 即可安装相应的驱动模块。
//安装模块
insmod 100ask_led.ko
安装完成后使用 lsmod 查看是否安装成功。
如果没有更新板子上的内核,会出现 Invaild paramerters错误。
也可以使用 insmod -f 强行安装,会提示说内核被污染,但不影响使用。
4.7 执行测试程序
驱动模块安装成功后,可以使用测试程序 ledtest 来控制 led 灯的状态。
//执行ledtest文件,控制设备/dev/100ask_led0,关闭off
[root@100ask:~]# ./ledtest /dev/100ask_led0 off
第五章 构建Bootloader、内核、文件系统
5.1 解压编译bootloader
5.1.1 Bootloader介绍
Bootloader是在操作系统运行之前运行的一段代码,用于启动操作系统,完成操作系统必要初始化设置。
U-Boot 是一个开源的主引导加载程序,用于引导设备操作系统内核,并含有多种命令以便调试系统。它适用于多种计算机体系结构,包括 ARM,RISC-V 和 x86 等。
5.1.2 编译uboot镜像
不同的开发板对应不同的配置文件,配置文件位于 u-boot 源码的"configs/"目录。
//在uboot源码文件下
//恢复源代码目录到一个干净状态,以便重新开始编译过程。
make distclean
//生成一个配置文件,其中包含了适用于该开发板的默认配置选项,用于编译 Linux 内核
make mx6ull_14x14_evk_defconfig
//执行Makefile,生成u-boot-dtb.imx
make
//将mmcblk1boot0设备的只读属性设置为可写
echo 0 > /sys/block/mmcblk1boot0/force_ro//使用dd工具将u-boot-dtb.imx文件的内容写入到指定扇区
//`bs=512` 指定了每次读写的块大小为 512 字节,
//`seek=2` 表示从第三个扇区(512字节 * 2)开始写入数据。
dd if=u-boot-dtb.imx of=/dev/mmcblk1boot0 bs=512 seek=2
5.2 编译Linux Kernel模块
Linux内核是一种开源的类Unix操作系统宏内核。Android操作系统底层也是Linux。Ubuntu属于Linux的发行版。
使用内核及内核模块前需要将其编译,安装到ubuntu开发板。详细步骤在4.2/4.3/4.4章节。
5.3 Buildroot用法
5.3.1 Buildroot简介
制作根文件系统有很多方法:
1、使用Busybox手工制作
Busybox本身包含了很多linux命令。但是要编译其他程序的话需要手工下载、编译,需要依赖库,也需要手工下载、编译这些依赖库。
极简的文件系统可以使用Busybox手工制作。
2、使用Buildroot自动制作
Buildroot是一个自动化程度很高的系统,可以看作一组Makefile和补丁,可以在里面配置、编译内核、uboot、rootfs。在编译某些APP时,它会自动去下载源码、依赖库,自动编译程序。
Buildroot的语法类似Makefile。
Buildroot 运行于 Linux 平台,可以使用交叉编译工具为多个目标板构建嵌入式 Linux 平台。
Buildroot 可以自动构建所需的交叉编译工具链,创建根文件系统,编译 Linux 内核映像,并生成引导加载程序用于目标嵌入式系统,或者它可以执行这些步骤的任何独立组合。
3、使用Yocto
NXP、ST等公司的官方开发包使用的是Yocto,但是Yocto语法复杂,而且工程较大。不适合初学者。
什么是init系统服务?
init系统服务是守护进程,其进程号为 1。用来产生其它所有进程。Linux 系统在引导时加载 Linux 内核后,便由 Linux 内核加载 init 程序,由 init 程序完成余下的引导过程,比如加载运行级别,加载服务,引导 Shell/图形化界面等等。
Linux内核是linux系统的核心组件,负责管理硬件并提供进程管理、文件系统、设备驱动等功能。
什么是systemv守护进程?
System V(SysV)是一种 Unix 操作系统的版本。在 systemv 中,在内核加载后运行的第 1 个程序被称为 init系统服务(守护进程)。Init 做一些事情,其中之一就是加载一系列脚本来启动各种系统服务,例如网络,ssh 守护程序等。System V 中的运行级别描述了某些状态,例如:
运行级别 0:暂停
运行级别 1:单用户模式
运行级别 6:重新启动
SystemV有一个问题就是需要为服务的启动设置严格的优先级顺序。
比如想在SystemV启动时运行网络文件系统(NFS)客户端,由于网络正常工作前启动NFS没有任何意义,因此必须等待网络正常工作才能启动SystemV,SystemV init的这种做法为服务的启动设置了严格的优先级顺序。每个服务都有一个优先级编号,init 会按优先级顺序启动服务。
什么是Systemd守护进程?
以d作为系统守护进程的后缀是Unix的惯例。
Systemd 是 Linux 操作系统的一套中央化系统及设置管理程序(init),包括有守护进程、程序库以及应用软件。其开发目标是实现系统初始化时服务的并行启动,同时达到降低 Shell 的系统开销的效果,最终代替现在常用的 System V 与 BSD 风格的 init 程序。目前绝大多数的 Linux
发行版都已采用 systemd 代替原来的 System V。
将 service(服务)、target(运行模式,类似于运行级别)、mount、timer、snapshot、path、socket、swap 等称为 Unit。比如,一个 auditd 服务(就是 auditd.service)就是一个Unit,一个 multi-user.target 运行模式也是一个 Unit,其中不同的服务通过 systemctl 来进行统一管理,例如重启一个 sshd 服务,需要执行 systemctl restart sshd 命令,同样的如果添加一个启动程序需要自己定义一个 service 服务才可以。
5.4 开发板使用 NFS 根文件系统
根文件系统就是类似Windos的C盘。里面存放有必须的APP、库文件、配置文件。
Buildroot 编译完成之后生成的 rootfs.tar.bz2,可以解压之后放到 NFS 服务器(Ubuntu服务器)上作为 NFS 文件系统供开发板使用。
使用 NFS 根文件系统时,我们一般还会在 u-boot 使用 tftpboot 命令从 Ubuntu 或Windows 中下载内核镜像文件 zImage 和设备树文件 dtb。这时,Ubuntu 上既要配置 NFS 服务,也要配置 TFTP 服务。
使用 NFS 根文件系统时,涉及 xImage、设备树、根文件系统rootfs。在 Uboot 中设置启动参数使用ubuntu的某个目录作为根文件系统(记得rootfs放里面)。
开发板开机后,mobaxterm工具显示串口消息,其实是进入了Uboot界面。
设置好 主机和开发版的IP地址,设置好 nfs文件系统所在目录,使用run netroot指令就可以运行文件系统。
可以用工具烧写或更新部分系统。