DDR3(5):DDR3自动读写控制器
和 DDR2 的设计类似,在 DDR3_burst 的基础上,添加 FIFO,打造一个可以自动读写的 DDR3 控制器,让其能够方便的适用于不同的场合。
一、DDR3_ctrl
1、架构
由架构图可以看出,DDR3_ctrl 模块由写FIFO、读FIFO、DDR3_burst构成,结构比较简单。
2、代码
1 //************************************************************************** 2 // *** 名称 : DDR3_burst.v 3 // *** 作者 : xianyu_FPGA 4 // *** 博客 : https://www.cnblogs.com/xianyufpga/ 5 // *** 日期 : 2020年7月 6 // *** 描述 : 完成一次DDR3的突发 7 //************************************************************************** 8 module DDR3_ctrl 9 //============================< 参数 >====================================== 10 #( 11 parameter DDR_DM_W = 2 , //芯片dm位宽 12 parameter DDR_DQS_W = 2 , //芯片dqs位宽 13 parameter DDR_BANK_W = 3 , //芯片bank位宽 14 parameter DDR_ADDR_W = 14 , //芯片地址位宽 15 parameter DDR_DATA_W = 16 , //芯片数据位宽 16 //------------------------------------------------------- 17 parameter APP_ADDR_W = 28 , //用户地址位宽 18 parameter APP_DATA_W = 128 , //用户数据位宽 19 //------------------------------------------------------- 20 parameter BURST_ADDR_W = 25 //外部突发位宽 28-3 21 ) 22 //============================< 信号 >====================================== 23 ( 24 //时钟和复位 -------------------------------------------- 25 input sys_clk_i , //DDR3 参考时钟 26 input sys_rst , //FPGA 全局复位 27 //DDR3写 ------------------------------------------------ 28 input [BURST_ADDR_W -3:0] wr_min_addr , //写侧 起始地址 29 input [BURST_ADDR_W -3:0] wr_max_addr , //写侧 结束地址 30 input wr_clk , //写侧 时钟 31 input [15:0] wr_data , //写侧 数据 32 input wr_vld , //写侧 有效 33 //DDR3写 ------------------------------------------------ 34 input [BURST_ADDR_W -3:0] rd_min_addr , //读侧 起始地址 35 input [BURST_ADDR_W -3:0] rd_max_addr , //读侧 结束地址 36 input rd_clk , //读侧 时钟 37 output [15:0] rd_data , //读侧 数据 38 input rd_req , //读侧 请求 39 //DDR3控制 ---------------------------------------------- 40 input [BURST_ADDR_W -3:0] burst_len , //突发长度 41 output DDR3_rst , //DDR3复位 42 input pingpang_vld , //乒乓操作 43 //DDR3接口 ---------------------------------------------- 44 output [DDR_ADDR_W -1:0] ddr3_addr , 45 output [DDR_BANK_W -1:0] ddr3_ba , 46 output ddr3_cas_n , 47 output ddr3_ck_n , 48 output ddr3_ck_p , 49 output ddr3_cke , 50 output ddr3_ras_n , 51 output ddr3_cs_n , 52 output ddr3_reset_n , 53 output ddr3_we_n , 54 inout [DDR_DATA_W -1:0] ddr3_dq , 55 inout [DDR_DQS_W -1:0] ddr3_dqs_n , 56 inout [DDR_DQS_W -1:0] ddr3_dqs_p , 57 output [DDR_DM_W -1:0] ddr3_dm , 58 output ddr3_odt 59 ); 60 //============================< 信号 >====================================== 61 wire ui_clk ; 62 wire [APP_DATA_W -1:0] burst_rd_data ; //读突发数据 63 wire [APP_DATA_W -1:0] burst_wr_data ; //写突发数据 64 wire burst_rd_ack ; //读突发应答信号 65 wire burst_wr_ack ; //写突发应答信号 66 wire burst_rd_done ; //突发读完成信号 67 wire burst_wr_done ; //突发写完成信号 68 //------------------------------------------------------- 69 wire [ 9:0] wrFIFO_rd_count ; //写FIFO剩余数据个数 70 wire [ 9:0] rdFIFO_wr_count ; //读FIFO剩余数据个数 71 //------------------------------------------------------- 72 reg [ 5:0] state ; 73 reg burst_wr_req ; //突发写请求 74 reg burst_rd_req ; //突发读请求 75 reg [BURST_ADDR_W -3:3] wr_addr ; 76 reg [BURST_ADDR_W -3:3] rd_addr ; 77 reg [ 1:0] wr_addr_msb ; //乒乓操作写分区 78 reg [ 1:0] rd_addr_msb ; //乒乓操作读分区 79 wire [BURST_ADDR_W -1:0] burst_wr_addr ; //写突发地址 80 wire [BURST_ADDR_W -1:0] burst_rd_addr ; //读突发地址 81 //============================< 参数 >====================================== 82 localparam IDLE = 6'b000001 ; //空闲状态 83 localparam ARBIT = 6'b000010 ; //仲裁状态 84 localparam WR = 6'b000100 ; //写状态 85 localparam WR_DONE = 6'b001000 ; //写完成状态 86 localparam RD = 6'b010000 ; //读状态 87 localparam RD_DONE = 6'b100000 ; //读完成状态 88 //========================================================================== 89 //== DDR3突发读写模块,实现一段长度的突发读写 90 //========================================================================== 91 DDR3_burst 92 #( 93 .DDR_DM_W (DDR_DM_W ), //芯片dm位宽 94 .DDR_DQS_W (DDR_DQS_W ), //芯片dqs位宽 95 .DDR_BANK_W (DDR_BANK_W ), //芯片bank位宽 96 .DDR_ADDR_W (DDR_ADDR_W ), //芯片地址位宽 97 .DDR_DATA_W (DDR_DATA_W ), //芯片数据位宽 98 //--------------------------------------------------- 99 .APP_DATA_W (APP_DATA_W ), //用户数据位宽 100 .APP_ADDR_W (APP_ADDR_W ), //用户地址位宽 101 //--------------------------------------------------- 102 .BURST_ADDR_W (BURST_ADDR_W ) //外部突发位宽 28-3 103 ) 104 u_DDR3_burst 105 ( 106 .sys_clk_i (sys_clk_i ), //DDR3 参考时钟 107 .sys_rst (sys_rst ), //FPGA 全局复位 108 .ui_clk (ui_clk ), //DDR3 工作时钟 109 .DDR3_rst (DDR3_rst ), //DDR3 同步复位 110 //--------------------------------------------------- 111 .burst_rd_req (burst_rd_req ), //突发读请求 112 .burst_wr_req (burst_wr_req ), //突发写请求 113 .burst_rd_len (burst_len ), //突发读长度 114 .burst_wr_len (burst_len ), //突发写长度 115 .burst_rd_addr (burst_rd_addr ), //突发读地址 116 .burst_wr_addr (burst_wr_addr ), //突发写地址 117 .burst_rd_data (burst_rd_data ), //突发读数据 118 .burst_wr_data (burst_wr_data ), //突发写数据 119 .burst_rd_ack (burst_rd_ack ), //突发读应答,连接FIFO 120 .burst_wr_ack (burst_wr_ack ), //突发写应答,连接FIFO 121 .burst_rd_done (burst_rd_done ), //突发读完成信号 122 .burst_wr_done (burst_wr_done ), //突发写完成信号 123 //--------------------------------------------------- 124 .ddr3_addr (ddr3_addr ), 125 .ddr3_ba (ddr3_ba ), 126 .ddr3_cas_n (ddr3_cas_n ), 127 .ddr3_ck_n (ddr3_ck_n ), 128 .ddr3_ck_p (ddr3_ck_p ), 129 .ddr3_cke (ddr3_cke ), 130 .ddr3_ras_n (ddr3_ras_n ), 131 .ddr3_cs_n (ddr3_cs_n ), 132 .ddr3_reset_n (ddr3_reset_n ), 133 .ddr3_we_n (ddr3_we_n ), 134 .ddr3_dq (ddr3_dq ), 135 .ddr3_dqs_n (ddr3_dqs_n ), 136 .ddr3_dqs_p (ddr3_dqs_p ), 137 .ddr3_dm (ddr3_dm ), 138 .ddr3_odt (ddr3_odt ) 139 ); 140 //========================================================================== 141 //== FIFO 142 //========================================================================== 143 //写FIFO 144 //--------------------------------------------------- 145 wrFIFO_wr16_rd128_4096 wrFIFO 146 ( 147 .wr_clk (wr_clk ), // input wire wr_clk 148 .wr_en (wr_vld ), // input wire wr_en 149 .din (wr_data ), // input wire [15 : 0] din 150 .rd_clk (ui_clk ), // input wire rd_clk 151 .rd_en (burst_wr_ack ), // input wire rd_en 152 .dout (burst_wr_data ), // output wire [127 : 0] dout 153 .full ( ), // output wire full 154 .empty ( ), // output wire empty 155 .rd_data_count (wrFIFO_rd_count ) // output wire [9 : 0] rd_data_count 156 ); 157 158 //读FIFO 159 //--------------------------------------------------- 160 rdFIFO_wr128_rd16_512 rdFIFO 161 ( 162 .wr_clk (ui_clk ), // input wire wr_clk 163 .wr_en (burst_rd_ack ), // input wire wr_en 164 .din (burst_rd_data ), // input wire [127 : 0] din 165 .rd_clk (rd_clk ), // input wire rd_clk 166 .rd_en (rd_req ), // input wire rd_en 167 .dout (rd_data ), // output wire [15 : 0] dout 168 .full ( ), // output wire full 169 .empty ( ), // output wire empty 170 .wr_data_count (rdFIFO_wr_count ) // output wire [9 : 0] wr_data_count 171 ); 172 //========================================================================== 173 //== 状态机 174 //========================================================================== 175 always @(posedge ui_clk) begin 176 if(DDR3_rst) 177 state <= IDLE; 178 else begin 179 case(state) 180 //--------------------------------------------------- 空闲 181 IDLE: state <= ARBIT; 182 //--------------------------------------------------- 仲裁 183 ARBIT: if(wrFIFO_rd_count >= burst_len) 184 state <= WR; 185 else if(rdFIFO_wr_count < burst_len) 186 state <= RD; 187 //--------------------------------------------------- 写 188 WR: if(burst_wr_done) 189 state <= WR_DONE; 190 //--------------------------------------------------- 写完成 191 WR_DONE: state <= IDLE; 192 //--------------------------------------------------- 读 193 RD: if(burst_rd_done) 194 state <= RD_DONE; 195 //--------------------------------------------------- 读完成 196 RD_DONE: state <= IDLE; 197 198 default: state <= IDLE; 199 endcase 200 end 201 end 202 203 //状态机名称,Modelsim测试用 204 //--------------------------------------------------- 205 reg [55:0] state_name; //1个字符8位宽 206 always @(*) begin 207 case(state) 208 IDLE : state_name = "IDLE"; 209 ARBIT : state_name = "ARBIT"; 210 WR : state_name = "WR"; 211 WR_DONE : state_name = "WR_DONE"; 212 RD : state_name = "RD"; 213 RD_DONE : state_name = "RD_DONE"; 214 default : state_name = "IDLE"; 215 endcase 216 end 217 //========================================================================== 218 //== 读写请求 219 //========================================================================== 220 always @ (posedge ui_clk) begin 221 if(DDR3_rst) begin 222 burst_wr_req <= 1'b0; 223 end 224 else if(burst_wr_req == 1'b0 && state == WR) begin 225 burst_wr_req <= 1'b1; 226 end 227 else if(burst_wr_req == 1'b1 && state == WR && burst_wr_done) begin 228 burst_wr_req <= 1'b0; 229 end 230 end 231 232 always @ (posedge ui_clk) begin 233 if(DDR3_rst) begin 234 burst_rd_req <= 1'b0; 235 end 236 else if(burst_rd_req == 1'b0 && state == RD) begin 237 burst_rd_req <= 1'b1; 238 end 239 else if(burst_rd_req == 1'b1 && state == RD && burst_rd_done) begin 240 burst_rd_req <= 1'b0; 241 end 242 end 243 //========================================================================== 244 //== 读写地址设计 245 //========================================================================== 246 always @ (posedge ui_clk) begin 247 if(DDR3_rst) begin 248 wr_addr <= wr_min_addr[BURST_ADDR_W-3:3]; 249 end 250 else if(state == WR && burst_wr_done) begin 251 if(wr_addr == wr_max_addr[BURST_ADDR_W-3:3] - burst_len) 252 wr_addr <= wr_min_addr[BURST_ADDR_W-3:3]; 253 else 254 wr_addr <= wr_addr + burst_len; 255 end 256 end 257 258 always @ (posedge ui_clk) begin 259 if(DDR3_rst) begin 260 rd_addr <= rd_min_addr[BURST_ADDR_W-3:3]; 261 end 262 else if(state == RD && burst_rd_done) begin 263 if(rd_addr == rd_max_addr[BURST_ADDR_W-3:3]- burst_len) 264 rd_addr <= rd_min_addr[BURST_ADDR_W-3:3]; 265 else 266 rd_addr <= rd_addr + burst_len; 267 end 268 end 269 270 //写乒乓,未测试 271 //--------------------------------------------------- 272 always @ (posedge ui_clk) begin 273 if(DDR3_rst) begin 274 wr_addr_msb <= 2'b1; 275 end 276 else if(pingpang_vld == 1'b1) begin 277 if(state == WR && burst_wr_done && wr_addr == wr_max_addr[BURST_ADDR_W-3:3] - burst_len && rd_addr_msb != wr_addr_msb+1) 278 wr_addr_msb <= wr_addr_msb + 2'h1; 279 end 280 else if(pingpang_vld == 1'b0) begin 281 wr_addr_msb <= 2'b0; 282 end 283 end 284 285 //读乒乓,未测试 286 //--------------------------------------------------- 287 always @ (posedge ui_clk) begin 288 if(DDR3_rst) begin 289 rd_addr_msb <= 2'h0; 290 end 291 else if(pingpang_vld == 1'b1) begin 292 if(state == RD && burst_rd_done && rd_addr == rd_max_addr[BURST_ADDR_W-3:3] - burst_len && wr_addr_msb != rd_addr_msb+1) 293 rd_addr_msb <= rd_addr_msb + 2'h1; 294 end 295 else if(pingpang_vld == 1'b0) begin 296 rd_addr_msb <= 2'b0; 297 end 298 end 299 300 //读写地址 301 //--------------------------------------------------- 302 assign burst_wr_addr = {wr_addr_msb,wr_addr}; 303 assign burst_rd_addr = {rd_addr_msb,rd_addr}; 304 305 306 endmodule
1、DDR3_burst 的写采用【数据对齐模式】,加上本模块向 DDR3 发送读写请求是通过判断 FIFO 里的个数来决定的,因此读写 FIFO 采用 first word fall through 模式,其读使能和读数据对齐,而且有更精准的 FIFO 数据计数,因此更适合于本次的控制器设计。外部连接的 VGA_req 信号需要由常用的提前一拍给出改为直接给出。
2、突发长度在端口上输入,一般设置为一行图像个数的 1/8,数据进行 16 转 128 处理后,刚好一次突发就是一行的图像数据。
3、一开始照着 DDR2 的方式设计读写地址,结果数据大了后就读空了,后来才知道将 DDR3 设计为跳跃式的读写效率非常低,所以改成了顺序式的读写地址,问题就解决了。
二、仿真设计
1 `timescale 1ns/1ps //时间精度 2 3 module DDR3_ctrl_tb; 4 //============================< 端口 >========================================== 5 parameter DDR_DM_W = 2 ; //芯片dm位宽 6 parameter DDR_DQS_W = 2 ; //芯片dqs位宽 7 parameter DDR_BANK_W = 3 ; //芯片bank位宽 8 parameter DDR_ADDR_W = 14 ; //芯片地址位宽 9 parameter DDR_DATA_W = 16 ; //芯片数据位宽 10 //------------------------------------------------------- 11 parameter APP_ADDR_W = 28 ; //用户地址位宽 12 parameter APP_DATA_W = 128 ; //用户数据位宽 13 //------------------------------------------------------- 14 parameter BURST_ADDR_W = 25 ; //外部突发位宽 28-3 15 //============================< 信号 >====================================== 16 reg DDR3_200m ; //DDR3 参考时钟 17 reg FPGA_rst_n ; //FPGA 全局复位 18 //DDR3写 ------------------------------------------------ 19 reg UART_50m ; //写侧 时钟 20 reg [15:0] DDR3_wr_data ; //写侧 数据 21 reg DDR3_wr_vld ; //写侧 有效 22 //DDR3写 ------------------------------------------------ 23 reg HDMI_clk1x ; //读侧 时钟 24 wire [15:0] DDR3_rd_data ; //读侧 数据 25 wire DDR3_rd_req ; //读侧 请求 26 //DDR3控制 ---------------------------------------------- 27 wire DDR3_rst ; //DDR3 IP核复位 28 //DDR3接口 ---------------------------------------------- 29 wire [DDR_ADDR_W -1:0] ddr3_addr ; 30 wire [DDR_BANK_W -1:0] ddr3_ba ; 31 wire ddr3_cas_n ; 32 wire ddr3_ck_n ; 33 wire ddr3_ck_p ; 34 wire ddr3_cke ; 35 wire ddr3_ras_n ; 36 wire ddr3_cs_n ; 37 wire ddr3_reset_n ; 38 wire ddr3_we_n ; 39 wire [DDR_DATA_W -1:0] ddr3_dq ; 40 wire [DDR_DQS_W -1:0] ddr3_dqs_n ; 41 wire [DDR_DQS_W -1:0] ddr3_dqs_p ; 42 wire [DDR_DM_W -1:0] ddr3_dm ; 43 wire ddr3_odt ; 44 //========================================================================== 45 //== DDR3,输入200m得到400m,内部4:1,用100m 46 //========================================================================== 47 DDR3_ctrl 48 #( 49 .DDR_DM_W (2 ), //芯片dm位宽 50 .DDR_DQS_W (2 ), //芯片dqs位宽 51 .DDR_BANK_W (3 ), //芯片bank位宽 52 .DDR_ADDR_W (14 ), //芯片地址位宽 53 .DDR_DATA_W (16 ), //芯片数据位宽 54 //--------------------------------------------------- 55 .APP_DATA_W (128 ), //用户数据位宽 56 .APP_ADDR_W (28 ), //用户地址位宽 57 //--------------------------------------------------- 58 .BURST_ADDR_W (25 ) //外部突发位宽 28-3 59 ) 60 u_DDR3_ctrl 61 ( 62 //时钟和复位 ---------------------------------------- 63 .sys_clk_i (DDR3_200m ), //DDR3 参考时钟 64 .sys_rst (FPGA_rst_n ), //FPGA 全局复位 65 //DDR3写 -------------------------------------------- 66 .wr_min_addr (0 ), //写侧 起始地址 67 .wr_max_addr (200*10 ), //写侧 结束地址 68 .wr_clk (UART_50m ), //写侧 时钟 69 .wr_data (DDR3_wr_data ), //写侧 数据 70 .wr_vld (DDR3_wr_vld ), //写侧 有效 71 //DDR3读 -------------------------------------------- 72 .rd_min_addr (0 ), //读侧 起始地址 73 .rd_max_addr (200*10 ), //读侧 结束地址 74 .rd_clk (HDMI_clk1x ), //读侧 时钟 75 .rd_data (DDR3_rd_data ), //读侧 数据 76 .rd_req (DDR3_rd_req ), //读侧 请求 77 //DDR3控制 ------------------------------------------ 78 .burst_len (25 ), //突发长度(行/8) 79 .DDR3_rst (DDR3_rst ), //DDR3复位 80 .pingpang_vld (1'b0 ), //乒乓操作 81 //DDR3接口 ------------------------------------------ 82 .ddr3_addr (ddr3_addr ), 83 .ddr3_ba (ddr3_ba ), 84 .ddr3_cas_n (ddr3_cas_n ), 85 .ddr3_ck_n (ddr3_ck_n ), 86 .ddr3_ck_p (ddr3_ck_p ), 87 .ddr3_cke (ddr3_cke ), 88 .ddr3_ras_n (ddr3_ras_n ), 89 .ddr3_cs_n (ddr3_cs_n ), 90 .ddr3_reset_n (ddr3_reset_n ), 91 .ddr3_we_n (ddr3_we_n ), 92 .ddr3_dq (ddr3_dq ), 93 .ddr3_dqs_n (ddr3_dqs_n ), 94 .ddr3_dqs_p (ddr3_dqs_p ), 95 .ddr3_dm (ddr3_dm ), 96 .ddr3_odt (ddr3_odt ) 97 ); 98 99 //仿真模型 100 ddr3_model u_ddr3_model 101 ( 102 .rst_n (ddr3_reset_n ), 103 .ck (ddr3_ck_p ), 104 .ck_n (ddr3_ck_n ), 105 .cke (ddr3_cke ), 106 .cs_n (ddr3_cs_n ), 107 .ras_n (ddr3_ras_n ), 108 .cas_n (ddr3_cas_n ), 109 .we_n (ddr3_we_n ), 110 .dm_tdqs ({ddr3_dm[1],ddr3_dm[0]} ), //ddr3_dm为2位 111 .ba (ddr3_ba ), 112 .addr (ddr3_addr ), 113 .dq (ddr3_dq[15:0] ), //ddr3_dq为16位 114 .dqs ({ddr3_dqs_p[1],ddr3_dqs_p[0]} ), //ddr3_dqs_p为2位 115 .dqs_n ({ddr3_dqs_n[1],ddr3_dqs_n[0]} ), //ddr3_dqs_n为2位 116 .tdqs_n ( ), 117 .odt (ddr3_odt ) 118 ); 119 //========================================================================== 120 //== 时钟信号和复位信号 121 //========================================================================== 122 always #2.5 DDR3_200m = ~DDR3_200m; //200Mhz 123 always #10 UART_50m = ~UART_50m; //50Mhz 124 always #5 HDMI_clk1x = ~HDMI_clk1x; //100Mhz 125 126 initial begin 127 UART_50m = 0; 128 DDR3_200m = 0; 129 HDMI_clk1x = 0; 130 131 FPGA_rst_n = 0; #21; 132 FPGA_rst_n = 1; 133 end 134 //========================================================================== 135 //== 写 136 //========================================================================== 137 reg [15:0] h_cnt ; 138 wire add_h_cnt ; 139 wire end_h_cnt ; 140 reg [15:0] v_cnt ; 141 wire add_v_cnt ; 142 wire end_v_cnt ; 143 144 //宽度计数 145 //--------------------------------------------------- 146 always @(posedge UART_50m) begin 147 if(DDR3_rst) 148 h_cnt <= 'd0; 149 else if(add_h_cnt) begin 150 if(end_h_cnt) 151 h_cnt <= 'd0; 152 else 153 h_cnt <= h_cnt + 1'b1; 154 end 155 end 156 157 assign add_h_cnt = 1; 158 assign end_h_cnt = add_h_cnt && h_cnt== 200+1; 159 160 //高度计数 161 //--------------------------------------------------- 162 always @(posedge UART_50m) begin 163 if(DDR3_rst) 164 v_cnt <= 'd0; 165 else if(add_v_cnt) begin 166 if(end_v_cnt) 167 v_cnt <= 'd0; 168 else 169 v_cnt <= v_cnt + 1'b1; 170 end 171 end 172 173 assign add_v_cnt = end_h_cnt; 174 assign end_v_cnt = add_v_cnt && v_cnt== 10+1; 175 176 always @(posedge UART_50m) begin 177 if(DDR3_rst) begin 178 DDR3_wr_vld <= 'd0; 179 DDR3_wr_data <= 'd0; 180 end 181 else if(v_cnt > 'd0 && v_cnt <= 'd10) begin 182 if(h_cnt > 'd0 && h_cnt <= 'd200) begin 183 DDR3_wr_vld <= 1'd1; 184 DDR3_wr_data <= DDR3_wr_data + 'd1; 185 end 186 else begin 187 DDR3_wr_vld <= 'd0; 188 end 189 end 190 else begin 191 DDR3_wr_vld <= 'd0; 192 DDR3_wr_data <= 'd0; 193 end 194 end 195 //========================================================================== 196 //== 读 197 //========================================================================== 198 reg [15:0] cnt_h ; 199 wire add_cnt_h ; 200 wire end_cnt_h ; 201 reg [15:0] cnt_v ; 202 wire add_cnt_v ; 203 wire end_cnt_v ; 204 //========================< 参数 >========================================== 205 always @(posedge HDMI_clk1x) begin 206 if(DDR3_rst) 207 cnt_h <= 'd0; 208 else if(add_cnt_h) begin 209 if(end_cnt_h) 210 cnt_h <= 'd0; 211 else 212 cnt_h <= cnt_h + 1'b1; 213 end 214 end 215 216 assign add_cnt_h = 1; 217 assign end_cnt_h = add_cnt_h && cnt_h==200+1; 218 219 always @(posedge HDMI_clk1x) begin 220 if(DDR3_rst) 221 cnt_v <= 'd0; 222 else if(add_cnt_v) begin 223 if(end_cnt_v) 224 cnt_v <= 'd0; 225 else 226 cnt_v <= cnt_v + 1'b1; 227 end 228 end 229 230 assign add_cnt_v = end_cnt_h; 231 assign end_cnt_v = add_cnt_v && cnt_v==10+1; 232 233 234 assign DDR3_rd_req = (cnt_v > 0) && (cnt_v <=10 ) && 235 (cnt_h > 0) && (cnt_h <=200); 236 237 endmodule
仿真模仿 200x10 的图片写入到 DDR3 中,图像数据为 1-2000,一行200个数据,突发长度设置为 200/8 = 25。写时钟设置为 50Mhz,读时钟设置为 100Mhz。
三、仿真波形
1、总体波形
2、端口处的写数据波形细节
3、往DDR3写数据的波形细节
4、端口处的读数据波形细节
5、往DDR3读数据的波形细节
四、UART_DDR3_HDMI
DDR3 控制器写好后,建个串口传图工程看看能不能用,通过串口输入一张 1280*720 的图片,图片在 DDR3 中缓存,最终通过 HDMI 输出到显示屏中,关于串口传图的实现可以参阅博客《串口传图:RGB332格式和RGB565格式》,关于HDMI 协议可以参阅博客《协议——HDMI》。
1、工程架构
2、实验结果
完结撒花!
参考资料:V3学院FPGA教程