和 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教程