zoukankan      html  css  js  c++  java
  • spi master接口的fpga实现

    前言

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

    以上。

  • 相关阅读:
    小程序 循环遍历 传参数 获取参数的方法
    小程序技巧 盒子布局
    小程序的初体验
    python制作网易云免费下载器
    数据结构实验报告之三元组顺序存储的稀疏矩阵练习(代码版)
    JavaFX作业8
    用JavaFX显示一个转动的风扇
    用JavaFX模拟一个交通信号灯
    数据结构作业周三必交
    大数据的就业观与考研观
  • 原文地址:https://www.cnblogs.com/kingstacker/p/7490002.html
Copyright © 2011-2022 走看看