天天看點

FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]一.SPI協定簡要介紹

FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]

一.SPI協定簡要介紹

SPI,是英語Serial Peripheral Interface的縮寫,顧名思義就是串行外圍裝置接口。SPI,是一種高速的,全雙工,同步的通信總線,并且在晶片的管腳上隻占用四根線,節約了晶片的管腳,同時為PCB的布局上節省空間,提供友善,正是出于這種簡單易用的特性,現在越來越多的晶片內建了這種通信協定。

  SPI總線是Motorola公司推出的三線同步接口,同步串行3線方式進行通信:一條時鐘線SCK,一條資料輸入線MOSI,一條資料輸出線MISO;用于 CPU與各種外圍器件進行全雙工、同步串行通訊。SPI主要特點有:可以同時發出和接收串行資料;可以當作主機或從機工作;提供頻率可程式設計時鐘;發送結束中斷标志;寫沖突保護;總線競争保護等。

SPI總線有四種工作方式(SP0, SP1, SP2, SP3),其中使用的最為廣泛的是SPI0和SPI3方式。SPI子產品為了和外設進行資料交換,根據外設工作要求,其輸出串行同步時鐘極性和相位可以進行配置,時鐘極性(CPOL)對傳輸協定沒有重大的影響。如果CPOL=0,串行同步時鐘的空閑狀态為低電平;如果CPOL=1,串行同步時鐘的空閑狀态為高電平。時鐘相位(CPHA)能夠配置用于選擇兩種不同的傳輸協定之一進行資料傳輸。如果 CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)資料被采樣;如果CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)資料被采樣。

SPI主子產品和與之通信的外設時鐘相位和極性應該一緻。

以下是SPI時序圖:

FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]一.SPI協定簡要介紹

   主要講解一下廣泛使用的兩種方式設定:

SPI0方式:CPOL=0,CPHA=0;SCK空閑狀态為低電平,第一個跳變沿(上升沿)采樣資料,無論對Master還是Slaver都是如此。

SPI3方式:CPOL=1,CPHA=1;SCK空閑狀态為高電平,第二個跳變沿(上升沿采樣資料,無論對Master還是Slaver都是如此。

其實對于SPI0和SPI1發送與接收資料,可以總結為一句話:上升沿采樣資料,下降沿發送資料。全雙工同時進行,當然,必須在CS拉低使能情況下。

二.FPGA作為Slaver實作SPI3方式與STM32通信

1.STM32方面:用庫函數配置SPI1,設定CPOL=1,CPHA=1.

2.FPGA方面:

(1)通過邊沿檢測技術得出SCK上升沿與下降沿标志,用于下面狀态機中的資料采樣及發送。

(2)根據時序圖,采用2個狀态機分别在SCK上升沿實作資料采樣,下降沿實作資料發送。無論是采樣還是發送,都是高位在前,從Bit[7]到Bit[0],共8位資料。

(3)最後通過邊沿檢測技術得出資料采樣完成标志,用于使用者操作。

以下是SPI3的時序圖:

FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]一.SPI協定簡要介紹

三.Verilog代碼部分

測試工程代碼:實作了STM32每隔200ms發送流水燈資料給FPGA,使FPGA系統闆上的4個LED燈實作流水操作;同時,FPGA每隔1s發送計數資料給STM32,并在STM32系統闆上的LCD屏出來,即:顯示0-9循環計數。

但下面的代碼隻是SPI作為從機的驅動部分,包括SPI發送資料與接收資料。

1 /***********************************************************************
  2      ****************** name:SPI_Slaver_Driver **************
  3             ********** author:made by zzuxzt **********
  4      ****************** time:2014.4.29 **********************
  5 ***********************************************************************/
  6 //use SPI 3 mode,CHOL = 1,CHAL = 1
  7 module spi(input clk,
  8               input rst_n,
  9               input CS_N,
 10               input SCK,
 11               input MOSI,
 12               input [7:0] txd_data,
 13               output reg MISO,
 14               output reg [7:0] rxd_data,
 15               output rxd_flag);   //recieve done,please transmit data
 16 
 17 //-------------------------capture the sck-----------------------------          
 18 reg sck_r0,sck_r1;
 19 wire sck_n,sck_p;
 20 always@(posedge clk or negedge rst_n)
 21 begin
 22     if(!rst_n)
 23         begin
 24             sck_r0 <= 1'b1;   //sck of the idle state is high 
 25             sck_r1 <= 1'b1;
 26         end
 27     else
 28         begin
 29             sck_r0 <= SCK;
 30             sck_r1 <= sck_r0;
 31         end
 32 end
 33 
 34 assign sck_n = (~sck_r0 & sck_r1)? 1'b1:1'b0;   //capture the sck negedge
 35 assign sck_p = (~sck_r1 & sck_r0)? 1'b1:1'b0;   //capture the sck posedge
 36 
 37 //-----------------------spi_slaver read data-------------------------------
 38 reg rxd_flag_r;
 39 reg [2:0] rxd_state;
 40 always@(posedge clk or negedge rst_n)
 41 begin
 42     if(!rst_n)
 43         begin
 44             rxd_data <= 1'b0;
 45             rxd_flag_r <= 1'b0;
 46             rxd_state <= 1'b0;
 47         end
 48     else if(sck_p && !CS_N)   
 49         begin
 50             case(rxd_state)
 51                 3'd0:begin
 52                         rxd_data[7] <= MOSI;
 53                         rxd_flag_r <= 1'b0;   //reset rxd_flag
 54                         rxd_state <= 3'd1;
 55                       end
 56                 3'd1:begin
 57                         rxd_data[6] <= MOSI;
 58                         rxd_state <= 3'd2;
 59                       end
 60                 3'd2:begin
 61                         rxd_data[5] <= MOSI;
 62                         rxd_state <= 3'd3;
 63                       end
 64                 3'd3:begin
 65                         rxd_data[4] <= MOSI;
 66                         rxd_state <= 3'd4;
 67                       end
 68                 3'd4:begin
 69                         rxd_data[3] <= MOSI;
 70                         rxd_state <= 3'd5;
 71                       end
 72                 3'd5:begin
 73                         rxd_data[2] <= MOSI;
 74                         rxd_state <= 3'd6;
 75                       end
 76                 3'd6:begin
 77                         rxd_data[1] <= MOSI;
 78                         rxd_state <= 3'd7;
 79                       end
 80                 3'd7:begin
 81                         rxd_data[0] <= MOSI;
 82                         rxd_flag_r <= 1'b1;  //set rxd_flag
 83                         rxd_state <= 3'd0;
 84                       end
 85                 default: ;
 86             endcase
 87         end
 88 end
 89 
 90 
 91 //--------------------capture spi_flag posedge--------------------------------
 92 reg rxd_flag_r0,rxd_flag_r1;
 93 always@(posedge clk or negedge rst_n)
 94 begin
 95     if(!rst_n)
 96         begin
 97             rxd_flag_r0 <= 1'b0;
 98             rxd_flag_r1 <= 1'b0;
 99         end
100     else
101         begin
102             rxd_flag_r0 <= rxd_flag_r;
103             rxd_flag_r1 <= rxd_flag_r0;
104         end
105 end
106 
107 assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 1'b1:1'b0;   
108 
109 //---------------------spi_slaver send data---------------------------
110 reg [2:0] txd_state;
111 always@(posedge clk or negedge rst_n)
112 begin
113     if(!rst_n)
114         begin
115             txd_state <= 1'b0;
116         end
117     else if(sck_n && !CS_N)
118         begin
119             case(txd_state)
120                 3'd0:begin
121                         MISO <= txd_data[7];
122                         txd_state <= 3'd1;
123                       end
124                 3'd1:begin
125                         MISO <= txd_data[6];
126                         txd_state <= 3'd2;
127                       end
128                 3'd2:begin
129                         MISO <= txd_data[5];
130                         txd_state <= 3'd3;
131                       end
132                 3'd3:begin
133                         MISO <= txd_data[4];
134                         txd_state <= 3'd4;
135                       end
136                 3'd4:begin
137                         MISO <= txd_data[3];
138                         txd_state <= 3'd5;
139                       end
140                 3'd5:begin
141                         MISO <= txd_data[2];
142                         txd_state <= 3'd6;
143                       end
144                 3'd6:begin
145                         MISO <= txd_data[1];
146                         txd_state <= 3'd7;
147                       end
148                 3'd7:begin
149                         MISO <= txd_data[0];
150                         txd_state <= 3'd0;
151                       end
152                 default: ;
153             endcase
154         end
155 end
156 
157 endmodule      

六.Modelsim仿真圖

FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]一.SPI協定簡要介紹
FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]FPGA作為從機與STM32進行SPI協定通信---Verilog實作 [轉]一.SPI協定簡要介紹