编辑整理 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 仓库 中,见里面相关的文件夹,东西真的很丰富~
Linux 驱动和应用的体验
Ubuntu 主机 的配置工作
-
首先换源,参考前面 “换源 和 添加系统变量” 一节。
-
配置 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 "user@100ask.com"
、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内核源码》。
获取交叉编译工具链
这里提供三个获取方式。
用开发板厂家提供的 SDK 里的工具链
这里是 百问网的 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 官网下载 合适的工具链
-
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 <应用>
。
使用 Linaro GCC 编译器
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/<设备名称>
可以看到此设备的主、此设备号等更多信息。 -
执行测试程序进行验证。
linux内核编译操作
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
使用 Buildroot 构建系统简约步骤
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 <pkg>-rebuild
。 -
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:文章来源:https://www.toymoban.com/news/detail-759373.html
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。文章来源地址https://www.toymoban.com/news/detail-759373.html
到了这里,关于ARM & Linux 基础学习 / 配置交叉编译工具链 / 编译 Linux 应用和驱动 / 编译内核的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!