S04_CH01_搭建工程移植LINUX/测试EMMC/VGA
S04_CH01_搭建工程移植LINUX/测试EMMC/VGA
1.1概述:
本章内容是在已经提供安装了VIVADO2015.4 的ubuntu系统下,进行。大家可以下周我们已经提供的虚拟机镜像,我们提供的虚拟机镜像是安装了VIVADO的ubuntu系统,系统版本是ubuntu14.04。
主要完成的内容如下:
1)、利用VIVADO搭建VDMA Frambuffer 工程 修改VTG IP模块 支持1024X600分辨率(主要考虑支持7寸HDMI液晶显示器)
2)、产生FSBL文件
3)、环境变量的批量设置
4)、基于linux kernel部分zynq_zed.dts(miz702n需要使用到)/zynq_zybo(miz701n需要使用到) 修改设备树
5)、修改kernel其他文件
6)、通过menuconfig 向导配置 frambuffer驱动
7)、编译kernel、编译uboot
8)、测试显示器输出和串口打印信息
9)、测试读EMMC内存、写EMMC内存、读写EMMC内存
10)、测试frambuffer应用程序
1.2 LINUX开发环境搭建
1.2.1虚拟机环境配置(提供下载虚拟机已经完成)
Step1:
本例程的工作环境(包括 FPGA及嵌入式 Linux的开发)是在 ubuntu14.04 操作系统下完成,对于 其它 Linux操作系统可能需要解决相关包的依赖问题。
Step2:
例子放在/mnt/workspace/linux目录下,读者可以在该目录下正确编译、运行。而 /mnt/workspace/linux目录是为读者实验准备的。
Step3:
单击桌面上的控制台或者(ctrl+alt+T)即可打开命令行,然后输入 su,根据提示输入root密码即可切换到 root用 户。
Step4:
对于新安装的ubuntu操作系统需要命令行下运行一下scripts目录下的 fix_xilinx_deps.sh脚本, 该脚本主要是解决编译 u-boot、kernel源码等所需要的包依赖。而提供的虚拟机已经解决了这些问题。 # /mnt/workspace/linux/scripts/fix_xilinx_deps.sh
注意:开机的时候可能系统会提示正在检查更新(如 ),此时可以打开图 示的有个勾的那个图标,然后点击 Install Updates,待其完成更新后再运行该脚本(如下图所示)。当 然,在平时的开发过程中,可以在打开虚拟机之前,禁止网络功能,提供的虚拟机已经禁止了。
Step5:
对于 Vivado开发工具的安装,将下载的压缩包解压后,从命令行进入该目录,执行 xsetup即可像在 Windows一样安装。注意:为减少虚拟机所占用硬盘空间,虚拟机里提供的开发套件是直接将本人PC中安装好的 Vivado和 SDK等复制到/mnt/workspace/toolchains目录中的,这里不提供全新安装 Vivado的步骤,若需要帮助的话,可以通过邮件联系我。
Step6:
本开发使用的是 Vivado开发套件里提供的交叉编译器,无须再安装其它交叉编译器。 Step7:
整个开发过程主要使用脚本进行操作,故在每次开发前,需要执行如下图所示操作来设置好环境变量。如果需要支持新的开发板时,只需要建立新的目录(如 miz702等),然后把 scripts复制到新的目 录中,修改相关设置(如 uboot版本等),十分方便。
1.2.2下载资源
使用 get_xilinx_sources.sh脚本下载 uboot、kernel、device tree等源码及 ramdisk到 packages目录中,并 解压 uboot和 kernel等源码。若需要更改源码的版本,则打开 get_xilinx_sources.sh文件后,修改相应的 设置即可。当网络不是很好时,可以直接压缩包目录中的包复制到 packages目录下即可。
1.3 VIVADO 工程的搭建
计 FPGA 这部分相信读者已经相当熟悉了,这里只是对工程里的一些关键地方进行说明。在命令行下切换到/mnt/workspace/MIZ702N(工程目录读者可以自己指定)目录下,通过输入 vivado即可打开 vivado工具。
此工程可以在WINDOWS或者LINUX下使用。建议初学者WINDOWS下使用。
1.3.1 VIVADO 硬件工程构架
MIZ701N
MIZ702/MIZ702N
1.3.2 时钟设置
Step1: 双击ZYNQ CPU IP 进行如下步骤设置:MIZ702和MIZ702N的输入时钟是333.333333MHZ
Step2:MIZ701N PS的输入时钟是50MHZ
Step3:PS的PLL提供本系统的时钟100MHZ
Step4:MIZ702的开发板采用的是单片256MB的MT41K128M16JI-125
Step5:MIZ701N和MIZ702N的内存型号一样,都是单片512MB的MT41K256M16RE-125
Step6:启动1路HP接口,HP接口是ZYNQ个高速数据接口
Step7:勾选PL到PS的中断资源(关于中断,在第二季的课程中有详细讲解,不熟悉的读者可以到第二季课程中温习一下)
Step8:增加必要的外设,包括ENET0以太网接口、USB_0 USB接口、SD0 TF卡接口、SD1 EMMC接口、UART1串口。
Step9:设置完成后单击OK
Step10:双击VDMA IP 由于只使用了VDMA读通道设置如下:
Step11:双击PLL时钟IP
MIZ701N PLL时钟设置
MIZ702/MIZ702N PLL时钟设置
Step13:修改VTC 显示时序发生IP参数符合1024X600分辨率
1.4 PS设置
1.4.1 PS SDK测试显示器输出
新建Display_VMDA_Test空的工程,为了测试在裸机下图形系统显示正确,编写SDK测试代码main.c函数以及其他必要函数。
/* *南京米联电子科技有限公司 *www.milinker.com *www.osrc.cn *test display Copyright (c) 2009-2012 Xilinx, Inc. All rights reserved. */ #include "xaxivdma.h" #include "xaxivdma_i.h" #include "sleep.h" #define DDR_BASEADDR 0x00000000 #define VDMA_BASEADDR XPAR_AXI_VDMA_0_BASEADDR #define H_STRIDE 1024 #define H_ACTIVE 1024 #define V_ACTIVE 600 #define pi 3.14159265358 #define COUNTS_PER_SECOND (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ)/64 #define VIDEO_LENGTH (H_STRIDE*V_ACTIVE) #define VIDEO_BASEADDR0 DDR_BASEADDR + 0x2000000 #define VIDEO_BASEADDR1 DDR_BASEADDR + 0x3000000 #define VIDEO_BASEADDR2 DDR_BASEADDR + 0x4000000 u32 *BufferPtr[3]; unsigned int srcBuffer = (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x1000000); int run_triple_frame_buffer(XAxiVdma* InstancePtr, int DeviceId, int hsize, int vsize, int buf_base_addr, int number_frame_count, int enable_frm_cnt_intr); //函数声明 void Xil_DCacheFlush(void); // 所有数据格式 为 RGBA,低位的透明度暂不起作用 extern const unsigned char gImage_beauty[1729536]; extern const unsigned char gImage_mm[1228800]; extern const unsigned char gImage_miz702[600000]; extern const unsigned char gImage_miz702_rgba[600000]; void show_img(u32 x, u32 y, u32 disp_base_addr, const unsigned char * addr, u32 size_x, u32 size_y) { //计算图片 左上角坐标 u32 i=0; u32 j=0; u32 r,g,b; u32 start_addr=disp_base_addr; start_addr = disp_base_addr + 4*x + y*4*H_STRIDE; for(j=0;j<size_y;j++) { for(i=0;i<size_x;i++) { b = *(addr+(i+j*size_x)*4+1); g = *(addr+(i+j*size_x)*4+2); r = *(addr+(i+j*size_x)*4+3); Xil_Out32((start_addr+(i+j*H_STRIDE)*4),((r<<16)|(g<<8)|(b<<0)|0x0)); } } Xil_DCacheFlush(); } int main(void) { u32 i; //Xil_DCacheFlush(); xil_printf("Starting the first VDMA \n\r"); //VDMA configurateAXI VDMA0 /*****************往DDR写数据设置**********************/ //Xil_Out32((VDMA_BASEADDR + 0x030), 0x00000003);// enable circular mode //Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0); // start address //Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1); // start address //Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2); // start address //Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*4)); // h offset (640 * 4) bytes //Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*4)); // h size (640 * 4) bytes //Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE); // v size (480) /*****************从DDR读数据设置**********************/ Xil_Out32((VDMA_BASEADDR + 0x000), 0x00000003); // enable circular mode Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); // start address Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR0); // start address Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR0); // start address Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*4)); // h offset (640 * 4) bytes Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*4)); // h size (640 * 4) bytes Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE); // v size (480) for(i=0;i<614400;i++) { Xil_Out32(VIDEO_BASEADDR0+i,0); } while(1) { show_img(0,0,VIDEO_BASEADDR0,&gImage_beauty[0],563,600); sleep(5); show_img(0,0,VIDEO_BASEADDR0,&gImage_miz702_rgba[0],375,400); sleep(5); } return 0; } |
1.4.2测试效果 缺图
1.4.3 新建FSBL工程
产生的fsbl.elf 后面将用于参数BOOT.BIN文件
1.4.4产生设备树
Step1:首先解压 device-tree-xlnx-xilinx-v2015.4.tar.gz,然后打开 Xilinx Tools→Repositories将刚 才解压的目录包含进来。
Step2:打开 File→New→Board Support Package创建,其它弹出窗口按默认设置即可
Step3:在该工程中,zynq-7000.dtsi文件是 Xilinx提供给所有 zynq-7000开发板使用的,只所有的 status都 设置为”disabled”,而 system.dts里根据板子上的具体实现,修改设备树使其可以正常工作。pl.dtsi文件 是 FPGA里使用的 IP对应的设备树。
1.5编译 u-boot、kernel、设备树和文件系统
1.5.1批处理文件
这里使用 xilinx在 github上提供的 u-boot和 kernel源码,在 Wiki上提供的文件系统(当然,也可以直 接使用 buildroot自己匹配根文件系统,该方法简单快捷,不用再去解决什么依赖问题,但好像国内很 少有人这么干,他们都把 busybox等模块一个个搭建起来)。 1、配置 uboot和编译 uboot自带的工具,为编译 kernel提供 mkimage工具的支持。注意,由于编译新 版本的 uboot需要 openssl和 dtc的支持,这里呢,在系统里已经安装好了 openssl,而 dtc则利用 kernel 里自带的,所以这一步做完,我们将直接编译内核,等编译完内核后再来编译 uboot。注意: cfg_bootloader.sh可以在任意目录下使用,而 make tools只能在 bootloader目录下使用,bootloader就是 我们存放 uboot源码的地方。(注意:这部分仅在恢复配置文件至 Xilinx提供的配置时用,在自己修改完配置之后,除了需要恢复配置文件外,请谨慎使用这两条命令) 。
Step1:运行setup_env.sh批处理文件(管理员模式下的密码为root)
Step2:运行cfg_bootloader.sh批处理文件
Step2:运行make tools处理命令(执行的是清理工作,重置配置时候使用)
Step3:配置内核(注意:这部分仅在恢复配置文件至 Xilinx提供的配置时用,在自己修改完配置之后,除了需要恢复配 置文件外,请谨慎使用这条命令)
1.5.2 修改设备树
Step1:由于各种开发板可以参考zedboard的配置设备参数,因此我们可以修改已经存在的相关文件,来满足我们的自定义需求打开/mnt/workspace/linux/kernel/arch/arm/boot/dts/zynq-zed.dts
Step2:修改 bootargs信息 启动参数 bootargs是传递给 kernel的参数。Console是一个输出系统管理信息的文本输出设备,这些信 息来自于内核,系统启动和系统用户,其中 console=ttyPS0,115200用来设置串口作为输出终端设备,是 这些信息可以通过串口在远程的终端上显示。而 console=tty0则是设置显示器作为输出终端。
如果想屏幕永不休眠,则在启动参数 bootargs中增加 consoleblank=0,网络上大部分是讲修改内核源码, 但我觉得这种方法才是最方便,且符合一个内核适合多种产品的思想。 其它参数读者应该也知道是什么意思,这里也就不多讲了。
Step3:添加 vdma和 framebuffer设备树节点,注意:这里是添加到根节点。笔者觉得,arm linux引进设备树,比以前版本的做法好很多,只是驱动里需要设备树提供哪些参数, 在 Linux文档里没有很好的说明,或者是驱动里所需要的参数改变了,而文档又没有及时更新,这部分 是 linux的不足之处。所以,开发 Linux过程中,最好还是以源码为中心。设备树这部分是参考之前在 SDK里产生的设备树和内核里相关文档,在阅读 vdma等驱动源码后,修改而来的,并不是说 SDK里 产生的设备树直接搬来就可以正常使用。
Step4:修改 SD卡和 emmc设备树节点
这部分直接将之前在 SDK里产生的设备树复制过来就可以正常使用。总的来说,对于 PS的外设,其 硬件是固定的,驱动也基本不会有太大的变化,故基本上是可以直接搬来就可以用,但也有例外,如果 USB,SDK里并不知道你要当 host或者 otg来使用,所以需要做些小修改。而对于 PL中使用的 IP,其 硬件和驱动经常有变化,SDK里产生的设备树不能直接拿来使用。
1.5.3 添加 framebuffer驱动
Step1:把vdmafb.c文件复制到 /mnt/workspace/linux/kernel/drivers/video/fbdev 目录下,对于驱动这部分,主要还是要看源码,注意, 该驱动仅支持 640x480分辨率,若需要支持其它分辨率,需要修改和调试相关源码。
Step2:打开/mnt/workspace/linux/kernel/drivers/video/fbdev目录下的 Makefile文件,当然也可以用其它 文本编辑器。
找到 CONFIG_FB_XILINX,在其下方添加 obj-$(CONFIG_FB_VDMA)+= vdmafb.o。读者可以直接复制笔者提供的开发包中的修改好的文件。
Step3:打开/mnt/workspace/linux/kernel/drivers/video/fbdev目录下的 Kconfig文件:
找到 FB_XILINX,在其下方添加以下信息。读者可以直接复制笔者提供的开发包中的修改好的文件。
Step4:打开/mnt/workspace/linux/kernel/drivers目录下的 Makefile文件,找到 obj-y += video/ 读者可以直接复制笔者提供的开发包中的修改好的文件。
把它剪切并粘贴到
Step5:回到 kernel目录下,执行 make menuconfig,配置 kernel。
按向下方向键找到 Device Drivers,按回车键进入
按向下方向键找到 Graphics support,按回车键进入
按向下方向键找到 Bootup logo,按空格键选择
按向上方向键找到 Frame buffer Devices,按回车键选择
至此已经完成 linux kernel的配置,按向左方向键至<Exit>,再按回车键返回上一级菜单
直到看到以下窗口,按<Yes>保存。
1.5.4执行mk_kernel.sh编译内核
1.5.5执行mk_bootloader.sh编译uboot
1.5.6制作UBOOT.BIN
Step1:把system_wrapper.bit 和 fsbl.elf复制到 output/target/目录下。
Step2:执行mk_sd_image.sh打包从 SD启动所需要的文件
Step3:至此系统部分已经完成,复制linux/image/sd_images文件下文件到TF卡测试移植好的LINUX系统。
1.6 EMMC 8GB内存测试(MIZ702不支持)
Step1:从系统的启动信息可以看到,系统已经发现 mmc0(即 SD卡)和 mmc1(即 emmc),而且列出了 SD 卡为 7.41GB,而 emmc为 7.20GB
Step2:给 eMMC分区 当然,如果只分为一个分区的话,其它也可以不分区。在命令行下运行 fdisk /dev/mmcblk1来对 emmc 进行分区。这里需要注意,确认有没有 SD卡插入,也就是说确认当前 eMMC是/dev/mmcblk1还是 /dev/mmcblk0,还有对于有多个分区的,可能存在/dev/mmcblk0p1、/dev/mmcblk0p2等等。
Step3:将分区格式化为 ext2格式 能格式化为什么格式,如 ext2、ext3、nfts、fat32,这些都跟系统的定制有关
Step4:测试 emmc的性能
在 Linux下,既可以使用 dd命令来低格 U盘等,也可以用来复制文件(类似于 windows下的 ghost功 能),当然也可以用来测试硬盘等的性能,虽然没有专业软件的测试得准确,但用来对比性能已经足够 了。对于/dev/zero和/dev/null两个设备的说明,可以百度一下
Step4.1写性能
下面使用 dd命令将从/dev/zero设备中产生一个 1GB的文件写入到 emmc:
Step4.2读性能
下面使用 dd命令将 1GB的文件写入到/dev/null设备中:
Step4.3读写性能
下面使用 dd命令将 emmc中的一个 1GB的文件写入到 emmc的另外一个文件
1.7 测试 framebuffer
Step1:将虚拟机/mnt/workspace/linux/framebuffer目录下的测试程序(源代码也在该目录里)复制到 SD 卡上,然后给开发板上电。在 Windows下打开串口终端putty
软件。
Step2:切换到 sd卡目录下(比如 mount /dev/mmcblk0p1 /mnt, cd /mnt),然后运行./framebuffer,在串口终端 会显示 以下信息。
Step3:在屏幕上会显示以下信息