LV05-01-uboot-03-uboot相关命令
本文主要是uboot相关命令的相关笔记。若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows版本 | windows11 |
Ubuntu版本 | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) |
Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
Win32DiskImager | Win32DiskImager v1.0 |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
https://elixir.bootlin.com/linux/latest/source | 在线阅读linux kernel源码 | |
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) |
这里使用的是NXP厂商提供的u-boot,u-boot的命令是可以自己定义和裁剪的。
一、几个常用命令
1. help
1.1 查看所有支持的命令
我们在 SecureCRT 终端输入 help ,便会打印出当前 uboot 所支持的所有命令。
点击查看相关命令
1 | ? - alias for 'help' |
1.2 查看指定命令帮助信息
我们输入 help(或 ? )命令名 就可以查看指定命令的详细用法 ,即
1 | ? cmd_name |
1.3 使用实例
点击查看实例
1 | => help bootz |
2. reset
2.1 使用格式
reset 命令可以用于重启开发板,我们直接在命令行输入 reset 即可:
1 | reset |
2.2 使用实例
点击查看实例
1 | => reset |
3. loadb
3.1 使用格式
loadb 命令通过串口进行数据的传输,我们一般使用该命令进行二进制文件的传输,它使用的是 kermit protocol 传输协议,一般使用格式如下:
1 | loadb [ off ] [ baud ] |
【参数说明】
- off :其实就是数据要加载到内存中的起始地址。
- baud :传输的波特率,可以不写,默认为 115200 。
【注意】我们要是使用此种方式传输裸机程序的话,需要将裸机可执行文件 xxx.bin下载到开发板 DRAM 的 0X87800000 地址处,因为裸机可执行程序的链接首地址就0x87800000,当然,我们也可以修改裸机工程中的链接文件,修改链接地址,这里与链接地址一致即可。
3.2 使用实例
点击查看详情
1 | => loadb 87800000 |
然后按下 enter 按键便会等待数据的传输,我们可以直接将文件拖拽到 SecureCRT 终端界面中,然后选择发送 Kermmit 即可开启文件传输,将会有以下提示:
1 | kermit trl+C ȡ |
4. go
4.1 使用格式
go 命令用于跳到指定的地址处执行应用,命令格式如下:
1 | go addr [arg ...] |
【参数说明】
- addr :是应用在 DRAM 中的首地址。
4.2 使用实例
点击查看详情
1 | => tftp 87800000 /imx6ull/lcd.bin |
5. run
5.1 使用格式
run 命令用于运行环境变量中定义的命令,比如可以通过 run bootcmd 来运行 bootcmd 中的启动命令,但是 run 命令最大的作用在于运行我们自定义的环境变量。
在后面调试 Linux 系统的时候可能常常要在网络启动和 EMMC/NAND 启动之间来回切换,而 bootcmd 只能保存一种启动方式,如果要换另外一种启动方式的话就得重写 bootcmd ,会很麻烦。这里我们就可以通过自定义环境变量来实现不同的启动方式,比如定义环境变量 mybootemmc 表示从 emmc 启动,定义 mybootnet 表示从网络启动,定义 mybootnand 表示从 NAND 启动。如果要切换启动方式的话只需要运行 run mybootxxx ( xxx 为 emmc 、 net 或 nand )即可。一般命令格式如下:
1 | run var [...] |
【参数说明】
- var :表示需要运行的定义了命令的环境变量名。
5.2 使用实例
点击查看详情
1 | => setenv bootcmd 'tftp 80800000 /imx6ull/zImage\;tftp 83000000 /imx6ull/imx6ull-14x14-evk.dtb\;bootz 80800000 - 83000000' |
6. mtest
mtest 命令是一个简单的内存读写测试命令,可以用来测试自己开发板上的 DDR ,一般命令格式如下:
1 | mtest [start [end [pattern [iterations]]]] |
- start :要测试的 DRAM 开始地址。
- end :是结束地址。
【注意】如果要结束测试就按下键盘上的 Ctrl + C 键。
二、信息查询
常用的和信息查询有关的命令有 3 个: printenv、bdinfo 和 version。
1. printenv
1.1 使用格式
该命令主要用于打印出所有的环境变量信息,我们在 SecureCRT 终端中直接执行下边的命令,便可以得到该命令的使用格式:
1 | => ? printenv |
该命令使用方式很简单,我们直接在命令行输入下边的命令即可。
1 | printenv [env_name] |
【参数说明】
- env_name :环境变量名,它是可选的,若要查看所有环境变量,省略该参数即可。
1.2 使用实例
1.2.1 查看所有环境变量
点击查看详情
1 |
|
1.2.2 查看指定环境变量
点击查看详情
1 | => print bootcmd |
2. bdinfo
2.1 使用格式
bdinfo 命令,此命令用于查看板子信息,直接在命令行输入该命令即可,一般使用格式如下:
1 | bdinfo |
通过该命令,我们可以看到 DRAM 的起始地址和大小、启动参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息。
2.2 使用实例
点击查看详情
1 | => bdinfo |
3. version
3.1 使用格式
version 用于查看 uboot 的版本号,直接输入 version 即可:
1 | version |
3.2 使用实例
点击查看详情
1 | => version |
三、环境变量
上边我们通过 printenv 打印出来的信息中有很多的环境变量,比如 baudrate 、 bootcmd 等等。 uboot 中的环境变量都是字符串,既然叫做环境变量,那么它的作用就和变量一样。比如 bootdelay 这个环境变量就表示 uboot 启动延时时间,默认 bootdelay=3 ,也就默认延时 3 秒。前面说的 3 秒倒计时就是由 bootdelay 定 义的,如果将 bootdelay 改为 5 的话就会倒计时 5s 了。
1. setenv
1.1 使用格式
该命令主要用于操作环境变量,我们在 SecureCRT 终端中查看一下该命令使用格式:
1 | => ? setenv |
该命令可以用于创建、修改、删除环境变量,一般使用格式如下:
1 | setenv env_name env_value |
【参数说明】
- env_name :表示要修改的环境变量名称。
- env_value : 表示环境变量的值,此参数省略的话可以用于删除相应的环境变量。
【注意】
(1)此命令修改完后,开发板若重启,那么所有环境变量将会复原。
(2)有时候我们修改的环境变量值可能会有空格, 比如 bootcmd、 bootargs 等, 这个时候环境变量值就得用单引号括起来(后便会介绍这两个环境变量)。
1.2 使用实例
1.2.1 修改环境变量
点击查看详情
我们想修改一下 uboot 启动 linux 倒计时,这个时间是由 bootdelay 环境变量来控制的,我们上边是 5 秒,我们可以通过以下命令更改秒数
1 | => printenv bootdelay |
1.2.2 创建环境变量
点击查看详情
1 | => printenv aaa |
1.2.3 删除环境变量
点击查看详情
我们创建了不想要的环境变量怎么办呢?有创建肯定有删除,该命令同样也可以删除环境变量,去掉后边的值,就可以将一个已经存在的环境变量删除:
1 | => printenv aaa |
删除后,我们打印一个不存在测环境变量便会出错。
2. saveenv
2.1 使用格式
前边的环境变量我们修改后,只在此次使用有效,当开发板关机时,修改过的环境变量全部会失效,那如何保存下来,让这些修改过的环境变量后边也依然可以生效呢?我们可以使用 saveenv 命令,我们直接在终端输入命令即可,一般格式如下:
1 | saveenv |
2.2 保存到了哪里?
我们使用这个命令后,环境变量被保存到哪里了呢?这个应该是在uboot源码中进行了定义,我没有去追踪,但是后来在一些资料中了解到,开发板若是从SD卡启动就保存到SD卡,EMMC启动就保存到EMMC,从后边学习mmc read命令的时候,可以看到环境变量存储的起始地址是从相应的mmc的0x600开始的。
2.3 使用实例
点击查看详情
1 | => saveenv |
这样我们修改过的环境变量就会被保存到 eMMC ,下一次开发板重新启动,环境变量还会是我们修改后的值。
四、内存操作
内存操作命令就是用于直接对 DRAM 进行读写操作的,常用的内存操作命令有 md、 nm、mm、 mw、 cp 和 cmp。
1. md
1.1 使用格式
md 命令用于显示内存值,格式如下:
1 | 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 ,也就是 20*2=40 个字节;如果显示格式为 .l 的话就表示 20 个 long ,也就是 20*4=80 个字节。
【注意】
(1)uboot 命令中的数字都是十六进制的,不是十进制的!命令里面的数字都是十六进制的,所以可以不用写 0x 前缀,十进制的 20 其十六进制为 0x14 ,所以命令 md 后面的个数应该是 14 ,如果写成 20 的话就表示查看 32 (十六进制为 0x20 )个字节的数据。
(2)md与[.b, .w, .l]之间没有空格,紧挨着写。
1.2 使用实例
点击查看详情
我们若想查看以 0x80000000 开始的 20 个字节的内存值,显示格式为 .b 的话,应该使用如下所示命令:
1 | => md.b 80000000 14 |
1.3 b、w、l
这三者是指定显示内存值的基本单位,我们可以实际看一下这三个参数的区别:
1 | => md.b 80000000 10 |
上面这三个命令都是查看以 0x80000000 为起始地址的内存数据,第一个命令以 .b 格式显示,长度为 0x10,也就是 16 个字节;第二个命令以 .w 格式显示,长度为 0x10,也就是 16*2=32 个字节;最后一个命令以 .l 格式显示,长度也是 0x10,也就是 16*4=64 个字节。
2. nm
2.1 使用格式
nm 命令用于修改指定地址的内存值,命令格式如下:
1 | nm[.b, .w, .l] address |
nm 命令同样可以以 .b 、 .w 和 .l 来指定操作格式。需要注意的是,修改内存需要两步,而且需要退出内存修改,后边的实例会有体现。
【注意】
(1)nm与[.b, .w, .l]之间没有空格,紧挨着写。
(2)使用 q 退出内存的修改。
2.2 使用实例
例如,我们现在要以 .l 格式修改 0x80000000 地址处数据为 12345678 ,我们输入以下命令:
1 | => nm.l 80000000 |
其中 80000000 表示现在要修改的内存地址, fff7ffff 表示地址 40008000 现在的数据, ? 后面就可以输入要修改后的数据 0x12345678 ,输入完成以后按下回车:
1 | => nm.l 80000000 |
这样我们便修改了相应的数据,然后输入 q 再按下回车就可以退出了
1 | => nm.l 80000000 |
3. mm
3.1 使用格式
mm 命令也是修改指定地址内存值的,使用 mm 修改内存值的时候地址会自增,而使用命令 nm 的话地址不会自增。使用格式如下:
1 | mm[.b, .w, .l] address |
使用方式与 nm 一致,只不过它的地址会自己增加,
【注意】
(1)mm与[.b, .w, .l]之间没有空格,紧挨着写。
3.2 使用实例
点击查看详情
此处,我们以以 .l 格式修改从地址 0x80000000 开始的连续 3 个内存块(3*4=12个字节)的数据为 0x87654321 :
1 | => mm.l 80000000 |
4. mw
4.1 使用格式
mw 用于使用一个指定的数据填充一段内存,命令格式如下:
1 | mw[.b, .w, .l] address value [count] |
【参数说明】
- [.b .w .l] :对应 byte 、 word 和 long ,也就是分别以 1 个字节 、 2 个字节、 4 个字节填充指定的内存。
- address :要查看的内存起始地址。
- value :为要填充的数据。
- count :填充的长度。
4.2 使用实例
点击查看详情
我们使用.l 格式将以 0x80000000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0x50505050,
1 | => mw.l 80000000 50505050 10 |
5. cp
5.1 使用格式
cp 是数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 Nor Flash 中的数据拷贝到 DRAM 中。命令格式如下:
1 | cp[.b, .w, .l] source target count |
【参数说明】
- [.b .w .l] :对应 byte 、 word 和 long ,也就是分别以 1 个字节 、 2 个字节、 4 个字节拷贝数据。
- source :源地址。
- target :目的地址。
- count :为拷贝的长度。
5.2 使用实例
点击查看详情
我们使用 .l 格式将 0x80000000 处的地址拷贝到 0X80000100 处,长度为 0x10 个内存块(0x10 * 4=64 个字节),命令如下所示:
1 | => md.l 80000000 10 |
6. cmp
6.1 使用格式
cmp 是比较命令,用于比较两段内存的数据是否相等,命令格式如下:
1 | cmp[.b, .w, .l] addr1 addr2 count |
【参数说明】
- [.b .w .l] :对应 byte 、 word 和 long ,也就是对应 1 个字节 、 2 个字节、 4 个字节。
- addr1 :第一段内存首地址。
- addr1 :第二段内存首地址。
- count :为要比较的长度。
6.2 使用实例
点击查看详情
我们使用 .l 格式来比较 0x80000000 和 0x80000100 这两个地址数据是否相等,比较长度为 0x10 个内存块(16 * 4=64 个字节)
1 | => md.l 80000000 10 |
五、存储器访问
uboot 支持 EMMC 和 SD 卡,因此也会提供 EMMC 和 SD 卡的操作命令。 关于存储器的访问主要是 mmc 命令,我们使用 help mmc 来查看它的帮助信息:
1 | => help mmc |
需要注意的是不同版本的uboot对命令的支持也不尽相同,关于目前使用的uboot2016.03版本中关于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
1.1 使用格式
该命令用于查看当前设备的 mmc 信息,直接输入命令即可:
1 | mmc info |
还有一个与 mmc info 命令相同功能的命令: mmcinfo,mmc和info之间没有空格。
1.2 使用实例
点击查看详情
1 | => mmc info |
这里我们采用的是从SD卡启动,所以默认的设备是SD卡,所以这里显示的是SD卡的相关信息。
2. mmc rescan
mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备,包括 EMMC 和 SD 卡,直接输入 mmc rescan 即可。
1 | mmc rescan |
3. mmc list
3.1 使用格式
mmc list 命令用于来查看当前开发板一共有几个 MMC 设备,直接输入 mmc list 即可:
1 | mmc list |
3.2 使用实例
点击查看详情
1 | => mmc list |
可以看出当前开发板有两个 MMC 设备: FSL_SDHC:0 和 FSL_SDHC:1 (eMMC),这是因为现在用的是 EMMC 版本的核心板,加上 SD 卡一共有两个 MMC 设备, FSL_SDHC:0 是 SD卡, FSL_SDHC:1是 EMMC。由于我们启动方式设置的是从SD卡启动,所以默认会将 SD 卡设置为当前 MMC 设备,这就是为什么输入“mmc info”查询到的是 SD卡 设备信息,而不是 EMMC 。要想查看 EMMC 信息,就要使
用命令“mmc dev”来将 EMMC 设置为当前的 MMC 设备。
4. mmc dev
4.1 使用格式
mmc dev 命令用于切换当前 MMC 设备,一般使用格式如下:
1 | mmc dev [dev] [part] |
【参数说明】
- dev :设置要切换的 MMC 设备号。
- part :分区号,如果不写分区号的话默认为分区 0 。
4.2 使用实例
点击查看详情
1 | => mmc list |
5. mmc part
5.1 使用格式
有时候 SD 卡或者 EMMC 会有多个分区,可以使用命令 mmc part 来查看其分区,直接输入命令即可:
1 | mmc part |
5.2 使用实例
点击查看详情
我们来查看一下开发板中 emmc 的分区情况:
1 | => mmc dev 1 |
此时 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 里面。
6. mmc read
6.1 使用格式
mmc read 命令用于将 MMC 中指定扇区中的内容读取到内存中指定的地址,命令格式如下:
1 | mmc read <dev_num> addr blk# cnt |
【参数说明】
- dev_num : mmc 的设备号,可以通过 mmc list 查询到,这个参数可以不写,不写的话默认为当前 mmc 设备。
- addr :数据读取到内存中的起始地址。
- blk# :要读取的块起始地址 (十六进制 ),一个块是 512 字节,这里的块和扇区是一个意思,在 MMC 设备中我们通常说扇区。
- cnt :要读取的块数量 (十六进制 )。
【注意】一个块是 512 字节。
6.2 使用实例
点击查看详情
我们这里使用的mmc设备为SD卡,我们从 SD卡的第 1536(0x600)个块开始,读取 16(0x10)个块的数据到 DRAM 的0x80800000 地址处,命令如下:
1 | => md.l 80800000 20 |
从这里我们可以看到,uboot的环境变量是保存在了SD卡中,并且存储起始地址就是1536*512=786432。
7. mmc write
7.1 使用格式
mmc write 命令用于将数据写到 MMC 设备里面。我们可以使用命令 mmc write命令来升级 uboot ,也就是在 uboot 中更新uboot 。这里会要用到 nfs 或者 tftp 命令,通过 nfs 或者 tftp 命令将新的 u-boot.bin 下载到开发板的 DRAM 中,然后再使用命令 mmc write 将其写入到 MMC 设备中。一般使用格式如下:
1 | mmc write <dev_num> addr blk# cnt |
【参数说明】
- dev_num : mmc 的设备号,可以通过 mmc list 查询到,这个参数可以不写,不写的话默认为当前 mmc 设备。
- addr :数据将要写入到内存中的起始地址。
- blk# :要写入的块起始地址 (十六进制 ),一个块是 512 字节,这里的块和扇区是一个意思,在 MMC 设备中我们通常说扇区。
- cnt :要写入的块数量 (十六进制 )。
【注意】千万不要写 SD 卡或者 EMMC 的前两个块 (扇区 ),里面保存着分区表。
7.2 使用实例
我们可以使用命令 mmc write 来升级 uboot,也就是在 uboot 中更新 uboot。这里要用到 nfs 或者 tftp 命令,通过 nfs 或者 tftp 命令将新的 u-boot.bin 下载到开发板的 DRAM 中,然后再使用命令 mmc write 将其写入到 MMC设备中。
7.2.1 更新SD卡中的uboot
- 查看原来的uboot信息
1 | => mmc dev 0 |
我们切换到SD卡设备,然后查看一下当前的uboot信息,可以看到目前的uboot编译时间为 Sep 25 2022 - 21:24:46。
- 重新编译uboot,并生成load.imx文件
重编编译uboot后,我们会得到一个 u-boot.bin 文件,这个文件不能直接使用,我们还需要通过烧写工具加上一些信息,得到一个 .imx 文件,这个可以修改一下源码,将 imxdownload.c 文件中的这句注释掉:
1 | system(cmdbuf); |
这样就不会真的烧写到设备节点啦,所以这个情况下,设备节点随便写就是了,然后我们就会得到一个 load.imx文件,然后我们将这个文件放到tftp目录下:
1 | /home/hk/3tftp/imx6ull/load.imx |
点击查看直接方式
其实,uboot源码中带有一个工具,我们编译好uboot后,会自动生成一个 u-boot.imx 文件,我们可以直接使用的。
- 通过tftp下载uboot
1 | => tftp 80800000 /imx6ull/load.imx |
可以看出,load.imx 大小为 421464 字节, 421464/512=824,所以我们要向 SD 卡中写入824(0x338)个块(如果有小数的话就要加 1 个块 )。
- 写入uboot到SD卡中
1 | => mmc dev 0 0 |
- 重启开发板,查看编译时间
1 | => version |
可以看到此时的uboot编译时间变成了 Oct 13 2022 - 17:11:27,这也就意味着我们完成了SD卡中uboot的更新。
7.2.2 更新EMMC中uboot
其实跟更新SD卡中 uboot 过程类似,这里只写需要的命令(在开发板的终端执行):
1 | mmc dev 1 0 # 切换到 EMMC 分区 0 |
8. mmc erase
mmc erase 命令用于擦除 MMC 设备的指定块,一般使用格式如下:
1 | mmc erase blk# cnt |
【参数说明】
- blk# :要擦除的起始块。
- cnt :要擦除的数量。
【注意】一般不要用 mmc erase 来擦除 MMC 设备。
六、网络操作
在 uboot 中,至少支持的外设就是串口和网口,因为我们需要通过这两个外设进行文件的传输,下边我们先来学习一下网络操作相关命令吧。这里需要注意I.MX6U-ALPHA 开发板有两个网口: ENET1 和 ENET2,一定要连接 ENET2,当然也可以修改uboot源码,使其改为 ENET1 ,默认没有修改的是使用的 ENET2。
1. 网络环境变量
要使用网络的话,还是需要先设置一下网络的相关环境变量。相关的环境变量如下:
环境变量 | 描述 |
ipaddr | 开发板 IP 地址,可以不设置,使用 dhcp 命令来从路由器获取 IP 地址。 |
ethaddr | 开发板的 MAC 地址,一定要设置。 |
gatewayip | 网关地址。 |
netmask | 子网掩码。 |
serverip | 服务器IP地址,也就是 Ubuntu主机 IP 地址,用于调试代码。 |
【注意】
(1)开发板的 IP 一定要与 ubuntu 主机的 IP 处于网段,这样才能实现网络通信。
(2)如果在同一个网段内有多个开发板的话一定要保证每个开发板的 ethaddr 是不同的,否则通信会有问题。
我的一般设置如下:
1 | => setenv ipaddr 192.168.10.102 |
2. ping
2.1 使用格式
我们的开发板的网络能否使用,是否可以和服务器 ( Ubuntu 主机 )进行通信,可以通过 ping 命令验证,直接 ping 服务器的 IP 地址即可,一般格式如下:
1 | ping ip_addr |
【参数说明】
- ip_addr :表示我们要测试是否可联通的的 ip 地址。
【注意】
(1)只能在 uboot 中 ping 其他的机器,其他机器不能 ping uboot ,因为 uboot 没有对 ping 命令做处理,如果用其他的机器 ping uboot 的话会失败。
2.2 使用实例
点击查看详情
比如我的服务器 IP 地址为 192.168.10.100 ,那么命令格式如下:
1 | ping 192.168.10.100 |
如果连接成功的话,会有以下信息提示:
1 | => ping 192.168.10.100 |
如果连接不成功(服务器没开启或者说 IP 不在同一网段的话),可能会有以下提示:
1 | => ping 192.168.10.102 |
3. dhcp
dhcp 用于从路由器获取 IP 地址,前提得开发板连接到路由器上的,如果开发板是和电脑直连的,那么 dhcp 命令就会失效。直接输入 dhcp 命令即可通过路由器获取到 IP 地址。
4. tftp
4.1 使用格式
tftp 命令用于通过网络下载数据到指定的内存地址中, tftp 命令使用的是 TFTP 协议, ubuntu 主机作为 TFTP 服务器。因此需要在 ubuntu 上搭建 TFTP 服务器,之前的时候我们已经搭建并本地验证过了(Linux开发中的《LV10-01-TFTP和NFS》这篇笔记),在 uboot 中使用的格式如下:
1 | tftpboot [loadAddress] [[hostIPaddr:]bootfilename] |
【参数说明】
- tftpboot :命令的全称,但是其实我们输入一个 tftp 就足够了。
- loadAddress :是要下载的文件在内存( DRAM )中的存放地址。
- hostIPaddr :服务器的 IP 地址,实际就是 ubuntu 主机的 IP 地址,如果说前边我们设置了 serverip 环境变量的话,这里是可以省略的。
- bootfilename :是要从 ubuntu 中下载的文件这个文件是以服务器中 tftp 目录为根目录的。
4.2 使用实例
点击查看详情
例如,我们前边设置的 tftp 目录为 /home/hk/3tftp ,然后我们需要下载这个文件:
1 | /home/hk/3tftp/imx6ull/lcd.bin |
这个时候我们使用的命令如下:
1 | => tftp 80000000 /imx6ull/lcd.bin |
按下 enter 按键之后,我们会得到以下提示:
1 | => tftp 80000000 /imx6ull/lcd.bin |
5. nfs
5.1 命令简介
nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源,比如我们将 linux 镜像和设备树文件放到 ubuntu 中,然后在 uboot 中使用 nfs 命令将 ubuntu 中的 linux 镜像和设备树下载到开发板的 DRAM 中。这样做的目的是为了方便调试 linux 镜像和设备树,也就是网络调试,通过网络调试是 Linux 开发中最常用的调试方法。
原因是嵌入式 linux开发不像单片机开发,可以直接通过 JLINK 或 STLink 等仿真器将代码直接烧写到单片机内部的 flash 中,嵌入式 Linux 通常是烧写到 EMMC、 NAND Flash、 SPI Flash 等外置 flash 中,但是嵌入式 Linux 开发也没有 MDK, IAR 这样的 IDE,更没有烧写算法,因此不可能通过点击一个“download”按钮就将固件烧写到外部 flash 中。虽然半导体厂商一般都会提供一个烧写固件的软件,但是这个软件使用起来比较复杂,这个烧写软件一般用于量产的。其远没有 MDK、 IAR的一键下载方便,在 Linux 内核调试阶段,如果用这个烧写软件的话将会非常浪费时间,而这个时候网络调试的优势就显现出来了,可以通过网络将编译好的 linux 镜像和设备树文件下载到 DRAM 中,然后就可以直接运行。
5.2 使用格式
首先是需要搭建nfs的环境,可以看这篇笔记:Linux开发中的《LV10-01-TFTP和NFS》。一般使用格式如下:
1 | nfs [loadAddress] [[hostIPaddr:]bootfilename] |
【参数说明】
- nfs :命令的全称。
- loadAddress :是要下载的文件在内存( DRAM )中的保存的地址。
- hostIPaddr :服务器的 IP 地址,实际就是 ubuntu 主机的 IP 地址,如果说前边我们设置了 serverip 环境变量的话,这里是可以省略的。
- bootfilename :是要从 ubuntu 中下载的文件,这里似乎是需要一个相对于ubuntu根目录的绝对路径才可以。
5.3 使用实例
点击查看详情
我们在ubuntu的nfs目录中有这样一个文件:
1 | /home/hk/4nfs/imx_rootfs/linuxrc |
我们现在通过nfs命令将这个文件下载到开发板内存的 0x80000000,可使用如下命令:
1 | => nfs 80000000 192.168.10.101:/home/hk/4nfs/imx_rootfs/linuxrc |
这里关于后边文件路径问题,我尝试了使用 nfs 目录作为根目录,这样就无法找到相应的文件了,会有如下情况:
1 | => nfs 80000000 192.168.10.101:/imx_rootfs/linuxrc |
七、文件系统操作
有时候需要在 uboot 中对 SD 卡或者 EMMC 中存储的文件进行操作,这时候就要用到文件操作命令。
1. FAT 格式文件系统
1.1 fatinfo
1.1.1 使用格式
fatinfo 命令用于查询指定 MMC 设备分区的文件系统信息,一般格式如下:
1 | fatinfo <interface> [<dev[:part]>] |
【参数说明】
- interface :表示接口,比如 mmc。
- dev :查询的设备号。
- part :要查询的分区。
1.1.2 使用实例
点击查看详情
我们要查询 EMMC 分区 1 的文件系统信息,命令如下:
1 | => fatinfo mmc 1:1 |
1.2 fatls
1.2.1 使用格式
fatls 命令用于查询 FAT 格式设备的目录和文件信息,一般格式如下:
1 | fatls <interface> [<dev[:part]>] [directory] |
【参数说明】
- interface :表示接口,比如 mmc 。
- dev :查询的设备号。
- part :要查询的分区。
- directory :是要查询的目录。
1.2.2 使用实例
点击查看详情
我们要查询 EMMC 分区 1 的所有目录和文件(正点原子开发板出厂的时候EMMC中有相应的一些文件),命令如下:
1 | => fatls mmc 1:1 |
1.3 fstype
1.3.1 使用格式
fstype 命令用于查看 MMC 设备某个分区的文件系统格式 ,一般格式如下:
1 | fstype <interface> <dev>:<part> |
【参数说明】
- interface :表示接口,比如 mmc 。
- dev :查询的设备号。
- part :要查询的分区。
1.3.2 使用实例
点击查看详情
在正点原子 EMMC 核心板上的 EMMC 在出厂的时候默认有 3 个分区,我们来查看一下这三个分区的文件系统格式 ,命令如下:
1 | => fstype mmc 1:0 |
分区 0 格式未知,因为分区 0 存放的 uboot,并且分区 0 没有格式化,所以文件系统格式未知。
分区 1 的格式为 fat,分区 1 用于存放 linux 镜像和设备树。
分区 2 的格式为 ext4,用于存放 Linux 的根文件系统(rootfs)。
1.4 fatload
1.4.1 使用格式
fatload 命令用于将指定的文件读取到内存中,命令格式如下:,格式如下:
1 | fatload <interface> [<dev[:part]>] <addr> <filename> [bytes [pos]] |
【参数说明】
- interface :表示接口,比如 mmc 。
- dev :设备号。
- part :分区。
- addr :要保存到内存中的起始地址。
- filename :要读取的文件名字。
- bytes :表示读取多少字节的数据,如果 bytes 为 0 或者省略的话表示读取整个文件。
- pos :是要读的文件相对于文件首地址的偏移,如果为 0 或者省略的话表示从文件首地址开始读取。
1.4.2 使用实例
点击查看详情
我们将 EMMC 分区 1 中的 zImage 文件读取到 DRAM 中的0x80800000 地址处,命令如下:
1 | => fatls mmc 1:1 |
可以看出在 223ms 内读取了 6785360 个字节的数据,速度为 29MiB/s,速度是非常快的,因为这是从 EMMC 里面读取的,而 EMMC 是 8 位的,速度就很快了。
1.5 fatwrite
1.5.1 使用格式
fatwrite 命令用于将 DRAM 中的数据写入到 MMC 设备中,命令格式如下:,格式如下:
1 | fatwrite <interface> <dev[:part]> <addr> <filename> <bytes> |
【参数说明】
- interface :表示接口,比如 mmc 。
- dev :设备号。
- part :分区。
- addr :要保存到内存中的起始地址。
- filename :要写入的文件名字。
- bytes :表示读取多少字节的数据。
【注意】uboot 默认没有使能 fatwrite 命令,需要修改板子配置头文件,例如,mx6ullevk.h、mx6ull_alientek_emmc.h 等等,板子不同,其配置头文件也不同。找到所用的开发板对应的配置头文件然后添加如下一行宏定义来使能 fatwrite 命令:
1 |
1.5.2 使用实例
点击查看详情
这里没有实际的去测试,使用的命令格式如下:
1 | tftp 80800000 zImage |
zImage 大小为 6785272(0X6788f8)个字节(注意,由于开发板系统在不断的更新中,因此zImage 大小不是固定的,一切以实际大小为准)
2. EXT 格式文件系统
uboot 有 ext2 和 ext4 这两种格式的文件系统的操作命令,常用的就四个命令,分别为:ext2load、 ext2ls、 ext4load、 ext4ls 和ext4write。这些命令的含义和使用与 fatload、 fatls 和 fatwrite一样,只是 ext2 和 ext4 都是针对 ext 文件系统的。
八、boot 操作
1.两个环境变量
1.1 boodcmd
bootcmd 环境变量中保存着 uboot 的默认命令,该环境变量其实也叫做自启动环境变量。在我们重启开发板的时候,会有这么一个提示信息:
1 | Hit any key to stop autoboot : 3 |
这里就是 uboot 倒计时,这里的这个时间由环境变量 bootdelay 控制,当倒计时结束之前按下任意按键,就会进入 uboot 的一个命令行的模式,着大盖就类似于我们重装 windows 系统时的 BIOS 系统一样。
当我们在倒计时期间没有按下任何按键的话,倒计时结束以后就会执行 bootcmd 中的命令。这些命令一般用来启动 linu 内核,比如读取 EMMC 或者 NAND Flash 中的 linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 linux 内核。可以在 uboot 启动以后进入命令行设置 bootcmd 环境变量的值。如果 EMMC 或者 NAND 中没有保存 bootcmd 的值,那么 uboot 就会使用默认的值,板子第一次运行 uboot 的时候都会使用默认值来设置 bootcmd 环境变量。
【注意】该环境变量中可以有多条命令,多条命令之间用 \;
分隔开,修改完后我们需要将环境变量进行保存,否则下次重启,我们设置的环境变量就会失效。
【设置实例】
另外,我们可以通过 run 命令来运行这个环境变量中的命令。例如,
1 | => setenv bootcmd 'tftp 80800000 /imx6ull/zImage\;tftp 83000000 /imx6ull/imx6ull-14x14-evk.dtb\;bootz 80800000 - 83000000' |
1.2 bootargs
bootargs 保存着 uboot 传递给 Linux 内核的参数,也被叫做自启动参数, uboot 不需要使用。在 Linux 内核源码里面有相应的文档讲解如何设置,文档为 Documentation/filesystems/nfs/nfsroot.txt ,后边可以看一下,常见的格式如下:
1 | root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip> |
点击查看参数说明
【参数说明】
- server-ip :服务器 IP 地址,也就是存放根文件系统主机的 IP 地址,那就是 ubuntu 的 IP地址,比如我的 ubuntu 主机 IP 地址为 192.168.10.101。
- root-dir : 根文件系统的存放路径,比如我的就是 /home/hk/4nfs。
- nfs-options : NFS 的其他可选选项,一般不设置。
- client-ip : 客户端 IP 地址,也就是开发板的 IP 地址, Linux 内核启动以后就会使用此 IP 地址来配置开发板。注意此地址一定要和 ubuntu 主机在同一个网段内,并且没有被其他的设备使用,在 ubuntu 中使用 ping 命令 ping 一下就知道要设置的 IP 地址有没有被使用,如果不能 ping 通就说明没有被使用,那么就可以设置为开发板的 IP 地址,比如我的开发板设置为192.168.10.102。
- server-ip : 服务器 IP 地址,就是ubuntu的IP地址,我的是192.168.10.101。
- gw-ip : 网关地址,我的是 192.168.10.1。
- netmask :子网掩码,我的是 255.255.255.0。
- hostname :客户机的名字,一般不设置,此值可以空着。
- device : 设备名,也就是网卡名,一般是 eth0, eth1….,正点原子的 I.MX6U-ALPHA 开发板的 ENET2 为 eth0, ENET1 为 eth1。如果电脑只有一个网卡,那么基本只能是 eth0,这里我们使用 ENET2,所以网卡名就是 eth0。
- autoconf : 自动配置,一般不使用,所以设置为 off。
- dns0-ip : DNS0 服务器 IP 地址,不使用。
- dns1-ip : DNS1 服务器 IP 地址,不使用。
根据上边这个格式,我们的bootargs参数可以设置为:
1 | root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs/imx_rootfs,proto=tcp rw ip=192.168.10.102:192.168.10.101:192.168.10.1:255.255.255.0::eth0:off |
其中 proto=tcp 表示使用 TCP 协议, rw 表示 nfs 挂载的根文件系统为可读可写 。
【设置实例】
最终我们设置的bootargs参数为:
1 | => setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.101:/home/hk/4nfs/imx_rootfs,proto=tcp rw ip=192.168.10.102:192.168.10.101:192.168.10.1:255.255.255.0::eth0:off init=/linuxrc' |
【命令说明】
console
console 用来设置 linux 终端(或者叫控制台),也就是开发板安装好 linux 后,我们通过什么设备来和 Linux 进行交互,是串口还是 LCD 屏幕?如果是串口的话串口号是多少等。这里设置 console 为 ttySAC2 。 ttySAC2 后面有个 ,115200 ,这是设置串口的波特率, console=ttySAC2,115200 综合起来就是设置 ttySAC2 作为 Linux 的终端,并且串口波特率设置为 115200 。init
init 用来指定 init 进程的程序路径,一般 init=/linuxrc , 或者 init=/etc/preinit , preinit 的内容一般是创建 console 、 null 设备节点,运行 init 程序,挂载一些文件系统等操作。我们可能以为 init=/linuxrc 是固定写法,其实不然, /linuxrc 指的是 / 目录下面的 linuxrc 脚本,一般指向 busybox 。
2. bootz
要启动 Linux,需要先将 Linux 镜像文件拷贝到 DRAM 中,如果使用到设备树的话也需要将设备树拷贝到 DRAM 中。可以从 EMMC 或者 NAND 等存储设备中将 Linux 镜像和设备树文件拷贝到 DRAM,也可以通过 nfs 或者 tftp 将 Linux 镜像文件和设备树文件下载到 DRAM 中。不管用那种方法,只要能将 Linux 镜像和设备树文件存到 DRAM 中就行,然后使用 bootz 命令来启动, bootz 命令用于启动 zImage 镜像文件
2.1 使用格式
一般使用格式如下:
1 | bootz [addr [initrd[:size]] [fdt]] |
【参数说明】
- addr :Linux 镜像文件在 DRAM 中的位置
- initrd :是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘ - ’代替即可。
点击查看什么是 initrd
Linux初始RAM磁盘(initrd)是在系统引导过程中挂载的一个临时根文件系统,用来支持两阶段的引导过程。initrd文件中包含了各种可执行程序和驱动程序,它们可以用来挂载实际的根文件系统,然后再将这个 initrd RAM磁盘卸载,并释放内存。在很多嵌入式Linux系统中,initrd 就是最终的根文件系统。
- fdt :就是设备树文件在 DRAM 中的地址。
2.2 使用实例
2.2.1 通过网络下载文件
点击查看详情
首先我们在ubuntu中准备好所需文件:
1 | /home/hk/3tftp/imx6ull/zImage # linux镜像文件 |
然后我们下载相应文件到开发板指定位置:
1 | => tftp 80800000 /imx6ull/zImage |
所有命令运行结果如下:
2.2.2 通过EMMC启动
我们要从 EMMC 中启动 Linux 系统的话只需要使用命令 fatload 将 zImage 和 imx6ull-14x14-evk.dtb 从EMMC 的分区 1 中拷贝到 DRAM 中,然后使用命令 bootz 启动即可。
先使用命令 fatls 查看要下 EMMC 的分区 1 中有没有 Linux 镜像文件和设备树文件,如果没有的话就使用 fatwrite 命令将服务器tftp目录下的中的 zImage 和 imx6ull-14x14-evk.dtb 文件下载到内存,然后烧写到 EMMC 的分区 1 中。
EMMC中有相应的linux镜像文件和设备树文件后,我们就可以使用命令 fatload 将 zImage 和 imx6ull-14x14-evk.dtb文件拷贝到 DRAM 中,地址分别为 0x80800000 和 0x83000000,最后使用 bootz 启动。
1 | fatload mmc 1:1 80800000 zImage |
3. bootm
3.1 使用格式
boom 命令也是用于启动linux系统的,不使用设备树时,一般使用格式如下:
1 | bootm [addr [arg ...]] |
【参数说明】
- addr 是 linux 镜像在 DRAM 中的首地址。
- arg :可以是一个 initrd 映像的地址,当引导一个需要设备树的 Linux 内核时,需要第三个参数,它是设备树的地址。要在不使用 initrd 镜像的情况下引导内核,我们需要使用 - 作为第二个参数。
其实有的资料中,该命令格式是这样的,我感觉更加详细一点:
1 | bootm [addr [initrd[:size]] [fdt]] |
【参数说明】
- addr :是 Linux 镜像文件在 DRAM 中的位置,
- initrd :是 initrd 文件在 DRAM 中的地址,如果不使用 initrd 的话使用 - 代替即可 。
- fdt :就是设备树文件在 DRAM 中的地址。
【注意】若不使用相应的地址,对应的位置写 - 。
或者直接这样写可能更清晰一点:
1 | bootm kernel-addr ramdisk-addr dtb-addr |
【参数说明】
- kernel-addr : 内核的下载地址 。
- ramdisk-addr : 根文件系统的下载地址。
- dtb-addr : 设备树的下载地址。
【注意】若不使用相应的地址,对应的位置写 - 。
3.2 使用实例
与bootz一样。
4. boot
4.1 使用格式
boot 命令也是用来启动 Linux 系统的,只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统,一般使用格式如下:
1 | boot |
【注意】它启动linux的时候需要借助 bootcmd 环境变量。
4.2 使用实例
点击查看详情
使用该命令的时候,我们需要输入的命令有:
1 | setenv bootcmd 'tftp 80800000 /imx6ull/zImage\;tftp 83000000 /imx6ull/imx6ull-14x14-evk.dtb\;bootz 80800000 - 83000000' |