基于Lemon ZYNQ的PS实验七 TF卡启动演示

ZYNQ 有多种启动方式可以选择,除了之前介绍的从QSPI FLASH 的方式来启动外,还可以让系统从TF 卡的方式来启动,本文将演示TF卡的启动过程。

  • 此章节内容适用于Lemon ZYNQ主板,如是其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

本工程和上一节工程内容高度重合,请选择性的参看。(仅在BlockDesign 设置的地方将 FLASH 相关的设置更换成SD即可, 最后将我们SDK下生成的boot.bin文件复制到FAT32格式的TF卡中即可)

一、ZYNQ启动流程介绍

1)首先了解ZYNQ的启动过程, ZYNQ的启动过程以ARM核为主,上电后 硬件先读取ARM核PS端特定引脚的电平状态以确定 系统从NAND ,QSPI ,SD Card还是 JTAG 启动系统。 启动的方式可以通过板子的拨码开关进行调整

2)ZYNQ是根据MIO5,MIO4,和MIO3三个管脚在上电时的电平状态来决定系统的启动方式的,如下图所示。

3)主板上的启动选项:我们的最小系统板只有 QSPI 和TF的硬件,所以只需要关注QUAD-SPI ,SD,JTAG 三种启动方式就好。也就是看系统上电瞬间MIO5和MIO4两个管脚的电平状态,用来区分不同的上电方式。在电路上已将MIO5和MIO4分别接到了 拨动开关上了,也就是按照拨动开关在上电瞬间的状态即可控制系统的启动方式 ,具体可参考板子上的丝印标注。

4) 要想TF卡启动,我们仅需将拨码开关调整到如图所示状态 ,此时如果TF卡上有可执行程序,断电重启后,系统将会从TF卡启动了

二、实验内容

这个实验将介绍ZYNQ的TF卡启动流程。实验中有两个LED灯,其中一个由PL逻辑控制,另一个由PS控制(EMIO方式)。这样可以使本工程适应更多应用场景。

三、工程创建

工程创建的过程可以参考试验一中的内容,这里不再详细描述了。基于Lemon ZYNQ的PS实验一 GPIO之用EMIO方式点亮LED(完整图文)(芯片型号选XC7Z020CLG400-1)

四、Block Design中的设置

1)创建一个BLOCK设计 :IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

2) 在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。

5)因为Lemon ZYNQ主板的PS时钟是50M的晶振输入的,所以这里需要把默认的PS输入时钟33.33M改成50M

6)在PS的MIO配置选项的GPIO栏里,增加一路EMIO(因为本次测试的是一个,如果需要增加按键或者其它IO 这里可以对应的调整(这里GPIO是为了点亮LED灯看效果演示用的,非固化必须)

7)重要的一步 MIO Configuration 中 使能SD 0的功能,这一步是 TF卡启动的关键设置

8)最后 点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置

9)将刚才添加EMIO GPIO 引出 右键GPIO_0—->Make External

10)用线将M_AXI_GP0_ACLK与 FCLK_CLK0连接起来

11)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示。

12)在弹出的对话框里保持默认

13)软件自动为我们生成HDL文件

五、添加我们的FPGA部分点LED代码,并例化ZYNQ模块

1)在主界面点击左侧 Add Sources ,点击 复选框的Add or create design sources 选项 并点击NEXT

此图片的 alt 属性为空;文件名为 image-5.png

2)在出现的Add Sources 中 选择创建新文件 Create FILE 如下图所示,并在弹出的窗口中 选择类别为Verilog ,在FILE name中填写文件的名称,这里用LED 代替,点击OK 并点击FINISH

3)在跳出的窗口中可以填写模块的输入输出信号,由于这部分工作在代码中可以完成,所以这里直接点OK 完成VERILOG 文件的创建.

4)双击打开刚才创建的LED.V文件 并在里面写入LED的代码

LED部分的代码如下,和我们之前FPGA实验一中的一致。

`timescale 1ns / 1ps
module LED(
input clk,//125m
output led
);
parameter T1MS = 27'd125_000_000 ; //125M CLK
reg [26:0]time_count =27'd0;//time counter
reg led_r;
always@(posedge clk)
if(time_count>=T1MS)begin
time_count<=27'd0;
led_r<=~led_r;
end
else time_count<=time_count+1'b1;
assign led=led_r;
endmodule

5) 在程序中例化ZYNQ模块

首先回看我们的工程, 现在工程有两部分构成,一个是我们的纯FPGA代码 LED.V (里面是逻辑点LED的功能),另一个是刚刚创建的ZYNQ_CORE_wrapper ,两者是相互独立的,也就是如果代码按现在的结构运行,硬件只会包含ZYNQ_CORE,而不会包含LED。 所以这里我们需要将两者整合到一起,可以再创建一个顶层代码top.v 来分别例化我们的LED 还有 ZYNQ,也可以偷懒直接在我们原先的工程LED.V中直接例化ZYNQ_CORE(因为本章的重点是介绍代码的固化,所以这里我们选择更简单的第二种方式)。

打开刚才的LED.v,并在 endmodule的 上方添加ZYNQ_CORE 例化的代码,以及在模块定义上添加一个output信号 led_emio,用于引出ZYNQ模块的EMIO脚。

 wire [0:0]GPIO_EMIO;
ZYNQ_CORE_wrapper zynq_u(
.GPIO_0_0_tri_io(GPIO_EMIO)
);
assign led_emio=GPIO_EMIO[0];

(因为ZYNQ中定义的 GPIO_O_O_tri_io是inout [0:0]GPIO_0_0_tri_io ,所以这里 GPIO_EMIO定义的时候也要定义 wire [0:0]GPIO_EMIO,否则会出现综合不通过的情况)

肯定有人会问 ZYNQ_CORE 里明明有那么多信号,为啥我都留空了只保留了GPIO_0_0_tri_io信号,其实这里我也偷懒了,因为本章中ZYNQ只添加了一个EMIO外设,而剩下诸如DDR FIX_IO这种信号线因为本身是硬件连接的,所以即使程序例化的时候留空,这些信号线仍然是硬件同外部连接的。(备注 如果有其他的EMIO 或者AXI 等涉及到和FPGA通讯或者映射的信号,则这里例化的时候必须添加信号上去)

这样我们就在LED.V中增加了ZYNQ部分了。 (这里容易产生误区,ZYNQ模块是硬件存在的,并不是实例化凭空出现的,只是通过例化这种方式将两部分结合在一起了)

完整代码如下:

`timescale 1ns / 1ps
module LED(
input clk,//125m
output led,
inout led_emio
);
parameter T1MS = 27'd125_000_000 ; //125M CLK
reg [26:0]time_count =27'd0;//time counter
reg led_r;
always@(posedge clk)
if(time_count>=T1MS)begin
time_count<=27'd0;
led_r<=~led_r;
end
else time_count<=time_count+1'b1;
assign led=led_r;

wire [0:0]GPIO_EMIO;
ZYNQ_CORE_wrapper zynq_u(
.GPIO_0_0_tri_io(GPIO_EMIO)
);
assign led_emio=GPIO_EMIO[0];

endmodule

六、创建约束文件,并定义管脚

1)Add Source → Add or create constraints 点Next

因为这个项目没有创建过约束文件 所以这里创建一个约束文件,并在File name 里设置约束文件的名称,并且点击FINISH 完成约束文件的创建

2)Sources → Constraints 里找到刚才创建的约束文件 双击并打开该XDC约束文件

在约束文件里面复制下面代码来对输出的GPIO进行管脚。

set_property IOSTANDARD LVCMOS33 [get_ports led_emio]
set_property IOSTANDARD LVCMOS33 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property PACKAGE_PIN H16 [get_ports clk]
set_property PACKAGE_PIN R14 [get_ports led]
set_property PACKAGE_PIN P14 [get_ports led_emio]

七、综合布线和生成bit文件

1)按下绿色箭头对工程进行编译

2)按下Generate Bitstream 完成综合以及生成bit文件

八、SDK程序编写

1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

系统将自动打开SDK开发环境

3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。

4)在新建工程名中输入自己的工程名称,点击NEXT

5)选择空工程,点击完成FINISH

6) 在工程中添加main.c文件 src—>New—>Source File 如下图所示

7)在弹出的窗口中填入main.c 并且保存

8).打开刚才创建的main.c

然后 写入以下代码(代码是在 例程的基础上进行精简的) 有一个地方值得注意 EMIO的 IO口编号 是从54开始的,也就是我VIVADO 下创建的 EMIO端口,在PS端都是从54-55-56 依次排序的(小贴士 小于54的是MIO 也就是芯片PS的硬件IO口)

#include "xparameters.h"
#include "xgpiops.h"
#include "xstatus.h"
#include "xplatform_info.h"

#define LED 54

#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
XGpioPs Gpio;


void Gpio_Init(void){
XGpioPs_Config *ConfigPtr;

ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);

XGpioPs_SetDirectionPin(&Gpio, LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, LED, 1);
XGpioPs_WritePin(&Gpio, LED, 0);
}


#define LED_DELAY 10000000
volatile int Delay;

int main(void)
{
Gpio_Init();

while(1){

XGpioPs_WritePin(&Gpio, LED, 1);
for (Delay = 0; Delay < LED_DELAY; Delay++);
XGpioPs_WritePin(&Gpio, LED, 0);
for (Delay = 0; Delay < LED_DELAY; Delay++);

};

return 0;
}

九、下载与验证

1)新创建的工程最好先对Run as 进行配置:右键工程,并点选Run As -> Run Configurations

2) 在弹出的窗口中对Reset entire system 和 Program FPGA两个选项进行勾选操作,这样就不会出现下载程序debug的时候概率性不工作的问题了。(这样操作后系统会自动对FPGA进行配置,不需要按之前工程手动对FPGA进行编程了)

PS如果没有出现下图对话框,可以直接双击左侧的applicationo (System Debugger)。

3)设置好之后,选择Run As -> Launch on Hardware (System Debugger) 进行调试。

下载成功后,可以看到板子上的两个LED以不同的频率正进行闪烁,其中LD0对应的是FPGA逻辑功能中的LED, 而LD1对应的是PS逻辑中的LED灯。 两者闪烁证明程序都正常运行了。

备注 这里的调试下载是没有固化的,断电后 程序会丢失。 接下来才是 PS部分的固化设置

十、创建TF卡的镜像文件

程序固化分为两步1. 创建FSBL模块,2.创建image(boot.bin)文件

在zynq上运行程序的时候,加载过程中肯定需要用到一个文件,那就是fsbl,是zynq启动第一阶段的加载程序,经过了fsbl这一阶段,后面系统才能够运行裸奔程序或者是引导操作系统的u-boot

1)创建FSBL:在SDK中新建工程如下

设置工程名fsbl,点next选择FSBL模板

2)制作BOOT.bin即TF卡镜像文件

BOOT.bin由fsbl.elf文件 vivado生成的fpga 的bit文件 app工程的elf文件(这里为led工程的elf)三个文件组成。在生成image的时候要分别填入三个文件的路径, 这里也有个偷懒的方法,就是在点 create boot image之前先选中 我们的APP工程,这样系统会自动为我们添加路径。如下所示

a) 先选中 我们的APP工程目录,这里是LED_CODE( 不是FSBL 也不是BSP 和 platform) 如果一开始已经被选中了,请先用鼠标选择上下任意一个目录,再选择回APP目录,否则路径可能不自动加载

b) 点xilinx –>create boot image

在界面里分别设置 boot.bin的输出路径,以及生成boot.bin需要的三个文件的路径(这里有一个偷懒的方法,就是在点下Create Boot Image 之前先选中我们的APP工程),如下图所示,如果没有出现三个文件的路径,请重试上一步。 如果有三个文件路径,则直接点create image生成镜像

十一、 验证SD TF 卡启动

1)在刚才create boot image 中的boot.bin文件的导出文件夹中,复制出这两个文件到空的TF卡中 (切记 需要格式化成FAT32格式)

也可以直接在SDK软件中直接COPY 生成的boot.bin文件,如下图所示

2. 将TF 卡插入到 主板的卡槽中

3. 将板子设置成 TF卡启动模式 如下图所示

4.重新断电再上电(或者按下POR_RST键),正常的话两个LED 会开始闪烁,说明板子的FPGA 和PS部分的代码都正常工作了,证明TF卡启动成功。

不启动问题排查

  1. TF卡的 格式不对 必须是FAT32格式。
  2. TF卡有多个分区,需要统一成一个再进行格式化,(用老毛桃等工具做过启动盘的会出现这种情况)。
  3. TF卡不支持,尝试更换不同品牌 不同容量大小的TF卡, 大容量,越高速的TF卡的兼容性越差(PS 我这边测试 128g的闪迪高速盘也能支持)。

  • 本文的完整工程下载:07_PS_TF_BOOT_TEST
  • VIVADO的版本:2018.3
  • 工程创建目录: E:\Lemon_ZYNQ\SDK\07_PS_TF_BOOT_TEST

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注