(原創) 如何在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)