U-Boot 使用实验

在这里插入图片描述

在上一篇中我们学习了如何进行I.MX6U 的裸机开发,通过21 个裸机例程我们掌握了I.MX6U 的常用外设。通过裸机的学习我们掌握了外设的底层原理,这样在以后进行Linux 驱动开发的时候就只需要将精力放到Linux 驱动框架上,在进行Linux 驱动开发之前肯定需要先将Linux 系统移植到开发板上去。

如果学习过UCOS/FreeRTOS 应该知道,UCOS/FreeRTOS 移植就是在官方的SDK 包里面找一个和自己所使用的芯片一样的工程编译一下,然后下载到开发板就可以了。那么Linux 的移植是不是也是这样的,下载Linux 源码,然后找个和我们所使用的芯片一样的工程编译一下就可以了?很明显不是的!Linux 的移植要复杂的多,在移植Linux之前我们需要先移植一个bootloader 代码,这个bootloader 代码用于启动Linux 内核,常用的就是U-Boot

移植好U-Boot 以后再移植Linux 内核,移植完Linux 内核以后Linux 还不能正常启动,还需要再移植一个根文件系统(rootfs),根文件系统里面包含了一些最常用的命令和文件。所以U-Boot、Linux kernel 和rootfs 这三者一起构成了一个完整的Linux 系统,一个可以正常使用、功能完善的Linux 系统。

本篇我们就来讲解U-Boot、Linux Kernel 和rootfs 的移植,与其说是“移植”,倒不如说是“适配”,因为大部分的移植工作都由NXP 完成了,我们这里所谓的“移植”主要是使其能够在I.MX6U-ALPHA 开发板上跑起来。

在移植U-Boot 之前,我们肯定要先使用一下U-Boot,得先体验一下U-Boot 是个什么东西。
I.MX6U-ALPHA 开发板光盘资料里面已经提供了一个正点原子团队已经移植好的U-Boot,本章我们就直接编译这个移植好的U-Boot,然后烧写到SD 卡里面启动,启动U-Boot 以后就可以学习使用U-Boot 的命令。

U-Boot 简介

Linux 系统要启动就必须需要一个bootloader(裸机程序) 程序,也就说芯片上电以后先运行一段bootloader 程序。这段bootloader 程序会先初始化DDR 等外设(前面学习了I.MX6ULL是内部BOOT ROM初始化DDR的,但是其他大部分ARM架构都是bootloader初始化DDR),然后将Linux 内核从flash(NAND,NOR FLASH,SD,MMC 等)拷贝到DDR 中,最后启动Linux 内核

当然了,bootloader 的实际工作要复杂的多,但是它最主要的工作就是启动Linux 内核,bootloader 和Linux 内核的关系就跟PC 上的BIOS 和Windows 的关系一样,bootloader 就相当于BIOS。所以我们要先搞定bootloader,有很多现成的bootloader 软件可以使用,比如U-Boot、vivi、RedBoot 等等,其中U-Boot 使用最为广泛,为了方便书写,本书会将U-Boot 写为uboot。

uboot 的全称是Universal Boot Loader,uboot 是一个遵循GPL 协议的开源软件,uboot 是一个超级裸机代码(集成各种驱动,只是没有操作系统进程管理相关内容),可以看作是一个裸机综合例程。现在的uboot 已经支持液晶屏、网络、USB 等高级功能。uboot 官网为http://www.denx.de/wiki/U-Boot/,如图30.1.1 所示:

对比一下之前学习的BOOT ROM做的事情:ARM(IMX6U)裸机之I.MX6ULL启动头文件详解(内部BOOT ROM、IVT + Boot data + DCD + led.bin)

类似于我们电脑X86的BIOS。
在这里插入图片描述
SOC厂商,半导体厂商,比如NXP
开发板的厂商,比如正点原子
关于SOC
这个词是System on Chip的缩写,意为片上系统,是将CPU、GPU、内存、基带和GPS模块整合在一起的解决方案,是将系统运行所需的芯片整合在一块芯片上。
我们熟知的骁龙855、苹果的A12、华为的麒麟980和三星的猎户座都是这个片上系统的代号,并非单指某个CPU或是GPU,相反,这些片上系统内其实有自己的CPU和GPU编号。比如A12的GPU是自研的G11P,骁龙855的GPU是Adreno
640。

在这里插入图片描述

图30.1.1 uboot 官网

我们可以在uboot 官网下载uboot 源码,点击图30.1.1 中左侧Topics 中的“Source Code”,打开如图30.1.2 所示界面:

在这里插入图片描述
图30.1.2 uboot 源码界面

点击图30.1.2 中的“FTP Server”,进入其FTP 服务器即可看到uboot 源码,如图30.1.3 所示:

在这里插入图片描述

图30.1.3 uboot 源码

图30.1.3 中就是uboot 原汁原味的源码文件,目前最新的版本是2019.04。但是我们一般不会直接用uboot 官方的U-Boot 源码的。uboot 官方的uboot 源码是给半导体厂商准备的,半导体厂商会下载uboot 官方的uboot 源码,然后将自家相应的芯片移植进去。也就是说半导体厂商会自己维护一个版本的uboot,这个版本的uboot 相当于是他们定制的。既然是定制的,那么肯定对自家的芯片支持会很全,虽然uboot 官网的源码中一般也会支持他们的芯片,但是绝对是没有半导体厂商自己维护的uboot 全面。

在这里插入图片描述

NXP 就维护的2016.03 这个版本的uboot ,下载地址为:
http://git.freescale.com/git/cgit.cgi/imx/uboot-imx.git/tag/?h=imx_v2016.03_4.1.15_2.0.0_ga&id=
rel_imx_4.1.15_2.1.0_ga,下载界面如图30.1.4 所示:

在这里插入图片描述
图30.1.4 NXP 官方uboot 下载界面

图30.1.4 中的uboot-imx_rel_imx4.1.15_2.1.0_ga.xx(xx 为zip、tar.gz 或tar.bz2)就是NXP 官方维护的uboot,后面我们学习uboot 移植的时候就是使用的图30.1.4 中的uboot,下载uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。我们已经放到了开发板光盘中,路径为:开发板光盘->1、程序源码->4、NXP 官方原版Uboot 和Linux->uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。

图30.1.4中的uboot 基本支持了NXP 当前所有可以跑Linux 的芯片,而且支持各种启动方式,比如EMMC、NAND、NOR FLASH 等等,这些都是uboot 官方所不支持的。但是图30.1.4 中的uboot 是针对NXP 自家评估板的,如果是我们自己做的板子就需要修改NXP 官方的uboot,使其支持我们自己做的板子,正点原子的I.MX6U 开发板就是自己做的板子,虽然大部分都参考了NXP 官方的I.MX6ULL EVK 开发板,但是还是有很多不同的地方,所以需要修改NXP 官方的uboot,使其适配正点原子的I.MX6U 开发板。所以当我们拿到开发板以后,是有三种uboot 的,这三种uboot的区别如表30.1.1 所示:

在这里插入图片描述
表30.1.1 三种uboot 的区别

那么这三种uboot 该如何选择呢?首先uboot 官方的基本是不会用的,因为支持太弱了。
最常用的就是半导体厂商或者开发板厂商的uboot,如果你用的半导体厂商的评估板,那么就使用半导体厂商的uboot,如果你是购买的第三方开发板,比如正点原子的I.MX6ULL 开发板,那么就使用正点原子提供的uboot 源码(也是在半导体厂商的uboot 上修改的)。当然了,你也可以在购买了第三方开发板以后使用半导体厂商提供的uboot,只不过有些外设驱动可能不支持,需要自己移植,这个就是我们常说的uboot 移植。

本节是uboot 的使用,直接使用正点原子已经移植好的uboot,这个已经放到了开发板光盘中了,路径为:开发板光盘->1、程序源码->3、正点原子Uboot 和Linux 出厂源码->uboot-imx-2016.03-2.1.0-ge468cdc-v1.5.tar.bz2。

SecureCRT启动显示log

拨码开关拨到从EMMC启动,因为前面将系统烧写进了EMMC里面,板子上电启动,SecureCRT显示启动log信息。
在这里插入图片描述
在这里插入图片描述

U-Boot 初次编译

在这里插入图片描述
上述笔记第三点就是建立shell脚本实现的
第四点就是修改Makefile文件实现的,下面均有实现步骤讲解。

首先在Ubuntu 中安装ncurses 库,否则编译会报错,安装命令如下:

sudo apt-get install libncurses5-dev

在Ubuntu 中创建存放uboot 的目录,比如我的是/home/$USER/linux/uboot,然后在此目录下新建一个名为“alientek_uboot”的文件夹用于存放正点原子提供的uboot 源码。alientek_uboot文件夹创建成功以后使用FileZilla 软件将正点原子提供的uboot 源码拷贝到此目录中,正点原子提供的uboot 源码已经放到了开发板光盘中,路径为:开发板光盘->1、例程源码->3、正点原子Uboot 和Linux 出厂源码-> uboot-imx-2016.03-2.1.0-ge468cdc-v1.5.tar.bz2。将其拷贝到Ubuntu中新建的alientek_uboot 文件夹下,完成以后如图30.2.1 所示:

在这里插入图片描述

图30.2.1 将uboot 拷贝到Ubuntu 中

使用如下命令对其进行解压缩:

tar -vxjf uboot-imx-2016.03-2.1.0-g8b546e4.tar.bz2

解压完成以后alientek_uboot 文件夹内容如图30.2.2 所示:

在这里插入图片描述

图30.2.2 解压后的uboot

图30.2.2 中除了uboot-imx-2016.03-2.1.0-g8b546e4.tar.bz2 这个正点原子提供的uboot 源码压缩包以外,其他的文件和文件夹都是解压出来的uboot 源码。可以发现有Makefile,不过不能直接进行编译,需要先进行配置(因为Makefile是通用的,板子不一样)

1、512MB(DDR3)+8GB(EMMC)核心板
如果使用的是512MB+8GB 的EMMC 核心板,使用如下命令来编译对应的uboot:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- (加空格)
						mx6ull_14x14_ddr512_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12

这三条命令中ARCH=arm 设置目标为arm 架构,CROSS_COMPILE 指定所使用的交叉编译器。第一条命令相当于“make distclean”,目的是清除工程,一般在第一次编译的时候最好清理一下工程。

第二条指令相当于“make mx6ull_14x14_ddr512_emmc_defconfig”,用于配置uboot,配置文件为mx6ull_14x14_ddr512_emmc_defconfig。

最后一条指令相当于“make -j12”也就是使用12 核来编译uboot。当这三条命令执行完以后uboot 也就编译成功了,如图30.2.3 所示:

在这里插入图片描述

图30.2.3 编译完成

编译完成以后的alentek_uboot 文件夹内容如图30.2.4 所示:

在这里插入图片描述

图30.2.4 编译后的uboot 源码

可以看出,编译完成以后uboot 源码多了一些文件,其中u-boot.bin 就是编译出来的uboot二进制文件。uboot 是个裸机程序,因此需要在其前面加上头部(IVT、DCD 等数据) 才能在I.MX6U上执行【联想到前面裸机学习的,I.MX 6ULL中内部BOOT ROM初始化DDR,然后将.bin文件加载到RAM里面运行,这里就是u-boot.bin(需要加头部),然后运行的u-boot程序去引导操作系统运行】,图30.2.4 中的u-boot.imx 文件就是添加头部以后的u-boot.bin,u-boot.imx 就是我们最终要烧写到开发板中的uboot 镜像文件。

每次编译uboot 都要输入一长串命令,为了简单起见,我们可以新建一个shell 脚本文件,将这些命令写到shell 脚本文件里面,然后每次只需要执行shell 脚本即可完成编译工作。

【为了方便,引入shell脚本。其实把Makefile文件进行适当修改,也可以减少输入很多字母,参考上面笔记的第四点,实际操作如下:】
在这里插入图片描述
然后编译的时候只要在命令行输入以下命令即可(交叉编译工具变量直接替换了):
在这里插入图片描述

新建名为mx6ull_alientek_emmc.sh 的shell 脚本文件,然后在里面输入如下内容:

示例代码30.2.1 mx6ull_alientek_emmc.sh 文件代码
1 #!/bin/bash
2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- (加空格) mx6ull_14x14_ddr512_emmc_defconfig
4 make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12
  • 第1 行是shell 脚本要求的,必须是“#!/bin/bash”或者“#!/bin/sh”。
  • 第2 行使用了make 命令,用于清理工程,也就是每次在编译uboot 之前都清理一下工程。这里的make 命令带有三个参数,第一个是ARCH,也就是指定架构,这里肯定是arm;第二个参数CROSS_COMPILE 用于指定编译器,只需要指明编译器前缀就行了,比如arm-linux-gnueabihf-gcc 编译器的前缀就是“arm-linux-gnueabihf-”;最后一个参数distclean 就是清除工程。
  • 第3 行也使用了make 命令,用于配置uboot。同样有三个参数,不同的是,最后一个参数是mx6ull_14x14_ddr512_emmc_defconfig。前面说了uboot 是bootloader 的一种,可以用来引导Linux,但是uboot 除了引导Linux 以外还可以引导其它的系统,而且uboot 还支持其它的架构和外设,比如USB、网络、SD 卡等。这些都是可以配置的,需要什么功能就使能什么功能。所以在编译uboot 之前,一定要根据自己的需求配置uboot。mx6ull_14x14_ddr512_emmc_defconfig就是正点原子针对I.MX6U-ALPHA 的EMMC 核心板编写的配置文件,这个配置文件在uboot源码的configs 目录中。在uboot 中,通过“make xxx_defconfig”来配置uboot,xxx_defconfig就是不同板子的配置文件,这些配置文件都在uboot/configs 目录中。
  • 第4 行有4 个参数,用于编译uboot,通过第3 行配置好uboot 以后就可以直接“make”编译uboot了。其中V=1 用于设置编译过程的信息输出级别;-j 用于设置主机使用多少线程编译uboot,最好设置成我们虚拟机所设置的核心数,如果在VMware 里面给虚拟就分配了4 个核,那么使用-j4 是最合适的,这样4 个核都会一起编译。

使用chmod 命令给予mx6ull_alientek_emmc.sh 文件可执行权限,然后就可以使用这个shell脚本文件来重新编译uboot,命令如下:

./mx6ull_alientek_emmc.sh

2、256MB(DDR3)+ 512MB(NAND)核心板
如果用的256MB+512MB 的NAND 核心板,新建名为mx6ull_alientek_nand.sh 的shell 脚本文件,然后在里面输入如下内容:

示例代码30.2.2 mx6ull_alientek_nand.sh 文件代码
1 #!/bin/bash
2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- (加空格) mx6ull_14x14_ddr256_nand_defconfig
4 make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12

完成以后同样使用chmod 指令给予mx6ull_alientek_nand.sh 可执行权限,然后输入如下命令即可编译NAND 版本的uboot:

./mx6ull_alientek_nand.sh

mx6ull_alientek_nand.sh 和mx6ull_alientek_emmc.sh 类似,只是uboot 配置文件不同,这里就不详细介绍了。

U-Boot 烧写与启动

视频里老师先是演示了简单方便的OTG方式(参照上面笔记的第二点,给.bin添加头使用的也是另一种方式),烧写到EMMC里的。
后面我们还是使用imxdownload软件进行烧写,就像裸机开发一样。因为使用OTG方式不仅把U_boot,还有系统镜像zimage、设备树、根文件系统全部重新烧进去,很费时间,我们只是想更新一个u-boot而已。
在这里插入图片描述

uboot 编译好以后就可以烧写到板子上使用了,这里我们跟前面裸机例程一样,将uboot烧写到SD 卡中,然后通过SD 卡来启动来运行uboot。使用imxdownload 软件烧写,命令如下:

chmod 777 imxdownload //给予imxdownload 可执行权限,一次即可
./imxdownload u-boot.bin /dev/sdd //烧写到SD 卡,不能烧写到/dev/sda 或sda1 设备里面!

等待烧写完成,完成以后将SD 卡插到I.MX6U-ALPHA 开发板上,BOOT 设置从SD 卡启动,使用USB 线将USB_TTL 和电脑连接,也就是将开发板的串口1 连接到电脑上。打开MobaXterm,设置好串口参数并打开,最后复位开发板。在MobaXterm 上出现“Hit any key to stop autoboot: ”倒计时的时候按下键盘上的回车键,默认是3 秒倒计时,在3 秒倒计时结束以后如果没有按下回车键的话uboot 就会使用默认参数来启动Linux 内核了。如果在3 秒倒计时结束之前按下回车键,那么就会进入uboot 的命令行模式,如图30.3.1 所示:

在这里插入图片描述

图30.3.1 uboot 启动过程

从图30.3.1 可以看出,当进入到uboot 的命令行模式以后,左侧会出现一个“=>”标志。
uboot 启动的时候会输出一些信息,这些信息如下所示:

U-Boot 2016.03-gd3f0479 (Aug 07 2020 - 20:47:37 +0800)

CPU: Freescale i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 51C
Reset cause: POR
Board: I.MX6U ALPHA|MINI
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
Display: ATK-LCD-7-1024x600 (1024x600)
Video: 1024x600x24
In: serial
Out: serial
Err: serial
switch to partitions #0, OK
mmc1(part 0) is current device
Net: FEC1
Error: FEC1 address not set.

Normal Boot
Hit any key to stop autoboot: 0
=>
  • 第1 行是uboot 版本号和编译时间,可以看出,当前的uboot 版本号是2016.03,编译时间是2020 年8 月7 日 20 点 47 分。
  • 第3 和第4 行是CPU 信息,可以看出当前使用的CPU 是飞思卡尔的I.MX6ULL(I.MX 以前属于飞思卡尔,然而飞思卡尔被NXP 收购了),频率为792MHz,但是此时运行在396MHz。这颗芯片是工业级的,结温为-40°C~105°C。
  • 第5 行是复位原因,当前的复位原因是POR。I.MX6ULL 芯片上有个POR_B 引脚,将这个引脚拉低即可复位I.MX6ULL。
  • 第6 行是板子名字,当前的板子名字为“I.MX6U ALPHA|MINI”。
  • 第7 行提示I2C 准备就绪。
  • 第8 行提示当前板子的DRAM(内存)为512MB,如果是NAND 版本的话内存为256MB。
  • 第9 行提示当前有两个MMC/SD 卡控制器:FSL_SDHC(0)和FSL_SDHC(1)。I.MX6ULL
    支持两个MMC/SD,正点原子的I.MX6ULL EMMC 核心板上FSL_SDHC(0)接的SD(TF)卡,FSL_SDHC(1)接的EMMC。
  • 第10 和第11 行是LCD 型号,当前的LCD 型号是ATK-LCD-7-1024x600 (1024x600),分辨率为1024x600,格式为RGB888(24 位)。
  • 第12~14 是标准输入、标准输出和标准错误所使用的终端,这里都使用串口(serial)作为终端。
  • 第15 和16 行是切换到emmc 的第0 个分区上,因为当前的uboot 是emmc 版本的,也就是从emmc 启动的。我们只是为了方便将其烧写到了SD 卡上,但是它的“内心”还是EMMC的。所以uboot 启动以后会将emmc 作为默认存储器,当然了,你也可以将SD 卡作为uboot 的存储器,这个我们后面会讲解怎么做。
  • 第17 行是网口信息,提示我们当前使用的FEC1 这个网口,I.MX6ULL 支持两个网口。
  • 第18 行提示FEC1 网卡地址没有设置,后面我们会讲解如何在uboot 里面设置网卡地址。
  • 第20 行提示正常启动,也就是说uboot 要从emmc 里面读取环境变量和参数信息启动Linux内核了。
  • 第21 行是倒计时提示,默认倒计时3 秒,倒计时结束之前按下回车键就会进入Linux 命令行模式。如果在倒计时结束以后没有按下回车键,那么Linux 内核就会启动,Linux 内核一旦启动,uboot 就会寿终正寝。

这个就是uboot 默认输出信息的含义,NAND 版本的uboot 也是类似的,只是NAND 版本的就没有EMMC/SD 相关信息了,取而代之的就是NAND 的信息,比如NAND 容量大小信息。

uboot 是来干活的,我们现在已经进入uboot 的命令行模式了,进入命令行模式以后就可以给uboot 发号施令了。当然了,不能随便发号施令,得看看uboot 支持哪些命令,然后使用这些uboot 所支持的命令来做一些工作。下一节就讲解uboot 命令的使用。

U-Boot 命令使用

进入uboot 的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前uboot 所支持的命令,如图30.4.1 所示:

在这里插入图片描述

图30.4.1 uboot 命令列表

图30.4.1 中只是uboot 的一部分命令,具体的命令列表以实际为准。图30.4.1 中的命令并不是uboot 所支持的所有命令,前面说过uboot 是可配置的,需要什么命令就使能什么命令。所以图30.4.1 中的命令是正点原子提供的uboot 中使能的命令,uboot 支持的命令还有很多,而且也可以在uboot 中自定义命令。这些命令后面都跟有命令说明,用于描述此命令的作用,但是命令具体怎么用呢?我们输入“help(或?) 命令名”既可以查看命令的详细用法,以“bootz”这个命令为例,我们输入如下命令即可查看“bootz”这个命令的用法:

? bootz 或help bootz

结果如图30.4.2 所示:

在这里插入图片描述
图30.4.2 bootz 命令使用说明
图30.4.2 中就详细的列出了“bootz”这个命令的详细,其它的命令也可以使用此方法查询具体的使用方法。接下来我们学习一下一些常用的uboot 命令。

U-Boot信息查询命令

命令描述
bdinfo用于查看板子信息
printenv用于输出环境变量信息
version用于查看 uboot 的版本号

bdinfo 命令

此命令用于查看板子信息,直接输入“bdinfo”即可,结果如下图所示:

在这里插入图片描述

从上图中可以得出 DRAM 的起始地址和大小、启动参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息。

printenv命令

命令“printenv”用于输出环境变量信息, uboot 也支持 TAB 键自动补全功能,输入“print”然后按下 TAB 键就会自动补全命令,直接输入“print”也可以。输入“print”,然后按下回车键,环境变量如下图所示:
在这里插入图片描述

在上图中有很多的环境变量,比如 baudrate、 board_name、 board_rec、 boot_fdt、 bootcmd等等。 uboot 中的环境变量都是字符串,既然叫做环境变量,那么它的作用就和“变量”一样。比如 bootdelay 这个环境变量就表示 uboot 启动延时时间,默认 bootdelay=3,也就默认延时 3秒。前面说的 3 秒倒计时就是由 bootdelay 定义的,如果将 bootdelay 改为 4 的话就会倒计时 4s了。还有串口波特率等等都是环境变量。 uboot 中的环境变量是可以修改的,有专门的命令来修改环境变量的值(下面一节讲到)

version命令

命令 version 用于查看 uboot 的版本号,输入“version”, uboot 版本号如下图所示:
在这里插入图片描述
图30.4.1.3 version 命令结果

从图30.4.1.3 可以看出,当前uboot 版本号为2016.03,2020 年8 月7 日编译的,编译器为
arm-poky-linux-gnueabi-gcc,这是NXP 官方提供的编译器,正点原子出厂系统用的此编译器编译的,但是本教程我们统一使用arm-linux-gnueabihf-gcc。

环境变量操作命令

1、修改环境变量

环境变量的操作涉及到两个命令: setenv 和 saveenv

命令描述
setenv用于设置或者修改环境变量的值
saveenv用于保存修改后的环境变量

一般环境变量是存放在外部 flash 中的,uboot 启动的时候会将环境变量从 flash 读取到 DRAM 中。所以使用命令 setenv 修改的是 DRAM中的环境变量值,修改以后要使用 saveenv 命令将修改后的环境变量保存到 flash 中,否则的话uboot 下一次重启会继续使用以前的环境变量值。

命令 saveenv 使用起来很简单,格式为:

saveenv

比如我们要将环境变量 bootdelay 改为 4,就可以使用如下所示命令:

setenv bootdelay 4
saveenv

查看当前环境变量bootdelay的值:

在这里插入图片描述

此时把他修改成为4:

setenv bootdelay 4
saveenv

在这里插入图片描述
图30.4.2.1 环境变量修改
在图30.4.2.1 中,当我们使用命令saveenv 保存修改后的环境变量的话会有保存过程提示信息,根据提示可以看出环境变量保存到了MMC(0)中,也就是SD 卡中。因为我们现在将uboot烧写到了SD 卡里面,所以会保存到MMC(0)中。如果烧写到EMMC 里面就会提示保存到MMC(1),也就是EMMC 设备,同理,如果是NAND 版本核心板的话就会提示保存到NAND中。

修改 bootdelay 以后,重启开发板, uboot 就是变为 4 秒倒计时,如图下所示

在这里插入图片描述

有时候我们修改的环境变量值可能会有空格, 比如 bootcmd、 bootargs 等, 这个时候环境变量值就得用单引号括起来,比如下面修改环境变量 bootargs 的值:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv

上面命令设置 bootargs 的值为“console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw”,其中“console=ttymxc0,115200”、“root=/dev/mmcblk1p2”、“rootwait”和“rw”相当于四组“值”,这四组“值”之间用空格隔开,所以需要使用单引号‘’将其括起来,表示这四组“值”都属于环境变量 bootargs。

2、新建环境变量

命令 setenv 也可以用于新建命令,用法就是修改环境变量一样,比如我们新建一个环境变量 author, author 的值为我的名字拼音: qingmu,那么就可以使用如下命令:

setenv author qingmu
saveenv

新建命令 author 完成以后重启 uboot,然后使用命令 printenv 查看当前环境变量,如下图所示:

在这里插入图片描述

从上图可以看到新建的环境变量: author,其值为: qingmu

3、删除环境变量

既然可以新建环境变量,那么就可以删除环境变量,删除环境变量也是使用命令 setenv,要删除一个环境变量只要给这个环境变量赋空值即可,比如我们删除掉上面新建的 author 这个环境变量,命令如下:

setenv author
saveenv

在这里插入图片描述
上面命令中通过 setenv 给 author 赋空值,也就是什么都不写来删除环境变量 author。重启uboot 就会发现环境变量 author 没有了。

内存操作命令

内存操作命令就是用于直接对 DRAM 进行读写操作的。前面讲了,u-boot一个是初始化DDR等硬件的操作,再一个就是引导操作系统启动,所以肯定要和DDR内存打交道。常用的内存操作命令有 md、 nm、mm、 mw、 cp 和 cmp。

命令描述
md用于显示内存值
nm用于修改指定地址的内存值
mm用于修改指定地址的内存值
mw用于使用一个指定的数据填充一段内存
cp用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 NorFlash 中的数据拷贝到 DRAM 中
cmp用于比较两段内存的数据是否相等

1、 md 命令

md 命令用于显示内存值,格式如下:

md[.b, .w, .l] address [# of objects]

命令中的[.b .w .l]对应 byte、 word 和 long,也就是分别以 1 个字节、 2 个字节、 4 个字节来显示内存值address 就是要查看的内存起始地址, [# of objects]表示要查看的数据长度,这个数据长度单位不是字节,而是跟你所选择的显示格式有关。

比如你设置要查看的内存长度为20(十六进制为 0x14)

  • 如果显示格式为.b 的话那就表示 20 个字节;
  • 如果显示格式为.w 的话就表示 20 个 word,也就是 202=40 个字节;
  • 如果显示格式为.l 的话就表示 20 个 long,也就是204=80 个字节。

另外要注意:

uboot 命令中的数字都是十六进制的!不是十进制的!

比如你想查看以 0X80000000 开始的 20 个字节的内存值,显示格式为.b 的话,应该使用如下所示命令:

md.b 80000000 14

而不是

md.b 80000000 20

上面说了, uboot 命令里面的数字都是十六进制的,所以可以不用写“0x”前缀,十进制的 20 其十六进制为 0x14,所以命令 md 后面的个数应该是 14,如果写成 20 的话就表示查看32(十六进制为 0x20)个字节的数据。

分析下面三个命令的区别:

md.b 80000000 10
md.w 80000000 10
md.l 80000000 10

上面这三个命令都是查看以0X80000000 为起始地址的内存数据,第一个命令以.b 格式显示,长度为0x10,也就是16 个字节;第二个命令以.w 格式显示,长度为0x10,也就是162=32个字节;最后一个命令以.l 格式显示,长度也是0x10,也就是164=64 个字节。这三个命令的执行结果如图30.4.3.1 所示:
在这里插入图片描述
图30.4.3.1 md 命令使用示例

2、 nm 命令

nm 命令用于修改指定地址的内存值,命令格式如下:

nm [.b, .w, .l] address

nm 命令同样可以以.b、 .w 和.l 来指定操作格式,比如现在以.l 格式修改 0x80000000 地址的数据为 0x12345678。输入命令:

nm.l 80000000

输入上述命令以后如下图所示:
在这里插入图片描述
在上图中, 80000000 表示现在要修改的内存地址, efffe177 表示地址 0x80000000 现在的数据,?后面就可以输入要修改后的数据 0x12345678,输入完成以后按下回车,然后再输入‘q’即可退出,如下图所示:
在这里插入图片描述
修改完成以后在使用命令 md 来查看一下有没有修改成功,如下图所示:
在这里插入图片描述

从上图可以看出,此时地址 0X80000000 的值变为了 0x12345678。

3、 mm 命令

mm 命令也是修改指定地址内存值的,使用 mm 修改内存值的时候**地址会自增**,而使用命令 nm 的话地址不会自增。比如以.l 格式修改从地址 0x80000000 开始的连续 3 个内存块(3*4=12个字节)的数据为 0X05050505,操作如下图所示:
在这里插入图片描述
从上图可以看出,修改了地址 0X80000000、 0X80000004 和 0X80000008 的内容为0x05050505。使用命令 md 查看修改后的值,结果如下图所示:
在这里插入图片描述
从上图可以看出内存数据修改成功。

4、 mw 命令

命令 mw 用于使用一个指定的数据填充一段内存,命令格式如下:

mw [.b, .w, .l] address value [count]

mw 命令同样可以以.b、 .w 和.l 来指定操作格式, address 表示要填充的内存起始地址, value为要填充的数据, count 是填充的长度。比如使用.l 格式将以 0X80000000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0X0A0A0A0A,命令如下:

mw.l 80000000 0A0A0A0A 10

然后使用命令 md 来查看,如下图所示:
在这里插入图片描述
从上图可以看出内存数据修改成功.

5、 cp 命令

cp是数据拷贝命令,用于将DRAM中的数据从一段内存拷贝到另一段内存,或者将Nor Flash中的数据拷贝到DRAM中。命令格式如下:

cp [.b, .w, .l] source target count

cp 命令同样可以以.b、 .w 和.l 来指定操作格式, source 为源地址, target 为目的地址, count为拷贝的长度。我们使用.l 格式将 0x80000000 处的地址拷贝到 0X80000100 处,长度为 0x10 个内存块(0x10 * 4=64 个字节),命令如下所示:

cp.l 80000000 80000100 10

结果如下图所示:

在这里插入图片描述

在上图中,先使用 md.l 命令打印出地址 0x80000000 和 0x80000100 处的数据,然后使用命令cp.l将0x80000000处的数据拷贝到0x80000100处。最后使用命令md.l查看0x80000100处的数据有没有变化,检查拷贝是否成功。

6、 cmp 命令

cmp 是比较命令,用于比较两段内存的数据是否相等,命令格式如下:

cmp [.b, .w, .l] addr1 addr2 count

cmp 命令同样可以以.b、 .w 和.l 来指定操作格式, addr1 为第一段内存首地址, addr2 为第二段内存首地址, count 为要比较的长度。我们使用.l 格式来比较 0x80000000 和 0X80000100 这两个地址数据是否相等,比较长度为 0x10 个内存块(16 * 4=64 个字节),命令如下所示:

cmp.l 80000000 80000100 10

结果如下图所示:
在这里插入图片描述
从上图可以看出两段内存的数据相等。 我们再随便挑两段内存比较一下,比如地址0x80002000 和 0x800003000,长度为 0X10,比较结果如下图所示:

在这里插入图片描述
从上图可以看出, 0x80002000 处的数据和 0x80003000 处的数据就不一样

网络操作命令

uboot 是支持网络的,我们在移植uboot 的时候一般都要调通网络功能,因为在移植linux kernel 的时候需要使用到uboot 的网络功能做调试。uboot 支持大量的网络相关命令,比如dhcp、ping、nfs 和tftpboot,我们接下来依次学习一下这几个和网络有关的命令。

在使用uboot 的网络功能之前先用网线将开发板的ENET2 接口和电脑或者路由器连接起来,I.MX6U-ALPHA 开发板有两个网口:ENET1 和ENET2,一定要连接ENET2,不能连接错了,ENET2 接口如图30.4.4.1 所示。

在这里插入图片描述

图30.4.4.1 ENET2 网络接口
在这里插入图片描述
建议开发板和主机 PC 都连接到同一个路由器上!最后设置下表中所示的几个环境变量(前面学到的)。

环境变量描述
ipaddr开发板 ip 地址,可以不设置,使用 dhcp 命令来从路由器获取 IP 地址。
ethaddr开发板的 MAC 地址,一定要设置。
gatewayip网关地址。
netmask子网掩码。
serverip服务器 IP 地址,也就是 Ubuntu 主机 IP 地址,用于调试代码。

表30.4.4.1 网络相关环境变量
表30.4.4.1 中环境变量设置命令如下所示:

setenv ipaddr 192.168.1.50
setenv ethaddr b8:ae:1d:01:00:00
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.253
saveenv

注意:
注意,网络地址环境变量的设置要根据自己的实际情况,确保Ubuntu 主机和开发板的IP地址在同一个网段内,比如我现在的开发板和电脑都在192.168.1.0 这个网段内,所以设置开发板的IP 地址为192.168.1.50,我的Ubuntu 主机的地址为192.168.1.253,因此serverip 就是192.168.1.253。ethaddr 为网络MAC 地址,是一个48bit 的地址,如果在同一个网段内有多个开发板的话一定要保证每个开发板的ethaddr 是不同的,否则通信会有问题!设置好网络相关的环境变量以后就可以使用网络相关命令了。

1、 ping 命令

开发板的网络能否使用,是否可以和服务器(Ubuntu 主机)进行通信,通过ping 命令就可以验证,直接ping 服务器的IP 地址即可,比如我的服务器IP 地址为192.168.1.253,命令如下:(前提是板子要设置好IP地址,参照上面的步骤):

ping 192.168.1.253

结果如图30.4.4.2 所示:
在这里插入图片描述
图30.4.4.2 ping 命令

从图30.4.4.2 可以看出,192.168.1.253 这个主机存在,说明ping 成功,uboot 的网络工作正常。

注意!只能在 uboot 中 ping 其他的机器,其他机器不能 ping uboot,因为 uboot 没有对 ping命令做处理,如果用其他的机器 ping uboot 的话会失败!

2、 dhcp 命令

dhcp 用于从路由器获取 IP 地址,前提得开发连接到路由器上的,如果开发板是和电脑直连的,那么 dhcp 命令就会失效。直接输入 dhcp 命令即可通过路由器获取到 IP 地址,如下图所示:

在这里插入图片描述

图30.4.4.3 dhcp 命令

从图30.4.4.3 可以看出,开发板通过dhcp 获取到的IP 地址为192.168.1.137。同时在图30.4.4.3 中可以看到“warning:no boot file name;”、“TFTP from server 192.168.1.1”这样的字样。

这是因为DHCP 不单单是获取IP 地址,其还会通过TFTP 来启动linux 内核,输入“? dhcp”即可查看dhcp 命令详细的信息,如图30.4.4.4 所示:

在这里插入图片描述
图30.4.4.4 dhcp 命令使用查询

3、 nfs 命令

前面裸机部分讲到过这个,参照博文:Ubuntu开启NFS、SSH服务(驱动开发用到、电脑端登录ARM板用到)

nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源,比如我们将 linux 镜像和设备树文件放到 Ubuntu 中,然后在 uboot 中使用 nfs 命令将 Ubuntu 中的 linux 镜像和设备树下载到开发板的 DRAM 中整体逻辑就是:板子先运行u-boot,然后用网络nfs命令将内核镜像由ubuntu复制到板子上来,然后由u-boot再去引导内核启动,具体怎么启动后面继续学习。
这样做的目的是为了方便调试 linux 镜像和设备树(少了前面需要烧写的步骤)也就是网络调试,通过网络调试是 Linux 开发中最常用的调试方法。

原因是嵌入式 linux开发不像单片机开发,可以直接通过 JLINK 或 STLink 等仿真器将代码直接烧写到单片机内部的 flash中,嵌入式 Linux 通常是烧写到 EMMC、 NAND Flash、 SPI Flash 等外置 flash 中,但是嵌入式 Linux开发也没有 MDK, IAR 这样的 IDE,更没有烧写算法,因此不可能通过点击一个“download”按钮就将固件烧写到外部 flash中。虽然半导体厂商一般都会提供一个烧写固件的软件,但是这个软件使用起来比较复杂,这个烧写软件一般用于量产的。其远没有 MDK、 IAR的一键下载方便,在 Linux内核调试阶段,如果用这个烧写软件的话将会非常浪费时间!而这个时候网络调试的优势就显现出来了,可以通过网络将编译好的 linux镜像和设备树文件下载到 DRAM 中,然后就可以直接运行。

我们一般使用 uboot 中的 nfs 命令将 Ubuntu 中的文件下载到开发板的 DRAM 中,在使用之前需要开启 Ubuntu 主机的 NFS 服务,并且要新建一个 NFS 使用的目录,以后所有要通过NFS 访问的文件都需要放到这个 NFS 目录中。Ubuntu 的NFS 服务开启我们在4.2.1 小节已经详细讲解过了,包括NFS 文件目录的创建,如果忘记的话可以去查看一下4.2.1 小节。NFS服务的开启参考:NFS开启 我设置的/home/qiaoqiao/linux/nfs 这个目录为我的 NFS 文件目录。

在这里插入图片描述
uboot 中的 nfs 命令格式如下所示:

nfs [loadAddress] [[hostIPaddr:]bootfilename]

loadAddress 是要保存的 DRAM 地址, [[hostIPaddr:]bootfilename]是要下载的文件地址。这里我们将正点原子官方编译出来的 Linux 镜像文件 zImage 下载到开发板 DRAM 的 0x80800000这个地址处

正点原子编译出来的zImage 文件已经放到了开发板光盘中,路径为:8、系统镜像->1、出厂系统镜像->2、kernel 镜像\linux-imx-4.1.15-2.1.0-gbfed875-v1.6 ->zImage。将文件zImage 通过FileZilla 发送到Ubuntu 中的NFS 目录下,比如我的就是放到/home/zuozhongkai/linux/nfs 这个目录下,完成以后的NFS 目录如图30.4.4.5 所示:

在这里插入图片描述

图30.4.4.5 NFS 目录中的zImage 文件

准备好以后就可以使用nfs 命令来将zImage 下载到开发板DRAM 的0X80800000 地址处,命令如下:

nfs 80800000 192.168.1.253:/home/zuozhongkai/linux/nfs/zImage

命令中的“80800000 ”表示zImage 保存地址,
“192.168.1.253:/home/zuozhongkai/linux/nfs/zImage”表示zImage 在192.168.1.253 这个主机中,路径为/home/zuozhongkai/linux/nfs/zImage。下载过程如图30.4.4.6 所示:

在这里插入图片描述

图30.4.4.6 nfs 命令下载zImage 过程
在图30.4.4.6 中会以“#”提示下载过程,下载完成以后会提示下载的数据大小,这里下载的6785272 字节(出厂系统在不断的更更新中,因此以实际的zImage 大小为准),而zImage 的大小就是6785272 字节,如图30.4.4.7 所示:

在这里插入图片描述
图30.4.4.7 zImage 大小
下载完成以后查看0x80800000 地址处的数据,使用命令md.b 来查看前0x100 个字节的数据,如图30.4.4.8 所示:
在这里插入图片描述
图30.4.4.8 下载的数据
在使用winhex 软件来查看zImage,检查一下前面的数据是否和图30.4.4.8 只的一致,结果如图30.4.4.9 所示:
在这里插入图片描述
图30.4.4.9 winhex 查看zImage
可以看出图30.4.4.8 和图30.4.4.9 中的前100 个字节的数据一致,说明nfs 命令下载到的zImage 是正确的。

4、 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/zuozhongkai/linux/tftpboot
chmod 777 /home/zuozhongkai/linux/tftpboot

这样我就在我的电脑上创建了一个名为tftpboot 的目录( 文件夹) ,路径为/home/zuozhongkai/linux/tftpboot。注意!我们要给tftpboot 文件夹权限,否则的话uboot 不能从tftpboot 文件夹里面下载文件。

最后配置tftp,安装完成以后新建文件/etc/xinetd.d/tftp,如果没有/etc/xinetd.d 目录的话自行创建,然后在里面输入如下内容:

在这里插入图片描述

server tftp
{
	socket_type = dgram
	protocol = udp
	wait = yes
	user = root
	server = /usr/sbin/in.tftpd
	server_args = -s /home/zuozhongkai/linux/tftpboot/
	disable = no
	per_source = 11
	cps = 100 2
	flags = IPv4
}

完了以后启动 tftp 服务,命令如下:

sudo service tftpd-hpa start

打开/etc/default/tftpd-hpa 文件,将其修改为如下所示内容:
在这里插入图片描述

# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/zuozhongkai/linux/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="-l -c -s"

TFTP_DIRECTORY 就是我们上面创建的 tftp 文件夹目录,以后我们就将所有需要通过TFTP 传输的文件都放到这个文件夹里面,并且要给予这些文件相应的权限。

最后输入如下命令, 重启 tftp 服务器:

sudo service tftpd-hpa restart

tftp 服务器已经搭建好了,接下来就是使用了。将 zImage 镜像文件拷贝到 tftpboot 文件夹中,并且给予 zImage 相应的权限,命令如下:

cp zImage /home/zuozhongkai/linux/tftpboot/
cd /home/zuozhongkai/linux/tftpboot/
chmod 777 zImage

万事俱备,只剩验证了, uboot 中的 tftp 命令格式如下:

tftpboot [loadAddress] [[hostIPaddr:]bootfilename]

看 起 来 和 nfs 命 令 格式 一 样 的 , loadAddress 是 文 件 在 DRAM 中 的存 放 地 址 ,[[hostIPaddr:]bootfilename]是要从 Ubuntu 中下载的文件。但是和 nfs 命令的区别在于, tftp 命令不需要输入文件在 Ubuntu 中的完整路径,只需要输入文件名即可。比如我们现在将 tftpboot 文件夹里面的 zImage 文件下载到开发板 DRAM 的 0X80800000 地址处,命令如下:

tftp 80800000 zImage

下载过程如图30.4.4.10 所示:
在这里插入图片描述
图30.4.4.10 tftp 命令下载过程
从图30.4.4.10 可以看出,zImage 下载成功了,网速为1.4MibB/s,文件大小为6071136 字节。同样的,可以使用md.b 命令来查看前100 个字节的数据是否和图30.4.4.9 中的相等。有时候使用tftp 命令从Ubuntu 中下载文件的时候会出现如图30.4.4.11 所示的错误提示:
在这里插入图片描述
图30.4.4.11 tftp 下载出错
在图30.4.4.11 中可以看到“TFTP error: ‘Permission denied’ (0)”这样的错误提示,提示没有
权限,出现这个错误一般有两个原因:
①、在Ubuntu 中创建tftpboot 目录的时候没有给予tftboot 相应的权限。
②、tftpboot 目录中要下载的文件没有给予相应的权限。
针对上述两个问题,使用命令“chmod 777 xxx”来给予权限,其中“xxx”就是要给予权限的文件或文件夹。
好了,uboot 中关于网络的命令就讲解到这里,我们最常用的就是ping、nfs 和tftp 这三个命令。使用ping 命令来查看网络的连接状态,使用nfs 和tftp 命令来从Ubuntu 主机中下载文件。

MMC(EMMC和SD卡)操作命令

uboot 支持 EMMC 和 SD 卡,因此也要提供 EMMC 和 SD 卡的操作命令。一般认为 EMMC和 SD 卡是同一个东西,所以没有特殊说明,统一使用 MMC 来代指 EMMC 和 SD 卡

uboot 中常用于操作 MMC 设备的命令为“mmc”

mmc 是一系列的命令,其后可以跟不同的参数,输入“? mmc”即可查看 mmc 有关的命令,如下图所示:
在这里插入图片描述
图30.4.5.1 mmc 命令

从上图可以看出, mmc 后面跟不同的参数可以实现不同的功能,如下表所示:

命令描述
mmc info输出 MMC 设备信息
mmc read读取 MMC 中的数据。
mmc wirte向 MMC 设备写入数据。
mmc rescan扫描 MMC 设备。
mmc part列出 MMC 设备的分区。
mmc dev切换 MMC 设备。
mmc list列出当前有效的所有 MMC 设备。
mmc hwpartition设置 MMC 设备的分区。
mmc bootbus……设置指定 MMC 设备的 BOOT_BUS_WIDTH 域的值。
mmc bootpart……设置指定 MMC 设备的 boot 和 RPMB 分区的大小。
mmc partconf……设置指定 MMC 设备的 PARTITION_CONFG 域的值。
mmc rst复位 MMC 设备
mmc setdsr设置 DSR 寄存器的值。

1、 mmc info 命令

mmc info 命令用于输出当前选中的 mmc info 设备的信息,输入命令“mmc info”即可,如下图所示:
在这里插入图片描述
图30.4.5.2 mmc info 命令
从图30.4.5.2 可以看出,当前选中的MMC 设备是EMMC,版本为5.0,容量为7.1GiB(EMMC
为8GB),速度为52000000Hz=52MHz,8 位宽的总线。还有一个与mmc info 命令相同功能的命令:mmcinfo,“mmc”和“info”之间没有空格。实际量产的EMMC 核心板所使用的EMMC芯片是多厂商供应的,因此EMMC 信息以实际为准,但是容量都为8GB 的!

2、 mmc rescan 命令

mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备,包括 EMMC 和 SD 卡,输入“mmc rescan”即可。
在这里插入图片描述

3、 mmc list 命令

mmc list 命令用于来查看当前开发板一共有几个 MMC 设备,输入“mmc list”
在这里插入图片描述

图30.4.5.3 扫描MMC 设备
可以看出当前开发板有两个MMC 设备:FSL_SDHC:0 和FSL_SDHC:1 (eMMC),这是因为我现在用的是EMMC 版本的核心板,加上SD 卡一共有两个MMC 设备,FSL_SDHC:0 是SD卡,FSL_SDHC:1(eMMC)是EMMC,。默认会将EMMC 设置为当前MMC 设备,这就是为什么输入“mmc info”查询到的是EMMC 设备信息,而不是SD 卡。要想查看SD 卡信息,就要使用命令“mmc dev”来将SD 卡设置为当前的MMC 设备。

4、 mmc dev 命令

mmc dev 命令用于切换当前 MMC 设备,命令格式如下:

mmc dev [dev] [part]

[dev]用来设置要切换的MMC 设备号,[part]是分区号。如果不写分区号的话默认为分区0。使用如下命令切换到SD 卡:

mmc dev 0 //切换到SD 卡,0 为SD 卡,1 为eMMC

结果如下图所示:
在这里插入图片描述
图30.4.5.4 切换到SD 卡
从图30.4.5.4 可以看出,切换到SD 卡成功,mmc0 为当前的MMC 设备,输入命令“mmc info”即可查看SD 卡的信息,结果如图30.4.5.5 所示:

在这里插入图片描述
图30.4.5.5 SD 信息
从图30.4.5.5 可以看出当前SD 卡为3.0 版本的,容量为14.8GiB(16GB 的SD 卡),4 位宽的总线。

5、 mmc part 命令

有时候 SD 卡或者 EMMC 会有多个分区,可以使用命令“mmc part”来查看其分区,比如查看 EMMC 的分区情况,输入如下命令:

mmc dev 1 //切换到EMMC
mmc part //查看EMMC 分区

结果如图30.4.5.6 所示:
在这里插入图片描述
图30.4.5.6 查看EMMC 分区
从图30.4.5.6 中可以看出,此时EMMC 有两个分区,第一个分区起始扇区为20480,长度为262144 个扇区;第二个分区起始扇区为282624,长度为14594048 个扇区。如果EMMC 里面烧写了Linux 系统的话,EMMC 是有3 个分区的,第0 个分区存放uboot,第1 个分区存放Linux 镜像文件和设备树,第2 个分区存放根文件系统。但是在图30.4.5.6 中只有两个分区,那是因为第0 个分区没有格式化,所以识别不出来,实际上第0 个分区是存在的。一个新的SD卡默认只有一个分区,那就是分区0,所以前面讲解的uboot 烧写到SD 卡,其实就是将u-boot.bin烧写到了SD 卡的分区0 里面。后面学习Linux 内核移植的时候再讲解怎么在SD 卡中创建并格式化第二个分区,并将Linux 镜像文件和设备树文件存放到第二个分区中。
如果要将EMMC 的分区2 设置为当前MMC 设备,可以使用如下命令:

mmc dev 1 2

结果如图30.4.5.7 所示:

在这里插入图片描述
图30.4.5.7 设置EMMC 分区2 为当前设备

6、 mmc read 命令

mmc read 命令用于读取 mmc 设备的数据,命令格式如下:

mmc read addr blk# cnt

addr 是数据读取到 DRAM 中的地址, blk 是要读取的块起始地址(十六进制),一个块是 512字节,这里的块和扇区是一个意思,在 MMC 设备中我们通常说扇区, cnt 是要读取的块数量(十六进制)。比如从 EMMC 的第 1536(0x600)个块开始,读取 16(0x10)个块的数据到 DRAM 的0X80800000 地址处,命令如下:

mmc dev 1 0 //切换到MMC 分区0
mmc read 80800000 600 10 //读取数据

结果如图30.4.5.8 所示:
在这里插入图片描述
图30.4.5.8 mmc read 命令
这里我们还看不出来读取是否正确,通过md.b 命令查看0x80800000 处的数据就行了,查看16*512=8192(0x2000)个字节的数据,命令如下:

md.b 80800000 2000

结果如图30.4.5.9 所示:
在这里插入图片描述

图30.4.5.9 读取到的数据(部分截图)

从图30.4.5.9 可以看到“baudrate=115200.board_name=EVK.board_rev=14X14.”等字样,这个就是uboot 中的环境变量。EMMC 核心板uboot 环境变量的存储起始地址就是1536*512=786432。

7、 mmc write 命令

要将数据写到 MMC 设备里面(ubuntn先写到DDR,然后再写到MMC),可以使用命令“mmc write”,格式如下:

mmc write addr blk# cnt

addr 是要写入 MMC 中的数据在 DRAM 中的起始地址, blk 是要写入 MMC 的块起始地址(十六进制), cnt 是要写入的块大小,一个块为 512 字节。我们可以使用命令“mmc write”来升级 uboot,也就是在 uboot 中更新 uboot。这里要用到 nfs 或者 tftp 命令,通过 nfs 或者 tftp 命令将新的 u-boot.bin 下载到开发板的 DRAM 中,然后再使用命令“mmc write”将其写入到 MMC设备中。我们就来更新一下 SD 中的 uboot,先查看一下 SD 卡中的 uboot 版本号,注意编译时间,输入命令:

mmc dev 0 //切换到 SD 卡
version //查看版本号

结果如图30.4.5.10 所示:
在这里插入图片描述

图30.4.5.10 uboot 版本查询
可以看出当前SD 卡中的uboot 是2020 年3 月12 日15:11:51 编译的。我们现在重新编译一下uboot,然后将编译出来的u-boot.imx(u-boot.bin 前面加了一些头文件)拷贝到Ubuntu 中的tftpboot 目录下。最后使用tftp 命令将其下载到0x80800000 地址处,命令如下:

tftpboot 80800000 u-boot.imx

下载过程如图30.4.5.11 所示:
在这里插入图片描述
图30.4.5.11 u-boot.imx 下载过程
可以看出,u-boot.imx 大小为379904 字节,379904/512=742,所以我们要向SD 卡中写入742 个块,如果有小数的话就要加1 个块。使用命令“mmc write”从SD 卡分区0 第2 个块(扇区)开始烧写,一共烧写742(0x2E6)个块,命令如下:

mmc dev 0 0
mmc write 80800000 2 2E6

烧写过程如图30.4.5.12 所示:
在这里插入图片描述
图30.4.5.12 烧写过程
烧写成功,重启开发板(从SD 卡启动),重启以后再输入version 来查看版本号,结果如图30.4.5.13 所示:
在这里插入图片描述

图30.4.5.13 uboot 版本号
从图30.4.5.13 可以看出,此时的uboot 是2020 年10 月27 号11:44:31 编译的,说明uboot更新成功。这里我们就学会了如何在uboot 中更新uboot 了,如果要更新EMMC 中的uboot 也是一样的。
同理,如果要在uboot 中更新EMMC 对应的uboot,可以使用如下所示命令:

mmc dev 1 0 //切换到EMMC 分区0
tftp 80800000 u-boot.imx //下载u-boot.imx 到DRAM
mmc write 80800000 2 32E //烧写u-boot.imx 到EMMC 中
mmc partconf 1 1 0 0 //分区配置,EMMC 需要这一步!

千万不要写SD 卡或者EMMC 的前两个块(扇区),里面保存着分区表!

8、 mmc erase 命令

如果要擦除 MMC 设备的指定块就是用命令“mmc erase”,命令格式如下:

mmc erase blk# cnt

blk 为要擦除的起始块,cnt 是要擦除的数量。没事不要用mmc erase 来擦除MMC 设备!!!
关于MMC 设备相关的命令就讲解到这里,表30.4.5.1 中还有一些跟MMC 设备操作有关的命令,但是很少用到,这里就不讲解了,感兴趣的可以上网查一下,或者在uboot 中查看这些命令的使用方法。

FAT 格式文件系统操作命令

前面树莓派讲系统移植的时候讲到过这个。
第一个分区u-boot,将SD卡插到电脑上是识别不出来的。
这里是引用

有时候需要在uboot 中对SD 卡或者EMMC 中存储的文件进行操作,这时候就要用到文件操作命令,跟文件操作相关的命令有:fatinfo、fatls、fstype、fatload 和fatwrite,但是这些文件操作命令只支持FAT 格式的文件系统!!

命令描述
fatinfo用于查询指定 MMC 设置指定分区的文件系统信息
fatls用于查询 FAT 格式设备的目录和文件信息
fstype查看 MMC 设备某个分区的文件系统格式
fatload用于将指定的文件读取到 DRAM 中
fatwrite用于将 DRAM 中的数据写入到 MMC 设备中

1、 fatinfo 命令

fatinfo 命令用于查询指定 MMC 设置指定分区的文件系统信息,格式如下:

fatinfo <interface> [<dev[:part]>]

interface 表示接口,比如 mmc, dev 是查询的设备号, part 是要查询的分区。比如我们要查询 EMMC 分区 1 的文件系统信息,命令如下:

fatinfo mmc 1:1

结果如下图所示:
在这里插入图片描述

从上图可以看出,EMMC 分区1 的文件系统为FAT32 格式的。

2、 fatls 命令

fatls 命令用于查询FAT 格式设备的目录和文件信息,命令格式如下:

fatls <interface> [<dev[:part]>] [directory]

interface 是要查询的接口,比如mmc,dev 是要查询的设备号,part 是要查询的分区,directory是要查询的目录。比如查询EMMC 分区1 中的所有的目录和文件,输入命令:

fatls mmc 1:1

结果如下图所示:
在这里插入图片描述

从上图可以看出, emmc 的分区 1 中存放着八个文件: zimage 和 imx6ull-14x14-evk.dtb文件,这些文件分别是 linux 镜像文件和设备树。并且在 emmc 的分区 1 中有八个文件,没有目录.

3、 fstype 命令

fstype 用于查看 MMC 设备某个分区的文件系统格式,命令格式如下:

fstype <interface> <dev>:<part>

正点原子EMMC 核心板上的EMMC 默认有3 个分区,我们来查看一下这三个分区的文件系统格式,输入命令:

fstype mmc 1:0
fstype mmc 1:1
fstype mmc 1:2

结果如下图所示:
在这里插入图片描述

从上图可以看出,分区0 格式未知,因为分区0 存放的uboot,并且分区0 没有格式化,所以文件系统格式未知。分区1 的格式为fat,分区1 用于存放linux 镜像和设备树。分区2 的格式为ext4,用于存放Linux 的根文件系统(rootfs)。

4、 fatload 命令(u-boot启动系统所用命令)

fatload 命令用于将指定的EMMC、SD里的文件读取到 DRAM 中,命令格式如下:

fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]

interface 为接口,比如 mmc, dev 是设备号, part 是分区, addr 是保存在 DRAM 中的起始地址, filename 是要读取的文件名字。 bytes 表示读取多少字节的数据,如果 bytes 为 0 或者省略的话表示读取整个文件。 pos 是要读的文件相对于文件首地址的偏移,如果为 0 或者省略的话表示从文件首地址开始读取。我们将 EMMC 分区 1 中的 zImage 文件读取到 DRAM 中的0X80800000 地址处,命令如下:

fatload mmc 1:1 80800000 zImage

操作过程如下图所示:
在这里插入图片描述

从上图可以看出在225ms 内读取了6785272 个字节的数据,速度为28.8MiB/s,速度是非常快的,因为这是从EMMC 里面读取的,而EMMC 是8 位的,速度肯定会很快的。

5、 fatwrite 命令

注意! uboot 默认没有使能 fatwrite 命令,需要修改板子配置头文件,比如 mx6ullevk.h、mx6ull_alientek_emmc.h 等等,板子不同,其配置头文件也不同。找到自己开发板对应的配置头文件然后添加如下一行宏定义来使能 fatwrite 命令:

#define CONFIG_FAT_WRITE /* 使能 fatwrite 命令 */

fatwirte 命令用于将 DRAM 中的数据写入到 MMC 设备中,命令格式如下:

fatwrite <interface> <dev[:part]> <addr> <filename> <bytes>

interface 为接口,比如mmc,dev 是设备号,part 是分区,addr 是要写入的数据在DRAM中的起始地址,filename 是写入的数据文件名字,bytes 表示要写入多少字节的数据。我们可以通过fatwrite 命令在uboot 中更新linux 镜像文件和设备树。我们以更新linux 镜像文件zImage为例,首先将正点原子I.MX6U-ALPHA 开发板提供的zImage 镜像文件拷贝到Ubuntu 中的tftpboot 目录下,zImage 镜像文件放到了开发板光盘中,路径为:开发板光盘->8、系统镜像->1、出厂系统镜像->2、kernel 镜像->linux-imx-4.1.15-2.1.0-gbfed875-v1.6->zImage。
拷贝完成以后使用命令tftp 将zImage 下载到DRAM 的0X80800000 地址处,命令如下:

tftp 80800000 zImage

下载过程如图30.4.6.5 所示:
在这里插入图片描述

图30.4.6.5 zImage 下载过程
zImage 大小为6785272(0X6788f8)个字节(注意,由于开发板系统在不断的更新中,因此zImage 大小不是固定的,一切以实际大小为准),接下来使用命令fatwrite 将其写入到EMMC 的分区1 中,文件名字为zImage,命令如下:

fatwrite mmc 1:1 80800000 zImage 6788f8

结果如图30.4.6.6 所示:
在这里插入图片描述
图30.4.6.6 将zImage 烧写到EMMC 扇区1 中
完成以后使用“fatls”命令查看一下EMMC 分区1 里面的文件,结果如图30.4.6.7 所示:
在这里插入图片描述
图30.4.6.7 EMMC 分区1 里面的文件

EXT 格式文件系统操作命令

uboot 有ext2 和ext4 这两种格式的文件系统的操作命令,常用的就四个命令,分别为:
ext2load、ext2ls、ext4load、ext4ls 和ext4write。这些命令的含义和使用与fatload、fatls 和fatwrite一样,只是ext2 和ext4 都是针对ext 文件系统的。

命令描述
ext2ls用于查询 ext2 格式设备的目录和文件信息
ext4ls用于查询 ext4 格式设备的目录和文件信息
ext2load用于将指定的文件读取到 DRAM 中
ext4load用于将指定的文件读取到 DRAM 中
ext4write用于将 DRAM 中的数据写入到 MMC 设备中
ext2write用于将 DRAM 中的数据写入到 MMC 设备中

比如 ext4ls 命令, EMMC 的分区 2 就是 ext4格式的,使用 ext4ls 就可以查询 EMMC 的分区 2 中的文件和目录,输入命令:
在这里插入图片描述

关于ext 格式文件系统其他命令的操作参考30.4.6 小节的即可,这里就不讲解了。

NAND操作命令

uboot 是支持NAND Flash 的,所以也有NAND Flash 的操作命令,前提是使用的NAND 版本的核心板,并且编译NAND 核心板对应的uboot,然后使用imxdownload 软件将u-boot.bin 烧写到SD 卡中,最后通过SD 卡启动。

一般情况下NAND 版本的核心板已经烧写好了uboot、linux kernel 和rootfs 这些文件,所以可以将BOOT 拨到NAND,然后直接从NAND Flash 启动即可。
NAND 版核心板启动信息如图30.4.8.1 所示:
在这里插入图片描述
图30.4.8.1 NAND 核心板启动信息
从图30.4.8.1 可以看出,当前开发板的NAND 容量为512MiB。输入“? nand”即可查看NAND 相关命令,如图30.4.8.2 所示:
在这里插入图片描述
图30.4.8.2 NAND 相关操作命令
可以看出,NAND 相关的操作命令不少,本节我们讲解一些常用的命令。

1、nand info 命令

此命令用户打印 NAND Flash 信息,输入“nand info”,结果如图:
在这里插入图片描述
图30.4.8.3 nand 信息

图30.4.8.3 中给出了NAND 的页大小、OOB 域大小,擦除大小等信息。可以对照着所使用的NAND Flash 数据手册来查看一下这些信息是否正确。

2、nand device 命令

nand device 用于切换 NAND Flash,如果你的板子支持多片 NAND 的话就可以使用此命令来设置当前所使用的 NAND。这个需要你的 CPU 有两个 NAND 控制器,并且两个 NAND 控制器各接一片 NAND Flash。就跟 I.MX6U 有两个 SDIO 接口,这两个 SDIO 接口可以接两个 MMC设备一样。不过一般情况下 CPU 只有一个 NAND 接口,而且在使用中只接一片 NAND。

3、nand erase 命令

nand erase 命令用于擦除 NAND Flash,NAND Flash 的特性决定了在向 NAND Flash 写数据之前一定要先对要写入的区域进行擦除。“nand erase”命令有三种形式:

nand erase[.spread] [clean] off size //从指定地址开始(off)开始,擦除指定大小(size)的区域。
nand erase.part [clean] partition //擦除指定的分区
nand erase.chip [clean] //全篇擦除

NAND 的擦除命令一般是配合写命令的,后面讲解 NAND 写命令的时候在演示如何使用“nand erase”。

4、nand write 命令

此命令用于向 NAND 指定地址写入指定的数据,一般和“nand erase”命令配置使用来更新NAND 中的 uboot、linux kernel 或设备树等文件,命令格式如下:

nand write addr off size

addr 是要写入的数据首地址(DRAM里面的首地址),off 是 NAND 中的目的地址,size 是要写入的数据大小。

由于I.MX6ULL 要求NAND 对应的uboot 可执行文件还需要另外包含BCB 和DBBT,因此直接编译出来的uboot.imx 不能直接烧写到NAND 里面。关于BCB 和DBBT 的详细介绍请参考《I.MX6ULL 参考手册》的8.5.2.2 小节,笔者目前没有详细去研究BCB 和DBBT,因此我们不能在NAND 版的uboot 里面更新uboot 自身。除非大家去研究一下I.MX6ULL 的BCB 和DBBT,然后在u-boot.imx 前面加上相应的信息,否则即使将uboot 烧进去了也不能运行。我们使用mfgtool 烧写系统到NAND 里面的时候,mfgtool 会使用一个叫做“kogs-ng”的工具完成BCB 和DBBT 的添加。
但是我们可以在uboot 里面使用“nand write”命令烧写kernel 和dtb。先编译出来NAND版本的kernel 和dtb 文件,在烧写之前要先对NAND 进行分区,也就是规划好uboot、linux kernel、设备树和根文件系统的存储区域,I.MX6U-ALPHA 开发板出厂系统NAND 分区如下:

0x000000000000-0x0000003FFFFF : "boot"
0x000000400000-0x00000041FFFF : "env"
0x000000420000-0x00000051FFFF : "logo"
0x000000520000-0x00000061FFFF : "dtb"
0x000000620000-0x000000E1FFFF : "kernel"
0x000000E20000-0x000020000000 : "rootfs"

一共有六个分区,第一个分区存放uboot,地址范围为0x0~ 0x3FFFFF(共4MB);第二个分区存放env(环境变量),地址范围为0x400000~ 0x420000(共128KB);第三个分区存放logo(启动图标),地址范围为0x420000~ 0x51FFFF(共1MB);第四个分区存放dtb(设备树),地址范为0x520000~ 0x61FFFF(共1MB);第五个分区存放kernel(也就是linux kernel),地址范围为0x620000~0xE1FFFF(共8MB);剩下的所有存储空间全部作为最后一个分区,存放rootfs(根文件系统)。
可以看出kernel 是从地址0x620000 开始存放的,将NAND 版本kernel 对应的zImage 文件
放到Ubuntu 中的tftpboot 目录中,然后使用tftp 命令将其下载到开发板的0X87800000 地址处,最终使用“nand write”将其烧写到NAND 中,命令如下:

tftp 0x87800000 zImage //下载zImage 到DRAM 中
nand erase 0x620000 0x800000 //从地址0x620000 开始擦除8MB 的空间
nand write 0x87800000 0x620000 0x800000 //将接收到的zImage 写到NAND 中

这里我们擦除了8MB 的空间,因为一般zImage 就是6,7MB 左右,8MB 肯定够了,如果不够的话就再多擦除一点就行了。
同理,最后烧写设备树(dtb)文件文件,命令如下:

tftp 0x87800000 imx6ull-14x14-emmc-7-1024x600-c.dtb //下载dtb 到DRAM 中
nand erase 0x520000 0x100000 //从地址0x520000 开始擦除1MB 的空间
nand write 0x87800000 0x520000 0x100000 //将接收到的dtb 写到NAND 中

dtb 文件一般只有几十KB,所以擦除1M 是绰绰有余的了。注意!正点原子出厂系统在NAND 里面烧写了很多种设备树文件!这里只是举例烧写一种的方法,我们在实际产品开发中肯定只有一种设备树。

根文件系统(rootfs)就不要在uboot 中更新了,还是使用NXP 提供的Mfgtool 工具来烧写,因为根文件系统太大!很有可能超过开发板DRAM 的大小,这样连下载都没法下载,更别说更新了。

5、nand read 命令

此命令用于从 NAND 中的指定地址读取指定大小的数据到 DRAM 中,命令格式如下:

nand read addr off size

addr 是目的地址,off 是要读取的 NAND 中的数据源地址,size 是要读取的数据大小。比如我们读取设备树(dtb)文件到 0x83000000 地址处,命令如下:

nand read 0x83000000 0x520000 0x19000

设备树文件读取到 DRAM 中以后就可以使用 fdt 命令来对设备树进行操作了,首先设置 fdt的地址,fdt 地址就是 DRAM 中设备树的首地址,命令如下:

fdt addr 83000000

过程如图30.4.8.4 所示:
在这里插入图片描述
图30.4.8.4 nand read 读取过程
设备树文件读取到DRAM 中以后就可以使用fdt 命令来对设备树进行操作了,首先设置fdt的地址,fdt 地址就是DRAM 中设备树的首地址,命令如下:

fdt addr 83000000

设置好以后可以使用“fdt header”来查看设备树的头信息,输入命令:

fdt header

结果如图30.4.8.5 所示:
在这里插入图片描述
图30.4.8.5 设备树头信息
输入命令“fdt print”就可以查看设备树文件的内容,输入命令:

fdt print

结果如图30.4.8.6 所示:
在这里插入图片描述

图30.4.8.6 设备树文件

图30.4.8.6 中的文件就是我们写到NAND 中的设备树文件,至于设备树文件的详细内容我们后面会有专门的章节来讲解,这里大家知道这个文件就行了。
NAND 常用的操作命令就是擦除、读和写,至于其他的命令大家可以自行研究一下,一定不要尝试全片擦除NAND 的指令!!否则NAND 就被全部擦除掉了,什么都没有了,又得重头烧整个系统。

BOOT操作命令(引导Linux)

uboot 的本质工作是引导 Linux,所以 uboot 肯定有相关的 boot(引导)命令来启动 Linux。常用的跟 boot 有关的命令有: bootz、 bootm 和 boot。

命令描述
bootz用于启动 zImage 镜像文件
bootm用于启动 uImage 镜像文件
boot用来启动 Linux 系统的(只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统)

1、 bootz 命令

要启动 Linux,需要先将 Linux 镜像文件zimage拷贝到 DRAM 中如果使用到设备树的话也需要将设备树拷贝到 DRAM 中

  • 可以从 EMMC 或者 NAND 等存储设备中将 Linux 镜像和设备树文件拷贝到 DRAM(使用fatload 命令,前面讲过的);
  • 也可以通过 nfs 或者 tftp 将 Linux 镜像文件和设备树文件从ubuntu下载到 DRAM 中。

不管用哪种方法,只要能将 Linux 镜像和设备树文件存到 DRAM 中就行,然后使用 bootz 命令来启动bootz 命令用于启动 zImage 镜像文件, bootz 命令格式如下:

bootz [addr [initrd[:size]] [fdt]]

命令 bootz 有三个参数:

  • addr 是 Linux 镜像文件zimage在 DRAM 中的位置;
  • initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可;
  • fdt 就是设备树文件在 DRAM 中的地址。

现在我们使用网络和EMMC 两种方法来启动Linux 系统,首先将I.MX6U-ALPHA 开发板的Linux 镜像和设备树发送到Ubuntu 主机中的tftpboot 文件夹下。Linux 镜像文件前面已经放到了tftpboot 文件夹中,现在把设备树文件放到tftpboot 文件夹里面。由于不同的屏幕其设备树不同,因此我们出厂系统提供了很多设备树,路径为:开发板光盘->8、系统镜像->1、出厂系统镜像->2、kernel 镜像->linux-imx-4.1.15-2.1.0-gbfed875-v1.6,所有设备树文件如图30.4.9.1所示:

在这里插入图片描述

图30.4.9.1 正点原子出厂设备树
从图30.4.9.1 可以看出,我们提供了14 种设备树,笔者正在使用的是EMMC 核心板,7 寸1024×600 分辨率的屏幕,所以需要使用imx6ull-14x14-emmc-7-1024x600-c.dtb 这个设备树。将imx6ull-14x14-emmc-7-1024x600-c.dtb 发送到Ubuntu 主机中的tftpboot 文件夹里面,完成以后的tftpboot 文件夹如图30.4.9.2 所示:
在这里插入图片描述
图30.4.9.2 tftpboot 文件夹
给予imx6ull-14x14-emmc-7-1024x600-c.dtb 可执行权限,命令如下:

chmod 777 imx6ull-14x14-emmc-7-1024x600-c.dtb

Linux 镜像文件和设备树都准备好了,我们先学习如何通过网络启动Linux,使用tftp 命令将zImage 下载到DRAM 的0X80800000 地址处,然后将设备树imx6ull-14x14-emmc-7-1024x600-c.dtb 下载到DRAM 中的0X83000000 地址处,最后之后命令bootz 启动,命令如下:

tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb
bootz 80800000 - 83000000

命令运行结果如图30.4.9.3 所示:

在这里插入图片描述

图30.4.9.3 通过网络启动Linux
上图就是我们通过tftp 和bootz 命令来从网络启动Linux 系统,如果我们要从EMMC 中启动Linux 系统的话只需要使用命令fatload 将zImage 和imx6ull-14x14-emmc-7-1024x600-c.dtb 从EMMC 的分区1 中拷贝到DRAM 中,然后使用命令bootz 启动即可。先使用命令fatls 查看要下EMMC 的分区1 中有没有Linux 镜像文件和设备树文件,如果没有的话参考30.4.6 小节中讲解的fatwrite 命令将tftpboot 中的zImage 和imx6ull-14x14-emmc-7-1024x600-c.dtb 文件烧写到EMMC 的分区1 中。然后使用命令fatload 将zImage 和imx6ull-14x14-emmc-7-1024x600-c.dtb文件拷贝到DRAM 中,地址分别为0X80800000 和0X83000000,最后使用bootz 启动,命令如下:

fatload mmc 1:1 80800000 zImage
fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb
bootz 80800000 - 83000000

命令运行结果如图30.4.9.4 所示:
在这里插入图片描述

图30.4.9.4 从EMMC 中启动Linux

2、 bootm 命令

bootm 和 bootz 功能类似,但是 bootm 用于启动 uImage 镜像文件。如果不使用设备树的话启动 Linux 内核的命令如下:

bootm addr

addr 是 uImage 镜像在 DRAM 中的首地址。
如果要使用设备树,那么 bootm 命令和 bootz 一样,命令格式如下:

bootm [addr [initrd[:size]] [fdt]]

其中 addr 是 uImage 在 DRAM 中的首地址, initrd 是 initrd 的地址, fdt 是设备树(.dtb)文件在 DRAM 中的首地址,如果 initrd 为空的话,同样是用“-”来替代。

3、 boot 命令

boot 命令也是用来启动 Linux 系统的,只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统, bootcmd 是一个很重要的环境变量!

其名字分为“boot”和“cmd”,也就是“引导”和“命令”,说明这个环境变量保存着引导命令,其实就是启动的命令集合,具体的引导命令内容是可以修改的。

比如我们要想使用tftp 命令从网络启动Linux 那么就可以设置bootcmd 为“tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 -83000000”,然后使用saveenv 将bootcmd 保存起来。然后直接输入boot 命令即可从网络启动Linux 系统,命令如下:

setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000'
saveenv
boot

运行结果如图30.4.9.5 所示:
在这里插入图片描述

图30.4.9.5 设置bootcmd 从网络启动Linux
前面说过uboot 倒计时结束以后就会启动Linux 系统,其实就是执行的bootcmd 中的启动命令。只要不修改bootcmd 中的内容,以后每次开机uboot 倒计时结束以后都会使用tftp 命令从网络下载zImage 和imx6ull-14x14-emmc-7-1024x600-c.dtb,然后启动Linux。
如果想从EMMC 启动那就设置bootcmd 为“fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000”,然后使用boot命令启动即可,命令如下:

setenv bootcmd 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000'
savenev
boot

运行结果如图30.4.9.6 所示:
在这里插入图片描述
图30.4.9.6 设置bootcmd 从EMMC 启动Linux
如果不修改bootcmd 的话,每次开机uboot 倒计时结束以后都会自动从EMMC 里面读取zImage 和imx6ull-14x14-emmc-7-1024x600-c.dtb,然后启动Linux。
在启动Linux 内核的时候可能会遇到如下错误:

“Kernel panic –not Syncing: VFS: Unable to mount root fs on unknown-block(0,0)

这个错误的原因是linux 内核没有找到根文件系统,这个很正常,因为没有设置uboot 的bootargs 环境变量,关于bootargs 环境变量后面会讲解!此处我们重点是验证boot 命令,linux内核已经成功启动了,说明boot 命令工作正常。

reset 、go、 run、mtest操作命令

uboot 中还有其他一些常用的命令,比如 reset、 go、 run 和 mtest 等。

命令描述
reset输入“reset”即可复位重启
go用于跳到指定的地址处执行应用
run用于运行环境变量中定义的命令
mtest内存读写测试命令

1、 reset 命令

reset 命令顾名思义就是复位的,输入“reset”即可复位重启,如下图所示:
在这里插入图片描述

2、 go 命令(可执行裸机代码)

go 命令用于跳到指定的地址处执行应用,命令格式如下:

go addr [arg ...]

addr 是应用在 DRAM 中的首地址,我们可以编译一下裸机例程的实验 13_printf,然后将编译出来的 printf.bin 拷贝到 Ubuntu 中的 tftpboot 文件夹里面,注意,这里要拷贝 printf.bin 文件,不需要在前面添加头部 IVT 信息,因为 uboot 已经初始化好了 DDR 了。【前面学裸机时bootroom需要这个头部信息】。使用 tftp 命令将 printf.bin下载到开发板 DRAM 的 0X87800000 地址处,因为裸机例程的链接首地址就是 0X87800000,最后使用 go 命令启动 printf.bin 这个应用,命令如下:

tftp 87800000 printf.bin
go 87800000

结果如图30.4.10.2 所示:
在这里插入图片描述

从上图可以看出,通过 go 命令我们就可以在 uboot 中运行裸机例程。免去了将代码烧写到SD卡,不断拔插SD卡的步骤

3、 run 命令

run 命令用于运行环境变量中定义的命令,比如可以通过“run bootcmd”来运行 bootcmd 中的启动命令,但是 run 命令最大的作用在于运行我们自定义的环境变量。在后面调试 Linux 系统的时候常常要在网络启动和 EMMC/NAND 启动之间来回切换,而 bootcmd 只能保存一种启动方式,如果要换另外一种启动方式的话就得重写 bootcmd,会很麻烦。这里我们就可以通过自定义环境变量来实现不同的启动方式,比如定义环境变量 mybootemmc 表示从 emmc 启动,定义 mybootnet 表示从网络启动,定义 mybootnand 表示从 NAND 启动。如果要切换启动方式的话只需要运行“run mybootxxx(xxx 为 emmc、 net 或 nand)”即可。

说干就干,创建环境变量 mybootemmc、 mybootnet 和 mybootnand,命令如下:

setenv mybootemmc 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ullalientek-emmc.dtb;bootz 80800000 -83000000'

setenv mybootnand 'nand read 80800000 4000000 800000;nand read 83000000 6000000100000;bootz 80800000 - 83000000'

setenv mybootnet 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz  80800000 - 83000000'

saveenv

创建环境变量成功以后就可以使用 run 命令来运行 mybootemmc、 mybootnet 或 mybootnand来实现不同的启动:

run mybootemmc

run mytoobnand

run mybootnet

4、 mtest 命令

mtest 命令是一个简单的内存读写测试命令,可以用来测试自己开发板上的 DDR,命令格式如下:

mtest [start [end [pattern [iterations]]]]

start 是要测试的DRAM 开始地址,end 是结束地址,比如我们测试0X80000000~0X80001000这段内存,输入“mtest 80000000 80001000”,结果如图30.4.10.3 所示:
在这里插入图片描述

图30.4.10.3 mtest 命令运行结果
从图30.4.10.3 可以看出,测试范围为0X80000000~0X80001000,已经测试了486 次,如果要结束测试就按下键盘上的“Ctrl+C”键。

至此,uboot 常用的命令就讲解完了,如果要使用uboot 的其他命令,可以查看uboot 中的帮助信息,或者上网查询一下相应的资料。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行稳方能走远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值