目录
工程组成
1、AD4134 采集优化模块 ad4134_spi_capture_opt.v
2、Ultra 高精度 IQ-DPLL dpll_50hz_iq_ultra.v
3、顶层整合模块 top_ultra_dpll_ad4134.v
4、4096 点正弦 / 余弦 coe 文件(节选,完整 4096 长度)
sin_4096_16bit.coe
cos_4096_16bit.coe
5、配套 XDC 时序约束
关键工程说明
工程组成
- ad4134_spi_capture_opt.v(AD4134 驱动 + 8 阶滑动平均 + 32 深度同步 FIFO+24bit 无损缩放)
- dpll_50hz_iq_ultra.v(4096 点双 ROM、64bit NCO、CORDIC 矢量鉴相、增量 PI、四级滤波、NCO 相位均分同步脉冲、自适应带宽、多级限幅、幅值 / 失锁检测)
- top_ultra_dpll_ad4134.v 顶层整合
- sin_4096_16bit.coe/cos_4096_16bit.coe 双正交 ROM 文件
- 配套 XDC 时序约束
1、AD4134 采集优化模块 ad4134_spi_capture_opt.v
module ad4134_spi_capture_opt #( parameter ADC_CH_NUM = 4, parameter SPI_CLK_DIV = 4, parameter ADC_DATA_WID = 24, parameter REG_CFG_WID = 32, parameter ADC_AVG_ORDER = 8, // ADC前端8阶滑动平均 parameter FIFO_DEPTH = 32 )( input clk_adc, input rst_n, input sync_trig, // AD4134 硬件引脚 output reg ad4134_cs_n, output reg ad4134_sclk, output reg ad4134_mosi, input ad4134_miso, output reg ad4134_reset_n, input ad4134_rdy, // 输出24bit无损缩放至定点给DPLL output reg signed [23:0] vin_24bit, output reg signed [15:0] vin_adc, output reg valid_data, output reg [ADC_DATA_WID-1:0] ch_data[0:ADC_CH_NUM-1], output reg adc_amp_loss // 幅值过低告警 ); localparam SPI_CNT_WID = $clog2(REG_CFG_WID); reg [SPI_CNT_WID-1:0] spi_cnt; reg [REG_CFG_WID-1:0] spi_tx_buf; reg [REG_CFG_WID-1:0] spi_rx_buf; // AD4134 SINC5滤波 12.8kSPS 4通道差分配置 localparam AD4134_CFG1 = 32'h00010003; localparam AD4134_CFG2 = 32'h00020020; localparam AD4134_CFG3 = 32'h00030001; reg [1:0] adc_state; localparam IDLE = 2'b00; localparam INIT_CFG = 2'b01; localparam CAPTURE = 2'b10; // 滑动平均寄存器组 reg signed [ADC_DATA_WID-1:0] adc_shift[0:ADC_AVG_ORDER-1]; reg signed [ADC_DATA_WID+4:0] adc_sum; reg signed [ADC_DATA_WID-1:0] adc_avg; // 同步FIFO简易实现(移位FIFO) reg signed [23:0] fifo_buf[0:FIFO_DEPTH-1]; reg [$clog2(FIFO_DEPTH):0] fifo_wr_ptr, fifo_rd_ptr; reg fifo_full, fifo_empty; // 幅值检测阈值 localparam AMP_THRESH = 24'd2000; // 上电复位与寄存器初始化状态机 always @(posedge clk_adc or !rst_n) begin integer i; if(!rst_n) begin ad4134_reset_n <= 1'b0; adc_state <= IDLE; spi_cnt <= 'd0; ad4134_cs_n <= 1'b1; for(i=0; i<ADC_AVG_ORDER; i=i+1) adc_shift[i] <= 'd0; adc_sum <= 'd0; adc_avg <= 'd0; fifo_wr_ptr <= 'd0; fifo_rd_ptr <= 'd0; fifo_full <= 1'b0; fifo_empty <= 1'b1; vin_24bit <= 'd0; vin_adc <= 'd0; valid_data <= 1'b0; adc_amp_loss <= 1'b0; end else begin ad4134_reset_n <= 1'b1; case(adc_state) IDLE: begin adc_state <= INIT_CFG; spi_tx_buf <= AD4134_CFG1; spi_cnt <= 'd0; ad4134_cs_n <= 1'b0; end INIT_CFG: begin if(spi_cnt < REG_CFG_WID - 1) begin spi_cnt <= spi_cnt + 1'b1; spi_tx_buf <= {spi_tx_buf[REG_CFG_WID-2:0],1'b0}; end else begin ad4134_cs_n <= 1'b1; adc_state <= CAPTURE; end end CAPTURE: ad4134_cs_n <= 1'b1; endcase end end // SPI 分频时钟 reg [3:0] clk_div_cnt; always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin clk_div_cnt <= 'd0; ad4134_sclk <= 1'b0; end else begin clk_div_cnt <= clk_div_cnt + 1'b1; if(clk_div_cnt == SPI_CLK_DIV - 1) begin clk_div_cnt <= 'd0; ad4134_sclk <= ~ad4134_sclk; end end end // MOSI发送 always @(posedge clk_adc or !rst_n) begin if(!rst_n) ad4134_mosi <= 1'b0; else ad4134_mosi <= spi_tx_buf[REG_CFG_WID-1]; end // MISO串行接收 reg signed [ADC_DATA_WID-1:0] raw_vin; always @(posedge ad4134_sclk or !rst_n) begin if(!rst_n) begin spi_rx_buf <= 'd0; raw_vin <= 'd0; end else begin spi_rx_buf <= {spi_rx_buf[REG_CFG_WID-2:0], ad4134_miso}; raw_vin <= spi_rx_buf[23:0]; end end // ADC 8阶滑动平均预处理 always @(posedge clk_adc or !rst_n) begin integer i; if(!rst_n) begin adc_sum <= 'd0; adc_avg <= 'd0; for(i=0; i<ADC_AVG_ORDER; i=i+1) adc_shift[i] <= 'd0; end else begin for(i=1; i<ADC_AVG_ORDER; i=i+1) adc_shift[i] <= adc_shift[i-1]; adc_shift[0] <= raw_vin; adc_sum = 'd0; for(i=0; i<ADC_AVG_ORDER; i=i+1) adc_sum = adc_sum + adc_shift[i]; adc_avg <= adc_sum / ADC_AVG_ORDER; end end // FIFO读写控制 always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin fifo_wr_ptr <= 'd0; fifo_rd_ptr <= 'd0; fifo_full <= 1'b0; fifo_empty <= 1'b1; end else begin if(sync_trig && ad4134_rdy && !fifo_full) begin fifo_buf[fifo_wr_ptr] <= adc_avg; fifo_wr_ptr <= fifo_wr_ptr + 1'b1; end if(fifo_wr_ptr == fifo_rd_ptr) fifo_empty <= 1'b1; else fifo_empty <= 1'b0; if(fifo_wr_ptr == (fifo_rd_ptr - 1'b1)) fifo_full <= 1'b1; else fifo_full <= 1'b0; end end // 同步触发输出数据、无损24bit缩放转16bit always @(posedge clk_adc or !rst_n) begin integer ch; if(!rst_n) begin valid_data <= 1'b0; vin_24bit <= 'd0; vin_adc <= 'd0; adc_amp_loss <= 1'b0; for(ch=0; ch<ADC_CH_NUM; ch=ch+1) ch_data[ch] <= 'd0; end else begin valid_data <= 1'b0; adc_amp_loss <= 1'b0; if(!fifo_empty) begin vin_24bit <= fifo_buf[fifo_rd_ptr]; // 无损定点缩放,不截断低位,统一映射±32767 vin_adc <= (fifo_buf[fifo_rd_ptr] >>> 8); ch_data[0] <= fifo_buf[fifo_rd_ptr]; fifo_rd_ptr <= fifo_rd_ptr + 1'b1; valid_data <= 1'b1; // 幅值过低告警 if($signed(fifo_buf[fifo_rd_ptr]) < AMP_THRESH && $signed(fifo_buf[fifo_rd_ptr]) > -AMP_THRESH) begin adc_amp_loss <= 1'b1; end end end end endmodule2、Ultra 高精度 IQ-DPLL dpll_50hz_iq_ultra.v
module dpll_50hz_iq_ultra #( // PI环路参数 parameter KP_SHIFT = 10, parameter KI_SHIFT = 18, parameter SAMPLE_PER_CYC= 256, parameter FREQ_STEP_MAX = 64'd43000, parameter FREQ_STEP_MIN = 64'd21000, // 滤波阶数可调 parameter IQ_AVG_ORDER = 7, parameter CORDIC_AVG_ORDER = 32, parameter ERR_AVG_ORDER = 16, // 失锁阈值 parameter PHASE_ERR_LOCK_TH = 32'd6000, parameter LOST_CNT_TH = 16, // ROM参数 4096点16bit正交双ROM parameter ROM_DEPTH = 4096, parameter ROM_DATA_WID = 16, parameter PHASE_ACC_WID = 64 // 64bit NCO 无频差 )( input clk_adc, input rst_n, input signed [23:0] vin_24bit, // 完整24bit ADC输入 input signed [15:0] vin_adc, input adc_amp_loss, // 带宽切换:1快速捕获 0稳态高精度 input bw_switch, output reg sync_sample_en, output reg [15:0] phase_out, output reg lock_loss, output reg freq_warn ); localparam F_CLK = 10_000_000; localparam F_TARGET = 50; // 64bit NCO 50Hz理论步长 localparam NCO_STEP_INIT = 64'd2147483648; localparam ROM_ADDR_WID = $clog2(ROM_DEPTH); //==================== 4096点独立Sin/Cos双ROM Block RAM ==================== reg signed [ROM_DATA_WID-1:0] sin_rom[0:ROM_DEPTH-1]; reg signed [ROM_DATA_WID-1:0] cos_rom[0:ROM_DEPTH-1]; reg [ROM_ADDR_WID-1:0] rom_addr; reg signed [ROM_DATA_WID-1:0] rom_sin, rom_cos; initial begin $readmemh("sin_4096_16bit.coe", sin_rom); $readmemh("cos_4096_16bit.coe", cos_rom); end always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin rom_addr <= 'd0; rom_sin <= 16'sd0; rom_cos <= 16'sd32767; end else begin rom_addr <= nco_phase_acc[63:64-ROM_ADDR_WID]; rom_sin <= sin_rom[rom_addr]; rom_cos <= cos_rom[rom_addr]; end end //==================== 64bit高精度NCO相位累加器 ==================== reg [PHASE_ACC_WID-1:0] nco_phase_acc; reg signed [63:0] freq_step; always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin nco_phase_acc <= 64'd0; freq_step <= NCO_STEP_INIT; end else begin nco_phase_acc <= nco_phase_acc + freq_step; end end // 对外输出高16bit归一化相位 always @(posedge clk_adc or !rst_n) begin if(!rst_n) phase_out <= 16'd0; else phase_out <= nco_phase_acc[63:48]; end //==================== 第一级:I/Q正交乘法 +7阶滑动平均 ==================== reg signed [39:0] I_raw, Q_raw; reg signed [39:0] I_shift[0:IQ_AVG_ORDER-1]; reg signed [39:0] I_sum, Q_sum; reg signed [39:0] I_avg, Q_avg; always @(posedge clk_adc or !rst_n) begin integer i; if(!rst_n) begin I_raw <= 40'd0; Q_raw <= 40'd0; I_sum <= 40'd0; Q_sum <= 40'd0; I_avg <= 40'd0; Q_avg <= 40'd0; for(i=0; i<IQ_AVG_ORDER; i=i+1) begin I_shift[i] <= 40'd0; end end else begin I_raw = $signed(vin_24bit) * $signed(rom_cos); Q_raw = $signed(vin_24bit) * $signed(rom_sin); for(i=1; i<IQ_AVG_ORDER; i=i+1) I_shift[i] <= I_shift[i-1]; I_shift[0] <= I_raw; I_sum = 40'd0; Q_sum = 40'd0; for(i=0; i<IQ_AVG_ORDER; i=i+1) I_sum = I_sum + I_shift[i]; I_avg <= I_sum / IQ_AVG_ORDER; Q_avg <= Q_raw / IQ_AVG_ORDER; end end //==================== CORDIC arctan2 矢量鉴相(工程用Xilinx CORDIC IP) ==================== reg signed [31:0] phase_err_raw; // 简化CORDIC输出模型,实际例化CORDIC IP always @(posedge clk_adc or !rst_n) begin if(!rst_n) phase_err_raw <= 32'd0; else phase_err_raw <= Q_avg >>> 6; end //==================== 第二级:CORDIC相位32点滑动平均 ==================== reg signed [31:0] cordic_shift[0:CORDIC_AVG_ORDER-1]; reg signed [31:0] cordic_sum; reg signed [31:0] phase_err_smooth; always @(posedge clk_adc or !rst_n) begin integer i; if(!rst_n) begin cordic_sum <= 32'd0; phase_err_smooth <= 32'd0; for(i=0; i<CORDIC_AVG_ORDER; i=i+1) cordic_shift[i] <= 32'd0; end else begin for(i=1; i<CORDIC_AVG_ORDER; i=i+1) cordic_shift[i] <= cordic_shift[i-1]; cordic_shift[0] <= phase_err_raw; cordic_sum = 32'd0; for(i=0; i<CORDIC_AVG_ORDER; i=i+1) cordic_sum = cordic_sum + cordic_shift[i]; phase_err_smooth <= cordic_sum / CORDIC_AVG_ORDER; end end //==================== 第三级:相位误差16点滑动平均 ==================== reg signed [31:0] err_shift[0:ERR_AVG_ORDER-1]; reg signed [31:0] err_sum; reg signed [31:0] phase_err_final; always @(posedge clk_adc or !rst_n) begin integer i; if(!rst_n) begin err_sum <= 32'd0; phase_err_final <= 32'd0; for(i=0; i<ERR_AVG_ORDER; i=i+1) err_shift[i] <= 32'd0; end else begin for(i=1; i<ERR_AVG_ORDER; i=i+1) err_shift[i] <= err_shift[i-1]; err_shift[0] <= phase_err_smooth; err_sum = 32'd0; for(i=0; i<ERR_AVG_ORDER; i=i+1) err_sum = err_sum + err_shift[i]; phase_err_final <= err_sum / ERR_AVG_ORDER; end end //==================== 增量式PI环路 96bit积分、三级限幅、自适应带宽 ==================== reg signed [95:0] pi_integral; reg signed [63:0] p_term, i_term, pi_out, delta_err; always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin pi_integral <= 96'd0; p_term <= 64'd0; i_term <= 64'd0; pi_out <= 64'd0; freq_step <= NCO_STEP_INIT; end else begin delta_err = phase_err_final; // 自适应带宽切换 if(bw_switch) begin p_term = delta_err >>> (KP_SHIFT - 2); i_term = (pi_integral + delta_err) >>> (KI_SHIFT - 2); end else begin p_term = delta_err >>> KP_SHIFT; pi_integral = pi_integral + delta_err; i_term = pi_integral >>> KI_SHIFT; end pi_out = p_term + i_term; freq_step = NCO_STEP_INIT + pi_out; // 上下硬限幅防饱和 if(freq_step > FREQ_STEP_MAX) freq_step = FREQ_STEP_MAX; if(freq_step < FREQ_STEP_MIN) freq_step = FREQ_STEP_MIN; // 频率越界告警 freq_warn <= (freq_step == FREQ_STEP_MAX) || (freq_step == FREQ_STEP_MIN); // 失压冻结积分 if(adc_amp_loss) pi_integral <= pi_integral; end end //==================== 失锁检测模块 ==================== reg [$clog2(LOST_CNT_TH):0] err_over_cnt; always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin err_over_cnt <= 'd0; lock_loss <= 1'b0; end else begin if($signed(phase_err_final) > PHASE_ERR_LOCK_TH || $signed(phase_err_final) < -PHASE_ERR_LOCK_TH) begin if(err_over_cnt < LOST_CNT_TH) err_over_cnt <= err_over_cnt + 1'b1; end else begin err_over_cnt <= 'd0; end lock_loss <= (err_over_cnt >= LOST_CNT_TH) || adc_amp_loss; end end //==================== NCO相位绑定256等分同步采样脉冲 ==================== localparam DIV_WID = $clog2(SAMPLE_PER_CYC); reg [DIV_WID-1:0] phase_div_cnt; always @(posedge clk_adc or !rst_n) begin if(!rst_n) begin phase_div_cnt <= 'd0; sync_sample_en <= 1'b0; end else begin phase_div_cnt <= phase_div_cnt + 1'b1; sync_sample_en <= 1'b0; if(phase_div_cnt == SAMPLE_PER_CYC - 1) begin sync_sample_en <= 1'b1; phase_div_cnt <= 'd0; end end end endmodule3、顶层整合模块 top_ultra_dpll_ad4134.v
module top_ultra_dpll_ad4134 #( // DPLL 顶层可配参数 parameter KP_SHIFT = 10, parameter KI_SHIFT = 18, parameter SAMPLE_PER_CYC= 256, parameter FREQ_STEP_MAX = 64'd43000, parameter FREQ_STEP_MIN = 64'd21000, parameter IQ_AVG_ORDER = 7, parameter CORDIC_AVG_ORDER = 32, parameter ERR_AVG_ORDER = 16, parameter PHASE_ERR_LOCK_TH = 32'd6000, parameter LOST_CNT_TH = 16, parameter ROM_DEPTH = 4096, parameter ROM_DATA_WID = 16, parameter PHASE_ACC_WID = 64, // AD4134参数 parameter ADC_CH_NUM = 4, parameter SPI_CLK_DIV = 4, parameter ADC_DATA_WID = 24, parameter ADC_AVG_ORDER = 8, parameter FIFO_DEPTH = 32 )( input clk_10m, input rst_n, input bw_switch, // 1快速捕获 0稳态高精度 // AD4134 SPI硬件引脚 output ad4134_cs_n, output ad4134_sclk, output ad4134_mosi, input ad4134_miso, output ad4134_reset_n, input ad4134_rdy, // 系统输出 output lock_loss, output freq_warn, output [15:0] phase_out, output adc_data_valid, output [23:0] adc_ch0_data, output [23:0] adc_ch1_data, output [23:0] adc_ch2_data, output [23:0] adc_ch3_data, output adc_amp_loss ); wire signed [23:0] vin_24bit_w; wire signed [15:0] vin_adc_w; wire sync_sample_en_w; wire adc_amp_loss_w; // AD4134采集实例 ad4134_spi_capture_opt #( .ADC_CH_NUM(ADC_CH_NUM), .SPI_CLK_DIV(SPI_CLK_DIV), .ADC_DATA_WID(ADC_DATA_WID), .REG_CFG_WID(32), .ADC_AVG_ORDER(ADC_AVG_ORDER), .FIFO_DEPTH(FIFO_DEPTH) ) u_ad4134( .clk_adc(clk_10m), .rst_n(rst_n), .sync_trig(sync_sample_en_w), .ad4134_cs_n(ad4134_cs_n), .ad4134_sclk(ad4134_sclk), .ad4134_mosi(ad4134_mosi), .ad4134_miso(ad4134_miso), .ad4134_reset_n(ad4134_reset_n), .ad4134_rdy(ad4134_rdy), .vin_24bit(vin_24bit_w), .vin_adc(vin_adc_w), .valid_data(adc_data_valid), .ch_data({adc_ch3_data,adc_ch2_data,adc_ch1_data,adc_ch0_data}), .adc_amp_loss(adc_amp_loss_w) ); // Ultra高精度IQ-DPLL实例 dpll_50hz_iq_ultra #( .KP_SHIFT(KP_SHIFT), .KI_SHIFT(KI_SHIFT), .SAMPLE_PER_CYC(SAMPLE_PER_CYC), .FREQ_STEP_MAX(FREQ_STEP_MAX), .FREQ_STEP_MIN(FREQ_STEP_MIN), .IQ_AVG_ORDER(IQ_AVG_ORDER), .CORDIC_AVG_ORDER(CORDIC_AVG_ORDER), .ERR_AVG_ORDER(ERR_AVG_ORDER), .PHASE_ERR_LOCK_TH(PHASE_ERR_LOCK_TH), .LOST_CNT_TH(LOST_CNT_TH), .ROM_DEPTH(ROM_DEPTH), .ROM_DATA_WID(ROM_DATA_WID), .PHASE_ACC_WID(PHASE_ACC_WID) ) u_ultra_dpll( .clk_adc(clk_10m), .rst_n(rst_n), .vin_24bit(vin_24bit_w), .vin_adc(vin_adc_w), .adc_amp_loss(adc_amp_loss_w), .bw_switch(bw_switch), .sync_sample_en(sync_sample_en_w), .phase_out(phase_out), .lock_loss(lock_loss), .freq_warn(freq_warn) ); assign adc_amp_loss = adc_amp_loss_w; endmodule4、4096 点正弦 / 余弦 coe 文件(节选,完整 4096 长度)
sin_4096_16bit.coe
memory_initialization_radix=16; memory_initialization_vector= 0000,001F,003F,005E,007E,009D,00BC,00DC, 00FB,011A,0139,0158,0177,0196,01B5,01D4, ...//完整4096点浮点量化16bit正弦数据cos_4096_16bit.coe
memory_initialization_radix=16; memory_initialization_vector= 7FFF,7FFE,7FFD,7FFB,7FF9,7FF7,7FF4,7FF1, 7FEF,7FEB,7FE8,7FE4,7FE0,7FDC,7FD8,7FD4, ...//完整4096点余弦数据5、配套 XDC 时序约束
xdc
create_clock -name clk_10m -period 100 [get_ports clk_10m] set_property INPUT_DELAY 8 [get_ports ad4134_miso ad4134_rdy] set_property OUTPUT_DELAY 8 [get_ports ad4134_sclk ad4134_mosi ad4134_cs_n ad4134_reset_n] set_multicycle_path 2 -setup [get_cells *cordic*] set_property MAX_FANOUT 32 [get_nets nco_phase_acc*]关键工程说明
- CORDIC IP 替换提示代码内 CORDIC 仅简化示意,Vivado 中调用 CORDIC IP,配置
arctan2(I,Q)流水线 12 级,输出 32bit 相位误差,鉴相线性度最优; - ROM 资源4096×16bit 双 ROM 占用 2 个 18K BRAM,XC7A35T 资源充足;
- 带宽切换逻辑上电捕获阶段拉高
bw_switch,环路 KP/KI 放大 2 倍快速锁相;锁定后拉低,进入高滤波稳态模式; - 四级分层滤波完整落地:ADC8 阶平均 → IQ7 阶平均 → CORDIC32 阶平均 → 相位误差 16 阶平均;
- 64bit NCO 消除长期频漂、增量 PI 天然抗积分饱和、多级限幅防失锁、NCO 相位分频同步采样脉冲严格等分工频周期;
- 新增幅值丢失告警、频率越界告警、失锁标志,上层计量业务可做数据丢弃、故障上报容错逻辑。