嵌入式Linux(十七)Linux系统移植之U-Boot

1. 系统固化方法及移植初识

1.1 系统固化

  其实就是烧写系统。windows下直接用正点原子改过的mfgtool烧写即可,ubuntu下要用脚本固化比较麻烦,还是建议用windows的工具。注意因为我用的是正点原子的板子所以用他们家的mfgtool,最好用和自己板子适配的。

1.2 系统移植概述

  Linux系统的移植可以简单分为三步:①移植bootloader代码,用于启动Linux内核,常用的比如U-Boot;②移植Linux内核;③移植根文件系统tootfs。

2. U-Boot

2.1 Bootloader

  Bootloader程序首先会初始化DDR等外设,然后将Linux内核从flash中拷贝到DDR,最后启动内核。Bootloader和Linux系统的关系类似于BIOS和Windows的关系。U-Boot是一个常用的Bootloader,是一个裸机综合程序。

3. U-Boot初次移植

3.1 配置U-Boot

  根据不同的uboot源码和板子,需要各自进行配置,步骤类似,以EMMC版本的6ull为例,配置指令如下所示。其中第一行指令为makefile指定架构和交叉编译器并进行一次清零;第二行指令使用对应的配置文件配置uboot;第三行指令为编译uboot。
在这里插入图片描述
  编译得到u-boot.bin文件是一个裸机程序,需要加上头部才能在6ull上执行,uboot编译过程最后会通过/tools/mkimage软件添加头部信息生成u-boot.imx。
  以上操作可以由脚本完成。不过如果配置过uboot,shell脚本的第一行指令会清除整个工程,导致配置项也会被删除,所以为了方便可以直接在makefile里面配置好ARCH和CROSS_COMPILE变量。以后直接make就行

3.2 固化

  首先将刚才得到的imx文件复制到windows下,替换掉mfgtool/Profiles下两个子文件夹对应emmc版本的imx文件(注意重命名为指定格式)。然后用mfgtool进行OTG烧写就行,EMMC启动。
  为了调试方便还是直接用SD卡吧。烧写之后启动,信息如下:
在这里插入图片描述
  使用mmc list命令查看设备,mmc dev 0/1分别检查SD卡和EMMC,mmc info检查两者驱动。都OK。那么唯一的问题是网络驱动还有问题,显示"'No ethernet found"。查了一下发现是正点原子的uboot版本和新的开发板对不上,换最新的uboot源码就解决了,具体的原因应该是网卡驱动的配置问题。
在这里插入图片描述

4. U-Boot命令

  help + 命令名可以查看帮助。

4.1 信息查询命令

①bdinfo:查看板子信息。DARM的起始地址和大小,启动参数保存起始地址,波特率,sp起始地址等。
printenv:输出环境变量信息。
③version:查看uboot版本号。

4.2 操作环境变量

1)修改,添加,删除环境变量–setenv
①修改-修改bootdelay为3:setenv bootdelay 3
②添加-给不存在的环境变量赋值就会创建:setenv author FSY
③删除-给环境变量赋空:setenv author
2)保存环境变量–saveenv

4.3 内存操作命令

  直接对DRAM进行操作的命令。
①md–显示内存值:md [.b .w .l] address [# of objects]
  [.b .w .l]分别对应以以1,2,4个字节来显示内存值。address是要查看的内存起始地址。[# of objects]表示要看的数据长度。这里需要注意uboot里的数字都是十六进制的,比如md.b要查看20字节需要输入14而不是20,md.w则是输入A即可。
②nm–修改指定地址内存值:nm [.b, .w, .l] address
在这里插入图片描述
  在?后面输入要修改的值,然后回车输入q即可退出修改。修改完可以用md命令查看一下。
③mm–修改指定地址内存值:区别于nm的是,mm修改内存值时地址会自增,直到输入q退出为止 ,用于连续修改。
④mw–利用一个指定数据填充一段内存:mw [.b, .w, .l] address value [count]
  value时填充数据,count是填充的长度。
⑤cp–将DRAM中的数据从一段内存中拷贝到另一端内存中:cp [.b, .w, .l] source target count
  source为源地址,target为目标地址,count为拷贝长度。
⑥cmp–比较两端内存数据是否相等:cmp [.b, .w, .l] addr1 addr2 count

4.4 网络操作命令

  先用网线吧开发板的ENET2口和电脑或者路由器以保证电脑和板子在一个网段。然后直接ping一下ubuntu的地址,ifconfig即可查看。如下图,可以发现ping不通,提示没设置环境变量。
在这里插入图片描述
  设置一下,先ping一下新地址看看有没有被其他设备占用:
在这里插入图片描述
  环境变量设置
  ipaddr设置为192.168.222.51(因为我的ubuntu主机ip地址为192.168.222.132,要确保在同一个网段下),ethaddr是b8:ae:1d:01:00:00,gatewayip为192.168.222.1,netmask为255.255.255.0,serverip为192.168.222.132。
在这里插入图片描述
①ping–验证是否可以和ubuntu主机通信
  一定要确保ipaddr是可以用的ip地址,然后我本来是ping不通的,好像是虚拟机没有设置为桥接模式,解决办法是先将win10的网络适配器里的有线网卡手动设置到192.168.222.2网段,以及netmask,然后将虚拟机设置为桥接模式,选择有线网卡即可,就可以ping通了。想要了解更多可以看这篇博客:https://segmentfault.com/a/1190000041827346
在这里插入图片描述

②dhcp–从路由器获取ip地址
  必须是开发板连到路由器上的,我的开发板是电脑直连的,所以这个命令会失效。该命令还会通过TFTP启动linux内核。

③nfs–网络文件系统
  作用是网络调试。使用nfs可以将ubuntu中的linux镜像和设备树通过网络下载到开发板的DRAM中,不需要每次都用mfgtool烧写。
  使用之前需要在ubuntu中开启NFS服务,并且新建一个NFS使用的目录,之后需要通过NFS访问的文件都放到该目录下。这里已经在前面的学习中设置过了。
  uboot中nfs命令格式:nfs [loadAddress] [[hostIPaddr:] bootfilename]。其中loadAddress为要保存的DRAM地址,[[hostIPaddr:] bootfilename]是要下载到开发板的文件地址。
  首先将zImage镜像文件放到nfs文件夹下,然后下载到开发板DRAM的0x80800000地址。报错了,喜闻乐见。
在这里插入图片描述
  百度了一下错误原因,可以确定是ubuntu的nfs版本太高,开发板的是低版本nfs导致不兼容。输入sudo vim /etc/default/nfs-kernel-server修改文件,然后输入sudo /etc/init.d/nfs-kernel-server restart重启一下nfs服务:
在这里插入图片描述
  再下载一次,成功了。参考博客:https://blog.csdn.net/qq_41709234/article/details/123160029
在这里插入图片描述
  在uboot中使用md命令查看一下,和winhex打开同样的zImage文件查看一下,可以看到内存值是一样的,所以下载的镜像没什么问题。
在这里插入图片描述

④tftp
  作用和nfs类似,只不过用的是TFTP协议,ubuntu主机作为TFTP服务器。
首先创建文件夹并给予权限,然后创建一个内容如下的文件:
在这里插入图片描述
  然后就是安装配置tftp,不过我这里因为源的问题下载不了,无线网卡丢在学校,ubuntu没法上网,先不搞了。

⑤EMMC和SD卡操作命令
mmc0为SD卡,mmc1为EMMC。
,长度为在这里插入图片描述
  mmc part:列出mmc设备分区,可以看到当前为EMMC,第1分区起始扇区为2048,长度65536扇区,第2分区起始扇区67584,长度15185920扇区。EMMC中烧写了linux系统后,内部会有三个分区,第0分区存放uboot,第1分区存放linux镜像和设备树,第2分区存放根文件系统。
在这里插入图片描述
  SD卡默认只有第0分区,uboot就是烧到这里,后面进行内核移植的时候需要在其中创建并格式化第1分区,存放linux镜像和设备树。
在这里插入图片描述
  mmc read addr blk# cnt:addr是数据读取到DRAM的地址,blk(十六进制)是要读取的扇区起始地址,一个扇区为512字节,cnt(十六进制)是要读取的扇区长度。
  mmc write addr blk# cnt:可以用来升级uboot。这里需要注意不管是SD还是EMMC,都不要往前两个扇区写入,里面保存了分区表。

⑥FAT格式文件系统操作命令
  在uboot中对mmc中的文件进行操作,以下命令只支持FAT文件格式的文件系统。
1)fatinfo [interface] [dev[:part]]。查询指定mmc设备的分区信息。interface表示接口比如mmc,dev是查询的设备号,part是分区。如下图查询了SD卡的分区1,是FAT32格式的。
在这里插入图片描述
2)fatls [interface] [dev[:part]] [directory]。查询FAT格式设备的目录和文件信息。directory是要查询的目录。如下图可以看出SD卡的分区1中存放了0个文件。
在这里插入图片描述
3)fstype [interface] [dev]:[part]。用于查看mmc设备某个分区的文件系统格式。 如下图查看了EMMC三个分区的文件格式,分区0存放的是uboot且尚未格式化所以未知,分区1为fat,分区2为ext4。
在这里插入图片描述
4)fatload [interface] [dev[:part] [addr[filename[bytes[pos]]]]]。用于将指定的文件读取到DRAM。addr是保存在DRAM中的起始地址,filename是要读取的文件名,bytes表示要读取多少字节的数据(为0或省略表示读取整个文件),pos是要读取的文件相对于文件首地址的偏移(为0或省略表示从首地址开始读取)。将EMMC分区1的zImage文件读取到DRAM中的0x80800000处:
在这里插入图片描述
5)fatwrite [interface] [dev[:part]] [addr] [filename] [bytes]。将DRAM中的数据写入到MMC设备。首先在配置头文件中加上#define CONFIG_FAT_WRITE使能fatwrite命令。之前已经用nfs将镜像下载到DRAM的80800000了,使用fatwrite将其写入到EMMC的分区1(我的zImage大小为0x6789c8字节,下图是错误的,懒得换图了):
在这里插入图片描述
用fatls查看了一下,确实写进去了。
在这里插入图片描述

⑦EXT格式文件系统操作命令
  主要就是ext2load,ext2ls,ext4load,ext4ls,ext4write。作用和fat的一样,只不过是针对ext系统的。所以在使用之前最好先用fstype命令查看一下分区的文件格式。

⑧BOOT操作命令
  uboot是用于引导linux的,相关的命令有bootz,bootm和boot。
1)bootz [addr [initrd[:size]] [fdt]]:使用linux需要将镜像文件zImage和设备树dtb文件放到DRAM。使用nfs或者tftp下载到DRAM或者从MMC中拷贝到DRAM后,使用bootz启动镜像文件
  addr在是linux镜像文件在DRAM中的地址,initrd是initrd文件在DRAM中的地址(不使用initrd文件的话用"-"代替),fdt是dtb文件在DRAM中的地址。
  用nfs下载了zImage和dtb,使用bootz启动,这里可以看到linux启动了,后面会卡住,先不管。
在这里插入图片描述
  也可以从EMMC中读取,首先查看一下emmc里有没有镜像文件和设备树。然后使用fatload进行下载。
在这里插入图片描述
在这里插入图片描述
  bootz后提示Bad linux arm什么的,感觉就是前面第一次写的zImage大小不对导致的,重新写了一遍。然后再fatload一下镜像和设备树,ok,启动成功。
在这里插入图片描述
在这里插入图片描述

2)bootm [addr [initrd[:size]] [fdt]]:用于启动uImage镜像文件。类似bootz。
3)boot:读取环境变量bootcmd后启动linux系统。bootcmd其实是引导命令的合集,比如把刚才的命令打到一个bootcmd环境变量里,然后输入boot就直接从EMMC启动了linux。其实uboot倒计时结束之后就是在执行boot命令。
在这里插入图片描述
在这里插入图片描述
  到这里为止,启动linux都会卡在下面这里,原因是没有设置uboot的bootargs环境变量,暂时不用在意。
在这里插入图片描述
⑨其它常用命令
1)reset:复位重启uboot。
2)go addr [arg…]:用于跳到指定的地址处执行应用。addr是DRAM中的首地址,可以将裸机例程的bin文件拷贝到nfs文件夹下,用nfs命令下载到DRAM的0x87800000(因为裸机例程的链接首地址是0x87800000),然后使用go命令启动bin这个应用即可。
在这里插入图片描述
3)run命令:前面bootcmd只定义了一种启动方式,使用run bootcmdxxx可以指定启动方式,也就是说run命令可以运行指定环境变量。比如我创建了bootemmc和bootnet分别使用emmc和nfs启动linux。
在这里插入图片描述
  run一下,ok。
在这里插入图片描述
4)mtest [start [end [pattern [iterations]]]]:内存读写测试命令,可以用来测试开发板上的DDR。start是要测试的DRAM开始地址,end是结束地址。如下图,测试了1429次正常读写,按"ctrl + C"终止。
在这里插入图片描述

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值