如何让FPGA中的SPI与其他模块互动起来

在上一篇文章《FPGA的SPI从机模块实现》中,已经实现了SPI的从机模块,如何通过SPI总线与FPGA内部其他模块进行通信,是本文的主要讨论内容。

一. 新建FPGA内部DAC控制模块

这里由于手上项目需求,有两块单独DAC902核心板,其中一片DAC902的输出作为另一片DAC902的基准源输入,我们分别称它们为DACref和DACsin,顾名思义一片提供基准源电压,一片输出正弦信号或者扩展成DDS信号输出。
因此,此模块的RTL模型必须有与SPI模块通信端和外部控制DAC902的信号管脚。所以预设计这个模块为:
module dac_reg_rw_spi(clk, nrst, rec_flag, rec_data, send_flag, sending_flag, send_data, dac_clk, dacref_clk, dacref_fudu, dacsin_output);
        input clk, nrst;  //模块系统时钟、复位
//与spi模块交互引脚
	input rec_flag;   //spi字节接收标志
	input[7:0] rec_data;  //spi接收数据缓存寄存器
	input sending_flag;  //spi模块正在发送数据标志位
	
//与spi模块交互引脚
	output send_flag;   //dac控制模块存在需要发送数据标志位,主要负责触发spi发送
	output[7:0] send_data;   //spi需要发送的数据
//与外部dac通信引脚
	output[11:0] dacref_fudu;  //直接输出到dacref中
	output[11:0] dacsin_output;
	output dac_clk;
	output dacref_clk;

这里假定先发送一个字节的命令,紧接着通过spi发送、接收dac控制模块所需的数据。所以定义命令字如下:

//指令代号
	parameter read_dacref_fudukongzhizi=8'b00000001;  //读取dacref的幅度控制字
	parameter read_dacsin_xiangweikongzhizi=8'b00000010;  //读取dacsin的相位控制字
	parameter read_dacsin_pinlvkongzhizi=8'b00000011;  //读取dacsin的频率控制字
	parameter set_dacsin_pinlvkongzhizi=8'b00100001;   //写入dacsin的频率控制字
	parameter set_dacsin_xiangweikongzhizi=8'b00100010;  //写入dacsin的相位控制字
	parameter set_dacref_fudukongzhizi=8'b00100011;  //写入dacref的幅度控制字
	parameter set_dac_clk_pdf=8'b00100100;  //设置dac时钟预分频
	parameter reset_to_default=8'b11100000; //复位dac控制模块
	parameter start_dac=8'b11100001;  //开启dac模块
	parameter stop_dac=8'b11100010;   //停止dac模块

由于spi属于串行接收,一次以8位传输格式,而我们的DDS模块需要32位的频率控制字、10位的相位控制字、12位的基准源幅度控制字(具体DDS原理,由于篇幅有限,这里就不再详细介绍了),因此我们需要读取这几个寄存器或者写入这几个寄存器,需要输出、接收不等的字节长度,而dds模块处于实时运行中,所以这里需要影子寄存器的介入。

//dac配置的影子寄存器(dac运作依据的值)
	reg[11:0] dacref_fudukongzhizi_shadow;
	reg[31:0] dacsin_pinlvkongzhizi_shadow;
	reg[9:0] dacsin_xiangweikongzhizi_shadow;
	reg[3:0] dac_clk_pdf_shadow;

开始设计dac的模块吧:

 
        reg[3:0] rw_reg_status;  //处理spi接收发送数据状态机
	reg[3:0] rw_reg_status_temp;  处理spi接收发送数据状态机(影子寄存器)
	reg[7:0] rec_data_temp;  //8位spi数据接收缓存
	reg[3:0] delay_cnt;  //发送数据延时计数器
	
	//dac配置寄存器临时值
	reg[31:0] dacsin_pinlvkongzhizi;  
	reg[11:0] dacref_fudukongzhizi;
	reg[9:0] dacsin_xiangweikongzhizi;
	
	reg[7:0] send_data;  //与myspi模块通信脚
	reg send_flag;  //与myspi模块通信脚
	reg[2:0] byte_sended_cnt;  //发送数据字节数计数器
	reg[2:0] byte_received_cnt;  //接收数据字节数计数器
	reg dac_start_flag;  //dac使能脚
	reg dacref_clk;
	
	//spi通信处理状态机,需要注意的是,clk时钟频率必须为sck时钟频率约10倍以上,保证正确操作。
	always @ (posedge clk or negedge nrst)
	begin
		if(~nrst)
		begin
        //初始化上述寄存器
			rw_reg_status <= 4'h0;
			rw_reg_status_temp <= 4'h0;  //处理spi接收发送数据状态机(影子寄存器)
			rec_data_temp <= 8'h00;
			dacsin_pinlvkongzhizi <= 32'h00412345;
			dacsin_xiangweikongzhizi <= 10'h123;
			dacref_fudukongzhizi <= 12'h800;
			delay_cnt <= 4'b0000;
			byte_sended_cnt <= 3'b000;
			send_flag <= 1'b0;
			byte_received_cnt <= 3'b000;
			dac_start_flag <= 1'b0;
			dacref_clk <= 1'b0;
			
			dacref_fudukongzhizi_shadow <= 12'h800;
			dacsin_pinlvkongzhizi_shadow <= 32'h00423456;
			dacsin_xiangweikongzhizi_shadow <= 10'h200;
			dac_clk_pdf_shadow <= 4'h1;
		end
		else
		begin 
			 case (rw_reg_status)
			 4'b0000: begin  //从机接收指令
				  if(rec_flag)
				  begin
					   rec_data_temp <= rec_data;
						rw_reg_status <= 4'b0001;  //进入命令解析
				  end
			 end
			 4'b0001: begin  //指令解析,跳转相应状态
				  case (rec_data_temp)
				  reset_to_default: begin
					   rw_reg_status <= 4'b1110;
				  end
				  read_dacref_fudukongzhizi: begin
					   rw_reg_status <= 4'b0011;  //读dacref的幅度控制字
				  end
				  read_dacsin_xiangweikongzhizi: begin
					   rw_reg_status <= 4'b0010;  //读dacsin的相位控制字
				  end
				  read_dacsin_pinlvkongzhizi: begin
					   rw_reg_status <= 4'b0110;  //读dacsin的频率控制字
				  end
				  set_dacsin_pinlvkongzhizi: begin
					   rw_reg_status <= 4'b1101;  //设置dacsin的频率控制字
						rw_reg_status_temp <= 4'b0101;
				  end
				  set_dacsin_xiangweikongzhizi: begin  //设置dacsin的相位控制字
						rw_reg_status <= 4'b1101;
					   rw_reg_status_temp <= 4'b0100;
				  end
				  set_dacref_fudukongzhizi: begin  //设置dacref的幅度控制字
					   rw_reg_status <= 4'b1101;
						rw_reg_status_temp <= 4'b1100;
				  end
				  set_dac_clk_pdf: begin  //设置dac时钟预分频值
					   rw_reg_status <= 4'b1101;
						rw_reg_status_temp <= 4'b1001;
				  end
				  start_dac: begin
					   rw_reg_status <= 4'b1010;
						//rw_reg_status_temp <= 4'b0000;
				  end
				  stop_dac: begin
					   rw_reg_status <= 4'b1011;
						//rw_reg_status_temp <= 4'b0000;
				  end
				  default: begin
					   rw_reg_status <= 4'b1101;
						rw_reg_status_temp <= 4'b0000;
				  end
				  endcase
			 end
			 //----------------------------------------------------
			 4'b0011: begin  //先发送幅度控制字高八位字节然后发送低八位字节
				  if(~sending_flag) begin  //判断spi是否处于发送状态
					  case (byte_sended_cnt)
					  3'b000: begin
							send_data <= {4'b0000, dacref_fudukongzhizi_shadow[11:8]};
							rw_reg_status_temp <= 4'b0011;
							rw_reg_status <= 4'b0111;
					  end
					  3'b001: begin
							send_data <= dacref_fudukongzhizi_shadow[7:0];
							rw_reg_status_temp <= 4'b0011;
							rw_reg_status <= 4'b0111;
					  end
					  default: begin
							byte_sended_cnt <= 3'b000;
							rw_reg_status_temp <= 4'b0000;
							rw_reg_status <= 4'b0000;  //发送完成
					  end
					  endcase
				  end
				  else begin
					  send_flag <= 1'b0;
				  end
			 end
			 //----------------------------------------------------
			 4'b0010: begin
				  if(~sending_flag) begin  //判断spi是否处于发送状态
					  case (byte_sended_cnt)
					  3'b000: begin
							send_data <= {6'b000000, dacsin_xiangweikongzhizi_shadow[9:8]};
							rw_reg_status_temp <= 4'b0010;  //4'b0110;
							rw_reg_status <= 4'b0111;
					  end
					  3'b001: begin
							send_data <= dacsin_xiangweikongzhizi_shadow[7:0];
							rw_reg_status_temp <= 4'b0010;  //4'b0110;
							rw_reg_status <= 4'b0111;
					  end
					  default: begin
							rw_reg_status <= 4'b0000;  //发送完成
							rw_reg_status_temp <= 4'b0000;
							byte_sended_cnt <= 3'b000;
					  end
					  endcase
				  end
				  else begin
					  send_flag <= 1'b0;
				  end
			 end
			 //----------------------------------------------------
			 4'b0110: begin
				  if(~sending_flag) begin  //判断spi模块是否处于发送状态
					  case (byte_sended_cnt)
					  3'b000: begin
							send_data <= dacsin_pinlvkongzhizi_shadow[31:24];
							rw_reg_status_temp <= 4'b0110;
							rw_reg_status <= 4'b0111;  //4'b0100;
					  end
					  3'b001: begin
							send_data <= dacsin_pinlvkongzhizi_shadow[23:16];
							rw_reg_status_temp <= 4'b0110;
							rw_reg_status <= 4'b0111;  //4'b0100;
					  end
					  3'b010: begin 
						   send_data <= dacsin_pinlvkongzhizi_shadow[15:8];
							rw_reg_status_temp <= 4'b0110;
							rw_reg_status <= 4'b0111;
					  end
					  3'b011: begin
						   send_data <= dacsin_pinlvkongzhizi_shadow[7:0];
							rw_reg_status_temp <= 4'b0110;
							rw_reg_status <= 4'b0111;
					  end
					  default: begin
							rw_reg_status <= 4'b0000;  //发送完成
							rw_reg_status_temp <= 4'b0000;
							byte_sended_cnt <= 3'b000;
					  end
					  endcase
				  end
				  else begin
					  send_flag <= 1'b0;
				  end
			 end
//通用状态			 
			 4'b0111: begin
        //dac控制模块向spi模块提出发送请求,即生成send_flag脉冲
				  send_flag <= 1'b1;
				  if(delay_cnt == 4'b0011)
				  begin
					   delay_cnt <= 4'b0000;
						rw_reg_status <= rw_reg_status_temp;
						byte_sended_cnt <= byte_sended_cnt+1;
				  end
				  else
				  begin
					   delay_cnt <= delay_cnt+1;
				  end
			 end
			 //----------------------------------------------------
			 4'b0101: begin
				  //if(rec_flag) begin  
					  case (byte_received_cnt)
					  3'b000: begin
							if(rec_flag) begin  //spi字节接收完成标志位
								dacsin_pinlvkongzhizi[31:24] <= rec_data;
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b001;
							end
					  end
					  3'b001: begin
							if(rec_flag) begin
								dacsin_pinlvkongzhizi[23:16] <= rec_data;
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b010;
							end
					  end
					  3'b010: begin
							if(rec_flag) begin
								dacsin_pinlvkongzhizi[15:8] <= rec_data;
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b011;
							end
					  end
					  3'b011: begin
							if(rec_flag) begin
								dacsin_pinlvkongzhizi[7:0] <= rec_data;
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b100;
							end
					  end
					  3'b100: begin
							dacsin_pinlvkongzhizi_shadow <= dacsin_pinlvkongzhizi;
							byte_received_cnt <= 3'b101;
					  end
					  3'b101: begin
							rw_reg_status <= 4'b1101;
							rw_reg_status_temp <= 4'b0000;
							byte_received_cnt <= 3'b000;
					  end
					  endcase
				  //end
			 end
			 //----------------------------------------------------
        //在spi接收到命令字时,下一个系统时钟clk上跳沿则进入此状态,此时rec_flag可能仍然是有效,所以会先进入4'b1101模块等待rec_flag标志位复位后再接收数据,其他状态其实大同小异,这里不一一描述。
			 4'b0100: begin
				  //if(rec_flag) begin
					  case (byte_received_cnt)
					  3'b000: begin
							if(rec_flag) begin
								dacsin_xiangweikongzhizi[9:8] <= rec_data[1:0];
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b001;
							end
					  end
					  3'b001: begin
							if(rec_flag) begin
								dacsin_xiangweikongzhizi[7:0] <= rec_data;
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b010;
							end
					  end
					  3'b010: begin
							dacsin_xiangweikongzhizi_shadow <= dacsin_xiangweikongzhizi;
							byte_received_cnt <= 3'b011;
					  end
					  3'b011: begin
							rw_reg_status <= 4'b1101;  //4'b0000;
							rw_reg_status_temp <= 4'b0000;
							byte_received_cnt <= 3'b000;
					  end
					  endcase
				  //end
			 end
			 //----------------------------------------------------
			 4'b1100: begin
				  //if(rec_flag) begin
					  case (byte_received_cnt)
					  3'b000: begin
							if(rec_flag) begin
								dacref_fudukongzhizi[11:8] <= rec_data[3:0];
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b001;
							end
					  end
					  3'b001: begin
							if(rec_flag) begin
								dacref_fudukongzhizi[7:0] <= rec_data;
								rw_reg_status <= 4'b1101;
								byte_received_cnt <= 3'b010;
							end
					  end
					  3'b010: begin
							dacref_fudukongzhizi_shadow <= dacref_fudukongzhizi;
							byte_received_cnt <= 3'b011;
					  end
					  3'b011: begin
							dacref_clk <= 1'b1;
							if(delay_cnt == 4'b0011)
							begin
								delay_cnt <= 4'b0000;
								byte_received_cnt <= 3'b111;
						   end
						   else
						   begin
								delay_cnt <= delay_cnt+1;
						   end
					  end
					  3'b111: begin
							dacref_clk <= 1'b0;
							rw_reg_status <= 4'b1101;
							rw_reg_status_temp <= 4'b0000;
							byte_received_cnt <= 3'b000;
					  end
					  endcase
				  //end
			 end
			 
			 4'b1101: begin
				  if(~rec_flag) begin  //字节接收完成标志位复位等待
					   rw_reg_status <= rw_reg_status_temp;
				  end
			 end
			 //----------------------------------------------------
			 4'b1110: begin
				  dacsin_pinlvkongzhizi <= 32'h00454321;
				  dacsin_xiangweikongzhizi <= 10'h234;
				  dacref_fudukongzhizi <= 12'h321;
				  rw_reg_status_temp <= 4'b0000;
				  rw_reg_status <= 4'b1101;
			 end
			 4'b1111: begin
				  if(delay_cnt == 4'b0011)
				  begin
					   delay_cnt <= 4'b0000;
						rw_reg_status <= 4'b0000;
				  end
				  else
				  begin
					   delay_cnt <= delay_cnt+1;
				  end
			 end
			 //----------------------------------------------------
			 4'b1010: begin
				  dac_start_flag <= 1'b1;
				  rw_reg_status <= 4'b1101;
				  rw_reg_status_temp <= 4'b0000;
			 end
			 //----------------------------------------------------
			 4'b1011: begin
				  dac_start_flag <= 1'b0;
				  rw_reg_status <= 4'b1101;
				  rw_reg_status_temp <= 4'b0000;
			 end
			 //----------------------------------------------------
			 4'b1001: begin
				  if(rec_flag) begin
					   dac_clk_pdf_shadow <= rec_data[3:0];
						rw_reg_status <= 4'b1101;
						rw_reg_status_temp <= 4'b0000;
				  end
			 end
			 endcase
		end
	end

既然dac控制模块的spi接收和发送设计好了,dds模块当然不能少,这部分就相对简单些。

//dac时钟分频模块
	reg dac_clk;
	reg[3:0] dac_clk_cnt;  //分频,后面可以对dac_clk_cnt进行预分频处理
	reg[3:0] dac_clk_pdf;  //预分频
	always @ (posedge clk or negedge nrst)
	begin
		 if(~nrst)
		 begin
			  dac_clk <= 1'b0;
			  dac_clk_cnt <= 4'b0;
			  dac_clk_pdf <= 4'h1;
		 end
		 else begin
			  if(dac_start_flag) begin
				  if(dac_clk_cnt == dac_clk_pdf) begin
						dac_clk_cnt <= 4'b0;
						dac_clk <= ~dac_clk;
						dac_clk_pdf <= dac_clk_pdf_shadow;
				  end
				  else begin
						dac_clk_cnt <= dac_clk_cnt+1;
				  end
			  end
		 end
	end
	
	//dac输出模块
	assign dacref_fudu = dacref_fudukongzhizi_shadow;  //直接输出到dacref中
	//reg[11:0] dacsin_output;
	reg[31:0] leijiazi;
	reg[9:0] dac_rom_addr;
	//assign dacsin_enable = nrst&dac_start_flag;
	always @ (posedge clk or negedge nrst)
	begin
		 if(~nrst)  //dacsin失能
		 begin
			  leijiazi <= {dacsin_xiangweikongzhizi_shadow, 22'h000000};  //累加字存储器
			  dac_rom_addr <= 10'h000;
		 end
		 else  //dacsin使能
		 begin
			  if(dac_start_flag) begin
				   leijiazi <= leijiazi+dacsin_pinlvkongzhizi_shadow;
					dac_rom_addr <= leijiazi[31:22];
			  end
			  else begin
				   dac_rom_addr <= 10'h000;
			  end
		 end
	end
	
	sin_table U3(
	  .clka(clk),
	  .addra(dac_rom_addr),
	  .douta(dacsin_output)
	);
这里用到了名为sin_table的ROM软核,使用Block RAM组合成12位数据输出,10位数据深度(即1024个存储空间)的ROM,空间为12bits*1024。

题外话:既然提到了核,那么想当然联想到他们的分类:软核、固核和硬核三种。

软核:属于综合之前的RTL模型,只经过功能仿真,最后需要进行综合及布线后才能使用。但是不同的布线环境对其效果是不一样的,存在发送错误的可能性。

固核:带有局部规划信息的网表,对时序有一定约束后的产物,只需要通过布线工具就可以使用。

硬核:就是经过验证的设计版图,其物理版图不允许再进行修改,模块时序要求非常严格,可靠性相当高。

二. 修改spi从机模块

根据上面的dac控制模块,我们需要对先前的spi从机模块进行适当修改。
module myspi(nrst, clk, ncs, mosi, miso, sck, rec_flag, rec_data, send_flag, sending_flag, send_data);  //miso主入从出,mosi主出从入
	input clk, nrst;
	input ncs, mosi, sck;
	input send_flag;
	input[7:0] send_data;
	output[7:0] rec_data;
	output miso;
	output sending_flag;
	output rec_flag;
这样,spi模块就加入与dac控制模块的通信线路了,是不是很方便。

三. 生成顶层模块

这个主要是考虑fpga最终IO口输出情况,有点像将模块打包成一个模块,在外看FPGA内部模块相当于一个黑匣子,我们操作的时候则只关心FPGA留给我们的通信管脚就可以了。
module dac_top(clk, nrst, ncs, mosi, miso, sck, dac_clk, dacref_fudu, dacsin_output, dacref_clk);
	input clk, nrst, ncs;
	input mosi, sck;
	output miso;
	
	output dac_clk;
	output dacref_clk;
	output[11:0] dacref_fudu;
	output[11:0] dacsin_output;
	
	wire send_flag, rec_flag, sending_flag;
	wire[7:0] rec_data;
	wire[7:0] send_data;
	
	myspi U1(
		.clk(clk), 
		.nrst(nrst), 
		.ncs(ncs), 
		.mosi(mosi), 
		.miso(miso), 
		.sck(sck), 
		.rec_flag(rec_flag), 
		.rec_data(rec_data), 
		.send_flag(send_flag), 
		.sending_flag(sending_flag), 
		.send_data(send_data)
	);
	
	dac_reg_rw_spi U2(
		.clk(clk), 
		.nrst(nrst), 
		.rec_flag(rec_flag), 
		.rec_data(rec_data), 
		.send_flag(send_flag), 
		.sending_flag(sending_flag), 
		.send_data(send_data),
		.dac_clk(dac_clk),
		.dacref_fudu(dacref_fudu),
		.dacsin_output(dacsin_output),
		.dacref_clk(dacref_clk)
	);

endmodule

四. ModelSim的功能验证

module dac_top_test;

	// Inputs
	reg clk;
	reg nrst;
	reg ncs;
	reg mosi;
	reg sck;

	// Outputs
	wire miso;
	wire dac_clk;
	wire[11:0] dacref_fudu;
	wire[11:0] dacsin_output;

	// Instantiate the Unit Under Test (UUT)
	dac_top uut (
		.clk(clk), 
		.nrst(nrst), 
		.ncs(ncs), 
		.mosi(mosi), 
		.miso(miso), 
		.sck(sck),
		.dac_clk(dac_clk),
		.dacref_fudu(dacref_fudu),
		.dacsin_output(dacsin_output)
	);

	initial begin
		// Initialize Inputs
		clk = 0;
		nrst = 0;
		ncs = 1;
		mosi = 0;
		sck = 0;

		// Wait 100 ns for global reset to finish
		#100;
		nrst = 1;
		#20;
		ncs = 0;
		
		#100;	         mosi = 0;  //先发送高位 00100011 写入频率控制字
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0;
		//
		#100;	         mosi = 0;  //发送 00001111
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0;
		//
		#100;	         mosi = 1;  //发送 11111110
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0;
		//
      #100;	         mosi = 0;  //发送 00000001
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0;  
		//
		#100;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;	
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		//
		#100;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;	
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		#100 sck = 1;  #100 sck = 0;
		//
      #100;	         mosi = 1;  //发送 11100001  启动dac控制模块
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; 
		//
		#50000;        mosi = 0;  //延时50000个时间单元后再次修改频率控制字
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0;
		//
		#100;	         mosi = 0;  
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 1;		
		#100; sck = 1;
		#100; sck = 0;
		//
		#100;	         mosi = 0;  
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0;
		//
		#100;	         mosi = 0;  
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0;
		//
		#100;	         mosi = 0;  
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0; mosi = 0;	
		#100; sck = 1;
		#100; sck = 0; mosi = 0;		
		#100; sck = 1;
		#100; sck = 0;
	end
	
	always #5 clk=~clk;  //sck必须为clk的频率的十分之一或低于十分之一
      
endmodule
如何让FPGA中的SPI与其他模块互动起来_第1张图片
最终的实物图~~
如何让FPGA中的SPI与其他模块互动起来_第2张图片
如何让FPGA中的SPI与其他模块互动起来_第3张图片



你可能感兴趣的:(FPGA,fpga,verilog,spi,dac902)