SPI代码详解FPGA-verilog部分(FPGA+STM32)(一)

声明:本篇文章面向在已对SPI的四种时序有所了解的人

我们采用SPI3模式以及将FPGA作从机,STM32作主机的方式讲解,在STM32控制部分采用的是半双工模式,但其实半双工与全双工区别不大,
稍加修改即可


本文章属于SPI的升级版,将原本的片选线CS_N再多加一根,变成spi_cs_cmd和spi_cs_data,当spi_cs_cmd拉低的时候表示传送的是命令(命令只由单片机发送),当cs_data拉低的时候表示传送的是数据(数据可以是FPGA传给单片机的,也可以是单片机传给FPGA的)




module spi #(
	parameter cmd_width = 8,
	parameter data_width = 32    //这个位宽是可以自己定义的,由于STM32F407的硬件SPI不支持32位,所																		              以在STM32部分我选用了模拟SPI,具体STM32部分代码可以在我的后续文章中查看       
)
(
	input clk,            
	input rstn,
	input spi_scl,					//SCK
	input spi_sdi,					//MOSI
	input spi_cs_cmd,				//CS_CMD
	input spi_cs_data,				//CS_DATA
	input [data_width - 1:0] din,	//送入SPI模块的数据,将来是要通过SPI模块的MISO口传到单片机的
	output reg spi_sdo,				//MISO
	output reg cmd_done,			//通过判断CS_CMD的边沿变化判断CMD命令是不是传输完成
	output reg data_done,			//通过判断CS_DATA的边沿变化判断DATA数据是不是传输完成
	output reg [cmd_width - 1:0] dcmd, //送出SPI模块的数据,即单片机传输给FPGA的bit数据,dcmd为命令
	output reg [data_width - 1:0] dout //送出SPI模块的数据,即单片机传输给FPGA的bit数据,dout为数据
	);
	
	
reg [1:0] r_spi_scl;
reg [1:0] r_cs_cmd;
reg [1:0] r_cs_data;

wire pos_spi_scl;
wire neg_spi_scl;
wire pos_cs_cmd;
wire neg_cs_cmd;
wire en_cs_cmd;
wire pos_cs_data;
wire neg_cs_data;
wire en_cs_data;

reg [data_width - 1:0] r_din;


// 边沿检测
always @(posedge clk , negedge rstn) begin
	if(!rstn)
		r_spi_scl <= 2'd0;
	else
		r_spi_scl <= {r_spi_scl[0], spi_scl};
end

assign pos_spi_scl = (!r_spi_scl[1]) &(r_spi_scl[0]);
assign neg_spi_scl = (r_spi_scl[1])  &(!r_spi_scl[0]);

always @(posedge clk , negedge rstn) begin
	if(!rstn)
		r_cs_cmd <= 2'd0;
	else
		r_cs_cmd <= {r_cs_cmd[0], spi_cs_cmd};
end	

assign pos_cs_cmd = (!r_cs_cmd[1]) &(r_cs_cmd[0]);
assign neg_cs_cmd = (r_cs_cmd[1]) &(!r_cs_cmd[0]);
assign en_cs_cmd = (!r_cs_cmd[1]) &(!r_cs_cmd[0]);

always @(posedge clk , negedge rstn) begin
	if(!rstn)
		r_cs_data <= 2'd0;
	else
		r_cs_data <= {r_cs_data[0], spi_cs_data};
end

assign pos_cs_data = (!r_cs_data[1]) &(r_cs_data[0]);
assign neg_cs_data = (r_cs_data[1]) &(!r_cs_data[0]);
assign en_cs_data = (!r_cs_data[1]) &(!r_cs_data[0]);


// 接收模块
always @(posedge clk , negedge rstn) begin
	if(!rstn)
		dcmd <= 0;
	else if(neg_cs_cmd)
		dcmd <= 0;
	else if(en_cs_cmd) 
		if(pos_spi_scl)     //由于采用的是SPI3模式,所以上升沿采样数据
			dcmd[cmd_width - 1:0] <= {dcmd[cmd_width - 2:0], spi_sdi};
		else
			dcmd[cmd_width - 1:0] <= dcmd[cmd_width - 1:0];
	else
		dcmd <= dcmd;
end

always @(posedge clk , negedge rstn) begin
	if(!rstn)
		dout <= 0;
	else if(neg_cs_data)
		dout <= 0;
	else if(en_cs_data) 		
		if(pos_spi_scl) 			//由于采用的是SPI3模式,所以上升沿采样数据
			dout[data_width - 1:0] <= {dout[data_width - 2:0], spi_sdi};
		else
			dout[data_width - 1:0] <= dout[data_width - 1:0];
	else
		dout <= dout;
end

always @(posedge clk , negedge rstn) begin
	if(!rstn)
		cmd_done <= 1'b0;
	else if(pos_cs_cmd)
		cmd_done <= 1'b1;
	else
		cmd_done <= 1'b0;
end

always @(posedge clk , negedge rstn) begin
	if(!rstn)
		data_done <= 1'b0;
	else if(pos_cs_data)
		data_done <= 1'b1;
	else
		data_done <= 1'b0;
end


// 发送模块
always @(posedge clk , negedge rstn) begin
	if(!rstn) begin
		spi_sdo <= 1'b0;
		r_din <= 0;
	end
	else if(en_cs_data)
		if(neg_spi_scl) begin    //由于采用的是SPI3模式,所以下降沿发送数据
			spi_sdo <= r_din[data_width - 1];
			r_din[data_width - 1:0] <= {r_din[data_width - 2:0], 1'b0};
		end
		else begin
			spi_sdo <= spi_sdo;
			r_din[data_width - 1:0] <= r_din[data_width - 1:0];
		end
	else if(!en_cs_data) begin
		spi_sdo <= spi_sdo;
		r_din[data_width - 1:0] <= din[data_width - 1:0];
	end
	else begin
		spi_sdo <= spi_sdo;
			r_din[data_width - 1:0] <= r_din[data_width - 1:0];
	end
end


endmodule

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA(现场可编程门阵列)和STM32(一种基于ARM架构的微控制器)可以通过SPI(串行外设接口)协议进行通信。在这种通信方式中,FPGA作为SPI通信的从机,而STM32作为主机。 为了实现这种通信,我们需要使用Verilog语言编写从机FPGA代码。首先,我们需要确定FPGASPI接口的基本参数,如数据位宽、时钟频率和时钟极性等。然后,我们可以使用Verilog语言编写从机的SPI控制器,将其连接到FPGA的其他逻辑电路中。 在Verilog代码中,我们需要实现SPI的Slave模式。在SPI通信中,从机始终被动地响应主机的指令,并将数据传送给主机。从机的Verilog代码需要包括两个关键部分:状态机和数据传输。 状态机是从机的控制核心,它根据主机的指令进行状态切换,并管理数据传输过程的流程控制。例如,当主机发起读取指令时,从机会进入接收状态,并将要传输的数据存储到缓冲区中。当主机发起写入指令时,从机会进入发送状态,并将数据从缓冲区传输给主机。 数据传输部分负责实际的数据传输。从机需要实现接收和发送两个功能。接收部分负责接收主机发送的数据,并将其存储到缓冲区中。发送部分负责从缓冲区中读取数据,并将其传输给主机。 在编写Verilog代码时,需要注意时序问题和信号同步。SPI通信需要精确的时钟同步,在从机和主机之间共享和交换数据需要遵循一定的时序要求。因此,在设计代码时要特别注意时钟同步和数据的正确传输顺序。 最后,我们需要将Verilog代码综合到FPGA芯片中,并进行功能验证和调试。在验证过程中,我们可以通过观察FPGA输出波形和和STM32的通信结果来判断通信是否成功。如果通信出现问题,我们可以通过调试代码和时序分析来进行故障排查和修复。 通过以上步骤,我们可以实现FPGA作为从机与STM32进行SPI协议通信,并使用Verilog语言完成代码的设计与实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值