There are three practical ways to “implement ADC on an [FPGA](https://www.ampheo.com/c/fpgas-field-programmable-gate-array),” depending on what you really need:

**1) Use an external ADC and interface it (most common)**
You don’t synthesize the analog converter in LUTs—you capture its digital outputs.
**Pick an interface by speed:**
* Low speed (≤1–2 MSPS): SPI/I²C SAR ADC (e.g., [MCP3008](https://www.onzuu.com/search/MCP3008), [ADS7042](https://www.onzuu.com/search/ADS7042)).
* Mid speed (10–125 MSPS): Parallel CMOS/LVDS data + data clock (source-synchronous).
* High speed (100 MSPS–Gsps): JESD204B/C over high-speed serial transceivers.
**FPGA tasks:**
Clean clocking (PLL/MMCM), source-synchronous capture (IDDR/ISERDES), lane alignment, FIFO, optional digital filtering and calibration.
**Minimal SPI SAR example (MCP3008-style, 10-bit):**
```
module spi_adc_mcp3008 (
input wire clk, // e.g., 50 MHz
input wire start, // one-shot start conversion
input wire [2:0] ch, // channel 0..7
output reg busy,
output reg [9:0] data,
// SPI pins
output reg cs_n, sclk, mosi,
input wire miso
);
localparam IDLE=0, CMD=1, READ=2, DONE=3;
reg [1:0] state;
reg [5:0] bitcnt;
reg [15:0] shifter;
always @(posedge clk) begin
case (state)
IDLE: begin
sclk<=0; cs_n<=1; busy<=0;
if (start) begin
// Start bit=1, SGL/DIFF=1, D2..D0=channel
shifter <= {5'b11000 | ch, 11'd0}; // command frame
bitcnt <= 0;
cs_n <= 0; busy <= 1; state <= CMD;
end
end
CMD: begin
// SPI mode 0
sclk <= ~sclk;
if (!sclk) mosi <= shifter[15];
else begin
shifter <= {shifter[14:0],1'b0};
bitcnt <= bitcnt + 1;
if (bitcnt==15) begin bitcnt<=0; state<=READ; end
end
end
READ: begin
sclk <= ~sclk;
if (sclk) begin
shifter <= {shifter[14:0], miso};
bitcnt <= bitcnt + 1;
if (bitcnt==11) begin // 1 null + 10 bits
data <= shifter[9:0];
state <= DONE;
end
end
end
DONE: begin cs_n<=1; busy<=0; state<=IDLE; end
endcase
end
endmodule
```
**Parallel/LVDS capture sketch:**
* Use the ADC’s output data clock (DCO) as input to an IDDR/ISERDES slice to sample data lines.
* Phase-shift DCO with MMCM for optimal setup/hold.
* Constrain with XDC: input delays, clock groups, and false paths across clock domains.
```
# Example XDC snippets
create_clock -name dco_clk -period 5.000 [get_ports ADC_DCO] ;# 200 MHz
set_input_delay -clock dco_clk 1.0 [get_ports {ADC_D[*]}]
set_false_path -from [get_clocks dco_clk] -to [get_clocks sys_clk]
```
**JESD204B/C:**
* Use FPGA GT/GTH transceivers + vendor JESD IP (link layer, transport).
* Tasks: CGS/ILAS bring-up, lane deskew, deterministic latency, LMFC alignment, subclass selection.
**2) Use the FPGA’s built-in ADC hard block (if available)**
Some devices have on-chip ADCs (e.g., [Xilinx 7-series](https://www.vemeko.com/product/#xilinx) XADC, [Intel MAX 10](https://www.vemeko.com/max-10-cplds/) ADC, some Lattice parts).
* Great for board monitoring (voltages, temperature) or low-speed sensors.
* Instantiate vendor IP core; read samples via AXI/APB or simple registers; add a small moving-average/IIR filter.
**3) Build a discrete ADC around the FPGA (hybrid)**
You can implement the digital side of certain ADC architectures and use a few external analog parts:
**Sigma-Delta (1st/2nd-order):**
* External: 1-bit comparator + simple RC (integrator).
* FPGA: generate 1-bit DAC (PWM/DS), read comparator, run CIC/decimation to produce N-bit samples.
* Pros: excellent resolution for audio/slow sensors; minimal analog; Cons: latency, needs good clocking.
**SAR-style loop:**
* External: comparator + [resistor](https://www.onzuu.com/category/resistors) ladder/DAC;
* FPGA: binary search over DAC codes, read comparator to converge on N-bit result.
* Good for learning/medium speeds; not trivial to make precision-grade.
**Tiny 1-bit ΣΔ decimator (CIC) example (conceptual):**
```
// Sum 1-bit stream (signed) and decimate by R
module cic_decimator #(parameter R=256, W=24)(
input wire clk, // modulator clock
input wire sd_bit, // 1-bit stream: 1->+1, 0->-1
output reg valid,
output reg signed [W-1:0] y
);
reg signed [W-1:0] acc;
reg [$clog2(R)-1:0] cnt;
wire signed [1:0] s = sd_bit ? 2'sd1 : -2'sd1;
always @(posedge clk) begin
acc <= acc + s;
cnt <= cnt + 1;
if (cnt==R-1) begin
y <= acc; valid <= 1'b1; acc <= '0; cnt <= '0;
end else valid <= 1'b0;
end
endmodule
```
**System design checklist**
* Clocking & Jitter: ADC SNR is clock-jitter sensitive. Use low-jitter clocks (XO + PLL).
* IO Standards: Match ADC IO (LVDS, CMOS 1.8/2.5/3.3 V), set proper termination.
* Timing Closure: For source-synchronous, use IDELAY/ISERDES and constrain correctly.
* Throughput buffering: CDC FIFOs from ADC domain → system/AXI domain.
* Digital filtering: Moving average/IIR for slow SAR; FIR/CIC/halfband for ΣΔ or decimation chains.
* Calibration: Offset/gain/phase correction; background calibration for multichannel.
* Board layout: Short, impedance-controlled pairs for LVDS; isolate analog ground; solid power decoupling near ADC.
**Quick “which path should I take?” guide**
* You need real performance (audio–RF, reliable specs): Use a commercial ADC and capture it in [FPGA](https://www.ampheoelec.de/c/fpgas-field-programmable-gate-array).
* You need quick board telemetry or very low speed: Use the FPGA’s internal ADC (if present).
* You want to learn/experiment, audio-band: Try a sigma-delta with comparator + RC and do the [DSP](https://www.ampheo.com/c/dsp-digital-signal-processors) in FPGA.