Files
fpga_modem/HW/sampling.v
2025-10-01 21:52:21 +02:00

134 lines
4.2 KiB
Verilog

`timescale 1ns/1ps
module sampling(
input wire adc_A,
input wire adc_B,
output wire adc_O,
input wire clk_15,
input wire clk_120,
input wire reset_n
);
wire sigmadelta_sample;
sigmadelta_sampler m_sdsampler(
.clk(clk_15),
.A(adc_A),
.B(adc_B),
.out(sigmadelta_sample)
);
assign adc_O = sigmadelta_sample;
// RC model, output is y_next_q15
// ------------------------------
reg signed [15:0] y_q15;
wire signed [15:0] x_q15 = sigmadelta_sample ? 16'sh7fff : 16'sh0000;
wire signed [15:0] e_q15 = x_q15 - y_q15;
wire signed [31:0] prod_q30 = $signed(16'sh0b00) * $signed(e_q15); // factor should be 0b3b, used bit simplified here
wire signed [15:0] delta_q15 = prod_q30 >>> 15;
wire signed [15:0] y_next_q15 = y_q15 + delta_q15;
// Optional clamp to [0, 0x7FFF] (keeps GTKWave tidy)
function signed [15:0] clamp01_q15(input signed [15:0] v);
if (v < 16'sd0000) clamp01_q15 = 16'sd0000;
else if (v > 16'sh7FFF) clamp01_q15 = 16'sh7FFF;
else clamp01_q15 = v;
endfunction
always @(posedge clk_15 or negedge reset_n) begin
if (!reset_n) y_q15 <= 16'sd0000;
else y_q15 <= clamp01_q15(y_next_q15);
end
// ------------------------------
wire signed [15:0] lpfed_q15;
lpf_iir_q15 #(.K(7)) m_lpf (
.clk(clk_15),
.rst_n(reset_n),
.x_q15(y_next_q15),
.y_q15(lpfed_q15)
);
wire signed [15:0] decimated_q15;
decimate_by_r #(.R(375)) m_decimator (
.clk(clk_15),
.rst_n(reset_n),
.in_valid(1'b1),
.in_q15(lpfed_q15),
.out_valid(),
.out_q15(decimated_q15)
);
// decimated_q15 + out_valid @ 40KHz
endmodule
// --------------------------------------------------------------------
// Simple 1-pole IIR LPF, Q1.15 in/out, multiplier-less (alpha = 1/2^K)
// --------------------------------------------------------------------
module lpf_iir_q15 #(
parameter integer K = 10 // try 8..12; bigger = more smoothing
)(
input wire clk,
input wire rst_n,
input wire signed [15:0] x_q15, // Q1.15 input (e.g., 0..0x7FFF)
output reg signed [15:0] y_q15 // Q1.15 output
);
wire signed [15:0] e_q15 = x_q15 - y_q15;
wire signed [15:0] delta_q15 = e_q15 >>> K; // arithmetic shift
wire signed [15:0] y_next = y_q15 + delta_q15;
// clamp to [0, 0x7FFF] (handy if your signal is non-negative)
function signed [15:0] clamp01;
input signed [15:0] v;
begin
if (v < 16'sd0) clamp01 = 16'sd0;
else if (v > 16'sh7FFF) clamp01 = 16'sh7FFF;
else clamp01 = v;
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) y_q15 <= 16'sd0;
else y_q15 <= clamp01(y_next);
end
endmodule
// -------------------------------------------------------------
// Decimate-by-R: passes through one sample every R input clocks
// No $clog2 used; set CNT_W wide enough for your R.
// -------------------------------------------------------------
module decimate_by_r #(
parameter integer R = 400, // decimation factor
parameter integer CNT_W = 10 // width so that 2^CNT_W > R (e.g., 10 for 750)
)(
input wire clk,
input wire rst_n,
input wire in_valid, // assert 1'b1 if always valid
input wire signed [15:0] in_q15, // Q1.15 sample at full rate
output reg out_valid, // 1-cycle pulse every R samples
output reg signed [15:0] out_q15 // Q1.15 sample at decimated rate
);
reg [CNT_W-1:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= {CNT_W{1'b0}};
out_valid <= 1'b0;
out_q15 <= 16'sd0;
end else begin
out_valid <= 1'b0;
if (in_valid) begin
if (cnt == R-1) begin
cnt <= {CNT_W{1'b0}};
out_q15 <= in_q15;
out_valid <= 1'b1;
end else begin
cnt <= cnt + 1'b1;
end
end
end
end
endmodule