前言
当你器件的引脚贼少的时候,需要主机和从机通信,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 : [email protected] 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 [2:0] DIV_NUMBER = 4; //div number,you can change; 23 localparam CNT_MAX = (DIV_NUMBER >>1) - 1‘b1; //max cnt number,6/2 -1 ; 24 reg cnt; //sck cnt; 25 reg sck_en; //enable sck; 26 reg data_cnt_en; 27 reg sck_reg1; 28 reg sck_reg2; 29 wire sck_p; //posedge sck; 30 wire sck_n; //negedge sck; 31 wire send_over; 32 localparam IDEL = 2‘b00; 33 localparam SEND = 2‘b01; 34 localparam FINISH = 2‘b10; 35 reg [1:0] cstate; 36 reg [4:0] data_cnt; //cnt the send data; 37 reg [7:0] master_din_reg; 38 reg [7:0] master_dout_reg; 39 reg [2:0] mosi_cnt; 40 //produce sck; 41 always @(posedge clk or negedge rst_n) begin 42 if (~rst_n) begin 43 cnt <= 0; 44 sck <= 1‘b0; 45 end //if 46 else begin 47 if (sck_en == 1‘b1) begin 48 if (cnt == CNT_MAX) begin 49 cnt <= 0; 50 sck <= ~sck; 51 end 52 else begin 53 cnt <= cnt + 1‘b1; 54 sck <= sck; 55 end 56 end 57 else begin 58 cnt <= 0; 59 sck <= 1‘b0; 60 end 61 end //else 62 end //always 63 //produce sck_p and sck_n; 64 always @(posedge clk or negedge rst_n) begin 65 if (~rst_n) begin 66 sck_reg1 <= 1‘b0; 67 sck_reg2 <= 1‘b0; 68 end //if 69 else begin 70 sck_reg1 <= sck; 71 sck_reg2 <= sck_reg1; 72 end //else 73 end //always 74 assign sck_p = (sck_reg1 & (~sck_reg2)); //sck posedge; 75 assign sck_n = ((~sck_reg1) & sck_reg2); //sck negedge; 76 //fsm;hot code; 77 always @(posedge clk or negedge rst_n) begin 78 if (~rst_n) begin 79 cstate <= IDEL; 80 end 81 else begin 82 case (cstate) 83 IDEL: cstate <= (wr)? SEND : IDEL; 84 SEND: cstate <= (send_over) ? FINISH : SEND; 85 FINISH: cstate <= IDEL; 86 default: cstate <= IDEL; 87 endcase //case 88 end 89 end 90 always @(posedge clk or negedge rst_n) begin 91 if (~rst_n) begin 92 cs <= 1‘b1; 93 data_cnt_en <= 1‘b0; 94 sck_en <= 1‘b0; 95 master_din_reg <= 0; 96 master_dout <= 0; 97 end 98 else begin 99 case (cstate) 100 IDEL: begin 101 data_cnt_en <= 1‘b0; 102 master_din_reg <= (wr) ? master_din : master_din_reg; //load the data you want send to slaver; 103 end 104 SEND: begin 105 data_cnt_en <= 1‘b1; 106 cs <= 1‘b0; 107 sck_en <= 1‘b1; 108 master_dout <= (send_over) ? master_dout_reg : master_dout; //master receiverd data; 109 end 110 FINISH: begin //send and load ok; 111 sck_en <= 1‘b0; 112 cs <= 1‘b1; 113 data_cnt_en <= 1‘b0; 114 end 115 default: begin 116 cs <= 1‘b1; 117 sck_en <= 1‘b0; 118 data_cnt_en <= 1‘b0; 119 end 120 endcase //case 121 end 122 end 123 always @(posedge clk or negedge rst_n) begin 124 if (~rst_n) begin 125 data_cnt <= 0; 126 end 127 else begin 128 data_cnt <= (data_cnt_en) ? (data_cnt + 1‘b1) : 5‘d0; //4 div * 8bit = 32 cnt; 129 end 130 end 131 assign send_over = (data_cnt == 5‘d31) ? 1‘b1 : 1‘b0; 132 //rising edge miso; 133 always @(posedge clk or negedge rst_n) begin 134 if (~rst_n) begin 135 master_dout_reg <= 0; 136 end 137 else begin 138 master_dout_reg <= (sck_p) ? {master_dout_reg[6:0],miso} : master_dout_reg; 139 end 140 end 141 //miso; 142 always @(posedge clk or negedge rst_n) begin 143 if (~rst_n) begin 144 mosi_cnt <= 0; 145 end 146 else begin 147 if (sck_n) begin 148 if (mosi_cnt == 3‘d7) begin 149 mosi_cnt <= 0; 150 end 151 else begin 152 mosi_cnt <= mosi_cnt + 1‘b1; 153 end 154 end 155 else begin 156 mosi_cnt <= mosi_cnt; 157 end 158 end 159 end 160 always @(posedge clk or negedge rst_n) begin 161 if (~rst_n) begin 162 mosi <= 1‘b0; 163 end 164 else begin 165 mosi <= (sck_n) ? master_din_reg[3‘d7-mosi_cnt] : mosi; 166 end 167 end 168 endmodule
仿真:
综合资源使用:
Fmax:
以上。
时间: 2024-10-10 22:28:26