温馨提示:在阅读本文之前需具备DDR3 SDRAM(详见https://blog.csdn.net/xingchenfeiying/article/details/123439177?utm_source=app&app_version=5.1.1&utm_source=app)和AXI4总线协议(详见https://blog.csdn.net/xingchenfeiying/article/details/123460900?utm_source=app&app_version=5.1.1&utm_source=app)相关知识,结合Modelsim仿真工程更利于了解内在联系(详见基于FPGA+MIG+AXI4实现DDR3 SDRAM读写操作仿真(附代码+各模块仿真时序图)_春风细雨无声的博客-CSDN博客)。
EDA工具:Vivado 2018.3
FPGA型号:Kintex-7
DDR3 SDRAM型号:MT41K256M16HA-107
首先,先看看设计的逻辑顶层:整个工程可以分为获取图像数据源、图像数据写入DDR3、图像数据读出DDR3和图像显示。接下来将针对每一部分手把手进行“文字+图片+代码”方式详细说明。
一、图像数据源
为方便测试分析验证,工程中使用的图像源为640×512×16bit的模拟假图像,由逻辑代码按照时序要求产生场同步信号、行有效信号和图像数据。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity img_data_gen is
generic(
IMG_WIDTH : integer := 640;
IMG_HIGH : integer := 512
);
port (
clk : in std_logic;
rst : in std_logic;
fval : buffer std_logic;
lval : inout std_logic;
dval : out std_logic;
pixel_clk : out std_logic;
pixel_data : inout std_logic_vector(13 downto 0)
);
end img_data_gen;
architecture Behavioral of img_data_gen is
signal fval_cnt : std_logic_vector(7 downto 0) := (others => '0');
signal v_cnt : std_logic_vector(9 downto 0) := (others => '0');
signal h_cnt : std_logic_vector(9 downto 0) := (others => '0');
signal frame_cnt : std_logic_vector(18 downto 0) := (others => '0');
signal lval_start_flag : std_logic := '0';
signal lval_dly1 : std_logic := '0';
signal lval_dly2 : std_logic := '0';
signal lval_rise : std_logic := '0';
signal lval_down : std_logic := '0';
signal fval_dly1 : std_logic := '0';
signal fval_rise : std_logic := '0';
signal img_shift : std_logic := '0';
begin
process(clk,rst)
begin
if rst = '1' then
lval_start_flag <= '0';
elsif rising_edge (clk) then
if frame_cnt >= 3 and frame_cnt <= 332794 then
lval_start_flag <= '1';
else
lval_start_flag <= '0';
end if;
end if;
end process;
process(clk,rst)
begin
if rst = '1' or fval = '0' then
v_cnt <= (others => '0');
elsif rising_edge (clk) then
if lval_start_flag = '1' and v_cnt <= 648 then
v_cnt <= v_cnt + 1;
elsif v_cnt = 649 then
v_cnt <= (others => '0');
end if;
end if;
end process;
process(clk,rst)
begin
if rst = '1' then
lval <= '0';
elsif rising_edge (clk) then
if v_cnt >= 1 and v_cnt <= IMG_WIDTH then
lval <= '1';
else
lval <= '0';
end if;
end if;
end process;
process(clk,rst)
begin
if rst = '1' then
lval_dly1 <= '0';
lval_dly2 <= '0';
elsif rising_edge (clk) then
lval_dly1 <= lval;
lval_dly2 <= lval_dly1;
end if;
end process;
lval_rise <= lval_dly1 and (not lval_dly2);
lval_down <= (not lval_dly1) and lval_dly2;
process(clk,rst)
begin
if rst = '1' or fval = '0' then
h_cnt <= (others => '0');
elsif rising_edge (clk) then
if lval_rise = '1' then
h_cnt <= h_cnt + 1;
if h_cnt = 512 then
h_cnt <= (others => '0');
end if;
else
h_cnt <= h_cnt;
end if;
end if;
end process;
process(clk,rst) --产生一张静态图像
begin
if rst = '1' then
pixel_data <= (others => '0');
elsif rising_edge (clk) then
if lval = '1' then
pixel_data <= pixel_data + 1;
else
pixel_data <= (others => '0');
end if;
end if;
end process;
--------------------------------------------生成场同步信号--------------------------------
process(clk,rst)
begin
if rst = '1' then
frame_cnt <= (others => '0');
elsif rising_edge (clk) then
frame_cnt <= frame_cnt + 1;
if frame_cnt = 400000 then
frame_cnt <= (others => '0');
end if;
end if;
end process;
process(clk,rst)
begin
if rst = '1' then
fval <= '0';
elsif rising_edge (clk) then
if frame_cnt >= 0 and frame_cnt <= 332794 then
fval <= '1';
else
fval <= '0';
end if;
end if;
end process;
---------------------------------------场同步信号计数--------------------------------
process(clk,rst)
begin
if rst = '1' then
fval_dly1 <= '0';
elsif rising_edge (clk) then
fval_dly1 <= fval;
end if;
end process;
fval_rise <= fval and (not fval_dly1);
process(clk,rst)
begin
if rst = '1' then
fval_cnt <= (others => '0');
elsif rising_edge (clk) then
if fval_rise = '1' then
fval_cnt <= fval_cnt + 1;
elsif fval_cnt = 200 then
fval_cnt <= (others => '0');
else
fval_cnt <= fval_cnt;
end if;
end if;
end process;
process(clk,rst)
begin
if rst = '1' then
elsif rising_edge (clk) then
if fval_cnt>= 0 and fval_cnt< 100 then
img_shift <= '0';
elsif fval_cnt >= 100 and fval_cnt <= 200 then
img_shift <= '1';
end if;
end if;
end process;
----------------------------------------生成像素时钟------------------------------
pixel_clk <= clk;
dval <= lval;
end Behavioral;
二、图像数据写入DDR3
有了图像数据源之后,就需要将图像数据存放进DDR3 SDRAM中。那么,怎么存?DDR3 SDRAM是独立于FPGA的一种外部存储器,存放数据肯定需要有接口与FPGA进行数据交互。问题在于:接口是什么?有哪些信号?FPGA逻辑怎么来控制?
其实,直接通过逻辑代码来控制DDR3 SDRAM读写是相当有难度的,但好在Xilinx官方提供了IP核(即MIG)方便设计人员使用,大大降低了开发难度。接下来,深入探讨一下MIG核具体调用和配置。
2.1 MIG核配置
在建立好工程后,按如下步骤进行 DDR 控制器 IP 的创建和配置。
1、搜索查找 DDR 控制器 IP。
Xilinx 的 DDR 控制器的名称简写为 MIG(Memory Interface Generator), 在 Vivado 左侧
窗口点击 IP Catalog,然后在 IP Catalog 窗口直接搜索关键字“mig” ,就可以很容易的找到Memory Interface Generator(MIG 7 Series)。如下图所示。
直接双击鼠标左键或通过鼠标右键选项中选择 Customize IP 并点击。 如下图所示,可进入到 IP 配置界面。
2、 MIG IP 的配置。
进入IP配置界面后,第一个界面是 Memory Interface Generator 介绍页面, 如下图所示。
默认的器件家族(FPGA Family)、器件 型号(FPGA Part)、速度等级(Speed Grade)、综合
工具(Synthesis Tool)和设计输入语言(Design Entry)都和创建工程是保持一致。
点击 Next 到 MIG Output Options 配置页面中, 如下图所示。 勾选“Create Design”,默
认名称(Component Name)为“mig_7series_0”,用户可对其进行修改,这里改为“m