明(míng)德揚專注于(yú)FPGA培訓:設有(yǒu) FPGA网(wǎng)絡班、FPGA就(jiù)業班
什麼(me)时(shí)候SPI
SPI是(shì)一(yī)个(gè)簡單的(de)接口(kǒu),允许一(yī)个(gè)芯片(piàn)與(yǔ)一(yī)个(gè)或(huò)多(duō)个(gè)其他(tā)芯片(piàn)通(tòng)信(xìn)。
讓我(wǒ)们(men)從一(yī)个(gè)簡單的(de)例子開(kāi)始,其中(zhōng)只(zhī)有(yǒu)两(liǎng)个(gè)芯片(piàn)必須通(tòng)信(xìn)在(zài)一(yī)起。
SPI需要(yào)在(zài)两(liǎng)片(piàn)芯片(piàn)之間(jiān)使用(yòng)4根(gēn)線(xiàn)。
正(zhèng)如(rú)您所(suǒ)看(kàn)到(dào)的(de),这(zhè)些線(xiàn)被(bèi)稱为(wèi)SCK、MOSI、MISO和(hé)Ssel,其中(zhōng)一(yī)个(gè)芯片(piàn)被(bèi)稱为(wèi)SPI主(zhǔ)芯片(piàn),而(ér)另(lìng)一(yī)个(gè)芯片(piàn)稱为(wèi)SPI從機(jī)。
SPI基礎
基本(běn)上(shàng):- 它(tā)是(shì)同(tóng)步的(de)。
- 是(shì)全(quán)双(shuāng)工系(xì)列。
- 这(zhè)不(bù)是(shì)即插即用(yòng)。
- 有(yǒu)一(yī)个(gè)(而(ér)且只(zhī)有(yǒu)一(yī)个(gè))主(zhǔ)人(rén)和(hé)一(yī)个(gè)(或(huò)更(gèng)多(duō))奴隸。
- 同(tóng)步:时(shí)鐘(zhōng)由(yóu)主(zhǔ)程序産生(shēng)。
- 全(quán)双(shuāng)工串行:數據(jù)被(bèi)串行化(huà),在(zài)每个(gè)时(shí)鐘(zhōng)周期(qī)內(nèi)每个(gè)方(fāng)向(xiàng)傳輸一(yī)位數據(jù),因(yīn)此(cǐ)使用(yòng)两(liǎng)条(tiáo)數據(jù)線(xiàn)(MOSI和(hé)MISO)。
- 不(bù)是(shì)即插即用(yòng):主(zhǔ)從双(shuāng)方(fāng)事(shì)先(xiān)知道(dào)通(tòng)信(xìn)的(de)细(xì)节(jié)(位順序、交換數據(jù)的(de)长度(dù)等)。
- 一(yī)个(gè)主(zhǔ)從:從不(bù)能(néng)發(fà)起通(tòng)信(xìn),只(zhī)有(yǒu)主(zhǔ)可(kě)以(yǐ)。奴隸傾听(tīng)并回(huí)應(yìng)。
簡單轉(zhuǎn)移
讓我(wǒ)们(men)假設主(zhǔ)從期(qī)望8位數據(jù)傳輸,首先(xiān)傳輸MSB。
下(xià)面(miàn)是(shì)一(yī)个(gè)8位數據(jù)傳輸的(de)外(wài)观。
MOSI行是(shì)“主(zhǔ)輸出(chū)”,MISO是(shì)“從輸出(chū)”。由(yóu)于(yú)SPI是(shì)全(quán)双(shuāng)工,两(liǎng)行同(tóng)时(shí)切(qiè)換,不(bù)同(tóng)的(de)數據(jù)從主(zhǔ)從和(hé)從到(dào)主(zhǔ)。
詳情(qíng)如(rú)下(xià):
- 主(zhǔ)從将ssel拉下(xià)来(lái),以(yǐ)指示通(tòng)信(xìn)正(zhèng)在(zài)啟動(dòng)(ssel处于(yú)低活動(dòng)狀态)。
- 主(zhǔ)開(kāi)關(guān)时(shí)鐘(zhōng)8次(cì),并在(zài)其MOSI線(xiàn)路(lù)上(shàng)發(fà)送8位數據(jù)。同(tóng)时(shí),它(tā)從MISO線(xiàn)路(lù)上(shàng)的(de)從站接收(shōu)8个(gè)數據(jù)位。
- 主(zhǔ)人(rén)拉起ssel表(biǎo)示轉(zhuǎn)移已經(jīng)結束(shù)。
如(rú)果(guǒ)主(zhǔ)機(jī)有(yǒu)多(duō)个(gè)8位數據(jù)要(yào)發(fà)送/接收(shōu),則只(zhī)有(yǒu)在(zài)完成(chéng)时(shí)才能(néng)繼續發(fà)送/接收(shōu)和(hé)取(qǔ)消斷言。
多(duō)个(gè)從機(jī)
SPI主(zhǔ)機(jī)可(kě)以(yǐ)通(tòng)过(guò)两(liǎng)種(zhǒng)方(fāng)式與(yǔ)多(duō)路(lù)從站進(jìn)行通(tòng)信(xìn):通(tòng)过(guò)并聯連(lián)接大多(duō)數信(xìn)号(hào)并添加ssel線(xiàn),或(huò)者(zhě)通(tòng)过(guò)将從機(jī)鍊(liàn)接起来(lái)。
使用(yòng)多(duō)条(tiáo)流線(xiàn)技術(shù),一(yī)次(cì)只(zhī)能(néng)激活一(yī)条(tiáo)流線(xiàn),而(ér)未被(bèi)選擇的(de)從線(xiàn)不(bù)能(néng)驅動(dòng)MISO線(xiàn)。
簡單实現(xiàn)
ARM处理器
为(wèi)了(le)有(yǒu)機(jī)会(huì)测試我(wǒ)们(men)新獲得的(de)SPI知識,我(wǒ)们(men)使用(yòng)薩克(kè)索-L董事(shì)会(huì)。它(tā)有(yǒu)ARM 7处理器(LPC 2138)和(hé)旋风FPGA(EP1C3),通(tòng)过(guò)SPI總(zǒng)線(xiàn)連(lián)接。
ARM用(yòng)作SPI主(zhǔ)電(diàn)路(lù),FPGA作为(wèi)SPI從機(jī)。Saxo-L ARM处理器实際上(shàng)有(yǒu)两(liǎng)个(gè)SPI接口(kǒu),一(yī)个(gè)稱为(wèi)SPI 0,另(lìng)一(yī)个(gè)稱为(wèi)SPI 1/SSP。它(tā)们(men)都同(tóng)樣(yàng)容易使用(yòng)。我(wǒ)们(men)在(zài)Saxo-L上(shàng)使用(yòng)SPI 1/SSP,因(yīn)为(wèi)它(tā)是(shì)預先(xiān)連(lián)接在(zài)板上(shàng)的(de)。
SPI主(zhǔ)C ARM代(dài)碼
使用(yòng)SSP只(zhī)是(shì)初始化(huà)幾(jǐ)个(gè)寄存器,然後(hòu)写入(rù)/读(dú)取(qǔ)數據(jù)以(yǐ)自(zì)動(dòng)發(fà)送/接收(shōu)。.
void main(void) { // initialize SSP SSP0CPSR = 0x02; // SSP max speed SSP0CR0 = 0x07; // SSP max speed, 8 bits SSP0CR1 = 0x02; // SSP master mode PINSEL1 = 0x2A8; // SSP mode for pins P0.17 to P0.20 while(1) { // send two bytes SSP0DR = 0x55; // one nice thing about the SSP is that it has a 8-words deep FIFO SSP0DR = 0x54; // so here we write the data to be sent without worrying // now wait until both bytes are sent while(!(SSP0SR & 0x01)); // now we can read the two bytes received... and do anything with them int data1 = SSP0DR; int data2 = SSP0DR; // ... } }SPI從HDL FPGA碼
現(xiàn)在(zài)用(yòng)于(yú)FPGA中(zhōng)的(de)SPI從站。
由(yóu)于(yú)SPI總(zǒng)線(xiàn)通(tòng)常比FPGA工作时(shí)鐘(zhōng)慢(màn)得多(duō),所(suǒ)以(yǐ)我(wǒ)们(men)選擇使用(yòng)FPGA时(shí)鐘(zhōng)对(duì)SPI總(zǒng)線(xiàn)進(jìn)行过(guò)采樣(yàng)。这(zhè)使得從代(dài)碼稍微複雜一(yī)些,但它(tā)的(de)优點(diǎn)是(shì)在(zài)FPGA时(shí)鐘(zhōng)域中(zhōng)運行SPI邏輯,这(zhè)将使以(yǐ)後(hòu)的(de)工作變(biàn)得更(gèng)容易。
首先(xiān)是(shì)模块(kuài)聲明(míng)。
moduleSPI_slave(clk, SCK, MOSI, MISO, SSEL, LED);inputclk;inputSCK, SSEL, MOSI;outputMISO;outputLED;請注意(yì),我(wǒ)们(men)有(yǒu)“CLK”(FPGA时(shí)鐘(zhōng))和(hé)一(yī)个(gè)LED輸出(chū)。一(yī)个(gè)不(bù)錯的(de)調試工具。“CLK”需要(yào)比SPI總(zǒng)線(xiàn)更(gèng)快(kuài)。Saxo-L的(de)默認时(shí)鐘(zhōng)为(wèi)24 MHz,在(zài)这(zhè)里(lǐ)工作得很好(hǎo)。
我(wǒ)们(men)使用(yòng)FPGA时(shí)鐘(zhōng)和(hé)移位寄存器对(duì)SPI信(xìn)号(hào)(SCK、SSEL和(hé)MOSI)進(jìn)行采樣(yàng)/同(tóng)步。
// sync SCK to the FPGA clock using a 3-bits shift registerreg[2:0] SCKr;always@(posedgeclk) SCKr <= {SCKr[1:0], SCK};wireSCK_risingedge = (SCKr[2:1]==2'b01); // now we can detect SCK rising edgeswireSCK_fallingedge = (SCKr[2:1]==2'b10); // and falling edges // same thing for SSELreg[2:0] SSELr;always@(posedgeclk) SSELr <= {SSELr[1:0], SSEL};wireSSEL_active = ~SSELr[1]; // SSEL is active lowwireSSEL_startmessage = (SSELr[2:1]==2'b10); // message starts at falling edgewireSSEL_endmessage = (SSELr[2:1]==2'b01); // message stops at rising edge // and for MOSIreg[1:0] MOSIr;always@(posedgeclk) MOSIr <= {MOSIr[0], MOSI};wireMOSI_data = MOSIr[1];現(xiàn)在(zài)從SPI總(zǒng)線(xiàn)接收(shōu)數據(jù)很容易。
// we handle SPI in 8-bits format, so we need a 3 bits counter to count the bits as they come inreg[2:0] bitcnt;regbyte_received; // high when a byte has been receivedreg[7:0] byte_data_received;always@(posedgeclk)beginif(~SSEL_active) bitcnt <= 3'b000;elseif(SCK_risingedge)beginbitcnt <= bitcnt + 3'b001; // implement a shift-left register (since we receive the data MSB first) byte_data_received <= {byte_data_received[6:0], MOSI_data};endendalways@(posedgeclk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111); // we use the LSB of the data received to control an LEDregLED;always@(posedgeclk)if(byte_received) LED <= byte_data_received[0];最(zuì)後(hòu)是(shì)傳輸部(bù)分(fēn)。
reg[7:0] byte_data_sent;reg[7:0] cnt;always@(posedgeclk)if(SSEL_startmessage) cnt<=cnt+8'h1; // count the messagesalways@(posedgeclk)if(SSEL_active)beginif(SSEL_startmessage) byte_data_sent <= cnt; // first byte sent in a message is the message countelseif(SCK_fallingedge)beginif(bitcnt==3'b000) byte_data_sent <= 8'h00; // after that, we send 0selsebyte_data_sent <= {byte_data_sent[6:0], 1'b0};endendassignMISO = byte_data_sent[7]; // send MSB first // we assume that there is only one slave on the SPI bus // so we don't bother with a tri-state buffer for MISO // otherwise we would need to tri-state MISO when SSEL is inactiveendmodule我(wǒ)们(men)已經(jīng)建立了(le)ARM和(hé)FPGA之間(jiān)的(de)通(tòng)信(xìn)!
運行代(dài)碼
當我(wǒ)们(men)通(tòng)过(guò)ARM代(dài)碼时(shí),我(wǒ)们(men)可(kě)以(yǐ)看(kàn)到(dào)LED的(de)變(biàn)化(huà)狀态,以(yǐ)及(jí)FPGA返回(huí)的(de)數據(jù)。















