标签: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. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。