ZYNQ7000 #5 - 从vivado工程开始,从emmc启动Linux

 

本文从最简单的petalinux需求的vivado工程开始,建立一个能跑起来linux的vivado工程。同时将linux kernel、根文件系统部署在接到SD1接口上的emmc中,qspi-flash中放置BOOT.BIN,uboot唤起emmc中的image.ub。并填坑关于petalinux在SD0为空时,配置从SD1启动的bug

目录

1 - VIVADO工程建立

1.1 - PS配置

1.2 - 加个AXI-GPIO

1.3 - 引脚约束,bitstream生成与压缩

1.4 - 生成bitstream,导出hdf

2 - Petalinux工程

2.1 - 配置BOOT.BIN从QSPI FLASH唤起emmc中的image.ub

2.2 - petalinux从跳过空SD0从SD1启动的bug修复

2.3 - 编译,打包

3 - 启动


1 - VIVADO工程建立

这里我们从建立一个petalinux所要求的最小linux系统开始,从这个工程搭建我们后面所需的PL框架。

依照UG1144中介绍,在zynq-7000系列上启动linux所需要的必备器件有以下三个:

  • 三态时钟
  • 外部32MB以上的内存
  • UART串口(用作基本串口登录linux使用)

1.1 - PS配置

新建一个vivado工程,创建框图设计(Block Design),添加ZYNQ7 Processing System

MIO配置,添加QSPI Flash,根据你的板子来设置引脚,注意Bank0和Bank1的电平设置

MIO配置,添加外设,这里添加了一个以太网ENET0,一个USB0,SD0 和SD1分别是连接到SD卡和eMMC,UART1被选中,它将被作为linux系统基本串口登录

Clock配置,修改IO上的外设时钟

DDR配置,修改为PS上接入的内存

1.2 - 加个AXI-GPIO

添加一个AXI GPIO IP核,用来控制板上的4个LED。将其GPIO设置为4bit地址宽度,设置GPIO为外部引脚

点击“Run Connection Automation”和“Run Block Automation”,自动连接部分信号线和自动添加缺少的ip

完成后我们可以点击Diagram框内的Optimiz Routing,优化一下布局

可以看到,整个框图比较简单,PS核DDR和部分FIXED_IO引出,AXI GPIO通过一个AXI桥连入到PS核上的AXI_GP通用总线上

1.3 - 引脚约束,bitstream生成与压缩

创建HDL wrapper

在生成的 design_1_wrapper.v 文件中,我们可以看到我们外连的led引脚(名称会因为你外连后是否修改名称而定)

添加一个xdc约束文件

这里名称我们取“myLinuxBase”,添加完毕后在其内加入下述代码:

set_property PACKAGE_PIN F13 [get_ports led_0_tri_o[0]]
set_property PACKAGE_PIN E13 [get_ports led_0_tri_o[1]]
set_property PACKAGE_PIN G12 [get_ports led_0_tri_o[2]]
set_property PACKAGE_PIN G11 [get_ports led_0_tri_o[3]]

set_property IOSTANDARD LVCMOS18 [get_ports led_0_tri_o[*]]


#bit compress 
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]

可以看到,前4行代码都是led引脚管脚约束,第6行是约束这4个管脚的电平

后面3行则是对生成的bitstream进行压缩,否则bitstream生成后会有13MB之大。

1.4 - 生成bitstream,导出hdf

生成bitstream,因为之前没有进行综合,这里会提示进行综合,无错误后会成功生成bitstream文件

生成bitstream后,我们导出hdf硬件描述文件 File -> Export -> Export Hardware,一定勾选包括bitstream!!

bitstream是vivado中生成的,导出为hdf文件时需要include bitstream。

hdf实际只是个压缩文件,其中包括硬件信息、bitstream等等,petalinux需要解包hdf然后将其中的bitstream用于后面进行petalinux-package

这样,我们就得到petalinux所需的包含bitstream的hdf文件了,接下来开始petalinux生成

2 - Petalinux工程

petalinux工程的建立、导入hdf就不赘述了。

我们板上现在的情况是,SD0和SD1口都被使用,其中SD0口是SD卡使用,SD1口是接到了板上的eMMC。

eMMC被分区为两个部分,mmcblock1p1是FAT分区,里面存放image.ub,mmcblock1p2是EXT4分区,里面是根文件系统。

eMMC的分区和根文件系统的部署可以用以下的方法:

先使用一个从SD启动的linux,在板上启动SD-Linux后,使用fdisk对emmc进行分区,使用mount进行挂载,挂载EXT4分区后将已经制作好的根文件系统放入eMMC上的EXT4分区

也可以使用uboot对eMMC进行读写,我这里只是取巧而已

我们期望的是板子上电后,从QSPI-FLASH读取BOOT.BIN,执行到uboot后,uboot从eMMC的FAT分区读取image.ub,并将内核释放到内存中运行。

ZYNQ-7000系列只支持SD启动和QSPI启动,不支持直接的从eMMC启动BOOT.BIN,但是UltraScale的支持

参考:

2.1 - 配置BOOT.BIN从QSPI FLASH唤起emmc中的image.ub

主要有以下几点需要配置

  • 配置boot image从primary flash启动
  • 配置kernel镜像从primary sd启动
  • 配置SD/SDIO中,主SD为SD1
  • 配置根文件系统从mmcblk1p2读取(这里我们已经将根文件系统放到了eMMC的p2分区)

这里暂时不做别的配置了,保存退出

2.2 - petalinux从跳过空SD0从SD1启动的bug修复

petalinux2018.3中会有一个这样的bug(实际上之前也存在,官方修复还是有漏洞),当像我们这样SD0接入SD卡,SD1接入eMMC时,当SD卡没有插入时启动,尽管配置petalinux的主sd为ps7_sd_1,但是其uboot启动时会报错找不到mmc 0 

“no mmc device at slot 0”

"card did not respond to voltage select"

这个问题实际上官方之前已经发现,并且在petalinux2017.4之后的版本进行了修复(AR#69780),但是修复并没有完全解决问题。在版本修复之前,问题的来源是在petalinux-config设置主SD为1后,并没有能够成功修改uboot的启动指令,故给出了AR69780中的解决方案,但是解决方案并不完美。

在版本修复之后,我们打开 <plnx-proj-root>/project-spec/meta-plnx-generated/recipes-bsp/u-boot/configs/platform-auto.h 文件,可以看到官方加上了一个sdbootdev变量,并让这个变量表示我们在petalinux-config中标识的主SD编号:

看到光标高亮的cp_kernel2ram变量,其在后面会被执行

"default_bootcmd=run uenvboot; run cp_kernel2ram && bootm ${netstart}\0" \ 
""

/* BOOTCOMMAND */
#define CONFIG_BOOTCOMMAND	"run default_bootcmd"

但是这里,如果当板上使用了两个SD/SDIO,但是用户将SD0作为SD卡使用,SD1作为eMMC使用,则会有一个问题。那就是虽然在petalinux中配置使用eMMC作为主启动SD(也的确修改了sdbootdev变量),但是当SD0,即SD卡槽没有插入SD卡时,uboot在执行mmcinfo时会报错提示mmc0 卡槽未检测成功,导致后面的命令全部终止。

这里介绍简单的解决方法:

在 project-spec/meta-user/recipes-bsp/u-boot/files/platform-top.h 文件的末尾加入下面的代码

/*   fix codes  */
#ifdef CONFIG_BOOTCOMMAND
#undef CONFIG_BOOTCOMMAND
#define CONFIG_BOOTCOMMAND	"mmc dev ${sdbootdev}; run default_bootcmd"
#endif

实际上是在执行默认启动环境变量前先将mmc切换到sdbootdev所表示的SD设备(可能是0,也可能是1,这取决于用户在petalinux中设置primary SD是哪一个)

也可以直接看我在xilinx论坛中关于这个问题的解答(https://forums.xilinx.com/t5/Embedded-Linux/BOOting-image-ub-from-eMMC/m-p/979363/highlight/false#M33948

2.3 - 编译,打包

$ petalinux-build
$ petalinux-package --boot --fsbl --fpga --u-boot --force

然后将BOOT.BIN烧录到QSPI-FLASH中,image.ub写入emmc的FAT分区中

还记得我们前面的SD-Linux吗,我们依旧可以用这个作为媒介进行写入

首先擦除QSPI-FLASH:flash_erashall /dev/mtd0

使用 dd 或者 flash_write 指令将 BOOT.BIN 写入flash:dd if=BOOT.BIN of=/dev/mtdblock0

使用mount挂载eMMC的FAT分区:mount /mnt/mmcFat /dev/mmcblk1p1 

直接将image.ub使用cp指令拷贝进 /mnt/mmcFat即可

3 - 启动

上电启动,拨码设置从QSPI启动,我们可以看到下面的uboot输出

U-Boot 2018.01-00083-gd8fc4b3b70 (Jun 01 2019 - 09:37:43 +0000) Xilinx Zynq ZC702

Board: Xilinx Zynq
Silicon: v3.1
DRAM:  ECC disabled 1 GiB
MMC:   Card did not respond to voltage select!
mmc_init: -95, time 24
mmc@e0100000 - probe failed: -95
sdhci_transfer_data: Error detected in status(0x208000)!
Card did not respond to voltage select!
mmc_init: -95, time 25

SF: Detected n25q256 with page size 256 Bytes, erase size 4 KiB, total 32 MiB
*** Warning - bad CRC, using default environment

In:    serial@e0001000
Out:   serial@e0001000
Err:   serial@e0001000
Board: Xilinx Zynq
Silicon: v3.1
Net:   ZYNQ GEM: e000b000, phyaddr ffffffff, interface rgmii-id
eth0: ethernet@e000b000
U-BOOT for osrc_myLinuxBase

ethernet@e000b000 Waiting for PHY auto negotiation to complete...... done
BOOTP broadcast 1
DHCP client bound to address 192.168.2.54 (8 ms)
Hit any key to stop autoboot:  0 
sdhci_transfer_data: Error detected in status(0x208000)!
switch to partitions #0, OK
mmc1(part 0) is current device
Device: mmc@e0101000

可以看到,在最开始,MMC报错还是Card did not respond to voltage select

但是在读秒过后,执行我们修改了的BOOTCOMMAND,在上面的启动代码片段的末尾我们可以看到,mmc切换到了1为主启动mmc,然后升高的从mmc中读取了image.ub,解压了linux到内存,启动了系统

发布了38 篇原创文章 · 获赞 23 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u013662665/article/details/90732312
今日推荐