前言
當你器件的引腳賊少的時候,需要主機和從機通信,spi就派上了用場,它可以一對多,但只是片選到的從機能和主機通信,其他的掛機。
spi:serial peripheral interface 串行外圍接口
大致了解:
spi是個同步協議,數據在master和slaver間交換通過時鐘sck,由于它是同步協議,時鐘速率就可以各種變換。
sck:主機提供,從機不能操控,從器件由主機產生的時鐘控制。數據只有在sck來了的上升沿或者下降沿才傳輸。
高級一點的spi芯片有配置寄存器,高級一點的工作有四種模式,采樣相位和sck空閑電平可配置。
當然在這里我們主要實現簡單的spi協議:sck是系統時鐘的四分頻,wr請求信號有效時,主機開始工作,數據位8bit,sck空閑時低電平,工作時第一個沿數據傳輸。只有一個從機,cs低電平片選。
看下結構:
接口定義:
編碼實現:(版權所有,請勿用于商業用途,僅供學習使用)
1 //************************************************ 2 // Filename : spi_ms_test1.v 3 // Author : Kingstacker 4 // Company : School 5 // Email : kingstacker_work@163.com 6 // Device : Altera cyclone4 ep4ce6f17c8 7 // Description : spi master module;data 8bit;sck is 4 div of the clk; 8 //************************************************ 9 module spi_ms #(parameter WIDTH = 8)( 10 //input; 11 input wire clk, 12 input wire rst_n, 13 input wire wr, //send request; 14 input wire [WIDTH-1:0] master_din, //the data you want send; 15 input wire miso, //the data form slave; 16 //output; 17 output reg cs, //slave select; 18 output reg sck, //data exchange clock; 19 output reg mosi, //master out; 20 output reg [WIDTH-1:0] master_dout //the data you received; 21 ); 22 localparam CLK_HZ = 50_000_000; //clk frequency; 23 localparam SCK_HZ = 12_500_000; //sck frequency; 24 localparam DIV_NUMBER = CLK_HZ / SCK_HZ; 25 localparam CNT_MAX = (DIV_NUMBER >>1) - 1'b1; 26 localparam DATA_CNT_MAX = 5'd31; 27 localparam MOSI_CNT_MAX = 3'd7; 28 localparam IDEL = 2'b00; 29 localparam SEND = 2'b01; 30 localparam FINISH = 2'b10; 31 reg cnt; //sck cnt; 32 reg sck_en; //enable sck; 33 reg data_cnt_en; 34 reg sck_reg1; 35 reg sck_reg2; 36 wire sck_p; //posedge sck; 37 wire sck_n; //negedge sck; 38 wire send_over; 39 reg [1:0] cstate; 40 reg [4:0] data_cnt; //cnt the send data; 41 reg [2:0] mosi_cnt; 42 reg [WIDTH-1:0] master_din_reg; 43 reg [WIDTH-1:0] master_dout_reg; 44 //produce sck; 45 always @(posedge clk or negedge rst_n) begin 46 if (~rst_n) begin 47 cnt <= 0; 48 sck <= 1'b0; 49 end //if 50 else begin 51 if (sck_en == 1'b1) begin 52 if (cnt == CNT_MAX) begin 53 cnt <= 0; 54 sck <= ~sck; 55 end 56 else begin 57 cnt <= cnt + 1'b1; 58 sck <= sck; 59 end 60 end 61 else begin 62 cnt <= 0; 63 sck <= 1'b0; 64 end 65 end //else 66 end //always 67 //produce sck_p and sck_n; 68 always @(posedge clk or negedge rst_n) begin 69 if (~rst_n) begin 70 sck_reg1 <= 1'b0; 71 sck_reg2 <= 1'b0; 72 end //if 73 else begin 74 sck_reg1 <= sck; 75 sck_reg2 <= sck_reg1; 76 end //else 77 end //always 78 assign sck_p = (sck_reg1 & (~sck_reg2)); //sck posedge; 79 assign sck_n = ((~sck_reg1) & sck_reg2); //sck negedge; 80 //fsm;hot code; 81 always @(posedge clk or negedge rst_n) begin 82 if (~rst_n) begin 83 cstate <= IDEL; 84 end 85 else begin 86 case (cstate) 87 IDEL: cstate <= (wr)? SEND : IDEL; 88 SEND: cstate <= (send_over) ? FINISH : SEND; 89 FINISH: cstate <= IDEL; 90 default: cstate <= IDEL; 91 endcase //case 92 end 93 end 94 always @(posedge clk or negedge rst_n) begin 95 if (~rst_n) begin 96 cs <= 1'b1; 97 data_cnt_en <= 1'b0; 98 sck_en <= 1'b0; 99 master_din_reg <= 0; 100 master_dout <= 0; 101 end 102 else begin 103 case (cstate) 104 IDEL: begin 105 data_cnt_en <= 1'b0; 106 master_din_reg <= (wr) ? master_din : master_din_reg; //load the data you want send to slaver; 107 end 108 SEND: begin 109 data_cnt_en <= 1'b1; 110 cs <= 1'b0; 111 sck_en <= 1'b1; 112 master_dout <= (send_over) ? master_dout_reg : master_dout; //master receiverd data; 113 end 114 FINISH: begin //send and load ok; 115 sck_en <= 1'b0; 116 cs <= 1'b1; 117 data_cnt_en <= 1'b0; 118 end 119 default: begin 120 cs <= 1'b1; 121 sck_en <= 1'b0; 122 data_cnt_en <= 1'b0; 123 end 124 endcase //case 125 end 126 end 127 always @(posedge clk or negedge rst_n) begin 128 if (~rst_n) begin 129 data_cnt <= 0; 130 end 131 else begin 132 data_cnt <= (data_cnt_en) ? (data_cnt + 1'b1) : 5'd0; //4 div * 8bit = 32 cnt; 133 end 134 end 135 assign send_over = (data_cnt == DATA_CNT_MAX) ? 1'b1 : 1'b0; 136 //rising edge miso; 137 always @(posedge clk or negedge rst_n) begin 138 if (~rst_n) begin 139 master_dout_reg <= 0; 140 end 141 else begin 142 master_dout_reg <= (sck_p) ? {master_dout_reg[6:0],miso} : master_dout_reg; 143 end 144 end 145 //mosi; 146 always @(posedge clk or negedge rst_n) begin 147 if (~rst_n) begin 148 mosi_cnt <= 0; 149 end 150 else begin 151 if (sck_n) begin 152 if (mosi_cnt == MOSI_CNT_MAX) begin 153 mosi_cnt <= 0; 154 end 155 else begin 156 mosi_cnt <= mosi_cnt + 1'b1; 157 end 158 end 159 else begin 160 mosi_cnt <= mosi_cnt; 161 end 162 end 163 end 164 always @(posedge clk or negedge rst_n) begin 165 if (~rst_n) begin 166 mosi <= 1'b0; 167 end 168 else begin 169 mosi <= (sck_n) ? master_din_reg[MOSI_CNT_MAX-mosi_cnt] : mosi; 170 end 171 end 172 endmodule
仿真:
綜合資源使用:
Fmax:
以上。
-
FPGA
+關注
關注
1629文章
21729瀏覽量
602986 -
接口
+關注
關注
33文章
8575瀏覽量
151015 -
SPI
+關注
關注
17文章
1706瀏覽量
91502
原文標題:spi master接口的fpga實現
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論