I.MX6ULL 开发板从零移植U-BOOT、Linux内核和根文件系统的历程和心得
参考文档
【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf
【适合有一定基础参考】嵌入式Linux应用开发完全手册_韦东山全系列视频文档-IMX6ULL开发板(从零移植篇-预览版)-V0.1.pdf
嵌入式Linux应用开发完全手册V5.3_IMX6ULL_Pro开发板.pdf
目录
一、Linux系统组成

Linux系统启动流程:
1、系统上电后,bootloader(如U-Boot)首先运行,初始化硬件并加载Linux内核。
2、Linux内核接管控制权,初始化驱动程序,识别硬件,并启动init进程。
3、init进程挂载根文件系统,并启动系统服务和用户应用程序。
4、系统完全启动,应用程序开始运行。
1.1 Bootloader(引导加载程序)
作用:Bootloader是系统启动的第一个软件程序。它负责初始化硬件设备、建立内存空间映射,以便为加载操作系统内核准备正确的环境。
常用bootloader:U-Boot(Universal Bootloader)是一种开源的、广泛使用的bootloader,特别常见于嵌入式系统中。它支持多种架构,如ARM、PowerPC等。
启动过程:当电源打开或系统复位时,处理器会执行固定在某个地址的代码(通常是bootloader)。Bootloader会加载操作系统内核到内存中,然后跳转到内核的入口点开始执行。
加载内核本身:Bootloader会从存储设备(如Flash、SD卡)中读取Linux内核镜像,并将其解压或直接加载到内存中。
1.2 Linux内核
作用:Linux内核是操作系统的核心,负责管理系统的硬件和软件资源。
驱动程序:内核包含各种硬件驱动程序,这些驱动程序允许内核与硬件设备通信。在启动过程中,内核会初始化这些驱动程序,检测和配置硬件设备。
识别:内核会识别系统上的硬件设备,并加载相应的驱动程序。这个过程包括设备树(Device Tree)或AC表(ACPI)的使用,以描述硬件配置。
系统必备APP:内核启动后,会启动第一个用户空间进程(通常是init进程,如systemd或SysVinit)。这个进程是系统必备的应用程序,它负责启动其他系统服务和应用程序。
其中重点:设备树
设备树定义:
设备树采用一种声明式的、树状结构的数据格式(.dts / .dtsi 文本文件)来描述硬件,而不是用编程语言(如 C)来写代码。是描述而不是编码。它的核心目的是将硬件的详细信息从 Linux 内核代码中分离出来,使得同一个内核二进制文件能够支持不同的硬件平台。
引入设备树的优点:
1、把硬件信息以独立文件形式告诉内核,而不是硬编码在驱动里。
2、硬件更换时不用修改内核源码,只要改设备树。
3、 驱动代码更通用,减少与具体硬件平台的耦合。
设备树关键组成部分:
.dts + .dtsi → dtc 编译器 → .dtb
1、设备树源文件 (.dts / .dtsi): 人类可读的文本文件,描述特定硬件平台的设备树。
.dts: 描述特定开发板或机器的完整设备树源文件。
.dtsi: 类似 C 语言中的头文件,包含可以被多个 .dts 文件复用的通用部分(如 SoC 级别的描述)。.dts 文件通过 #include 包含 .dtsi 文件。
2、设备树编译器 (dtc): 将 .dts / .dtsi 源文件编译成二进制格式.dtb的工具。
3、设备树二进制文件 / Blob (.dtb): dtc 编译 .dts 后生成的二进制文件。这个文件包含了所有硬件描述信息,可以被引导加载程序和内核解析。
4、设备树覆盖 (.dtbo): 用于在运行时动态修改基础设备树的片段,常用于支持插件硬件模块(如 Cape, HAT, Shield)。
5、设备树结构:
设备树本质上是一个分层的节点树结构(类似 JSON 或 XML),每个节点描述一个硬件设备及其属性。
基本格式:
设备树 (内核源码/arch/arm/boot/dts/imx6ull-mmc-npi.dts)

设备树源码分为三部分,介绍如下:
第1-2行: 头文件。设备树是可以像C语言那样使用“#include”引用“.h”后缀的头文件,也可以引用设备树“.dtsi”后缀的头文件。 imx6ull.dtsi由NXP官方提供,是一个imx6ull平台“共用”的设备树文件。
第4-35行: 设备树节点。设备树给我们最直观的感受是它由一些嵌套的大括号“{}”组成, 每一个“{}”都是一个“节点”。“/ {…};”表示“根节点”,每一个设备树只有一个根节点。 如果打开“imx6ull.dtsi”文件可以发现它也有一个根节点,虽然“imx6ull-mmc-npi.dts”引用了“imx6ull.dtsi”文件, 但这并不代表“imx6ull-mmc-npi.dts”设备树有两个根节点,因为不同文件的根节点最终会合并为一个。 在根节点内部的“aliases {…}”、“chosen {…}”、“memory {…}”等字符,都是根节点的子节点。
第37-53行: 设备树节点追加内容。第三部分的子节点比根节点下的子节点多了一个“&”, 这表示该节点在向已经存在的子节点追加数据。这些“已经存在的节点”可能定义在“imx6ull-mmc-npi.dts”文件, 也可能定义在“imx6ull-mmc-npi.dts”文件所包含的设备树文件里。 本代码中的“&cpu0 {…}”、“&clks {…}”、“&fec1 {…}”等等追加的目标节点,就是定义在“imx6ull.dtsi”中。
imx6ull.dtsi头文件 (内核源码/arch/arm/boot/dts/imx6ull.dtsi)

设备树(DT)在linux启动中的位置:
Bootloader (如 U-Boot) 在启动内核时,除了加载内核镜像 (zImage, uImage 等) 外,还会将编译好的.dtb 文件加载到内存中的特定地址。
1.3 根文件系统
作用:根文件系统是操作系统在启动时挂载的第一个文件系统。它包含了操作系统运行所需的文件、库、配置文件和应用程序。
我们的APP:在根文件系统中,存放着用户或开发者编写的应用程序。这些应用程序可能是系统服务或用户程序。
运行:一旦根文件系统被挂载,init进程会根据配置文件(如/etc/inittab或systemd单元文件)启动系统服务和应用程序。
APP:最终,用户应用程序被启动,系统进入可操作状态。
二、烧写系统
烧录韦东山imx6ull pro开发板,详见嵌入式Linux应用开发完全手册V5.3_IMX6ULL_Pro开发板.pdf 第七章
OTG烧写 :
指的是利用开发板上支持 USB On-The-Go 功能的接口,让开发板临时充当一个USB设备(通常是模拟U盘),使得主机电脑能够直接通过USB线连接并像操作U盘一样将系统镜像文件写入开发板存储器的过程。
在韦东山IMX6ULL-pro开发板中,需要将板子设置为USB启动、连接USB OTG线、电源线(不要插TF卡)
三、配置ubuntu与开发板的网络服务
3.1 nfs:
在目录/home/book/下新建目录my_nfs,修改/etc/exports文件,在其中添加语句:

![]()
重启 NFS 服务,使用命令如下:
sudo /etc/init.d/nfs-kernel-server restart
在开发板linux中挂载服务器Ubuntu的目录:
首先开发板能够ping通Ubuntu
然后执行:
mount -t nfs -o nolock 10.23.42.28:/home/book/my_nfs /mnt/nfs
后面可以直接使用nfs服务从网络启动根文件系统,便于开发调试
3.2 tftp:
tftp命令的作用和nfs命令一样,都是用于通过网络下载东西到DRAM中,只是tftp命令使用的TFTP协议,Ubuntu主机作为TFTP服务器。因此需要在Ubuntu上搭建TFTP服务器,需要安装tftp-hpa和tftpd-hpa,命令如下:
sudo apt-get install tftp-hpa tftpd-hpa
sudo apt-get install xinetd
和NFS一样,TFTP也需要一个文件夹来存放文件,在用户目录下新建一个目录,
mkdir /home/book/my_tftpboot
chmod 777 /home/book/my_tftpboot
最后配置tftp,安装完成以后新建文件/etc/xinetd.d/tftp,如果没有/etc/xinetd.d目录的话自行 创建,然后在里面输入如下内容:

完了以后启动tftp服务,命令如下:
sudo service tftpd-hpa start
打开/etc/default/tftpd-hpa文件,将其修改为如下所示内容:

最后输入如下命令, 重启tftp服务器:
sudo service tftpd-hpa restart
之后需要使用tftp服务将文件传输到其他主机时需要将文件存放在/home/book/my_tftpboot中。
后面使用tftp服务,在uboot启动时从Ubuntu下载linux内核和设备树文件。
四、u-boot移植
4.1 uboot目录简单分析:
uboot的全称是Universal Boot Loader,uboot 是一个遵循GPL协议的开源软件, uboot 是一个裸机代码,可以看作是一个裸机综合例程。uboot 官网为 :http://www.denx.de/wiki/U-Boot/
借用韦东山imx6ull开发板u-boot源码分析:

编译命令:
book@100ask: ~/100ask_imx6ull-sdk$cd Uboot-2017.03
book@100ask: ~/100ask_imx6ull-sdk/Uboot-2017.03$ make distclean
book@100ask: ~/100ask_imx6ull-sdk/Uboot-2017.03$ make
mx6ull_14x14_evk_defconfig
book@100ask: ~/100ask_imx6ull-sdk/Uboot-2017.03$ make
编译后的文件夹:

编译完成之后生成的u-boot-dtb.imx即是可以烧录到开发板中的u-boot镜像文件。
拷贝到Windows中分析可以自己修改来配置到自己板子的文件:
.\board\freescale 板子的信息
.\config 配置文件,主要是_defconfig
.\
重点关注子文件下的Makefile
关注顶层Makefile
关注顶层Readme
执行:make mx6ull_14x14_evk_defconfig命令之后,在.config文件中会保存详细的配置信息。

编辑
4.2 Uboot源码的Make执行流程(了解即可):
1、Makefile执行流程分析(下文默认分析的为顶层Makefile):
先在vscode中创建工作区分析uboot源码,创建流程详见正点原子imx6ull嵌入式驱动开发指南。
Makefile分析:
在Makefile中可添加
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-guneabinf-
2、make命令显示详细信息:
执行 make mx6ull_14x14_ddr512_emmc_defconfig V=1
V=1 参数可以使得make结果显示详细过程
3、设置包含底层Makefile
MAKEFLAGS是make进程的控制变量,-rR --include-dir为其中的选项,$(CURDIR)表示当前目录。

4、是否将变量传递个子make
使用“export”来导出要传递给子 make 的变量即可,如果不希望哪个变量传递给子
make 的话就使用“unexport”来声明不导出:

5、控制命令输出

静默输出:

6、设置输出目录

124行判断命令行中是否有0参数指定,如果有则使用指定输出目录,如何没有(135行判断KEBILD_OUTPUT是否为空)则于135行设置默认输出目录。
第 139 行调用 mkdir 命令,创建 KBUILD_OUTPUT 目录,并且将创建成功以后的绝对路径赋值给 KBUILD_OUTPUT。至此,通过 O 指定的输出目录就存在了。
7、动态检测并标准化构建 U-Boot 的宿主机(Host)CPU 架构类型

uname -m:为shell命令,获取主机原始CPU架构标识;
| :为Linux管道符,可将左侧命令的输出作为右侧命令的输入;
sed 流编辑器:
sed:流编辑器,用于文本转换
-e:指定编辑命令(可以有多个)
s/pattern/replacement/:替换命令语法
pattern:正则表达式匹配模式
replacement:替换后的文本
替换规则:

8、临时设置参数ARCH和CROSS_COMPILE

否则在Ubuntu中编译会识别宿主机为X86而不是开发板的arm。
9、包含scripts/Kbuild.include文件

执行make命令时:每次执行make命令就会认为scripts/Kbuild.include是最新的文件,然后将该文件包含进当前位置;
- scripts/Kbuild.include: ; # 空目标规则,即不需要依赖,将scripts/Kbuild.include识别为新文件;
- include scripts/Kbuild.include #包含该文件:
include scripts/Kbuild.include定义了一些变量

include scripts/Kbuild.include部分内容
10、设置其他交叉编译工具

这里的CROSS_COMPILE在8、临时设置参数ARCH和CROSS_COMPILE中设置了临时的内容:CROSS_COMPILE=arm-linux_guneabinf-
11、导出其他变量

export决定了哪些变量会被传递到子进程的环境中, export 确保指定的变量:
对当前 Makefile 的所有子进程可见
在递归调用的 make 命令中可用
被所有执行命令继承为环境变量
重点变量:ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
这些变量定义在源码顶层目录的config.mk中:

第25行:ARCH := $(CONFIG_SYS_ARCH:"%"=%)语法解释:
语法模板:$(VARIABLE_NAME:"PATTERN"=REPLACEMENT)
$(VARIABLE_NAME):变量引用;
"PATTERN":包含通配符的匹配模式;
=REPLACEMENT:替换表达式;
ARCH := $(CONFIG_SYS_ARCH:"%"=%)的功能就是把CONFIG_SYS_ARCH的值带引号的引号中的内容取出来附给ARCH:
例:

这些变量:CONFIG SYS ARCH、CONFIG SYS CPU、CONFIG SYS BOARD、CONFIG SYS VENDOR 和 CONFIG SYS SOC在uboot根目录下的.config文件中有定义

12、make mx6ull_14x14_evk_defconfig配置命令
前面章节u-boot移植/ uboot目录简单分析中提到的配置命令:
make mx6ull_14x14_evk_defconfig

其中用到了变量Q、MAKE、build,从Makefile源码中478行前文可以分析出:
Q=@或为空
MAKE=make
build为:

命令展开为@make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
就是会执行脚本:scripts/Makefile.build
该命令使用 Kbuild 系统的核心构建框架 (`Makefile.build`),在 `scripts/kconfig` 目录下执行指定的 `xxx_defconfig` 配置目标,以生成项目的配置文件(`.config`)。**
命令的核心功能:
1. **构建框架**:`-f ./scripts/Makefile.build` → 使用标准化构建引擎
2. **目标定位**:`obj=scripts/kconfig` → 作用于配置系统目录
3. **配置动作**:`xxx_defconfig` → 执行特定硬件配置
4. **核心产出**:生成决定整个项目构建行为的 `.config` 文件
13、make命令执行过程
默认目标:

_all依赖于all:

All依赖于$(ALL-y)

ALL-y:
![]()
u-boot.bin的来源:
源文件中没有CONFIG_OF_SEPARATE=y;所有u-boot.bin来源于u-boot-nodtb.bin

4.3 链接脚本u-boot.lds详解(了解即可):
1、u-boot.lds在u-boot中的作用:
u-boot.lds是u-boot源码中的链接脚本文件,它决定了编译生成的u-boot.bin在内存中的内部结构和关键符号地址,这些是 U-Boot 自身启动、重定位以及后续引导 Linux 内核的基础。
链接脚本(.lds文件)简介:
是程序编译阶段(预处理-编译-汇编-链接)的链接阶段的重要管理文件,链接脚本决定了一个可执行程序的各个段的存储位置,相当于要给程序中的数据和变量进行分类,并确定每一类的存放位置。
参考博客https://blog.csdn.net/challenglistic/article/details/131130355
2、u-boot.lds在u-boot编译流程中的作用与位置:
u-boot.lds作用在u-boot编译的链接阶段;
具体位置: 在 U-Boot 源码经过预处理、编译(gcc -c 生成 .o 文件)之后,链接器 (ld) 被调用,将所有目标文件 (.o) 和库文件 (.a) 合并成一个最终的可执行文件(通常是 u-boot 或 u-boot-nodtb.bin)。
入口在u-boot.lds中的:ENTRY(_start)
4.4 NXP官方开发板uboot编译与测试:
半导体厂商会将 uboot 移植到他们自己的原厂开发板上,测试好以后就会将这个 uboot 发布出去,这就是大家常说的原厂 BSP 包。我们一般做产品的时候就会参考原厂的开发板做硬件,然后在原厂提供的 BSP 包上做修改,将 uboot 或者 linux kernel 移植到我们的硬件上。
这个就是uboot 移植的一般流程:
①、在 uboot 中找到参考的开发平台,一般是原厂的开发板。
②、参考原厂开发板移植 uboot 到我们所使用的开发板上。
首先使用NXP官方的原版Uboot:

将NXP官方原版uboot拷贝到开发板中,解压。
编译时使用配套的configs文件:
在官方uboot源码中的configs目录中,搜索mx6ull_14x14_evk_*(因为韦东山6ull开发板是基于NXP官方的evk开发板改进出来的),显示如下四个配置文件:
![]()
找到配置文件之后开始编译,
已经事先在~/.bashrc中设置了环境变量(下文中默认已经在这指定ARCH和交叉编译工具链路径了):
![]()
编译时就不需要指定ARCH和CROSS_COMPILE了
执行:
make distclean
make mx6ull_14x14_evk_emmc_defconfig
make V=1
(原先使用韦东山教程中的配置文件mx6ull_14x14_evk_defconfig,启动开发板时报错MMC: no card present,于是使用emmc版本的evk配置文件)
编译后的源码目录:

源码目录下生成了u-boot.bin和u-boot.imx(u-boot.imx就是在u-boot.bin基础上加了头部信息),u-boot.imx就是可以烧写到开发板EMMC或者SD/TF卡的镜像文件。
使用韦东山烧写软件100ask_imx6ull_flashing_tool_v4.0.exe,首先将编译生成的u-boot.imx拷贝到烧写软件目录下的files目录中,替换掉原来的u-boot-dtb.imx,再将u-boot.imx重命名为u-boot-dtb.imx,保持目录中文件名与之前一致。
设置板子为usb启动,将板子复位或者重新上电,运行固件,烧写Uboot


有问题详见韦东山linux应用开发完全手册7.3。
将开发板设置为emmc启动,重新上电:

显示时间已经为新编译的u-boot的时间,识别到了emmc,但是net网络初始化失败。
4.5 在NXP官方uboot中配置自己的开发板:
为自己的100ask_imx6ull开发板配置的u-boot位于目录/home/book/mycode/NXP官方原版Uboot和Linux/uboot-imx-rel_imx_4.1.15_2.1.0_my100ask_mx6ull
复制一份自己的config文件命名为mx6ull_my100ask_emmc_defconfig
![]()
原defconfig文件:

其中的imximage.cfg提供了u-boot.imx的头部信息,u-boot.imx就是u-boot.bin添加头部信息得到的。
1、修改mx6ull_my100ask_emmc_defconfig
u-boot源码目录下的configs/mx6ull_my100ask_emmc_defconfig

修改文件内容:
mx6ull_my100ask_emmc
CONFIG_TARGET_MX6ULL_MY100ASK_EMMC=y

2、添加自己开发版头文件
源码目录include/configs中有开发板头文件,复制evk开发板头文件一份并且重命名为:mx6ull_my100ask_emmc.h
![]()
修改宏定义为:

暂时不修改mx6ull_my100ask_emmc.h中的内容
3、添加开发板对应的板级文件夹
进入u-boot目录下的/board/freescale目录,拷贝一份mx6ullevk 重命名为mx6ull_my100ask_emmc
![]()
拷贝一份mx6ull_my100ask_emmc中的mx6ullevk.c为mx6ull_100ask_emmc.c
![]()
a、修改mx6ull_my100ask_emmc/Makefile
第6行为mx6ull_100ask_emmc.o
b、修改mx6ull_my100ask_emmc/imximage.cfg
![]()
第34行:

c、修改mx6ull_my100ask_emmc/Kconfig

图中内容:

修改mx6ull_my100ask_emmc/MAINTAINERS
![]()
图中内容:

4、修改 U-Boot 图形界面配置文件
在arch/arm/cpu/armv7/mx6/Kconfig中207行添加如下内容:

并且在末尾添加:
![]()
5、使用新添加的板子配置编译 uboot
make distclean
make mx6ull_my100ask_emmc_defconfig
make V=1

结果:

编译成功!
6、使用韦东山烧写工具先开发板烧写uboot并且开机测试
具体烧写步骤参照嵌入式Linux应用开发完全手册V5.3_IMX6ULL_Pro开发板.pdf 7.3
将u-boot.imx烧写进板子中,可以成功启动u-boot,与原版相同结果:

需要配置网络:
需要配置LCD驱动:
7、网络驱动修改
A、摸清楚开发板原理图使用的PHY芯片以及PIN口和PHY初始化方式。
首先了解IMX6uLL以太网与外部PHY(以太网物理层收发器)的连接方式,并且
MAC是CPU与外部PHY芯片的桥梁,用于处理数据和与PHY芯片通信:

MII/RMII连接框图

RMII接口描述
Myir_board原理图右下角是核心板的网络接口,与之相连的是Ethernet2中的LAN8720A网卡,与RMII接口对应。

100ask版原理图:
ENET板块如图所示:

查看原理图100ask_imx6ull_v1.1.pdf的Ethernet2,发现Imx6ull_my100ask开发板ENET2引脚连接的是lan8720a网卡,左侧:ENET2即与myir_board相连的接口,右侧即网络插口外设。

NXP公板原理图:
SPF-29364_A1.pdf中第7页有ENET网卡pin number

SPF-28616_C2.pdf中第11页有ENET2与什么PHY芯片连接:

【适合有一定基础参考】嵌入式Linux应用开发完全手册_韦东山全系列视频文档-IMX6ULL开发板(从零移植篇-预览版)-V0.1中
描述:

100ask板子ENET RST引脚与公板引脚不同,感觉应该是这里不同:
100askENET2_nRST引脚与芯片连接图:

SPF-28616_C2.pdf中PHY部分:

猜测公板的PHY端ENET2_nRST与CPU连接的引脚叫ENET_nRST,而100ask板子PHY与CPU连接的端叫SNVS_TAMPER6。
那么就需要修改ENET2_RST的引脚。
网卡通过PHY地址进行区分查找,所以还需要查看PHY芯片手册确认PHY地址。
阅读lan8720a芯片手册LAN8720A.pdf:



首先通3.7.1判断PHY芯片的地址,描述中提到PHYAD0位被驱动为高或者低,在芯片上电或硬件复位时,芯片会检测这个引脚上的电平(高或低),并将这个值锁存下来,作为PHY地址的最低位(Bit 0)。
又提到了PHYAD0硬件配置引脚与RXER引脚复用,所以观察原理图连接方式,发现RXER引脚接了一个,上拉电阻所以ENET2网卡PHY地址是0x1。

再看3.8.5 Resets章节了解硬件复位和软件复位:
3.8.5提到Resets描述为设备需要进行软件复位和硬件复位;
3.8.5.1提到硬件复位需要将nRST拉低一段时间,具体描述在5.5.3中;
3.8.5.2则说明了软件复位需要设置Basic Control Register bit为1。

5.5.3中描述:
通过手册描述可知到nRST在上电过程中,硬件复位需要assertion time时间至少为trstia,即100 µs。在25ms之后进行电平转换,
【适合有一定基础参考】嵌入式Linux应用开发完全手册_韦东山全系列视频文档-IMX6ULL开发板(从零移植篇-预览版)-V0.1中描述为:

我不太理解这个描述
翻译:

Basic Control Register:
从4.2.1描述可知 Basic Control Register的bit15位设置为1表示软件复位。

总结需要修改ENET2网络驱动有三点:
1、ENET复位引脚初始化
2、LAN8720A的器件id
3、LAN8720驱动
B、修改源码:
a、首先理解韦东山开发手册中修改文件的描述:git语法描述:
1、diff –git a/configs/mx6ull_14x14_evk_defconfig b/configs/mx6ull_14x14_evk_defconfig
这一行是Git差异的标头。它告诉我们正在比较(diff)的是同一个文件的两个版本,第一个是旧版本,第二个是新版本
2、index b4a8246b_949eea7b 100644
index 行显示了这个文件两个版本对应的唯一 Git 对象哈希值(缩写)。100644 是标准的文件权限代码,表示这是一个普通文件。
3、— a/configs/mx6ull_14x14_evk_defconfig
这行表示后续以 - 开头的行代表从旧版本(a版本) 中删除的内容。
4、+++ b/configs/mx6ull_14x14_evk_defconfig
这行表示后续以 + 开头的行代表向新版本(b版本) 中添加的内容。
5、@@ -46,8 +46,7 @@ CONFIG_SF_DEFAULT_SPEED=40000000
这行是 “块标头”(hunk header),它指明了后续差异所发生的具体位置。
-46,8:在旧版本中,从第 46 行开始,显示了 8 行内容。
+46,7:在新版本中,从第 46 行开始,显示了 7 行内容。
CONFIG_SF_DEFAULT_SPEED=40000000 是上下文,帮助定位。


从上面面韦东山完全开发手册截图来看,移除了PHY_MICREL的两行,增加了PHY_SMSC的配置,于是打开自己配置的mx6ull_my100ask_emmc_deconfig进行修改:
b、在configs/mx6ull_my100ask_emmc_defconfig中增加SMSC配置项:

c、网络PHY地址修改
打开include/configs/mx6ull_my100ask_emmc.h修改:
331行宏 CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择ENET2。
339行为 ENET2 的 PHY 地址,默认为 0x1。根据前面分析可知,PHY地址为0x1

345行修改为SMSC,因为LAN8720A是SMSC公司生产的,默认的是Micrel公司生产的芯片
![]()
d、驱动代码修改
修改board/freescale/mx6ull_my100ask_emmc/mx6ull_my100ask_emmc.c中以下代码,
以 IOX 开头的宏定义是 74LV595 的相关 GPIO,因为 NXP 官方I.MX6ULL EVK 开发板使用 74LV595 来扩展 IO,两个网络的复位引脚就是由 74LV595 来控制的。
ENET2 的复位引脚连接到 SNVS_TAMPER6上,对应 GPIO5_IO06。

删除上面的IOX宏定义,添加以下代码,ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO06。
![]()
![]()

![]()
删除以下代码,代码是74LV595的IO配置参数结构体,将其删除掉。

![]()
继续在mx6ull_alientek_emmc.c 中找到函数 iox74lv_init和iox74lv_set,删除,如下所示:


![]()
board/freescale/mx6ull_my100ask_emmc/mx6ull_my100ask_emmc.c 中的board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化74lv595 的 GPIO,将这两行删除掉。至此, mx6ull_alientek_emmc.c 中关于 74LV595 芯片的驱动代码都删除掉了,接下来就是添加 mx6ull_my100ask开发板网络复位引脚了。

e、添加mx6ull_my100ask_emmc开发板网络复位引脚驱动
在 mx6ull_alientek_emmc.c 中找到如下所示代码:

结构体数组 fec1_pads 和 fec2_pads 是 ENET1 和 ENET2 这两个网口的 IO 配置参数,在这第二个数组中添加个网口的复位 IO 配置参数,完成以后如下所示:

代码:MX6_PAD_SNVS_TAMPER6__GPIO5_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL)
代码位于fec2_pads[]中,用于 ENET12(第二个网络接口) 的复位引脚。将 SNVS_TAMPER7 这个引脚配置为 GPIO5_IO07 功能,并使用默认的电气属性。 这样,开发者就可以通过控制 GPIO5_7 这个软件抽象来输出高低电平,从而控制连接到 ENET1 的 PHY 芯片的复位引脚 (ENET1_nRST)。
继续在文件 mx6ull_alientek_emmc.c 中找到函数 setup_iomux_fec,此函数默认代码如下:

函数 setup_iomux_fec 就是根据 fec1_pads 和 fec2_pads 这两个网络 IO 配置数组来初始化I.MX6ULL 的网络 IO。我们需要在其中添加网络复位 IO 的初始化代码,并且复位一下 PHY 芯片,修改后的 setup_iomux_fec 函数如下:

gpio_direction_output(ENET1_RESET, 1);
将一个 GPIO 引脚设置为输出模式,并同时设置其初始输出电平。
gpio_set_value(ENET1_RESET, 0);
设置一个已配置为输出的 GPIO 引脚的为低电平。
mdelay(20):
这是一个延时函数,让程序在这里等待 20 毫秒。
f、修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link
添加红色框中代码,225 行~237 行就是新添加的代码,为条件编译代码段,只有使用 SMSC 公司的 PHY 这段代码才会执行(目前只测试了 LAN8720A, SMSC 公司其他的芯片还未测试)。第 229 行读取LAN8720A 的 BMCR 寄存器(寄存器地址为 0),此寄存器为 LAN8720A 的配置寄存器,这里先读取此寄存器的默认值并保存起来。 230 行向寄存器 BMCR 寄存器写入 BMCR_RESET(值为0X8000),因为 BMCR 的 bit15 是软件复位控制位,因此 230 行就是软件复位 LAN8720A,复位完成以后此位会自动清零。第 231~233 行等待 LAN8720A 软件复位完成,也就是判断 BMCR
的 bit15 位是否为 1,为 1 的话表示还没有复位完成。第 234 行重新向 BMCR 寄存器写入以前的值,也就是 229 行读出的那个值。

8、LCD驱动修改
board/freescale/mx6ull_my100ask_emmc/mx6ull_my100ask_emmc.c
include/configs/mx6ull_my100ask_emmc.h
目前观察原理图,100ask的lcd应该与公板连接相同,也就是 LCD 的 IO 和背光 IO 都一样的。
需要修改的LCD 参数,打开文件 mx6ull_alientek_emmc.c,找到如下所示内容:

上述代码中定义了一个变量 displays,类型为 display_info_t,这个结构体是 LCD信息结构体,其中包括了 LCD 的分辨率,像素格式, LCD 的各个参数等。 display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,定义如下:

pixfmt 是像素格式,也就是一个像素点是多少位,如果是 RGB565 的话就是 16 位,如果是 888 的话就是 24 位,一般使用 RGB888。结构体 display_info_t 还有个 mode 成员变量,此成员变量也是个结构体,为 fb_videomode,定义在文件 include/linux/fb.h 中,定义如下:

结构体 fb_videomode 里面的成员变量为 LCD 的参数,这些成员变量函数如下:
name: LCD 名字,要和环境变量中的 panel 相等。
xres、 yres: LCD X 轴和 Y 轴像素数量。
pixclock:像素时钟,每个像素时钟周期的长度,单位为皮秒。
left_margin: HBP,水平同步后肩。
right_margin: HFP,水平同步前肩。
upper_margin: VBP,垂直同步后肩。
lower_margin: VFP,垂直同步前肩。
hsync_len: HSPW,行同步脉宽。
vsync_len: VSPW,垂直同步脉宽。
vmode: 大多数使用 FB_VMODE_NONINTERLACED,也就是不使用隔行扫描。
在我使用的LCD屏幕手册NTW430T40X005A 规格书IPS 500亮度.pdf中寻找相关参数:

图中可知:
name :NTW430T40X005A
xres :800
yres :480

上图可知DCLK频率的典型值为25 MHz(25兆赫兹);
则pixclock=![]()
编辑 ×![]()
编辑 =40000ps

最终参数:

于是修改后的mx6ull_alientek_emmc.c中的参数为:

9、bootcmd和bootargs环境变量
【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf中分析了一大堆u-boot启动内核的流程,bootcmd保存着uboot默认命令, uboot倒计时结束以后就会执行bootcmd中的命令。这些命令一般都是用来启动Linux内核的,比如读取 EMMC或者NAND Flash中的Linux内核镜像文件和设备树文件到DRA中,然后启动 Linux内核。
打开文件 include/env_default.h,在此文件中有bootcmd:

宏CONFIG_BOOTCOMMAND 在mx6ull_my100ask_emmc.h中,很复杂一大堆,【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf分析了该宏,是类似shell脚本编写的,目的是兼容多种板子以启动linux,但是我们只需要启动我们自己的板子,
查看emmc中zImage和dtb位置
=> ext4ls mmc 1:2 /boot
<DIR> 4096 .
<DIR> 4096 ..
7924872 zImage
<DIR> 4096 bin
37940 100ask_imx6ull_mini.dtb
36885 100ask_myir_imx6ull_mini.dtb
38370 100ask_imx6ull-14x14.dtb
确认zImage和dtb在emmc 1:2 的/boot目录下;
于是可以将CONFIG_BOOTCOMMAND简化:

205行为切换到EMMC
206行为读取zImage到0x80800000处
207行为读取设备树到0x83000000处
208行为启动Linux
但是启动还是显示没有识别文件,猜测是u-boot环境变量还是默认的命令,于是:
设置u-boot中的环境变量:
=> setenv bootcmd=mmc dev 1; ext4load mmc 1:2 0x80800000 /boot/zImage; ext4load mmc 1:2 0x83000000 /boot/100ask_imx6ull-14x14.dtb; bootz 0x80800000 - 0x83000000
#防止环境变量设置为默认bootcmd
=> setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
#告诉内核“从哪儿加载根文件系统、日志往哪儿输出、启动有哪些特殊配置”。
=> saveenv
此时自己修改的u-boot可以顺利启动内核:

10、解决uboot界面中cpu报错的问题
我按照正点原子教程在u-boot源码中添加韦东山板子并且配置net运行后ping网络出现以下报错:
=> ping 192.168.58.137
FEC1 Waiting for PHY auto negotiation to complete......... TIMEOUT !
Using FEC1 device
data abort
pc : [<9ff83ae0>] lr : [<9ff84db0>]
reloc pc : [<8783bae0>] lr : [<8783cdb0>]
sp : 9ef45d08 ip : 00000001 fp : 9ff53534
r10: 00000002 r9 : 9ef45eb8 r8 : 00000000
r7 : 00000001 r6 : 00000000 r5 : 0000002a r4 : 9ffecc0e
r3 : 14000045 r2 : 373aa8c0 r1 : 893aa8c0 r0 : 9ffecc0e
Flags: nZCv IRQs off FIQs off Mode SVC_32
Resetting CPU ...
resetting ...
在网上查询之后有回答:
编辑
于是按照【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf4.3下载正点原子教程使用的交叉编译工具链,地址:https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/

将该工具链存放在路径下:
/home/book/my_sdk/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
修改环境变量:
book@100ask:~/my_sdk$ vim ~/.bashrc

重新编译u-boot
book@100ask:~/mycode/NXP官方原版Uboot和Linux/uboot-imx-rel_imx_4.1.15_2.1.0_my100ask_mx6ull$ make distclean
book@100ask:~/mycode/NXP官方原版Uboot和Linux/uboot-imx-rel_imx_4.1.15_2.1.0_my100ask_mx6ull$ make mx6ull_my100ask_emmc_defconfig
book@100ask:~/mycode/NXP官方原版Uboot和Linux/uboot-imx-rel_imx_4.1.15_2.1.0_my100ask_mx6ull$ make V=1
运行之后使用ping命令未出现CPU报错
设置ip环境:
ethaddr=00:04:9f:00:01:01
gatewayip=10.23.42.1
ipaddr=10.23.42.20
netmask=255.255.255.0
serverip=10.23.42.28
测试开发板的ip对应Ubuntu中ip地址,确保他们在同一个网段:

经过测试,将开发板设置为192.168.58.1网段内,开发板无法ping通Ubuntu,但是设置为10.23.42.1的网段,开发板可以ping通Ubuntu。

4.6 U-Boot图形化配置界面
1、U-Boot图形化配置界面简单尝试
首先在Ubuntu中安装ncurses库
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev
在uboot或者Linux内核输入make menuconfig命令可以打开图形化配置界面,menuconfig重点用到两个文件:.config 和 Kconfig。
config文件保存着 uboot 的配置项,使用 menuconfig 配置完 uboot 以后肯定要更新.config 文件。 Kconfig文件是图形界面的描述文件,也就是描述界面应该有什么内容,很多目录下都会有 Kconfig 文件。
打开图形化界面之前首先使用defconfig对uboot进行配置:
make mx6ull_my100ask_emmc_defconfig
如何执行命令打开图形化界面:
make menuconfig
界面显示如下:

以dns命令的使能做案例:
使用键盘上下左右案件选中command line interface
按下enter

选中Network commands

选中dns,然后按下键盘上的“Y”键,此时 dns 前面的“[ ]”变成了“[ * ]”,每个选项有3种编译选项:编译进 uboot 中(也就是编译进u-boot.bin中)、取消编译(也就是不编译这个功能模块)、编译为模块。按下“Y”键表示编译进uboot中,此时“[ ]”变成了“[ * ]”;

按下“N”表示不编译,“[ ]”默认表示不编译;
双击Esc退出上一个界面
然后在源码根目录中的.config文件中发现CONFIG_CMD_DNS=y

注意不要执行make distclean
直接执行make进行编译,然后在uboot中输入命令help,发现有了dns命令:

2、U-Boot图形化配置界面原理
原理详见正点原子【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf
P34.2.1
最终会调用uboot根目录下的Kconfig文件开始构建图像配置界面。
3、Kconfig 语法简介
语法详见正点原子【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf
P34.2.2
五、Linux内核编译与移植
5.1 使用正点原子的Linux源码进行编译
路径:
/home/book/mycode/03、正点原子Uboot和Linux出厂源码
解压源码:
tar -vxjf linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7.tar.bz2
解压之后:

编译:
book@100ask:~/mycode/03、正点原子Uboot和Linux出厂源码$ make distclean
book@100ask:~/mycode/03、正点原子Uboot和Linux出厂源码$ make imx_v7_defconfig
book@100ask:~/mycode/03、正点原子Uboot和Linux出厂源码$ make -j16
在linux内核中编译使用比较多的图形化界面命令
make menuconfig
编译完成以后就会在 arch/arm/boot 这个目录下生成一个叫做 zImage 的文件, zImage 就是我们要用的 Linux 镜像文件。另外也会在 arch/arm/boot/dts 下生成很多.dtb 文件,这些.dtb 就是设备树文件。
获取其中的zImage和设备树文件
zImage:arch/arm/boot/zImage
dtb:arch/arm/boot/dts/*.dtb
编译单独.dtb文件命令:
make ./arch/arm/boot/dts/imx6ull-14x14-emmc-7-1024x600-c.dtb
编译后的源码目录含义:



1、arch目录
/arch/arm/configs中有板子的配置文件xxx_defconfig,
在 arch/arm/configs 中就包含有 正点原子的I.MX6U-ALPHA 开发板的默认配置文件: imx_v7_defconfig,
执行“make imx_v7_defconfig”即可完成配置

arch/arm/boot 目录下会保存编译出来的 Image 和 zImage 镜像文件,而 zImage 就是我们要用的 linux 镜像文件。

arch/arm/mach-xxx 目录分别为相应平台的驱动和初始化文件,比如 mach-imx 目录里面就是 I.MX 系列 CPU 的驱动和初始化文件

2、其他
详细参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf P35.3
5.2 使用NXP的Linux源码进行编译
NXP官方源码目录:/home/book/mycode/NXP官方原版Uboot和Linux/linux-imx-rel_imx_4.1.15_2.1.0_ga
1、修改顶层Makefile
直接在顶层 Makefile 文件里面定义 ARCH 和 CROSS_COMPILE 这两个的变量值为 arm 和 arm-linux-gnueabihf-:

确保交叉编译在arm平台
2、编译内核并且在uboot中下载启动
编译NXP提供的内核,编译命令:
make clean
make imx_v7_defconfig
make menuconfig (打开图形化界面,可选)
make all -j16
编译完成后在arch/arm/boot文件夹下生成Image和zImage,
![]()
在arch/arm/boot/dts文件夹中生成:imx6ull-14x14-evk-emmc.dtb

将内核和设备树文件移动到tftp目录中:
cp arch/arm/boot/zImage /home/book/my_tftpboot/
cp arch/arm/boot/dts/imx6ull-14x14-evk-emmc.dtb /home/book/my_tftpboot/
使用tftp在uboot下载zImage和imx6ull-14x14-evk-emmc.dtb,并且使用文件启动:
=> tftp 80800000 zImage
FEC1 Waiting for PHY auto negotiation to complete... done
Using FEC1 device
TFTP from server 10.23.42.28; our IP address is 10.23.42.20
Filename 'zImage'.
Load address: 0x80800000
Loading: ####################################################################################################################################################################################################################################################################################################################################################################################################################################################################
2.3 MiB/s
done
Bytes transferred = 6680408 (65ef58 hex)
=> tftp 83000000 imx6ull-14x14-evk.dtb
Using FEC1 device
TFTP from server 10.23.42.28; our IP address is 10.23.42.20
Filename 'imx6ull-14x14-evk.dtb'.
Load address: 0x83000000
Loading: ###
2.3 MiB/s
done
Bytes transferred = 35969 (8c81 hex)
=> bootz 80800000 - 83000000
但是猜测根文件系统是韦东山开发板自带的,与原始NXP的内核编译不匹配,导致启动失败:

5.3 在NXP的Linux源码中添加自己的开发板
1、添加开发板默认配置文件
cd ./arch/arm/configs/
cp imx_v7_defconfig imx_my100ask_emmc_defconfig
2、添加开发板对应的设备树文件
cd arch/arm/boot/dts/
cp imx6ull-14x14-evk.dts imx6ull-my100ask-emmc.dts
.dts 是设备树源码文件,编译 Linux 的时候会将其编译为.dtb 文件。imx6ull-my100ask-emmc.dts创 建 好 以 后 我 们 还 需 要 修 改 文 件 arch/arm/boot/dts/Makefile , 找 到 “ dtb- $(CONFIG_SOC_IMX6ULL)”配置项,在此配置项中加入“imx6ull-my100ask-emmc.dts” ,如下所示:
编辑
3、编译测试
前面两小节以及完成了自己开发板的添加,接下来进行编译测试:
make distclean
make imx_my100ask_emmc_defconfig
make menuconfig
make all -j8
将zImage和设备树文件添加到tftp目录
cp arch/arm/boot/zImage /home/book/my_tftpboot/
cp arch/arm/boot/dts/imx6ull-my100ask-emmc.dtb /home/book/my_tftpboot/
在uboot中下载并且启动:
tftp 80800000 zImage
tftp 83000000 imx6ull-my100ask-emmc.dtb
bootz 80800000 - 83000000

启动成功,虽然遇到根文件系统问题,
5.4 EMMC使能修改和网络驱动修改
1、EMMC使能修改
韦东山imxull EMMC 版本核心板上的EMMC采用的8位数据线,原理图如图所示:

Linux内核驱动里面EMMC默认是4线模式的,所以本节我将EMMC的驱动修改为 8 线模式。直接修改设备树即可,打开文件 imx6ull-my100ask-emmc.dts,找到如下所示内容并且修改为图中所示:

修改完之后执行命令编译dts并且拷贝到tftp文件夹中:

使用编译后的设备树文件再启动内核,还是emmc处出现问题:

2、网络驱动修改
从原理图可以看出GPIO5为 SNVS_TAMPER6引脚,连的是ENET2的复位引脚,


所以在配置文件imx6ull-alientek-emmc.dts 里面找到名为“iomuxc_snvs”的节点中添加复位信息:

修改一下 ENET1 和 ENET2 的网络时钟引脚配置, 继续在 imx6ull-alientekemmc.dts 中找到如下所示代码:

第 318 和 333 行, 分别为 ENET1 和 ENET2 的网络时钟引脚配置信息,将这两个引脚的电气属性值改为 0x4001b009,原来默认值为 0x4001b031。
3、修改 fec2 节点的 pinctrl-0 属性
修改为:

![]()
第184和185行,ENET2网络复位引脚所使用的IO为GPIO5_IO08,同样低电平有效,持续时间同样为200ms。
第194和200行,“smsc,disable-energy-detect”表明PHY芯片是SMSC公司的,这样 Linux内核就会找到 SMSC 公司的 PHY 芯片驱动来驱动 LAN8720A。
第198行,注意“ethernet-phy@”后面的数字是 PHY 的地址,ENET2的PHY 地址为1,所以“@”后面是1。
第 199 行,reg 的值也表示PHY地址,ENET1的PHY地址为0,所以reg=0。
第 202 行,ENET2的PHY地址为1,因此“@”后面为1。第 205 行,因为 ENET2 的 PHY 地址为 1,所以 reg=1。
至此,LAN8720A 的 PHY 地址就改好了,保存一下 imx6ull-alientek-emmc.dts 文件。
然后使用“make dtbs”命令重新编译一下设备树。
4、修改 fec_main.c 文件
要在I.MX6ULL上使用LAN8720A,需要修改一下Linux内核源码,打开drivers/net/ethernet/freescale/fec_main.c,找到函数fec_probe,在fec_probe中加入如下代码:

5、配置Linux内核,使能LAN8720驱动
输入命令“make menuconfig”,打开图形化配置界面,选择使能 LAN8720A 的驱动,路径如下:
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs

图中选择将“Drivers for SMSC PHYs”编译到 Linux 内核中,因此“<>”里面变为了“*”。LAN8720A 是 SMSC 公司出品的,因此勾选这个以后就会编译LAN8720驱动,配置好以后退出配置界面,然后重新编译一下Linux内核
6、修改smsc.c文件
在uboot中需要对LAN8720A进行一次软复位,要设置LAN8720A的BMCR(寄存器地址为0)寄存器bit15为1。所以猜测,在 Linux中也需要对LAN8720A进行一次软复位。
首先需要找到LAN8720A的驱动文件,LAN8720A的驱动文件是 drivers/net/phy/smsc.c,在此文件中有个叫做 smsc_phy_reset 的函数,看名字都知道这是 SMSC PHY 的复位函数,因此,LAN8720A肯定也会使用到这个复位函数,修改此函数的内容,修改以后的smsc_phy_reset函数内容如下所示:

![]()
修改之后重新编译内核,但是启动之后无法测试,因为没有配置匹配的根文件系统,后面移植了根文件系统之后再测试。
7、保存修改后的图形化配置文件
之前在图形化配置界面中使能的SMSC驱动需要在图形化界面中保存,否则之后执行make distclean之后会清除:
在图形化界面首页有保存选项:

点击之后会让输入保存文件以及路径(相对路径):

输入板子的配置文件相对路径:
arch/arm/configs/imx_my100ask_emmc_defconfig
然后点击ok退出
然后在imx_my100ask_emmc_defconfig中就可以看到:
CONFIG SMSCPHY=y

六、根文件系统移植
6.1 根文件系统简介
见【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf 38.1
6.2 BusyBox 构建根文件系统
1、busybox下载
BusyBox 可以在其官网下载到,官网地址为: https://busybox.net/

在官网左侧的“Get BusyBox”栏有一行“Download Source”,点击“Download Source”即可打开 BusyBox 的下载页


![]()
打开文件 busybox- 1.29.0/libbb/printable_string.c,找到函数 printable_string,缩减后的函数内容如下:


接着打开文件 busybox-1.29.0/libbb/unicode.c,修改为如下内容

2、busybox配置
默认配置:make defconfig
图形化配置:make menuconfig
3、测试
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=10.23.42.28:/home/book/my_nfs/rootfs,proto=tcp rw ip=10.23.42.20:10.23.42.28:10.23.42.1:255.255.255.0::eth0:off'
saveenv
tftp 80800000 zImage
tftp 83000000 imx6ull-my100ask-emmc.dtb
bootz 80800000 - 83000000
6.3 一直测试失败,使用AI提供的dts顺利启动
Ai分析出emmc启动出有问题把:提供了修改后的dts:imx6ull-my100ask-emmc-fixed.dts
修改要点(ai提供并且说明的没有去dts文件中详细分析):
1、为 &usdhc1 节点添加:
- voltage-ranges = <2700000 3600000>;
- vqmmc-supply = <®_sd1_vmmc>;
2、为 &usdhc2 节点添加:
- vmmc-supply = <®_sd1_vmmc>;
- vqmmc-supply = <®_sd1_vmmc>;
- voltage-ranges = <1800000 3600000>;
将修改后的imx6ull-my100ask-emmc-fixed.dts添加到arch/arm/boot/dts中
在kernel源码中编译dts:
make imx6ull-my100ask-emmc-fixed.dtb
把生成的imx6ull-my100ask-emmc-fixed.dtb拷贝到/home/book/my_tftpboot/中
在uboot中下载/home/book/my_tftpboot/中的zImage以及dts:
tftp 80800000 zImage
tftp 83000000 imx6ull-my100ask-emmc-fixed.dtb
启动:
bootz 80800000 – 83000000
(此处没有使用网络挂载rootfs,而是将rootfs烧写到sd卡,再使用sd卡启动:bootargs=console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait rw,烧写方法详见《SD卡格式化和烧写》)
6.4 完善根文件系统

![]()
提示can't run /etc/init.d/rcs': No such file or directory
按照【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf 38.4逐步操作,没有更改的。
6.5 开发板linux网络配置
开发板启动时使用ping命令连接服务器10.23.42.28失败,于是配置地址:
/ # ifconfig eth0 up
/ # ifconfig eth0 10.23.42.20 netmask 255.255.255.0
/ # route add default gw 10.23.42.1
配置完可以ping通服务器:
/ # ping 10.23.42.28
PING 10.23.42.28 (10.23.42.28): 56 data bytes
64 bytes from 10.23.42.28: seq=0 ttl=64 time=1.638 ms
64 bytes from 10.23.42.28: seq=1 ttl=64 time=0.764 ms
64 bytes from 10.23.42.28: seq=2 ttl=64 time=0.754 ms
‘’’
将网络配置添加到开机自启动中:
设置网卡 IP 地址的命令添加到/etc/init.d/rcS 文件中:
6.6 目前的以SD卡为介质的根文件系统移植方法
1、开发板连接并且挂载Ubuntu
先判断开发板linux是否可以ping通Ubuntu
/ # ping 10.23.42.28
可以ping通之后在开发板中挂载PC端Ubuntu中/home/book/my_nfs目录:
/ # mount -t nfs -o nolock 10.23.42.28:/home/book/my_nfs /mnt/nfs
/ # cd /mnt/nfs/
/mnt/nfs # ls
rootfs rootfs.tar.bz2
此处就可以看到成功挂载了Ubuntu中的目录
使用完毕记得卸载:
umount /mnt/nfs
2、在Ubuntu中修改根文件系统,再在开发板中将根文件系统烧写到sd卡中
在开发板中挂载了Ubuntu目录,就可以在开发板中同时访问到Ubuntu目录中正在开发的rootfs和访问SD卡了,配合之前的uboot通过sd卡中的rootfs启动可以实现快速在Ubuntu中配置rootfs并且在开发板中将roots烧写到sd卡中,再直接重启便可以使用新配置的rootfs了。
在ubuntu中rootfs目录中加入测试文件:

在开发板linux中就可以看到新建的文件:

查看开发板连接的sd卡:
/mnt/nfs # ls /dev/mmcblk*

/mnt/nfs # cat /proc/partitions

其中mmcblk0是我的sd卡,并且之前创建的存放rootfs的分区是p2
在开发板Linux目录中创建用于挂载sd卡的目录:
网络挂载服务器Ubuntu中的rootfs目录:
/ # mount -t nfs -o nolock 10.23.42.28:/home/book/my_nfs /mnt/nfs


挂载sd卡到该目录:
/ # mount /dev/mmcblk0p2 /mnt/sd_root/

可以看到目前是没有test.txt文件的
拷贝挂载的Ubuntu中rootfs目录到sd卡挂载目录中:
cp -a /mnt/nfs/rootfs/* /mnt/sd_root/

现在sd卡中也有test.txt了
验证应该可以拷贝单个文件吧:
创建新的测试文件:


cp -a /mnt/nfs/rootfs/test2.txt /mnt/sd_root/

以后拷贝修改的文件就好了
卸载:
/ # umount /mnt/nfs
/ # umount /mnt/sd_root
/ # reboot
重启之后可以看到根文件系统有新文件了:

6.7 解决了uboot中无法网络启动的原因
1、修改/etc/exports
vim /etc/exports
修改为以下内容:
/home/book/my_nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check)
在原来基础上加入了no_subtree_check
再保存配置:
$ sudo exportfs -ra
$ sudo exportfs -v
2、修改bootargs
Uboot中bootargs配置:
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs ip=10.23.42.20:10.23.42.28:10.23.42.1:255.255.255.0::eth0:off nfsroot=10.23.42.28:/home/book/my_nfs/rootfs,v3,tcp rw'
saveenv
这在一些内核版本里默认会尝试 NFSv4,如果服务端(即ubuntu)没开 v4,就挂不上。
后来改成:
nfsroot=10.23.42.28:/home/book/my_nfs/rootfs,v3,tcp
主要添加了v3
现在可以顺利在uboot中提供网络启动了:
关键uboot环境配置:
bootargs=console=ttymxc0,115200 root=/dev/nfs ip=10.23.42.20:10.23.42.28:10.23.42.1:255.255.255.0::eth0:off nfsroot=10.23.42.28:/home/book/my_nfs/rootfs,v3,tcp rw
bootcmd=tftp 80800000 zImage; tftp 83000000 imx6ull-my100ask-emmc-fixed.dtb; bootz 80800000 – 83000000
gatewayip=10.23.42.1
serverip=10.23.42.28
ipaddr=10.23.42.20
netmask=255.255.255.0
现在就可以在ubuntu中修改rootfs,再提供uboot中网络挂载启动了
6.8 开发板无法ping外网的问题
将开发板网关修改为10.23.42.28,因为Ubuntu中网络配置:
ens33 → NAT 网络,IP 是 192.168.58.137(这条是虚拟机对外上网用的)。
ens36 → Host-only 或桥接网络,IP 是 10.23.42.28,这个才是你和开发板通信的网口。
10.23.42.28 是虚拟机自己,属于 Host-only 网络段。
- Host-only 网段里通常没有网关(因为它只是 VM ↔ 主机互联,不通外网)。
- 所以在开发板里设置 10.23.42.1 作为网关是无效的,ping 不通。
1、在虚拟机里开路由转发(ens36 → ens33 NAT)。
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
2、在开发板上把网关设置成虚拟机的 Host-only IP(10.23.42.28),而不是 10.23.42.1:
route add default gw 10.23.42.28
echo "nameserver 114.114.114.114" > /etc/resolv.conf
在Ubuntu中永久设置:
1. 开启 IP 转发(永久)编辑配置文件:
sudo nano /etc/sysctl.conf
找到这一行:
#net.ipv4.ip_forward=1
改成:
net.ipv4.ip_forward=1
保存后执行:
sudo sysctl -p
2. 配置 NAT 转发(iptables)
写 systemd 脚本:
sudo nano /etc/systemd/system/nat-routing.service
写入:
[Unit]
Description=Enable NAT routing for Dev Board
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
然后:
sudo systemctl enable nat-routing
sudo systemctl start nat-routing
在开发板中永久设置:
在rootfs中开机脚本编辑:
route add default gw 10.23.42.28
6.9 Buildroot构建根文件系统
1、下载解压Buildroot
Buildroot官网:https://buildroot.org/

点击DOWNLOAD:


下载buildroot-2019.02.6.tar.bz2
拷贝到Ubuntu中需要网络启动的目录:
|
book@100ask:~/my_nfs$ pwd |
|
/home/book/my_nfs |
|
book@100ask:~/my_nfs$ ls |
|
buildroot-2019.02.6.tar.bz2 rootfs rootfs.tar.bz2 |
解压:
tar -vxjf buildroot-2019.02.6.tar.bz2
进入解压的文件
cd buildroot-2019.02.6/

我的buildroot工程目录:/home/book/my_nfs/buildroot-2019.02.6
2、配置Buildroot
buildroot 和 uboot、 Linux kernel 一样也支持图形化配置,输入如下命令即可打开图形化配置界:
make menuconfig

a、配置 Target options
首先配置 Target options 选项,需要配置的项目和其对应的内容如下(“=”号后面是配置项要选择的内容! ):
Target options
-> Toolchain type = External toolchain
-> Toolchain = Custom toolchain //用户自己的交叉编译器
-> Toolchain origin = Pre-installed toolchain //预装的编译器
-> Toolchain path =/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
-> Toolchain prefix = $(ARCH)-linux-gnueabihf //前缀
-> External toolchain gcc version = 4.9.x
-> External toolchain kernel headers series = 4.1.x
-> External toolchain C library = glibc/eglibc
-> [*] Toolchain has SSP support? (NEW) //选中
-> [*] Toolchain has RPC support? (NEW) //选中
-> [*] Toolchain has C++ support? //选中
-> [*] Enable MMU support (NEW) //选中
b、配置 Toolchain
此配置项用于配置交叉编译工具链,也就是交叉编译器,这里设置为我们自己所使用的交
叉编译器即可。 buildroot 其实是可以自动下载交叉编译器的,但是都是从国外服务器下载的,
鉴于国内的网络环境,强烈推荐大家设置成自己所使用的交叉编译器。需要配置的项目和其对
应的内容如下:
Toolchain
-> Toolchain type = External toolchain
-> Toolchain = Custom toolchain //用户自己的交叉编译器
-> Toolchain origin = Pre-installed toolchain //预装的编译器
-> Toolchain path =/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
-> Toolchain prefix = $(ARCH)-linux-gnueabihf //前缀
-> External toolchain gcc version = 4.9.x
-> External toolchain kernel headers series = 4.1.x
-> External toolchain C library = glibc/eglibc
-> [*] Toolchain has SSP support? (NEW) //选中
-> [*] Toolchain has RPC support? (NEW) //选中
-> [*] Toolchain has C++ support? //选中
-> [*] Enable MMU support (NEW) //选中
c、 配置 System configuration
此选项用于设置一些系统配置,比如开发板名字、欢迎语、用户名、密码等。需要配置的
项目和其对应的内容如下:
System configuration
-> System hostname = alpha_imx6ull //平台名字,自行设置
-> System banner = Welcome to alpha i.mx6ull //欢迎语
-> Init system = BusyBox //使用 busybox
-> /dev management = Dynamic using devtmpfs + mdev //使用 mdev
-> [*] Enable root login with password (NEW) //使能登录密码
-> Root password = 123456 //登录密码为 123456
d、配置 Filesystem images
-> Filesystem images
-> [*] ext2/3/4 root filesystem //是 EMMC 或 SD 卡的话,用 ext3/ext4
-> ext2/3/4 variant = ext4 //选择 ext4 格式
e、 禁止编译 Linux 内核和 uboot
-> Kernel
-> [ ] Linux Kernel //不要选择编译 Linux Kernel 选项!
接着禁止编译 Uboot, 配置如下:
-> Bootloaders
-> [ ] U-Boot //不要选择编译 U-Boot 选项!
3、编译Buildroot
sudo make //注意,一定要加 sudo,而且不能通过-jx 来指定多核编译!!!
工程清理命令:
make clean:清理编译生成的目标文件和 output/build/*,不会清理 .config。
make <package>-dirclean:只清理某个包(比如 qt5base),不会清理 .config。
比如:make qt5base-dirclean
make distclean:把整个工程恢复到初始状态(包括 .config),等同于全新解压源码,这时候 所有配置都会丢失。

其中rootfs.tar 就是打包好的根文件系统,我们就使用 rootfs.tar 进行测试。在 nfs 目录下新建一个名为 buildrootfs 的文件夹:
mkdir /home/book/my_nfs/buildrootfs
至此,可以使用开发板中uboot挂载启动的buildroot构建的根文件系统目录为:
/home/book/my_nfs/buildrootfs
然后将rootfs.tar 拷贝到 buildrootfs 目录下并解压:
cp ./output/images/rootfs.tar /home/book/my_nfs/buildrootfs/
cd /home/book/my_nfs/buildrootfs/
tar -vxf rootfs.tar
rm rootfs.tar
![]()
修改挂载目录:
sudo vim /etc/exports
修改为:
/home/book/my_nfs/buildrootfs *(rw,sync,no_root_squash,no_subtree_check)
一定记得保存配置!:
$ sudo exportfs -ra
$ sudo exportfs -v
修改bootargs:
setenv bootargs 'console= ttymxc0,115200 root=/dev/nfs ip=10.23.42.20:10.23.42.28:10.23.42.1:255.255.255.0::eth0:off nfsroot=10.23.42.28:/home/book/my_nfs/buildrootfs,v3,tcp rw'
启动之后:
Welcome to imx6ull my100ask
imx6ull_my100ask login: root
Password:123456
解决外网连接问题;
echo "nameserver 114.114.114.114" > /etc/resolv.conf
route add default gw 10.23.42.28
解决中文显示问题,参考:
【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf 38.2.2第二点
以及参考第三点进行相关busybox配置
4、交叉编译工具链
使用buildroot构建的工程中包含适合我开发板的交叉编译环境
/home/book/my_nfs/buildroot-2019.02.6//output/host/arm-buildroot-linux-gnueabihf/sysroot
猜测以后为我的开发板编译程序时应该配置环境变量:
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/home/book/my_nfs/buildroot-2019.02.6/output/host/bin/
5、保留文件更新根文件系统
在 Buildroot 工程的根目录中创建一个 overlay 目录。这个目录将用于存放你想要添加到最终根文件系统中的自定义文件或目录。接下来,Buildroot 在构建过程中会将这个目录中的内容合并到生成的文件系统中。
具体步骤:
1、进入 Buildroot 项目根目录:
假设你的 Buildroot 工程位于 /path/to/your/project/,你需要进入该目录:
cd /path/to/your/project/
2、创建 Overlay 目录:
在根目录下创建一个名为 overlay 的目录。这是存放自定义文件的地方:
mkdir -p overlay
3、将自定义文件放入 overlay 目录:
你可以根据需要在 overlay 中创建子目录,并放入你需要添加的文件。例如,假设你需要将一个配置文件 my_config.conf 放到 /etc/ 目录下,可以这样做:
mkdir -p overlay/etc
cp /path/to/your/my_config.conf overlay/etc/
4、配置 Buildroot 使用 Overlay:
接下来,你需要告诉 Buildroot 使用这个 overlay 目录。在 Buildroot 配置界面中,启用 Overlay 支持并指定该目录:
make menuconfig
在配置界面中,依次选择:
System configuration ---> Overlay files
5、在 Overlay directory 选项中,设置为你刚才创建的 overlay 目录的路径:
Overlay directory: /path/to/your/project/overlay
6、配置系统时间
make menuconfig
Target packages --->
Networking applications --->
[*] chrony
make
需要先通网
创建/etc/chrony.conf
|
# /etc/chrony.conf |
|
# 使用公共 NTP 服务器 |
|
server 0.pool.ntp.org iburst |
|
server 1.pool.ntp.org iburst |
|
server 2.pool.ntp.org iburst |
|
# 允许与特定 IP 地址的客户端通信 |
|
allow 10.23.43.0/24 |
|
# 设置本地时钟作为备用 |
|
local stratum 10 |
|
# 启用硬件时钟同步 |
|
rtcsync |
|
# 使用默认的时钟源 |
|
driftfile /var/lib/chrony/drift |
|
# 保存当前状态到文件 |
|
log tracking measurements statistics |
启动:
/usr/sbin/chronyd
验证:
chronyc tracking
6.10 Buildroot配置支持qt的根文件系统
1、配置支持qt的Buildroot工程
在Buildroot工程界面打开图形化配置工具配置qt环境;
make menuconfig
配置:
Target packages --->
Graphic libraries and applications (graphic/text) --->
Qt5 --->
这里有很多可选模块,常见的有:
- qtbase(必须,Qt 的核心库)
- qtdeclarative(QML/Quick 支持)
- qtserialport(串口类支持)
- qttools(包含 lrelease, lupdate 等工具)
- qtimageformats(额外图片格式支持)
- qtwayland / qtsvg / qtmultimedia(可选,看你项目需要)
⚠️ 建议最小化选择:先勾选 qtbase,确保能编译最基础的 Qt 程序。
选择显示后端
进入 qtbase 配置后,可以选择:
[*] linuxfb
[*] tslib (触摸屏支持,可选)
后面参考了博客中的配置:https://blog.csdn.net/qq_32605451/article/details/104897859
编译buildroot:
sudo make
编译成功后拷贝到uboot挂载的根文件系统启动目录中
cp ./output/images/rootfs.tar /home/book/my_nfs/buildrootfs/
2、配置qt的开发环境
qmake路径:/home/book/my_nfs/buildroot-2019.02.6/output/host/usr/bin/qmake
接下来需要在qt creator中配置为开发板设置的qt开发环境:
编译器路径:
/home/book/my_nfs/buildroot-2019.02.6/output/host/bin/
中有:
arm-linux-gnueabihf-g++
arm-linux-gnueabihf-gcc
于是在Tools -> Options中开始配置我开发板的qt环境

![]()
配置g++/gcc编译器,使用buildroot工程中构建的交叉编译工具中的编译器

添加qt versions为buildroot工程中构建的交叉编译工具中的qmake


配置直接开发板的编译kits:
注意,之前配置错了,需要将kits中的qt version修改为Qt5 for i.MX6ULL

![]()
3、配置开发板的qt编译环境
export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
4、测试qt在开发板的运行
拷贝程序到开发板文件系统中:
cp /home/book/mycode/Meteorological_terminal_qt/build-untitledMeteorological_app-my_100ask-Debug/untitledMeteorological_app /home/book/my_nfs/buildrootfs/usr/
运行测试
# pwd
/usr
# ./Meteorological_app -platform linuxfb

![]()
运行成功!
开机自启动脚本:
vim /etc/init.d/S99myqt
编辑内容:
1 #!/bin/sh
2 #
3 # Start Qt Application at boot
4 #
5
6 case "$1" in
7 start)
8 echo "Starting Qt application..."
9 export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
10 export QT_QPA_PLATFORM=linuxfb
11 # 如果有触摸屏,启用 tslib
12 # export TSLIB_TSDEVICE=/dev/input/event0
13 # export TSLIB_FBDEVICE=/dev/fb0
14 # export TSLIB_CONFFILE=/etc/ts.conf
15 # export TSLIB_PLUGINDIR=/usr/lib/ts
16
17 /usr/Meteorological_app -platform linuxfb &
18 ;;
19 stop)
20 echo "Stopping Qt application..."
21 killall Meteorological_app
22 ;;
23 restart)
24 $0 stop
25 $0 start
26 ;;
27 *)
28 echo "Usage: $0 {start|stop|restart}"
29 exit 1
30 esac
31 exit 0
添加权限:
chmod +x ./S99myqt
5、解决qt运行问题
解决中文显示问题:
开发板qt默认寻找的字体目录:
/usr/lib/fonts/ //应该是qt在这找到字体
拷贝字体到该目录下:
cp /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc /home/book/my_nfs/buildrootfs/usr/lib/fonts/
更多推荐


所有评论(0)