基于Spartan6系列FPGA的AD4683双道数据采集+SRAM+串口发送设计——学习笔记整理第三天-20220313

今天在昨天的基础上对AD4683的的双通道读数据进行了改进,同时编写了对寄存器的写时序进行了编写,先附上代码如下,具体一些细节将在代码后进行讨论。


/* 本文件搭建一个同步双通道的AD4683控制模块 */

/*
	input	clk,			驱动时钟,50MHz
	input	rst_n,			复位信号
	input	AD_SDA,			AD4683通道A的数据线
	input	AD_SDB,			AD4683通道B的数据线
	input	AD_RdorWr_Req,	AD4683读或写取请求信号(读为1,写为2,空闲为0)
	(计划利用串口接收模块接受标志,来开启读取或写寄存器)
	
	output	reg				CS_n			AD4683片选寄存器
	output	reg				AD_SDI,			AD4683写操作数据线
	output	reg				SPI_Clock,		AD4683的SPI驱动时钟
	output	reg		[15:0]	ChannelA_Data,	输出至SRAM的A通道数据
	output	reg		[15:0]	ChannelB_Data,	输出至SRAM的B通道数据
	output	reg				AD_Read_Finish	AD4683读取结束标志
	output	reg				AD_Write_Finish	AD4683写结束标志
*/

module AD4683_Control
(
	input			clk,
	input			rst_n,
	input			AD_SDA,
	input			AD_SDB,
	input	[1:0]	AD_RdorWr_Req,
	
	output	reg				CS_n,
	output	reg				AD_SDI,
	output	reg				SPI_Clock,
	output	reg		[15:0]	ChannelA_Data,
	output	reg		[15:0]	ChannelB_Data,
	output	reg				AD_Read_Finish,
	output	reg				AD_Write_Finish
	
);

/*
	参数定义:
			Read	= 2'd1,读状态
			Write	= 2'd2,写状态
			Idle	= 2'd0;空闲状态
	
*/

parameter	Read	= 2'd1,
			Write	= 2'd2,
			Idle	= 2'd0;	


/*
	Cnt_Read:8位的计数器
	用于控制AD4683的250KHz的采样率时序读取
	由于输入时钟为50MHz,周期为20ns,因此需要对其进行计数实现250KHz.
    一次完整的读操作时间要200*20ns=4000ns.
*/
reg [7:0]	Cnt_Read;
always @(posedge clk or negedge rst_n)
	if(!rst_n)
		Cnt_Read <=8'd199;
	else 
		begin
			case(AD_RdorWr_Req)
				Read:	
						begin
							if(Cnt_Read<8'd199)
								Cnt_Read <= Cnt_Read + 8'd1;
							else
								Cnt_Read <=8'd0;
						end
				default:Cnt_Read <= 8'd0;
			endcase
		end

		
/*
		Cnt_Write:写时序计数器
		用于对AD4683的寄存器进行写时序的计数操作
*/
reg [7:0]	Cnt_Write;

always @(negedge clk or negedge rst_n)
	if(!rst_n)
		Cnt_Write <= 8'd199;
	else
		begin
			case(AD_RdorWr_Req)
				Write:
						begin
							if(Cnt_Write < 8'd199)
								Cnt_Write <= Cnt_Write +1;
							else
								Cnt_Write <= 8'd0;
						end
				default:Cnt_Write <= 8'd0;
			endcase
		end


/*	片选管脚CS_n	*/
/*
	1、复位后默认为高电平
	2、空闲状态保持高电平
	3、当且仅当输入的空闲状态信号变为0,即处于忙碌状态,且有
	读或写请求时才进行拉低
*/
always	@(posedge clk or negedge rst_n)
	if(!rst_n)
		CS_n <= 1'b1;
	else
		begin
			case(AD_RdorWr_Req)
				Idle:	CS_n <= 1'b1;
				Read:
						begin
							if(Cnt_Read < 8'd99)
								CS_n <= 1'b0;
							else if(Cnt_Read == 8'd99)
								CS_n <= 1'b1;
							else if(Cnt_Read == 8'd199)
								CS_n <= 1'b0;
						end
				Write:	
						begin
							if(Cnt_Write < 8'd99)
								CS_n <= 1'b0;
							else if(Cnt_Write == 8'd99)
								CS_n <= 1'b1;
							else if(Cnt_Write == 8'd199)
								CS_n <= 1'b1;
						end
				default:CS_n <= 1'b1;
			endcase
				
		end

/*
	SPI_Clock:	AD4683的SPI驱动时钟
*/
always	@(posedge clk or negedge rst_n)
	if(!rst_n)
		SPI_Clock <= 1'b1;
	else if(CS_n == 1'b0)
		begin
			case(AD_RdorWr_Req)
				Read:
					begin
						if(Cnt_Read >=20 && Cnt_Read < 52)
							SPI_Clock <= ~SPI_Clock;
						else
							SPI_Clock <= 1'b1;
					end
				Write:
					begin
						if(Cnt_Write >=20 && Cnt_Write < 52)
							SPI_Clock <= ~SPI_Clock;
						else
							SPI_Clock <= 1'b1;
					end
				default:SPI_Clock <= 1'b1;
			endcase
		end



/*
	Cnt_data:定义数据个数寄存器,利用SPI时序读取或写寄存器16个数据
*/
reg [4:0]Cnt_data;
always @(posedge SPI_Clock or negedge rst_n)
	if(!rst_n)
		Cnt_data <=5'd0;
	else if(Cnt_data<5'd15 && CS_n == 1'b0 && (AD_RdorWr_Req == 2'd1))
		Cnt_data <=Cnt_data + 1;
	else if(Cnt_data == 5'd15 && (AD_RdorWr_Req == 2'd1))
		Cnt_data <= 5'd0;
	else if(CS_n == 1'b1 )
		Cnt_data <=5'd0;
		
		
/*	
	ChannelA_Data:通道A数据寄存器	

 */
always @(posedge SPI_Clock or negedge rst_n)
	if(!rst_n)
		ChannelA_Data <=16'h00;
	else if((Cnt_data <5'd16) && (CS_n == 0) &&(AD_RdorWr_Req == 2'd1))
		begin
			ChannelA_Data <={ChannelA_Data[14:0],AD_SDA};
		end
		
/*	
	ChannelB_Data:通道A数据寄存器	

 */
always @(posedge SPI_Clock or negedge rst_n)
	if(!rst_n)
		ChannelB_Data <=16'h00;
	else if( (Cnt_data <5'd16) && (CS_n == 0) && (AD_RdorWr_Req == 2'd1))
		begin
			ChannelB_Data <={ChannelB_Data[14:0],AD_SDB};
		end	
	

/*
	AD_SDI:	写数据寄存器

	写条件:
	由于需要配置为外部的基准电压源,因此需要将Register1 的REFSEL位写1
	SDI写的数据为1001_0000_0000_0010
*/
always @(posedge clk or negedge rst_n)
	if(!rst_n)
			AD_SDI <= 	1'b0;
	else if((CS_n == 0) &&(AD_RdorWr_Req == 2'd2)&&(Cnt_Write == 19 || Cnt_Write == 20||Cnt_Write == 25||Cnt_Write == 26 || Cnt_Write == 47||Cnt_Write == 48))
			AD_SDI<= 1'b1;
	else
		
		AD_SDI<= 1'b0;
		



/*
		Write_data_time:写数据个数计数器
*/
reg [4:0]Write_data_time;
always @(negedge SPI_Clock or negedge rst_n)
	if(!rst_n)
		Write_data_time <= 5'd0;
	else if(AD_RdorWr_Req == 2'd2)
		Write_data_time <= Write_data_time+1'b1;
	else
		Write_data_time <= 5'd0;
	
endmodule

上面代码是对AD4683的控制模块,要注意一点是,读数据的通道A与B的触发边沿是SPI_Clock,而写通道数据SDI的触发边沿是输入时钟clk。这主要是根据读写的特性不同而来的。对于读操作而言,利用SPI_Clock的上升沿读出由AD4683传递出来的数据即可;但是对于写操作,写的数据需要我们利用输入的时钟不断更新,在SPI_Clock的下降沿来时已经准备好,这样就可以写入外部的AD4683。可以附上AD4683的时序图如下:

 

`timescale 1ns / 1ps


// Company: 浙江理工大学
// Engineer:
//
// Create Date:   21:19:54 03/13/2022
// Design Name:   AD4683_Control
// Module Name:   E:/Graduation_Design/FPGA_Code/SRAM_Read/Sef_Design/TestBench/AD4683_tb.v
// Project Name:  AD4683_Sram
// Target Device:  
// Tool versions:  
// Description: 这是AD4683控制模块的工程测试文件,一般称为testbench文件
//
// Verilog Test Fixture created by ISE for module: AD4683_Control
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 


module AD4683_tb;

	// Inputs
	reg clk;
	reg rst_n;
	reg AD_SDA;
	reg AD_SDB;
	reg [1:0] AD_RdorWr_Req;

	// Outputs
	wire CS_n;
	wire AD_SDI;
	wire SPI_Clock;
	wire [15:0] ChannelA_Data;
	wire [15:0] ChannelB_Data;
	wire AD_Read_Finish;
	wire AD_Write_Finish;

	// Instantiate the Unit Under Test (UUT)
	AD4683_Control uut (
		.clk(clk), 
		.rst_n(rst_n), 
		.AD_SDA(AD_SDA), 
		.AD_SDB(AD_SDB), 
		.AD_RdorWr_Req(AD_RdorWr_Req), 
		.CS_n(CS_n), 
		.AD_SDI(AD_SDI), 
		.SPI_Clock(SPI_Clock), 
		.ChannelA_Data(ChannelA_Data), 
		.ChannelB_Data(ChannelB_Data), 
		.AD_Read_Finish(AD_Read_Finish),
		.AD_Write_Finish(AD_Write_Finish)
	);

	initial begin
		// Initialize Inputs
		clk = 0;
		rst_n = 0;
		AD_RdorWr_Req = 0;
		AD_SDA=1;
		AD_SDB=0;
		#20;
		rst_n = 1;
		AD_RdorWr_Req = 1;
		#400
		AD_SDA=0;
		AD_SDB=1;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=0;
		AD_SDB=1;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=0;
		AD_SDB=1;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#40
		AD_SDA=1;
		AD_SDB=0;
		#2000
		AD_RdorWr_Req = 2;
		#4000
		AD_RdorWr_Req = 1;
		
		// Wait 100 ns for global reset to finish
        
		// Add stimulus here

	end
	
/* 设置驱动时钟为50MHz */	
always #10	clk = ~clk;
      
endmodule

通过功能仿真,可验证保证的AD4683双通道的同步采样率在250kHz,对寄存器1进行写0x9002

 双通道读操作功能仿真时序图

 AD4683寄存器1写操作功能仿真时序图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值