编辑整理 by Staok。
本文部分内容摘自 “100ask imx6ull” 开发板的配套资料(如 百问网的《嵌入式Linux应用开发完全手册》,在 百问网 imx6ull pro 开发板 页面 中的《2.1 100ASK_IMX6ULL_PRO:开发板资料》或《2.2 全系列Linux教程:在线视频与配套资料》里面可以下载到),还有参考 菜鸟教程、C语言中文网、红联的等等等等,比较广泛,侵删。进行了精髓提取,方便日后查阅。过于基础的内容不会在此提及。如有错误恭谢指出!
注:在 Github 上的原版文章日后可能会更新,在其它位置发的不会跟进。文章的 Gitee 仓库地址,Gitee 访问更流畅。
注意本文是基于 IMX6ULL 这个 SoC,即 A7 内核(ARM 各个内核介绍 【主线剧情 番外01】ARM 系列快速鸟瞰 - 欢迎来到 Staok - 瞰百易 (gitee.io)),本文所配置的交叉编译器也是对应的,即 ARMv7 32位,若是 i.mx8mm 这种基于 A53 内核的,就是对应 ARMv8 64位 的交叉编译器,要注意,不熟悉的仔细看一下~祝好
任何文章都有时效性,学习 linux 这种复杂系统,保持脑袋清醒和逻辑链清晰,耐下心来,共勉!
更全面的 Linux 应用 和 驱动编程,还见仓库 Github 仓库 或 Gitee 仓库 中,见里面相关的文件夹,东西真的很丰富~
首先换源,参考前面 “换源 和 添加系统变量” 一节。
配置 100ask Ubuntu 主机 的环境,执行:
wget --no-check-certificate -O Configuring_ubuntu.sh https://weidongshan.coding.net/p/DevelopmentEnvConf/d/DevelopmentEnvConf/git/raw/master/Configuring_ubuntu.sh && sudo chmod +x Configuring_ubuntu.sh && sudo ./Configuring_ubuntu.sh
这个会配置/安装一些基本应用如 NFS/TFTP 等,还建立 /home/book 目录,book 用户 等,具体看其 shell 程序。
百问网的 imx6ull pro 开发板的 SDK包(包括 Linux、uboot、buildroot 等源码和工具链,这个需要 windows 电脑 和 虚拟机 ubuntu 各存一份,前者用来阅读,后者用来编译)两个下载途径:
本地拷贝法:百问网 imx6ull pro 开发板 页面,找到 100ask_imx6ull_pro_2020.02.29_v2.0(这个很大,网盘下载),里面有固件、SDK包、原理图(底板+核心板)、应用例程、工具软件等等。其中 SDK包(包括 Linux、uboot、buildroot 等源码和工具链)在 07_Bsp_sdk (系统源码,包含uboot kernel rootfs 工具链 测试代码等)) 里面,自行拷贝到虚拟机 ubuntu 里面并解压。但是这是本地拷贝的不是最新的,最新的可以 git 下载(注意很大),看下面 “在线下载&更新法”。
在线下载&更新法:参考 百问网的《嵌入式Linux应用开发完全手册》里面 第二篇 的 《8.2 使用repo获取内核及工具链等》 里面的 《8.2.2 在线下载》。
配置 Git 邮箱和用户名:git config --global user.email "[email protected]"
、git config --global user.name "100ask"
。
执行四条命令:
git clone https://e.coding.net/codebug8/repo.git mkdir -p 100ask_imx6ull-sdk && cd 100ask_imx6ull-sdk ../repo/repo init -u https://gitee.com/weidongshan/manifests.git -b linux-sdk -m imx6ull/100ask_imx6ull_linux4.9.88_release.xml --no-repo-verify ../repo/repo sync -j4
今后可以直接在 100ask_imx6ull-sdk
目录下执行 ../repo/repo sync -c
进行同步更新最新代码!
推荐在 windows 端 使用 Source Insight 来阅读 Linux 内核源码,详见 百问网的《嵌入式Linux应用开发完全手册》里面 第二篇 的《8.4 使用Source Insight阅读Linux内核源码》。
这里提供三个获取方式。
这里是 百问网的 imx6ull pro 开发板 的 SDK 中的工具链,在 /.../100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
里面,使用 Vim 工具编辑 ~/.bashrc
文件,在最后添加:
export ARCH=arm export CROSS_COMPILE=arm-buildroot-linux-gnueabihf- export PATH=$PATH:/.../100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
并在终端键入 source ~/.bashrc
使其生效。
然后在终端测试一下 arm-buildroot-linux-gnueabihf-gcc -v
。
ARM GUN-A 官方编译器下载页面: GNU Toolchain | GNU-A Downloads – Arm Developer。下面几个连接是对各个编译器命名的说明,必看。
arm-linux-gnueabihf、aarch64-linux-gnu等ARM交叉编译GCC的区别_Namcodream521的博客-CSDN博客。
转:ARM交叉编译工具链分类说明 arm-linux-gnueabi和arm-linux-gnueabihf 的区别_Beyoungbehappy的博客-CSDN博客。
arm交叉编译器gnueabi、none-eabi、arm-eabi、gnueabihf等的区别 - 涛少& - 博客园 (cnblogs.com)。
带有 “bare-metal” 的为不支持操作系统的。
总的来说:
经过 Codesourcery 公司基于GCC优化,带有 none 标识的编译器。
ARM GUN-A 官方编译器下载页面 Downloads | GNU-A Downloads – Arm Developer。要下载的编译器要运行在 x86_x64 机器的虚拟机里面的ubuntu 18.04 里面,因此找到 x86_64 Linux hosted cross toolchains 下面的各个编译器版本。
AArch32 target with hard float (arm-none-linux-gnueabihf) —— 可用于交叉编译ARMv7 32位 目标系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
AArch64 GNU/Linux target (aarch64-none-linux-gnu) —— 可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
由 Linaro 公司基于GCC推出。
Linaro Releases 页面 Linaro Releases。
arm-linux-gnueabihf-gcc:可用于交叉编译ARMv7 32位 目标系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
aarch64-linux-gnu-gcc:可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
在 x86_64 Linux hosted cross compilers
下面找到 AArch32 target with hard float (arm-none-linux-gnueabihf)
(i.mx6ull 为 A7 内核,即为 32 位的 armv7 指令集),并下载;(AArch64 Linux hosted cross compilers
下的编译器可以运行在 64位的 嵌入式板子 SoC 的 Linux 上);
使用 tar xvf
命令解压。
最后,添加环境变量。使用 Vim 工具编辑 ~/.bashrc
文件,在最后添加:
export ARCH=arm export CROSS_COMPILE=arm-none-linux-gnueabihf- # 添加名为 CROSS_COMPILE、ARCH 环境变量,写 makefile 用 make 工具编译的时候会用到 export PATH=$PATH:/<交叉编译器工具链的目录>/bin # 交叉编译器工具链的 路径,可以直接在 shell 中 打编译器的名字来 执行编译器 bin 应用
并在终端键入 source ~/.bashrc
使其生效。
然后在终端测试一下 arm-none-linux-gnueabihf-gcc -v
。
使用交叉编译工具链编译程序产生 固件/应用 后,通过 “PC 与 嵌入式板 传输文件的方式汇总” 一节提供的方法,传给 嵌入式 linux 开发板,再执行,也许需要添加执行的权限:chmod +x <应用>
。
p.s 这里作者没有试验,只是把说明放在这里。
正点原子的文章【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.1
在 4.3.1.2 小节
里说到个别版本能编译通过但是不能运行,多换换版本试试。
到 Linaro Releases 下载适合的编译器,使用方法与上面类似。Linaro 的编译器对应的名字为 arm-linux-gnueabihf-
。
略,略略略~。(在 百问网 imx6ull pro 开发板 页面 中的《2.2 全系列Linux教程:在线视频与配套资料》里面的 \01_all_series_quickstart\04_嵌入式Linux应用开发基础知识\source
里面)
注意:
驱动程序用到 Linux 内核的 API,编译驱动程序之前要先编译内核。
编译驱动时用的内核和嵌入式板子上运行的内核,要一致(不一致的话,不能正常安装 .ko 模块,强装会有意想不到的问题)。
板子使用新编译出来的内核时,板子上原来的其他驱动也要更换为新编译出来的。
不同的开发板对应不同的配置文件,配置文件位于内核源码 arch/arm/configs/
目录。
在 Linux 源码目录里执行:
make mrproper make xxx_imx6ull_defconfig make zImage -j4 make dtbs
释义:
make mrproper
命令会删除所有的编译生成文件、内核配置文件(.config文件)和各种备份文件,所以几乎只在第一次执行内核编译前才用这条命令。make clean
命令则是用于删除大多数的编译生成文件,但是会保留内核的配置文件 .config,还有足够的编译支持来建立扩展模块。所以你若只想删除前一次编译过程的残留数据,只需执行 make clean 命令。总而言之,make mrproper 删除的范围比 make clean 大,实际上,make mrproper 在具体执行时第一步就是调用 make clean。
得到 内核文件 和 设备树文件 这两个文件:
arch/arm/boot/zImage arch/arm/boot/dts/100ask_imx6ull-14x14.dtb
在 Linux 源码目录里执行:
make ARCH=arm CROSS_COMPILE=<选择一个编译器,比如 Linaro 的 arm-linux-gnueabihf-> modules sudo make ARCH=arm INSTALL_MOD_PATH=/home/book/nfs_rootfs modules_install # 编译出的模块 都装存到 /home/book/nfs_rootfs 下,自行更换
释义:
第一条,如果设置好了 ARCH 和 CROSS_COMPILE 环境变量,直接键入 make modules
也可。
第二条命令是把模块安装到 /home/book/nfs_rootfs
目录下备用 , 会得到 /home/book/nfs_rootfs/lib/modules
目录。
有很多种方式传输文件,详见 "PC 与 嵌入式板 传输文件的方式汇总" 章节。将 zImage 、100ask_imx6ull-14x14.dtb 和 内核模块的 lib 目录 这三者 分别放到嵌入式板子的 /boot 、 /boot 和 /lib 目录,比如使用方便的 nfs 文件系统;然后存储 sync
,重启 reboot
。
按照驱动程序的编写规则,写好驱动程序(hello_drv.c)和 对其进行编译的 Makefile 文件,以及 相应的 应用程序/测试程序(hello_drv_test.c)。
举例 Makefile 文件(这里面也同时将 测试程序 给编译了):
# 修改为 Linux 内核所在目录 KERN_DIR = /home/book/100ask_roc-rk3399-pc/linux-4.4 all: make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c # 这里就用到 环境变量 CROSS_COMPILE 了 clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order rm -f hello_drv_test obj-m += hello_drv.o
确保三个环境变量 ARCH、CROSS_COMPILE 和 PATH(交叉编译器的 /bin 目录)都以就绪。
执行 make
或 make all
。产生 驱动程序的内核模块(hello_drv.ko)和 测试程序 ARM 端的二进制可执行文件,共两个文件,转移其到 嵌入式目标板子上。
在嵌入式 Linux 开发板上 安装驱动程序模块 insmod hello_drv.ko
。
在 lsmod
命令下可以看到 hello_drv
模块;执行 cat /proc/devices
可以看到 对应的设备及其主设备号;执行 ls -l /dev/<设备名称>
可以看到此设备的主、此设备号等更多信息。
执行测试程序进行验证。
make bzImage # 编译生成压缩的内核二进制文件 make vmlinux # 编译生成二进制内核文件 make modules # 编译生成内核模块 make modules_install # 安装模块 make bzdisk|fdimage|isoimage # 编译生成启动软盘镜像或者光盘镜像 make install # 安装内核文件 make all # 相当于vmlinux+modules+bzImage make rpm # 构建内核rpm包 make foo/bar/foobar.ko # 编译单个驱动 make header_install # 安装内核头文件 make M=some/sub/dir # 编译指定目录 make O=/path/to/some/dir # 指定生成的文件放到该目录 make kernelversion # 输出内核版本信息 make kernelrelease # 输出内核发行标识 make rpm-pkg|deb-pkg|tar-pkg|targz-pkg|tarbz2-pkg # 构建这种格式的内核包 make clean # 清除生成文件(保留.config和部分模块文件) make mrproper # 清除全部文件(包括.config和备份文件) make distclean # 在make mrproper上还清除编辑器其他的备份文件
芯片厂家(大概)应该都会提供完整的 U-boot、 Linux 内核、芯片上硬件资源的驱动程序。
看韦东山的 imx6ull 板子的裸机开发源码,可以得知,启动文件 .s 文件需要看懂,都大同小异,然后官网会提供所有寄存器的 .h 文件及其结构体,然后每个外设似乎还会提供初始化、配置的代码(因为韦的源码里面,外设底层配置代码为英文注释的,99%的概率是官方提供的),这样就好了嘛,外设的底层驱动可以都扒官方例程。
这里只简约说明编译步骤,并非详细使用说明(以后的系列文章可能会有)。
以下工作进行前,先配置好环境变量和开发链工具等工作,详见 "准备交叉编译工具链" 章节。
1、编译 u-boot,配置文件位于 u-boot 源码的 configs/ 目录,生成 u-boot 启动镜像 u-boot-dtb.imx。在 Uboot 目录下执行:
make distclean make mx6ull_14x14_evk_defconfig make
2、编译内核,配置文件位于内核源码 arch/arm/configs/ 目录,生成 arch/arm/boot/zImage 内核文件 和 arch/arm/boot/dts/xxx_imx6ull-14x14.dtb 设备树文件。在 Linux 内核目录下执行:
Linux-4.9.88$ make mrproper Linux-4.9.88$ make xxx_imx6ull_defconfig Linux-4.9.88$ make zImage -j4 Linux-4.9.88$ make dtbs
3、编译内核模块,并把模块文件导入 /home/book/nfs_rootfs/lib/modules 目录。在 Linux 内核目录下执行:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules sudo make ARCH=arm INSTALL_MOD_PATH=/home/book/nfs_rootfs modules_install
Linux 平台上有许多开源的嵌入式 linux 系统构建框架,这些框架极大的方便了开发者进行嵌入式系统的定制化构建,目前比较常见的有 OpenWrt, Buildroot, Yocto 等等。其中 Buildroot 功能强大,使用简单,而且采用了类似于 linux kernel 的配置和编译框架。
制作根文件系统方法比较:
Busybox。Busybox 本身包含了很了 Linux 命令,但是要编译其他程序的话需要手工下载、编译,如果它需要某些依赖库,你还需要手工下载、编译这些依赖库。如果想做一个极简的文件系统,可以使用 Busybox 手工制作。
Buildroot。它是一个自动化程序很高的系统,可以在里面配置、编译内核,配置编译 u-boot、配置编译根文件系统。在编译某些APP时,它会自动去下载源码、下载它的依赖库,自动编译这些程序。Buildroot 的语法跟一般的 Makefile 语法类似,很容易掌握。
Yocto。NXP、 ST 等公司的官方开发包是使用 Yocto,Yocto 语法复杂,容量大(10GB 以上),编译时间长。
Buildroot 是一组 Makefile 和补丁,可简化并自动化地为嵌入式系统构建完整的、可启动的 Linux 环境(包括 bootloader、 Linux 内核、包含各种 APP 的文件系统)。 Buildroot 运行于 Linux 平台,可以使用交叉编译工具为多个目标板构建嵌入式 Linux 平台。 Buildroot 可以自动构建所需的交叉编译工具链,创建根文件系统,编译 Linux 内核映像,并生成引导加载程序用于目标嵌入式系统,或者它可以执行这些步骤的任何独立组合。例如,可以单独使用已安装的交叉编译工具链,而 Buildroot 仅创建根文件系统。
学习更多关于 Buildroot 知识请参考这里。
扩展学习:
buildroot 下进入 menuconfig 包选择配置配置界面 make menuconfig
。
buildroot 下单独编译 u-boot make uboot-rebuild
。
buildroot 下进入内核 make menuconfig 配置选项界面 make linux-menuconfig
。
buildroot 下单独编译某个软件包 make
。
buildroot 下进入 busybox 配置界面 make busybox-menuconfig
。
buildroot 下生成系统 sdk,最后生成的目录在 output/images/ 目录下 make sdk
。
构建根文件系统:
在 Buildroot 目录下执行:
make clean make xxx_imx6ull_defconfig make all
漫长长长(2~6个小时,视电脑性能)的等待后编译完成。
可以配置多个不同的配置文件 xxx_imx6ull_defconfig,比如有的带 qt5 ,有的用于构建最精简的文件系统,有的用于另一块板子等待。
编译成功后文件输出路径为 output/images:
buildroot 20xx.xx ├── output ├── images ├── xxx_imx6ull-14x14.dtb <--设备树文件 ├── rootfs.ext2 <--ext2 格式根文件系统 ├── rootfs.ext4 -> rootfs.ext2 <--ext2 格式根文件系统 ├── rootfs.tar ├── rootfs.tar.bz2 <--打包并压缩的根文件系统,用于 NFSROOT 启动 ├── sdcard.img <--完整的 SD 卡系统镜像 ├── u-boot-dtb.imx <--u-boot 镜像 └── zImage <--内核镜像
对应的文件更新到嵌入式板子的对应位置,或者使用 sdcard.img 或者 emmc.img 完整系统映像文件烧入 sd卡 或 emmc。