標(biāo)題:
利用SPI驅(qū)動(dòng)12864液晶
[打印本頁]
作者:
51黑黑黑
時(shí)間:
2016-2-23 17:37
標(biāo)題:
利用SPI驅(qū)動(dòng)12864液晶
SPI 發(fā)送模塊
在這里,我們要在主機(jī)上建立,一個(gè)向從機(jī)寫入數(shù)據(jù)的SPI發(fā)送模塊,首先我們先從C語言上了解幾個(gè)主機(jī)在SPI寫操作上容易被疏忽的小細(xì)節(jié):我們知道SPI設(shè)備在傳輸都有一個(gè)規(guī)則,SCL 時(shí)鐘信號(hào)在“上升沿”的時(shí)候是“鎖存數(shù)據(jù)”,SCL時(shí)鐘信號(hào)在“下降沿”是“設(shè)置數(shù)據(jù)”。在這里我們SPI 主機(jī)(FPGA),寫操作要干的工作就是在“拉高SCL時(shí)鐘信號(hào)之前”設(shè)置數(shù)據(jù)(移位數(shù)據(jù)),設(shè)置數(shù)據(jù)之后,再拉高時(shí)鐘信號(hào)。但是我們常常會(huì)忽略了一些具體的細(xì)節(jié)。
上面有兩個(gè)主機(jī)的SPI_Send函數(shù)(寫函數(shù)),左邊的寫法是最常用,但是也是最容易忽略小細(xì)節(jié)。相比右邊的寫法比較謹(jǐn)慎,在最低的程度上符合一寫小細(xì)節(jié)。
再來,我們繼續(xù)引用ST7565P芯片的寫入時(shí)序圖,分析并且區(qū)分上邊的兩個(gè)寫法。關(guān)于SCL信號(hào)在空閑的時(shí)候總是處于高電平。當(dāng)主機(jī)開始向從機(jī)寫入數(shù)據(jù),主機(jī)會(huì)先拉低CS 信號(hào),再拉低SCL信號(hào),然后“設(shè)置”數(shù)據(jù),亦即主機(jī)(FPGA)更新SI 的數(shù)據(jù)(主機(jī)數(shù)據(jù)移位操作),最后再拉高SCL信號(hào)。同一時(shí)間,從機(jī)會(huì)因?yàn)镾CL 的上升沿變化,從機(jī)(液晶資源)“鎖存”(從機(jī)讀取數(shù)據(jù)操作)SI上的數(shù)據(jù)。很明顯左邊的寫法沒有符合這些細(xì)節(jié),然而右邊的寫法卻符合這些細(xì)節(jié)。無論是左邊的寫法還是右邊的寫法,都忽略了一個(gè)致命的細(xì)節(jié),兩種寫法都無法確定SPI時(shí)鐘信號(hào)的時(shí)鐘頻率。
module spi_write_module
(
CLK,RSTn,Start_Sig,SPI_Data,Done_Sig,SPI_Out
);
input CLK;
input RSTn;
input Start_Sig;
output [9:0] SPI_Data;
output Done_Sig;
output [3:0]SPI_Out;//[3]CS,[2]A0[1]CLK [0]D0
parameter T0P5US=4'd9;//0.5us
always@(posedge CLK or negedgeRSTn)
if(!RSTn)
Count1<=4'd0;
else if(Count1==T0P5US)
Count1<4'd0;
else if(Start_Sig)
Count1<=Count1+1'b1;
else
Count1<=4'd0;
reg[4:0]i;
reg rCLK;
reg rDO;
reg isDone;
always@(posedge CLK or negedgeRSTn)
if(!RSTn)
begin
i<=5'd0;
rCLK<=1'b1;
rDO<=1'b0;
isDone<=1'b0;
end
else if(Start_Sig)
case(i)
5'd0,5'd2,5'd4,5'd6,5'd8,5'd10,5'd12,5'd14:
if(Count1==T0P5US)beginrCLK<=1'b0;rDO<=SPI_Data[7-(i>>1)];i<=1+1'b1;end
5'd1,5'd3,5'd5,5'd7,5'd9,5'd11,5'd13,5'd15:
if(Count==T0P5US)beginrCLK<=1'b1;i<=i+1'b1;end
5'd16:
beginisDone<=1'b1;i<=i+1'b1;end
5'd17:
beginisDone<=1'b0;i<=5'd0;end
endcase
assign Done_Sig=isDone;
assignSPI_Out={SPI_Data[9],SPI_Data[8],rCLK,rDO};
endmodule
SCL 的時(shí)鐘頻率定義為1Mhz , 也就是說周期時(shí)間是1us,半周期就是0.5us 。如果以20Mhz 來定時(shí),那么計(jì)數(shù)的結(jié)果是10。在19行定義了0.5us 的常量,第23~33 行是0.5us的定時(shí)器。但是比較不同的是,這個(gè)定時(shí)器平時(shí)不工作,當(dāng)Start_Sig拉高的時(shí)候才開始計(jì)數(shù)(第30 行)。第37~65 行是spi_write_module.v的核心功能。i 寄存器表示操作步驟,rCLK 寄存器表示SCL 然而rDO 寄存器表示SI。如同前面所述那樣,SCL 時(shí)鐘信號(hào),處于空閑狀態(tài)
時(shí)是出于高電平,所以rCLK 復(fù)位值是邏輯1(46 行)。
SPI_Data : 第9 位表示CS,第8 位表示A0,第7 .. 0位表示一字節(jié)數(shù)據(jù)。
SPI_Out : 第3 位表示CS,第2 位表示A0,第1位表示SCL,第0 位表示SI。
當(dāng)Start_Sig 拉高的同時(shí),定時(shí)器開始計(jì)數(shù)(30行),該模塊也開始執(zhí)行(50 行)。
當(dāng)?shù)谝粋(gè)0.5us 定時(shí)產(chǎn)生的時(shí)候(54行),也就是第一個(gè)時(shí)鐘的前半周期,亦即下降沿,
rCLK 設(shè)置為邏輯0。根據(jù)SPI傳輸?shù)囊?guī)則,下降沿的時(shí)候主機(jī)設(shè)置數(shù)據(jù),rDO 賦予SPI_Data 信號(hào)的第7 位(SPI傳輸是從最高位開始,最低位結(jié)束),最后i 遞增以示下一個(gè)步驟。當(dāng)i 等于1 的時(shí)候并且定時(shí)產(chǎn)生(56行),這表示第一個(gè)時(shí)鐘的后半周期,亦即上升沿,rCLK 設(shè)置為邏輯1。在SPI傳輸?shù)囊?guī)則中上升沿的時(shí)候,從機(jī)鎖存數(shù)據(jù)。然后i 遞增以示下一個(gè)步驟。
上述的步驟會(huì)一直重復(fù)到第八次,直到一字節(jié)的數(shù)據(jù)發(fā)送完畢。最后會(huì)產(chǎn)生一個(gè)完成信號(hào)(59~63 行)。
這里有一個(gè)表達(dá)式需要說明一下:
i >> 1 : 表示i / 2。右移操作也代表了“i /j2”(j 是右移次數(shù))。
假設(shè)8 >> 2 ,亦即8 / 22 等于2。8>> 3, 亦即8 / 23 等于1。
最后還有一個(gè)重點(diǎn)就是SPI_Out 的驅(qū)動(dòng)(70行)。在上面我已經(jīng)重復(fù)過SPI_Out 是占4位的輸出。而且每一個(gè)位都有意義。
SPI_Out 第3 位:表示了CS,所以直接由SPI_Data 的第9位驅(qū)動(dòng)。
SPI_Out 第2 位:表示了A0,同樣也是直接由SPI_Data的第8 位驅(qū)動(dòng)。
SPI_Out 第1 位:表示了SCL,以寄存器rCLK來驅(qū)動(dòng)。
SPI_Out 第0 位:表示了SI,以寄存器rDO來驅(qū)動(dòng)。
這樣的目的是簡化連線的復(fù)雜度。我們知道Verilog HDL語言的位操作是很強(qiáng)大。懂得善用,會(huì)對(duì)建模提到很大的幫助。
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1