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
相关推荐
坏孩子的诺亚方舟16 天前
FPGA系统架构设计实践15_高云Arora V系列时钟体系
fpga开发·系统架构
FPGA小徐16 天前
入门 CNN 结构全解析|从流程图理论到 FPGA Verilog 硬件实现(含习题带讲解)
fpga开发
FPGA小徐16 天前
FPGA 数字信号处理:并行 FIR 与串行滤波器设计原理、对比与完整 Verilog 实现
fpga开发
Saniffer_SH17 天前
【高清视频】Gen6 服务器还没到,Gen6 SSD 怎么测?Emily 现场演示三种测试环境
人工智能·驱动开发·测试工具·缓存·fpga开发·计算机外设·压力测试
zlinear数据采集卡17 天前
双核架构深度解析:ARM+FPGA如何让数据采集卡实现500Ksps高性能?
arm开发·fpga开发·架构
9527华安17 天前
FPGA实现GTH Transceivers Wizard传输2路视频,基于aurora 8b10b编解码架构,提供4套工程源码和技术支持
fpga开发·gth·aurora 8b10b·transceivers
FPGA小徐18 天前
FPGA 数字信号处理(二):并行 FIR 滤波器的 Verilog 全流程设计与实现
fpga开发
国科安芯18 天前
基于AS32S601ZIT2型抗辐照MCU的商业航天卫星姿态确定与控制系统研究
单片机·嵌入式硬件·安全·fpga开发·架构·risc-v
ALINX技术博客18 天前
【黑金云课堂】FPGA技术教程FPGA基础:I2C 总线通信技术
fpga开发·i2c
Hello-FPGA18 天前
Xilinx KU040 FPGA Camera Link 图像采集
c++·fpga开发