协议篇(三)SPI的verilog实现

1.基本协议

点击链接:SPI接口详细介绍
简单来说四根线:

SCK : Serial Clock 串行时钟

MOSI : Master Output, Slave Input 主发从收信号

MISO : Master Input, Slave Output 主收从发信号

SS/CS : Slave Select 片选信号

SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线。常规只占用四根线,节约了芯片管脚,PCB的布局省空间。现在越来越多的芯片集成了这种通信协议,常见的有EEPROM、FLASH、AD转换器等。

传输速度:支持高速(100MHz以上),一般看传感器的硬件手册的要求,根据要求设置SCK的长度就可以了

这是我配置ADC是用到的代码

SPI 写入模块

module SPI_ADC(

input   clk,                //100M
input   rst_n,

input  Sig_start,           //模块开始工作信号
input [7:0]  WR_ADDR,
input [7:0]  WR_DATA,
output   wr_finish,		  //写入完成信号

output  ADC_CS_n,
output ADC_SCK,
output ADC_SDI
    );

reg Sig_start_r;
always@ (posedge clk)
    begin
        Sig_start_r <= Sig_start;
    end

reg rCSn =1;
reg rSCK =1;
reg rSDI =0;
reg wr_finish_r= 0;  
reg [4:0] state = 0;
reg [9:0] count;
reg [15:0]rDATA=0;

parameter Ts = 5'd10;
parameter Tds = 5'd10;
parameter Tdh = 5'd10;
parameter Th = 5'd10;

always @ (posedge clk or negedge rst_n)
    begin
        if(~rst_n)
            begin
                rCSn <=1;
                rSCK <=0;
                rSDI <=0;
                wr_finish_r <=0;
                state <=0;
                count <=0;
                rDATA <=0;
            end
        else
            begin
                case(state)
                    0:begin
                        rCSn <=1;
                        rSCK <=0;
                        rSDI <=0;
                        wr_finish_r <=0;
                        count <=0;
                        
                        if(~Sig_start_r&&Sig_start)
                            begin
                                state <= 5'd1;
                            end
                    end
                    1:begin     //发送IIC开始信号
                    
                        rDATA ={WR_ADDR,WR_DATA};//发送数据
                   
                        if(count ==0 )
                              rCSn <=1'b1;
                        else if(count == 10)
                              rCSn <=1'b0;
                      
                        if(count == 0)
                            rSCK <=1'b0;
                        else if(count == 20)
                            rSCK <=1'b0;
                         
                        if(count == 30) 
                            begin
                                count <=0;
                                state <=5'd2;
                            end 
                        else
                            begin
                                count <= count + 1'b1;
                            end
                    end
                    2:begin    
                         rSDI <= rDATA[15];
                         
                         if(count == 5)
                            begin
                                state <= 5'd3;
                                count <= 0;
                            end
                        else
                            begin
                                count <= count +1'b1;
                            end
                            
                         
                    end
                    3,4,5,6,7,8,9,10,11,12,13,14,15,16,17:begin  //BIT 15 - 1                 
                        if(count ==0)
                            begin
                                rSCK <=1'b1;
                            end
                        else if(count == 10)
                            begin
                                rSCK <=1'b0;
                                rSDI <= rDATA[17-state];
                            end
                        
                        
                        if(count == 20)
                            begin
                               state <= state +1'b1; 
                               count <= 0;
                            end
                        else
                            begin
                                count <= count +1'b1;
                            end
                    end
                    18:begin
                        if(count ==0)
                            begin
                                 rSCK <=1'b1;
                            end
                        else if(count ==10)
                            begin
                                rCSn <=1'b1;
                            end
                         
                         
                        if(count == 15)
                            begin
                                state <= 5'd19;
                                count <= 0;
                            end
                        else
                            begin
                                count <= count + 1'b1;
                            end      
                    end
                    19:begin //完成
                            wr_finish_r<= 1'b1;
                            state <=5'd0;
                    end
                    default:begin
                        state <=5'd0;
                    end
                    
                endcase
            end
    end

assign ADC_CS_n =rCSn;
assign ADC_SCK =rSCK;
assign ADC_SDI =rSDI;
assign wr_finish =wr_finish_r;
endmodule

在这里插入图片描述

SPi 回读模块

module SPI_SDIO(
    input   clk,        //100M
    input   rst_n,
    
    input  RSig_start,			//模块开始工作
    input [7:0]  WR_ADDR,
    output   r_finish,			//完成回读	
    
    output ADC_CS_n,
    output ADC_SCK,
    output ADC_SDI,
    input  ADC_SDIO,
    
    output reg [7:0] A			//回读数据
    
    );

reg RSig_start_r;
always@ (posedge clk)
    begin
        RSig_start_r <= RSig_start;
    end

reg rCSn =1;
reg rSCK =1;
reg rSDI =0;
reg r_finish_r= 0;  
reg [4:0] state = 0;
reg [9:0] count;
reg [7:0]rDATA=0;

parameter Ts = 5'd10;
parameter Tds = 5'd10;
parameter Tdh = 5'd10;
parameter Th = 5'd10;
parameter TDO = 5'd20;

reg [7:0] A_reg = 0;
always @ (posedge clk or negedge rst_n)
    begin
        if(~rst_n)
            begin
                rCSn <=1;
                rSCK <=0;
                rSDI <=0;
                r_finish_r <=0;
                state <=0;
                count <=0;
                rDATA <=0;
                A_reg <=0;
            end
        else
            begin
                case(state)
                    0:begin
                        rCSn <=1;
                        rSCK <=0;
                        rSDI <=0;
                        r_finish_r <=0;
                        count <=0;
                        A_reg <=0;
                        
                        if(~RSig_start_r&&RSig_start)
                            begin
                                state <= 5'd1;
                            end
                    end
                    1:begin     //发送IIC开始信号
                    
                        rDATA =WR_ADDR;//发送数据
                   
                        if(count ==0 )
                              rCSn <=1'b1;
                        else if(count == 10)
                              rCSn <=1'b0;
                      
                        if(count == 0)
                            rSCK <=1'b0;
                        else if(count == 20)
                            rSCK <=1'b0;
                         
                        if(count == 30) 
                            begin
                                count <=0;
                                state <=5'd2;
                            end 
                        else
                            begin
                                count <= count + 1'b1;
                            end
                    end
                    2:begin    
                         rSDI <= 1'b1;
                         
                         if(count == 5)
                            begin
                                state <= 5'd3;
                                count <= 0;
                            end
                        else
                            begin
                                count <= count +1'b1;
                            end
                            
                         
                    end
                    3,4,5,6,7,8,9:begin  //BIT 15 - 1                 
                        if(count ==0)
                            begin
                                rSCK <=1'b1;
                            end
                        else if(count == 10)
                            begin
                                rSCK <=1'b0;
                                rSDI <= rDATA[9-state];
                            end
                        
                        
                        if(count == 20)
                            begin
                               state <= state +1'b1; 
                               count <= 0;
                            end
                        else
                            begin
                                count <= count +1'b1;
                            end
                    end
                    10:begin 
                        if(count ==0)
                           begin
                               rSCK <=1'b1;
                           end
                        else if(count == 10)
                           begin
                               rSCK <=1'b0;
                           end
                           
                         if(count == 30)
                             begin
                                state <= state +1'b1; 
                                count <= 0;
                             end
                         else
                             begin
                                 count <= count +1'b1;
                             end
                    end
                    11,12,13,14,15,16,17:begin
                        if(count ==0)
                           begin
                               rSCK <=1'b1;
                               A_reg[18-state] <= ADC_SDIO;
                           end
                        else if(count == 10)
                           begin
                               rSCK <=1'b0;
                           end
                           
                         if(count == 30)
                             begin
                                state <= state +1'b1; 
                                count <= 0;
                             end
                         else
                             begin
                                 count <= count +1'b1;
                             end  
                    end
                    18:begin
                        if(count ==0)
                            begin
                                 rSCK <=1'b1;
                                 A_reg[0] <=ADC_SDIO;
                            end
                        else if(count ==10)
                            begin
                                rCSn <=1'b1;
                            end
                                                 
                        if(count == 15)
                            begin
                                state <= 5'd19;
                                count <= 0;
                            end
                        else
                            begin
                                count <= count + 1'b1;
                            end      
                    end
                    19:begin //完成
                            r_finish_r<= 1'b1;
                            state <=5'd0;
                            A <= A_reg;
                    end
                    default:begin
                        state <=5'd0;
                    end
                    
                endcase
            end
    end

assign ADC_CS_n =rCSn;
assign ADC_SCK =rSCK;
assign ADC_SDI =rSDI;
assign r_finish =r_finish_r;
endmodule

在这里插入图片描述

顶层调用文件

`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2019/06/26 10:30:19
// Design Name:
// Module Name: SPI_ini
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//

module SPI_ini(
    input clk,
    input rst_n,
    
    output ADC_CS_n,
    output ADC_SCK,
    output ADC_SDI,
    input ADC_SDIO,
    
    output Done_ini

    );
    
/************************** 配置ADC    ************************/
    /****************************************
    模块功能:SPI配置
    采样时钟:ADC_ENCLK 10M  Th=50ns  Tl = 50ns  fs= 10M
    备注:采用两个状态机状态机编写配置ADC文件
    
    
    
    配置任务:1.全速率配置    2.10M采样速率   3. OFFSET BINARY
    协议: 写数据均为   2Bit\
    
    Ts                                  min 5ns          设定100ns
    tdS      CS to SCK Setup Time     min 5ns            设定100ns
    ths       HSCK to CS Setup Time    min 5ns           设定100ns   
    Th                                   min 5ns         设定100ns
    tSCK    SCK Period               min 40ns            设定00ns
    
    1.A0 复位寄存器(地址00H)    BIT7      = 1   软件复位  
    2.A1 电源寄存器(地址01H)     BIT1-0   = 00  正常工作       BIT1-0   = 00  两路都睡眠
    3.A2 时间寄存器 (地址02H)    BIT3   = 0  不翻转时钟记性以保证上升沿抓数据       BIT2-1 = 00 没有时钟相位延迟   BIT0 = 0 ,不开启时钟稳定电路
    4.A3 输出模式寄存器(地址03H)     BIT6-4 011 不适用LVDS BIT3 = 0     BIT2 = 0 不启用数字输出禁止    BIT1-0 =00 Full-Rate CMOS Output Mode
    5.A4 数据格式寄存器 (地址05H)    BIT5-3 = 000 输出数据测试关闭   BIT2 =  0 交替极性位关闭(开启后需要在FPGA中解码)    BIT1 = 0 随机数字输出关闭   BIT0 = 0  Offset Binary Data Format
    *****************************************/ 
    //复位等待
    reg ADC_config = 0;
    reg [8:0] count_ADC_config = 0;
    always @ (posedge clk or negedge rst_n)
        begin
            if(~rst_n)
                begin
                    ADC_config <= 0;
                    count_ADC_config <=0;
                end
            else
                begin
                    if(count_ADC_config < 9'd200)
                        begin
                            count_ADC_config <= count_ADC_config + 1'b1;
                            ADC_config <=0;
                        end
                    else
                        begin
                            ADC_config <=1'b1;
                        end
                end
        end
        
    //配置寄存器转换状态机
    parameter ADDR_A0 =8'h00;
    parameter ADDR_A1 =8'h01;
    parameter ADDR_A2 =8'h02;
    parameter ADDR_A3 =8'h03;
    parameter ADDR_A4 =8'h04;
    
    parameter DATA_A0 =8'b10000000;
    parameter DATA_A1 =8'b00000000;
   // parameter DATA_A1 =8'b00000011;   睡眠模式,时间为2ms默认情况下
    parameter DATA_A2 =8'b00000000;
    parameter DATA_A3 =8'b00110000;
    parameter DATA_A4 =8'b00000000;
    
//    parameter DATA_A0 =8'b10000000;
//    parameter DATA_A1 =8'b00000000;
//    parameter DATA_A2 =8'b00001000; //时钟翻转
//    parameter DATA_A3 =8'b00110000;
//    parameter DATA_A4 =8'b00011000; //输出都为1
    
    //parameter A0 =8'b10000000;
    //parameter A1 =8'b00000000;
    //parameter A2 =8'b00000000;
    //parameter A3 =8'b00110000;
    //parameter A4 =8'b00000000;
    
    reg [2:0] State_convert=0;
    reg   Sig_start=0;
    wire  wr_finish;
    reg [7:0]  WR_ADDR=0;
    reg [7:0]  WR_DATA=0;
    reg [4:0] count=0;
    reg Done_ini_r =0 ;
    
    reg RSig_start = 0;
 (*mark_debug = "true"*) (* KEEP = "TRUE" *)    wire r_finish;
(*mark_debug = "true"*) (* KEEP = "TRUE" *)   wire [7:0] A;
 
    always @ (posedge clk or negedge rst_n )
        begin
            if(~rst_n)
                begin
                   State_convert<=0;
                   Sig_start <=0;
                   WR_ADDR <=0;
                   WR_DATA <=0;
                   count <=0;
                   Done_ini_r  <=0;
                   RSig_start <= 0;
                end
            else
               begin
                    case(State_convert)
                        3'd0:begin
                            Sig_start <=0;
                            
                            if(ADC_config)
                                begin
                                    State_convert <= 3'd1;
                                end
                        end
                        3'd1:begin
                            Sig_start <= 1'b1;
                            WR_ADDR <=  ADDR_A0;
                            WR_DATA <=  DATA_A0;
                            
                            if(wr_finish)
                                begin
                                    Sig_start <=0;
                                    State_convert <= 3'd2;
                                end
                        end
                        3'd2:begin
                            if(count ==5'd10)
                                begin
                                    Sig_start <= 1'b1;
                                    WR_ADDR <=  ADDR_A1;
                                    WR_DATA <=  DATA_A1;
                                end
                                
                            if(wr_finish)
                                begin
                                    Sig_start <=0;
                                    State_convert <= 3'd3;
                                    count  <= 0;
                                end
                            else
                                begin
                                    count <= count + 1'b1;
                                end
                        end
                        3'd3:begin
                            if(count ==5'd10)
                                begin
                                    Sig_start <= 1'b1;
                                    WR_ADDR <=  ADDR_A2;
                                    WR_DATA <=  DATA_A2;                               
                                end
    
                            
                            if(wr_finish)
                                begin
                                    Sig_start <=0;
                                    State_convert <= 3'd4;
                                    count  <= 0;
                                end
                            else
                                begin
                                    count <= count + 1'b1;
                                end
                        end
                        3'd4:begin
                            if(count ==5'd10)
                            begin
                                Sig_start <= 1'b1;
                                WR_ADDR <=  ADDR_A3;
                                WR_DATA <=  DATA_A3;                        
                            end
                            
                            if(wr_finish)
                                begin
                                    Sig_start <=0;
                                    State_convert <= 3'd5;
                                    count  <= 0;
                                end
                            else
                                begin
                                    count <= count + 1'b1;
                                end
                        end
                        3'd5:begin
                            if(count ==5'd10)
                            begin
                                Sig_start <= 1'b1;
                                WR_ADDR <=  ADDR_A4;
                                WR_DATA <=  DATA_A4;
                            end
    
                            if(wr_finish)
                                begin
                                    Sig_start <=0;
                                    State_convert <= 3'd6;
                                    count  <= 0;
                                end
                            else
                                begin
                                    count <= count + 1'b1;
                                end
                        end
                        3'd6:begin
                             if(count ==5'd10)
                               begin
                                   RSig_start <= 1'b1;
                                   WR_ADDR <=  ADDR_A3;
                               end

                            if(r_finish)
                                begin
                                    RSig_start <=0;
                                    State_convert <= 3'd7;
                                    count  <= 0;
                                end
                            else
                                begin
                                    count <= count + 1'b1;
                                end
                        end
                        
                        3'd7:begin
                            State_convert <= 3'd7;
                            
                            if(count == 10)
                                Done_ini_r <= 1'b1;
                            else
                                count <= count +1'b1;
                            
                        end
                    endcase
               end 
        end

assign Done_ini = Done_ini_r ;

wire ADC_CS_n_0;
wire ADC_CS_n_1;
wire ADC_SCK_0;
wire ADC_SCK_1;
wire ADC_SDI_0;
wire ADC_SDI_1;

SPI_ADC  S1(
. clk(clk),        //100M
. rst_n(rst_n),

. Sig_start(Sig_start),
. WR_ADDR(WR_ADDR),
. WR_DATA(WR_DATA),
. wr_finish(wr_finish),

. ADC_CS_n(ADC_CS_n_0),
. ADC_SCK(ADC_SCK_0),
. ADC_SDI(ADC_SDI_0)
); 
   
SPI_SDIO  S2(
. clk(clk) ,        //100M
. rst_n(rst_n),

. RSig_start(RSig_start),
. WR_ADDR(WR_ADDR),

. r_finish(r_finish),
. ADC_CS_n(ADC_CS_n_1),
. ADC_SCK(ADC_SCK_1),
. ADC_SDI(ADC_SDI_1),
. ADC_SDIO(ADC_SDIO),
. A( A)    
    ); 
    
  assign     ADC_CS_n =  RSig_start?ADC_CS_n_1:ADC_CS_n_0;
   assign     ADC_SCK =  RSig_start?ADC_SCK_1:ADC_SCK_0;
    assign    ADC_SDI =  RSig_start?ADC_SDI_1:ADC_SDI_0;
endmodule

因为是给ADC初始化,所以仿真就是给个时钟和复位,就不写了

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值