基於FPGA的SPI協議及設計實現

基於FPGA的SPI協議及設計實現

博主微信:flm13724054952,不懂的有疑惑的也可以加微信諮詢,歡迎大家前來投稿,謝謝!

引言介紹

在電子通信領域裏採用的通信協議有IIC,SPI,UART,FSMC等協議。本文將基於FPGA來介紹並設計標準的SPI總線協議,實現FPGA與MCU的數據通信。SPI是英語Serial Peripheral Interface的縮寫,顧名思義就是串行外圍設備接口。SPI是一種高速的、全雙工、同步通信總線,標準的SPI也僅僅使用4個引腳,常用於FPGA和 EEPROM、FLASH、數字信號處理器等器件的數據通信。

SPI的原理介紹

SPI的通信方式是主從方式通信。這種模式通常只有一個主機和一個從機或者一個主機和多個從機;一般來說,標準的SPI協議是由4根線組成,分別是SSEL(從機片選使能信號,也寫作 SCS,CSB)、SCLK(串行時鐘,也寫作SCK)、MOSI(主機輸出從機輸入Master Output/Slave Input)和MISO(主機輸入從機輸出Master Input/Slave Output)。有的SPI接口芯片帶有中斷信號INT,也有的SPI接口芯片只作爲從機使用故只有MISO口,不過這裏本文將基於FPGA來介紹並設計標準的SPI總線協議。

SPI的標準接口

CSB:從設備片選使能信號。注意的是,如果從設備是低電平使能信號的有效話,當拉低這個引腳後,從設備就會被選中,主機和這個被選中的從機進行通信。如果從設備是高電平使能信號的有效話,當拉高這個引腳後,從設備就會被選中,主機和這個被選中的從機進行通信
(高低電平的使能信號對數據的採集捕捉有不同的影響,後面再做闡述介紹)。

SCLK:串行時鐘信號,由主機產生,和I2C通信的SCL類似。

MOSI:主機輸出從機輸入線,主機給從機發送指令或者數據的通道。

MISO:主機輸入從機輸出線,主機讀取從機的狀態或者數據的通道。

SPI的工作模式

SPI通信的工作模式根據CPOL,CPHA的狀態分爲四種通信工作模式。爲什麼根據CPOL,CPHA狀態可以有不同的通信模式呢?這裏就得介紹CPOL,CPHA的“含義”了。CPHA全稱爲Clock Polarity,就是時鐘的極性。時鐘的極性又是什麼?就是在SPI通信的整個過程中,分爲空閒時刻(在數據通信之前和之後的無工作狀態)和通信時刻,如果CPOL=1時,空閒狀態的SCLK就是高電平,如果 CPOL=0時,空閒狀態的SCLK就是低電平,那麼就是 CPOL=0。
在這裏插入圖片描述
CPHA的全稱爲Clock Phase,就是時鐘的相位。CPHA的狀態決定了主機輸出數據跟從機採集數據的“捕捉沿的上或下”,同步通信的一個特點就是所有數據的變化和採樣都是伴隨着時鐘沿進行的,也就是說數據總是在時鐘的邊沿附近變化或被採樣。而在一個時鐘週期裏面有下降沿跟上升沿,只是這兩個沿的先後並無規定。
那麼主機和從機要交換數據的時候,就會牽涉到一個問題:主機在什麼時刻輸出數據到MOSI上而從機在什麼時刻採樣這個數據?如果主機在上升沿輸出數據到MOSI上,從機就只能在下降沿去採樣這個數據了。反之如果一方在下降沿輸出數據,那麼另一方就必須在上升沿採樣這個數據。
CPHA=1:表示數據的輸出是在一個時鐘週期的第一個沿上,而數據的採集是在第二個沿上。
至於這個沿是上升沿還是下降沿,這要視CPOL的值而定,CPOL=1 那就是數據輸出在下降沿,數據採集在第二個沿(上升沿);反之CPOL=0時那就是數據輸出在上升沿,數據採集在下降沿(第二個沿)。
CPHA=0:表示數據的採樣是在一個時鐘週期的第一個沿上,而數據的輸出是在第二個沿上。
同樣它是什麼沿由 CPOL 決定。CPOL=1的時候那就是數據採集在下降沿,數據輸出在上升沿(第二個沿);反之CPOL=0的時候那就是數據採集在上升沿,數據輸出在下降沿(第二個沿)。
仔細想一下,這裏會有一個問題:就是當一幀數據開始傳輸第一個 bit 時,在第一個時鐘沿上就採樣該數據了,那麼它是在什麼時候輸出來的呢?有兩種情況:一是 SSEL 使能的邊沿,二是上一幀數據的最後一個時鐘沿,或者兩種都有可能。

SPI的工作時序

從上面的分析介紹可以得到,SPI通信中根據CPOL,CPHA的狀態有四種工作時序。下面來介紹SPI的四種工作時序的不同情況,來深入體會SPI協議的設計原理。例如下圖爲CPOL=0,CPHA=0情況下的SPI工作時序,從下圖可以看得出,在空閒狀態下(數據的發送前跟數據的接收後)SCK的時鐘爲低電平,因此CPOL爲0。數據流在上升沿(第一個沿)被先採集,再在下降沿被輸出(第二個沿),因此CPHA=0;這種工作時序的好處就是數據先採集再輸出,就可以保證在一個讀寫週期裏面可以先讀寫完一個完整的數據流,而不用被延遲到下一個讀寫週期裏面。保證了信號的完整性。
在這裏插入圖片描述
下圖爲CPOL=0,CPHA=1情況下的SPI工作時序,從下圖可以看得出,在空閒狀態下(數據的發送前跟數據的接收後)SCK的時鐘爲低電平,因此CPOL爲0。數據流在上升沿(第一個沿)先輸出,再在下降沿被採集(第二個沿),因此CPHA=1;這種工作時序就是數據先輸出再採集,從下圖就可以就可以看得出,在一個讀寫週期裏面,一個數據流也可以被完整採集到,但是由於先輸出(在一個週期裏面)會導致輸出的第一個數據爲上一個數據流的。這樣子有一個隱患會造成數據流的不完整。
在這裏插入圖片描述
剩下的兩種工作時序如下圖所示,這裏不再做詳細介紹。
在這裏插入圖片描述

MCU_SPI的設計實現

本文的設計是基於CPOL=0,CPHA=0情況下的SPI工作時序,時序圖如下所示:
在這裏插入圖片描述
本文的設計架構如下所示,主機通過SPI協議的sdata_in寫入地址跟數據,對ram的寄存器進行寫數據控制,通過SPI協議的sdata_out讀取了從機mcu_ram的相應地址的寄存器數據。所以本文的設計主要有兩部分一個是SPI傳輸協議,一個是MCU_RAM存儲器。這裏重點介紹SPI協議的設計實現。ram的設計只是爲了更好的驗證SPI協議的傳輸功能。
在這裏插入圖片描述

SPI的設計實現

SPI的端口設計如下所示,主機通過SPI的sdata_in將數據寫入到中間寄存器reg_data_shift,再通過產生的wr_flag寫入使能信號將相應地址reg_addr_shift的寄存器數據寫入到mcu_ram裏面。從機想將數據傳輸到主機時,可讀取ram的數據,通過sdata_out傳輸到主機上。從而構成了一個主從機寫入讀取數據的一個完整流程。
在這裏插入圖片描述

SPI的狀態機設計

正如上面所說的,對於一個主從機寫入讀取數據的一個完整流程,主要細分着其實有五個流程的
S0:判斷csb的狀態,是否啓動從機進行讀寫數據;
S1:判斷寫入還是讀取的流程;
S2:讀取主機傳輸的寄存器地址;
S3:將主機sdata_in傳輸過來的數據寫入到中間寄存器;
S4:將存儲在寄存器的數據讀取到sdata_out給主機。
對於一個主從機寫入讀取數據的一個完整流程,有一些人特意對寫數據跟讀數據設計成兩個模塊,進行數據交互,這裏本文采用狀態機的設計思路,不僅完成了讀取數據的整個流程,而且使整個流程設計更爲嚴謹簡單。
本文對SPI的狀態機設計如下所示:
在這裏插入圖片描述
在這裏插入圖片描述

SPI的讀寫設計

SPI的讀寫設計,可以來說就是按照狀態機的相應狀態從sdata_in寫入數據,讀取數據到sdata_out中。這裏注意的是我們從機對主機的數據採集都是上升沿採集數據,從下圖的設計也可以看的出來。
在這裏插入圖片描述
S0:判斷csb的狀態,是否啓動從機進行讀寫數據;此時各寄存器都爲復位到初始狀態。
S1:判斷是寫入還是讀取的流程;rd_flag=1是讀操作rd_flag=0是寫操作。在這裏插入圖片描述
S2:讀取主機傳輸的寄存器地址;將sdtaa_in寫入到地址寄存器reg_addr_shift。記住了要操作的地址寄存器。
S3:將主機sdata_in傳輸過來的數據寫入到中間寄存器reg_data_shift。
S4:將存儲在寄存器的數據讀取到sdata_out_po(即爲sdata_out)給主機。
在這裏插入圖片描述

MCU_RAM的設計實現

這裏是簡單設計一個存儲器mcu_ram進行數據的讀寫儲存,不做詳細介紹。
在這裏插入圖片描述

SPI的仿真驗證

這裏對MCU_SPI進行功能仿真驗證,設計兩個任務spi_wr,spi_rd。模仿testbench環境主機對從機mcu_spi進行讀寫數據。
如下面的功能仿真波形圖所示,先寫入地址reg_adr=3,reg_dat=56。可以看到當csb=0從機mcu_spi開始工作。在狀態1的時候先判斷讀寫,rd_flag=0,即爲寫操作。在狀態2的時候將地址reg_adr=3寫入到地址寄存器reg_addr_reg。完成寫地址後,進入狀態3將reg_dat=56寫入到中間寄存器reg_data_shift。完成了一個從機寫操作的流程。
當主機想讀取從機數據的時候,csb=0從機mcu_spi開始工作,狀態1的時候先判斷讀寫,rd_flag=1,即爲讀操作。在狀態2的時候將地址reg_adr=3寫入到地址寄存器reg_addr_reg。完成寫地址後,進入狀態4將存儲器的相應地址數據的ram_rd讀取到sdata_out。完成了一個讀取從機的流程。
在這裏插入圖片描述
如下面的功能仿真波形圖所示,先寫入地址reg_adr=3,reg_dat=56。可以看到當csb=0從機mcu_spi開始工作。在狀態1的時候先判斷讀寫,rd_flag=0,即爲寫操作。在狀態2的時候將地址reg_adr=3寫入到地址寄存器reg_addr_reg。完成寫地址後,進入狀態3將reg_dat=56寫入到中間寄存器reg_data_shift。完成了一個從機寫操作的流程的時候,會根據相應的地址將中間寄存器的數據寫入到存儲器mcu_ram的相應寄存器上去,等待讀取的時候被讀取。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章