SPI主机的Verilog代码及验证(优化版)

这次重新写了一遍初学FPGA时写的SPI主机驱动,减少了代码量,舍弃了状态机,补充了同时发送和接受功能的验证

代码

//Module Name:SPI Master
//Author:Yang Cheng Yu
//Date:2020/4/20
`define SIM
module	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

Test Bench

`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);
	end
end
endmodule

仿真模拟发送0x56,接收0x37数据。波形正确

仿真时序图

在这里插入图片描述

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值