From 49b8a774807a867e46abd824d6713c2d63d2d369 Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Sun, 19 Oct 2025 20:03:51 +0200 Subject: [PATCH] Combined all sigmadelta things to one input block --- project.cfg | 2 + rtl/core/sigmadelta_input_q15.v | 58 ++++++++++++++++++ rtl/util/conv.vh | 7 ++- rtl/util/rc_alpha_q15.vh | 101 +++++++++++++++++++------------- sim/tb/tb_sigmadelta.v | 35 ++++------- 5 files changed, 137 insertions(+), 66 deletions(-) create mode 100644 rtl/core/sigmadelta_input_q15.v diff --git a/project.cfg b/project.cfg index 7098231..f1973a1 100644 --- a/project.cfg +++ b/project.cfg @@ -22,6 +22,7 @@ files_verilog = rtl/toplevel/top_generic.v rtl/core/nco_q15.v rtl/core/sigmadelta_sampler.v rtl/core/sigmadelta_rcmodel_q15.v + rtl/core/sigmadelta_input_q15.v rtl/core/mul_const.v rtl/core/lpf_iir_q15_k.v rtl/core/decimate_by_r_q15.v @@ -51,6 +52,7 @@ files_verilog = sim/tb/tb_nco_q15.v rtl/core/nco_q15.v rtl/core/lvds_comparator.v rtl/core/sigmadelta_rcmodel_q15.v + rtl/core/sigmadelta_input_q15.v rtl/core/mul_const.v rtl/core/lpf_iir_q15_k.v rtl/core/decimate_by_r_q15.v diff --git a/rtl/core/sigmadelta_input_q15.v b/rtl/core/sigmadelta_input_q15.v new file mode 100644 index 0000000..f6e8c37 --- /dev/null +++ b/rtl/core/sigmadelta_input_q15.v @@ -0,0 +1,58 @@ +`timescale 1ns/1ps + +module sigmadelta_input #( + parameter integer R_OHM = 3300, + parameter integer C_PF = 220 +)( + input wire clk_15, + input wire resetn, + + input wire adc_a, + input wire adc_b, + output wire adc_o, + + output wire signed [15:0] signal_q15, + output wire signal_valid +); + `include "rc_alpha_q15.vh" + + wire sd_signal; + wire signed [15:0] raw_sample_q15; + wire signed [15:0] lpf_sample_q15; + + sigmadelta_sampler sd_sampler( + .clk(clk_15), + .a(adc_a), .b(adc_b), + .o(sd_signal) + ); + assign adc_o = sd_signal; + + localparam integer alpha_q15_int = alpha_q15_from_rc(R_OHM, C_PF, 15000000); + localparam signed [15:0] alpha_q15 = alpha_q15_int[15:0]; + localparam signed [15:0] alpha_q15_top = alpha_q15 & 16'hff00; + sigmadelta_rcmodel_q15 #( + .alpha_q15(alpha_q15_top) + ) rc_model ( + .clk(clk_15), .resetn(resetn), + .sd_sample(sd_signal), + .sample_q15(raw_sample_q15) + ); + + lpf_iir_q15_k #( + .K(10) + ) lpf ( + .clk(clk_15), .rst_n(resetn), + .x_q15(raw_sample_q15), + .y_q15(lpf_sample_q15) + ); + + decimate_by_r_q15 #( + .R(375), // 15MHz/375 = 40KHz + .CNT_W(10) + ) decimate ( + .clk(clk_15), .rst_n(resetn), + .in_valid(1'b1), .in_q15(lpf_sample_q15), + .out_valid(signal_valid), .out_q15(signal_q15) + ); + +endmodule diff --git a/rtl/util/conv.vh b/rtl/util/conv.vh index 8a6c268..b59628b 100644 --- a/rtl/util/conv.vh +++ b/rtl/util/conv.vh @@ -1,3 +1,6 @@ +`ifndef CONV_VH +`define CONV_VH + // ============================================================================= // Convert Q1.15 to a biased UQ0.16 signal // ============================================================================= @@ -8,4 +11,6 @@ begin biased = q15 + 17'sd32768; q15_to_uq16 = biased[15:0]; end -endfunction \ No newline at end of file +endfunction + +`endif \ No newline at end of file diff --git a/rtl/util/rc_alpha_q15.vh b/rtl/util/rc_alpha_q15.vh index 5ab0e69..27e6804 100644 --- a/rtl/util/rc_alpha_q15.vh +++ b/rtl/util/rc_alpha_q15.vh @@ -7,61 +7,82 @@ `define RC_ALPHA_Q15_VH function integer alpha_q15_from_rc; - input integer R_OHM; // resistance in ohms - input integer C_PF; // capacitance in picofarads - input integer FS_HZ; // sampling frequency in Hz + input integer R_OHM; // ohms + input integer C_PF; // picofarads + input integer FS_HZ; // Hz - integer N; // fractional bits for x (QN) - reg [127:0] num_1e12_sllN; - reg [127:0] denom_u; - reg [127:0] x_qN; // x in QN - reg [255:0] x2; // x^2 in Q(2N) - reg [383:0] x3; // x^3 in Q(3N) - - integer term1_q15; // x -> Q1.15 - integer term2_q15; // x^2/2 -> Q1.15 - integer term3_q15; // x^3/6 -> Q1.15 - integer acc; // accumulator for result -begin // Choose QN for x. N=24 is a good balance for accuracy/width. - N = 24; + integer N; - // x = 1 / (Fs * R * C) with C in pF ==> x = 1e12 / (Fs * R * C_PF) + // We'll keep everything as unsigned vectors; inputs copied into vectors first. + reg [63:0] R_u, C_u, FS_u; + + // x = 1 / (Fs * R * C) with C in pF -> x = 1e12 / (Fs*R*C_pf) // x_qN = round( x * 2^N ) = round( (1e12 << N) / denom ) - num_1e12_sllN = 128'd1000000000000 << N; - - // denom = Fs * R * C_PF (fits in 64..96 bits for typical values) - denom_u = 0; - denom_u = denom_u + FS_HZ[127:0]; - denom_u = denom_u * R_OHM[127:0]; - denom_u = denom_u * C_PF[127:0]; - - // rounded divide for x_qN - x_qN = (num_1e12_sllN + (denom_u >> 1)) / denom_u; + reg [127:0] NUM_1E12_SLLN; // big enough for 1e12 << N + reg [127:0] DENOM; // Fs*R*C + reg [127:0] X_qN; // x in QN // Powers - x2 = x_qN * x_qN; // 128x128 -> 256 - x3 = x2 * x_qN; // 256x128 -> 384 + reg [255:0] X2; // x^2 in Q(2N) + reg [383:0] X3; // x^3 in Q(3N) - // term1 = x -> shift from QN to Q15 - term1_q15 = (x_qN >> (N - 15)) & 16'hFFFF; + integer term1_q15; + integer term2_q15; + integer term3_q15; + integer acc; - // term2 = x^2 / 2 -> shift from Q(2N) to Q15 and divide by 2 - term2_q15 = (x2 >> (2*N - 15 + 1)) & 16'hFFFF; +begin + N = 24; - // term3 = x^3 / 6 -> shift from Q(3N) to Q15, then divide by 6 (rounded) - begin : gen_term3 + // Copy integer inputs into 64-bit vectors (no bit-slicing of integers) + R_u = R_OHM[31:0]; + C_u = C_PF[31:0]; + FS_u = FS_HZ[31:0]; + + // Denominator = Fs * R * C_pf (fits in < 2^64 for typical values) + DENOM = 128'd0; + DENOM = FS_u; + DENOM = DENOM * R_u; + DENOM = DENOM * C_u; + + // // Guard: avoid divide by zero + // if (DENOM == 0) begin + // alpha_q15_from_rc = 0; + // disable alpha_q15_from_rc; + // end + + // Numerator = (1e12 << N). 1e12 * 2^24 ≈ 1.6777e19 (fits in 2^64..2^65), + // so use 128 bits to be safe. + NUM_1E12_SLLN = 128'd1000000000000 << N; + + // x_qN = rounded division + X_qN = (NUM_1E12_SLLN + (DENOM >> 1)) / DENOM; + + // Powers + X2 = X_qN * X_qN; + X3 = X2 * X_qN; + + // Convert terms to Q1.15: + // term1 = x -> shift from QN to Q15 + term1_q15 = (X_qN >> (N - 15)) & 16'hFFFF; + + // term2 = x^2 / 2 -> Q(2N) to Q15 and /2 + term2_q15 = (X2 >> (2*N - 15 + 1)) & 16'hFFFF; + + // term3 = x^3 / 6 -> Q(3N) to Q15, then /6 with rounding + begin : gen_t3 reg [383:0] tmp_q15_wide; reg [383:0] tmp_div6; - tmp_q15_wide = (x3 >> (3*N - 15)); - tmp_div6 = (tmp_q15_wide + 6'd3) / 6; // +3 for rounding + tmp_q15_wide = (X3 >> (3*N - 15)); + tmp_div6 = (tmp_q15_wide + 6'd3) / 6; term3_q15 = tmp_div6[15:0]; end - // Combine: alpha_q15 = x - x^2/2 + x^3/6 ; clamp to [0, 0x7FFF] + // Combine and clamp acc = term1_q15 - term2_q15 + term3_q15; - if (acc < 0) acc = 0; - else if (acc > 16'h7FFF) acc = 16'h7FFF; + if (acc < 0) acc = 0; + else if (acc > 16'h7FFF) acc = 16'h7FFF; alpha_q15_from_rc = acc; end diff --git a/sim/tb/tb_sigmadelta.v b/sim/tb/tb_sigmadelta.v index 3adeb5a..4d09fd2 100644 --- a/sim/tb/tb_sigmadelta.v +++ b/sim/tb/tb_sigmadelta.v @@ -20,32 +20,17 @@ module tb_sigmadelta(); wire sd_a; wire sd_b; wire sd_o; - // 3K3R 220PC 15MHZT - sigmadelta_sampler sd_sampler( - .clk(clk), - .a(sd_a), .b(sd_b), - .o(sd_o) - ); - - wire signed [15:0] sample_q15; - sigmadelta_rcmodel_q15 rc_model( - .clk(clk), .resetn(resetn), - .sd_sample(sd_o), - .sample_q15(sample_q15) - ); - - wire signed [15:0] y_q15; - lpf_iir_q15_k #(10) lpf( - .clk(clk), .rst_n(resetn), - .x_q15(sample_q15), - .y_q15(y_q15) - ); - wire signed [15:0] decimated_q15; - decimate_by_r_q15 #(400, 10) decimate( - .clk(clk), .rst_n(resetn), - .in_valid(1'b1), .in_q15(y_q15), - .out_valid(), .out_q15(decimated_q15) + wire decimated_valid; + + sigmadelta_input #( + .R_OHM(3300), + .C_PF(220) + ) dut( + .clk_15(clk), .resetn(resetn), + .adc_a(sd_a), .adc_b(sd_b), .adc_o(sd_o), + .signal_q15(decimated_q15), + .signal_valid(decimated_valid) ); endmodule