前言
当你器件的引脚贼少的时候,需要主机和从机通信,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:
以上。