imx6ull-系统移植篇2—— U-Boot 命令使用(上)
目录
前言
U-Boot 命令
help
信息查询命令
bdinfo
printenv
version
环境变量操作命令
setenv 和 saveenv
修改环境变量
新建环境变量
删除环境变量
内存操作命令
md
nm
mm
mw
cp
cmp
网络操作命令
ping 命令
dhcp 命令
nfs 命令
tftp 命令
EMMC 和 SD 卡操作命令
mmc
mmc info 命令
mmc rescan 命令
mmc list 命令
mmc dev 命令
mmc part 命令
mmc read 命令
mmc write 命令
mmc erase 命令
前言
我们使用正点原子开发板imx6ull,在上一讲实验中:UBoot使用体验,我们介绍了UBoot的编译步骤、烧写启动流程,讲解到在倒计时3秒内按下回车键进入命令行模式。
聪明的宝子们就会问了,命令行模式有什么作用?能够用来做什么?本讲实验就来学习一下U-Boot 命令使用,主要包含:help、信息查询命令(bdinfo/printenv/version)、环境变量操作命令(setenv/saveenv)、内存操作命令(md/nm/mm/mw/cp/cmp)、网络操作命令(ping/dhcp/nfs/tftp)、操作MMC设备命令(mmc)等。
U-Boot 命令
help
进入 uboot 的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前 uboot 所支持的命令,如图:
Uboot 是可配置的,需要什么命令就使能什么命令。这些命令后面都跟有命令说明,用于描述此命令的作用。
输入“help(或?) 命令名”,可以查看命令的详细用法:
信息查询命令
bdinfo
bdinfo 命令,此命令用于查看板子信息:
可以得出 DRAM 的起始地址和大小、启动参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息。
printenv
“printenv”用于输出环境变量信息:
=> printenv
baudrate=115200
board_name=EVK
board_rev=14X14
boot_fdt=try
bootcmd=run findfdt;mmc dev ${mmcdev};mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot; else run netboot; fi; fi; else run netboot; fi
bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};
bootdelay=1
bootscript=echo Running bootscript from mmc ...; source
console=ttymxc0
ethact=FEC1
ethprime=FEC
fdt_addr=0x83000000
fdt_file=imx6ull-14x14-emmc-4.3-480x272-c.dtb
fdt_high=0xffffffff
findfdt=if test $fdt_file = undefined; then if test $board_name = EVK && test $board_rev = 9X9; then setenv fdt_file imx6ull-9x9-evk.dtb; fi; if test $board_name = EVK && test $board_rev = 14X14; then setenv fdt_file imx6ull-14x14-evk.dtb; fi; if test $fdt_file = undefined; then echo WARNING: Could not determine dtb to use; fi; fi;
image=zImage
initrd_addr=0x83800000
initrd_high=0xffffffff
ip_dyn=yes
loadaddr=0x80800000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
logo_file=alientek.bmp
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc g_mass_storage.stall=0 g_mass_storage.removable=1 g_mass_storage.file=/fat g_mass_storage.ro=1 g_mass_storage.idVendor=0x066F g_mass_storage.idProduct=0x37FF g_mass_storage.iSerialNumber="" clk_ignore_unused
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
mmcautodetect=yes
mmcboot=echo Booting from mmc ...; run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
mmcdev=0
mmcpart=1
mmcroot=/dev/mmcblk0p2 rootwait rw
netargs=setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
netboot=echo Booting from net ...; run netargs; if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${image}; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_file}; then bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
panel=ATK-LCD-4.3-480x272
script=boot.scr
splashimage=0x88000000
splashpos=m,m
stderr=serial
stdin=serial
stdout=serialEnvironment size: 2583/8188 bytes
uboot 中的环境变量都是字符串,是可以修改的,有专门的命令来修改环境变量的值。
version
version 用于查看 uboot 的版本号:
环境变量操作命令
setenv 和 saveenv
命令 setenv 用于设置或者修改环境变量的值。
命令 saveenv 用于保存修改后的环境变量。
一般环境变量是存放在外部 flash 中的, uboot 启动的时候会将环境变量从 flash 读取到 DRAM 中。所以使用命令 setenv 修改的是 DRAM中的环境变量值,修改以后要使用 saveenv 命令将修改后的环境变量保存到 flash 中,否则的话uboot 下一次重启会继续使用以前的环境变量值。
修改环境变量
比如我们要将环境变量 bootdelay (倒计时延时时间)改为 5,就可以使用如下所示命令:
可以看出环境变量保存到了 MMC(0)中,也就是 SD 卡中。
修改 bootdelay 以后,重启开发板, uboot 就会变为 5 秒倒计时。嫌时间太久记得修改回来哦。
有时候我们修改的环境变量值可能会有空格, 比如 bootcmd、 bootargs 等, 这个时候环境变量值就得用单引号括起来,每组值之间用空格隔开。
比如下面修改环境变量 bootargs 的值:
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv
新建环境变量
命令 setenv 也可以用于新建命令,比如我们新建一个环境变量cmdtest,将这个变量的值设为huaxuan,那么就可以使用如下命令:
setenv cmdtest huaxuan
saveenv
新建环境变量以后,需要重启 uboot,然后使用命令 printenv 查看是否有我们新增的命令。
删除环境变量
要删除一个环境变量只要给这个环境变量赋空值即可,像这样删掉我们刚新增的命令:
setenv cmdtest
saveenv
内存操作命令
内存操作命令就是用于直接对 DRAM 进行读写操作的,常用的内存操作命令有 md、 nm、mm、 mw、 cp 和 cmp。
md
md 命令用于显示内存值,格式如下:
md[.b, .w, .l] address [# of objects]
- 命令中的[.b .w .l]对应 byte、 word 和 long,也就是分别以 1 个字节、 2 个字节、 4 个字节来显示内存值。
- address 就是要查看的内存起始地址。
- [# of objects]表示要查看的数据长度。
查看以 0X80000000 为起始地址的内存数据:
nm
nm 命令用于修改指定地址的内存值,命令格式如下:
nm [.b, .w, .l] address
比如想修改 0x80000000 地址的数据:
?后面就可以输入要修改后的数据,输入完成以后按下回车,然后再输入‘q’即可退出。
但是可以看见使用nm命令修改地址的时候,地址不会自己递增,一直操作的都是同一个地址。
mm
mm 命令也是修改指定地址内存值的,使用 mm 修改内存值的时候地址会自增。
mm [.b, .w, .l] address
mw
命令 mw 用于使用一个指定的数据填充一段内存,命令格式如下:
mw [.b, .w, .l] address value [count]
- mw 命令同样可以以.b、 .w 和.l 来指定操作格式,
- address 表示要填充的内存起始地址,
- value为要填充的数据,
- count 是填充的长度。
比如使用.l 格式将以 0X80000000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0X0A0A0A0A
怎么知道数据填充成功没有呢?使用命令 md 来查看:
cp
cp 是数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 Nor Flash 中的数据拷贝到 DRAM 中。命令格式如下:
cp [.b, .w, .l] source target count
- 以.b、 .w 和.l 来指定操作格式,
- source 为源地址,
- target 为目的地址,
- count为拷贝的长度。
比如使用.l 格式将 0x80000000 处的地址拷贝到 0X80000040 处,长度为 0x10 个内存块(0x10 * 4=64 个字节):
cmp
cmp 是比较命令,用于比较两段内存的数据是否相等,命令格式如下:
cmp [.b, .w, .l] addr1 addr2 count
我们使用.l 格式来比较 0x80000000 和 0X80000040 这两个地址数据是否相等,比较长度为 0x10 个内存块:
可以看出这两段内存的数据相等。那么不相等的时候会怎么样显示呢?
网络操作命令
uboot 支持大量的网络相关命令,比如 dhcp、ping、 nfs 和 tftpboot。
在使用 uboot 的网络功能之前先用网线将开发板的 ENET2 接口和电脑或者路由器连接起来。
还要设置表中所示的几个环境变量:
网络地址环境变量的设置,要确保 Ubuntu 主机和开发板的 IP地址在同一个网段内。
ping 命令
通过 ping 命令,ping 服务器的 IP 地址,来检测两者之间网络是否连通。如果网络正常,如下图:
dhcp 命令
dhcp 用于从路由器获取 IP 地址,前提得开发板连接到路由器上的,如果开发板是和电脑直连的,那么 dhcp 命令就会失效。
直接输入 dhcp 命令即可通过路由器获取到 IP 地址:
nfs 命令
nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源。
uboot 中的 nfs 命令格式如下所示:
nfs [loadAddress] [[hostIPaddr:]bootfilename]
- loadAddress 是要保存的 DRAM 地址,
- [[hostIPaddr:]bootfilename]是要下载的文件地址。
在 uboot 中使用 nfs 命令,将 Ubuntu 中的 linux 镜像和设备树下载到开发板的 DRAM 中
,可以更方便调试 linux 镜像和设备树。我们之后都会使用网络调试的方法。
首先需要开启 Ubuntu 主机的 NFS 服务,然后新建一个 NFS 使用的目录,以后所有要通过NFS 访问的文件都需要放到这个 NFS 目录中。现在nfs目录里我已经放了一个zImage的镜像文件。
使用 nfs 命令来将 zImage 下载到开发板 DRAM 的 0X80800000 地址处:
nfs 80800000 192.168.1.253:/home/huax/linux/nfs/zImage
- “ 80800000 ” 表 示 zImage 保 存 地 址 ,
- “192.168.1.253:/home/huax/linux/nfs/zImage”表示 zImage 在 192.168.1.253 这个主机中,对应的nfs目录路径。
下载过程如图:打印done就是下载结束了。
下载完成以后可以查看 0x80800000 地址处的数据,使用命令 md.b 来查看前 0x100 个字节的数据,然后再用能查看二进制的工具比对,可以看见数据一致的。
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
TFTP 也需要一个文件夹tftpboot来存放文件,记得给 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 文件,将TFTP_DIRECTORY 修改为我们上面创建的 tftp 文件夹目录,以后我们就将所有需要通过TFTP 传输的文件都放到这个文件夹里面,并且要给予这些文件相应的权限。
然后再重启一次 tftp 服务器。tftp 服务器已经搭建好了。
将我们需要烧写的zImage 镜像文件拷贝到 tftpboot 文件夹中,并且给予 zImage 相应的权限。
uboot 中的 tftp 命令格式如下:
tftpboot [loadAddress] [[hostIPaddr:]bootfilename]
- loadAddress 是文 件在 DRAM 中的 存放 地址 ,
- [[hostIPaddr:]bootfilename]是要从 Ubuntu 中下载的文件。
将 tftpboot 文件夹里面的 zImage 文件下载到开发板 DRAM 的 0X80800000 地址处,命令如下:
tftp 80800000 zImage
EMMC 和 SD 卡操作命令
mmc
mmc 后面跟不同的参数可以实现不同的功能:
我们常用的几个功能如下:
mmc info 命令
mmc info 命令用于输出当前选中的 mmc info 设备的信息:
mmc rescan 命令
mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备,包括 EMMC 和 SD 卡。
mmc list 命令
mmc list 命令用于来查看当前开发板一共有几个 MMC 设备:
mmc dev 命令
mmc dev 命令用于切换当前 MMC 设备,命令格式如下:
mmc dev [dev] [part]
- [dev]用来设置要切换的 MMC 设备号,
- [part]是分区号。如果不写分区号的话默认为分区 0。
我们现在使用的EMMC,可以使用如下命令切换到 SD 卡:
mmc part 命令
有时候 SD 卡或者 EMMC 会有多个分区,可以使用命令“mmc part”来查看其分区。
比如查看 EMMC 的分区情况,输入如下命令:
mmc dev 1 //切换到 EMMC
mmc part //查看 EMMC 分区
由上图可知:此时 EMMC 有两个分区, 第一个分区起始扇区为 20480,长度为 262144 个扇区; 第二个分区起始扇区为 282624,长度为 14594048 个扇区。
如果 EMMC 里面烧写了 Linux 系统的话, EMMC 是有 3 个分区的:
- 第 0 个分区存放 uboot,
- 第 1 个分区存放Linux 镜像文件和设备树,
- 第 2 个分区存放根文件系统。
如果要将 EMMC 的分区 2 设置为当前 MMC 设备,可以使用如下命令:
mmc read 命令
mmc read 命令用于读取 mmc 设备的数据,命令格式如下:
mmc read addr blk# cnt
- addr 是数据读取到 DRAM 中的地址,
- blk 是要读取的块起始地址(十六进制),一个块是 512字节,
- cnt 是要读取的块数量(十六进制)。
比如从 EMMC 的第 1536(0x600)个块开始,读取 16(0x10)个块的数据到 DRAM 的0X80800000 地址处,命令如下::
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 80800000 u-boot.imx
mmc dev 0 0
mmc write 80800000 2 2E6
使用 tftp 命令将烧写文件下载到 0x80800000 地址处,假设u-boot.imx 大小为 379904 字节, 379904/512=742,所以我们要向 SD 卡中写入742 个块,如果有小数的话就要加 1 个块。使用命令“mmc write”从 SD 卡分区 0 第 2 个块(扇区)开始烧写,一共烧写 742(0x2E6)个块。
如果要在 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 需要这一步.
mmc erase 命令
如果要擦除 MMC 设备的指定块就是用命令“mmc erase”,命令格式如下:
mmc erase blk# cnt
- blk 为要擦除的起始块,
- cnt 是要擦除的数量。
本讲实验就先写到这吧,这些命令实在太多了,为了方便阅读和复习,我觉得分为上下两讲比较好。
在下讲内容里,我们会介绍:FAT 格式文件系统操作命令、EXT 格式文件系统操作命令、NAND 操作命令、BOOT 操作命令、和其它常用的命令(reset、 go、 run 和 mtest)。