【Quartus FPGA】EMIF DDR3 读写带宽测试

在通信原理中,通信系统的有效性用带宽来衡量,带宽定义为每秒传输的比特数,单位 b/s,或 bps。在 DDR3 接口的产品设计中,DDR3 读/写带宽是设计者必须考虑的指标。本文主要介绍了 Quartus FPGA 平台 EMIF 参数配置,以及测试 DDR3 读写带宽的过程,FPGA 器件型号是 Cyclone 10 GX 10CX220YF780E6G,DDR3 颗粒型号是 Winbond W631GG6KB。

目录

[1 EMIF IP 配置](#1 EMIF IP 配置)

[2 AMM 接口](#2 AMM 接口)

[3 读写带宽测试](#3 读写带宽测试)


1 EMIF IP 配置

在进行 EMIF DDR3 读写带宽测试之前,先确保 EMIF DDR3 IP 时钟与时序参数配置正确。

General -> Clocks 选项卡,填写内存时钟频率 Memory clock frequency ,这里填了 933M,PLL 参考时钟频率为 116.625MHz.

Memory -> Latency and Burst 选项卡,根据 DDR3 内存颗粒用户手册,设置 Memory CAS latency 和 Memory write CAS latency 值。

这里所使用的 DDR3 内存型号为 Winbond W631GG6KB,933M 对应的 tCK 为 1.07ns,根据手册得知,CL = 13,CWL = 9.

Memory Timing 参数如下:

2 AMM 接口

Quartus EMIF IP 提供了 AMM(Avalon Memory-Mapped) 接口,用于 DDR3 数据的传输,AMM 接口定义如下。

amm_ready 扮演 waitrequest_n 的角色,当控制器处于 busy 状态时,该信号将会拉低;amm_burstcount 表示读/写 burst 传输的周期数;DDR3 颗粒数据接口位宽是 16bit,8n-prefetch,所以 amm_writedata 与 amm_readdata 的位宽是 16bit × 8 = 128bit。

AMM 接口读写时序图与其他细节,可以参考 Intel 官网 Avalon® 接口规范简介

3 读写带宽测试

在本设计中,DDR3 读写采用固定地址突发的方式,amm_burstcount 大小固定为 64,每次先写入 64 个数据,再读出 64 个数据。

同时定义两个计数器 wr_data_cnt 与 rd_data_cnt,用于一段时间读写数据的计数,需要注意计数器位宽,避免溢出的情况。这里计数器位宽定义 32bit,时间间隔取 200ms。

VHDL 设计代码如下,

复制代码
process(sys_rst,sys_clk) 
begin
   if sys_rst = '1' then
      pstate <= st_init;
      buf_test_wr_req <= '0';
      buf_test_rd_req <= '0';
      test_wr_q <= (others => '0');
      test_wr_mask <= (others => '0');
      wr_cnt_scope <= (others => '0');
      rd_cnt_scope <= (others => '0');
      rd_err_cnt_scope <= (others => '0');
   elsif rising_edge(sys_clk) then
      if timeout_event = '1' then
         wr_cnt_scope <= (others => '0');
         rd_cnt_scope <= (others => '0');
         rd_err_cnt_scope <= (others => '0');
      end if;
   
      case(pstate) is
         when st_init => 
            -- power on delay and initialization
            if ddr_init_done = '1' then
               pstate <= st_idle;
            else
               pstate <= st_init;
            end if;
            
         when st_idle => 
            -- idle state
            pstate <= st_test_write;
            
         when st_test_write => 
            -- pull up req and wait fot ack
            if buf_test_wr_req = '1' and test_wr_ack = '1' then
               pstate <= st_test_write_end;
               buf_test_wr_req <= '0';
            else
               pstate <= st_test_write;
               buf_test_wr_req <= '1';
            end if;
         
         when st_test_write_end => 
            -- wait write ending
            if test_wr_end = '1' then
               pstate <= st_test_read;
            else
               pstate <= st_test_write_end;
            end if;
            
            test_wr_q(4*128-1 downto 3*128) <= DDR_DATA_PATTERN;
            test_wr_q(3*128-1 downto 2*128) <= DDR_DATA_PATTERN;
            test_wr_q(2*128-1 downto 1*128) <= DDR_DATA_PATTERN;
            test_wr_q(1*128-1 downto 0*128) <= DDR_DATA_PATTERN;
            test_wr_mask <= (others => '0');
            if test_wr_rden = '1' then
               wr_cnt_scope <= wr_cnt_scope + 1;
            end if;
            
         when st_test_read => 
            -- pull up req and wait for ack
            if buf_test_rd_req = '1' and test_rd_ack = '1' then
               pstate <= st_test_read_end;
               buf_test_rd_req <= '0';
            else
               pstate <= st_test_read;
               buf_test_rd_req <= '1';
            end if;
         
         when st_test_read_end => 
            -- wait read ending
            if test_rd_end = '1' then
               pstate <= st_idle;
            else
               pstate <= st_test_read_end;
               if test_rd_rdvld = '1' then
                  rd_cnt_scope <= rd_cnt_scope + 1;
                  if test_rd_rdata(4*128-1 downto 3*128) /= DDR_DATA_PATTERN then
                     rd_err_cnt_scope <= rd_err_cnt_scope + 1;
                  elsif test_rd_rdata(3*128-1 downto 2*128) /= DDR_DATA_PATTERN then
                     rd_err_cnt_scope <= rd_err_cnt_scope + 1;
                  elsif test_rd_rdata(2*128-1 downto 1*128) /= DDR_DATA_PATTERN then
                     rd_err_cnt_scope <= rd_err_cnt_scope + 1;
                  elsif test_rd_rdata(1*128-1 downto 0*128) /= DDR_DATA_PATTERN then
                     rd_err_cnt_scope <= rd_err_cnt_scope + 1;
                  end if;
               end if;
            end if;
         
         when others => NULL;
            
      end case;
   end if;
end process;

SignalTap 调试波形如下:

读带宽:

7533666 × 128bit × 1s/200ms = 4.822Gbps

写带宽:

7653248 × 128bit × 1s/200ms = 4.898Gbps

可以进一步计算,在突发传输为 64 时,DDR3 的读写效率约 32.56%.

相关推荐
ALINX技术博客13 小时前
【ALINX 教程】FPGA Multiboot 功能实现——基于 ALINX Artix US+ AXAU25 开发板
fpga开发·fpga
Genevieve_xiao15 小时前
【verilog】如何一小时成为verilog高手(并非
fpga开发
从此不归路15 小时前
FPGA 结构与 CAD 设计(第3章)上
ide·fpga开发
Aaron158818 小时前
基于VU13P在人工智能高速接口传输上的应用浅析
人工智能·算法·fpga开发·硬件架构·信息与通信·信号处理·基带工程
碎碎思18 小时前
在 FPGA 上实现并行脉冲神经网络(Spiking Neural Net)
人工智能·深度学习·神经网络·机器学习·fpga开发
集芯微电科技有限公司20 小时前
替代HT6310/KP3310离线式AC-DC无感线性稳压器
数据结构·人工智能·单片机·嵌入式硬件·fpga开发
minglie121 小时前
Zynq上UART/IIC/SPI的24个实验-第0课:目录
fpga开发
FPGA小c鸡1 天前
FPGA摄像头到屏幕完整链路:从OV5640采集到HDMI实时显示(附完整工程代码)
fpga开发
dai8910111 天前
使用紫光同创FPGA实现HSSTLP IP支持的线速率
fpga开发
s09071361 天前
XIlinx FPGA使用LVDS的电源与电平关键指南
fpga开发·xilinx·lvds