当前位置:   article > 正文

FPGA 29 ADC(数据采集)模数字转换驱动设计_数模驱动

数模驱动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t93Mpr2Y-1627401356069)(FPGA 09 阻塞和非阻塞状态的理解.assets/test.png)]

FPGA 29 ADC(数据采集)模数字转换驱动设计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wfZPS8Im-1629962218562)(img/blog_img/fpga/image-20210826112214548.png)]

模块名称 : adc_128s022 模数驱动模块设计

主要功能 :本实验设计了adc_128s022 数模驱动芯片,通过在ADC_DIN输出端发送配置数据来完成芯片通道的配置和数字电压信号的传输,ADC_DOUT 来获取信号的输入,最终内部转换得到输出采集的数字信号。

设计流程:我们在这次实验中,在内部通过CLK的时钟分频,来输出时钟ADC_SCLK信号,根据ADC_SCLK 的时钟,通过ADC_DIN 来发送通道的配置引脚,随后ADC_DOUT 来接收模拟信号的采样数据点。最终完成在内部进行转换得到电压。通过该时钟,我们进而来设计线性序列机(可以理解一种比较特殊的状态机)来编写ADC模数芯片的SPI的时序.

AD128S022芯片的线性序列逻辑:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xZcSzq4o-1629962218565)(img/blog_img/fpga/image-20210818230658359.png)]

12位分辨率

CS_N : 片选信号,低电平有效

SCLK : 时钟

DIN(FPGA输出) : 信号输入引脚,SCLK 上升沿采样输入,【对于FPGA,需要下降沿改变输出的数据】

DOUT(对应FPGA输入): 转换结构输出脚,SCLK下降沿输出,【对于FPGA,还是上升沿读取】。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bxx8H4DV-1629962218566)(FPGA 29 ADC 模数转换驱动模块.assets/image-20210323184039234.png)]

模块实现:

数据手册的基本信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7OBLtMDe-1629962218568)(img/blog_img/fpga/image-20210826145701649.png)]

ksps (kilo samples per second) : 每秒多少K次采样。

500ksps -1Msps : 表示的是采样速率是,500k采样/1s - 1000k采样/1s.

功能描述:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLHu0Jqo-1629962218571)(img/blog_img/fpga/image-20210826142533908.png)]

注:这里主要关注的是一些关于dac的位数,工作电压,支持的采样速率,低功耗模式等较为重要的信息。

这个是内部电路给出的时序操作图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C7gFHsug-1629962218571)(img/blog_img/fpga/image-20210826144917803.png)]

实现过程可以看到,在CS片选信号拉低以后,我们将以SCLK的下降来进行计数,DIN在第四个下降沿到来时,开始连续的发送3个采样的信道地址ADDR[2:0]。同时我们也统计上升沿的个数,我们在SCLK的第5个上升沿开始接收采样的数据DATA[11:0],统计16个上升沿数据。随后完成一次数据的采集。

在上述图片中,描述的是一个连续的信号采集过程,一次完整的信号采集一共有16个上升沿和16个下降沿,我们以下降作为一次的开始(实际的情况也是下降沿作为信号采集的起始信号)计数,一共有16个时钟周期。随后又是16个时钟周期开始执行相同的操作。

数据典型电路:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VwR2goVH-1629962218572)(img/blog_img/fpga/image-20210826145126072.png)]

布局布线设计电路:
在这里插入图片描述

ad128s022.v 文件

module ad128s022
(
			Clk,
			Rst_n,
			
			Channel,
			Data,
			
			En_Conv,
			Conv_Done,
			ADC_State,
			DIV_PARAM,
			
			ADC_SCLK,
			ADC_DOUT,
			ADC_DIN,
			ADC_CS_N	
);

			input Clk;
			input Rst_n;
			
			input  [2:0]Channel;
			output reg [11:0]Data;
			
			input En_Conv;
			output reg Conv_Done;
			output ADC_State;
			input [7:0]DIV_PARAM;
			
			output reg ADC_SCLK;
			input  ADC_DOUT;
			output reg ADC_DIN;
			output reg ADC_CS_N;	

			
			reg en ;
			reg [2:0]r_Channel;
			reg [7:0]DIV_CNT ;
			reg  SCLK2X ;
			reg [5:0]SCLK_GEN_CNT;
			reg [11:0]r_Data;
			

			
			
			//  en handle 
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				en <= 1'b0;
			else if(En_Conv)
				en <= 1'b1;
			else if(Conv_Done)
				en <= 1'b0 ;
			else
				en <= en ;
			
			

			// r_Channel  we set En_Conv is a plus signal 
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				r_Channel <= 3'd0;
			else if(En_Conv)
				r_Channel <= Channel;
			else
				r_Channel <= r_Channel;
			
			// 时钟分频脉冲计数
			// reg [7:0]DIV_CNT ;
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				DIV_CNT <= 8'd0 ;
			else if(en)
				begin
				if(DIV_CNT == (DIV_PARAM -1) )
					DIV_CNT <= 8'd0 ;
				else	
					DIV_CNT <= DIV_CNT + 1'd1 ;
				end
			else	
				DIV_CNT <= 8'd0 ;
			
			// SCLK2X plus
			// reg  SCLK2X
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				SCLK2X <= 1'b0;
			else if(DIV_CNT == (DIV_PARAM -1) )
				SCLK2X <= 1'b1 ;
			else
				SCLK2X <= 1'b0;
				
			// reg [5:0]SCLK_GEN_CNT 
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				SCLK_GEN_CNT  <= 6'd0 ;
			else if(en && SCLK2X)
				begin
				if(SCLK_GEN_CNT == 6'd33)
					SCLK_GEN_CNT <=6'd0;
				else
					SCLK_GEN_CNT <= SCLK_GEN_CNT + 1'b1 ;
				end
			else
				SCLK_GEN_CNT <= SCLK_GEN_CNT ;
			//
			
			/*
			output ADC_SCLK
			input  ADC_DOUT;
			output ADC_DIN;
			output reg ADC_CS_N;	
			reg [11:0]r_Data;
			*/
			
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				begin
				ADC_SCLK <= 1'b1;
				ADC_DIN  <= 1'b0;
				ADC_CS_N  <= 1'b1;
				end
			else if(en && SCLK2X)
				begin
				case(SCLK_GEN_CNT)
				0: begin ADC_CS_N <= 1'b0; ADC_SCLK <= 1'b1; ADC_DIN <= 1'b0; end
				1,3: begin ADC_SCLK <= 1'b0; end
				2,4,6,8:  begin ADC_SCLK <= 1'b1 ; end
				5:  begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[2]; end
				7:  begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[1]; end
				9:  begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[0]; end
				10: begin ADC_SCLK <= 1'b1; r_Data[11] <= ADC_DOUT ; end
				12: begin ADC_SCLK <= 1'b1; r_Data[10] <= ADC_DOUT ; end
				14: begin ADC_SCLK <= 1'b1; r_Data[9] <= ADC_DOUT ; end
				16: begin ADC_SCLK <= 1'b1; r_Data[8] <= ADC_DOUT ; end
				18: begin ADC_SCLK <= 1'b1; r_Data[7] <= ADC_DOUT ; end
				20: begin ADC_SCLK <= 1'b1; r_Data[6] <= ADC_DOUT ; end
				22: begin ADC_SCLK <= 1'b1; r_Data[5] <= ADC_DOUT ; end
				24: begin ADC_SCLK <= 1'b1; r_Data[4] <= ADC_DOUT ; end
				26: begin ADC_SCLK <= 1'b1; r_Data[3] <= ADC_DOUT ; end
				28: begin ADC_SCLK <= 1'b1; r_Data[2] <= ADC_DOUT ; end
				30: begin ADC_SCLK <= 1'b1; r_Data[1] <= ADC_DOUT ; end
				32: begin ADC_SCLK <= 1'b1; r_Data[0] <= ADC_DOUT ; end
				11,13,15,17,19,21,23,25,27,29,31: begin ADC_SCLK <= 1'b0;  end
				33: begin ADC_CS_N <= 1'b1; end
				default: ;
				endcase
				end	
			
		// output [11:0]Data 
		always@(posedge Clk or negedge Rst_n)
		if(!Rst_n)
			Data  <= 12'd0 ;
		else if(en && SCLK2X && (SCLK_GEN_CNT == 6'd33))
			Data <= r_Data ;
		else
			Data <= Data ;
	
		// conv_Done signal
		always@(posedge Clk or negedge Rst_n)
		if(!Rst_n)
			Conv_Done  <= 1'd0 ;
		else if(en && SCLK2X && (SCLK_GEN_CNT == 6'd33))
			Conv_Done <= 1'd1 ;
		else
			Conv_Done <= 1'd0 ;	
		
		//产生ADC工作状态指示信号,保持和CS片选信号同步即可
		assign ADC_State = ADC_CS_N ; 
			
endmodule





  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177

注(这个是用于分析时序的时钟问题): SCLK2X 和 DIV_PARAM 这两个信号,DIV_PARAM 是一个输入分频信号,可以看到:

情况1:

假设DIV_PARAM =2时,

SCLK2X = Clk/DIV_PARAM = 50Mhz/2=25Mhz 的【周期脉冲信号,非标准方波信号】。

这样的话,ADC_SCLK输出的时钟是 = SCLK2X/2 =25Mhz/2 =12.5Mhz 的时钟。

情况2:

假设DIV_PARAM =4时,

SCLK2X = Clk/DIV_PARAM = 50Mhz/4=12.5Mhz 的【周期脉冲信号,非标准方波信号】

这样的话,ADC_SCLK输出的时钟是 = SCLK2X/2 =25Mhz/2 =6.25Mhz 的时钟。

这里非常需要了解输出SCLK 的最终的时钟输出。

SCL2X:这个是来统计上升沿和下降沿的计数。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/653020
推荐阅读
相关标签
  

闽ICP备14008679号