ZYNQ防火墙开发8-PS-PL通信-AXI-RAM

AXI协议

AXI4 、 AXI4-Lite 、AXI4-Stream接口

​ AXI 作为 ARM AMBA 微控制器总线的一部分,第一次出现在AMBA 3.0中。后面AMBA 4.0发布,AXI4出现了。

AXI 4总线和别的总线一样,都用来传输bits信息(包含了数据或者地址)。AXI4总线有三种类型,分别是AXI4、AXI4-Lite、AXI4-Stream。

​ AXI4 是一种高性能memory-mapped总线,AXI4-Lite是一只简单的、低通量的memory-mapped 总线,而 AXI4-Stream 可以传输高速数据流。从字面意思去理解,AXI4-Lite是AXI4的轻量版。这里保留了memory-mapped的写法,主要是为了与AXI4-Stream区分开。

memory-mapped 可以这样去理解,假设有master A , 和 slave B, A与B通过AXI4或者AXI4-Lite连接通讯,A可以把B这个外设看作A上的某个地址。当A向B传输数据时,就等同于A向这个地址传输数据。

​ AXI4-Stream与AXI4、AXI4-Lite不同, 它不需要地址通道。

AXI4 和 AXI4-Lite接口包含5个不同的通道:两个读通道和三个写通道。

两个读通道:读地址通道(read address channel)、读数据通道(read data channel);

三个写通道:写地址通道(write address channel)、写数据通道(write data channel)、写响应通道(write response channel);

接口协议

​ 读通道和写通道是分开的,因此可以完成数据的双向传输。此外AXI4能够实现burst传输,换句说就是,可以在一个地址后传输多个数据,最多可以达256 字节。AXI4-Lite不支持burst传输。

​ AXI4-Stream 只有一个通道,不需要地址,可以burst 传输无限的数据。

常见的辅助IP

AXI Interconnect IP 和AXI SmartConnect IP :

​ AXI Interconnect IP允许将任意组合的AXI主设备和从设备连接到它,这些设备在数据宽度、时钟域和AXI子协议(AXI4、AXI3或AXI4-Lite)方面可能互不相同。当任何连接的主设备或从设备的接口特性与互连内部的交叉开关不同时,将自动推断并连接适当的基础架构 IP在互连内执行必要的转换。

Vivado中的smartConnect和InterConnect有什么区别?

1
2
Both IP have the same functionnalities.
AXI SmartConnect is the successor to AXI Interconnect, it uses a different IP technology. You should use it for any new design.

UG994

1
2
3
The AMD LogiCORE™ IP AXI InterConnect and SmartConnect cores both connect one or more AXI memory-mapped master devices to one or more memory-mapped slave devices; however, the SmartConnect is more tightly integrated into the Vivado design environment to automatically configure and adapt to connected AXI master and slave IP with minimal user intervention. The AXI Interconnect can be used in all memory-mapped designs.

There are certain cases for high bandwidth application where using a SmartConnect provides better optimization. The SmartConnect IP delivers the maximum system throughput at low latency by synthesizing a low area custom interconnect that is optimized for important interfaces.

SmartConnect比InterConnect的性能更好,延时更低,带宽更大。

AXI FIFOs :

​ 缓存数据,或者跨时钟域时有用。

AXI Direct Memory Access (DMA) engines

​ 当我们有一个AXI4-stream接口的IP想与AXI4接口的IP相连时,可以通过AXI DMA完成转换。

ZYNQ上的AXI接口

7be432f0-fb2e-11ec-ba43-dac502259ad0.jpg

图片源自 zynq 7 processing system ip

zynq的ps上共留了9个AXI接口,其中两个GP AXI master、两个GP AXI slave、四个HP AXI slave、以及一个ACP AXI slave。

这些接口都是AXI3类型的,但使用AXI4-Lite、AXI4 的IP仍然可以与这些接口通讯,因为在实际使用中,软件会使用AXI Interconnect ip帮助我们完成接口的转换。

主要参考

[1] ug1037-vivado-axi-reference-guide

[2] ug585-Zynq-7000-TRM

AXI LITE

AXI4和AXI3的主要区别

主要区别如下:

  • AXI4支持更长的突发传输(AxLEN从4bit扩展为8bit,相应的突发长度最大可以到256);
  • 增加了QoS信号,以提供服务质量。减少延迟,便于仲裁;
  • 多Slave Region(即AxRegion信号);
  • 移除了WID信号,因此不支持写数据interleave;
  • AxLOCK从2bit变为1bit,不再支持Lock Transfer;
  • 写响应必须在写数据和写地址全部给了以后才允许返回(之前可以在给了写数据以后就返回写响应);
  • 将Cacheable改为Modifyable

在这里插入图片描述

Write

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
            ___     ___     ___     ___     ___    
clk ___/ \___/ \___/ \___/ \___/ \___
_______
awid XXXX_ID____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
awaddr XXXX_ADDR__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
awlen XXXX_00____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
awsize XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
awburst XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
awprot XXXX_PROT__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
awvalid ___/ \_______________________________
___________ _______________________
awready \_______/
_______________
wdata XXXX_DATA__________XXXXXXXXXXXXXXXXXXXXXXXX
_______________
wstrb XXXX_STRB__________XXXXXXXXXXXXXXXXXXXXXXXX
_______________
wvalid ___/ \_______________________
_______
wready ___________/ \_______________________
_______
bid XXXXXXXXXXXXXXXXXXXXXXXXXXXX_ID____XXXXXXXX
_______
bresp XXXXXXXXXXXXXXXXXXXXXXXXXXXX_RESP__XXXXXXXX
_______
bvalid ___________________________/ \_______
___________________________________________
bready

Read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
            ___     ___     ___     ___     ___    
clk ___/ \___/ \___/ \___/ \___/ \___
_______
arid XXXX_ID____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
araddr XXXX_ADDR__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
arlen XXXX_00____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
arsize XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
arburst XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
arprot XXXX_PROT__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
_______
arvalid ___/ \_______________________________
___________________________________________
arready
_______
rid XXXXXXXXXXXXXXXXXXXXXXXXXXXX_ID____XXXXXXXX
_______
rdata XXXXXXXXXXXXXXXXXXXXXXXXXXXX_DATA__XXXXXXXX
_______
rresp XXXXXXXXXXXXXXXXXXXXXXXXXXXX_RESP__XXXXXXXX
_______
rvalid ___________________________/ \_______
___________________________________________
rready

1 创建Vivado IP工程

1 ) 具体步骤 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

img

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”,最后点击“Next” 备注,所有的路径均不能出现中文名称

img

3) 第四步Add Sources 选项直接留空,NEXT

4)第五步Add Constraints 选项直接留空,NEXT

5)选择芯片型号 我们板子上用的芯片是XC7Z010 ,并在列表栏中选择对应的封装型号,完整型号是XC7Z010CLG400-1 如下所示,选中后点NEXT

img

6)确认所选信息 点击“Finish”,完成vivado的工程创建

img

7)创建verilog源文件

8)创建文件并命名为axi_ram.v

9)提示添加约束接口留空即可。

10)编辑axi_ram.v,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
module axi_ram #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Extra pipeline register on output
parameter PIPELINE_OUTPUT = 0
)
(
input wire clk,
input wire rst,

input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire s_axi_bvalid,
input wire s_axi_bready,
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire s_axi_rvalid,
input wire s_axi_rready
);

parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;

// bus width assertions
initial begin
if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end

if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
end

localparam [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_BURST = 1'd1;

reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;

localparam [1:0]
WRITE_STATE_IDLE = 2'd0,
WRITE_STATE_BURST = 2'd1,
WRITE_STATE_RESP = 2'd2;

reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next;

reg mem_wr_en;
reg mem_rd_en;

reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next;
reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next;
reg [7:0] read_count_reg = 8'd0, read_count_next;
reg [2:0] read_size_reg = 3'd0, read_size_next;
reg [1:0] read_burst_reg = 2'd0, read_burst_next;
reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next;
reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next;
reg [7:0] write_count_reg = 8'd0, write_count_next;
reg [2:0] write_size_reg = 3'd0, write_size_next;
reg [1:0] write_burst_reg = 2'd0, write_burst_next;

reg s_axi_awready_reg = 1'b0, s_axi_awready_next;
reg s_axi_wready_reg = 1'b0, s_axi_wready_next;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next;
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
reg s_axi_arready_reg = 1'b0, s_axi_arready_next;
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next;
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next;
reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next;
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}};
reg s_axi_rlast_pipe_reg = 1'b0;
reg s_axi_rvalid_pipe_reg = 1'b0;

// (* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];

wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);

assign s_axi_awready = s_axi_awready_reg;
assign s_axi_wready = s_axi_wready_reg;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = 2'b00;
assign s_axi_bvalid = s_axi_bvalid_reg;
assign s_axi_arready = s_axi_arready_reg;
assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : s_axi_rid_reg;
assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : s_axi_rdata_reg;
assign s_axi_rresp = 2'b00;
assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg;
assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg;

integer i, j;

initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**VALID_ADDR_WIDTH; i = i + 2**(VALID_ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(VALID_ADDR_WIDTH/2); j = j + 1) begin
mem[j] = 0;
end
end
end

always @* begin
write_state_next = WRITE_STATE_IDLE;

mem_wr_en = 1'b0;

write_id_next = write_id_reg;
write_addr_next = write_addr_reg;
write_count_next = write_count_reg;
write_size_next = write_size_reg;
write_burst_next = write_burst_reg;

s_axi_awready_next = 1'b0;
s_axi_wready_next = 1'b0;
s_axi_bid_next = s_axi_bid_reg;
s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready;

case (write_state_reg)
WRITE_STATE_IDLE: begin
s_axi_awready_next = 1'b1;

if (s_axi_awready && s_axi_awvalid) begin
write_id_next = s_axi_awid;
write_addr_next = s_axi_awaddr;
write_count_next = s_axi_awlen;
write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH);
write_burst_next = s_axi_awburst;

s_axi_awready_next = 1'b0;
s_axi_wready_next = 1'b1;
write_state_next = WRITE_STATE_BURST;
end else begin
write_state_next = WRITE_STATE_IDLE;
end
end
WRITE_STATE_BURST: begin
s_axi_wready_next = 1'b1;

if (s_axi_wready && s_axi_wvalid) begin
mem_wr_en = 1'b1;
if (write_burst_reg != 2'b00) begin
write_addr_next = write_addr_reg + (1 << write_size_reg);
end
write_count_next = write_count_reg - 1;
if (write_count_reg > 0) begin
write_state_next = WRITE_STATE_BURST;
end else begin
s_axi_wready_next = 1'b0;
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
write_state_next = WRITE_STATE_IDLE;
end else begin
write_state_next = WRITE_STATE_RESP;
end
end
end else begin
write_state_next = WRITE_STATE_BURST;
end
end
WRITE_STATE_RESP: begin
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
write_state_next = WRITE_STATE_IDLE;
end else begin
write_state_next = WRITE_STATE_RESP;
end
end
endcase
end

always @(posedge clk) begin
write_state_reg <= write_state_next;

write_id_reg <= write_id_next;
write_addr_reg <= write_addr_next;
write_count_reg <= write_count_next;
write_size_reg <= write_size_next;
write_burst_reg <= write_burst_next;

s_axi_awready_reg <= s_axi_awready_next;
s_axi_wready_reg <= s_axi_wready_next;
s_axi_bid_reg <= s_axi_bid_next;
s_axi_bvalid_reg <= s_axi_bvalid_next;

for (i = 0; i < WORD_WIDTH; i = i + 1) begin
if (mem_wr_en & s_axi_wstrb[i]) begin
mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= s_axi_wdata[WORD_SIZE*i +: WORD_SIZE];
end
end

if (rst) begin
write_state_reg <= WRITE_STATE_IDLE;

s_axi_awready_reg <= 1'b0;
s_axi_wready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
end
end

always @* begin
read_state_next = READ_STATE_IDLE;

mem_rd_en = 1'b0;

s_axi_rid_next = s_axi_rid_reg;
s_axi_rlast_next = s_axi_rlast_reg;
s_axi_rvalid_next = s_axi_rvalid_reg && !(s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg));

read_id_next = read_id_reg;
read_addr_next = read_addr_reg;
read_count_next = read_count_reg;
read_size_next = read_size_reg;
read_burst_next = read_burst_reg;

s_axi_arready_next = 1'b0;

case (read_state_reg)
READ_STATE_IDLE: begin
s_axi_arready_next = 1'b1;

if (s_axi_arready && s_axi_arvalid) begin
read_id_next = s_axi_arid;
read_addr_next = s_axi_araddr;
read_count_next = s_axi_arlen;
read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH);
read_burst_next = s_axi_arburst;

s_axi_arready_next = 1'b0;
read_state_next = READ_STATE_BURST;
end else begin
read_state_next = READ_STATE_IDLE;
end
end
READ_STATE_BURST: begin
if (s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg) || !s_axi_rvalid_reg) begin
mem_rd_en = 1'b1;
s_axi_rvalid_next = 1'b1;
s_axi_rid_next = read_id_reg;
s_axi_rlast_next = read_count_reg == 0;
if (read_burst_reg != 2'b00) begin
read_addr_next = read_addr_reg + (1 << read_size_reg);
end
read_count_next = read_count_reg - 1;
if (read_count_reg > 0) begin
read_state_next = READ_STATE_BURST;
end else begin
s_axi_arready_next = 1'b1;
read_state_next = READ_STATE_IDLE;
end
end else begin
read_state_next = READ_STATE_BURST;
end
end
endcase
end

always @(posedge clk) begin
read_state_reg <= read_state_next;

read_id_reg <= read_id_next;
read_addr_reg <= read_addr_next;
read_count_reg <= read_count_next;
read_size_reg <= read_size_next;
read_burst_reg <= read_burst_next;

s_axi_arready_reg <= s_axi_arready_next;
s_axi_rid_reg <= s_axi_rid_next;
s_axi_rlast_reg <= s_axi_rlast_next;
s_axi_rvalid_reg <= s_axi_rvalid_next;

if (mem_rd_en) begin
s_axi_rdata_reg <= mem[read_addr_valid];
end

if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rid_pipe_reg <= s_axi_rid_reg;
s_axi_rdata_pipe_reg <= s_axi_rdata_reg;
s_axi_rlast_pipe_reg <= s_axi_rlast_reg;
s_axi_rvalid_pipe_reg <= s_axi_rvalid_reg;
end

if (rst) begin
read_state_reg <= READ_STATE_IDLE;

s_axi_arready_reg <= 1'b0;
s_axi_rvalid_reg <= 1'b0;
s_axi_rvalid_pipe_reg <= 1'b0;
end
end

endmodule

11) 点击Create and package New IP创建我们自己ip

12) 直接下一步

13)选择打包当前工程

14)默认下一步即可

14)点击finish

15)配置IP核参数,保持默认即可。

16) 直接到最后一步 package IP。

17)显示打包完成,到此创建完成我们自己的axi ram ip核。

2 创建Vivado BLOCK工程

1 ) 具体步骤 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

img

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”,最后点击“Next” 备注,所有的路径均不能出现中文名称

img

3) 第四步Add Sources 选项直接留空,NEXT

4)第五步Add Constraints 选项直接留空,NEXT

5)选择芯片型号 我们板子上用的芯片是XC7Z010 ,并在列表栏中选择对应的封装型号,完整型号是XC7Z010CLG400-1 如下所示,选中后点NEXT

img

6)确认所选信息 点击“Finish”,完成vivado的工程创建

img

7)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

img

8)在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

img

9)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

img

10)添加串口UART 1引脚为MIO 24-24, 串口在调试时用到。

11)此项目没有用到DDR,可以取消ENABLE

12)加入上面我们自己创建的axi ram ip核到当前工程,选择Tool下的Settings.

13)添加IP工程路径到Repository。

14)提示添加路径下包含的IP核。

15)完成IP的添加

16)在BLOCK设计中添加我们自己的IP核。

17)点击自动连接

17)选择a_axi后确认。

18)自动连接完成后的框图

18)由于我们的IP核的rst是高有效,所以重新连接rst引脚。

19)到此完成了我们的BLOCK设计,点击生成顶层工程

20) 选择自动更新

3.生成bit文件

21 )按下Generate Bitstream 完成综合以及生成bit文件

22) 生成bit流后,选择导出Hardware

4.SDK程序编写

1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

img

2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

img

系统将自动打开SDK开发环境

img

3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。

img

4)在新建工程名中输入自己的工程名称,点击NEXT

img

5)选择空工程,点击完成FINISH

img

6)编写测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include <xil_io.h>
#include <sleep.h>

#define PhyRead(addr) Xil_In32(addr)
#define PhyWrite(addr, value) Xil_Out32(addr, value)
#define AXILITE_BASEADDR XPAR_AXI_RAM_0_BASEADDR

int main()
{
init_platform();

print("Hello World\n\r");
for(int i=0;i<20;i++)
{
sleep(1);
printf("i is %d\n\r",i);
}
int reg0in = 320;
int reg0out = 0;

//*(volatile u32 *) XPAR_AXI_RAM_0_BASEADDR = reg0in;
//reg0out = *(volatile u32 *) XPAR_AXI_RAM_0_BASEADDR;

PhyWrite(AXILITE_BASEADDR, reg0in);
reg0out = PhyRead(AXILITE_BASEADDR);


printf("reg0out is %d\r\n",reg0out);

cleanup_platform();
return 0;
}

5.下载到板子上进行验证

选中工程中的硬件平台,并点击右键→Program FPGA,在弹出的对话框中选择默认,点击“program”,完成FPGA PL部分的Program工作

img

img

2)选中我们生成的GPIO工程 展开绿色箭头(RUN)右边的图标,选择Run As→1 Launch on Hardware(System Debugger)

img

6.查看串口打印

显示读写成功

AXI4 、 AXI4-Lite 、AXI4-Stream接口

https://www.elecfans.com/d/1856571.html

FPGA - AXI4_Lite(实现用户端与axi4_lite之间的交互逻辑)_axi4-lite-CSDN博客


ZYNQ防火墙开发8-PS-PL通信-AXI-RAM
http://witbit.cn/视频课程/FIREWALL_GATEWAY/ZYNQ防火墙开发8-PS-PL通信-AXI-RAM.html
作者
朝彻
发布于
2025年2月13日
许可协议