ZYNQ 自定义IP

一、实验目的:

        通过自定义AXI 接口 IP连接pl和ps侧然后通过ps侧操作axi寄存器来改变pl侧呼吸灯的频率。

二、实验架构:

三、实验流程

1、先创建两个文件夹,一个是管理我们自定义IP的文件夹,一个是存储待会儿用到我们自定义ip的工程

2、点击manage ip->new ip localtion

3、next->finish。如图暂时不选择器件,可以在配置好ip后添加器件

4、如图

5、创建AXI接口的 IP,为什么不选上面的三个呢,因为上面的几个是对我们已有的ip进行操作,而最下面是创建IP选项。

6、修改工程命,因为我这里的ip和我的呼吸灯工程有关,因此命名bre_led。点击next

7、AXI 有三种接口,由于我们这里的数据量比较小,因此我们选择AXI_lite接口。由于我们的要创建的工程是PS端控制PL端的呼吸灯工程,因此将PL侧的这个创建的IP定义为从机:slave。AXI数据位宽为32位,最少四个AXI接口数据寄存器。

8、next->默认点击确定。

9、右键自定义IP后点击编辑IP,进入编辑ip的界面,这个界面可以添加PL端控制led呼吸灯的代码。

10、添加呼吸灯的代码(.v)如下图将我们的代码复制到如下目录,然后导入进编辑ip项目的工程里面。

module breath_led(
    input          sys_clk        , //系统时钟 50MHz
    input          sys_rst_n      , //系统复位,低电平有效
	input          sw_ctrl        , //呼吸灯开关控制信号 1:亮 0:灭
    input          set_en         , //设置呼吸灯频率设置使能信号
    input   [9:0]  set_freq_step  , //设置呼吸灯频率变化步长
    
    output         led              //LED灯
);

//parameter define
parameter  START_FREQ_STEP = 10'd1; //设置频率步长初始值
parameter CNT_2US_MAX = 7'd100;    
parameter CNT_2MS_MAX = 10'd1000; 
parameter CNT_2S_MAX  = 10'd1000; 

//reg define
reg [6:0] cnt_2us; 
reg [9:0] cnt_2ms;   
reg [9:0] cnt_2s;     
reg       inc_dec_flag; //亮度递增/递减 0:递增 1:递减
reg [9:0] freq_step   ; //呼吸灯频率间隔步长
reg       led_t       ;

//*****************************************************
//**                  main code
//*****************************************************
assign led = led_t & sw_ctrl;

//设置频率间隔,频率步长值在1-10之间
always @(posedge sys_clk)
    if(!sys_rst_n)
        freq_step <= START_FREQ_STEP;
    else if(set_en) begin
        if(set_freq_step == 0)
            freq_step <= 10'd1;
        else if(set_freq_step >= 10'd1000)
            freq_step <= 10'd10;
        else    
            freq_step <= set_freq_step;
    end        

//cnt_2us:计数2us
always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cnt_2us <= 7'b0;
    else if(cnt_2us == (CNT_2US_MAX - 7'b1 ))
        cnt_2us <= 7'b0;
    else
        cnt_2us <= cnt_2us + 7'b1;
end

//cnt_2ms:计数2ms
always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cnt_2ms <= 10'b0;
    else if(cnt_2ms == (CNT_2MS_MAX - 10'b1) && cnt_2us == (CNT_2US_MAX - 7'b1))
        cnt_2ms <= 10'b0;
    else if(cnt_2us == CNT_2US_MAX - 7'b1)
        cnt_2ms <= cnt_2ms + 10'b1;
    else
        cnt_2ms <= cnt_2ms;
end

//cnt_2s:计数2s
always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        cnt_2s <= 10'b0;
    else if(cnt_2s >= (CNT_2S_MAX - 10'b1) && cnt_2ms == (CNT_2MS_MAX - 10'b1) && cnt_2us == (CNT_2US_MAX - 7'b1))
        cnt_2s <= 10'b0;
    else if(cnt_2ms == (CNT_2MS_MAX - 10'b1) && cnt_2us == (CNT_2US_MAX - 7'b1))
        cnt_2s <= cnt_2s + freq_step;
    else
        cnt_2s <= cnt_2s;         
end

//inc_dec_flag为低电平,led灯由暗变亮,inc_dec_flag为高电平,led灯由亮变暗
always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        inc_dec_flag <= 1'b0;
    else if(cnt_2s >= (CNT_2S_MAX - 10'b1) && cnt_2ms ==( CNT_2MS_MAX - 10'b1) && cnt_2us == (CNT_2US_MAX - 7'b1))
        inc_dec_flag <= ~inc_dec_flag;
    else
        inc_dec_flag <= inc_dec_flag;
end

//led:输出信号连接到外部的led灯
always@(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        led_t <= 1'b0;
    else if((inc_dec_flag == 1'b1 && cnt_2ms >= cnt_2s) || (inc_dec_flag == 1'b0 && cnt_2ms <= cnt_2s))
        led_t <= 1'b1;
    else
        led_t<= 1'b0;
end

endmodule

11、修改代码

在低层添加我们的用户逻辑,即添加我们呼吸灯例化的工程,当然因为这里使用到了一个输出端口,因此我门需要逐级添加led端口。以下是需要修改的地方。

	// Add user logic here
	breath_led(
    .sys_clk        (S_AXI_ACLK), //系统时钟 50MHz
    .sys_rst_n      (S_AXI_ARESETN), //系统复位,低电平有效
	.sw_ctrl        (slv_reg0[0]), //呼吸灯开关控制信号 1:亮 0:灭
    .set_en         (slv_reg1[31]), //设置呼吸灯频率设置使能信号
    .set_freq_step  (slv_reg1[9:0]), //设置呼吸灯频率变化步长
	
    .led            (led)  //LED灯
);
	// User logic ends

12、综合一下看看有没有语法错误

13、点击这里的merge........来刷新配置

14、点击cus后点击上面的提示信息刷新配置。

15、点击提示信息

16、添加zynq型号

17、修改我们添加的参数,记住这里的long类型的务必要将默认值换成相应的类型。比如我这里默认值为100,最下面一行。

18、点击Re-package ip,建立我们自定义的IP。

19、新建一个空工程

20、添加我们自定义的ip核进入工程,设置->IP->仓库->➕->自定义ip管理目录->ip_repo->选中IP->点击ok

可以看见已经添加进来了。

21、创建block design,并添加ps 侧的ip和我们刚刚创建的PS侧的呼吸灯的ip。按照以前的修改zynq ip的配置。

22、修改bre_led ip的配置。但这里留给外部的可修改的参数也就一个(步长)因此在配置参数的时候我们已经设置默认值了(100),所以我们不修改。

23、依次点击两个提示信息默认点击ok即可。然后刷新。到这里我们就完成我们block的设计了。接下来就是在SDK里面写代码操作寄存器即可。

24、右键bd文件生成ip设计文件。然后生成verilog顶层文件。都默认点击ok即可。

25、点击综合一下,然后配置引脚。保存生成约束文件。

26、一定要生成bit流

27、然后就是导出sdk设计文件,一定要勾选我们刚刚生成的bit流因为,这里用到了PL端的led。

28、打开SDK

29、新建项目->新建源文件(main.c)->复制以下代码进源文件。注意:这里的bre_led头文件和几个定义要和你生成的示例文件保持一致。因为如果每个人命名不一样生成的文件也不一样。导致报错。这几个定义和我们需要的函数都在如下第二张图片里面。注意:这几个文件是sdk根据你项目命名自动生成的。如果项目命名不一样里面的头文件和一些宏定义也是有去别的。根据自己的头文件和示例文件修改一下即可。

#include "stdio.h"
#include "xparameters.h"
#include "bre_led.h"
#include "xil_io.h"
#include "sleep.h"

#define BRE_IP_BASEADDR	XPAR_BRE_LED_0_S0_AXI_BASEADDR
#define BRE_IP_REG0		BRE_LED_S0_AXI_SLV_REG0_OFFSET
#define BRE_IP_REG1		BRE_LED_S0_AXI_SLV_REG1_OFFSET

int main()
{
	int freq_change=0;
	printf("custom ip test start\n");
	while(1)
	{
		if(freq_change==0)
		{
			BRE_LED_mWriteReg(BRE_IP_BASEADDR,BRE_IP_REG1,0x800000ef);
			freq_change=1;
		}
		else
		{
			BRE_LED_mWriteReg(BRE_IP_BASEADDR,BRE_IP_REG1,0x8000002f);
			freq_change=0;
		}
		print("led open\n");
		BRE_LED_mWriteReg(BRE_IP_BASEADDR,BRE_IP_REG0,1);
		sleep(6);

		print("led close\n");
		BRE_LED_mWriteReg(BRE_IP_BASEADDR,BRE_IP_REG0,0);
		sleep(2);
	}

	return 0;
}

30、连接串口(绿色➕)、右键项目->run as->run config......。因为这里用到了PL端外设因此我们需要配置bit文件。如果不需要用到pl端外设,就直接luanch on hardware 下载ps端程序即可。

31、双击GDB->勾选system reast 和program fpga 。勾选这两个可以帮助我们下载fpga pl侧程序。就不需要我们在vivade单独下载了。

32、点击run下载程序,观察结果。我这里是正确的。就不放视频演示了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值