FPGA通讯协议学习实践1- SPI协议

1、前言

  在具体的通信项目中,CPOL,CPHA可能就是固定不变的,发送/采集数据位宽也可能是固定不变的,那样的话,项目做起来就会很简单了(以前使用序列机实现的)。我自己实践的时候,是假设这些东西是可变的,所以就把这个事情就搞得很复杂了。当然,复杂的原因这只是其一,更多的可能是自己没太多经验与智慧吧。

  作为新手,肯定是有很多不完善的地方,所以仅供参考,如果有误,可以加我Q1011090284,我会更改。

2、系统功能

  a、可设置 CPOL(Clock  Polarity)时钟极性——配置SCLK空闲态状态,CPOL(Clock  Phase)时钟相位——配置数据采样在第1个/第2个边沿。

  b、可设置通信频率;

  c、可配置发送/采集数据位宽

3、模块划分

  将SPI通讯模块划分成以下模块:

  •        时钟模块
  •   数据采集模块
  •   数据发送模块
  •   控制模块

  

 

 

4、模块细化

  a.时钟模块:

    功能:

      1) 输出SPI_SCK时钟信号。预设了14种不同的时钟频率可供选择。默认1KHz

      2) 读取CPOL(Clock  Polarity)时钟极性——配置SCK空闲态状态。

      3 )  输出SCK_Posedge、SCK_Negedge信号,供采集/发送模块使用

      4) 采集结束之后,延迟半个采集时钟周期(要少6个系统时钟周期),给上层发送SPI通信结束信号

 

 

   代码如下

  1 /***************************************************
  2 *    Module Name        :    SPI_Clk_Module           
  3 *    Engineer           :    王小虎
  4 *    Target Device     :    EP4CE10F17C8 50MHZ时钟频率
  5 *    Tool versions     :    Quartus II 13.0
  6 *    Create Date        :    2019
  7 *    Revision           :    v1.0
  8 *    Description        :  1、SPI通讯SCK时钟信号输出(可选频率)
  9                          2、SCK_Posedge、SCK_Negedge标志位输出
 10 **************************************************/
 11 module SPI_Clk_Module(
 12    clk,
 13    rst_n,
 14    SPI_SCK_EN,
 15    SPI_SCK_STOP,
 16    SPI_SCK_Freq_Sel,
 17    SPI_SCK_CPOL,
 18    SCK_Posedge,
 19    SCK_Negedge,
 20     Delay_Done,
 21    SPI_SCK
 22    );
 23 //=================================<端口>===========================
 24 //--    物理端口
 25    input clk;                          //时钟信号
 26    input rst_n;                        //复位信号
 27    output reg SPI_SCK;                 //SPI时钟信号
 28 //--    上级系统通信
 29    input SPI_SCK_EN;                   //SPI时钟使能信号
 30    input SPI_SCK_STOP;                 //SPI时钟输出停止信号(重置)
 31    input [3:0]SPI_SCK_Freq_Sel;        //SPI频率选择信号
 32    input SPI_SCK_CPOL;                 //SPI空闲状态控制信号 0 空闲低电平 1 空闲高电平
 33    output reg SCK_Posedge;             //SPI时钟信号SCK上升沿标记
 34    output reg SCK_Negedge;             //SPI时钟信号SCK下降沿标记
 35    output reg Delay_Done;              //停止时钟输出信号
 36 //--   下级系统通信
 37 
 38 //--   内部信号
 39    reg [3:0]freq;                      //频率选择寄存器
 40    reg SCK_Init_O;                     //时钟默认信号寄存器
 41    reg [15:0]SCK_CNT_FULL;             //分频计数值
 42    reg [15:0]DIV_CNT;                  //分频计数寄存器
 43    reg SPI_SCK_Ostate;                 //时钟输出状态
 44     reg Done_delay_en;                 //停止延时使能
 45     reg [15:0]Done_delay_cnt;          //STOP信号延迟寄存器
 46 //-------------------------------------------------------------------
 47 //--序号01 功能描述:寄存上级指令或数据
 48 //-------------------------------------------------------------------
 49    always@(posedge clk or negedge rst_n)
 50       if(!rst_n)
 51          freq <= 4'd0;
 52       else if(SPI_SCK_EN)
 53          freq <= SPI_SCK_Freq_Sel;
 54       else
 55          freq <= freq;
 56    
 57       always@(posedge clk or negedge rst_n)
 58       if(!rst_n)
 59          SCK_Init_O <= 1'b0;
 60       else if(SPI_SCK_EN)
 61          SCK_Init_O <= SPI_SCK_CPOL;
 62       else if(SPI_SCK_Ostate)
 63          SCK_Init_O <= SCK_Init_O;        
 64         else
 65             SCK_Init_O <= SPI_SCK_CPOL;        //便于控制SCK空闲状态,可实时改变
 66 
 67    
 68 //-------------------------------------------------------------------
 69 //--序号02 功能描述:分频信号 SCK 、标记信号SCK_Posedge、SCK_Negedge输出
 70 //-------------------------------------------------------------------
 71    //--SPI_SCK_Ostate时钟输出状态确定
 72    always@(posedge clk or negedge rst_n)
 73       if(!rst_n)
 74          SPI_SCK_Ostate <= 1'b0; 
 75       else if(SPI_SCK_EN)
 76          SPI_SCK_Ostate <= 1'b1;
 77       else if(Delay_Done)
 78          SPI_SCK_Ostate <= 1'b0;
 79       else
 80          SPI_SCK_Ostate <= SPI_SCK_Ostate;
 81    
 82    //--分频计数器
 83    always@(posedge clk or negedge rst_n)
 84       if(!rst_n)
 85          DIV_CNT <= 16'd0;
 86       else if(SPI_SCK_Ostate)
 87          begin
 88             if(DIV_CNT == SCK_CNT_FULL)
 89                DIV_CNT <= 16'd0;
 90             else
 91                DIV_CNT <= DIV_CNT + 1'b1;
 92          end
 93       else
 94          DIV_CNT <= 16'd0;
 95    
 96    //--SPI SCK时钟信号输出
 97    always@(posedge clk or negedge rst_n)
 98       if(!rst_n)
 99          SPI_SCK <= 1'b0;
100       else if(SPI_SCK_Ostate)
101          begin
102             if(DIV_CNT == (SCK_CNT_FULL >> 1'b1))
103                SPI_SCK <= ~SPI_SCK;
104             else if(DIV_CNT == 1'b0)
105                SPI_SCK <= SCK_Init_O;
106             else
107                SPI_SCK <= SPI_SCK;
108          end
109       else
110          SPI_SCK <= SCK_Init_O;
111    
112    //--标记信号SCK_Posedge输出
113    always@(posedge clk or negedge rst_n)
114       if(!rst_n)
115          SCK_Posedge <= 1'b0;
116       else if( !SCK_Init_O && DIV_CNT == (SCK_CNT_FULL >> 1'b1))
117          SCK_Posedge <= 1'b1;
118       else if( SCK_Init_O && DIV_CNT == SCK_CNT_FULL)
119          SCK_Posedge <= 1'b1;
120       else
121          SCK_Posedge <= 1'b0;
122          
123    //--标记信号SCK_Negedge输出
124    always@(posedge clk or negedge rst_n)
125       if(!rst_n)
126          SCK_Negedge <= 1'b0;
127       else if( SCK_Init_O && DIV_CNT == (SCK_CNT_FULL >> 1'b1))
128          SCK_Negedge <= 1'b1;
129       else if( !SCK_Init_O && DIV_CNT == SCK_CNT_FULL)
130          SCK_Negedge <= 1'b1;
131       else
132          SCK_Negedge <= 1'b0;
133 //-------------------------------------------------------------------
134 //--序号03 功能描述:SCK时钟延迟停止函数
135 //-------------------------------------------------------------------    
136    //--Done_delay_en
137    always@(posedge clk or negedge rst_n)
138       if(!rst_n)
139             Done_delay_en <= 1'b0;
140         else if(SPI_SCK_STOP)
141             Done_delay_en <= 1'b1;
142         else if(Delay_Done)
143             Done_delay_en <= 1'b0;
144         else
145             Done_delay_en <= Done_delay_en;
146     //--Done_delay_cnt
147     always@(posedge clk or negedge rst_n)
148       if(!rst_n)
149             Done_delay_cnt <= 16'd0;
150         else if(Done_delay_en)
151             Done_delay_cnt <= Done_delay_cnt + 1'b1;
152         else
153             Done_delay_cnt <= 16'd0;
154     //--Done
155     always@(posedge clk or negedge rst_n)
156         if(!rst_n)
157             Delay_Done <= 1'b0;
158         else if(Done_delay_cnt == (SCK_CNT_FULL >> 1) - 3'd6)
159             Delay_Done <= 1'b1;
160         else
161             Delay_Done <= 1'b0;
162 //-------------------------------------------------------------------
163 //--序号04 功能描述:SCK时钟频率查找表
164 //-------------------------------------------------------------------
165    always@(*)
166       begin
167          case(freq)
168             4'd0 :SCK_CNT_FULL = 16'd49999 ;    //  1     KHz    
169             4'd1 :SCK_CNT_FULL = 16'd24999 ;    //  2       KHz    
170             4'd2 :SCK_CNT_FULL = 16'd12499 ;    //  4       KHz    
171             4'd3 :SCK_CNT_FULL = 16'd6249  ;    //  8       KHz    
172             4'd4 :SCK_CNT_FULL = 16'd4999  ;    //  10    KHz    
173             4'd5 :SCK_CNT_FULL = 16'd2499  ;    //  20    KHz    
174             4'd6 :SCK_CNT_FULL = 16'd1249  ;    //  40    KHz    
175             4'd7 :SCK_CNT_FULL = 16'd624   ;    //  80    KHz 
176             4'd8 :SCK_CNT_FULL = 16'd499   ;    //  100    KHz 
177             4'd9 :SCK_CNT_FULL = 16'd249   ;    //  200    KHz 
178             4'd10:SCK_CNT_FULL = 16'd124   ;    //  400    KHz 
179             4'd11:SCK_CNT_FULL = 16'd99    ;    //  500    KHz 
180             4'd12:SCK_CNT_FULL = 16'd49    ;    //  1      MHz 
181             4'd13:SCK_CNT_FULL = 16'd24    ;    //  2       MHz 
182             default:SCK_CNT_FULL = 16'd49999 ;  //  1        KHz 
183          endcase
184       end
185    
186 endmodule

  b.数据采集模块:

    功能:

      1) 采集8/16位数据

 

 

 

   代码如下

  1 /***************************************************
  2 *    Module Name        :  SPI_Rx_Module             
  3 *    Engineer           :    王小虎
  4 *    Target Device     :    EP4CE10F17C8
  5 *    Tool versions      :    Quartus II 13.0
  6 *    Create Date        :    2019
  7 *    Revision           :    v1.0
  8 *    Description        :  1、SPI通信数据采集模块;采集顺序MSB --> LSB
  9                             2、可通过设置SPI_SCK_CPOL、SPI_SCK_CPHA满足四种不同传输模式
 10                             3、数据位宽可设置 8/16位
 11 **************************************************/
 12 module SPI_Rx_Module(
 13    clk,
 14    rst_n,
 15    SPI_Rx_EN,
 16    SPI_Rx_Data_Width,
 17    SPI_SCK_CPOL,
 18    SPI_SCK_CPHA,
 19    SCK_Posedge,
 20    SCK_Negedge,
 21    SPI_Rx_Data,
 22    SPI_Rx_Done,
 23    SPI_MISO
 24    );
 25 //=================================<端口>===========================
 26 //--    物理端口
 27    input clk;                          //时钟信号
 28    input rst_n;                        //复位信号
 29    input SPI_MISO;                     //SPI输入信号
 30 //--    上级系统通信
 31    input SPI_Rx_EN;                    //接收使能信号
 32    input [4:0]SPI_Rx_Data_Width;       //将接收数据位宽
 33    input SPI_SCK_CPOL;                 //时钟极性设置
 34    input SPI_SCK_CPHA;                 //时钟相位设置
 35    input SCK_Posedge;                  //时钟上升沿标记
 36    input SCK_Negedge;                  //时钟下降沿标记
 37    output reg [15:0]SPI_Rx_Data;       //输出采集数据
 38    output reg SPI_Rx_Done;             //采集结束标志
 39 //--   下级系统通信
 40 
 41 //--   内部信号
 42    reg Rx_state;                       //采集状态
 43    reg [4:0]data_Width;                //采集数据位宽寄存器
 44    reg CPOL;                           //时钟极性参数寄存器
 45    reg CPHA;                           //时钟相位设置寄存器
 46    reg [4:0]Rx_cnt;                    //采集数据计数器
 47    reg [15:0]data;                     //采集数据寄存器
 48 
 49 //-------------------------------------------------------------------
 50 //--序号01 功能描述:寄存上级指令或数据
 51 //-------------------------------------------------------------------
 52    //--采集数据位宽寄存器
 53    always@(posedge clk or negedge rst_n)
 54       if(!rst_n)
 55          data_Width <= 5'd0;
 56       else if(SPI_Rx_EN)
 57          data_Width <= SPI_Rx_Data_Width;
 58       else
 59          data_Width <= data_Width;
 60    //--时钟极性参数寄存器
 61    always@(posedge clk or negedge rst_n)
 62       if(!rst_n)
 63          CPOL <= 1'b0;
 64       else if(SPI_Rx_EN)
 65          CPOL <= SPI_SCK_CPOL;
 66       else
 67          CPOL <= CPOL;
 68    //--时钟相位设置寄存器
 69    always@(posedge clk or negedge rst_n)
 70       if(!rst_n)
 71          CPHA <= 1'b0;
 72       else if(SPI_Rx_EN)
 73          CPHA <= SPI_SCK_CPHA;
 74       else
 75          CPHA <= CPHA;
 76 //-------------------------------------------------------------------
 77 //--序号02 功能描述:数据采集
 78 //-------------------------------------------------------------------
 79    //--采集状态
 80    always@(posedge clk or negedge rst_n)
 81       if(!rst_n)
 82          Rx_state <= 1'b0;
 83       else if(SPI_Rx_EN)
 84          Rx_state <= 1'b1;
 85       else if(SPI_Rx_Done)
 86          Rx_state <= 1'b0;
 87       else
 88          Rx_state <= Rx_state;
 89    
 90    //--采集结束标志    
 91     always@(posedge clk or negedge rst_n)
 92       if(!rst_n)
 93          SPI_Rx_Done <= 1'b0;
 94       else if( Rx_cnt == data_Width && Rx_state)
 95             SPI_Rx_Done <= 1'b1;
 96       else
 97          SPI_Rx_Done <= 1'b0;
 98    
 99    //--采集数据计数器
100    always@(posedge clk or negedge rst_n)
101       if(!rst_n)
102          Rx_cnt <= 5'd0;
103       else if(Rx_state)
104          begin
105             if(Rx_cnt >= data_Width)
106                Rx_cnt <= 5'd0;
107             else if(CPHA)
108                begin
109                   if((!CPOL && SCK_Negedge) || ((CPOL && SCK_Posedge)))
110                      Rx_cnt <= Rx_cnt + 1'b1;
111                   else
112                      Rx_cnt <= Rx_cnt;
113                end
114             else
115                begin
116                   if((!CPOL && SCK_Posedge) || (CPOL && SCK_Negedge))
117                      Rx_cnt <= Rx_cnt + 1'b1;
118                   else
119                      Rx_cnt <= Rx_cnt;
120                end
121          end
122       else
123          Rx_cnt <= 5'd0;
124  
125    //--采集数据
126    always@(posedge clk or negedge rst_n)
127       if(!rst_n)
128          data <= 16'd0;
129       else if(Rx_state)
130          begin
131             if(CPHA)
132                begin
133                   if((!CPOL && SCK_Negedge) || ((CPOL && SCK_Posedge)))
134                      data <= {data[14:0],SPI_MISO};
135                   else
136                      data <= data;
137                end
138             else
139                begin
140                   if((!CPOL && SCK_Posedge) || (CPOL && SCK_Negedge))
141                      data <= {data[14:0],SPI_MISO};
142                   else
143                      data <= data;
144                end
145          end
146       else
147          data <= 16'd0;
148    
149    //--采集数据
150    always@(posedge clk or negedge rst_n)
151       if(!rst_n)
152          SPI_Rx_Data <= 16'd0;
153       else if(Rx_cnt == data_Width)
154          SPI_Rx_Data <= data;
155       else
156          SPI_Rx_Data <= SPI_Rx_Data;
157           
158 endmodule

  c.数据发送模块:

    功能:

      1) 发送8/16位数据

   

 

   代码如下

  1 /***************************************************
  2 *    Module Name        :    SPI_Tx_Module           
  3 *    Engineer            :    王小虎
  4 *    Target Device    :    EP4CE10F17C8
  5 *    Tool versions    :    Quartus II 13.0
  6 *    Create Date        :    2019
  7 *    Revision            :    v1.0
  8 *    Description        :  1、可发送8/16位宽数据;
  9                             2、发送计数值以采集值作参考
 10 **************************************************/
 11 module SPI_Tx_Module(
 12    clk,
 13    rst_n,
 14    SPI_Tx_EN,
 15    SPI_Tx_Data_Width,
 16    SPI_Tx_Data,
 17    SPI_SCK_CPOL,
 18    SPI_SCK_CPHA,
 19    SCK_Posedge,
 20    SCK_Negedge,
 21    SPI_Tx_Done,
 22    SPI_MOSI  
 23    );
 24 //=================================<端口>===========================
 25 //--    物理端口
 26    input clk;                          //时钟信号
 27    input rst_n;                        //复位信号
 28    output reg SPI_MOSI;                //MOSI输出信号
 29 //--    上级系统通信
 30    input SPI_Tx_EN;                    //发送使能信号
 31    input [4:0]SPI_Tx_Data_Width;       //发送数据位宽
 32    input [15:0]SPI_Tx_Data;            //待发送数据
 33    input SPI_SCK_CPOL;                 //时钟极性
 34    input SPI_SCK_CPHA;                 //时钟相位
 35    input SCK_Posedge;                  //上升沿标记
 36    input SCK_Negedge;                  //下降沿标记
 37    output reg SPI_Tx_Done;             //发送结束标记
 38 //--   下级系统通信
 39    
 40 //--   内部信号
 41    reg Tx_state;                       //发送状态
 42    reg [4:0]data_width;                //数据位宽寄存器
 43    reg [15:0]data;                     //待发送数据寄存器
 44    reg CPOL;                           //时钟极性寄存器
 45    reg CPHA;                           //时钟相位寄存器
 46    reg [4:0]Tx_cnt;                    //发送数据计数寄存器
 47 //-------------------------------------------------------------------
 48 //--序号01 功能描述:寄存上级指令或数据
 49 //-------------------------------------------------------------------
 50    //--数据位宽寄存器
 51    always@(posedge clk or negedge rst_n)
 52       if(!rst_n)
 53          data_width <= 5'd0;
 54       else if(SPI_Tx_EN)
 55          data_width <= SPI_Tx_Data_Width;
 56       else
 57          data_width <= data_width;
 58    
 59    //--data寄存器
 60    always@(posedge clk or negedge rst_n)
 61       if(!rst_n)
 62          data <= 16'd0;
 63       else if(SPI_Tx_EN)      //如果待发送数据不是16位
 64          data <= ( SPI_Tx_Data << ( 5'd16 - SPI_Tx_Data_Width) );
 65       else if(Tx_state)begin
 66          if(CPHA)begin
 67             if( Tx_cnt >1'b0 )
 68                if( (!CPOL && SCK_Posedge) || (CPOL && SCK_Negedge) )
 69                   data <= {data[14:0],data[15]};
 70                else
 71                   data <= data;
 72             else
 73                data <= data;
 74          end
 75          else if( (CPOL && SCK_Posedge) || (!CPOL && SCK_Negedge))
 76             data <= {data[14:0],data[15]};
 77          else
 78             data <= data;
 79       end
 80       else
 81          data <= data;         
 82    
 83    //--时钟极性参数寄存器
 84    always@(posedge clk or negedge rst_n)
 85       if(!rst_n)
 86          CPOL <= 1'b0;
 87       else if(SPI_Tx_EN)
 88          CPOL <= SPI_SCK_CPOL;
 89       else
 90          CPOL <= CPOL;
 91          
 92    //--时钟相位设置寄存器
 93    always@(posedge clk or negedge rst_n)
 94       if(!rst_n)
 95          CPHA <= 1'b0;
 96       else if(SPI_Tx_EN)
 97          CPHA <= SPI_SCK_CPHA;
 98       else
 99          CPHA <= CPHA;
100 //-------------------------------------------------------------------
101 //--序号02 功能描述:发送数据模块
102 //-------------------------------------------------------------------
103    //--发送状态寄存器
104    always@(posedge clk or negedge rst_n)
105       if(!rst_n)
106          Tx_state <= 1'b0;
107       else if(SPI_Tx_EN)
108          Tx_state <= 1'b1;
109       else if(SPI_Tx_Done)
110          Tx_state <= 1'b0;
111       else
112          Tx_state <= Tx_state;
113    //--发送数据计数器
114    always@(posedge clk or negedge rst_n)
115       if(!rst_n)
116          Tx_cnt <= 5'd0;
117       else if(Tx_state)
118          begin
119             if(Tx_cnt >= data_width)
120                Tx_cnt <= 5'd0;
121             else if(CPHA)
122                begin
123                   if((!CPOL && SCK_Negedge) || ((CPOL && SCK_Posedge)))
124                      Tx_cnt <= Tx_cnt + 1'b1;
125                   else
126                      Tx_cnt <= Tx_cnt;
127                end
128             else
129                begin
130                   if((!CPOL && SCK_Posedge) || (CPOL && SCK_Negedge))
131                      Tx_cnt <= Tx_cnt + 1'b1;
132                   else
133                      Tx_cnt <= Tx_cnt;
134                end
135          end
136       else
137          Tx_cnt <= 5'd0;
138    //--发送数据
139    always@(posedge clk or negedge rst_n)
140       if(!rst_n)
141          SPI_MOSI <= 1'b0;
142       else if(Tx_state)
143          SPI_MOSI <= data[15];
144       else
145          SPI_MOSI <= 1'd1;             //在仅采集的情况下,让SPI_MOSI端口置1
146          
147          
148    //--SPI_Tx_Done
149    always@(posedge clk or negedge rst_n)
150       if(!rst_n)
151          SPI_Tx_Done <= 1'b0;
152       else if( Tx_cnt == data_width && Tx_state)
153          SPI_Tx_Done <= 1'b1;
154       else
155          SPI_Tx_Done <= 1'b0;
156 endmodule

  d.控制模块:

    功能:

      1) 输出片选信号

  代码如下

  1 /***************************************************
  2 *    Module Name        :    SPI_CTL           
  3 *    Engineer           :    王小虎
  4 *    Target Device     :    EP4CE10F17C8
  5 *    Tool versions      :    Quartus II 13.0
  6 *    Create Date        :    2019
  7 *    Revision           :    v1.0
  8 *    Description        :   1、片选信号默认为1,选中为0;
  9                             2、时钟结束信号以采集结束信号为标志
 10                             3、SPI_Done信号在采集结束SPI_Rx_Done之后延迟半个采集周期之后发送
 11 **************************************************/
 12 module SPI_CTL(
 13    clk,
 14    rst_n,
 15    SPI_EN,
 16     SPI_Done,
 17    SPI_SCK_CPOL,
 18    SPI_SCK_CPHA,
 19     SPI_SCK_Freq_Sel,
 20    SPI_Rx_Data_Width,
 21    SPI_Rx_Data,
 22     SPI_Tx_Data_Width,
 23     SPI_Tx_Data,
 24     SPI_CS,
 25     SPI_MOSI,
 26    SPI_MISO,
 27    SPI_SCK
 28    );
 29 //=================================<端口>===========================
 30 //--    物理端口
 31    input clk;                          //时钟信号
 32    input rst_n;                        //复位信号
 33     output reg SPI_CS;                 //片选信号
 34    input SPI_MISO;                     //SPI输入信号
 35     output SPI_MOSI;                   //MOSI输出信号
 36    output SPI_SCK;                     //SPI时钟输出信号
 37 //--    上级系统通信
 38    input SPI_EN;                       //SPI通信使能信号
 39    output SPI_Done;                    //采集结束标志    
 40    input SPI_SCK_CPOL;                 //时钟极性设置
 41    input SPI_SCK_CPHA;                 //时钟相位设置
 42     input [3:0]SPI_SCK_Freq_Sel;       //时钟频率选择信号
 43     input [4:0]SPI_Rx_Data_Width;      //将接收数据位宽
 44    output[15:0]SPI_Rx_Data;            //输出采集数据
 45     input [4:0]SPI_Tx_Data_Width;      //发送数据位宽
 46    input [15:0]SPI_Tx_Data;            //待发送数据    
 47     
 48 //--   下级系统通信
 49    wire SCK_Posedge;                   //时钟上升沿标记
 50    wire SCK_Negedge;                   //时钟下降沿标记
 51     wire SPI_Rx_Done;                  //采集结束标志
 52     wire SPI_Tx_Done;                  //发送结束标记
 53     wire Delay_Done;                   //延时停止信号
 54 //--   内部信号
 55 //-------------------------------------------------------------------
 56 //--序号01 功能描述:SPI_Done
 57 //-------------------------------------------------------------------
 58     assign SPI_Done = Delay_Done;
 59 //-------------------------------------------------------------------
 60 //--序号02 功能描述:SPI_CS
 61 //-------------------------------------------------------------------
 62     always@(posedge clk or negedge rst_n)
 63         if(!rst_n)
 64             SPI_CS <= 1'b1;
 65         else if(SPI_EN)
 66             SPI_CS <= 1'b0;
 67         else if(Delay_Done)
 68             SPI_CS <= 1'b1;
 69         else
 70             SPI_CS <= SPI_CS;
 71 //-------------------------------------------------------------------
 72 //--        模块例化
 73 //-------------------------------------------------------------------
 74 SPI_Clk_Module Clk_Module(
 75    .clk(clk),
 76    .rst_n(rst_n),
 77    .SPI_SCK_EN(SPI_EN),
 78    .SPI_SCK_STOP(SPI_Rx_Done),
 79    .SPI_SCK_Freq_Sel(SPI_SCK_Freq_Sel),
 80    .SPI_SCK_CPOL(SPI_SCK_CPOL),
 81    .SCK_Posedge(SCK_Posedge),
 82    .SCK_Negedge(SCK_Negedge),
 83     .Delay_Done(Delay_Done),
 84    .SPI_SCK(SPI_SCK)
 85    );
 86    
 87 SPI_Rx_Module Rx_Module(
 88    .clk(clk),
 89    .rst_n(rst_n),
 90    .SPI_Rx_EN(SPI_EN),
 91    .SPI_Rx_Data_Width(SPI_Rx_Data_Width),
 92    .SPI_SCK_CPOL(SPI_SCK_CPOL),
 93    .SPI_SCK_CPHA(SPI_SCK_CPHA),
 94    .SCK_Posedge(SCK_Posedge),
 95    .SCK_Negedge(SCK_Negedge),
 96    .SPI_Rx_Data(SPI_Rx_Data),
 97    .SPI_Rx_Done(SPI_Rx_Done),
 98    .SPI_MISO(SPI_MISO)
 99    );
100 SPI_Tx_Module Tx_Module(
101    .clk(clk),
102    .rst_n(rst_n),
103    .SPI_Tx_EN(SPI_EN),
104    .SPI_Tx_Data_Width(SPI_Tx_Data_Width),
105    .SPI_Tx_Data(SPI_Tx_Data),
106    .SPI_SCK_CPOL(SPI_SCK_CPOL),
107    .SPI_SCK_CPHA(SPI_SCK_CPHA),
108    .SCK_Posedge(SCK_Posedge),
109    .SCK_Negedge(SCK_Negedge),
110    .SPI_Tx_Done(SPI_Tx_Done),
111    .SPI_MOSI(SPI_MOSI)  
112    );
113 
114 endmodule

 

  e.顶层模块:

  代码如下

 

 1 /***************************************************
 2 *    Module Name        :    SPI_TOP           
 3 *    Engineer           :    王小虎
 4 *    Target Device     :    EP4CE10F17C8
 5 *    Tool versions      :    Quartus II 13.0
 6 *    Create Date        :    2019
 7 *    Revision           :    v1.0
 8 *    Description        :  1、SPI_SCK_CPOL/SPI_SCK_CPOL可设置
 9                          2、采集/发送数据位宽可设置(是否鸡肋?)
10                          3、发送频率可选择。采用查找表形式,可更改
11 **************************************************/
12 module SPI_TOP(
13    clk,
14    rst_n,
15    SPI_EN,
16     SPI_Done,
17    SPI_SCK_CPOL,
18    SPI_SCK_CPHA,
19     SPI_SCK_Freq_Sel,
20    SPI_Rx_Data_Width,
21    SPI_Rx_Data,
22     SPI_Tx_Data_Width,
23     SPI_Tx_Data,
24     SPI_CS,
25     SPI_MOSI,
26    SPI_MISO,
27    SPI_SCK
28    );
29 //=================================<端口>===========================
30 //--    物理端口
31    input clk;                          //时钟信号
32    input rst_n;                        //复位信号
33     output SPI_CS;                     //片选信号
34    input SPI_MISO;                     //SPI输入信号
35     output SPI_MOSI;                   //MOSI输出信号
36    output SPI_SCK;                     //SPI时钟输出信号
37 //--    上级系统通信
38    input SPI_EN;                       //SPI通信使能信号
39    output SPI_Done;                    //采集结束标志    
40    input SPI_SCK_CPOL;                 //时钟极性设置
41    input SPI_SCK_CPHA;                 //时钟相位设置
42     input [3:0]SPI_SCK_Freq_Sel;       //时钟频率选择信号
43     input [4:0]SPI_Rx_Data_Width;      //将接收数据位宽
44    output[15:0]SPI_Rx_Data;            //输出采集数据
45     input [4:0]SPI_Tx_Data_Width;      //发送数据位宽
46    input [15:0]SPI_Tx_Data;            //待发送数据    
47 //-------------------------------------------------------------------
48 //--        模块例化
49 //-------------------------------------------------------------------
50 SPI_CTL SPI_CTL(
51    .clk(clk),
52    .rst_n(rst_n),
53    .SPI_EN(SPI_EN),
54     .SPI_Done(SPI_Done),
55     .SPI_SCK_CPOL(SPI_SCK_CPOL),
56    .SPI_SCK_CPHA(SPI_SCK_CPHA),
57     .SPI_SCK_Freq_Sel(SPI_SCK_Freq_Sel),
58    .SPI_Rx_Data_Width(SPI_Rx_Data_Width),
59    .SPI_Rx_Data(SPI_Rx_Data),
60     .SPI_Tx_Data_Width(SPI_Tx_Data_Width),
61     .SPI_Tx_Data(SPI_Tx_Data),
62     .SPI_CS(SPI_CS),
63     .SPI_MOSI(SPI_MOSI),
64     .SPI_MISO(SPI_MISO),
65    .SPI_SCK(SPI_SCK)
66    ); 
67 endmodule

  附上仿真图两张

  前仿真

  后仿真

  

   

    

posted @ 2019-12-31 17:10  王小虎8821  阅读(623)  评论(0)    收藏  举报