使用的平臺:
多數FPGA芯片上沒有ADC的功能,而一些應用則需要用到ADC對一些模擬信號,比如直流電壓等進行量化,有沒有特別簡單、低成本的實現方法呢?
在要求轉換速率不高的情況下,完全可以借助一顆高速比較器(成本只有幾毛錢)來實現對模擬信號的量化,Lattice的官網上一篇文章就介紹了如何制作一個簡易的Sigma Delta ADC,如果FPGA能夠提供LVDS的接口,連外部的高速比較器都可以省掉。由于我們的小腳丫FPGA核心模塊在設計的時候沒有考慮到LVDS的應用場景,所以還是需要搭配一個高速的比較器來實現Lattice官網上推薦的簡易Sigma Delta ADC的功能。
讓小腳丫FPGA通過鎖相環PLL運行于120MHz的主時鐘(還可以更高,提速到240MHz、360MHz都應該沒有問題),測試1KHz以內的模擬信號是沒有問題的。
Lattice的官網上就可以下載到簡易Sigma Delta ADC的Verilog源代碼,可以非常方便地用在其它品牌、其它系列的FPGA上。
下面的截圖就是采用120MHz的主時鐘實現的對1KHz模擬信號的采樣,并通過DDS/DAC輸出,口袋儀器M2000采集并顯示的模擬信號波形。
M2000口袋儀器顯示的1KHz的波形
詳細的工作原理介紹可以參考項目https://www.eetree.cn/project/detail/255 及項目頁面中的參考資料,在這里以幾幅圖片來示例一下。
簡易Sigma Delta ADC的工作原理
直接連接 - 被測模擬信號的幅度范圍為0-3.3V
通過電阻分壓網絡輸入,并在比較器+端提供參考電壓,則被采集模擬信號的電壓變化范圍可以擴展
簡易Sigma Delta ADC的性能與邏輯電路的工作頻率
在不同的FPGA平臺上消耗的邏輯資源
以下就是我們的電賽綜合訓練板上簡易Sigma Delta ADC部分的電路連接
核心代碼:
頂層調用代碼:
wire [7:0] sd_adc_out; // sigma delta adc data output
wire sample_rdy; // flag for adc conversion
ADC_top my_adc(.clk_in(clk_hs),.rstn(1'b1),.digital_out(sd_adc_out), .analog_cmp(comp_in),.analog_out(ad_pwm),.sample_rdy(sample_rdy));
assign dac_data = sd_adc_out;
assign dac_clk = clk_hs; //120MHz generated by PLL
Sigma Delta ADC頂層程序
//*********************************************************************
//
// ADC Top Level Module
//
//*********************************************************************
module ADC_top (
clk_in,
rstn,
digital_out,
analog_cmp,
analog_out,
sample_rdy);
parameter
ADC_WIDTH = 8, // ADC Convertor Bit Precision
ACCUM_BITS = 10, // 2^ACCUM_BITS is decimation rate of accumulator
LPF_DEPTH_BITS = 3, // 2^LPF_DEPTH_BITS is decimation rate of averager
INPUT_TOPOLOGY = 1; // 0: DIRECT: Analog input directly connected to + input of comparitor
// 1: NETWORK:Analog input connected through R divider to - input of comp.
//input ports
input clk_in; // 62.5Mhz on Control Demo board
input rstn;
input analog_cmp; // from LVDS buffer or external comparitor
//output ports
output analog_out; // feedback to RC network
output sample_rdy;
output [7:0] digital_out; // connected to LED field on control demo bd.
//**********************************************************************
//
// Internal Wire & Reg Signals
//
//**********************************************************************
wire clk;
wire analog_out_i;
wire sample_rdy_i;
wire [ADC_WIDTH-1:0] digital_out_i;
wire [ADC_WIDTH-1:0] digital_out_abs;
assign clk = clk_in;
//***********************************************************************
//
// SSD ADC using onboard LVDS buffer or external comparitor
//
//***********************************************************************
sigmadelta_adc #(
.ADC_WIDTH(ADC_WIDTH),
.ACCUM_BITS(ACCUM_BITS),
.LPF_DEPTH_BITS(LPF_DEPTH_BITS)
)
SSD_ADC(
.clk(clk),
.rstn(rstn),
.analog_cmp(analog_cmp),
.digital_out(digital_out_i),
.analog_out(analog_out_i),
.sample_rdy(sample_rdy_i)
);
assign digital_out_abs = INPUT_TOPOLOGY ? ~digital_out_i : digital_out_i;
//***********************************************************************
//
// output assignments
//
//***********************************************************************
assign digital_out = ~digital_out_abs; // invert bits for LED display
assign analog_out = analog_out_i;
assign sample_rdy = sample_rdy_i;
endmodule
Sigma Delta ADC主程序
//*********************************************************************
//
// SSD Top Level Module
//
//*********************************************************************
module sigmadelta_adc (
clk,
rstn,
digital_out,
analog_cmp,
analog_out,
sample_rdy);
parameter
ADC_WIDTH = 8, // ADC Convertor Bit Precision
ACCUM_BITS = 10, // 2^ACCUM_BITS is decimation rate of accumulator
LPF_DEPTH_BITS = 3; // 2^LPF_DEPTH_BITS is decimation rate of averager
//input ports
input clk; // sample rate clock
input rstn; // async reset, asserted low
input analog_cmp ; // input from LVDS buffer (comparitor)
//output ports
output analog_out; // feedback to comparitor input RC circuit
output sample_rdy; // digital_out is ready
output [ADC_WIDTH-1:0] digital_out; // digital output word of ADC
//**********************************************************************
//
// Internal Wire & Reg Signals
//
//**********************************************************************
reg delta; // captured comparitor output
reg [ACCUM_BITS-1:0] sigma; // running accumulator value
reg [ADC_WIDTH-1:0] accum; // latched accumulator value
reg [ACCUM_BITS-1:0] counter; // decimation counter for accumulator
reg rollover; // decimation counter terminal count
reg accum_rdy; // latched accumulator value 'ready'
//***********************************************************************
//
// SSD 'Analog' Input - PWM
//
// External Comparator Generates High/Low Value
//
//***********************************************************************
always @ (posedge clk)
begin
delta <= analog_cmp; // capture comparitor output
end
assign analog_out = delta; // feedback to comparitor LPF
//***********************************************************************
//
// Accumulator Stage
//
// Adds PWM positive pulses over accumulator period
//
//***********************************************************************
always @ (posedge clk or negedge rstn)
begin
if( ~rstn )
begin
sigma <= 0;
accum <= 0;
accum_rdy <= 0;
end else begin
if (rollover) begin
// latch top ADC_WIDTH bits of sigma accumulator (drop LSBs)
accum <= sigma[ACCUM_BITS-1:ACCUM_BITS-ADC_WIDTH];
sigma <= delta; // reset accumulator, prime with current delta value
end else begin
if (&sigma != 1'b1) // if not saturated
sigma <= sigma + delta; // accumulate
end
accum_rdy <= rollover; // latch 'rdy' (to align with accum)
end
end
//***********************************************************************
//
// Box filter Average
//
// Acts as simple decimating Low-Pass Filter
//
//***********************************************************************
box_ave #(
.ADC_WIDTH(ADC_WIDTH),
.LPF_DEPTH_BITS(LPF_DEPTH_BITS))
box_ave (
.clk(clk),
.rstn(rstn),
.sample(accum_rdy),
.raw_data_in(accum),
.ave_data_out(digital_out),
.data_out_valid(sample_rdy)
);
//************************************************************************
//
// Sample Control - Accumulator Timing
//
//************************************************************************
always @(posedge clk or negedge rstn)
begin
if( ~rstn ) begin
counter <= 0;
rollover <= 0;
end
else begin
counter <= counter + 1; // running count
rollover <= &counter; // assert 'rollover' when counter is all 1's
end
end
endmodule
-
FPGA
+關注
關注
1629文章
21752瀏覽量
604118 -
芯片
+關注
關注
456文章
50910瀏覽量
424506 -
adc
+關注
關注
98文章
6509瀏覽量
544960
發布評論請先 登錄
相關推薦
評論