設(shè)計(jì)背景:
FLASH閃存閃存的英文名稱是"Flash Memory",一般簡(jiǎn)稱為"Flash",它屬于內(nèi)存器件的一種,是一種不揮發(fā)性( Non-Volatile )內(nèi)存。閃存的物理特性與常見的內(nèi)存有根本性的差異:目前各類 DDR 、 SDRAM 或者 RDRAM 都屬于揮發(fā)性內(nèi)存,只要停止電流供應(yīng)內(nèi)存中的數(shù)據(jù)便無法保持,因此每次電腦開機(jī)都需要把數(shù)據(jù)重新載入內(nèi)存;閃存在沒有電流供應(yīng)的條件下也能夠長(zhǎng)久地保持?jǐn)?shù)據(jù),其存儲(chǔ)特性相當(dāng)于硬盤,這項(xiàng)特性正是閃存得以成為各類便攜型數(shù)字設(shè)備的存儲(chǔ)介質(zhì)的基礎(chǔ)。
設(shè)計(jì)原理:
我們的設(shè)計(jì)用的是W25Q128FV 內(nèi)存128M的flash芯片,大家可以自行在網(wǎng)上下載器件手冊(cè)具體看所應(yīng)用的具體命令和自己項(xiàng)目具體的應(yīng)用和想發(fā)來設(shè)計(jì)。
這款flash芯片的的存儲(chǔ)是一個(gè)扇區(qū)4KB,一個(gè)扇區(qū)可以存256個(gè)字,一個(gè)字是8位,一個(gè)塊是64KB,一共有256個(gè)塊組成一個(gè)存儲(chǔ)flash內(nèi)存。
我在下面的講解中,將主要講實(shí)現(xiàn)一下字節(jié)的讀寫,我用的協(xié)議是SPI協(xié)議,這個(gè)芯片支持QSPI,雙端口SPI等。flash有三個(gè)狀態(tài)寄存器,每一個(gè)狀態(tài)寄存器的每一位都有各自的功能。大家可以具體的看器件手冊(cè),我給大家簡(jiǎn)單的講一下第一個(gè)狀態(tài)寄存器。
這個(gè)狀態(tài)寄存器第一位是可讀忙和不忙的標(biāo)志位,大家可以在我們的設(shè)計(jì)中判斷芯片是否忙和不忙來是否進(jìn)行下一步的操作。第二位是一個(gè)寫標(biāo)志的信號(hào),當(dāng)寫使能打開的時(shí)候它位1,只有它為1的時(shí)候我們才可以進(jìn)行寫,值得一說的不管是頁(yè)操作,還是擦除等命令后都會(huì)使這個(gè)標(biāo)志位變成0。然后前面的命令算的上的是保護(hù)命令,具體有使用的邏輯功能。
在flash中我們寫數(shù)據(jù)前先要擦除數(shù)據(jù)你想擦除的地方,然后進(jìn)行寫,如果沒有用過的flash芯片的話那么可以不用擦除。畢竟我們的flash可是掉電不丟失數(shù)據(jù)的。
我的設(shè)計(jì)思路是這樣的我們先讀出我們的器件廠商,和芯片ID,然后記性寫命令,寫使能打開,頁(yè)操作寫入數(shù)據(jù)(值得說明的是我們FLASH是新的所以沒進(jìn)行擦除命令,建議擦除---關(guān)閉寫使能 -- 打開寫使能),然后讀第一個(gè)寄存器判斷芯片的第一位是否忙,不忙然后進(jìn)行讀操作之后再數(shù)碼管上顯示出我們寫入的數(shù)據(jù)。
部分操作命令如下
我們的發(fā)送格式為在時(shí)鐘的上升沿寫入命令,在時(shí)鐘的下降沿讀出命令,我們用的是標(biāo)準(zhǔn)的SPI協(xié)議,端口IO0,和IO1,都是單向的。
寫使能時(shí)序:
讀使能時(shí)序:
之后別的時(shí)序我們將不展示,大家可以參考器件手冊(cè)。
設(shè)計(jì)架構(gòu)圖:
我們的設(shè)計(jì)是用一個(gè)FSM控制器來控制發(fā)送什么命令,flash模塊判斷FSM發(fā)送過來的state信號(hào)來選擇應(yīng)該執(zhí)行什么操作,當(dāng)命令寫入或者讀出后,會(huì)發(fā)送一個(gè)flag_done命令,這個(gè)命令讓我們判斷上個(gè)指令是否完成,如果完成后FAM將發(fā)送下一個(gè)命令。
設(shè)計(jì)代碼:
設(shè)計(jì)模塊
0modulefsm(clk,rst_n,flag_done,command,addr,state,data);
1
2 inputclk,rst_n;
3 inputflag_done;//輸入標(biāo)志位
4 outputreg[7:0]command;//輸出命令
5 outputreg[23:0]addr;//輸出地址
6 outputreg[2:0]state; //輸出狀態(tài)模式
7 outputreg[7:0]data;//輸出寫入數(shù)據(jù)
8
9 reg[2:0]state_s;
10 reg[20:0]count;
11 always@(posedgeclk)
12 if(!rst_n)
13 begin
14 state_s <=0;
15 data <=8'd0;
16 addr <=24'd0;
17 command <=8'd0;
18 state <=0;
19 count <=0;
20 end
21 else
22 case(state_s)
23 0 : begin
24 if(count <200)//延遲一段時(shí)間
25 count <=count +1;
26 else
27 begin//發(fā)送讀廠商ID的命令
28 command <=8'h90;
29 addr <=24'd0;
30 state <=1;
31 count <=1;
32 end
33 if(flag_done)//檢查是否完成
34 state_s <=1;
35 end
36
37 1 : begin
38 if(count <200)//延遲一段時(shí)間
39 count <=count +1;
40 else
41 begin//寫使能
42 command <=8'h06;
43 state <=3;
44 count <=0;
45 end
46 if(flag_done)//檢查是否完成
47 state_s <=2;
48 end
49
50 2 : begin
51 if(count <200)//延遲一段時(shí)間
52 count <=count +1;
53 else
54 begin//頁(yè)操作
55 command <=8'h02;
56 addr <=24'd0;
57 state <=4;
58 data <=8'haa;
59 count <=0;
60 end
61 if(flag_done)//檢查是否完成
62 state_s <=3;
63 end
64
65 3 : begin
66 if(count <200)//延遲一段時(shí)間
67 count <=count +1;
68 else
69 begin//讀寄存器
70 command <=8'h05;
71 count <=0;
72 state <=5;
73 end
74 if(flag_done)//檢查是否完成
75 state_s <=4;
76 end
77
78 4 : begin
79 if(count <200)//延遲一段時(shí)間
80 count <=count +1;
81 else
82 begin//讀數(shù)據(jù)
83 command <=8'h03;
84 addr <=24'd0;
85 state <=2;
86 count <=0;
87 end
88 end
89
90 default:state_s <=0;
91 endcase
92
93endmodule
0moduleflash (clk ,rst_n,q0,q1,sclk,cs,command,addr,state, data,show_data,flag_done);
1
2 inputclk,rst_n;
3 inputq0;
4 outputregq1;
5 outputregsclk;
6 outputregcs;
7 input[7:0]command; //輸入命令
8 input[23:0]addr; //地址
9 input[2:0]state; //狀態(tài)
10 input[7:0]data; //數(shù)據(jù)
11 outputreg[23:0]show_data; //顯示
12 outputregflag_done; //命令完成標(biāo)志
13
14 reg[5:0]count;
15 reg[5:0]cnt;
16 reg[31:0]temp;
17 reg[15:0]d;
18 reg[5:0]count_s;
19 reg[7:0]dou;
20 reg[39:0]xie;
21 reg[7:0]r_reg;
22
23 always@(posedgeclk)
24 if(!rst_n)
25 begin
26 sclk <=1;
27 count_s <=0;
28 end
29 elseif(cs)
30 begin
31 count_s <=0;
32 sclk <=1;
33 end
34 else
35 begin
36 if(count_s ==25-1) //產(chǎn)生1M的時(shí)鐘
37 begin
38 count_s <=0;
39 sclk <=~sclk;
40 end
41 else
42 count_s <=count_s +1;
43 end
44
45 reg[1:0]signle_s;
46
47 //邊沿檢測(cè)電路
48 always@(posedgeclk ornegedgerst_n)
49 if(!rst_n)
50 begin
51 signle_s <=2'b11;
52 end
53 else
54 begin
55 signle_s[0]<=sclk;
56 signle_s[1]<=signle_s[0];
57 end
58
59 assignpose_dge =signle_s[0]&&~signle_s[1];//上升沿脈沖
60 assignnege_dge =~signle_s[0]&&signle_s[1];//下降沿脈沖
61
62 reg[1:0]s;
63 reg[1:0]s1,s2,s3,s4;
64 always@(posedgeclk ornegedgerst_n)
65 if(!rst_n)
66 begin
67 q1 <=0;
68 count <=0;
69 cs <=1;
70 temp <=0;
71 d <=0;
72 cnt <=0;
73 s <=0;
74 s1 <=0;
75 s2 <=0;
76 s3 <=0;
77 flag_done <=0;
78 s4 <=0;
79 end
80 else
81 begin
82 if(state ==1)//state == 1進(jìn)入讀芯片的廠商和ID
83 case(s)
84 0:begincs <=0;temp <={command,addr};s <=1; end
85
86 1 :begin
87 if(nege_dge) //下降沿發(fā)送數(shù)據(jù)
88 begin
89 if(count <32)
90 begin
91 q1 <=temp[31];
92 count <=count +1;
93 temp <= {temp[30:0],temp[31]};
94 end
95 else
96 begin
97 count <=0;
98 s <=2;
99 end
100 end
101 else
102 q1 <=q1;
103 end
104
105 2 : begin
106 if(pose_dge) //上升沿采集數(shù)據(jù)
107 begin
108 if(count <16)
109 begin
110 count <=count +1;
111 d <={d[14:0],q0};
112 end
113 else
114 begin
115 s <=3;
116 cs <=1;
117 count <=0;
118 flag_done <=1;
119 show_data <=d;
120 end
121 end
122 else
123 begin
124 s <=2;
125 end
126 end
127
128 3 : begin
129 flag_done <=0;
130 end
131
132 endcase
133
134 elseif(state ==2) //state == 2進(jìn)入讀模式
135 case(s1)
136 0:begincs <=0;temp <={command,addr};s1 <=1; end
137
138 1 :begin
139 if(nege_dge)
140 begin
141 if(count <32)
142 begin
143 q1 <=temp[31];
144 count <=count +1;
145 temp <={temp[30:0],temp[31]};
146 end
147 else
148 begin
149 count <=0;
150 s1 <=2;
151 end
152 end
153 else
154 q1 <=q1;
155 end
156
157 2 : begin
158 if(pose_dge)
159 begin
160 if(count <8)
161 begin
162 count <=count +1;
163 dou <={dou[6:0],q0};
164 s1 <=2;
165 end
166 else
167 begin
168 s1 <=3;
169 cs <=1;
170 count <=0;
171 flag_done <=1;
172 show_data <=dou;
173 end
174 end
175 else
176 begin
177 s1 <=2;
178 end
179 end
180
181 3 : begin
182 flag_done <=0;
183 end
184 endcase
185
186 elseif(state ==3) //state == 3 進(jìn)入寫使能模式
187 case(s2)
188 0:begincs <=0;temp <={command,addr};s2 <=1; end
189
190 1 :begin
191 if(nege_dge)
192 begin
193 if(count <8)
194 begin
195 q1 <=temp[31];
196 count <=count +1;
197 temp <={temp[30:0],temp[31]};
198 end
199 else
200 begin
201 count <=0;
202 s2 <=2;
203 cs <=1;
204 flag_done <=1;
205 end
206 end
207 else
208 q1 <=q1;
209 end
210
211 2 :flag_done <=0;
212 endcase
213
214 elseif(state ==4) //state == 4 進(jìn)入頁(yè)寫操作
215 case(s3)
216 0:begincs <=0;xie <={command,addr,data};s3 <= 1;end
217
218 1 :begin
219 if(nege_dge)
220 begin
221 if(count <40)
222 begin
223 q1 <=xie[39];
224 count <=count +1;
225 xie <={xie[38:0],xie[39]};
226 end
227 else
228 begin
229 count <=0;
230 s3 <=2;
231 cs <=1;
232 flag_done <=1;
233 end
234 end
235 else
236 q1 <=q1;
237 end
238
239 2 :flag_done <=0;
240
241 endcase
242
243 elseif(state ==5) //state == 5 進(jìn)入讀第一個(gè)狀態(tài)寄存器 操作
244 case(s4)
245 0:begincs <=0;r_reg <=command;s4 <=1;end
246
247 1 :begin
248 if(nege_dge)
249 begin
250 if(count <8)
251 begin
252 q1 <=r_reg[7];
253 count <=count +1;
254 r_reg <={r_reg[6:0],r_reg[7]};
255 end
256 else
257 begin
258 count <=0;
259 s4 <=2;
260 end
261 end
262 else
263 q1 <=q1;
264 end
265
266 2 : begin
267 if(pose_dge)
268 begin
269 if(count <8)
270 begin
271 count <=count +1;
272 d <={d[14:0],q0};
273 end
274 else
275 begin
276 cs <=1;
277 count <=0;
278 if(!d[8])//判斷BUSY位忙不忙, 不忙進(jìn)入下個(gè)狀態(tài)
279 begin
280 flag_done <=1;
281 s4 <=3;
282 end
283 else//忙繼續(xù)讀第一個(gè)寄存器
284 s4 <=0;
285 end
286 end
287 else
288 begin
289 s4 <=2;
290 end
291 end
292
293 3 :flag_done <=0;
294
295 endcase
296
297 end
298
299endmodule
SignalTap 采集圖
圖中顯示的和我們的設(shè)計(jì)一樣,發(fā)送的各個(gè)命令也是一樣的,我們寫入的是AA然后下班接收的也是AA。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21729瀏覽量
602986
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論