1、由于一直在PL侧做算法,外设接口接触的比较少,目前只做了sfp的UDP传输,但是由于课题的原因需要将一部分PL计算数据存储,而RAM存储空间比较小,因此本次给大带来了ZCU106的PL侧读写ddr4的教程,本教程是全网ZCU106 DDR4 PL侧读写的唯一一篇教程。下面是4个参考资料:
2、本教程采用的是xilinx的ddr4的IP核的AXI4接口开发的,因此需要先了解AXI4总线协议。
①AXI4接口描述
| 通道 | 信号 | 主/从 | 信号描述 |
|---|---|---|---|
| 全局 信号 | aclk | 主机 | AXI4总线时钟 |
| aresetn | 主机 | AXI4总线复位 | |
| 写通 道地 址与 控制 信号 通道 | M_AXI_WR_awid | 主机 | 写地址ID,用来表示哪个主机写入的数据,一般是一台主机对应一个从机,因此这个可以随便写。 |
| M_AXI_WR_awaddr | 主机 | 写地址,给出一次写突发传输的写地址 | |
| M_AXI_WR_awlen | 主机 | 突发长度,给出突发传输的次数 | |
| M_AXI_WR_awsize | 主机 | 突发大小,给出每次突发传输的字节数 | |
| M_AXI_WR_awburst | 主机 | 突发类型 | |
| M_AXI_WR_awlock | 主机 | 总线锁信号,可提供操作的原子性 | |
| M_AXI_WR_awcache | 主机 | 内存类型,表明一次传输是怎样通过系统 的 | |
| M_AXI_WR_awprot | 主机 | 保护类型,表明一次传输的特权级及安全 等级 | |
| M_AXI_WR_awqos | 主机 | 质量服务QoS | |
| M_AXI_WR_awvalid | 主机 | 有效信号,表明此通道的地址控制信号有 效 | |
| M_AXI_WR_awready | 从机 | 表明“从”可以接收地址和对应的控制信 号 | |
| 写通 道数 据通 道 | M_AXI_WR_wdata | 主机 | 写入的数据 |
| M_AXI_WR_wstrb | 主机 | 写数据有效的字节线,用来表明哪8bits 数据是有效的(例如32位的数据[4个8bit数据],他的wstrb一般是4位宽,一般设置为F,表示全数据位有效) | |
| M_AXI_WR_wlast | 主机 | 表明此次传输是最后一个突发传输 | |
| M_AXI_WR_wvalid | 主机 | 写有效,表明此次写有效 | |
| M_AXI_WR_wready | 从机 | 表明从机可以接收写数据 | |
| 写通 道响 应通 道 | M_AXI_WR_bid | 从机 | 写响应ID |
| M_AXI_WR_bresp | 从机 | 写响应,表明写传输的状态 | |
| M_AXI_WR_bvalid | 从机 | 写响应有效 | |
| M_AXI_WR_bready | 主机 | 表明主机能够接收写响应 | |
| 读通 道地 址与 控制 信号 通道 | M_AXI_RD_arid | 主机 | 读地址ID,与M_AXI_WR_awid类似 |
| M_AXI_RD_araddr | 主机 | 读地址,给出一次写突发传输的读地址 | |
| M_AXI_RD_arlen | 主机 | 突发长度,给出突发传输的次数 | |
| M_AXI_RD_arsize | 主机 | 突发大小,给出每次突发传输的字节数 | |
| M_AXI_RD_arburst | 主机 | 突发类型 | |
| M_AXI_RD_arlock | 主机 | 总线锁信号,可提供操作的原子性 | |
| M_AXI_RD_arcache | 主机 | 内存类型,表明一次传输是怎样通过系统 的 | |
| M_AXI_RD_arprot | 主机 | 保护类型,表明一次传输的特权级及安全 等级 | |
| M_AXI_RD_arqos | 主机 | 质量服务QOS | |
| M_AXI_RD_arvalid | 主机 | 有效信号,表明此通道的地址控制信号有 效 | |
| M_AXI_RD_arready | 从机 | 表明“从”可以接收地址和对应的控制信 号 | |
| 读通 道数 据通 道 | M_AXI_RD_rid | 从机 | 读IDtag |
| M_AXI_RD_rdata | 从机 | 读数据 | |
| M_AXI_RD_rresp | 从机 | 读响应,表明读传输的状态 | |
| M_AXI_RD_rlast | 从机 | 表明读突发的最后一次传输 | |
| M_AXI_RD_rvalid | 从机 | 表明此通道信号有效 | |
| M_AXI_RD_rready | 主机 | 表明主机能够接收读数据和响应信息 |
②写数据:
写空闲:等待触发突发信号。
写通道写地址等待:准备好写地址AWADDR,然后拉高AWVALID。
写通道写地址:从机接受到AWVALID,发出AWREADY。
写数据等待:准备好数据WDATA,拉高WVALID。
写数据循环: 从机接受WVALID, 确认数据WDATA 有效并且接受, 发出WREADY,AXI 是突发传输:循环该操作到接受到WLAST 最后一个数据标志位。
接受写应答:接受到从机发出的BVALID,主机发出BREADY。
写结束:拉低未拉低的信号,进入写空闲。
③读数据:
读空闲:等待触发突发信号。
读通道写地址等待:准备好写地址ARADDR,然后拉高ARVALID。
读通道写地址:从机接受到ARVALID,发出ARREADY。
读数据等待:从机器准备好数据WDATA,从机拉高RVALID。
读数据循环:主机接受RVALID,确认数据RDATA 有效并且接受,发出RREADY 给从机,AXI 是突发传输:循环该操作到接受到RLAST 最后一个数据标志位。
读结束:拉低未拉低的信号,进入读空闲。
④总结:X代表W/R
空闲:等待突发读写信号
写地址等待:主机发出AXADDR,并且AXVALID置1
从机地址握手:从机发出AXREADY
写/读数据等待:主机发出WDATA,并且WVALID置1。/从机发出RDATA,并且RVALID置1。
主/从机数据循环:从机发出WREADY/主机发出RREADY,循环该操作到接受到XLAST 最后一个数据标志位。
接受写应答(写数据才有):接受到从机发出的BVALID,主机发出BREADY。
注:任何时候都是求偶方放出VALID信号,被求偶方放出READY信号
3、实验过程
①试验任务:完成ZCU106板卡PL侧对的ddr4的读写操作
②实验软硬件:ZCU106、Vivado 2019.1
③实验过程:
step1:建立项目:ddr4_test
step2:设置IP核
ddr4 IP:





fifo设置:
wr_fifo:



rd_fifo:除了下面两个设置都一样


③项目结构:


④代码部分:只给出用户生成数据、顶层、xdc文件,剩余文件请联系作者。
`timescale 1ns / 1ps
//
// Company: 东北电力大学
// Engineer: Yang Zheng
//
// Create Date: 2022/07/21 12:46:13
// Design Name:
// Module Name: ddr_data
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ddr_data(input sys_clk, //系统时钟
input sys_rst_n, //系统复位,低电平有效
output reg wr_en, //写使能
output reg [127:0] wr_data, //写数据
output reg rd_en, //读使能
input [127:0] rd_data, //读数据
input rd_fifo_valid,//读出数据时为高电平,由于ddr是512位的,因此我们需要计数4次,即每次读回4条数据
output read_enable); //写完成,开始读
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter COUTER_MAX = 30'd200;//0.2s
//reg define
reg [29:0] count; //写入计数器
reg wr_flag; //写标志
//记录数据
reg [127:0] rd_data_r0 = 128'b0;
reg [127:0] rd_data_r1 = 128'b0;
reg [127:0] rd_data_r2 = 128'b0;
reg [127:0] rd_data_r3 = 128'b0;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
assign read_enable = wr_flag;
reg [2:0] rd_data_count = 3'b0;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
rd_data_count <= 1'b0;
rd_data_r0 <= 128'b0;
rd_data_r1 <= 128'b0;
rd_data_r2 <= 128'b0;
rd_data_r3 <= 128'b0;
end
else if (rd_fifo_valid && rd_data_count == 'd0) begin
rd_data_r0 <= rd_data;
rd_data_count <= rd_data_count + 1'b1;
end
else if (rd_fifo_valid && rd_data_count == 'd1) begin
rd_data_r1 <= rd_data;
rd_data_count <= rd_data_count + 1'b1;
end
else if (rd_fifo_valid && rd_data_count == 'd2) begin
rd_data_r2 <= rd_data;
rd_data_count <= rd_data_count + 1'b1;
end
else if (rd_fifo_valid && rd_data_count == 'd3) begin
rd_data_r3 <= rd_data;
rd_data_count <= 1'b0;
end
end
//0.2s 计数器
always@(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
count <= 30'd0;
end
else begin
if (~rd_en) begin
count <= count+1;
if (count == COUTER_MAX) begin
count <= 30'd0;
end
end
end
end
//生成1 到200 个数据并且写入ddr 中
//这里的 wr_data是输入到ddr的数据,wr_en是使能端口
//这里的 wr_flag是可以ddr存有数据,因此可读标志
always@(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
wr_data <= 127'd0;
wr_en <= 1'd0;
wr_flag <= 1'b0;
end
else if (wr_flag == 1'b0) begin//写过程
wr_data <= {32'h00000001 + count,32'h00000002 + count,
32'h00000003 + count,32'h00000004 + count};
wr_en <= 1'd1;
if (count == 'd200) begin
//wr_data <= 127'd0;
wr_flag <= 1'b1;
end
end
else begin
wr_data <= wr_data;
wr_en <= 1'd0;
wr_flag <= wr_flag;//写完成
end
end
//根据写完成拉高读使能数据
//这里的rd_en可以控制是否读取ddr,因此每次读取给出一个周期的高电平即可
//一直读取
always@(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
rd_en <= 1'd0;
end
//0.2s 读取一次数据
else if (count == COUTER_MAX - 1) begin//(wr_flag == 1'b1)&&(count == COUTER_MAX)
rd_en <= 1'd1;
end
end
//每次读取4个
/*reg [1:0] COUNT_FLAG = 2'b0;
always@(posedge sys_clk or negedge sys_rst_n) begin
if (sys_rst_n == 1'b0) begin
rd_en <= 1'd0;
end
//0.2s 读取一次数据
else if (wr_flag && COUNT_FLAG == 2'd0) begin//(wr_flag == 1'b1)&&(count == COUTER_MAX)
rd_en <= 1'd1;
COUNT_FLAG <= 2'd1;
end
else begin
rd_en <= 1'd0;
end
if (COUNT_FLAG) begin
COUNT_FLAG <= 2'd2;
end
end*/
endmodule
`timescale 1ns / 1ps
//
// Company: 东北电力大学
// Engineer: Yang Zheng
//
// Create Date: 2022/07/21 12:28:54
// Design Name:
// Module Name: ddr
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module ddr(input sys_clk_p, //系统时钟
input sys_clk_n, //系统时钟
input sys_rst, //系统复位
output [16:0] c0_ddr4_adr,
output [1:0] c0_ddr4_ba,
output [0:0] c0_ddr4_cke,
output [0:0] c0_ddr4_cs_n,
inout [7:0] c0_ddr4_dm_dbi_n,
inout [63:0] c0_ddr4_dq,
inout [7:0] c0_ddr4_dqs_c,
inout [7:0] c0_ddr4_dqs_t,
output [0:0] c0_ddr4_odt,
output [0:0] c0_ddr4_bg,
output c0_ddr4_reset_n,
output c0_ddr4_act_n,
output [0:0] c0_ddr4_ck_c,
output [0:0] c0_ddr4_ck_t,
output c0_init_calib_complete,
output use_clk100m
);
reg pingpang = 0 ;
reg [30:0] wr_b_addr = 0 ;
reg [30:0] wr_e_addr = 200*16 ;
wire data_wren;
wire [127:0] data_wr;
reg wr_rst = 0 ;
reg [30:0] rd_b_addr = 0 ;
reg [30:0] rd_e_addr = 200*16 ;
reg user_rd_clk = 0 ;
wire data_rden;
reg rd_rst = 0 ;
wire read_enable;
// axi_ddr_top Outputs
wire [127:0] data_rd ;
wire ui_clk ;
wire ui_rst ;
wire rd_fifo_empty ;
axi_ddr_top #(
.DDR_WR_LEN ( 1 ),
.DDR_RD_LEN ( 1 ))
u_axi_ddr_top (
.sys_rst ( sys_rst ),//低电平复位
.c0_sys_clk_p ( sys_clk_p ),
.c0_sys_clk_n ( sys_clk_n ),
.pingpang ( pingpang ),
.wr_b_addr ( wr_b_addr [30:0] ),
.wr_e_addr ( wr_e_addr [30:0] ),
.user_wr_clk ( use_clk100m ),
.data_wren ( data_wren ),
.data_wr ( data_wr [127:0] ),
.wr_rst ( wr_rst ),
.rd_b_addr ( rd_b_addr [30:0] ),
.rd_e_addr ( rd_e_addr [30:0] ),
.user_rd_clk ( use_clk100m ),
.data_rden ( data_rden ),
.rd_rst ( rd_rst ),
.read_enable ( read_enable ),
.rd_fifo_valid (rd_fifo_valid ),
.c0_ddr4_adr ( c0_ddr4_adr [16:0] ),
.c0_ddr4_ba ( c0_ddr4_ba [1:0] ),
.c0_ddr4_cke ( c0_ddr4_cke [0:0] ),
.c0_ddr4_cs_n ( c0_ddr4_cs_n [0:0] ),
.c0_ddr4_odt ( c0_ddr4_odt [0:0] ),
.c0_ddr4_bg ( c0_ddr4_bg [0:0] ),
.c0_ddr4_reset_n ( c0_ddr4_reset_n ),
.c0_ddr4_act_n ( c0_ddr4_act_n ),
.c0_ddr4_ck_c ( c0_ddr4_ck_c [0:0] ),
.c0_ddr4_ck_t ( c0_ddr4_ck_t [0:0] ),
.data_rd ( data_rd [127:0] ),
.ui_clk ( ui_clk ),
.ui_rst ( ui_rst ),
.use_clk1 ( use_clk100m ),
.c0_init_calib_complete ( c0_init_calib_complete ),
.c0_ddr4_dm_dbi_n ( c0_ddr4_dm_dbi_n [7:0] ),
.c0_ddr4_dq ( c0_ddr4_dq [63:0] ),
.c0_ddr4_dqs_c ( c0_ddr4_dqs_c [7:0] ),
.c0_ddr4_dqs_t ( c0_ddr4_dqs_t [7:0] )
);
ddr_data u_ddr_data (
.sys_clk ( use_clk100m ),
.sys_rst_n ( c0_init_calib_complete ),
.rd_data ( data_rd [127:0] ),
.rd_fifo_valid (rd_fifo_valid ),
.wr_en ( data_wren ),
.wr_data ( data_wr [127:0] ),
.rd_en ( data_rden ),
.read_enable ( read_enable )
);
endmodule
set_property IOSTANDARD LVCMOS12 [get_ports sys_rst]
set_property PACKAGE_PIN AK12 [get_ports sys_rst]
set_property PACKAGE_PIN AL11 [get_ports c0_init_calib_complete]
set_property PACKAGE_PIN AK13 [get_ports use_clk100m]
set_property IOSTANDARD LVCMOS12 [get_ports c0_init_calib_complete]
set_property IOSTANDARD LVCMOS12 [get_ports use_clk100m]
set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets clk]
⑤仿真:ddr4仿真一般必须上板调试,而xilinx太牛了,直接用sverilog写了一个ddr4的模型应该。因此本人直接采用了xilinx自带的ddr4仿真文件进行的仿真,方便快捷。



可以看到用户侧的rd_data_rx已经收到了之前存入ddr4中数据。
4、DDR4 MIG的BUG


我们可以看到00地址记录01020304,40地址记录05060708,80地址记录09abc ,而读出数据是40地址读取的00,80地址才开始读取05060708。也就是读取时,00地址正常读取,40地址读到0数据,80地址以后对应的才是写入时的40地址的数据,这个原因我试了一天我也不清楚为啥,我反正觉得我代码没问题,哈哈哈。
FPGA时钟和时钟域时钟树所谓时钟树为FPGA内部资源,分:全局时钟树,区域时钟树,IO时钟树原则上优先使用全局时钟树,在GT接口上使用IO时钟树,一般工具也会对GT时钟加以限制;时钟树使用方式正确的物理连接FPGA会由物理管脚专门用于全局时钟设置,通过查询数据手册可以在PCB设计阶段进行确认,当外部时钟接入此管脚时,工具会自动占有全局时钟树资源,当接入普通信号时不会分配时钟树资源;恰当的代码描述原语的使用,即BUFG的使用,可以将PLL的输出等内部时钟进行全局时钟资源的分配;IO时钟资源需要参考相应接口手册,以ultrascale的GTH为例,其JESD204的时钟方案针对不同的子类会由不同
外部SPIFLASH:MicronN25Q128A13ESE40G(128Mbit(16MByte))FPGA:XC7A100T CPU:Microblaze第一种情况:Microblaze在简单的应用,比如运行LED,IIC,SPI,UART之类的低俗接口驱动,或做一些简单的辅助型工作时,一般生成的applicationelf文件都不大,在10几KB或者几十,百几KB,此时使用FPGA内部的BRAM资源已经足够。XC7A100T本身就有600几KB的BRAM资源。这种情况下直接将硬件流文件和elf文件合并为download.bit文件,在直接烧录到外部SPIFLAH即可。1.Xilinx--
这是为了能够使用嵌入的ruby代码开发postgres函数,但我一直无法构建它。根据建议http://www.robbyonrails.com/articles/2005/08/22/installing-untrusted-pl-ruby-for-postgresql我正在尝试从ftp://moulon.inra.fr/pub/ruby/提供的最新版本(plruby-0.5.3.tar.gz)构建所需的plruby.so我已经弄清楚我的本地postgres设置在哪里,并将调用调整为:rubyextconf.rb--with-pgsql-include=/usr/postgresql-
文/高扬(微信公众号:量子论)据上次3月18号发布的V1.8版,已经过去十天,这期间AI领域发生了很多重大变化。因此,我们对《ChatGPT实用指南》进行了重大改版,增加了大量实用的操作和详细的讲解,保证小白可以轻松上手,快速驾驭ChatGPT。V2.0版本亮点:1、结构更合理。分为基础篇、进阶篇、高级篇,从易到难,由浅入深,符合学习规律。2、内容更充实。扩充了27页的内容,尽量看图说话,将操作步骤一步步地展示出来。3、排版更美观。按图书出版的规范制作,便于知识点查阅。后记:2022年11月底,我们在HackerNews上看到了关于ChatGPT的新闻报道后,开始意识到,人工智能的春天来了,这
1FPGA启动流程图1 7SerialsFPGA配置流程1.1DevicePower-Up1.2ClearConfigurationMemory在上电后的任何时间内,可以对Slave-FPGA配置存储器(BlockRAM)进行复位处理。复位方式是将PROGRAM_B信号拉低(下降沿有效)。1.3SampleModePins当复位完成后,INIT_B恢复高电平,Slave-FPGA对M[2:0]模式引脚进行采样,然后开始在CCLK上升沿接收配置数据。1.4Synchronization在接收配置数据前,Slave-FPGA首先进行总线位宽检测。主机发送的配置文件中,“BusWidthAutoDe
文章目录1、行为级与RTL级的区别1.1RTL级(可综合成门级电路)1.2行为级2、关于LUT2.1LUT是什么2.2N维查找表2.3FPGA中的LUT3、`include和条件编译4、写异步D触发器(扬智电子笔试)4.1八位同步D触发器4.2具有异步清零,同步复位信号功能的D触发器5、静态、动态时序分析的优缺点(威盛VIA2003.11.06上海笔试试题)6、采用二选一多路器mux2和inv非门实现异或操作(飞利浦-大唐笔试)7、寄存器和锁存器的区别,为什么多用寄存器,行为级描述中锁存器如何产生8、D触发器实现2分频的Verilog描述(汉王笔试)9、D触发器实现带同步高置数和异步高复位端的
如何使用FPGA加速机器学习算法如何使用FPGA加速机器学习算法 当前,AI因为其CNN(卷积神经网络)算法出色的表现在图像识别领域占有举足轻重的地位。基本的CNN算法需要大量的计算和数据重用,非常适合使用FPGA来实现。上个月,RalphWittig(XilinxCTOOffice的卓越工程师)在2016年OpenPower峰会上发表了约20分钟时长的演讲并讨论了包括清华大学在内的中国各大学研究CNN的一些成果。在这项研究中出现了一些和CNN算法实现能耗相关的几个有趣的结论:①限定使用片上Memory;②使用更小的乘法器;③进行定点匹配:相对于32位定点或浮点计算,将定点计算结果精度降为16
///国家发改委:中国是全球能耗强度降低最快的国家之一2012年以来,我国以年均3%的能源消费增速支撑了年均6.6%的经济增长,单位GDP能耗下降26.4%,是全球能耗强度降低最快的国家之一///苹果自研5G芯片或将推迟至2025年后苹果原计划在2023年推出自研芯片,但因为功耗及效能表现不如预期,推出时间将延后到2025年之后,制程将推进采用台积电4nm,届时将搭载于iPhone17系列///飞常准:时隔近3年,国际单日客运航班量首次恢复至300班次以上时隔2年半多,国际及地区航线单日客运航班量首次恢复至300班次以上///国家发改委:我国风电、光伏发电装机均处于世界第一落实可再生能源发电全
paddleocr最后几个库一个比一个难装,特别是lanms库,巨难装,拒绝任何花里胡哨,十分钟,三步内解决问题。pip下载报错Keyringisskippedduetoanexception:'keyring.backends'CollectinglanmsUsingcachedlanms-1.0.2.tar.gz(973kB)ERROR:Commanderroredoutwithexitstatus1:command:'C:\Users\TensorFlow\anaconda3\python.exe'-c'importsys,setuptools,tokenize;sys.argv[0]=
1)实验平台:正点原子MPSoC开发板2)平台购买地址:https://detail.tmall.com/item.htm?id=6924508746703)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340252-1-1.html第二十三章DDS信号发生器实验DDS(DirectDigitalSynthesizer)即直接数字式频率合成器,是一种新型的频率合成技术。与传统的频率合成器相比,DDS具有相对带宽大,频率转换时间短,稳定性好,分辨率高,可灵活产生多种信号等优点。较容易实现频率、相位及幅度的数控调制,因此,在现代电子系统及设备的频率源