建立工程
这里参照上一篇文章ZYBO学习笔记(一)- PL端实现流水灯建立工程ps_led
建立 Block Design
当我们的设计需要用到 Zynq 的处理器系统(Processing System, PS)时候,就需要透过 Block Design 来建立我们的电路设计,点击IP Integrator -> Create Block Design
我们首先寻找 Zynq 并将ZYNQ7 Processing System
加入到我们的Block Design
双击添加后的PS核,然后点击上方的Import xps settings,导入zybo的板卡网表文件zybo_zynq_def.xml,然后点击ok。如下图红框所示
进入到Run Block Automation
的设定页面后,确认processing_system7_0
有被勾选到,并且Cross Trigger In
以及 Cross Trigger Out
都是Disable
的状态,点选 Ok 结束设定。
上面的设定好了后,就会看到ZYNQ7 Processing System
的 DDR 以及 FIXED_IO 都有接线出来
点选 Add IP 按钮去增加我们需要的 IP 核,这次我们要增加 AXI_GPIO ,用来对可程式逻辑(Programmable Logic, PL)区域的 LED 进行控制
双击GPIO IP,按如图配置,包含4bit的输入和4bit的输出,然后点击ok:
此时diagram界面如下所示。我们需要建立IP与PS之间的通道。点击Run connection automation,如下图所示
勾选“all automation“,点击ok
系统自动生成连接
此处详解:PS核与PL的IP之间通信方式只有一种,那就是通过AXI总线。AXI interconnect IP是一个功能强大的IP,它能管理多个AXI接口的IP。用户如果用到多个AXI IP,那么只需PS将M_AXI_GP0引脚连接到AXI interconnect Ip的SO0_AXI引脚,再将AXI interconnect ip的输出分别连接到每个AXI IP的S_AXI引脚即可,省去了多个AXI互联的管理问题。Processor System Reset IP为其他IP提供复位信号。
连接完毕axi ip后,还需进行ip的地址分配,以便ps部分对IP的调用。在Address Editor一栏,直接点击左侧的auto assign address按钮。如下图所示:
接下来将GPIO引脚重新命名
接下来点选 Validate Design 按钮,我们要确认我们的 Block Design 没问题才能够继续往下走。
添加引脚约束
参考前文ZYBO学习笔记(一)- PL端实现流水灯添加Zybo-Master.xdc
引脚约束文件,取消注释LED部分
产生HDL Wrapper
修改Constraints文件让Wrapper和Constraints文件里面的引脚对应起来
output [3:0]led_tri_o;
input [3:0]sw_tri_i;
改好后,点选上方的 Run Implementation 来确认我们这样的修改是否能编译/验证成功。
产生位元流 (bitstream)
前面的处理都好了后,接下来点选 Program and Debug -> Generate Bitstream 去让 Vivado 将这个专案产生出位元流 (bitstream),ZYNQ 会根据 bitstream 的资讯对 FPGA 进行设定。
当 bitstream 产生完成后,由于我们这次的实作,是要透过写 C 语言程式来控制 Zynq 进行 LED 的亮暗,因此要先将刚刚产生的硬体资讯输出给 Xilinx SDK 去。
点击File -> Export -> Export Hardware
完成后,启动 Xilinx SDK
Xilinx SDK
选择File -> New -> Application Project
建立工程
我这里命名为LED
建立 main.c
代码
#include
#include "platform.h"
#include "xgpio.h"
//void print(char *str);
XGpio SW_LED;
#define SW_CHANNEL 1
#define LED_CHANNEL 2
#define SW_IN XGpio_SetDataDirection(&SW_LED, SW_CHANNEL, 0x0f)
#define LED_OUT XGpio_SetDataDirection(&SW_LED, LED_CHANNEL, 0x00)
#define SW_VALUE XGpio_DiscreteRead(&SW_LED, SW_CHANNEL)
int init_gpio(){
int Status;
Status = XGpio_Initialize(&SW_LED, XPAR_AXI_GPIO_0_DEVICE_ID);
if (Status != XST_SUCCESS){
return XST_FAILURE;
}
SW_IN;
LED_OUT;
return XST_SUCCESS;
}
int main(){
int value;
init_platform();
print("Hello World\n\r");
init_gpio();
while(1){
value = SW_VALUE;
XGpio_DiscreteWrite(&SW_LED, LED_CHANNEL,value);
}
cleanup_platform();
return 0;
}
LED闪烁USB串口循环打印测试
int main(){
int value;
init_platform();
print("Hello World\n\r");
init_gpio();
value = SW_VALUE;
while(1){
XGpio_DiscreteWrite(&SW_LED, LED_CHANNEL, value);
value = ~value;
print("Hello World\n\r");
simple_delay(10000000);
}
cleanup_platform();
return 0;
}
程序分析
在 main.c 的开头,我们载入了需要使用的几个标头档,在 Xilinx SDK 中,已经包含了一些预设好的函式库等功能,具体资讯请查阅Xilinx OS and Libraries Document Collection (UG643)手册。
xparameters.h
这个标头档则是 Xilinx SDK 自己产生的,里面会包含一些关于你使用的 IP Core 的资讯,比如标准输出的基底位址 (base address) 或是其他和你这份硬体相关的设定。而xgpio.h
则提供了一些高阶的抽象函式,让你开发 GPIO 相关的功能可以更加轻松。
参考文档在vivado安装目录下可以找到,我的电脑在file:///D:/Xilinx/SDK/2015.4/data/embeddedsw/XilinxProcessorIPLib/drivers/gpio_v4_0/doc/html/api/group__gpio__v4__0.html
直接浏览器打开
int XGpio_Initialize(XGpio * InstancePtr, u16 DeviceId)
根据DeviceId
例化XGpio
,DeviceId
在xparameters.h
里定义,初始化成功返回XST_SUCCESS
void XGpio_SetDataDirection(XGpio * InstancePtr,unsigned Channel,u32 DirectionMask)
,Channel
控制当前操作IP核里哪一个通道的GPIO,这里1组是开关输入,2组是输出到LED。DirectionMask
参数决定了输入输出,0
输出,1
输入每位对应1个IO
u32 XGpio_DiscreteRead(XGpio * InstancePtr,unsigned Channel)
这个很好理解就是读GPIO上的值
void XGpio_DiscreteWrite(XGpio * InstancePtr, unsigned Channel, u32 Data)
设置GPIO输出的值
下载到Zybo board
确定此时你有将 Zybo board 接到电脑,并且你 JP5 设定在 QSPI 模式下,就像这样
选择 Xilinx Tools -> Program FPGA 进行 FPGA 的烧录。
确认要烧录的资料无误后,点选Program
将位元流 (bitstream) 烧录到 FPGA 去
下载bit完毕,接着就是运行PS了。在工程左侧Procject Explorer栏,右击hello->RunAs->Launch on Hardware,如下图:
稍等几秒,就可以操作SW了。LED的状态随着SW的改变而改变。
参考
https://reference.digilentinc...
https://coldnew.github.io/dec...
https://blog.csdn.net/lzy2729...