Tiny ZYNQ板 工程十六 基于ZYNQ的PS部分UART功能演示

本文用EMIO的方式在主板上演示串口的hello world例程(适用于主板Type C 端口的UART资源)

本文在 vivado2018.3版本上 演示, 其他版本请自行研究

1.硬件资源介绍

PS端串口的映射有两种,方式一 直接通过ZYNQ的PS专用串口的IO口。 方式2 PS端的UART 通过EMIO方式映射到任意PL端口进行引出,两种方式的效果是完全一样的(方式2拓展性更强)。(因为我们的串口是连接在PL端的,所以这里我们用方式二 通过EMIO将UART 映射到PL端 IO上)

2. 创建工程(本处将同时介绍 emio映射的uart 创建方法)

1)新建一个项目,芯片型号选择 XC7Z010CLG400-1(略掉部分过程,详细图文过程可以参考前面的几个帖子)

2) 创建一个BLOCK设计,并添加ZYNQ7 PROCESSING SYSTEM模块,软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

3)在ZYNQ中设置时钟功能:

找到 设置项目中的 Clock Configuration 选项, 在PL Fabric Clocks 设置自己需要的时钟频率,这里一共有4种频率可以设置 类似于我们的PLL功能。这里我们设置50M时钟

4)在zynq中设置DDR功能:

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

5) 添加 uart功能

由下图可知, 主板的UART功能接在 ZYNQ PL端的 U13脚和T12脚了,这里要反着看,CH340的TX 对应 ZYNQ的RX, CH340的RX 对应ZYNQ的TX,所以这里 ZYNQ的TX是 U13,ZYNQ的RX是T12

使能UART 0 并在IO选项力 选择EMIO方式

6)完成上述操作后, 点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置,并用鼠标连接FCLK_CLK和 M_AXI_GP0_ACLK,得到下图

在上图中分别点击IO口进行以下操作:

右键UART_0选择Make External(这一步仅仅 用到EMIO 的UART时需要用到,扩展板)

7)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper,打包BLOCK文件并生成.v代码

8) 点击绿色箭头RUN 对代码进行编译

9) 点击RTL 中的SCHEMATIC , 并选择右边出现的 IO Ports 来增加UART 0 EMIO部分的管脚定义(这一步也可以在约束文件中定义, 可看之前的例子)

将 UART 部分的 TX RX 分别设置成 U13,T12 电压属性设置成 LVCMOS33, 之后保存

10) 生成bit文件 :按下Generate Bitstream 完成综合以及生成bit文件(会弹出窗口要求保存 约束规则文件)

5.SDK程序编写

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

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

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

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

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

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

6) 在空工程中创建我们自己的代码

展开我们创建的工程,在src目录上右键,选择New->Source File,如下图所示:

在弹出的窗口中创建一个main.c文件

7)书写自己的代码

7.1小贴士:

在初次写PS部分的代码时,如GPIO代码 和UART代码,不知道怎么写的情况下,其实可以通过打开 BSP工程下的 system.mss文件, 然后在右边导入需要的参考例程, 然后将例程中自己需要的部分(如GPIO初始化,或者UART的写和读代码COPY到自己工程的main函数中)再进行修改。

7.2 复制 下列代码 到 main.c

#include "xparameters.h"
#include "xuartps.h"
#include "xil_printf.h"

XUartPs Uart_Ps_0;		/* The instance of the UART Driver */

int UART_init(){
	XUartPs_Config *Config;
	int Status;

	Config = XUartPs_LookupConfig(XPAR_XUARTPS_0_DEVICE_ID);
	Status = XUartPs_CfgInitialize(&Uart_Ps_0, Config, Config->BaseAddress);
	XUartPs_SetBaudRate(&Uart_Ps_0, 115200);

	return Status;
}

void UartPs_HelloWorld()
{
	u8 HelloWorld[] = "Hello World  ";
	int SentCount = 0;

	while (SentCount < (sizeof(HelloWorld) - 1)) {
		 XUartPs_Send(&Uart_Ps_0, &HelloWorld[SentCount], 1);
		SentCount++;
	}
}

int main(void)
{
	int Delay;
	UART_init();
	while(1){
		UartPs_HelloWorld();
		for (Delay = 0; Delay < 100000000; Delay++);
	}
}

我这边参考了官方的代码, 并做了一定的删减(删除了不必要的初始化验证等),将UART 0,和进行了初始化, 并且在helloworld的代码中,端口进行helloworld的字符串输出,反复循环。

8.代码下载验证

先对 RUN AS 的环境进行配置

在弹出的窗口中 对4个 方框都进行勾选操作,以确保每次运行都会重新启动系统,并且重新编程FPGA, 这样就不会出现下载程序debug的时候概率性不工作的问题了(不勾选情况下,板子本身运行程序的时候,再重新debug会概率性出现下载报错的情况)PS没有出现 下图对话框,可以先点绿色箭头DEBUG一下 ,再重新 点选上图RUN CONFIGURATIONS 的选项

设置好之后,选择Run As -> Launch on Hardware (System Debugger) 或者 Launch on Hardware (GDB).

经过上述操作后,串口就会正常输出数据了,此时用串口助手去查看,可以看到 系统在不停的发送 hello world字符串(串口波特率 115200)

以下是本文中提到的完整工程 ,仅供参考

备注 ZYNQ芯片功能非常强大,上述仅进行简单的helloworld演示, 实际串口功能还可以调用中断,调用FIFO等,这个各自自行学习尝试了

备注 如果你使用自己的TYPE C充电线 请注意,部分市面上的TYPE C充电线 是仅充电的,不带数据传输功能,需要用TYPE C 数据线才能实现通讯

发表回复

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