文章目录
前言
无,仅作记录,不具有参考价值。
1.创建自定义IP核工程





这里的名字可以和图中不同 ,这里取的是breath_led_ip_test(因为之前已经有个我自己建立的breath_led_ipIP核,这里只是为了展示IP核的建立过程,verilog代码还是使用的是breath_led_ip_test的名字,vitis代码中用的是breath_led_ip的名字,后面会有一个使用breath_led_ipIP核的工程打包zip给你们下载,这里要关注的是建立过程)



在D:\ldy\VivadoIPs\custom_ip\ip_repo\breath_led_ip_test_1.0\hdl中添加breath_led.v文件,并导入到工程中



修改前的breath_led.v:
c
module breath_led(
input sys_clk,
input sys_rst_n,
output reg led
);
parameter CNT_2US_MAX = 100;
reg [6:0] cnt_2us;
reg [9:0] cnt_2ms;
reg [9:0] cnt_2s;
reg led_flag;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_2us <= 0;
else if(cnt_2us < CNT_2US_MAX - 1)
cnt_2us <= cnt_2us + 1;
else
cnt_2us <= 0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_2ms <= 0;
else if(cnt_2us == CNT_2US_MAX - 1 && cnt_2ms < 1000 - 1)
cnt_2ms <= cnt_2ms + 1;
else if(cnt_2us == CNT_2US_MAX - 1 && cnt_2ms == 1000 - 1)
cnt_2ms <= 0;
else
cnt_2ms <= cnt_2ms;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_2s <= 0;
else if(cnt_2us == CNT_2US_MAX - 1 && cnt_2ms == 1000 - 1 && cnt_2s < 1000 - 1)
cnt_2s <= cnt_2s + 1;
else if(cnt_2us == CNT_2US_MAX - 1 && cnt_2ms == 1000 - 1 && cnt_2s == 1000 - 1)
cnt_2s <= 0;
else
cnt_2s <= cnt_2s;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_flag <= 1;
else if(cnt_2us == CNT_2US_MAX - 1 && cnt_2ms == 1000 - 1 && cnt_2s == 1000 - 1)
led_flag <= !led_flag;
else
led_flag <= led_flag;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 0;
else if(led_flag) begin
if(cnt_2ms <= cnt_2s)
led <= 1;
else
led <= 0;
end
else begin
if(cnt_2ms >= cnt_2s)
led <= 1;
else
led <= 0;
end
end
// ila_0 u_lia_0 (
// .clk(sys_clk), // input wire clk
// .probe0(sys_rst_n), // input wire [0:0] probe0
// .probe1(led), // input wire [0:0] probe1
// .probe2(cnt_2us), // input wire [6:0] probe2
// .probe3(cnt_2ms), // input wire [9:0] probe3
// .probe4(cnt_2s), // input wire [9:0] probe4
// .probe5(led_flag) // input wire [0:0] probe5
// );
endmodule
然后开始修改breath_led.v:








在这里添加要引出的端口






添加参数的过程就是一层一层的向外扩展
修改后的breath_led.v:
c
module breath_led(
input sys_clk,
input sys_rst_n,
input sw_ctrl, //呼吸灯开关控制 1:打开呼吸灯 0:关闭呼吸灯
input set_freq_en, //呼吸灯频率使能信号
input [9:0] set_freq_step, //呼吸灯频率步进挡位1-1000
output led
);
parameter START_FREQ_STEP = 10'd100;
reg [9:0] freq_step = 100;
reg [9:0] cnt_2us;
reg [9:0] cnt_2ms;
reg [9:0] cnt_2s;
reg led_flag; //亮度递增/递减的标志 0:递增 1:递减
reg led_t;
assign led = led_t & sw_ctrl;
//寄存set_freq_step的值,并将范围限定在1-1000
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
freq_step = START_FREQ_STEP;
else if(set_freq_en) begin
if(set_freq_step == 10'd0)
freq_step <= 10'd1;
else if(set_freq_step > 1000)
freq_step <= 10'd1000;
else
freq_step <= set_freq_step;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_2us <= 0;
else if(cnt_2us < freq_step - 1)
cnt_2us <= cnt_2us + 1;
else
cnt_2us <= 0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_2ms <= 0;
else if(cnt_2us == freq_step - 1 && cnt_2ms < 1000 - 1)
cnt_2ms <= cnt_2ms + 1;
else if(cnt_2us == freq_step - 1 && cnt_2ms == 1000 - 1)
cnt_2ms <= 0;
else
cnt_2ms <= cnt_2ms;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_2s <= 0;
else if(cnt_2us == freq_step - 1 && cnt_2ms == 1000 - 1 && cnt_2s < 1000 - 1)
cnt_2s <= cnt_2s + 1;
else if(cnt_2us == freq_step - 1 && cnt_2ms == 1000 - 1 && cnt_2s == 1000 - 1)
cnt_2s <= 0;
else
cnt_2s <= cnt_2s;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_flag <= 1;
else if(cnt_2us == freq_step - 1 && cnt_2ms == 1000 - 1 && cnt_2s == 1000 - 1)
led_flag <= !led_flag;
else
led_flag <= led_flag;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led_t <= 0;
else if(led_flag) begin
if(cnt_2ms <= cnt_2s)
led_t <= 1;
else
led_t <= 0;
end
else begin
if(cnt_2ms >= cnt_2s)
led_t <= 1;
else
led_t <= 0;
end
end
// ila_0 u_lia_0 (
// .clk(sys_clk), // input wire clk
// .probe0(sys_rst_n), // input wire [0:0] probe0
// .probe1(led), // input wire [0:0] probe1
// .probe2(cnt_2us), // input wire [6:0] probe2
// .probe3(cnt_2ms), // input wire [9:0] probe3
// .probe4(cnt_2s), // input wire [9:0] probe4
// .probe5(led_flag) // input wire [0:0] probe5
// );
endmodule

修改完毕之后开始综合








按下之后vivado工程会自动关闭
接下来是最重要的一步!!!
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
在D:\ldy\VivadoIPs\custom_ip\ip_repo\breath_led_ip_1.0\drivers\breath_led_ip_v1_0\src(路径仅供参考)中替换Makefile若不替换,编译时会报错且很难补救,一定一定要确保更换确实完成了之后再进行下面步骤。
替换后的Makefile内部代码为:
c
DRIVER_LIB_VERSION = 1.0
COMPILER=
ARCHIVER=
CP=cp
COMPILER_FLAGS=
EXTRA_COMPILER_FLAGS=
LIB=libxil.a
CC_FLAGS = $(COMPILER_FLAGS)
ECC_FLAGS = $(EXTRA_COMPILER_FLAGS)
RELEASEDIR=../../../lib/
INCLUDEDIR=../../../include/
INCLUDES=-I./. -I$(INCLUDEDIR)
SRCFILES:=$(wildcard *.c)
OBJECTS = $(addprefix $(RELEASEDIR), $(addsuffix .o, $(basename $(wildcard *.c))))
libs: $(OBJECTS)
DEPFILES := $(SRCFILES:%.c=$(RELEASEDIR)%.d)
include $(wildcard $(DEPFILES))
include $(wildcard ../../../../dep.mk)
$(RELEASEDIR)%.o: %.c
${COMPILER} $(CC_FLAGS) $(ECC_FLAGS) $(INCLUDES) $(DEPENDENCY_FLAGS) $< -o $@
.PHONY: include
include: $(addprefix $(INCLUDEDIR),$(wildcard *.h))
$(INCLUDEDIR)%.h: %.h
$(CP) $< $@
clean:
rm -rf ${OBJECTS}
rm -rf $(DEPFILES)
2.创建Vivado工程

创建工程,略
添加自定义的IP核,若不添加,block design中会找不到


选择ip_repo

选择刚刚或者之前创建的IP核
加入并配置zynq块(DDR3,uart,bank电压;过程略)

搜索并加入IP核



选中led引脚并引出

改名


创建pin.xdc文件

在pin.xdc中添加以下代码:
c
#核心板
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports pl_led]



3.Vitis软件设计
打开vitis并创建工程
过程略

在breath_led_test.h中可以找到操控寄存器函数

在breath_led_test_selftest.c中有待会会用到的头文件,选择这些头文件并复制

新建breath_led_test_ip_user文件夹,并创建左下红框处的文件






在main.c,main.h,breath_led_ip_user.c,breath_led_ip_user.h中添加以下代码:
main.c:
c
#include "main.h"
#include "breath_led_ip_user.h"
int main(void)
{
int freq_flag = 0; //定义频率的标志位,用户循环切换呼吸灯的频率
int led_state;
u32 data_in;
xil_printf("* LED User IP Test\n\r");
breath_led_set_freq(5);
while(1)
{
if(freq_flag == 0)
{
breath_led_set_freq(50);
freq_flag = 1;
}
else
{
breath_led_set_freq(500);
freq_flag = 0;
}
//获取LED当前开关状态
led_state = breath_led_readControlSw();
if(led_state == 0)
{
//打开呼吸灯开关
breath_led_control(1);
xil_printf("* Breath LED ON *\n\r");
sleep(8);
}
else
{
//关闭呼吸灯开关
breath_led_control(0);
xil_printf("* Breath LED OFF *\n\r");
sleep(1);
}
data_in = breath_led_readReg2();
xil_printf("data_in = %d\n\r", data_in);
}
}
main.h:
c
#ifndef __MAIN_H__
#define __MAIN_H__
#include "breath_led_ip.h"
#include "xparameters.h"
#include "stdio.h"
#include "xil_io.h"
#include "sleep.h"
#endif
breath_led_set_freq.c:
c
#include "breath_led_ip_user.h"
void breath_led_control(u32 led_state)
{
u32 reg0_state;
reg0_state = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG0);
if(led_state)
{
BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG0, reg0_state | (u32)0x1);
}
else
{
BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG0, reg0_state & ~((u32)0x1));
}
}
void breath_led_freq_set_EnableOrDisable(u32 sw)
{
u32 reg1_state;
reg1_state = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG1);
BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG1, (reg1_state & ~(1 << 31)) | (u32)(sw == 1));
}
void breath_led_set_freq(u32 freq)
{
u32 reg1_state;
reg1_state = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG1);
BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG1, (reg1_state & ~(0x3ff)) | freq);
}
u32 breath_led_readControlSw(void)
{
u32 led_state;
led_state = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG0) & 0x1;
return led_state;
}
u32 breath_led_readReg2(void)
{
u32 data_in;
data_in = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG2);
return data_in;
}
breath_led_set_freq.h:
c
#ifndef __BREATH_LED_IP_USER__
#define __BREATH_LED_IP_USER__
#include "main.h"
#define LED_IP_BASEADDR XPAR_BREATH_LED_IP_0_S0_AXI_BASEADDR //LED IP基地址
#define LED_IP_REG0 BREATH_LED_IP_S0_AXI_SLV_REG0_OFFSET //LED IP寄存器0的偏移地址
#define LED_IP_REG1 BREATH_LED_IP_S0_AXI_SLV_REG1_OFFSET //LED IP寄存器1的偏移地址
#define LED_IP_REG2 BREATH_LED_IP_S0_AXI_SLV_REG2_OFFSET //LED IP寄存器2的偏移地址
void breath_led_control(u32 led_state);
void breath_led_freq_set_EnableOrDisable(u32 sw);
void breath_led_set_freq(u32 freq);
u32 breath_led_readControlSw(void);
u32 breath_led_readReg2(void);
#endif
4.下载验证
略。
工程文件分享:
使用时记得将ip_repo里面的IP核添加进vivado中