【IMX6ULL学习笔记】二、U-Boot命令合集

注:参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6

一、help命令

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

help”或者“?

image

图中只是 uboot 的一部分命令,具体的命令列表以实际为准。图中的命令并不是 uboot 所支持的所有命令,uboot 是可配置的,需要什么命令就使能什么命令,而且也可以在 uboot 中自定义命令。这些命令后面都跟有命令说明,用于描述此命令的作用,输入:

help(或?) 命令名

可以查看命令的详细用法,以“bootz”这个命令为例,我们输入如下命令即可查看“bootz”这个命令的用法:

? bootz 或 help bootz

image

二、信息查询命令

常用的和信息查询有关的命令有 3 个:bdinfo、printenv 和 version。

1、bdinfo 命令

用于查看板子信息,直接输入“bdinfo”,结果如图所示:

bdinfo

image

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

2、printenv命令

用于输出环境变量信息,uboot 也支持 TAB 键自动补全功能,输入“print”,然后按下回车键,环境变量如图所示:

printenv

image
图中有很多的环境变量,比如 baudrate、board_name、board_rec、boot_fdt、bootcmd等等。uboot 中的环境变量都是字符串,既然叫做环境变量,那么它的作用就和“变量”一样。比如 bootdelay 这个环境变量就表示 uboot 启动延时时间,默认 bootdelay=3,也就默认延时 3秒。uboot 中的环境变量是可以修改的,有专门的命令来修改环境变量的值。

3、version命令

查看 uboot 的版本号,输入“version”,uboot 版本号如图所示:
image
当前 uboot 版本号为 2016.03,2020 年 8 月 7 日编译的,编译器为arm-poky-linux-gnueabi-gcc,这是 NXP 官方提供的编译器,正点原子出厂系统用的此编译器编译的,但是本教程我们统一使用 arm-linux-gnueabihf-gcc。

三、环境变量操作命令

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

1、修改环境变量setenv

命令 setenv 用于设置或者修改环境变量的值,命令 saveenv 用于保存修改后的环境变量。
命令 saveenv 使用格式为:

saveenv

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

setenv bootdelay 5
saveenv

有时候我们修改的环境变量值可能会有空格,比如 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

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

setenv author kodo
saveenv

3、删除环境变量setenv

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

setenv author
saveenv

上面命令中通过 setenv 给 author 赋空值,也就是什么都不写来删除环境变量 author。

四、内存操作命令

内存操作命令就是用于直接对 DRAM 进行读写操作的,常用的内存操作命令有 md、nm、mm、mw、cp 和 cmp。

1、md 命令

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

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

命令中的[.b .w .l]对应 byte、word 和 long,也就是分别以 1 个字节、2 个字节、4 个字节来显示内存值。address 就是要查看的内存起始地址,[# of objects]表示要查看的数据长度,这个数据长度单位跟选择的显示格式(byte、word、long)有关。
另外要注意:uboot 命令中的数字都是十六进制的!不是十进制的!比如你想查看以 0X80000000 开始的 20 个字节的内存值,显示格式为.b 的话,应该使用如下所示命令:

md.b 80000000 14

而不是:

md.b 80000000 20

uboot 命令里面的数字都是十六进制的,所以可以不用写“0x”前缀,十进制的 20 其十六进制为 0x14,所以命令 md 后面的个数应该是 14。

2、nm 命令

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

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

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

nm.l 80000000

输入上述命令以后如图 30.4.3.2 所示:
image
在上图中,80000000 表示现在要修改的内存地址,0500e031 表示地址 0x80000000 现在的数据,?后面就可以输入要修改后的数据 0x12345678,输入完成以后按下回车,然后再输入 q 即可退出,如图所示:
image

3、mm 命令

mm 命令也是修改指定地址内存值的,使用 mm 修改内存值的时候地址会自增,而使用命令 nm 的话地址不会自增。比如以.l 格式修改从地址 0x80000000 开始的连续 3 个内存块(3*4=12个字节)的数据为 0X05050505,操作如图 30.4.3.5 所示:

nm.l 80000000
05050505
05050505
05050505
q

image

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

image

5、cp 命令

cp 是数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 NorFlash 中的数据拷贝到 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

image

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

五、网络操作命令

uboot 支持大量的网络相关命令,比如 dhcp、ping、nfs 和 tftpboot。在移植 uboot 的时候一般都要调通网络功能,在移植 linux kernel 的时候需要使用到 uboot 的网络功能做调试。

设置以下几个环境变量:

setenv ipaddr 192.168.1.50        //开发板ip 地址,可以使用 dhcp 命令来获取IP 地址
setenv ethaddr b8:ae:1d:01:00:00  //开发板的 MAC 地址,一定要设置
setenv gatewayip 192.168.1.1      //网关地址
setenv netmask 255.255.255.0      //子网掩码
setenv serverip 192.168.1.253     //Ubuntu 主机服务器 IP 地址,用于调试代码
saveenv                           //保存环境变量

网络地址环境变量的设置,确保 Ubuntu 主机和开发板的 IP地址在同一个网段内。ethaddr 为网络 MAC 地址,是一个 48bit 的地址,在同一个网段内有多个开发板的话要保证每个开发板的 ethaddr 是不同的,否则通信会有问题!设置好网络相关的环境变量以后就可以使用网络相关命令了。

1、ping 命令

开发板的网络能否使用,是否可以和服务器(Ubuntu 主机)进行通信,通过 ping 命令就可以验证,直接 ping 服务器的 IP 地址即可,如下:

ping 192.168.148.200

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

2、dhcp 命令

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

dhcp

image
开发板通过 dhcp 获取到的 IP 地址为 192.168.1.137。同时在图中可以看到“warning:no boot file name;”、“TFTP from server 192.168.1.1”这样的字样。这是因为 DHCP 不单单是获取 IP 地址,其还会通过 TFTP 来启动 linux 内核。
输入“? dhcp”即可查看 dhcp 命令详细的信息:

? dhcp

image

3、nfs 命令

nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源。uboot 中的 nfs 命令格式如下所示:

nfs [loadAddress] [[hostIPaddr:]bootfilename]

loadAddress 是要保存的 DRAM 地址,[[hostIPaddr:]bootfilename] 是要下载的文件地址。
这里我们将编译出来的 Linux 镜像文件 zImage 下载到开发板 DRAM 的0x80800000这个地址处。将文件 zImage 放到 Ubuntu 的 NFS 目录下,比如放到 /home/qq/NFS 这个目录下,准备好以后就可以使用 nfs 命令来将 zImage 下载到开发板 DRAM 的0X80800000 地址处,命令如下:

nfs 80800000 192.168.148.200:/home/qq/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/qq/linux/tftpboot
chmod 777 /home/qq/linux/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 服务器:

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]

tftp 命令不需要输入文件在 Ubuntu 中的完整路径,只需要输入文件名即可。比如我们现在将 tftpboot 文件夹里面的 zImage 文件下载到开发板 DRAM 的 0X80800000 地址处,命令如下:

tftp 80800000 zImage

六、EMMC 和 SD 卡操作命令

一般认为 EMMC和 SD 卡是同一个东西,本教程统一使用 MMC 来代指 EMMC 和 SD 卡。uboot 中常用于操作 MMC 设备的命令为“mmc”。mmc 是一系列的命令,其后可以跟不同的参数,输入“?mmc”即可查看 mmc 有关的命令,如图所示:image
mmc 后面跟不同的参数可以实现不同的功能,如下表所示:
image

①、 mmc info 命令

mmc info 命令用于输出当前选中的 mmc info 设备的信息,输入命令“mmc info”即可:

mmc info

image

还有一个与 mmc info 命令相同功能的命令:

mmcinfo

②、mmc rescan 命令

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

mmc rescan

③、mmc list 命令

mmc list 命令用于来查看当前开发板一共有几个 MMC 设备,输入“mmc list”:

mmc list

image
可以看出当前开发板有两个 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 设备。

④、mmc dev 命令

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

mmc dev [dev] [part]

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

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

image
切换到 SD后,mmc0 为当前的 MMC 设备,输入命令“mmc info”可查看 SD 卡信息:
image

⑤、mmc part 命令

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

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

image
从图 中可以看出,此时 EMMC 有两个分区,第一个分区起始扇区为 20480,长度为 262144 个扇区;第二个分区起始扇区为 282624,长度为 14594048 个扇区。
如果 EMMC 里面烧写了 Linux 系统的话,EMMC 是有 3 个分区的,第 0 个分区存放 uboot,第 1 个分区存放Linux 镜像文件和设备树,第 2 个分区存放根文件系统。但是在图 中只有两个分区,那是因为第 0 个分区没有格式化,所以识别不出来,实际上第 0 个分区是存在的。

一个新的 SD卡默认只有一个分区,那就是分区 0,所以前面讲解的 uboot 烧写到 SD 卡,其实就是将 u-boot.bin烧写到了 SD 卡的分区 0 里面。后面学习 Linux 内核移植的时候再讲解怎么在 SD 卡中创建并格式化第二个分区,并将 Linux 镜像文件和设备树文件存放到第二个分区中。

如果要将 EMMC 的分区 2 设置为当前 MMC 设备,可以使用如下命令:

mmc dev 1 2

⑥、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		//读取数据

image

⑦、mmc write 命令

要将数据写到 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设备中。
TFTP下载:使用 tftp 命令将其下载到 0x80800000 地址处,命令如下:

tftp 80800000 u-boot.imx

image
u-boot.imx 大小为 379904 字节,379904/512=742,所以我们要向 SD 卡中写入742 个块,如果有小数的话就要加 1 个块。

写入SD卡:使用命令“mmc write”从 SD 卡分区 0 第 2 个块(扇区)开始烧写,一共烧写 742(0x2E6)个块,命令如下:

mmc dev 0 0
mmc write 80800000 2 32E

image

写入EMMC:要在 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 的前两个块(扇区),里面保存着分区表!

⑧、mmc erase 命令

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

mmc erase blk# cnt

blk 为要擦除的起始块,cnt 是要擦除的数量。没事不要用 mmc erase 擦除 MMC 设备!

七、FAT 格式文件系统操作命令

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

1、fatinfo 命令

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

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

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

fatinfo mmc 1:1

image

2、fatls 命令

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

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

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

fatls mmc 1:1

image

3、fstype 命令

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

fstype <interface> <dev>:<part>

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

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

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

4、fatload 命令

fatload 命令用于将指定的文件读取到 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

image

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为例,首先将开发板提供的 zImage 镜像文件拷贝到 Ubuntu 中的tftpboot 目录下,拷贝完成以后使用命令 tftp 将 zImage 下载到 DRAM 的 0X80800000地址处,命令如下:

tftp 80800000 zImage

image
zImage 大小为 6785272(0X6788f8)个字节,接下来使用命令 fatwrite 将其写入到 EMMC 的分区 1 中,文件名字为 zImage,命令如下:

fatwrite mmc 1:1 80800000 zImage 6788f8

image
使用“fatls”命令查看一下 EMMC 分区 1 里面的文件:
image

八、EXT 格式文件系统操作命令

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

比如 ext4ls 命令,EMMC 的分区 2 就是 ext4格式的,使用 ext4ls 就可以查询 EMMC 的分区 2 中的文件和目录,输入命令:

ext4ls mmc 1:2

image
ext 格式文件系统其他命令的操作可以参考FAT相对应的命令。

九、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 版核心板启动信息如图所示:
image
从图中可以看出,当前开发板的 NAND 容量为 512MiB。输入“? nand”即可查看
NAND 相关命令,如图所示:
image
本节讲解一些常用的命令。

1、nand info 命令

此命令用户打印 NAND Flash 信息,输入“nand info”,结果如图所示:
image
图中给出了 NAND 的页大小、OOB 域大小,擦除大小等信息。

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 是要写入的数据首地址,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),地址范围为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 的大小,这样连下载都没法下载,更别说更新了。

4、nand read 命令

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

nand read addr off size

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

nand read 0x83000000 0x520000 0x19000

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

fdt addr 83000000

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

fdt header

结果如图所示:
image
输入命令“fdt print”就可以查看设备树文件的内容,输入命令:

fdt print

结果如图所示:
image

NAND 常用的操作命令就是擦除、读和写,至于其他的命令大家可以自行研究一下,一定不要尝试全片擦除 NAND 的指令!否则 NAND 就被全部擦除掉了,什么都没有了,又得重头烧整个系统。

十、SPI FLASH操作命令

uboot 中如果支持 spi/qspi flash, 那么可以使用 sf 的 erase、read、write 命令操作spi flash。

sf read   //用来读取flash数据到内存
sf write  //写内存数据到flash
sf erase  //擦除指定位置,指定长度的flash内容, 擦除后内容全1

具体用法:

sf probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus and chip select
sf read addr offset len    - read `len' bytes starting at`offset' to memory at `addr'
sf write addr offset len   - write `len' bytes from memor at `addr' to flash at `offset'
sf erase offset [+]len     - erase `len' bytes from `offset' `+len' round up `len' to block size
sf update addr offset len  - erase and write `len' bytes from memory at `addr' to flash at `offset'

使用范例:
在使用sf read sf write之前,一定要调用sf probe

sf probe

写数据

sf write 0x82000000 0x0 0x20000  
//把内存 0x82000000 处的数据, 写入 flash 的偏移 0x0, 
//写入数据长度为 0x20000(128KB), 操作偏移和长度最小单位是 Byte

读数据

sf read 0x82000000 0x10000 0x20000
//把 flash 偏移 0x10000(64KB) 处, 长度为 0x20000(128KB) 的数据, 
//写入到内存 0x82000000, 操作偏移和长度最小单位是 Byte

擦除数据

sf erase 0x0 0x10000
//擦除偏移0x0处, 到0x10000之间的擦除块, 擦除操作是以erase block为单位的,
// 要求 offset 和 len 参数必须是 erase block 对齐的

从sf命令,可以看出几点:

  1. spi flash 没有 oob 数据存在, 不用考虑EDC ECC, 也没有坏块管理概念.
  2. 支持Byte级的读写操作, 支持随机访问.

十一、BOOT 操作命令

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

1、bootz 命令

要启动 Linux,需要先将 Linux 镜像文件拷贝到 DRAM 中,如果使用到设备树的话也需要将设备树拷贝到 DRAM 中。可以从 EMMC 或者 NAND 等存储设备中将 Linux 镜像和设备树文件拷贝到 DRAM,也可以通过 nfs 或者 tftp 将 Linux 镜像文件和设备树文件下载到 DRAM 中。不管用那种方法,只要能将 Linux 镜像和设备树文件存到 DRAM 中就行,然后使用 bootz 命令来启动,bootz 命令用于启动 zImage 镜像文件,bootz 命令格式如下:

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

命令 bootz 有三个参数,addr 是 Linux 镜像文件在 DRAM 中的位置,initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用 ‘-’ 代替即可,fdt 就是设备树文件在 DRAM 中的地址。

TFTP启动: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

image

EMMC启动:要从 EMMC 中启动 Linux 系统,先切换到emmc设备,使用命令 fatls 查看要下 EMMC 的分区 1 中有没有 Linux 镜像文件和设备树文件。再使用命令 fatload 将 zImage 和 imx6ull-14x14-emmc-7-1024x600-c.dtb 文件拷贝到 DRAM 中,地址分别为 0X80800000 和 0X83000000,最后使用 bootz 启动,命令如下:

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

image

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 是一个很重要的环境变量,这个环境变量保存着引导命令,其实就是启动的命令集合,具体的引导命令内容是可以修改的。

使用 tftp 命令从网络启动 Linux 那么就可以设置 bootcmd 为:

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

然后使用 saveenv 将 bootcmd 保存起来:

saveenv

然后直接输入 boot 命令即可从网络启动Linux 系统:

boot

image
uboot 倒计时结束以后就会启动 Linux 系统,其实就是执行的 bootcmd 中的启动
命令。只要不修改 bootcmd 中的内容,以后每次开机 uboot 倒计时结束以后都会使用 tftp 命令从网络下载 zImage 和 imx6ull-14x14-emmc-7-1024x600-c.dtb,然后启动 Linux。

如果想从 EMMC 启动,首先切换到emmc:

mmc dev 1

然后设置 bootcmd 为:

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

然后保存并使用 boot命令启动即可:

savenev
boot

image

如果不修改 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 环境变量后面会讲解。

posted @ 2023-02-16 16:07  酷电玩家  阅读(869)  评论(0)    收藏  举报