verilog实现采样电流有效值的计算

上一篇文章中的代码也能实现有效值计算,仿真中可以实现,但在有些资源有限的芯片中,纯逻辑除法消耗资源过多,无法实现。

这篇文章主要通过两个除法IP核实现有效值计算

重点在于迭代过程中IP核的调用

除法运算中,start脉冲在未完成本次计算时只能在开始时刻有一个时钟的置1,其它时刻为0

c 复制代码
`timescale 1ns / 1ps
module current_rms_calculator_low (
    input wire clk_100MHZ,
    input wire rst_n,
    input [15:0] data_a,
    input sample_valid,
    output [15:0] rms_value_a,
    output reg rms_valid
);

parameter divisor = 200;

//=============================
// 平方
//=============================
reg [31:0] square;
always @(posedge clk_100MHZ) begin
    square <= data_a * data_a;
end

//=============================
// 200点累加
//=============================
reg [15:0] sample_cnt;
reg [39:0] sum;
wire calc_done = (sample_cnt == 199);
always @(posedge clk_100MHZ or negedge rst_n) begin
    if(!rst_n) begin
        sum        <= 0;
        sample_cnt <= 0;
    end
    else if(calc_done) begin
        sum        <= 0;
        sample_cnt <= 0;
    end
    else if(sample_valid) begin
        sum        <= sum + square;
        sample_cnt <= sample_cnt + 1'd1;
    end
end


//=============================
// 第一层除法IP:求平均值 sum / 200
//=============================
wire avg_divide_done;
wire [47:0] out_div_data;
wire [39:0] avg_value = out_div_data[47:8];

div_gen_0 inst_divide_40x8(
    .aclk(clk_100MHZ),
    .s_axis_divisor_tvalid(1'b1),
    .s_axis_divisor_tdata(divisor),
    .s_axis_dividend_tvalid(calc_done),
    .s_axis_dividend_tdata(sum),
    .m_axis_dout_tvalid(avg_divide_done),
    .m_axis_dout_tuser(),
    .m_axis_dout_tdata(out_div_data)
);

//=============================
// 第二层除法IP:牛顿迭代专用 sqrt_S / sqrt_x
//=============================
wire        sqrt_div_done;
wire [79:0] sqrt_div_result;
reg         sqrt_div_start;
wire [39:0] sqrt_quotient;

div_gen_40x40 inst_divide_sqrt(
    .aclk(clk_100MHZ),
    .s_axis_divisor_tvalid(sqrt_div_start),
    .s_axis_divisor_tdata(sqrt_x),       // 除数:sqrt_x
    .s_axis_dividend_tvalid(sqrt_div_start),
    .s_axis_dividend_tdata(sqrt_S),      // 被除数:sqrt_S
    .m_axis_dout_tvalid(sqrt_div_done),
    .m_axis_dout_tdata(sqrt_div_result)
);


assign sqrt_quotient = sqrt_div_result[79:40]; // 商


//=============================
// 牛顿迭代 三段式状态机
//=============================
reg [39:0] sqrt_x;
reg [39:0] sqrt_S;
reg [7:0]  newton_sqrt_cnt;

localparam IDLE            = 3'd0;
localparam state_DIV       = 3'd1;  // 这里调用除法IP
localparam state_SHIFT     = 3'd2;
localparam state_sqrt_DONE = 3'd3;

reg [2:0] curr_state;
reg [2:0] next_state;

// 第一段:状态寄存器
always @(posedge clk_100MHZ or negedge rst_n) begin
    if(!rst_n)
        curr_state <= IDLE;
    else
        curr_state <= next_state;
end

// 第二段:组合逻辑转移
always @(*) begin
    case(curr_state)
        IDLE: begin
            if(avg_divide_done)
                next_state = state_DIV;
            else
                next_state = IDLE;
        end

        state_DIV: begin
            if(sqrt_div_done)       // 等待IP除法完成
                next_state = state_SHIFT;
            else
                next_state = state_DIV;
        end

        state_SHIFT: begin
            if(newton_sqrt_cnt >= 16)
                next_state = state_sqrt_DONE;
            else
                next_state = state_DIV;
        end

        state_sqrt_DONE: begin
            next_state = IDLE;
        end

        default: next_state = IDLE;
    endcase
end

reg        div_start_en; 

// 第三段:时序输出逻辑
always @(posedge clk_100MHZ or negedge rst_n) begin
    if(!rst_n) begin
        sqrt_x         <= 0;
        sqrt_S         <= 0;
        newton_sqrt_cnt<= 0;
        div_start_en   <= 0;
        rms_valid      <= 0;
    end
    else begin
        case(curr_state)
            IDLE: begin
                newton_sqrt_cnt <= 0;
                rms_valid <= 0;
                div_start_en <= 0;           // 关闭启动
                if(avg_divide_done) begin
                    sqrt_S <= avg_value;     // 载入被开方数
                    sqrt_x <= avg_value >> 1;// 初始值
                end
            end

            // ==============================
            // ✅ 只启动一次除法IP,绝对安全
            // ==============================
            state_DIV: begin
                if(!div_start_en) begin
                    div_start_en   <= 1'b1;    // 只在第一次进入时启动
                    sqrt_div_start <= 1'b1;    // 发启动脉冲
                end
                else begin
                    sqrt_div_start <= 1'b0;    // 之后永远保持 0
                end

                // 除法完成,更新迭代值
                if(sqrt_div_done) begin
                    sqrt_x <= sqrt_x + sqrt_quotient;
                    div_start_en <= 1'b0;      // 复位启动标志
                end
            end

            state_SHIFT: begin
                sqrt_x <= sqrt_x >> 1;
                newton_sqrt_cnt <= newton_sqrt_cnt + 1'd1;
            end

            state_sqrt_DONE: begin
                rms_valid <= 1'b1;
            end
        endcase
    end
end

reg [15:0] reg_rms_value;

always @(posedge clk_100MHZ or negedge rst_n) begin
    if(!rst_n) begin
        reg_rms_value <= 16'd0;
    end
    else begin
        if(rms_valid == 1) begin
            reg_rms_value <= sqrt_x[15:0];
        end
        else begin
            reg_rms_value <= reg_rms_value;
        end
    end
end


assign rms_value_a = reg_rms_value;

endmodule
相关推荐
NamoAmitabha12810 分钟前
PL 端的 GPIO IP(AXI GPIO)---PS控制----deepseek
fpga开发·zynq--ps
hahaha60163 小时前
3D降噪算法YUV降噪FPGA实现
fpga开发
Hello-FPGA1 天前
基于RFSOC FPGA ZCU216 的CoaXPress 采集demo
fpga开发
9527华安1 天前
FPGA基于ADV7182解码PAL视频,Video Processing Subsystem去隔行,提供6套工程源码和技术支持
fpga开发·音视频·pal·adv7182
hahaha60161 天前
数字图像时域滤波或者3D降噪算法FPGA实现
算法·计算机视觉·fpga开发
GateWorld1 天前
Xilinx 7系列FPGA时钟网络详解
fpga开发·时钟网络·xilinx 7系列
szxinmai主板定制专家2 天前
X86 工控机 vs RK3588 异构主控:AMR 控制器 BOM、散热、长期运维对比
运维·stm32·单片机·嵌入式硬件·fpga开发·am62x
szxinmai主板定制专家2 天前
AMR 项目落地:机器人控制器硬件定制化需求复盘
arm开发·单片机·fpga开发·系统架构·机器人·am62x
FPGA小迷弟3 天前
FPGA 与卫星:从星载硬件到在轨智能的完整技术解析
fpga开发·架构·fpga·1024程序员节·无线电
NamoAmitabha1283 天前
CPU 内部结构是什么?---deepseek
fpga开发