【时序协议】-SPI-驱动模块-实验
作者:互联网
分析
输出信号
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