Xilinx FPGA 嵌入式系统程序引导和启动的流程分析设计

来源:互联网 发布:nginx配置文件详解 编辑:程序博客网 时间:2024/05/02 19:54

Xilinx FPGA 嵌入式系统程序引导和启动的流程

北京华环电子        任晓亮

                            2016年1月15日

参考材料:http://www.360doc.com/content/13/1113/20/8744436_328989607.shtml

http://www.wiki.xilinx.com/Build+Device+Tree+Blob

在参考文献1中,有这样一句话,SystemACE解决方案是通过JTAG将程序下载到debug(对于MicroBlaze也就是,MicroBlaze debug module)。看到这句话,一时没反应过来。要知道SystemACE解决方案是将用于配置FPGA的bitsteams文件和程序可执行二进制文件融 合生成一个*.ace。在看了genace.tcl这个用于生成ace文件的脚本后,终于明白了,刚才提到的那句话。

首先说明一下SystemACE文件是如何生成的?

1. 通过iMPACT工具将bitstream文件转为SVF文件

该SVF文件包含了配置FPGA的JTAG指令序列

2.通过XMD将elf可执行文件转为SVF文件

该SVF文件包含了通过XMD将ELF文件下载带内存或许片上BRAM的JTAG指令序列

3.通过XMD将数据/二进制代码转为SVF文件

4.连结第一步和第二步中生成的SVF文件

5.通过iMPACT工具利用结合的SVF文件生成systemACE文件

整个生成过程一目了然了,SystemACE解决替代了这样一个在线调试的流程:通过iMPACT将含有bootloop的程序的bitstream文件通过JTAG下载到FPGA中,这个时候FPGA在空转,等待运行程序的加载。接下来通过XMD先跟debug和CPU通信,然后将程序下载到指定的内存或者BRAM中,然后运行CPU。

总结,SystemACE配置方案,需要硬件的支持,即SystemACE控制器和CF卡,当然在嵌入式系统中还需要添加Debug模块。优点显而易见,不用编写bootload类似的引导程序,也不用关心程序镜像的大小,因为CF卡的容量很大,满足了绝大多数的嵌入式应用的要求。

还有一种情况就是通过PROM/FLASH存储程序镜像和bitstream文件配置FPGA,并引导程序启动。具体的流程如下:


图2 Spartan6的配置和启动的过程

这里不关心如何去配置FPGA,而关心的是系统是如何引导的。以在FPGA运行Linux为例作说明。如图3所示,具体步骤如下:

第一步,CPU从0x0地址(BRAM)执行Loader1 (注意,Loader1放在BRAM中,在配置FPGA过程中就加在进去)

第二步,Loader1读取SPI Flash中Loader2程序,然后复制到内存中。

第三步,Loader1程序跳至在内存中执行Loader2

第四步,Loader2读取SPI Flash中压缩的内核镜像

第五步,Loader2程序解压缩内核到另一块内存空间

第六步,Loader2程序跳至解压缩的内核镜像

第七步,Linux内核启动


图3 Linux引导流程

由上面的流程可知,通过PROM或者Flash进行配置的话,需要Bootload作支持,即需要完成将程序镜像从Flash或者PROM中读取至内存上。当然嵌入式系统中需要添加PROM或者Flash控制器。

 

 

 

这节介绍以下如何生成基于zynq芯片的linux内核,使用Digilent公司的linux内核编译工具。

首先需要做一下准备工作:

1. 在Linux环境中建立交叉编译环境ARMGNU,具体方法在《基于zynq的交叉编译平台》有说明;

2. 下载Digilent Linuxkernel环境,笔者在ubuntu11.04使用git下载,输入以下脚本:

git clonehttps://github.com/Digilent/linux-digilent.git

Linux内核编译

准备工作完成之后,开始内核编译

1. 进入linux-digilent目录,进行目标板(ZedBoard)配置:

cd linux-digilent

make ARCH=arm digilent_zed_defconfig

2. 内核配置:

make ARCH=arm menuconfig

 

制作uramdisk.gz

Modifying the root filesystem

Initrd

To modify an initialramdisk:
1. Extract the initrd image from the gziparchive.

gunzip ramdisk.image.gz

2. Mount the initrdimage.

chmod u+rwx ramdisk.image

mkdir tmp_mnt/

sudo mount -o loopramdisk.image tmp_mnt/

cd tmp_mnt/

3. Make changes in themounted filesystem.
4. Unmount the initrd image and compress theimage.

sudo umount tmp_mnt/

gzip ramdisk.image
To create an initrd from scratch, tools such asBuildroot or Yocto may be used to populate the filesystem (with BusyBox, tools,etc.).
Alternatively, an empty initrd may be createdand then populated with the desired filesystem contents as specified above. Tocreate an empty (8MB) initrd:

dd if=/dev/zeroof=ramdisk.image bs=1024 count=8192

mke2fs -F ramdisk.image -L"ramdisk" -b 1024 -m 0

tune2fs ramdisk.image -i 0

chmod a+rwx ramdisk.image

Initramfs

To modify an initramfs:
1. Extract the contents of the cpio.gz archive.

mkdir tmp_mnt/

gunzip -cinitramfs.cpio.gz | sudo sh -c 'cd tmp_mnt/ && cpio -i'

cd tmp_mnt/

2. Make changes to thefilesystem.
3. Repack the filesystem into a cpio.gz archive.

sh -c 'cd tmp_mnt/ &&sudo find . | sudo cpio -H newc -o' | gzip -9 > new_initramfs.cpio.gz


To create an initramfs from scratch, tools suchas Buildroot or Yocto may be used to populate the filesystem (with BusyBox,tools, etc.).
Alternatively, initramfs image may be created bypopulating a directory with the desired filesystem contents and packing thesecontents into a cpio.gz archive as mentioned above.

Wrapping the image with a U-Boot header

For Zynq AP SoC only, theramdisk.image.gz needs to be wrapped with a U-Boot header in order for U-Bootto boot with it:

mkimage -A arm -T ramdisk -Cgzip -d ramdisk.image.gz uramdisk.image.gz

 
mkimage -A microblaze -O linux -T ramdisk -C gzip -d ramdisk.image.gz uramdisk.image.gz

 

 

git clonegit://github.com/Xilinx/u-boot-xlnx.git

git clone git://github.com/Xilinx/linux-xlnx.git
git clone https://github.com/Xilinx/linux-xlnx.git

 

sudo apt-get install uuid-dev

sudo apt-get install openssl
sudo apt-get install libssl-dev
sudo apt-get install libssl0.9.8
sudo apt-get install libgtk2.0-dev

apt-get install device-tree-compiler

 

搭建好的交叉编译环境编译嵌入式Linux所需的文件,包括u-bootuImage(内核)、uramdisk.image.gz(文件系统)和devicetree.dtb(设备树)。

原料:

  • u-boot-xlnx.git 
  • linux-xlnx.git
  • device-tree-xlnx-xilinx-v2014.4.zip
  • arm_ramdisk.image.gz 
    https://github.com/Xilinx下载前三者,注意下载xil2014.4版本的。 
    后者从http://www.wiki.xilinx.com/Build+and+Modify+a+Rootfs下载。

编译

1. U-Boot

~$ mkdir ZYNQ 
~$ cd ZYNQ/ 

~/ZYNQ$ mkdir buildxil2014.4 
~/ZYNQ$ cd buildxil2014.4/ 
~/ZYNQ/buildxil2014.4$ git clonehttps://github.com/Xilinx/u-boot-xlnx.git //或者先下载好,直接copy、解压 
cd u-boot-xlnx
 
在编译之前,先进行配置,配置文件在u-boot-xlnx/include/configs下,打开zynq_common.h可查看信息。包括所需要的几个文件的名称等 
make zynq_zed_config 
make 

cp u-boot u-boot.elf 
如果需要安装python  
sudo apt-get --reinstallinstall python-minimal 
u-boot-xlnx/include/configs下,查看zynq_common.hzynq_zed.h(优先),决定了内核等文件的名称。 
本例使用zynq_zed_config 
“ethaddr=00:0a:35:00:01:22\0”   \ 

“kernel_image=uImage\0”\ 
“kernel_load_address=0x2080000\0” \ 
“ramdisk_image=uramdisk.image.gz\0”\ 
“ramdisk_load_address=0x4000000\0”  \ 
“devicetree_image=devicetree.dtb\0”\ 
“devicetree_load_address=0x2000000\0”   \ 
“bitstream_image=system.bit.bin\0”  \ 
“boot_image=BOOT.bin\0” \

2. uImage

使用配置文件:xilinx_zynq_defconfig(arch/arm/configs)

cd ~/ZYNQ/buildxil2014.4 
git clone https://github.com/Xilinx/linux-xlnx.git    //
或直接copy下载好的linux-xlnx-xilinx-v2014.4.tar.gz 
cd~/ZYNQ/buildxil2014.4/u-boot-xlnx-xilinx-v2014.4/       //
需要先安装u-boot-tools 
sudo apt-get install u-boot-tools 

cd ~/ZYNQ/buildxil2014.4/linux-xlnx-xilinx-v2014.4 
make ARCH=arm xilinx_zynq_defconfig 
make ARCH=arm UIMAGE_LOADADDR=0x8000 uImage 
cp arch/arm/boot/uImage

3. uramdisk.image.gz文件系统

这里不进行编译了,直接使用官网的:http://www.wiki.xilinx.com/Build+and+Modify+a+Rootfs 
或: 
wgethttp://www.wiki.xilinx.com/file/view/arm_ramdisk.image.gz/41943558/arm_ramdisk.image.gz 
修改根文件系统 
cp arm_ramdisk.image.gzramdisk.image.gz 
gunzip ramdisk.image.gz 

mkdir file_tmp 
sudo mount ramdisk.image -o loop ./file_tmp/ 
这样可以在file_tmp目录中对文件系统进行修改,修改完成之后umount并重新压缩即可 
sudo umount file_tmp/ 
gzip ramdisk.image 

//添加u-boot头部 
sudo apt-get install u-boot-tools 

mkimage -A arm -T ramdisk -C gzip -d ramdisk.image.gz uramdisk.image.gz 
如果需要进行修改,可以先将uramdisk.image.gz解压为uramdisk.image,再挂载到指定目录

4. devicetree.dtb

建议: 
 
建立一个devicetree目录,将/scripts/dtc/dtc工具copy过来,每次使用时在其下建立工程目录; 
 
将所需要的dts,dtsi文件copy到其下的工程目录下; 
 
然后对工程目录打开终端:../dtc-I dts -O dtb -o devicetree.dtb system.dts即可;

如果只有ARM,没有使用PL部分: 
linux-xlnx/arch/arm/boot/dts/下,找到zynq-zed.dts及相关dtsi文件,copy到上述devicetree/xil2014.4/下: 
../dtc -I dts -O dtb -odevicetree.dtb zynq-zed.dts

PL配置devicetree 
自己写的PL程序对于ARM来说相当于是新的外设,在xil提供的Linux内核中的dts是没有的,需要自己制作匹配的dts文件。SDK提供了根据在vivado中的硬件设计文件来生成设备树的工具。也可以自己手工编写或作出调整。 
使用SDK制作和PL相匹配的devicetree 
SDK
设置 
下载device-tree-xlnx-xilinx-v2014.4.tar.gz,解压将device-tree-xlnx-xilinx-v2014.4文件夹。 
添加至:bsprepo=D:\Xilinx\SDK\2014.1\data\embeddedsw\lib\bsp下, 
使用SDK添加下载好的目录:SDKMenu: Xilinx Tools > Repositories > New… (bsp repo) > OK

注:由于device-tree-xlnx-xilinx-v2014.4.tar.gz,但是有win下路径\的问题;重新在https://github.com/Xilinx/device-tree-xlnx下载,device-tree-xlnx-xilinx-v2014.4.zipclonein desktop),解决

SDK使用 
新建
SDKMenu: File > New > Board Support Package > Board Support Package OS:device-tree > Finish 
在弹出的的对话框中修改参数;比如bootargs内核的命令行参数,内核启动时传给内核,可设置为:console=ttyPS0,115200root=/dev/ram rw earlyprintk 
编译完成后在工程的\HW\Lab2-LedIP\Lab2-LedIP.sdk\device_tree_bsp_0下可以找到system.dts文件 
将所有的dts,dtsi文件copy到虚拟机下的buildxil2014.4/linux-xlnx-xilinx-v2014.4下,使用dtc工具生成devicetree.dtb 
../dtc -I dts -O dtb -odevicetree.dtb system.dts

http://xilinx.eetrend.com/blog/7825

 

 

U-boot,设置uboot默认参数文件

1.      在u-boot的include/configs/zynq_common.h文件中决定了内核、文件系统和设备树编译后的文件名。如Kernel_image决定了u-boot引导zImage还是uImage。

2.      制作boot-image 顺序

(1).fsbl.elf + system.bitstream.bit + uboot.elf启动加载fpga

(2). fsbl.elf + uboot.elf 启动不加载fpga

(3).vivado综合的时候,生产bitstream时必须选择bin格式的,uboot加载fpga有两种格式:

一是:system.bit用fpga loadb 0 $ramaddr $size

二是:system.bin用 fpga load 0 $ramaddr $size

3.修改ramdisk

对于zImage用的ramdisk不需要添加uboot头,即mkimage 操作如下:

renxl@icserver:~/work/nios-kernel/arm_linux/xilinx/roofs$gunzip ramdisk8M.image.gz

root@icserver: ~/xilinx/roofs# mount -o loopramdisk8M.image uramdisk/ (root权限

修改完成:

root@icserver:/home/renxl/work/nios-kernel/arm_linux/xilinx/roofs#umount uramdisk

root@icserver:/home/renxl/work/nios-kernel/arm_linux/xilinx/roofs#gzip ramdisk8M.image

对于uImage用的uramdisk ,需要前进uboot头,操作如下:

         cparm_ramdisk.image.gz ramdisk.image.gz

gunzip ramdisk.image.gz

mkdir file_tmp

sudo mount ramdisk.image -o loop ./file_tmp/

这样可以在file_tmp目录中对文件系统进行修改,修改完成之后umount并重新压缩即可

sudo umount file_tmp/

gzip ramdisk.image

//添加u-boot头部

sudo apt-get install u-boot-tools

mkimage -A arm -T ramdisk -C gzip -d ramdisk.image.gzuramdisk.image.gz

 

修改machine ID:

uboot机器码路径:arch/arm/include/asm/mach-types.h

kernel机器码路径:arch/arm /tools/mach-types

0 0