(原創) 如何在DE2用硬體存取SDRAM? (IC Design) (DE2)
Abstract
之前討論過在DE2用軟體的C語言存取SDRAM,本文討論用硬體的Verilog存取SDRAM。
Introduction
使用環境:Quartus II 7.2 SP1 + MegaCore IP 7.2 SP1 + DE2(Cyclone II EP2C35F627C6)
在(原創) 如何在DE2用軟體存取SDRAM? (IC Design) (DE2) (Nios II) 討論過在Nios II下,用軟體C語言去存取SDRAM,由於DE2的Cyclone II是個FPGA,為了硬體加速,有時可能會想將演算法用硬體Verilog實現,這時就得用硬體Verilog去直接存取SDRAM。
如同上一篇的範例,用switch當成2進位的輸入,但這次改用七段顯示器做16進位輸出,使用到(原創) 如何顯示8位數的七段顯示器? (IC Design) (Verilog) (DE2)所開發的module。
Verilog / SDRAM_HR_HW.v
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3
4 Filename : SDRAM_HR_HW.v
5 Compiler : Quartus II 7.2 SP1
6 Description : Demo how to use abstract base class simulate interface
7 Release : 04/25/2008 1.0
8 */
9 module SDRAM_HR_HW (
10 input CLOCK_50,
11 input [3:0] KEY,
12 input [17:0] SW,
13 output [17:0] LEDR,
14 output [6:0] HEX0,
15 HEX1,
16 HEX2,
17 HEX3,
18 HEX4,
19 HEX5,
20 HEX6,
21 HEX7,
22 //SDRAM side
23 output [11:0] DRAM_ADDR,
24 inout [15:0] DRAM_DQ,
25 output DRAM_BA_0,
26 DRAM_BA_1,
27 DRAM_RAS_N,
28 DRAM_CAS_N,
29 DRAM_CKE,
30 DRAM_CLK,
31 DRAM_WE_N,
32 DRAM_CS_N,
33 DRAM_LDQM,
34 DRAM_UDQM
35 );
36
37 wire RESET_n = KEY[0];
38 wire DONE; // write / read done
39 reg [22:0] addr; // address regitster
40 reg read, // read enable register
41 write; // write enable register
42 reg [1:0] state; // FSM state register
43 reg [15:0] data_in; // data input register
44 wire [15:0] DATA_OUT; // data output
45 reg [15:0] data_out; // data output register
46
47 assign LEDR = SW;
48
49 Sdram_Controller u0 (
50 // HOST
51 .REF_CLK(CLOCK_50), //system clock
52 .RESET_N(RESET_n), //system reset
53 .ADDR(address), //address for controller request
54 .WR(write), //write request
55 .RD(read), //read request
56 .LENGTH(8'h02), //request data length
57 .ACT(), //SDRAM ACK(acknowledge)
58 .DONE(DONE), //write/read done
59 .DATAIN(data_in), //Data input
60 .DATAOUT(DATA_OUT), //Data output
61 .IN_REQ(), //input data request
62 .OUT_VALID(), //output data vilid
63 .DM(2'b00), //Data mask input
64 // SDRAM
65 .SA(DRAM_ADDR),
66 .BA({DRAM_BA_1,DRAM_BA_0}),
67 .CS_N(DRAM_CS_N),
68 .CKE(DRAM_CKE),
69 .RAS_N(DRAM_RAS_N),
70 .CAS_N(DRAM_CAS_N),
71 .WE_N(DRAM_WE_N),
72 .DQ(DRAM_DQ),
73 .DQM({DRAM_UDQM,DRAM_LDQM}),
74 .SDR_CLK(DRAM_CLK)
75 );
76
77 SEG7_LUT_8 u1 (
78 .oSEG0(HEX0), // output SEG0
79 .oSEG1(HEX1), // output SEG1
80 .oSEG2(HEX2), // output SEG2
81 .oSEG3(HEX3), // output SEG3
82 .oSEG4(HEX4), // output SEG4
83 .oSEG5(HEX5), // output SEG5
84 .oSEG6(HEX6), // output SEG6
85 .oSEG7(HEX7), // output SEG7
86 .iDIG(data_out), // input data
87 .iWR(1'b1), // write enable
88 .iCLK(CLOCK_50), // clock
89 .iRESET_n(RESET_n) // RESET
90 );
91
92 // state 0 : prepare write
93 // state 1 : read switch & write SDRAM
94 // state 2 : prepare read
95 // state 3 : read SDRAM & write to SEG7
96 always @(posedge CLOCK_50 or negedge RESET_n)
97 begin
98 if (!RESET_n) begin
99 addr <= 0; // address register
100 read <= 0; // read enable register
101 write <= 0; // write enale register
102 state <= 0; // FSM state register
103 data_in <= 0; // data input register
104 end
105 else
106 begin
107 case (state)
108 // state 0 : prepare write
109 0: begin
110 read <= 0; // read diable
111 write <= 1; // write enable
112 state <= 1; // next state
113 end
114
115 //state 1 : read switch & write SDRAM
116 1: begin
117 if (DONE) // prepared done
118 begin
119 addr <= {23{1'b0}}; // write SDRAM address
120 data_in <= {SW[15:0]}; // write SDRAM data
121
122 // ensure done change to 0
123 read <= 0; // read disable
124 write <= 0; // write disable
125 state <= 2; // next state
126 end
127 end
128
129 // state 2 : prepare read
130 2: begin
131 read <= 1; // read enable
132 write <= 0; // write disable
133 state <= 3; // next state
134 end
135
136 // state 3 : read SDRAM & write to SEG7
137 3: begin
138 if (DONE) begin
139 addr <= {23{1'b0}}; // read SDRAM address
140 data_out <= DATA_OUT; // read SDRAM data
141
142 read <= 0; // read disable
143 write <= 0; // write disable
144 state <= 0; // next state
145 end
146 end
147 endcase
148 end
149 end
150
151 endmodule
49行
// HOST
.REF_CLK(CLOCK_50), //system clock
.RESET_N(RESET_n), //system reset
.ADDR(address), //address for controller request
.WR(write), //write request
.RD(read), //read request
.LENGTH(8'h02), //request data length
.ACT(), //SDRAM ACK(acknowledge)
.DONE(DONE), //write/read done
.DATAIN(data_in), //Data input
.DATAOUT(DATA_OUT), //Data output
.IN_REQ(), //input data request
.OUT_VALID(), //output data vilid
.DM(2'b00), //Data mask input
// SDRAM
.SA(DRAM_ADDR),
.BA({DRAM_BA_1,DRAM_BA_0}),
.CS_N(DRAM_CS_N),
.CKE(DRAM_CKE),
.RAS_N(DRAM_RAS_N),
.CAS_N(DRAM_CAS_N),
.WE_N(DRAM_WE_N),
.DQ(DRAM_DQ),
.DQM({DRAM_UDQM,DRAM_LDQM}),
.SDR_CLK(DRAM_CLK)
);
我們引進了Sdram_Controller,這是個2 port的controller,1 read 1 write,大部分狀況下,2 port已經夠用,4 port的我會另外討論。
77行
.oSEG0(HEX0), // output SEG0
.oSEG1(HEX1), // output SEG1
.oSEG2(HEX2), // output SEG2
.oSEG3(HEX3), // output SEG3
.oSEG4(HEX4), // output SEG4
.oSEG5(HEX5), // output SEG5
.oSEG6(HEX6), // output SEG6
.oSEG7(HEX7), // output SEG7
.iDIG(data_out), // input data
.iWR(1'b1), // write enable
.iCLK(CLOCK_50), // clock
.iRESET_n(RESET_n) // RESET
);
引進了之前所寫的七段顯示器module,將output用七段顯示器表示。
91行
// state 1 : read switch & write SDRAM
// state 2 : prepare read
// state 3 : read SDRAM & write to SEG7
always @(posedge CLOCK_50 or negedge RESET_n)
begin
if (!RESET_n) begin
addr <= 0; // address register
read <= 0; // read enable register
write <= 0; // write enale register
state <= 0; // FSM state register
data_in <= 0; // data input register
end
else
begin
case (state)
// state 0 : prepare write
0: begin
read <= 0; // read diable
write <= 1; // write enable
state <= 1; // next state
end
//state 1 : read switch & write SDRAM
1: begin
if (DONE) // prepared done
begin
addr <= {23{1'b0}}; // write SDRAM address
data_in <= {SW[15:0]}; // write SDRAM data
// ensure done change to 0
read <= 0; // read disable
write <= 0; // write disable
state <= 2; // next state
end
end
// state 2 : prepare read
2: begin
read <= 1; // read enable
write <= 0; // write disable
state <= 3; // next state
end
// state 3 : read SDRAM & write to SEG7
3: begin
if (DONE) begin
addr <= {23{1'b0}}; // read SDRAM address
data_out <= DATA_OUT; // read SDRAM data
state <= 0; // next state
end
end
endcase
end
end
我們採用了FSM,對SDRAM做存取。
1.當state為0時,送出寫入準備信號。
2.當state為1時,讀取switch值並寫入SDRAM。
3.當state為2時,送出讀取準備信號。
4.當state為3時,讀取SDRAM並回到state 0。
108行
read <= 0; // read diable
write <= 1; // write enable
state <= 1; // next state
end
當state為0時,read <= 0;,write <= 1;表示準備寫入SDRAM,state <= 1;進入下一個state。
115行
1: begin
if (DONE) // prepared done
begin
addr <= {23{1'b0}}; // write SDRAM address
data_in <= {SW[15:0]}; // write SDRAM data
// ensure done change to 0
read <= 0; // read disable
write <= 0; // write disable
state <= 2; // next state
end
end
這是本程式最重要的一段程式碼。
當state為1時,對SDRAM正式寫入。
當DONE為0時,表示SDRAM還無法讀寫,必須先回到state 0做寫入準備,或state 2做讀取準備,等到DONE為1時才可對SDRAM作正常讀寫。
addr為指定寫入SDRAM的記憶體位址,data_in為欲寫入SDRAM的資料。DE2上的SDRAM容量為8 MB,由4個bank所組成,addr[22:20]為bank數,addr[19:0]為每個bank內的記憶體位址。
最後須將 read <= 0;與wrie <= 0;讓DONE還原成0,因為在Sdram_Controller.v的245行
mDONE<=0;
DONE變成0,SDRAM可重新做讀取與寫入準備。最後 state <= 2;進入下一個state。
130行
2: begin
read <= 1; // read enable
write <= 0; // write disable
state <= 3; // next state
end
道理同state 0,但此時是做讀取準備。
137行
3: begin
if (DONE) begin
addr <= {23{1'b0}}; // read SDRAM address
data_out <= DATA_OUT; // read SDRAM data
read <= 0; // read disable
write <= 0; // write disable
state <= 0; // next state
end
end
道理同state 1,但此時是從SDRAM讀取資料,從DATA_OUT讀取資料進register後,回到state 0。
完整程式碼下載
sdram_hr_hw.7z
Conclusion
SDRAM_Controller都放在完整程式碼中,有需要的人可自行下載。
相對於其他記憶體,SDRAM是最麻煩的,但其最便宜且容量最大,當你的資料很大時(如影像處理),使用SDRAM的機會就很大。在此範例也學到循序電路配合FSM後,可重複做不同的事情,這是硬體描述語言慣用的手法。
See Also
(原創) 如何在DE2用軟體存取SDRAM? (IC Design) (DE2) (Nios II)
(原創) 如何顯示8位數的七段顯示器? (IC Design) (Verilog) (DE2)
(原創) 如何在DE2用硬體存取SDRAM(4 port)? (IC Design) (DE2)
(筆記) DE2與SDRAM相關資料總整理 (SOC) (DE2)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步