爲了實現這一點,一下設計就是通過一個計數器,在計數器數到偶數的時候則輸出,計數器數到奇數的時候則輸入。代碼如下:*/
module spi_ctrl(
clk,rst_n,
spi_miso,spi_mosi,spi_clk,
spi_tx_en,spi_tx_rdy,spi_rx_en,spi_rx_rdy,spi_tx_db,spi_rx_db
);
input clk; //FPAG輸入時鐘信號50MHz
input rst_n; //FPGA輸入復位信號
input spi_miso; //SPI主機輸入從機輸出數據信號
output spi_mosi; //SPI主機輸出從機輸入數據信號
output spi_clk; //SPI時鐘信號,由主機產生
input spi_tx_en; //SPI數據發送使能信號,高有效
output spi_tx_rdy; //SPI數據發送完成標誌位,高有效
input spi_rx_en; //SPI數據接收使能信號,高有效
output spi_rx_rdy; //SPI數據接收完成標誌位,高有效
input [7:0]spi_tx_db; //SPI數據發送寄存器
output [7:0]spi_rx_db; //SPI數據接收寄存器
//模擬SPI的時序模式爲CPOL=1, CPHA=1,模擬速率爲50Mbit
//------------------------------------------------------
//SPI時序控制計數器,所有SPI時序由該計數器值控制
reg [4:0]cnt8; //SPI時序控制計數器,計數範圍在0-18
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt8 <= 5'd0;
else if(spi_tx_en || spi_rx_en) begin //SPI工作使能
if(cnt8 < 5'd18)
cnt8 <= cnt8 + 1'b1;
else cnt8<=cnt8; //計數到18停止,等待撤銷spi使能
end
else cnt8 <= 5'd0; //SPI關閉,計數停止
//--------------------------------------------------------
//SPI時鐘信號產生
reg spi_clkr; //SPI時鐘信號,由主機產生
always @(posedge clk or negedge rst_n)
if(!rst_n)
spi_clkr <= 1'b1; //spi時鐘只有在spi啓用過程中才有效
else if(cnt8>5'd1 && cnt8<5'd18)
spi_clkr <= ~spi_clkr;//在cnt8處於2-17時SPI時鐘有效翻轉
assign spi_clk = spi_clkr;
//-------------------------------------------------------
//SPI主機輸出數據控制
reg spi_mosir; //SPI主機輸出從機輸入數據信號
always @(posedge clk or negedge rst_n)
if(!rst_n) spi_mosir <= 1'b1;
else if(spi_tx_en) begin
case(cnt8[4:1]) //不判斷最低位,則數據在cnt8兩次加一後纔有一次變化,這裏剛好和接收的時鐘分開
4'd1: spi_mosir <= spi_tx_db[7]; //發送bit7 相當於cnt8=2
4'd2: spi_mosir <= spi_tx_db[6]; //發送bit6 相當於cnt8=4
4'd3: spi_mosir <= spi_tx_db[5]; //發送bit5 相當於cnt8=6
4'd4: spi_mosir <= spi_tx_db[4]; //發送bit4 相當於cnt8=8
4'd5: spi_mosir <= spi_tx_db[3]; //發送bit3 相當於cnt8=10
4'd6: spi_mosir <= spi_tx_db[2]; //發送bit2 相當於cnt8=12
4'd7: spi_mosir <= spi_tx_db[1]; //發送bit1 相當於cnt8=14
4'd8: spi_mosir <= spi_tx_db[0]; //發送bit0 相當於cnt8=16
default: spi_mosir <= 1'b1; //spi_mosi沒有輸出時應保持高電平
//如果這裏只是單純地使用cnt8的2、4、6..在default裏面有所不同,如果是246之類的那麼在357的時候default會有效,而本例中是無效的
endcase
end
else spi_mosir <= 1'b1; //spi_mosi沒有輸出時應保持高電平
assign spi_mosi = spi_mosir;
//---------------------------------------------------------------
//SPI主機輸入數據控制
reg [7:0]spi_rx_dbr; //SPI主機輸入從機輸出數據總線寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n) spi_rx_dbr <= 8'hff;
else if(spi_rx_en) begin
case(cnt8) //取cnt8的奇數,這樣可以和發送時鐘錯開
5'd3 : spi_rx_dbr[7] <= spi_miso; //接收bit7
5'd5 : spi_rx_dbr[6] <= spi_miso; //接收bit6
5'd7 : spi_rx_dbr[5] <= spi_miso; //接收bit5
5'd9 : spi_rx_dbr[4] <= spi_miso; //接收bit4
5'd11: spi_rx_dbr[3] <= spi_miso; //接收bit3
5'd13: spi_rx_dbr[2] <= spi_miso; //接收bit2
5'd15: spi_rx_dbr[1] <= spi_miso; //接收bit1
5'd17: spi_rx_dbr[0] <= spi_miso; //接收bit0
default: ; //區別上個always裏面的default,這裏也是無操作
endcase
end
assign spi_rx_db = spi_rx_dbr;
//-----------------------------------------------------------------
//SPI數據發送完成標誌位,高有效
assign spi_tx_rdy = (cnt8 == 5'd18);
//------------------------------------------------------------------
//SPI數據接收完成標誌位,高有效
assign spi_rx_rdy = (cnt8 == 5'd18);
endmodule