SPI(Serial Peripheral Interface--串行外(wài)設接口(kǒu))總(zǒng)線(xiàn)系(xì)統是(shì)一(yī)種(zhǒng)同(tóng)步串行外(wài)設接口(kǒu),它(tā)可(kě)以(yǐ)使MCU與(yǔ)各(gè)種(zhǒng)外(wài)圍設備以(yǐ)串行方(fāng)式進(jìn)行通(tòng)信(xìn)以(yǐ)交換信(xìn)息。本(běn)項目我(wǒ)们(men)通(tòng)过(guò)SPI接口(kǒu)实現(xiàn)FPGA與(yǔ)EEPROM芯片(piàn)——AT93C46的(de)通(tòng)信(xìn)。示意(yì)图(tú)如(rú)图(tú)3-16。
图(tú)3-16 SPI接口(kǒu)傳輸結構图(tú)
先(xiān)查閱AT93C46的(de)datasheet,了(le)解(jiě)各(gè)引脚的(de)作用(yòng)。
cs:從器件(jiàn)使能(néng)信(xìn)号(hào),由(yóu)主(zhǔ)器件(jiàn)控制;
sk:时(shí)鐘(zhōng)信(xìn)号(hào),由(yóu)主(zhǔ)器件(jiàn)産生(shēng);
do:主(zhǔ)器件(jiàn)數據(jù)輸入(rù),從器件(jiàn)數據(jù)輸出(chū);
di:主(zhǔ)器件(jiàn)數據(jù)輸出(chū),從器件(jiàn)數據(jù)輸入(rù)。
再明(míng)确实現(xiàn)相互通(tòng)信(xìn)需要(yào)哪些操作。
1. 三(sān)種(zhǒng)基本(běn)的(de)操作
(1)EWEN时(shí)序(图(tú)3-17)
图(tú)3-17 EWEN时(shí)序图(tú)
EWEN可(kě)以(yǐ)理解(jiě)为(wèi)激活設備,写、擦除(这(zhè)里(lǐ)沒(méi)有(yǒu)用(yòng)到(dào),有(yǒu)興趣的(de)读(dú)者(zhě)可(kě)以(yǐ)自(zì)行查閱datasheet)操作執行之前(qián)必須要(yào)先(xiān)執行完EWEN操作。其操作过(guò)程为(wèi):
1) cs在(zài)開(kāi)始操作时(shí)拉高(gāo),等到(dào)读(dú)操作完成(chéng),拉低;
2) sk在(zài)CS拉高(gāo)时(shí),産生(shēng)10个(gè)脈沖,脈沖周期(qī)大于(yú)400ns;
3) di在(zài)SK的(de)周期(qī)內(nèi)輸出(chū)數據(jù),前(qián)面(miàn)輸出(chū)固定(dìng)的(de)指令“10011”,指示是(shì)EWEN操作,後(hòu)面(miàn)則繼續輸出(chū)5比特(tè)的(de)“0”。
(2)WRITE时(shí)序(图(tú)3-18)
图(tú)3-18 WRITE时(shí)序图(tú)
写操作:
1) cs先(xiān)拉高(gāo)一(yī)段(duàn)时(shí)間(jiān),然後(hòu)再拉低TCS时(shí)間(jiān),最(zuì)後(hòu)再拉高(gāo)CS,直(zhí)至(zhì)檢测到(dào)DO为(wèi)1,拉低;
2) sk在(zài)CS第(dì)一(yī)段(duàn)拉高(gāo)时(shí),産生(shēng)18个(gè)脈沖,脈沖周期(qī)大于(yú)400ns;
3) di在(zài)sk的(de)周期(qī)內(nèi)輸出(chū)數據(jù),前(qián)面(miàn)輸出(chū)固定(dìng)的(de)指令“101”,指示是(shì)写操作,後(hòu)面(miàn)則繼續輸出(chū)地(dì)址“AN~A0”和(hé)數據(jù)“DN~D0”。
(3)READ时(shí)序(图(tú)3-19)
图(tú)3-19 ERAD时(shí)序图(tú)
1) cs在(zài)開(kāi)始操作时(shí)拉高(gāo),等到(dào)读(dú)操作完成(chéng),拉低;
2) sk在(zài)cs第(dì)一(yī)段(duàn)拉高(gāo)时(shí),産生(shēng)18个(gè)脈沖,脈沖周期(qī)大于(yú)400ns;
3) di在(zài)sk的(de)周期(qī)內(nèi)輸出(chū)數據(jù),前(qián)面(miàn)輸出(chū)固定(dìng)的(de)指令“110”,指示是(shì)读(dú)操作,後(hòu)面(miàn)則繼續輸出(chū)地(dì)址“AN~A0”和(hé)固定(dìng)的(de)“0”;
4) 模块(kuài)從sk的(de)第(dì)11个(gè)周期(qī)開(kāi)始從do中(zhōng)读(dú)取(qǔ)數據(jù),每个(gè)周期(qī)读(dú)取(qǔ)1比特(tè),共(gòng)8比特(tè)。
实現(xiàn)一(yī)个(gè)AT93C46的(de)接口(kǒu),該接口(kǒu)能(néng)够根(gēn)據(jù)命令,实現(xiàn)EWEN、WRITE和(hé)READ功能(néng)。具體(tǐ)功能(néng)如(rú)下(xià):
明(míng)德揚在(zài)變(biàn)化(huà)範圍內(nèi)取(qǔ)了(le)1us作为(wèi)tcs的(de)值;AT93C46时(shí)鐘(zhōng)取(qǔ)1MHz。
上(shàng)遊模块(kuài)在(zài)rdy=1时(shí),給(gěi)出(chū)start命令,開(kāi)始進(jìn)行EWEN、WRITE或(huò)者(zhě)READ操作。在(zài)rdy=0期(qī)間(jiān),start命令无效。
當start有(yǒu)效时(shí),如(rú)果(guǒ)mode=0表(biǎo)示進(jìn)行EWEN操作;mode=1表(biǎo)示進(jìn)行WRITE操作;mode=2表(biǎo)示進(jìn)行READ操作。
當start有(yǒu)效时(shí),addr和(hé)wdata有(yǒu)效。
當進(jìn)行EWEN操作时(shí),模块(kuài)将按at93c46 EWEN的(de)要(yào)求,将addr写入(rù)at93c46。
當進(jìn)行WRITE操作时(shí),模块(kuài)将按at93c46 WRITE的(de)要(yào)求,将addr和(hé)wdata写入(rù)at93c46。
當進(jìn)行READ操作时(shí),模块(kuài)将按at93c46 READ的(de)要(yào)求,将addr写入(rù)at93c46,并從at93c46读(dú)到(dào)數據(jù),通(tòng)过(guò)rdata和(hé)rdata_vld返回(huí)給(gěi)上(shàng)遊模块(kuài)。
2. 設計(jì)过(guò)程
(1)明(míng)确功能(néng)
根(gēn)據(jù)題(tí)目可(kě)以(yǐ)画(huà)出(chū)設備與(yǔ)AT93C46之間(jiān)的(de)具體(tǐ)通(tòng)信(xìn)框图(tú)。如(rú)图(tú)3-20。
图(tú)3-20 信(xìn)号(hào)傳輸架構图(tú)
表(biǎo)3.5 信(xìn)号(hào)列表(biǎo)
(2)輸出(chū)分(fēn)析
cs:在(zài)WRITE操作时(shí),写入(rù)一(yī)个(gè)地(dì)址和(hé)數據(jù)後(hòu)拉低,間(jiān)隔tcs拉高(gāo),等待写操作完成(chéng);READ操作和(hé)EWEN操作都是(shì)在(zài)操作期(qī)間(jiān)为(wèi)高(gāo),操作結束(shù)拉低。
sk:引入(rù)計(jì)數器,通(tòng)过(guò)計(jì)數産生(shēng)1MHz的(de)芯片(piàn)时(shí)鐘(zhōng)。
rdy:從操作開(kāi)始到(dào)結束(shù)一(yī)直(zhí)为(wèi)低電(diàn)平,其他(tā)时(shí)刻为(wèi)高(gāo)電(diàn)平。
di:根(gēn)據(jù)操作的(de)不(bù)同(tóng)輸出(chū)相應(yìng)的(de)值
rdata:僅在(zài)READ操作时(shí)do的(de)值從高(gāo)位到(dào)低位,一(yī)比特(tè)一(yī)比特(tè)地(dì)給(gěi)rdata賦值。
rdata_vld:在(zài)rdata賦值結束(shù)後(hòu),拉高(gāo)一(yī)个(gè)时(shí)鐘(zhōng)周期(qī),表(biǎo)示此(cǐ)时(shí)rdata有(yǒu)效。
(3)狀态劃(huà)分(fēn)
從EWEN、READ和(hé)WRITE的(de)时(shí)序图(tú)我(wǒ)们(men)可(kě)以(yǐ)發(fà)現(xiàn)在(zài)不(bù)同(tóng)操作中(zhōng)有(yǒu)很多(duō)階(jiē)段(duàn)是(shì)相似的(de),總(zǒng)結起来(lái)有(yǒu)4个(gè)狀态:
IDLE:初始狀态,模块(kuài)在(zài)等待start信(xìn)号(hào)有(yǒu)效。
WR_RD:读(dú)写狀态。
TCS:片(piàn)選信(xìn)号(hào)拉低。
DO:等待写入(rù)操作完成(chéng)。
(4)狀态轉(zhuǎn)移
狀态轉(zhuǎn)移图(tú)請見(jiàn)3-21。
图(tú)3-21 狀态轉(zhuǎn)移图(tú)
(5)轉(zhuǎn)移条(tiáo)件(jiàn)
确定(dìng)了(le)狀态轉(zhuǎn)移图(tú)後(hòu),我(wǒ)们(men)需要(yào)明(míng)确狀态轉(zhuǎn)移条(tiáo)件(jiàn):
wr_rd_start:在(zài)IDLE狀态下(xià)收(shōu)到(dào)start有(yǒu)效。
tcs_start:在(zài)WR_RD狀态結束(shù)。
idle_start1:,处于(yú)EWEN或(huò)READ模式,在(zài)TCS狀态結束(shù)(1us)。
do_start:处于(yú)WRITE模式,在(zài)TCS結束(shù)(1us)。
idle_start2:处于(yú)WRITE模式,在(zài)TCS狀态下(xià),收(shōu)到(dào)do==1。
(6)完整性(xìng)檢查
(7)狀态機(jī)代(dài)碼
第(dì)一(yī)段(duàn),用(yòng)同(tóng)步时(shí)序,将次(cì)态的(de)值賦給(gěi)現(xiàn)态。注意(yì)此(cǐ)时(shí)直(zhí)接套(tào)用(yòng)模块(kuài),不(bù)要(yào)做任何更(gèng)改。
2 if(rst_n==1'b0)begin
3 state_c <= IDLE;
4 end
5 else begin
6 state_c <=state_n;
7 end
8 end
第(dì)二(èr)段(duàn),用(yòng)組合邏輯描述狀态轉(zhuǎn)移条(tiáo)件(jiàn)。注意(yì)轉(zhuǎn)移条(tiáo)件(jiàn)用(yòng)信(xìn)号(hào)来(lái)表(biǎo)示,信(xìn)号(hào)名要(yào)按明(míng)德揚規則来(lái)命名。
2 case(state_c)
3 IDLE:begin
4 if(idl2wrd_start)begin
5 state_n = WR_RD;
6 end
7 else begin
8 state_n = state_c;
9 end
10 end
11 WR_RD:begin
12 if(wrd2tcs_start)begin
13 state_n = TCS;
14 end
15 else begin
16 state_n = state_c;
17 end
18 end
19 TCS:begin
20 if(tcs2do_start)begin
21 state_n = DO;
22 end
23 else if(tcs2idl_start)begin
24 state_n = IDLE;
25 end
26 else begin
27 state_n = state_c;
28 end
29 end
30 DO:begin
31 if(do2idl_start)begin
32 state_n = IDLE;
33 end
34 else begin
35 state_n = state_c;
36 end
37 end
38 default:begin
39 state_n = IDLE;
40 end
41 endcase
42 end
43
第(dì)三(sān)段(duàn),用(yòng)assign定(dìng)義轉(zhuǎn)移条(tiáo)件(jiàn)。注意(yì)条(tiáo)件(jiàn)一(yī)定(dìng)要(yào)加上(shàng)現(xiàn)态。
2 assign wrd2tcs_start = state_c == WR_RD&& end_cnt1;
3 assign tcs2idl_start = state_c == TCS && end_cnt
4 && (mode_reg==EWEN||mode_reg==READ);
5 assign tcs2do_start = state_c == TCS && mode_reg == WRITE && end_cnt;
6 assign do2idl_start = state_c == DO && mode_reg == WRITE && do_ff1 == 1;
7
第(dì)四(sì)段(duàn),則是(shì)輸出(chū)信(xìn)号(hào)設計(jì),在(zài)功能(néng)代(dài)碼部(bù)分(fēn)。
(8)功能(néng)代(dài)碼
2 always @(posedge clk or negedge rst_n)begin
3 if(rst_n==1'b0)begin
4 cnt <= 0;
5 end
6 else if(add_cnt) begin
7 if(end_cnt)
8 cnt <= 0;
9 else
10 cnt <= cnt + 1;
11 end
12 end
13 assign add_cnt = state_c == WR_RD || state_c == TCS;
14 assign end_cnt = add_cnt && cnt==100 - 1 ;
15
16 //根(gēn)據(jù)第(dì)六(liù)步第(dì)2點(diǎn),写出(chū)cnt1的(de)代(dài)碼
17 always @(posedge clk or negedge rst_n)begin
18 if(rst_n==1'b0)begin
19 cnt1<= 0;
20 end
21 else if(add_cnt1) begin
22 if(end_cnt1)
23 cnt1 <= 0;
24 else
25 cnt1 <= cnt1 + 1;
26 end
27 end
28 assign add_cnt1 = end_cnt;
29 assign end_cnt1 = add_cnt1 && cnt1==x -1 ;
30
31 always @(*)begin
32 if(mode_reg == EWEN)begin
33 x = 10;
34 end
35 else if(mode_reg == WRITE)begin
36 x = 18;
37 end
38 else if(mode_reg == READ)begin
39 x = 18;
40 end
41 else begin
42 x = 0;
43 end
44 end
45 //根(gēn)據(jù)第(dì)六(liù)步第(dì)3點(diǎn),写出(chū)do的(de)代(dài)碼
46 always @(posedge clk or negedge rst_n)begin
47 if(rst_n==1'b0)begin
48 do_ff0<=0;
49 do_ff1<=0;
50 end
51 else begin
52 do_ff0<=d0;
53 do_ff1<=do_ff0;
54 end
55 end
56
57 //根(gēn)據(jù)第(dì)六(liù)步第(dì)4點(diǎn),写出(chū)sk的(de)代(dài)碼
58 always @(posedge clk or negedge rst_n)begin
59 if(rst_n==1'b0)begin
60 sk <= 0;
61 end
62 else if(sk_high)begin
63 sk <= 1;
64 end
65 else if(sk_low)begin
66 sk <= 0;
67 end
68 end
69 assign sk_high = state_c == WR_RD && add_cnt && cnt == 50-1;
70 assign sk_low = state_c == WR_RD && end_cnt;
71
72 //根(gēn)據(jù)第(dì)六(liù)步第(dì)5點(diǎn),写出(chū)di的(de)代(dài)碼
73 always @(posedge clk or negedge rst_n)begin
74 if(rst_n==1'b0)begin
75 di <= 0;
76 end
77 else if(di_en)begin
78 di <= dout[17-cnt1];
79 end
80 end
81 assign di_en = cnt==0 && state_c == WR_RD;
82
83 //根(gēn)據(jù)第(dì)六(liù)步第(dì)6點(diǎn),写出(chū)cs的(de)代(dài)碼
84 always @(posedge clk or negedge rst_n)begin
85 if(rst_n==1'b0)begin
86 cs <= 0;
87 end
88 else if(cs_high)begin
89 cs <= 1;
90 end
91 else if(cs_low)begin
92 cs <= 0;
93 end
94 end
95 assign cs_high = idl2wrd_start || tcs2do_start;
96 assign cs_low = wrd2tcs_start || do2idl_start;
97
98 //根(gēn)據(jù)第(dì)六(liù)步第(dì)7點(diǎn),写出(chū)rdy的(de)代(dài)碼
99 always @(*)begin
100 if(rdy_low)
101 rdy = 0;
102 else
103 rdy = 1;
104 end
105 assign rdy_low = start || state_c != IDLE;
106
107 //根(gēn)據(jù)第(dì)六(liù)步第(dì)8點(diǎn),写出(chū)rdata的(de)代(dài)碼
108 always @(posedge clk or negedge rst_n)begin
109 if(rst_n==1'b0)begin
110 rdata <= 0;
111 end
112 else if(rdata_en)begin
113 rdata <= {rdata[6:0],do};
114 end
115 end
116 assign rdata_en = mode_reg == READ && state_c == WR_RD && end_cnt
117 && cnt1 >= 10 && cnt1 < 18;
118
119 //根(gēn)據(jù)第(dì)六(liù)步第(dì)9點(diǎn),写出(chū)rdata_vld的(de)代(dài)碼
120 always @(posedge clk or negedge rst_n)begin
121 if(rst_n==1'b0)begin
122 rdata_vld <= 0;
123 end
124 else if(rdata_vld_en)begin
125 rdata_vld <= 1;
126 end
127 else begin
128 rdata_vld <= 0;
129 end
130 end
131 assign rdata_vld_en = mode_reg == READ && wrd2tcs_start;
132
133 //根(gēn)據(jù)第(dì)六(liù)步第(dì)10點(diǎn),写出(chū)dout的(de)代(dài)碼
134 always @(posedge clk or negedge rst_n)begin
135 if(rst_n==1'b0)begin
136 dout <= 0;
137 end
138 else if(start && mode==0)begin
139 dout <= {3'b100,2’b11,13'b0};
140 end
141 else if(start && mode==1)begin
142 dout <= {3'b101,addr,wdata};
143 end
144 else if(start && mode==2)begin
145 dout <= {3'b110,addr,8'b0};
146 end
147 end
148
149 always @(posedge clk or negedge rst_n)begin
150 if(rst_n==1'b0)begin
151 mode_reg <= 0;
152 end
153 else if(start && mode==0)begin
154 mode_reg <= EWEN;
155 end
156 else if(start && mode==1)begin
157 mode_reg <= WRITE;
158 end
159 else if(start && mode==2)begin
160 mode_reg <= READ;
161 end
162 end
163
技術(shù)交流QQ群(qún):544453837
更(gèng)多(duō)FPGA技術(shù)資訊:明(míng)德揚科教
點(diǎn)擊了(le)解(jiě)>>至(zhì)簡設計(jì)法























