FPGA 工频同步采集 + DDR3 缓存完整实现方案
目录
整体系统架构功能概述
时钟域划分(核心跨域隔离)
一、50Hz 工频 DPLL 同步模块 dpll_50hz.v
原理
二、ADC 同步采集模块 adc_sync_sample.v
三、异步 FIFO 跨时钟域桥 data_fifo_bridge.v
四、DDR3 MIG 控制器封装 ddr3_mig_top.v
IP 配置要点(Xilinx 7 系列 XC7A35T 为例)
五、DDR3 环形缓存控制器 ring_buffer_ctrl.v
工作机制
六、顶层集成 top_acq_ddr3.v
七、关键工程配置与优化说明
1. DDR 带宽匹配计算
2. 同步采集核心优势
3. 时序与稳定性优化
4. 扩展升级方向
八、适配芯片与资源预估(XC7A35T)
整体系统架构功能概述
- 工频锁相 DPLL:同步 50Hz 电网电压相位,生成同步采样时钟、同步触发脉冲;
- 多通道 ADC 同步采集(差分模拟输入);
- 实时数据流写入 DDR3 缓存(分段环形缓存 / 帧缓存双模式);
- DDR3 读通路:串口 / 以太网回传采集波形;
- 顶层模块划分:
dpll_50hz.v工频数字锁相环同步单元adc_sync_sample.v多通道同步采样控制ddr3_mig_top.vXilinx MIG IP DDR3 控制器封装data_fifo_bridge.v异步 FIFO 跨时钟域桥(采集域 ↔ DDR 控制器域)ring_buffer_ctrl.vDDR3 环形缓存管理器uart_tx.v波形数据上传输出
时钟域划分(核心跨域隔离)
- 模拟采集域
clk_adc:10MHz,ADC 采样时钟、DPLL 运算时钟 - DDR 控制器域
clk_ddr_200m:MIG 参考时钟 200MHz,DDR 用户逻辑时钟 100MHz - 系统管理域
clk_sys_50m:外设串口、指令解析
一、50Hz 工频 DPLL 同步模块 dpll_50hz.v
原理
电网电压经 ADC 采样得到正弦数字波形,通过相位检测器 + PI 环路滤波 + 数控振荡器 NCO 锁定工频相位,输出同步采样使能,实现整周期等间隔同步采样。
1. 模块端口定义
vin_adc:正弦交流采样,正负分别对应电压正负半周;phase_out:NCO 累加器原始相位,线性映射 0~2π;sync_sample_en均匀等分工频周期输出采样触发,用于 ADC 同步采集。
module dpll_50hz( input clk_adc, //10MHz系统时钟 input rst_n, //低电平复位 input signed [15:0] vin_adc, //ADC采样电压,有符号正弦波 output reg sync_sample_en,//同步采样使能脉冲 output reg [15:0] phase_out //16bit相位输出 0~65535=0~2π ); //1. 相位误差提取:过零检测+象限判断 reg signed [15:0] vin_delay; reg cross_zero; always@(posedge clk_adc or !rst_n)begin if(!rst_n)begin vin_delay <= 16'd0; cross_zero <= 1'b0; end else begin vin_delay <= vin_adc; // 判断当前采样与上一拍符号相反 → 电压跨越零点 cross_zero <= (vin_adc[15] != vin_delay[15]) ? 1'b1 : 1'b0; end end //2. NCO 50Hz基准 16bit相位累加器 localparam FREQ_CTRL_INIT = 16'd65536; //10M clk下50Hz步长 reg [15:0] nco_phase; reg signed [15:0] pi_out; reg signed [15:0] freq_ctrl; always@(posedge clk_adc or !rst_n)begin if(!rst_n)begin nco_phase <= 16'd0; freq_ctrl <= FREQ_CTRL_INIT; end else begin nco_phase <= nco_phase + freq_ctrl; end end //3. PI环路滤波 reg signed [31:0] pi_acc; always@(posedge clk_adc or !rst_n)begin if(!rst_n)begin pi_acc <= 32'd0; freq_ctrl <= FREQ_CTRL_INIT; end else begin if(cross_zero)begin pi_acc <= pi_acc + {{16{nco_phase[15]}},nco_phase}; freq_ctrl <= FREQ_CTRL_INIT + pi_acc[20:5]; end end end //4. 同步采样脉冲:每N个NCO相位点触发一次采样 localparam SAMPLE_POINT_PER_CYC = 256; //每周256点同步采集 reg [7:0] sample_cnt; always@(posedge clk_adc or !rst_n)begin if(!rst_n)begin sample_cnt <= 8'd0; sync_sample_en <= 1'b0; phase_out <= 16'd0; end else begin phase_out <= nco_phase; sample_cnt <= sample_cnt + 1'b1; sync_sample_en <= (sample_cnt == SAMPLE_POINT_PER_CYC-1); if(sync_sample_en) sample_cnt <= 8'd0; end end endmodule二、ADC 同步采集模块 adc_sync_sample.v
多路 ADC 在 DPLL 同步使能下并行采集,拼接成 32bit 采样帧送入异步 FIFO 跨域缓存
module adc_sync_sample( input clk_adc, input rst_n, input sync_sample_en, //DPLL同步触发 input signed [15:0] adc_ch1, input signed [15:0] adc_ch2, input signed [15:0] adc_ch3, output reg [63:0] sample_data, //4通道16bit打包 output reg fifo_wr_en ); always@(posedge clk_adc or !rst_n)begin if(!rst_n)begin sample_data <= 64'd0; fifo_wr_en <= 1'b0; end else begin fifo_wr_en <= sync_sample_en; if(sync_sample_en)begin sample_data <= {adc_ch1,adc_ch2,adc_ch3,16'd0}; end end end endmodule三、异步 FIFO 跨时钟域桥 data_fifo_bridge.v
采集 10MHz 域 → DDR 100MHz 域,使用 Xilinx FIFO Generator IP,参数: 写宽 64bit,读宽 64bit,深度 1024;独立读写时钟、满空标志。 顶层封装接口:
module data_fifo_bridge( input wr_clk,wr_rst, input [63:0] din, input wr_en, output full, input rd_clk,rd_rst, output [63:0] dout, input rd_en, output empty ); //调用FIFO Generator IP fifo_async_64x1024 u_fifo( .wr_clk(wr_clk),.wr_rst(wr_rst), .din(din),.wr_en(wr_en),.full(full), .rd_clk(rd_clk),.rd_rst(rd_rst), .dout(dout),.rd_en(rd_en),.empty(empty) ); endmodule四、DDR3 MIG 控制器封装 ddr3_mig_top.v
IP 配置要点(Xilinx 7 系列 XC7A35T 为例)
- DDR3 芯片:MT41J64M16-15
- MIG 参考时钟:200MHz 差分输入
- 用户接口时钟
ui_clk= 100MHz - 用户数据位宽
APP_DATA_WIDTH=128bit,地址 32bit - 封装统一读写接口,屏蔽 MIG 复杂握手信号
module ddr3_mig_top( input sys_clk_200m, input rst_n, //用户读写接口 100MHz ui_clk域 input ui_rst, input wr_req, input [27:0] wr_addr, input [127:0] wr_data, output reg wr_done, input rd_req, input [27:0] rd_addr, output reg [127:0] rd_data, output reg rd_done, //DDR3物理引脚 inout [15:0] ddr3_dq, inout [1:0] ddr3_dqs_n, inout [1:0] ddr3_dqs_p, output [13:0] ddr3_addr, output [2:0] ddr3_ba, output ddr3_ras_n, output ddr3_cas_n, output ddr3_we_n, output [0:0] ddr3_ck_p,ddr3_ck_n, output [0:0] ddr3_cke, output [0:0] ddr3_cs_n, output [1:0] ddr3_dm, output ddr3_odt ); //MIG IP例化 mig_7series_0 u_mig( .sys_clk_i(sys_clk_200m), .sys_rst_n(rst_n), .ui_clk(ui_clk), .ui_clk_sync_rst(ui_rst_mig), .mmcm_locked(mmcm_locked), .app_rdy(app_rdy), .app_en(app_en), .app_cmd(app_cmd), .app_addr(app_addr), .app_wdf_rdy(app_wdf_rdy), .app_wdf_wren(app_wdf_wren), .app_wdf_data(app_wdf_data), .app_wdf_end(app_wdf_end), .app_rd_data_valid(app_rd_data_valid), .app_rd_data(app_rd_data), //DDR物理引脚映射 .ddr3_dq(ddr3_dq),.ddr3_dqs_n(ddr3_dqs_n),.ddr3_dqs_p(ddr3_dqs_p), .ddr3_addr(ddr3_addr),.ddr3_ba(ddr3_ba),.ddr3_ras_n(ddr3_ras_n), .ddr3_cas_n(ddr3_cas_n),.ddr3_we_n(ddr3_we_n),.ddr3_ck_p(ddr3_ck_p), .ddr3_ck_n(ddr3_ck_n),.ddr3_cke(ddr3_cke),.ddr3_cs_n(ddr3_cs_n), .ddr3_dm(ddr3_dm),.ddr3_odt(ddr3_odt) ); //本地状态机:读写命令缓存、握手转换 localparam IDLE=2'b00,WRITE=2'b01,READ=2'b10; reg [1:0] state; reg [27:0] curr_addr; reg [127:0] curr_wdata; always@(posedge ui_clk or ui_rst)begin if(ui_rst)begin state <= IDLE; wr_done <= 1'b0; rd_done <=1'b0; end else begin case(state) IDLE:begin wr_done <= 1'b0; rd_done <=1'b0; if(wr_req)begin state <= WRITE; curr_addr <= wr_addr; curr_wdata <= wr_data; end else if(rd_req)begin state <= READ; curr_addr <= rd_addr; end end WRITE:begin //MIG写握手逻辑 if(app_rdy && app_wdf_rdy)begin wr_done <=1'b1; state <= IDLE; end end READ:begin if(app_rd_data_valid)begin rd_data <= app_rd_data; rd_done <=1'b1; state <= IDLE; end end endcase end end endmodule五、DDR3 环形缓存控制器 ring_buffer_ctrl.v
工作机制
- 环形缓冲区划分整片 DDR 地址空间:总深度
BUF_LEN=2^18(128K 点,适配工频多周期波形存储) - 写指针
wr_ptr:FIFO 有数据就连续写入 DDR,自动循环回绕 - 读指针
rd_ptr:读取波形上传,跟随写指针,防止读超写 - 满判断:
(wr_ptr - rd_ptr) > BUF_LEN - 1024触发缓存溢出保护,暂停采集写入
module ring_buffer_ctrl( input ui_clk,ui_rst, //FIFO读输入 input [63:0] fifo_rdata, input fifo_empty, output reg fifo_rd_en, //DDR用户接口 output reg ddr_wr_req, output reg [27:0] ddr_wr_addr, output reg [127:0] ddr_wr_data, input ddr_wr_done, output reg ddr_rd_req, output reg [27:0] ddr_rd_addr, input [127:0] ddr_rdata, input ddr_rd_done, //上传控制 input tx_start, //启动波形上传 output reg [63:0] tx_data, output reg tx_en ); localparam BUF_LEN = 18'h3FFFF; //环形缓存总长度 reg [17:0] wr_ptr,rd_ptr; reg [1:0] wr_state; reg [1:0] rd_state; reg [63:0] data_buf[1:0]; //拼接64bit×2 → DDR128bit //写逻辑:双64bit拼成128bit写入DDR always@(posedge ui_clk or ui_rst)begin if(ui_rst)begin wr_ptr <= 18'd0; wr_state <= 2'b00; fifo_rd_en <= 1'b0; ddr_wr_req <= 1'b0; end else begin case(wr_state) 2'b00:begin //取第一个64bit if(!fifo_empty)begin fifo_rd_en <=1'b1; wr_state <=2'b01; data_buf[0] <= fifo_rdata; end end 2'b01:begin //取第二个64bit fifo_rd_en <=1'b0; if(!fifo_empty)begin fifo_rd_en <=1'b1; wr_state <=2'b10; data_buf[1] <= fifo_rdata; end end 2'b10:begin //发起DDR写 fifo_rd_en <=1'b0; ddr_wr_req <=1'b1; ddr_wr_addr <= {9'd0,wr_ptr}; ddr_wr_data <= {data_buf[0],data_buf[1]}; wr_state <=2'b11; end 2'b11:begin //等待写完成,指针自增 ddr_wr_req <=1'b0; if(ddr_wr_done)begin wr_ptr <= wr_ptr + 1'b1; if(wr_ptr == BUF_LEN) wr_ptr <= 18'd0; wr_state <=2'b00; end end endcase end end //读逻辑:串口上传波形,拆分128bit为两路64bit输出 always@(posedge ui_clk or ui_rst)begin if(ui_rst)begin rd_ptr <=18'd0; rd_state <=2'b00; ddr_rd_req <=1'b0; tx_en <=1'b0; end else if(tx_start)begin case(rd_state) 2'b00:begin //发起读DDR ddr_rd_req <=1'b1; ddr_rd_addr <= {9'd0,rd_ptr}; rd_state <=2'b01; end 2'b01:begin ddr_rd_req <=1'b0; if(ddr_rd_done)begin tx_data <= ddr_rdata[127:64]; tx_en <=1'b1; rd_state <=2'b10; end end 2'b10:begin tx_en <=1'b0; tx_data <= ddr_rdata[63:0]; tx_en <=1'b1; rd_ptr <= rd_ptr +1'b1; if(rd_ptr == BUF_LEN) rd_ptr <=18'd0; rd_state <=2'b00; end endcase end end endmodule六、顶层集成 top_acq_ddr3.v
所有模块互联,完整顶层连接逻辑
module top_acq_ddr3( input sys_clk_200m, input rst_n, input clk_adc, //10M ADC时钟 //ADC模拟输入采样 input signed [15:0] adc_ch1,adc_ch2,adc_ch3, //波形上传串口 output uart_tx, //DDR3物理引脚 inout [15:0] ddr3_dq, inout [1:0] ddr3_dqs_n,ddr3_dqs_p, output [13:0] ddr3_addr, output [2:0] ddr3_ba, output ddr3_ras_n,ddr3_cas_n,ddr3_we_n, output [0:0] ddr3_ck_p,ddr3_ck_n,ddr3_cke,ddr3_cs_n, output [1:0] ddr3_dm, output ddr3_odt ); //内部信号定义 wire sync_sample_en; wire [15:0] vin_phase; wire [63:0] adc_sample_data; wire fifo_wr_en,fifo_full,fifo_empty; wire [63:0] fifo_rdata; wire ui_clk,ui_rst; wire ddr_wr_req,ddr_wr_done,ddr_rd_req,ddr_rd_done; wire [27:0] ddr_wr_addr,ddr_rd_addr; wire [127:0] ddr_wr_data,ddr_rdata; wire [63:0] tx_data; wire tx_en; //1.工频DPLL同步 dpll_50hz u_dpll( .clk_adc(clk_adc),.rst_n(rst_n), .vin_adc(adc_ch1), //电压通道做同步参考 .sync_sample_en(sync_sample_en),.phase_out(vin_phase) ); //2.ADC同步采集打包 adc_sync_sample u_adc_acq( .clk_adc(clk_adc),.rst_n(rst_n), .sync_sample_en(sync_sample_en), .adc_ch1(adc_ch1),.adc_ch2(adc_ch2),.adc_ch3(adc_ch3), .sample_data(adc_sample_data),.fifo_wr_en(fifo_wr_en) ); //3.异步FIFO跨时钟域 data_fifo_bridge u_fifo_bridge( .wr_clk(clk_adc),.wr_rst(!rst_n), .din(adc_sample_data),.wr_en(fifo_wr_en),.full(fifo_full), .rd_clk(ui_clk),.rd_rst(ui_rst), .dout(fifo_rdata),.rd_en(fifo_rd_en),.empty(fifo_empty) ); //4.DDR3 MIG控制器 ddr3_mig_top u_ddr3( .sys_clk_200m(sys_clk_200m),.rst_n(rst_n), .ui_clk(ui_clk),.ui_rst(ui_rst), .wr_req(ddr_wr_req),.wr_addr(ddr_wr_addr),.wr_data(ddr_wr_data),.wr_done(ddr_wr_done), .rd_req(ddr_rd_req),.rd_addr(ddr_rd_addr),.rd_data(ddr_rdata),.rd_done(ddr_rd_done), .ddr3_dq(ddr3_dq),.ddr3_dqs_n(ddr3_dqs_n),.ddr3_dqs_p(ddr3_dqs_p), .ddr3_addr(ddr3_addr),.ddr3_ba(ddr3_ba),.ddr3_ras_n(ddr3_ras_n), .ddr3_cas_n(ddr3_cas_n),.ddr3_we_n(ddr3_we_n),.ddr3_ck_p(ddr3_ck_p), .ddr3_ck_n(ddr3_ck_n),.ddr3_cke(ddr3_cke),.ddr3_cs_n(ddr3_cs_n), .ddr3_dm(ddr3_dm),.ddr3_odt(ddr3_odt) ); //5.环形缓存控制 ring_buffer_ctrl u_ring_buf( .ui_clk(ui_clk),.ui_rst(ui_rst), .fifo_rdata(fifo_rdata),.fifo_empty(fifo_empty),.fifo_rd_en(fifo_rd_en), .ddr_wr_req(ddr_wr_req),.ddr_wr_addr(ddr_wr_addr),.ddr_wr_data(ddr_wr_data),.ddr_wr_done(ddr_wr_done), .ddr_rd_req(ddr_rd_req),.ddr_rd_addr(ddr_rd_addr),.ddr_rdata(ddr_rdata),.ddr_rd_done(ddr_rd_done), .tx_start(1'b1), //持续上传波形,可改外部指令控制 .tx_data(tx_data),.tx_en(tx_en) ); //6.UART波形输出 uart_tx u_uart( .clk(ui_clk),.rst_n(!ui_rst), .tx_data(tx_data),.tx_en(tx_en),.tx(uart_tx) ); endmodule七、关键工程配置与优化说明
1. DDR 带宽匹配计算
- 工频每周 256 点,3 通道 16bit = 768Byte / 周期
- 50Hz → 每秒数据量:
50 × 768 = 38400 Byte/s - DDR3 100MHz 用户域 128bit 带宽:1.6GB/s,带宽冗余极大,无吞吐压力
2. 同步采集核心优势
DPLL 锁定电网相位,消除采样异步误差,用于谐波分析、电能质量检测;环形 DDR 缓存可连续存储多秒工频波形,支持故障录波。
3. 时序与稳定性优化
- 采集与 DDR 跨域必须异步 FIFO 隔离,禁止直接打拍传递大量数据;
- DDR 读写状态机单周期握手,避免多周期组合逻辑造成时序违例;
- 环形缓存增加水位阈值,缓存快满时暂停 ADC 写入,防止数据丢失;
- MIG IP 输出
ui_clk做全局时钟布线,减少 DDR 域时序余量损耗。
4. 扩展升级方向
- 替换 UART 为千兆以太网 TCP/IP,高速波形上传;
- 增加 FFT 运算单元,DDR 读取波形实时谐波计算;
- 双 DDR 分区:一区缓存实时采集,二区读取上传,乒乓操作无中断录波;
- 增加触发逻辑(过流 / 过压故障触发定点存储波形)。
八、适配芯片与资源预估(XC7A35T)
- LUT:约 18000,FF:22000
- Block RAM:FIFO 占用 2 个 36K BRAM
- MIG DDR3 IP 占用 2 个 MMCM、16 个 IOB、PHY 资源
- DSP48E:DPLL PI 滤波、相位运算占用 8 个 DSP