ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【时序协议】-SPI-驱动模块-实验

2022-05-09 21:03:53  阅读:235  来源: 互联网

标签:SCK spi 时序 SPI 模块 output input reg


分析

输出信号

SCK、MOSI

SCK使用计数器实验4分频,在计数器cnt_4[0]=1的地方进行SCK翻转,就可以得到SCK输出信号

MOSI信号也需要使用cnt_4实现,分析如下图

MOSI的重点就是确定出什么时候采集信号、什么时候更新数据(即通过模式确定这2个重点)

 

一、设计文件

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/04/29 21:51:51
// Design Name: 
// Module Name: SPI
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// SPI驱动模块,工作在模式0,即SCK空闲状态为低电平,SCK下降沿更新MOSI的数据,MSB
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module SPI_drive_my(
    
input           clk             ,
input           rst_n           ,
input           spi_start       ,
input           spi_end         ,
input   [7:0]   data_in         ,

input             spi_MISO        ,
output    reg      spi_SCK         ,
output    reg      spi_CE          ,
output    reg     spi_MOSI        ,

output  reg        out_done        ,
output  reg        in_done         ,
output  reg [7:0]   data_out        
      
    );
// 定义状态机
parameter IDLE = 2'b01,
          DATA = 2'b10;
reg     [2:0]       state       ;
reg     [2:0]       next_state  ;

//定义计数器
reg     [1:0]       cnt_4      ;
reg     [3:0]       cnt_8       ;
parameter           MAX_CNT_4  =   3        ,
                    MAX_CNT_8   =   7       ;

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        state <= IDLE     ;
    else
        state <= next_state     ;
end

always @(*) begin
    case(state)
        IDLE:
            if(spi_start == 1'b1)
                next_state <= DATA  ;
            else
                next_state <= IDLE  ;
        DATA:
            if(cnt_4 == MAX_CNT_4 &&  cnt_8 == MAX_CNT_8 && spi_end) 
               next_state <= IDLE  ;
            else   
                next_state <= DATA  ;
            default:next_state <= IDLE  ;
    endcase
end

// 计数器
// SCK时钟计数器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt_4  <=  2'd0   ;
    else if(state != IDLE)
        cnt_4  <=  cnt_4  +   2'd1   ;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt_8 <= 8'd0;
    else if(cnt_4 == MAX_CNT_4)begin
            cnt_8 <= cnt_8 + 8'd1;
        if(cnt_8 == MAX_CNT_8)
            cnt_8 <= 8'd0;
    end

end

// 输出信号
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_SCK <= 1'd0;
    else if(cnt_4[0])
        spi_SCK <= ~spi_SCK;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_CE <= 1'b1;
    else if(spi_start == 1'b1)//SPI开始工作
        spi_CE <= 1'b0;
    else if(next_state == IDLE && cnt_8 == MAX_CNT_8 )//SPI结束工作
        spi_CE <= 1'b1;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_MOSI <= 1'b0;
    else if(!spi_CE && cnt_4 == 2'd0)//0模式、BSM 
        spi_MOSI <= data_in[7-cnt_8];
    else if(spi_CE)
        spi_MOSI <= 1'b0;
    else
        spi_MOSI <= spi_MOSI;
end
// 发送数据完成-标志位
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        out_done <= 1'b0;
    else if(cnt_4 == 2'd0 && cnt_8 == 3'd7)
        out_done <= 1'd1;
    else 
        out_done <= 1'b0;
end
// 接收数据完成-标志位
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        in_done <= 1'b0;
    else if(cnt_4 == 2'd0 && cnt_8 == 3'd7)
        in_done <= 1'd1;
    else 
        in_done <= 1'b0;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_out <= 8'd0;
    else if(cnt_4 == 2'd0 && state == IDLE)
        data_out[7-cnt_8] <= spi_MISO;
    else
        data_out <= data_out;
end

    
endmodule

二、测试文件

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/04/29 21:51:51
// Design Name: 
// Module Name: SPI
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// SPI驱动模块,工作在模式0,即SCK空闲状态为低电平,SCK下降沿更新MOSI的数据,MSB
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module My_SPI_Drive(
    
input           clk             ,
input           rst_n           ,
input           spi_start       ,
input           spi_end         ,
input   [7:0]   data_in         ,

input             spi_MISO        ,
output    reg      spi_SCK         ,
output    reg      spi_CE          ,
output    reg     spi_MOSI        ,

output  reg        out_done        ,
output  reg        in_done         ,
output  reg [7:0]  data_out        
      
    );
// 定义状态机
parameter IDLE = 2'b01,
          DATA = 2'b10;
reg     [2:0]       state       ;
reg     [2:0]       next_state  ;

//定义计数器
reg     [1:0]       cnt_4      ;
reg     [3:0]       cnt_8       ;
parameter           MAX_CNT_4  =   3        ,
                    MAX_CNT_8   =   7       ;

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        state <= IDLE     ;
    else
        state <= next_state     ;
end

always @(*) begin
    case(state)
        IDLE:
            if(spi_start == 1'b1)
                next_state <= DATA  ;
            else
                next_state <= IDLE  ;
        DATA:
            if(cnt_4 == MAX_CNT_4 &&  cnt_8 == MAX_CNT_8 && spi_end) 
               next_state <= IDLE  ;
            else   
                next_state <= DATA  ;
            default:next_state <= IDLE  ;
    endcase
end

// 计数器
// SCK时钟计数器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt_4  <=  2'd0   ;
    else if(state != IDLE)
        cnt_4  <=  cnt_4  +   2'd1   ;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        cnt_8 <= 8'd0;
    else if(cnt_4 == MAX_CNT_4)begin
            cnt_8 <= cnt_8 + 8'd1;
        if(cnt_8 == MAX_CNT_8)
            cnt_8 <= 8'd0;
    end

end

// 输出信号
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_SCK <= 1'd0;
    else if(cnt_4[0])
        spi_SCK <= ~spi_SCK;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_CE <= 1'b1;
    else if(spi_start == 1'b1)//SPI开始工作
        spi_CE <= 1'b0;
    else if(next_state == IDLE && cnt_8 == MAX_CNT_8 )//SPI结束工作
        spi_CE <= 1'b1;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_MOSI <= 1'b0;
    else if(!spi_CE && cnt_4 == 2'd0)//0模式、BSM 
        spi_MOSI <= data_in[7-cnt_8];
    else if(spi_CE)
        spi_MOSI <= 1'b0;
    else
        spi_MOSI <= spi_MOSI;
end
// 发送数据完成-标志位
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        out_done <= 1'b0;
    else if(cnt_4 == 2'd0 && cnt_8 == 3'd7)
        out_done <= 1'd1;
    else 
        out_done <= 1'b0;
end
// 接收数据完成-标志位
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        in_done <= 1'b0;
    else if(cnt_4 == 2'd0 && cnt_8 == 3'd7)
        in_done <= 1'd1;
    else 
        in_done <= 1'b0;
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_out <= 8'd0;
    else if(cnt_4 == 2'd0 && state == IDLE)
        data_out[7-cnt_8] <= spi_MISO;
    else
        data_out <= data_out;
end

    
endmodule

 

三、波形图

标签:SCK,spi,时序,SPI,模块,output,input,reg
来源: https://www.cnblogs.com/liuxiaoyanfpga/p/16211776.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有