diff --git a/rtl/digital_thermometer.v b/rtl/digital_thermometer.v index a4c6742..c707cca 100644 --- a/rtl/digital_thermometer.v +++ b/rtl/digital_thermometer.v @@ -2,77 +2,87 @@ ////////////////////////////////////////////////////////////////////////////////// // Engineer: Yangshenbo // version:V1.0 -// Create Date: 2026/03/22 +// Create Date: 2026/04/05 ////////////////////////////////////////////////////////////////////////////////// module digital_thermometer( input clk, input rst_n, - input vin, - input mode, - output reg [19:0]freq_x100hz, - output reg [15:0]temp_out, - output reg temp_valid + input sig_in, + input [23:0]win_us, + input [1:0]out_mode, //0输出对应温度, 1输出对应的频率,2单位窗口输出脉冲的个数 + input [15:0]temp_85_fre_k, //85°对应的频率,默认为600khz + input [15:0]temp_neg_40_fre_k , //-40对应的频率,默认为160khz,单位khz + input report_en, //主动上报使能 + input [23:0]rep_gap_us, //最小位win_us + output reg [23:0]therm_out, + output reg therm_vld ); - - wire [19:0] freq; - wire freq_valid; - //映射表: - reg [15:0] temp_lut [0:800]; - integer i; - initial begin - for (i = 0; i <= 800; i = i + 1) begin - // 50.0kHz->-40°C, 130.0kHz->85°C - // temp = -400 + (1250 * i) / 800 - temp_lut[i] = -400 + (1250 * i + 400) / 800; + wire [23:0] wd_cnt_out; + wire wd_cnt_vld; + reg [23:0] gap_cnt; // 上报间隔计数器 + wire [23:0] cur_freq_khz; + reg signed [31:0] temp_scaled; + + assign cur_freq_khz = (wd_cnt_out * 1000) / win_us; + //我们将温度结果放大100倍 + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + temp_scaled <= 0; + end else if (wd_cnt_vld) begin + // 线性插值计算 + temp_scaled <= ((cur_freq_khz - temp_neg_40_fre_k) * 12500) / (temp_85_fre_k - temp_neg_40_fre_k) - 4000; + end + end + + // 上报逻辑与输出选择 + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + gap_cnt <= 0; + therm_vld <= 0; + therm_out <= 0; + end else if (wd_cnt_vld) begin + if (report_en) begin + if (gap_cnt >= (rep_gap_us / win_us) - 1) begin + gap_cnt <= 0; + therm_vld <= 1'b1; + end else begin + gap_cnt <= gap_cnt + 1'b1; + therm_vld <= 1'b0; + end + end + else begin + gap_cnt <= 0; + therm_vld <= 1'b0; + end + + // 模式切换输出 + case (out_mode) + 2'd0: therm_out <= temp_scaled[23:0]; // 输出放大100倍的温度 + 2'd1: therm_out <= cur_freq_khz; // 输出频率(kHz) + 2'd2: therm_out <= wd_cnt_out; // 输出原始脉冲计数值 + default: therm_out <= temp_scaled[23:0]; + endcase + end + else begin + therm_vld <= 1'b0; end end - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - freq_x100hz <= 0; - temp_out <= 0; - temp_valid <= 0; - end - else begin - temp_valid <= freq_valid; - - if (freq_valid) begin - freq_x100hz <= freq; - - if (mode == 0) begin - // 模式0:线性输出 - // 频率范围:500~1300(50.0kHz~130.0kHz) - if (freq < 500) - temp_out <= -400; - else if (freq > 1300) - temp_out <= 850; - else - temp_out <= -400 + ((freq - 500) * 1250) / 800; - end else begin - // 模式1:查表输出 - if (freq < 500) - temp_out <= temp_lut[0]; - else if (freq > 1300) - temp_out <= temp_lut[800]; - else - temp_out <= temp_lut[freq - 500]; - end - end - end - end - - - pulse_freq_10ms u_freq_measure ( - .clk (clk), - .rst_n (rst_n), - .vin (vin), - .freq (freq), //1302 ->130.2KHz - .valid (freq_valid) + // 实例化被测模块 + pulse_cnt #( + .CLK_FREQ(50_000_000) + ) pulse_cnt_inst ( + .clk (clk), + .rst_n (rst_n), + .sig_in (sig_in), + .win_us (win_us), + .cnt_out(wd_cnt_out), + .vld_out(wd_cnt_vld) ); endmodule diff --git a/tb/tb_digital_thermometer.sv b/tb/tb_digital_thermometer.sv new file mode 100644 index 0000000..9c97922 --- /dev/null +++ b/tb/tb_digital_thermometer.sv @@ -0,0 +1,173 @@ +`timescale 1ns / 1ps + +module tb_digital_thermometer(); + + // --- Parameter --- + localparam CLK_PERIOD = 20; // 50MHz Clock + + // --- Signals --- + reg clk; + reg rst_n; + reg sig_in; + reg [23:0] win_us; + reg [1:0] out_mode; + reg [15:0] temp_85_fre_k; + reg [15:0] temp_neg_40_fre_k; + reg report_en; + reg [23:0] rep_gap_us; + + wire [23:0] therm_out; + wire therm_vld; + + // --- DUT Instantiation --- + digital_thermometer dut ( + .clk (clk), + .rst_n (rst_n), + .sig_in (sig_in), + .win_us (win_us), + .out_mode (out_mode), + .temp_85_fre_k (temp_85_fre_k), + .temp_neg_40_fre_k (temp_neg_40_fre_k), + .report_en (report_en), + .rep_gap_us (rep_gap_us), + .therm_out (therm_out), + .therm_vld (therm_vld) + ); + + // --- Clock Generation --- + initial begin + clk = 0; + forever #(CLK_PERIOD/2) clk = ~clk; + end + + // --- Pulse Generation Task --- + // freq_khz: Target frequency (kHz) + // duration_ms: Test duration (ms) + task automatic gen_pulses(input int freq_khz, input int duration_ms); + int half_period_ns; + longint end_time_ns; + begin + if (freq_khz <= 0) begin + sig_in = 0; + #(duration_ms * 1000000); + end else begin + half_period_ns = 500000 / freq_khz; + end_time_ns = $time + (longint'(duration_ms) * 1000000); + + $display("[%0t] Start generating signal: %0d kHz", $time, freq_khz); + while ($time < end_time_ns) begin + sig_in = 1; + #(half_period_ns); + sig_in = 0; + #(half_period_ns); + end + end + end + endtask + + // // --- Basic Test Stimulus --- + // initial begin + // // 1. Initialize signals + // rst_n = 0; + // sig_in = 0; + // win_us = 1000; // 1ms measurement window + // out_mode = 0; // Default: temperature output + // temp_85_fre_k = 600; // 85°C -> 600kHz + // temp_neg_40_fre_k = 160; // -40°C -> 160kHz + // report_en = 0; + // rep_gap_us = 2000; // Report interval: 2ms + + // // 2. Release reset + // #(CLK_PERIOD * 10); + // rst_n = 1; + // #(CLK_PERIOD * 10); + + // // --- Case 1: Test -40°C (160kHz) --- + // $display("\n--- Test Case 1: -40°C (160kHz) time:%t---",$time); + // gen_pulses(160, 5); + + // // --- Case 2: Test 85°C (600kHz) --- + // $display("\n--- Test Case 2: 85°C (600kHz) ---"); + // gen_pulses(600, 5); + + // // --- Case 3: Test mid-range temperature (380kHz) --- + // $display("\n--- Test Case 3: Mid-range (380kHz) ---"); + // gen_pulses(380, 5); + + // // --- Case 4: Test output modes --- + // $display("\n--- Test Case 4: Switch output modes ---"); + // out_mode = 1; // Frequency mode + // gen_pulses(500, 3); + // out_mode = 2; // Edge count mode + // gen_pulses(500, 3); + + // // --- Case 5: Test auto-report function --- + // $display("\n--- Test Case 5: Auto-report enabled (2ms interval) ---"); + // out_mode = 0; + // report_en = 1; + // gen_pulses(300, 10); + + // // End simulation + // $display("\nSimulation finished at: %0t", $time); + // #(CLK_PERIOD * 100); + // $stop; + // end + + // --- Main Test: Verify Configuration & Report Interval --- + initial begin + // 1. Init + rst_n = 0; + sig_in = 0; + win_us = 1000; // 1ms window + out_mode = 0; // Mode 0: Temperature (x100 scale) + report_en = 0; + temp_neg_40_fre_k = 200; + temp_85_fre_k = 700; + rep_gap_us = 2000; // 2ms report gap + + // 2. Release reset + #(CLK_PERIOD * 10); + rst_n = 1; + #(CLK_PERIOD * 20); + + // --- TEST 1: Verify frequency mapping configuration --- + $display("\n[TEST 1] Verify frequency mapping parameters..."); + + $display(">> Input: 450kHz | Config: -40°C=200k, 85°C=700k | Expected temp: 2250"); + gen_pulses(450, 4); + + temp_85_fre_k = 450; + $display(">> Updated config: 85°C=450k | Input: 450kHz | Expected temp: 8500"); + gen_pulses(450, 4); + + + // --- TEST 2: Verify rep_gap_us control --- + $display("\n[TEST 2] Verify report interval (rep_gap_us)..."); + report_en = 1; + + rep_gap_us = 2000; + $display(">> rep_gap_us = 2ms (Expected vld every 2ms)"); + gen_pulses(300, 10); + + rep_gap_us = 5000; + $display(">> rep_gap_us = 5ms (Expected vld every 5ms)"); + gen_pulses(300, 15); + + + // --- TEST 3: Boundary test (rep_gap_us < win_us) --- + $display("\n[TEST 3] Boundary test: rep_gap_us < win_us"); + rep_gap_us = 500; + gen_pulses(300, 5); + + // End + $display("\nConfiguration test completed at: %0t", $time); + #(CLK_PERIOD * 100); + $stop; + end + // --- Monitor --- + initial begin + $monitor("[%0t] Valid=%b | Mode=%0d | Result=%0d", + $time, therm_vld, out_mode, therm_out); + end + +endmodule \ No newline at end of file