Here's a simple Verilog example that demonstrates how to interface a potentiometer with an [FPGA](https://www.ampheo.com/c/fpgas-field-programmable-gate-array) using an external SPI ADC (e.g., MCP3008), and display the 10-bit analog value using LEDs or send it via UART. ![image-10-1024x768](https://hackmd.io/_uploads/SyT05yzdex.png) **Setup Overview** **Components** * [Potentiometer](https://www.onzuu.com/category/potentiometers) * [MCP3008](https://www.onzuu.com/search/MCP3008) (10-bit SPI ADC) * [FPGA Board](https://www.onzuu.com/category/embedded-complex-logic-fpga-cpld) (e.g., Xilinx or [Intel](https://www.ampheo.com/manufacturer/intel)) * Optional: UART interface / LEDs / 7-segment displays **MCP3008 Pinout (Important)** * VDD → 3.3V or 5V * VREF → Same as VDD * AGND & DGND → GND * CH0 → Potentiometer wiper * DIN (MOSI), DOUT (MISO), CLK, CS → Connect to [FPGA](https://www.ampheoelec.de/c/fpgas-field-programmable-gate-array) SPI interface **MCP3008 SPI Protocol Recap** To read CH0: * Send: 00000001 (Start bit) * Send: 10000000 (SGL/DIFF = 1, D2-D0 = 000 for CH0) * Read: 10-bit result (after null bit) **Verilog Modules Overview** We'll implement: 1. SPI Master Module 2. MCP3008 Reader 3. Top-Level Module **1. SPI Master Module (Basic, Mode 0)** ``` verilog module spi_master ( input clk, // System clock input start, // Start signal input [7:0] data_in, // Data to send output reg [7:0] data_out, output reg done, output reg sclk, output reg mosi, input miso, output reg cs ); reg [3:0] bit_cnt; reg [7:0] shift_reg; reg [2:0] state; localparam IDLE = 0, LOAD = 1, TRANSFER = 2, DONE = 3; always @(posedge clk) begin case (state) IDLE: begin done <= 0; cs <= 1; sclk <= 0; if (start) state <= LOAD; end LOAD: begin cs <= 0; shift_reg <= data_in; bit_cnt <= 7; state <= TRANSFER; end TRANSFER: begin sclk <= ~sclk; if (sclk == 0) begin mosi <= shift_reg[bit_cnt]; end else begin shift_reg[bit_cnt] <= miso; if (bit_cnt == 0) state <= DONE; else bit_cnt <= bit_cnt - 1; end end DONE: begin cs <= 1; sclk <= 0; data_out <= shift_reg; done <= 1; state <= IDLE; end endcase end endmodule ``` **2. MCP3008 Reader Module** ``` verilog module mcp3008_reader ( input clk, input miso, output sclk, output mosi, output cs, output reg [9:0] adc_value ); // SPI wires wire done; wire [7:0] data_out; reg start; reg [7:0] tx_data; reg [3:0] state; spi_master spi ( .clk(clk), .start(start), .data_in(tx_data), .data_out(data_out), .done(done), .sclk(sclk), .mosi(mosi), .miso(miso), .cs(cs) ); localparam IDLE = 0, SEND1 = 1, SEND2 = 2, READ1 = 3, READ2 = 4, DONE = 5; reg [7:0] rx1, rx2; always @(posedge clk) begin case (state) IDLE: begin tx_data <= 8'b00000001; start <= 1; state <= SEND1; end SEND1: if (done) begin start <= 0; tx_data <= 8'b10000000; start <= 1; state <= SEND2; end SEND2: if (done) begin start <= 0; tx_data <= 8'b00000000; start <= 1; state <= READ1; end READ1: if (done) begin start <= 0; rx1 <= data_out; tx_data <= 8'b00000000; start <= 1; state <= READ2; end READ2: if (done) begin start <= 0; rx2 <= data_out; adc_value <= {rx1[1:0], rx2[7:0]}; // Combine 10-bit result state <= IDLE; end endcase end endmodule ``` **3. Top-Level Module (Display on LEDs)** ``` verilog module top ( input clk, input miso, output sclk, output mosi, output cs, output [9:0] leds ); wire [9:0] adc_value; mcp3008_reader reader ( .clk(clk), .miso(miso), .sclk(sclk), .mosi(mosi), .cs(cs), .adc_value(adc_value) ); assign leds = adc_value; endmodule ``` **Simulation and Testing** * Simulate SPI behavior using a testbench. * Use a Saleae logic analyzer or [oscilloscope](https://www.onzuu.com/category/oscilloscopes) to verify SPI waveform. * Turn the potentiometer and observe LED brightness or value changes. ✅ Summary ![企业微信截图_20250807164338](https://hackmd.io/_uploads/HkoSDyfOle.png)