前言

当你器件的引脚贼少的时候,需要主机和从机通信,spi就派上了用场,它可以一对多,但只是片选到的从机能和主机通信,其他的挂机。

spi:serial peripheral interface 串行外围接口

大致了解:

spi master接口的fpga实现-LMLPHP

spi是个同步协议,数据在master和slaver间交换通过时钟sck,由于它是同步协议,时钟速率就可以各种变换。

sck:主机提供,从机不能操控,从器件由主机产生的时钟控制。数据只有在sck来了的上升沿或者下降沿才传输。

高级一点的spi芯片有配置寄存器,高级一点的工作有四种模式,采样相位和sck空闲电平可配置。

当然在这里我们主要实现简单的spi协议:sck是系统时钟的四分频,wr请求信号有效时,主机开始工作,数据位8bit,sck空闲时低电平,工作时第一个沿数据传输。只有一个从机,cs低电平片选。

spi master接口的fpga实现-LMLPHP

看下结构:

spi master接口的fpga实现-LMLPHP

接口定义:

spi master接口的fpga实现-LMLPHP

编码实现:(版权所有,请勿用于商业用途,仅供学习使用)

 //************************************************
 //  Filename      : spi_ms_test1.v
 //  Author        : Kingstacker
 //  Company       : School
 //  Email         : [email protected]
 //  Device        : Altera cyclone4 ep4ce6f17c8
 //  Description   : spi master module;data 8bit;sck is 4 div of the clk;
 //************************************************
 )(
     //input;
     input    wire    clk,
     input    wire    rst_n,
     input    wire    wr, //send request;
     :]    master_din, //the data you want send;
     input    wire    miso, //the data form slave;
     //output;
     output   reg     cs, //slave select;
     output   reg     sck, //data exchange clock;
     output   reg     mosi,    //master out;
     :]    master_dout //the data you received;
 );
 :] DIV_NUMBER = ;      //div number,you can change;
 ) - 'b1;  //max cnt number,6/2 -1 ;
 reg cnt; //sck cnt;
 reg sck_en; //enable sck;
 reg data_cnt_en;
 reg sck_reg1;
 reg sck_reg2;
 wire sck_p; //posedge sck;
 wire sck_n; //negedge sck;
 wire send_over;
 'b00;
 'b01;
 'b10;
 :] cstate;
 :] data_cnt; //cnt the send data;
 :] master_din_reg;
 :] master_dout_reg;
 :] mosi_cnt;
 //produce sck;
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         cnt <= ;
         sck <= 'b0;
     end //if
     else begin
         'b1) begin
             if (cnt == CNT_MAX) begin
                 cnt <= ;
                 sck <= ~sck;
             end
             else begin
                 cnt <= cnt + 'b1;
                 sck <= sck;
             end
         end
         else begin
             cnt <= ;
             sck <= 'b0;
         end
     end //else
 end //always
 //produce sck_p and sck_n;
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         sck_reg1 <= 'b0;
         sck_reg2 <= 'b0;
     end //if
     else begin
         sck_reg1 <= sck;
         sck_reg2 <= sck_reg1;
     end //else
 end //always
 assign sck_p = (sck_reg1 & (~sck_reg2)); //sck posedge;
 assign sck_n = ((~sck_reg1) & sck_reg2); //sck negedge;
 //fsm;hot code;
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         cstate <= IDEL;
     end
     else begin
         case (cstate)
             IDEL:    cstate <= (wr)? SEND : IDEL;
             SEND:    cstate <= (send_over) ? FINISH : SEND;
             FINISH:  cstate <= IDEL;
             default: cstate <= IDEL;
         endcase //case
     end
 end
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         cs <= 'b1;
         data_cnt_en <= 'b0;
         sck_en <= 'b0;
         master_din_reg <= ;
         master_dout <= ;
     end
     else begin
         case (cstate)
             IDEL: begin
             data_cnt_en <= 'b0;
             master_din_reg <= (wr) ? master_din : master_din_reg; //load the data you want send to slaver;
             end
             SEND: begin
                 data_cnt_en <= 'b1;
                 cs <= 'b0;
                 sck_en <= 'b1;
                 master_dout <= (send_over) ? master_dout_reg : master_dout; //master receiverd data;
             end
             FINISH: begin                  //send and load ok;
                 sck_en <= 'b0;
                 cs <= 'b1;
                 data_cnt_en <= 'b0;
             end
             default: begin
                 cs <= 'b1;
                 sck_en <= 'b0;
                 data_cnt_en <= 'b0;
             end
         endcase //case
     end
 end
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         data_cnt <= ;
     end
     else begin
         data_cnt <= (data_cnt_en) ? (data_cnt + 'b1) : 5'd0; //4 div * 8bit = 32 cnt;
     end
 end
 'b0;
 //rising edge miso;
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         master_dout_reg <= ;
     end
     else begin
         master_dout_reg <= (sck_p) ? {master_dout_reg[:],miso} : master_dout_reg;
     end
 end
 //miso;
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         mosi_cnt <= ;
     end
     else begin
         if (sck_n) begin
             'd7) begin
                 mosi_cnt <= ;
             end
             else begin
                 mosi_cnt <= mosi_cnt + 'b1;
             end
         end
         else begin
             mosi_cnt <= mosi_cnt;
         end
     end
 end
 always @(posedge clk or negedge rst_n) begin
     if (~rst_n) begin
         mosi <= 'b0;
     end
     else begin
         mosi <= (sck_n) ? master_din_reg['d7-mosi_cnt] : mosi;
     end
 end
 endmodule

仿真:

spi master接口的fpga实现-LMLPHP

综合资源使用:

spi master接口的fpga实现-LMLPHP

Fmax:

spi master接口的fpga实现-LMLPHP

以上。

04-24 21:21