PYNQ上手笔记 | ③PS端+PL端点灯

现在人工智能非常火爆,一般的教程都是为博硕生准备的,太难看懂了,分享一个非常适合小白入门的教程,不仅通俗易懂而且还很风趣幽默,点☞这里​​​​​​​☜进入传送门~

上一节中分别独立实验了Zynq的PS端和PL端,并初步实验了PS端先硬件再软件的开发流程和IP核设计的设计方法。第一节中提及到:Zynq是以PS端的ARM处理器系统为核心的,PS端和PL端是通过AXI总线,并且Xilinx已经提供了各种AXI通信的IP核,接下来的实验中将会更加明确的体验到利用IP核设计的设计方法。

1.实验目标

板载的LED和RGBLED都是接在PL端的,这个实验将利用PS端程序通过AXI总线控制连接在PL端的LED。
PYNQ上手笔记 | ③PS端+PL端点灯_第1张图片

2.实验步骤

整个实验流程参考《The Zynq Book Tutorials》的chpt1:First Designs on Zynq(这本实验指导手册是英文的,但我个人认为英文原版要比中文看着清楚很多)。
需要注意的一点是,这本实验指导手册是针对Zybo和Zedboard的,将其中关于板子的操作换为Pynq中的即可。关于软件驱动程序的部分,书中是采用空白工程+导入随书程序的方法,这里因为板子不同,不采用这种方法,直接利用SDK导入例程

2.1.创建基于Pynq-Z2开发板的Vivado工程

PYNQ上手笔记 | ③PS端+PL端点灯_第2张图片

2.2.基于ip核构建BlockDesign

点击左侧导航栏“IP INTEGRATOR -> Create Bolock Design”,在IP集成环境下创建一个块上设计:
PYNQ上手笔记 | ③PS端+PL端点灯_第3张图片

2.2.1.ZYNQ7 Processing System ip 核

注:搜索“zynq”即可添加。
PYNQ上手笔记 | ③PS端+PL端点灯_第4张图片

从图中可以看出,这只是一个空的IP核,并没有任何连接,双击打开该ip核配置,也全都是默认配置,接下来需要将这个IP核与实际PS处理器系统对应,点击Run Block Automation,Vivado就会自动根据板子的PS配置信息进行对应,这就是为什么要使用board file的原因,如果没有这个官方提供的board file,所有的PS端配置信息都需要手动配置:
PYNQ上手笔记 | ③PS端+PL端点灯_第5张图片

自动连接完成后,可以看到ip核的DDR端口和FIXED_IO端口已经导出,与实际开发板配置对应:
PYNQ上手笔记 | ③PS端+PL端点灯_第6张图片

这个时候双击ip核打开设置可以看到都已经自动完成了,其中“Peripheral I/O Pins”是指定PS端I/O外设引脚,此处我们暂且不作修改:
PYNQ上手笔记 | ③PS端+PL端点灯_第7张图片

2.2.2.AXI GPIO ip 核

注:搜索“gpio”即可添加。
PYNQ上手笔记 | ③PS端+PL端点灯_第8张图片

同样的,AXI GPIO ip核也是一个空核,并没有进行任何连接,要注意的是,这是AXI GPIO软核,在PL端实现,S_AXI端连接在AXI总线上与PS端处理器进行通信,GPIO端连接实际引脚(可任意分配),驱动板载外设
首先对AXI GPIO ip核双击进行设置:
PYNQ上手笔记 | ③PS端+PL端点灯_第9张图片

然后同样的,点击“Run Connection Automation”,自动完成ZynqPS核和AXI GPIO核之间的连接:
PYNQ上手笔记 | ③PS端+PL端点灯_第10张图片

连接完成后可以看到,整个硬件设计如下:
PYNQ上手笔记 | ③PS端+PL端点灯_第11张图片

点击右侧Address Editor即可看到硬件相关信息,在PL端实现的axi_gpio_0 IP核中所包含的寄存器首地址和结束地址,这个信息待会就要导出到硬件设计文件中,通过软件操作相关寄存器。
PYNQ上手笔记 | ③PS端+PL端点灯_第12张图片

2.2.3.验证设计

整体设计完成后,首先按F6或者选择Tools -> Validate Design验证设计:
PYNQ上手笔记 | ③PS端+PL端点灯_第13张图片

2.3.导出硬件设计到SDK

2.3.1.由设计文件创建HDL文件

在源文件页面右击设计文件,选择创建HDL文件
PYNQ上手笔记 | ③PS端+PL端点灯_第14张图片

PYNQ上手笔记 | ③PS端+PL端点灯_第15张图片

2.3.2.生成Bitstream

在右侧导航栏选择"PROGRAM AND DEBUG -> Generate Bitstream",生成比特流文件,用来配置PL端的设计(AXI GPIO 软ip核), 此过程需要花10-20min不等。

2.3.3.导出硬件设计文件

接下来导出整个设计的硬件设计文件(hdf)供SDK进行软件设计使用,因为设计中包含PL端设计,所以要勾选包含Bitstream文件:
PYNQ上手笔记 | ③PS端+PL端点灯_第16张图片

PYNQ上手笔记 | ③PS端+PL端点灯_第17张图片

2.3.3.过渡到SDK

导出完成之后硬件设计工作完成,打开SDK,进入软件设计工作:左上角进入“File -> Launch SDK”:
PYNQ上手笔记 | ③PS端+PL端点灯_第18张图片

2.4.SDK中软件设计

2.4.1.工程目录

PYNQ上手笔记 | ③PS端+PL端点灯_第19张图片

其中:

  • 橙色部分是需要自己编写的应用程序代码
  • 带有bsp的绿色部分是SDK自动生成的板级驱动支持包
  • 黄色部分是关于ARM内核的一些硬件设计文件

2.4.1.1.硬件设计文件(hdf)

红色文件system.hdf就是在vivado中设计完硬件之后导出的硬件设计文件,其中包含了一些设计信息和寄存器地址映射,可以看到其中axi_gpio_0 ip核所包含寄存器的地址信息和之前在vivado中看到的完全一样:
PYNQ上手笔记 | ③PS端+PL端点灯_第20张图片

2.4.1.2.板级驱动支持包(BSP)

板级驱动包中只需要关注绿色的文件system.mss,这个文件说明了该工程中板级驱动支持包的所有信息,包括:

  • 目标硬件信息

  • 采用操作系统信息
    PYNQ上手笔记 | ③PS端+PL端点灯_第21张图片

  • 外设驱动信息
    PYNQ上手笔记 | ③PS端+PL端点灯_第22张图片

  • 库信息

2.4.1.3.应用程序代码(APP)

应用程序代码可以自己编写或者从例程导入,这里直接在system.mss文件中导入:
PYNQ上手笔记 | ③PS端+PL端点灯_第23张图片
一共包括4个例程,导入第一个基本例程:
PYNQ上手笔记 | ③PS端+PL端点灯_第24张图片
PYNQ上手笔记 | ③PS端+PL端点灯_第25张图片

2.4.2.xgpio_example

最好的参考资料是官方文档,包含XGpio操作所有的API说明
PYNQ上手笔记 | ③PS端+PL端点灯_第26张图片
PYNQ上手笔记 | ③PS端+PL端点灯_第27张图片

2.4.2.1.Xilinx GPIO 控制器介绍

Xilinx GPIO控制器是专为Xilinx FPGA设计的软IP核,有以下功能:

  • 每个通道可设置32个I/O
  • 每个I/O可设置为输入或输出
  • 可配置支持双通道和外部中断

XGpio的API声明在xgpio.h文件中,API实现在xgpio.c文件中

2.4.2.2. 初始化XGpio

API:int Xgpio_Initialize(InstancePtr,DeviceID)
功能:根据给定的DeviceID初始化调用者提供的XGpio实例

参数 类型 说明
InstancePtr sturct* XGpio GPIO实例指针(xgpio.h)
DeviceID u16 导出hdl时自动生成(xparameters.h)
return int 成功-XST_SUCCESS 失败-XST_DEVICE_NOT_FOUND

注:
xparameters.h是在导出硬件设计文件时由Vivado自动生成的,包含了所有系统硬件参数的宏定义。
打开xparameters.h找到AXI_GPIO_0的有关宏定义,即可看到和之前在vivado中,在hdf文件中看到的,都是对应的:
PYNQ上手笔记 | ③PS端+PL端点灯_第28张图片

2.4.2.3. 设置XGpio输入/输出方向

API:void XGpio_SetDataDirection(XGpio *InstancePtr, unsigned Channel, u32 DirectionMask)
功能:根据给定的DeviceID初始化调用者提供的XGpio实例

参数 类型 说明
InstancePtr sturct* XGpio GPIO实例指针(xgpio.h)
Channel unsigned 包含要操作的GPIO的通道
DirectionMask u32 指定32个I/O的方向,0-出,1-入

注意:如果此功能与除1之外的任何通道一起使用,则必须为双通道构建硬件。如果不是,则此功能将断言。

2.4.2.4. XGpio电平逻辑操作

API:XGpio_DiscreteWrite(XGpio * InstancePtr,unsigned Channel,u32 Data)
功能:写入指定GPIO通道的寄存器

参数 类型 说明
InstancePtr sturct* XGpio GPIO实例指针(xgpio.h)
Channel unsigned 包含要操作的GPIO的通道
Data u32 32个I/O的电平,0-低,1-高
2.4.2.4.1.置高某个I/O的电平

API:XGpio_DiscreteSet(XGpio * InstancePtr,unsigned Channel,u32 Mask)
功能:将输出设置为指定GPIO通道的逻辑1

参数 类型 说明
InstancePtr sturct* XGpio GPIO实例指针(xgpio.h)
Channel unsigned 包含要操作的GPIO的通道
DirectionMask u32 将被设置为1的位组,0-不选中,1-选中(其它位不受影响)
2.4.2.4.1.拉低某个I/O的电平

API:XGpio_DiscreteClear(XGpio * InstancePtr,unsigned Channel,u32 Mask)
功能:将输出设置为指定GPIO通道的逻辑0

参数 类型 说明
InstancePtr sturct* XGpio GPIO实例指针(xgpio.h)
Channel unsigned 包含要操作的GPIO的通道
DirectionMask u32 将被设置为0的位组,0-不选中,1-选中(其它位不受影响)

2.4.3.修改main程序

导入的例程中如果未发生异常,串口没有任何输出,所以为了测试,进行以下小修改,将串口输出代码提前:
PYNQ上手笔记 | ③PS端+PL端点灯_第29张图片

2.4.4.下载并运行程序

因为该设计中包含PL端设计比特流,所以在run程序前需要设置,右键->Run As -> Run Configurations:
PYNQ上手笔记 | ③PS端+PL端点灯_第30张图片

3.实验结果

注:要在运行之前开启串口终端。
PYNQ上手笔记 | ③PS端+PL端点灯_第31张图片

PYNQ上手笔记 | ③PS端+PL端点灯_第32张图片

4.实验总结

完成了整个实验后再来看这张图,首先在PL端通过添加AXI GPIO IP核实现一个GPIO控制器,GPIO控制器由于在PL端,所以输出直接与4个板载LED相连,然后vivado自动布局布线,将GPIO控制器的受控端与PS端处理器核进行对应连接,然后生成导出硬件设计文件供SDK使用。
PYNQ上手笔记 | ③PS端+PL端点灯_第33张图片

SDK根据硬件设计文件生成C工程,通过运行于PS端ARM处理器的程序控制PL端实现的GPIO控制器,完成PS通过AXI总线控制PL端LED(GPIO)的实验。

5.实验扩展

5.1.自己动手实现led驱动

5.1.1.新建空工程

在SDK中左上角“File -> New -> Application Project”,创建一个空工程:
PYNQ上手笔记 | ③PS端+PL端点灯_第34张图片

PYNQ上手笔记 | ③PS端+PL端点灯_第35张图片

5.1.2.头文件

/**
 *   @filename		led_bsp_mculover666.h
 *   @brief				实现板载4颗LED驱动
 *   @data				 2018/10/18
 *   @author			Mculover666
 */

#ifndef LED_BSP_MCULOVER666_H_
#define LED_BSP_MCULOVER666_H_

#include "xgpio.h"
#include "xparameters.h"

#define ON								 1
#define OFF								 0
#define LED_XGpio_Device_ID  			 XPAR_GPIO_0_DEVICE_ID
#define LED_XGpio_Channel	 		     1
#define LED								 0x0000000F
#define LED1							 0x00000001
#define LED2							 0x00000002
#define LED3							 0x00000004
#define LED4							 0x00000008

/* 初始化LED所在io */
void led_init();
void LED1_Statue(int statue);
void LED2_Statue(int statue);
void LED3_Statue(int statue);
void LED4_Statue(int statue);
void LED_Statue(int statue);

#endif /* LED_BSP_MCULOVER666_H_ */

5.1.3.源文件

/**
 *   @filename		led_bsp_mculover666.c
 *   @brief				实现板载4颗LED驱动
 *   @data				 2018/10/18
 *   @author			Mculover666
 */
#include "led_bsp_mculover666.h"

XGpio gpio;		//实例化一个Xgpio类型结构体

/**
 * @brief		LED IO初始化
 * @param   none
 * @retval		none
 * */
void led_init()
{
	/* 初始化XGpio */
	XGpio_Initialize(&gpio, LED_XGpio_Device_ID);

	/* 设置XGpio中LED所在引脚方向为输出 */
	/* !!!注意:0-output 1-input !!! */
	XGpio_SetDataDirection(&gpio, LED_XGpio_Channel, ~LED);

	/* 默认输出低电平 */
	XGpio_DiscreteClear(&gpio, LED_XGpio_Channel, LED);
}


/* 定义LED单个操作函数 */
void LED1_Statue(int statue)
{
	if(statue)
		XGpio_DiscreteSet(&gpio, LED_XGpio_Channel, LED1);	//低电平点亮
	else
		XGpio_DiscreteClear(&gpio, LED_XGpio_Channel, LED1);		//高电平点亮
}
void LED2_Statue(int statue)
{
	if(statue)
		XGpio_DiscreteSet(&gpio, LED_XGpio_Channel, LED2);	//低电平点亮
	else
		XGpio_DiscreteClear(&gpio, LED_XGpio_Channel, LED2);		//高电平点亮
}
void LED3_Statue(int statue)
{
	if(statue)
		XGpio_DiscreteSet(&gpio, LED_XGpio_Channel, LED3);	//低电平点亮
	else
		XGpio_DiscreteClear(&gpio, LED_XGpio_Channel, LED3);		//高电平点亮
}
void LED4_Statue(int statue)
{
	if(statue)
		XGpio_DiscreteSet(&gpio, LED_XGpio_Channel, LED4);	//低电平点亮
	else
		XGpio_DiscreteClear(&gpio, LED_XGpio_Channel, LED4);		//高电平点亮
}

/* 定义LED整体操作函数 */
void LED_Statue(int statue)
{
	if(statue)
		XGpio_DiscreteSet(&gpio, LED_XGpio_Channel, LED);	//低电平点亮
	else
		XGpio_DiscreteClear(&gpio, LED_XGpio_Channel, LED);		//高电平点亮
}

5.1.4.主文件

/**
 *   @filename		main.c
 *   @brief				测试LED驱动
 *   @data				 2018/10/18
 *   @author			Mculover666
 */
#include "led_bsp_mculover666.h"
#include "xil_printf.h"

int main()
{
	/* 初始化LED所在io */
	led_init();
	print("LED init ok\r\n");

	/* 打开所有io */
	LED_Statue(ON);
	print("LED is all on\r\n");

	while(1);

}

5.1.5.实验结果

PYNQ上手笔记 | ③PS端+PL端点灯_第36张图片

5.2.加入RGBLED驱动

加入RGBLED驱动有两种方法:

  • 挂载在已实现的axi_gpio_0的通道1上:axi_gpio_0支持32个io,led只使用了前4个,所以可以将两颗rgbled的6个引脚挂载在axi_gpio_0上

  • 挂载在已实现的axi_gpio_0的通道2
    PYNQ上手笔记 | ③PS端+PL端点灯_第37张图片

PYNQ上手笔记 | ③PS端+PL端点灯_第38张图片

因为硬件设计文件更改,所以需要重新自动布局布线,生成比特流,导出硬件文件

然后将程序中通道值改为2,LED的值改为0x3f(使用了6个io)即可看到现象:

#define LED 0x3f   /* Assumes bit 0 of GPIO is connected to an LED  */
#define LED_CHANNEL 2

你可能感兴趣的:(#,Pynq/Zynq实战教程,FPGA开发)