PYNQ-Z2 初识(十二) 自定义IP核,通过PWM IP核实现led呼吸灯

ip核是开发过程中非常重要的东西,我感觉就有点像是python的很多库一样。

除了xilinx提供的ip核外,我们还可以自定义ip核

此次参考ALINX_ZYNQ(我没打错)的开发教程做一个可以通过PWN控制LED的IP核心。

首先第一步肯定是创建工程和添加zynq

创建IP

然后就是创建一个新的自定义ip了
在这里插入图片描述
创建一个AXI4的外设
在这里插入图片描述
完成之后点击左侧的IP Catalog,可以找到刚才创建的IP,右键Edit in IP packager

在这里插入图片描述

之后会打开一个新的工程

或者你直接结束的时候edit 也可以
在这里插入图片描述

IP核心内容

PWM

所谓PWM,指脉冲宽度调制,简单的讲就是生成一个宽度可变的方波,对于我们而言,可以通过计数阈值,计数器每到N就重置,那么N就控制了周期,然后计数器小于n大于0的时候输出高电平,大于n小于N的时候输出低电平,就控制了高电平的占比,也就是占空比。通过这种方式可以实现呼吸灯、电机调速等功能。

源文件的定义

点击Add source,添加一个叫pwm_generator.v的源文件,接口什么的咱们进文档去写。
在这里插入图片描述
既然是PWM,首先应该有个计数功能,我们定义几个变量:时钟clk,复位rst,使能en以及计数最大值period。
那么这块的内容应该有

always @(posedge clk or negedge rst)
	/***********计数功能***********/
	begin
		if(!rst)//如果复位就置0 
			count <= 0;
		else if (count >= period - 1 || en == 0) // 溢出置0
			count <= 0;
		else
			count <= count + 1'b1; // 计数+1
	end

然后就是按照计数给输出端赋值了。我们还需要一个变量,比如输出高的时间或者占空比,这里我们用一个新的输入量hight_time代表高电平对应的计数,period是总的计数,其比值就是占空比。

always @(posedge clk or negedge rst)
	/***********PWM输出************/
	begin
		if(!rst) //复位
			pwm <= 0;
		else
			begin
				if (en == 0) //关闭使能
					pwm <= 0; 
				else
					begin
						if(count < high_time)
							begin
								pwm <= 1;
							end
						else
							pwm <= 0;
					end
			end
	end

ok现在pwm模块就完成了,其完整内容为

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 战斗包子
// 
// Create Date: 2020/07/16 16:21:58
// Design Name: 
// Module Name: pwm_generator
// Project Name: 
// Target Devices: PYNQ-Z2
// Tool Versions: Vivado 2018.3
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module pwm_generator(
    input clk,
    input en,
    input rst,
	input [15:0] period,
	input [15:0] high_time,
    output reg pwm
	);
	
reg [31:0] count;

always @(posedge clk or negedge rst)
	/***********计数功能***********/
	begin
		if(!rst)//如果复位就置0 
			count <= 0;
		else if (count >= period - 1 || en == 0) // 溢出罿0
			count <= 0;
		else
			count <= count + 1'b1; // 计数+1
	end
		
always @(posedge clk or negedge rst)
	/***********PWM输出************/
	begin
		if(!rst) //复位
			pwm <= 0;
		else
			begin
				if (en == 0) //关闭使能
					pwm <= 0; 
				else
					begin
						if(count < high_time)
							begin
								pwm <= 1;
							end
						else
							pwm <= 0;
					end
			end
	end
	
endmodule

连接端口

到之前自动生成的文件中添加端口,此处有两个pwm_ctrl是为了控制两路输出pwm波。
在这里插入图片描述
在这里插入图片描述

保存,然后转到top level开始调用模块,
比之前多了两个pwm的输出模块
在这里插入图片描述

在模块中添加接口调用
在这里插入图片描述

同样用户logic的地方也得改,那就是实例化我们的pwm发生器

    pwm_generator pwm0(
        .clk(s00_axi_aclk),
        .en(en),
        .rst(s00_axi_aresetn),
        .period(pwm_ctrl0[15:0]),
        .high_time(pwm_ctrl0[31:16]),
        .pwm(pwm_out0)
    );
    
    pwm_generator pwm1(
        .clk(s00_axi_aclk),
        .en(en),
        .rst(s00_axi_aresetn),
        .period(pwm_ctrl1[15:0]),
        .high_time(pwm_ctrl1[31:16]),
        .pwm(pwm_out1)
    );

此时可以保存综合一下,看看有没有报错(也不一定能全查出来。)

IP核打包

打开compent.xml,进入file Groups,点击Merge changes from file groups wizard
在这里插入图片描述
然后依次让左侧不是勾的都打勾。

最后Re-pakage IP

ok 一个船新的IP核就打包好了。

工程实现

create一个block design,然后添加zynq处理器以及刚刚生成的ip
在这里插入图片描述
这个pwm模块有两个控制端两个输出端,一个使能端,就和我们定义的一样,让它自动二连。
自动连线后,我们的pwm ip的axi总线部分连接了,但是右边我们自己定义的端口还没连。
在这里插入图片描述
通过make external给pwm的out提供两个输出端
记得把名字改成pwm_out0和pwm_out1,不然的话一会改一下约束文件也可以。
在这里插入图片描述
然后右键system选择 generate output products
在这里插入图片描述
再create HDL wrapper

再添加约束,和之前的内容一样,输入

set_property -dict { PACKAGE_PIN R14   IOSTANDARD LVCMOS33 } [get_ports { pwm_out0 }]; 
set_property -dict { PACKAGE_PIN P14   IOSTANDARD LVCMOS33 } [get_ports { pwm_out1 }]; 

接下来老规矩,generate bitstream一波流

SDK

老规矩,export hardware(include bit stream),launch SDK

这次创建一个空应用工程
右键src,添加.c源文件
可以找到pwm0的内存地址是
在这里插入图片描述
pwm1的则是0x43c00004(寄存器的地址间隔为4)((为什么我也不知道))

我们定义第一个PWM的控制端口信号为

u32 pwm_gen0= 0x0BB81388;// 3000/5000

第二个端口为

u32 pwm_gen1= 0x07d01388;	//  2000/5000

总程序为

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
/* Include Files */
#include "xparameters.h"
#include "xil_io.h"
#include "xstatus.h"
/* Definitions */
#define printf xil_printf							/* smaller, optimised printf */
/*
 *
 */
u32 pwm_gen0= 0x0BB81388;							/* high_time & period*/
u32 pwm_gen1= 0x07d01388;							/* high_time & period*/
u32 pwm_en = 0x01;							/*enable flag*/
#define  pwm0 0x43c00000											/* address of pwm0 configure register*/
#define  pwm1 0x43c00004											/* address of pwm1 configure register*/
#define  en   0x43c00008								     		/* address of enable flag configure register*/
int main()
{
    init_platform();
    print("Hello World\n\r");

    cleanup_platform();
	/* Execute the pwm output. */
    	Xil_Out32(pwm0,pwm_gen0);     //configure pwm0 period and D
    	Xil_Out32(pwm1,pwm_gen1);	  //configure pwm1 period and D
    	Xil_Out32(en,pwm_en);	      // enable pwm0 pwm1 at the same time


    return 0;
}

然后和之前一样烧写程序并运行c程序,可以看到led0和led1两个灯亮了,不过看不出来什么差别啊,我们修改一下,让占空比不断变化,并且通过串口打印占空比。

修改后的程序如下,占空比会从0逐渐到100再逐渐到0,可以观察到小灯闪烁的效果。


#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
/* Include Files */
#include "xparameters.h"
#include "xil_io.h"
#include "xstatus.h"
/* Definitions */
#define printf xil_printf							/* smaller, optimised printf */
/*
 *
 */
//u32 pwm_gen0= 0x0BB81388;							/* high_time & period*/
//u32 pwm_gen1= 0x07d01388;							/* high_time & period*/
u16 period = 0x1388;
u16 h_time0 = 0x0000;
u16 h_time1 = 0x1388;

u32 pwm_en = 0x01;							/*enable flag*/
#define  pwm0 0x43c00000											/* address of pwm0 configure register*/
#define  pwm1 0x43c00004											/* address of pwm1 configure register*/
#define  en   0x43c00008								     		/* address of enable flag configure register*/
int main()
{
	u8 duty = 0;
	u8 dir = 1;
    init_platform();
    while (1){

		printf("duty cycle : %d \% \n\r",duty);
		if (dir == 1)
			duty ++;
		else
			duty --;
		if (duty == 100) dir = 0;
		if (duty == 0) dir = 1;
		h_time0 = period * duty/100;
		h_time1 = period * (100-duty)/100;

		cleanup_platform();
		/* Execute the pwm output. */
			Xil_Out32(pwm0,(h_time0<<8) + period);     //configure pwm0 period and D
			Xil_Out32(pwm1,(h_time1<<8) + period);	  //configure pwm1 period and D
			Xil_Out32(en,pwm_en);	      // enable pwm0 pwm1 at the same time
			usleep(100000);
    }

    return 0;
}

参考资料

https://blog.csdn.net/qq_42263796/article/details/102156228

  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: PYNQ-Z2是一款基于Xilinx Zynq-700 SoC的开发板,Vivado是Xilinx公司的FPGA设计工具,IP核是Vivado中的一种设计元素,可以用于快速构建复杂的硬件模块。因此,PYNQ-Z2 Vivado IP核设计是指在PYNQ-Z2开发板上使用Vivado设计IP核的过程。 ### 回答2: pynq-z2是一款基于Xilinx Zynq-7000系统级芯片的低成本开发板,可以通过使用Vivado进行IP核设计,实现各种功能。下面将介绍如何在pynq-z2上使用Vivado进行IP核设计。 首先,需要在Vivado中创建一个新项目。选择合适的目标设备和开发板,然后选择“RTL Project”选项。之后,可以按需添加各种IP核或自行设计。 其次,需要确认pynq-z2开发板中的引脚分配。可以从官方网站上获取pynq-z2的引脚分配表,或者在Vivado中使用IP Integrator工具进行查看和编辑引脚分配。在引脚分配正确的前提下,可以对IP核进行进一步的配置和设计。 接下来,需要将设计好的IP核综合、实现和生成比特流文件。在完成该步骤后,将生成的比特流文件拷贝到SD卡中,并将SD卡插入到pynq-z2开发板中。 最后,在pynq-z2开发板中运行Linux系统,并使用Jupyter Notebook进行开发工作。在使用过程中,可以通过在Python代码中加载对应的IP核进行调用和使用实现出各种功能,例如数字信号处理、视频图像处理等。 总之,pynq-z2与Vivado的结合为IP核设计提供了一个便利、高效、低成本开发环境,为用户提供了一个开发嵌入式系统和数字信号处理的理想平台。 ### 回答3: Pynq-Z2是由Xilinx推出的基于Zynq-7000 SoC的一款低成本开发板,拥有丰富的外设资源和可编程逻辑资源,是一款非常适合初学者或者小型项目开发的开发板。 Vivado是Xilinx在FPGA设计领域的一款全面的开发工具,可以支持从设计、仿真、综合、实现到调试等诸多领域的开发需求。在Pynq-Z2的开发过程中,可以使用Vivado工具集中包含的IP核完成各种高级功能的设计,例如DMA控制器、FIR滤波器、PLL模块等。 设计Pynq-Z2IP核需要完成以下几个步骤: 1. 准备环境。在使用Vivado工具之前,需要首先准备好Pynq-Z2的开发板,根据文档进行开发板的设定。 2. 创建IP。根据所需的功能,可以在Vivado中创建各种不同的IP核。其中包括VHDL/Verilog实现IP核以及基于SystemC/C++语言的高级综合IP核。 3. 配置IP。对于创建好的IP核,需要进行配置,将其调整为适合Pynq-Z2的外设资源。这一步需要根据Pynq-Z2的硬件资源手册进行设置。 4. 生成IP。完成配置之后,可以将IP核编译成可用的库文件。这个过程可以通过调试功能检查IP核设计的正确性。 5. 集成IP。将生成的IP库文件导入到Vivado中,并且根据需要连接到其他逻辑电路当中。这一步骤非常重要,需要根据硬件规范进行仔细的设计。 6. 仿真验证。在最终集成之前,需要进行IP核的仿真验证。通过仿真可以检查IP核与其他电路的正确性,确保电路能够正常工作。 7. 最终集成。在通过验证之后,可以将IP核集成到最终设计当中。这个过程需要使用Vivado自带的工具对电路进行综合、实现和按板子上传等操作。 总的来说,设计Pynq-Z2IP核需要非常细致的设计和验证工作才能够保证其正确性和可靠性。需要熟练掌握Vivado工具集的使用,并且对硬件规格有足够的了解,才能为Pynq-Z2的开发工作提供可靠的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆沙粽子好吃嘛!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值