本文共 4022 字,大约阅读时间需要 13 分钟。
这次重新写了一遍初学FPGA时写的SPI主机驱动,减少了代码量,舍弃了状态机,补充了同时发送和接受功能的验证
//Module Name:SPI Master//Author:Yang Cheng Yu//Date:2020/4/20`define SIMmodule spi_master( //system signal input clk, input rst_n, //spi_master interface output reg sclk, output reg mosi, input miso, input [7:0] data_tx, output reg [7:0] data_rx, //others input tx_req, output reg flag_work, output cs);//parameter and defines localparam SYS_FRE = 50_000_000; `ifndef SIM localparam SCLK_FRE = 1000; localparam BAUD_CNT_END = SYS_FRE/SCLK_FRE-1; localparam BAUD_CNT_HALF = SYS_FRE/SCLK_FRE/2-1; `else localparam BAUD_CNT_END = 499; localparam BAUD_CNT_HALF = 249; `endif// localparam BAUD_CNT_1_half2 = SYS_FRE/SCLK_FRE/4-1;//system regs reg[7:0] data_tx_reg; reg[15:0] cnt_baud; reg[2:0] cnt_bit; reg tx_req_t0; reg tx_req_t1; wire trig_tx_req; wire flag_bit; reg[7:0] data_rx_reg;//main_code //trig_tx_req always @(posedge clk)begin tx_req_t0 <= tx_req; tx_req_t1 <= tx_req_t0; end assign trig_tx_req = tx_req_t0&(~tx_req_t1); //sclk always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) sclk <= 1'b0; else if(cnt_baud==BAUD_CNT_HALF) sclk <= 1'b1; else if(cnt_baud==BAUD_CNT_END) sclk <= 1'b0; end //data_tx_reg always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) data_tx_reg <= 'd0; else if(trig_tx_req==1'b1&&flag_work==1'b0) data_tx_reg <= data_tx; end //cnt_baud always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) cnt_baud <= 'd0; else if(flag_work==1'b1) if(cnt_baud==BAUD_CNT_END) cnt_baud <= 'd0; else cnt_baud <= cnt_baud + 1'b1; else cnt_baud <= 'd0; end //cnt_bit always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) cnt_bit <= 'd0; else if(flag_bit==1'b1&&cnt_bit==3'd7) cnt_bit <= 'd0; else if(flag_bit==1'b1) cnt_bit <= cnt_bit + 1'b1; end //mosi always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) mosi <= 1'b0; else if(cnt_baud==BAUD_CNT_HALF) mosi <= data_tx_reg[7-cnt_bit]; end //flag_work always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) flag_work <= 1'b0; else if(flag_work==1'b0&&trig_tx_req==1'b1) flag_work <= 1'b1; else if(flag_work==1'b1&&cnt_bit==3'd7&&flag_bit==1'b1) flag_work <= 1'b0; end //flag_bit assign flag_bit = (cnt_baud==BAUD_CNT_END)?1'b1:1'b0; //data_rx_reg always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) data_rx_reg <= 'd0; else if(flag_work==1'b1) if(cnt_baud==BAUD_CNT_HALF) data_rx_reg <= { data_rx_reg[6:0],miso}; end //data_rx always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0) data_rx <= 'd0; else if(cnt_bit==7&&flag_bit==1'b1) data_rx <= data_rx_reg; end //cs assign cs = ~flag_work; endmodule
`timescale 1ns/1ns //时间精度`define clock_period 20 //时钟周期module tb_spi_master; //实体名称//===================== <系统端口> =============================reg clk;reg rst_n;//===================== <外设端口> =============================wire sclk;wire mosi;reg miso;reg [7:0] data_tx;wire[7:0] data_rx;reg tx_req;wire flag_work;wire cs;integer i;reg[7:0] data;spi_master spi_master_inst( //system signal .clk (clk), .rst_n (rst_n), //spi_master interface .sclk (sclk), .mosi (mosi), .miso (miso), .data_tx (data_tx), .data_rx (data_rx), //others .tx_req (tx_req), .flag_work (flag_work), .cs (cs));//===================== <时钟信号> =============================initial begin clk = 1; forever #(`clock_period/2) clk = ~clk;end//===================== <复位信号> =============================initial begin rst_n = 0;#(`clock_period*20+1); rst_n = 1;end//===================== <激励信号> =============================initial begin data_tx = 8'h00; tx_req = 1'b0; #(`clock_period*20+1);//初始化 data_tx = 8'h56; #100; tx_req = 1'b1; #20; tx_req = 1'b0;end initial begin miso = 0; data = 8'h00; #(`clock_period*20+1);//初始化 #100; data = 8'h37; for(i=0;i<7;i=i+1)begin miso = data[7-i]; #(`clock_period*500); endendendmodule 激励信号> 复位信号> 时钟信号> 外设端口> 系统端口>
仿真模拟发送0x56,接收0x37数据。波形正确
转载地址:http://nvug.baihongyu.com/