ICode9

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

【协议时序】- SPI-PP写操作-实验

2022-05-11 17:02:42  阅读:161  来源: 互联网

标签:PP SPI start 时序 spi input reg


分析

时序图

在下面的时序图中,指令之前还有一段写使能指令

 

一、设计文件

页写操作模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/10 15:39:07
// Design Name: 
// Module Name: SPI_PP
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module SPI_PP(

input       clk             ,
input       rst_n           ,
input       PP_start        ,

input       out_done        ,
input       in_done         ,
input [7:0] data_out        ,

output reg      spi_start       ,
output reg      spi_end         ,
output reg      W_R             ,
output reg[7:0] data_in

    );
// 指令
parameter   WREN = 8'b0000_0010,
            PP = 8'b0000_0110,
            SECTOR_ADDR = 8'b1000_0010,
            PAGE_ADDR   = 8'b0010_0100,
            BYTE_ADDR   = 8'b0100_0001,
            DATA = 8'b1011_1100;

// 计数器
parameter   MAX_BIT = 6'd40;

// 状态机参数
parameter   IDLE = 6'b000001,
            WREN_STATE = 6'b000010,
            DELAY = 6'b000100,
            PP_STATE_01 = 6'b001000,
            PP_STATE_02 = 6'b010000,
            PP_STATE_03 = 6'b100000;

// 定义计数器
reg [5:0]   cnt_39; 
reg [7:0]   cnt_byte;
reg [3:0]   cnt_10;

// 定义状态机
reg [5:0]   state;
reg [5:0]   next_state;
//-------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        state <= IDLE;
    else
        state <= next_state;
end

always @(*) begin
    case(state)
    IDLE:
        if(PP_start)
            next_state <= WREN_STATE;
        else
            next_state <= IDLE;
    WREN_STATE:
        if(in_done && cnt_byte == 8'd1-1)
            next_state <= DELAY;
        else    
            next_state <= WREN_STATE;
    DELAY:
        if(cnt_10 == 4'd9)
            next_state <= PP_STATE_01;
        else 
            next_state <= DELAY;
    PP_STATE_01:
        if(in_done && cnt_byte == 8'd1-1)
            next_state <= PP_STATE_02;
        else
            next_state <= PP_STATE_01;
    PP_STATE_02:
        if(in_done && cnt_byte == 8'd3-1)
            next_state <= PP_STATE_03;
        else
            next_state <= PP_STATE_02;
    PP_STATE_03:
        if(in_done && cnt_byte == 8'd1-1)
            next_state <= IDLE;
        else
            next_state <= PP_STATE_03;                        
    default:
        next_state <= IDLE;
    endcase
end

//-------------------------------------------------
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        spi_start <= 1'b0;
    else if(state == IDLE && next_state == WREN_STATE)
        spi_start <= 1'b1;
    else if(state == DELAY && next_state == PP_STATE_01)
        spi_start <= 1'b1;  
    else
         spi_start <= 1'b0;        
end
// spi_end要拉高2次
// 传完WREN拉高一次
// 传完PP指令-地址-数据后拉高一次
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        spi_end <= 1'b0;
    else if(state == WREN_STATE && next_state == DELAY)
        spi_end <= 1'b1;
    else if(state == PP_STATE_03 && next_state == IDLE)//状态为PP+位数计数器记到最大值
        spi_end <= 1'b1;
    else
        spi_end <= 1'b0;
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        W_R <= 1'b0;//默认为读操作
    else 
        W_R <= 1'b1;
end

always @(*) begin
    case (state)
    WREN_STATE: data_in <= WREN;
    PP_STATE_01:  data_in <= PP;
    PP_STATE_02:
        case (cnt_byte)
            8'd0:data_in <= SECTOR_ADDR;
            8'd1:data_in <= PAGE_ADDR;
            8'd2:data_in <= BYTE_ADDR; 
            default: data_in <= 8'd0;
        endcase
    PP_STATE_03: data_in <= DATA;
    default: data_in <= 8'd0;
    endcase
end
// 计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt_10 <= 4'd0;
    else if(state == DELAY) begin
        if(cnt_10 == 4'd9)
            cnt_10 <= 4'd0;
        else
            cnt_10 <= cnt_10 + 4'd1;
    end
    else
        cnt_10 <= 4'd0;
end
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt_byte <= 8'd0;
    else if(in_done) begin
        case (state)
        DELAY: cnt_byte <= 8'd0;
        IDLE: cnt_byte <= 8'd0;
        PP_STATE_01: cnt_byte <= 8'd0;
        PP_STATE_02:
            if(cnt_byte == 8'd2)
                cnt_byte <= 8'd0;
            else
                cnt_byte <= cnt_byte + 8'd1;
        PP_STATE_03: cnt_byte <= 8'd0;
        default: cnt_byte <= cnt_byte;
        endcase
    end
    else
        cnt_byte <= cnt_byte;
end
    
endmodule

SPI驱动模块

`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           W_R             ,//判断模块工作模式:读、写

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 = 3'b001,
          WR = 3'b010,
          RD = 3'b100;
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 && W_R == 1'b0)
                next_state <= RD  ;
            else if(spi_start == 1'b1 && W_R == 1'b1)
                next_state <= WR  ;
        RD:
            if(spi_end) 
                next_state <= IDLE  ;        
            else if(cnt_4 == MAX_CNT_4-2'd1 &&  cnt_8 == MAX_CNT_8-4'd1) begin
                    if(W_R == 1'b0) 
                        next_state <= RD  ;
                    else
                        next_state <= WR  ;
             
            end                     
        WR:
            if(spi_end) 
                next_state <= IDLE  ;
            else if(cnt_4 == MAX_CNT_4-2'd1 &&  cnt_8 == MAX_CNT_8-4'd1) begin
                    if(W_R == 1'b0) 
                        next_state <= RD  ;
                    else
                        next_state <= WR  ;
             
            end              
            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(spi_end)
//         spi_SCK <= 1'd0;
//     else if(cnt_4[0] && spi_end == 1'b0)
//         spi_SCK <= ~spi_SCK;
    
// end
// always@(posedge clk or negedge rst_n)begin
//     if(!rst_n)
//         spi_SCK <= 1'd0;
//     else if(cnt_4[0] && state != IDLE)
//         spi_SCK <= ~spi_SCK;
//     else 
//         spi_SCK <= 1'd0;
// end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)
        spi_SCK <= 1'd0;
    else if(cnt_4 == 2'd0 && state != IDLE)
        spi_SCK <= 2'd0;
    else if(cnt_4 == 2'd2 && state != IDLE)
        spi_SCK <= 1'd1;
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_end)//SPI结束工作
        spi_CE <= 1'b1;
    else 
        spi_CE <= spi_CE;
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'd3 && cnt_8 == 3'd7 && state == RD)
        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'd2 && cnt_8 == 3'd7 && state == WR)
        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 == RD)
        data_out[7-cnt_8] <= spi_MISO;
    else
        data_out <= data_out;
end
    
endmodule

顶层模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/10 20:33:57
// Design Name: 
// Module Name: top_SPI_PP_Dirve
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module top_SPI_PP_Dirve(
    input clk,
    input rst_n,
    input spi_MISO,
    input PP_start,

    output spi_SCK,
    output spi_CE,
    output spi_MOSI

    );
    wire spi_start;
    wire spi_end;
    wire W_R;
    wire out_done;
    wire in_done;
    wire [7:0]data_in;
    wire data_out;

SPI_PP SPI_PP_inst
(

.clk(clk)             ,
.rst_n(rst_n)           ,
.PP_start(PP_start),

.out_done(out_done)        ,
.in_done(in_done)         ,
.data_out(data_out)        ,

.spi_start(spi_start)       ,
.spi_end(spi_end)         ,
.W_R(W_R)             ,
.data_in(data_in)

    );

SPI_drive_my SPI_drive_my_inst
(
    
.clk(clk)             ,
.rst_n(rst_n)           ,
.spi_start(spi_start)       ,
.spi_end(spi_end)         ,
.data_in(data_in)         ,
.W_R(W_R)             ,//判断模块工作模式:读、写

.spi_MISO(spi_MISO)        ,
.spi_SCK(spi_SCK)         ,
.spi_CE(spi_CE)          ,
.spi_MOSI(spi_MOSI)        ,

.out_done(out_done)        ,
.in_done(in_done)         ,
.data_out(data_out)        
      
    );
endmodule

二、测试文件

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/10 20:46:39
// Design Name: 
// Module Name: tb_top_SPI_PP
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module tb_top_SPI_PP;

reg clk,rst_n,spi_MISO,PP_start;
wire spi_SCK,spi_CE,spi_MOSI;
initial begin
    clk = 1'b0;
    rst_n = 1'b1;
    #15
    rst_n = 1'b0;
    spi_MISO = 1'b0;
    PP_start = 1'b0;

    #80
    rst_n = 1'b1;
    PP_start = 1'b1;
    #20
    PP_start = 1'b0;

@(negedge spi_SCK);
spi_MISO <= 1'b0;
@(negedge spi_SCK);
spi_MISO <= 1'b0;  
@(negedge spi_SCK);
spi_MISO <= 1'b0;
@(negedge spi_SCK);
spi_MISO <= 1'b0;
@(negedge spi_SCK);
spi_MISO <= 1'b0;
@(negedge spi_SCK);
spi_MISO <= 1'b0;
@(negedge spi_SCK);
spi_MISO <= 1'b1;
@(negedge spi_SCK);
spi_MISO <= 1'b0;

end
always #10 clk = ~clk;

top_SPI_PP_Dirve top_SPI_PP_Dirve_inst
    (
.clk(clk),
.rst_n(rst_n),
.spi_MISO(spi_MISO),
.PP_start(PP_start),
.spi_SCK(spi_SCK),
.spi_CE(spi_CE),
.spi_MOSI(spi_MOSI)

    );
endmodule

三、波形图

 

 

  

 

标签:PP,SPI,start,时序,spi,input,reg
来源: https://www.cnblogs.com/liuxiaoyanfpga/p/16255319.html

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

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

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

ICode9版权所有