赞
踩
注:扫码关注小青菜哥哥的weixin公众号,免费获得更多优质的核探测器与电子学资讯~
Xilinx 7系列FPGA内置了一个模数转换模块,称为XADC。XADC内部集成了两个最高1MHz采样率,1Vpp的ADC模块,可以采集FPGA外部输入的模拟信号并转为数字信号。
XADC不需要外接任何输入信号,就可以测量FPGA内部的温度、VCCINT、VCCBRAM、VCCAUX电压。另外,还可以测量多达17路的外部差分输入模拟信号的幅度,包括专用差分信号输入信号VP/N以及VAUXP/N[15:0]。
所有的待测量信号均通过XADC内部的两个12bit-1MSPS的ADC模块(ADC_A和ADC_B)测量,并将转换结果存入状态寄存器(Status Registers),用户通过DRP接口可以在FPGA内部读取这些数据,也可以在vivado软件的调试界面中用JTAG获得这些数据。
另外ADC工作的配置参数由用户提供,用户将参数可以实时在线写入控制寄存器(Control Registers),从而实时控制ADC的工作状态,用户也可以在初始化配置XADC后将参数固定,不用实时配置,用户只需等待XADC初始化完成后,不断读取状态寄存器中的值即可。如下图1所示为XADC的功能模块图:
图1:XADC的功能模块图
1,硬件工作环境
FPGA:kintex-7。供电:12V/4A 直流电源。该板卡最多外接32通道2Vpp模拟信号以及20路外部触发信号。数据传输接口方式有千兆以太网接口、高速光纤接口以及低速USB串口。
图2:硬件PCB
2,逻辑开发环境
Vivado2017.4。
3,测试工程的逻辑框图介绍
如下图3所示为逻辑实现框图,由于硬件电路在设计时并没有考虑外部输入模拟电压的应用需求,因此本次测试针对的是FPGA内部的工作温度、内核电压VCCINT、VCCBRAM以及辅助电压VCCAUX这4个工作参数。
图3:逻辑测试框图
4,实现方法介绍
实现上就是对Dynamic Reconfiguration Port (DRP) 的时序进行读写操作,XADC的源语参数确定后,只需要对DRP端口进行读操作,就ok了。时序上并不复杂,其ug480官方文档给出的时序图如下图4所示,我们按照该时序控制信号就行了。
图4:DRP读写时序
如果我们连时序图都懒得看,也有其它办法。其官方给出了片上温度测量、VCCINT、VCCBRAM、VCCAUX以及4路VAUXP/N[3:0]的代码例程,ug480的第83页开始给出了应用例程和仿真测试时序,直接copy到我们的工程就可以了,DRP控制时序上非常简单,小青菜哥哥在这里就不一一介绍DRP端口信号的时序了,可以直接仿真看更清晰。
5,板级测试
我们copy了官方提供的代码并修改配置参数为只测试片上温度测量、VCCINT、VCCBRAM、VCCAUX这4路信号,并利用图3的框图建立工程,在线测试了温度和电压的功能。如图5所示为ILA在线监测的片上温度测量、VCCINT、VCCBRAM、VCCAUX这4路信号的时序图:其中EOC为每次ADC完成1路信号转换指示信号,EOS为每4路信号完成转换的指示信号。每个EOC指示信号的时间间隔为100个DRP时钟周期,因此可以推断出ADC的采样率为1MSPS。每次EOS拉高后,就表示用户可以从状态寄存器中读取4路信号的值了。
图5:4路信号整体测试时序图
如图6所示为读取这4路信号的更细节时序图,可以看到连续写入4个Dadd地址后,随后会出现drdy信号4次拉高,每次拉高时我们取出数据即可,共取4次,从而完成片上温度测量、VCCINT、VCCBRAM、VCCAUX这4路信号的取数。
图6:4路信号测试细节时序图
从图7可以更明显的观察到,每次drdy拉高时,对应读取了1路信号。拉高4次,完成4路信号的一次读取过程,之后再监测EOS信号,只要它再次拉高,就又在状态寄存器中读取这4路信号的值,如此循环往复。
图7:drdy信号拉高时取数
将取出来的4路数据通过网络接口发送到计算机,通过编写上位机软件就可以实时显示FPGA的温度和和电压了,如图8所示:FPGA的工作温度在49°附近波动,VCCINT为~1V,VCCBRAM也为~1V,VCCAUX为~1.8V,和实际FPGA的供电电压一致。
图8:上位机温度、电压监视界面
小青菜哥哥的XADC测试完整源代码如下,请大家参考:
- `timescale 1ns / 1ps
- //
- // Engineer: 小青菜哥哥
- // Create Date: 2020/06/12 17:12:08
- // Design Name:
- // Module Name: Module_XADC
- // Project Name: xilinx XADC测试
- module Module_XADC(
- input DCLK, // Clock input for DRP 100MHz
- input RESET,
- output [31:0] dataout,
- output datavld
- );
-
- wire busy;
- wire [5:0] channel;
- wire drdy;
- reg [6:0] daddr;
- reg [15:0] di_drp;
- wire [15:0] do_drp;
- wire [15:0] vauxp_active;
- wire [15:0] vauxn_active;
- reg [1:0] den_reg;
- reg [1:0] dwe_reg;
- reg [11:0] MEASURED_TEMP, MEASURED_VCCINT;
- reg TEMP_VALID,VCCINT_VALID,VCCAUX_VALID,VCCBRAM_VALID;
- reg [11:0] MEASURED_VCCAUX, MEASURED_VCCBRAM;
-
- reg [7:0] state = init_read;
- parameter init_read = 8'h00,
- read_waitdrdy = 8'h01,
- write_waitdrdy = 8'h03,
- read_reg00 = 8'h04,
- reg00_waitdrdy = 8'h05,
- read_reg01 = 8'h06,
- reg01_waitdrdy = 8'h07,
- read_reg02 = 8'h08,
- reg02_waitdrdy = 8'h09,
- read_reg06 = 8'h0a,
- reg06_waitdrdy = 8'h0b,
- read_reg10 = 8'h0c,
- reg10_waitdrdy = 8'h0d,
- read_reg11 = 8'h0e,
- reg11_waitdrdy = 8'h0f,
- read_reg12 = 8'h10,
- reg12_waitdrdy = 8'h11,
- read_reg13 = 8'h12,
- reg13_waitdrdy = 8'h13;
-
- always @(posedge DCLK)
- if (RESET) begin
- state <= init_read;
- den_reg <= 2'h0;
- dwe_reg <= 2'h0;
- di_drp <= 16'h0000;
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- end
- else
- case (state)
- init_read : begin
- daddr = 7'h40;
- den_reg = 2'h2; // performing read
- if (busy == 0 ) state <= read_waitdrdy;
- end
- read_waitdrdy :
- if (drdy ==1) begin
- di_drp = do_drp & 16'h03_FF; //Clearing AVG bits for Configreg0
- daddr = 7'h40;
- den_reg = 2'h2;
- dwe_reg = 2'h2; // performing write
- state = write_waitdrdy;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- write_waitdrdy :
- if (drdy ==1) begin
- state = read_reg00;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg00 : begin
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- daddr = 7'h00;
- den_reg = 2'h2; // performing read
- if (EOS == 1) state <=reg00_waitdrdy;
- end
- reg00_waitdrdy :
- if (drdy ==1) begin
- MEASURED_TEMP = do_drp[15:4];
- TEMP_VALID<=1'b1;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- state <=read_reg01;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg01 : begin
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- daddr = 7'h01;
- den_reg = 2'h2; // performing read
- state <=reg01_waitdrdy;
- end
- reg01_waitdrdy :
- if (drdy ==1) begin
- MEASURED_VCCINT = do_drp[15:4];
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b1;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- state <=read_reg02;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg02 : begin
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- daddr = 7'h02;
- den_reg = 2'h2; // performing read
- state <=reg02_waitdrdy;
- end
- reg02_waitdrdy :
- if (drdy ==1) begin
- MEASURED_VCCAUX = do_drp[15:4];
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b1;
- VCCBRAM_VALID<=1'b0;
- state <=read_reg06;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg06 : begin
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b0;
- daddr = 7'h06;
- den_reg = 2'h2; // performing read
- state <=reg06_waitdrdy;
- end
- reg06_waitdrdy :
- if (drdy ==1) begin
- MEASURED_VCCBRAM = do_drp[15:4]; //由于硬件设计没有使用外部输入模拟端口,因此只进行温度、vccint、vccaux、vccbram这前四个值的读取
- TEMP_VALID<=1'b0;
- VCCINT_VALID<=1'b0;
- VCCAUX_VALID<=1'b0;
- VCCBRAM_VALID<=1'b1;
- state <= read_reg00/*read_reg10*/;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- /* read_reg10 : begin
- daddr = 7'h10;
- den_reg = 2'h2; // performing read
- state <= reg10_waitdrdy;
- end
- reg10_waitdrdy :
- if (drdy ==1) begin
- MEASURED_AUX0 = do_drp;
- state <= read_reg11;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg11 : begin
- daddr = 7'h11;
- den_reg = 2'h2; // performing read
- state <= reg11_waitdrdy;
- end
- reg11_waitdrdy :
- if (drdy ==1) begin
- MEASURED_AUX1 = do_drp;
- state <= read_reg12;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg12 : begin
- daddr = 7'h12;
- den_reg = 2'h2; // performing read
- state <= reg12_waitdrdy;
- end
- reg12_waitdrdy :
- if (drdy ==1) begin
- MEASURED_AUX2= do_drp;
- state <= read_reg13;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end
- read_reg13 : begin
- daddr = 7'h13;
- den_reg = 2'h2; // performing read
- state <= reg13_waitdrdy;
- end
- reg13_waitdrdy :
- if (drdy ==1) begin
- MEASURED_AUX3= do_drp;
- state <=read_reg00;
- daddr = 7'h00;
- end
- else begin
- den_reg = { 1'b0, den_reg[1] } ;
- dwe_reg = { 1'b0, dwe_reg[1] } ;
- state = state;
- end*/
- endcase
-
- XADC #(// Initializing the XADC Control Registers
- .INIT_40(16'h9000),// Calibration coefficient averaging disabled, averaging of 16 selected for external channels
- .INIT_41(16'h2ef0),// Continuous Seq Mode, Disable unused ALMs, Enable calibration
- .INIT_42(16'h0400),// Set DCLK divider to 4, ADC = 1Msps, DCLK = 100MHz
- .INIT_48(16'h4701),// Sequencer channel - enable Temp sensor, VCCINT, VCCAUX, VCCBRAM, and calibration
- .INIT_49(16'h0000),// Sequencer channel - disabled all aux analog channels 0
- .INIT_4A(16'h4700),// Averaging enabled for Temp sensor, VCCINT, VCCAUX,VCCBRAM
- .INIT_4B(16'h0000),// No averaging on external channels
- .INIT_4C(16'h0000),// Sequencer Bipolar selection
- .INIT_4D(16'h0000),// Sequencer Bipolar selection
- .INIT_4E(16'h0000),// Sequencer Acq time selection
- .INIT_4F(16'h0000),// Sequencer Acq time selection
- .INIT_50(16'hb5ed),// Temp upper alarm trigger 85°C
- .INIT_51(16'h5999),// Vccint upper alarm limit 1.05V
- .INIT_52(16'hA147),// Vccaux upper alarm limit 1.89V
- .INIT_53(16'h0000),// OT upper alarm limit 125°C using automatic shutdown - see Thermal
- .INIT_54(16'ha93a),// Temp lower alarm reset 60°C
- .INIT_55(16'h5111),// Vccint lower alarm limit 0.95V
- .INIT_56(16'h91Eb),// Vccaux lower alarm limit 1.71V
- .INIT_57(16'hae4e),// OT lower alarm reset 70°C - see Thermal Management
- .INIT_58(16'h5999),// VCCBRAM upper alarm limit 1.05V
- .SIM_MONITOR_FILE("design.txt")// Analog Stimulus file for simulation
- )
-
- XADC_INST (// Connect up instance IO. See UG580 for port descriptions
- .CONVST (1'b0),// not used
- .CONVSTCLK (1'b0), // not used
- .DADDR (daddr),
- .DCLK (DCLK),
- .DEN (den_reg[0]),
- .DI (di_drp),
- .DWE (dwe_reg[0]),
- .RESET (RESET),
- .VAUXN (16'd0 ),// not used
- .VAUXP (16'd0 ),// not used
- .ALM (ALM),
- .BUSY (busy),
- .CHANNEL(CHANNEL),
- .DO (do_drp),
- .DRDY (drdy),
- .EOC (EOC),
- .EOS (EOS),
- .JTAGBUSY (),// not used
- .JTAGLOCKED (),// not used
- .JTAGMODIFIED (),// not used
- .OT (OT),
- .MUXADDR (),// not used
- .VP (1'b0),// not used
- .VN (1'b0)// not used
- );
-
-
- ila_xadc ila_xadc_inst (
- .clk (DCLK), // input wire clk
- .probe0(MEASURED_TEMP), // input wire [11:0] probe0
- .probe1(MEASURED_VCCINT), // input wire [11:0] probe1
- .probe2(MEASURED_VCCAUX), // input wire [11:0] probe2
- .probe3(MEASURED_VCCBRAM), // input wire [11:0] probe3
- .probe4(TEMP_VALID), // input wire [0:0] probe4
- .probe5(VCCINT_VALID), // input wire [0:0] probe5
- .probe6(VCCAUX_VALID), // input wire [0:0] probe6
- .probe7(VCCBRAM_VALID), // input wire [0:0] probe7
- .probe8(daddr),//wire [6:0]
- .probe9(den_reg[0]),//wire [0:0]
- .probe10(dwe_reg[0]),//wire [0:0]
- .probe11(busy),//wire [0:0]
- .probe12(do_drp),//wire [15:0]
- .probe13(drdy),//wire [0:0]
- .probe14(EOC),//wire [0:0]
- .probe15(EOS)//wire [0:0]
- );
-
- wire [31:0] fifo_in_temp = {16'd0,4'd1,MEASURED_TEMP};
- wire [31:0] fifo_in_vint = {16'd0,4'd2,MEASURED_VCCINT};
- wire [31:0] fifo_in_vaux = {16'd0,4'd3,MEASURED_VCCAUX};
- wire [31:0] fifo_in_vram = {16'd0,4'd4,MEASURED_VCCBRAM};
-
- reg [31:0] fifo_data_in;
- reg fifo_data_en;
- wire empty;
- fifo_xadc fifo_xadc_inst (
- .clk(DCLK), // input wire clk
- .srst(RESET), // input wire srst
- .din(fifo_data_in), // input wire [31 : 0] din
- .wr_en(fifo_data_en), // input wire wr_en
- .rd_en(~empty), // input wire rd_en
- .dout(dataout), // output wire [31 : 0] dout
- .full(), // output wire full
- .empty(empty), // output wire empty
- .valid(datavld) // output wire valid
- );
-
- always @(posedge DCLK)
- if (RESET) begin
- fifo_data_en<=1'b0;
- fifo_data_in<=32'b0;
- end
- else if(TEMP_VALID)
- begin
- fifo_data_en<=1'b1;
- fifo_data_in<=fifo_in_temp;
- end
- else if(VCCINT_VALID)
- begin
- fifo_data_en<=1'b1;
- fifo_data_in<=fifo_in_vint;
- end
- else if(VCCAUX_VALID)
- begin
- fifo_data_en<=1'b1;
- fifo_data_in<=fifo_in_vaux;
- end
- else if(VCCBRAM_VALID)
- begin
- fifo_data_en<=1'b1;
- fifo_data_in<=fifo_in_vram;
- end
- else
- begin
- fifo_data_en<=1'b0;
- fifo_data_in<=32'b0;
- end
- endmodule

今天的博文就到这里了,有问题请在小青菜哥哥的公众号留言,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。