PCIe数据采集系统
PCIe数据采集系统
一、模块功能划分与职责
1. 时钟管理模块 (clock_manager
)
- 核心功能:
- 生成系统所需的多时钟信号(100MHz 系统时钟、125MHz PCIe 时钟、200MHz DDR3 时钟)。
- 关键接口:
- 输入:系统主时钟
sys_clk
、PCIe 差分参考时钟pcie_refclk_p/n
、 - 输出:各模块所需时钟(
pcie_user_clk
、ddr3_user_clk
)
- 输入:系统主时钟
代码展示
module clock_manager (// 输入时钟input wire sys_clk, // 系统主时钟 (100MHz)input wire pcie_refclk_p, // PCIe参考时钟正极input wire pcie_refclk_n, // PCIe参考时钟负极// 输出时钟output wire pcie_user_clk, // PCIe用户时钟 (125MHz)output wire ddr3_user_clk, // DDR3用户时钟 (200MHz)output wire pll_locked // PLL锁定标志
);// 内部信号声明wire pcie_refclk; // 单端PCIe参考时钟wire pll_fb_out; // PLL反馈信号wire pcie_user_clk_bufg; // PCIe用户时钟 (BUFGMUX输出)wire ddr3_user_clk_bufg; // DDR3用户时钟 (BUFGMUX输出)// =========================// 差分时钟缓冲器 (IBUFDS_GTE2)// =========================IBUFDS_GTE2 #(.REFCLK_EN_TX_PATH ("FALSE"),.REFCLK_HROW_CK_SEL ("REFCLK_HROW_CK0"),.REFCLK_ICNTL_RX ("00")) ibufds_pcie_refclk (.O (pcie_refclk),.ODIV2 (),.CEB (1'b0),.I (pcie_refclk_p),.IB (pcie_refclk_n));// =========================// 时钟生成器 (MMCM/PLL)// =========================MMCME4_BASE #(.BANDWIDTH ("OPTIMIZED"),.CLKOUT0_DIVIDE_F (8.000), // 125MHz (1000MHz/8).CLKOUT0_DUTY_CYCLE (0.500),.CLKOUT0_PHASE (0.000),.CLKOUT1_DIVIDE (5), // 200MHz (1000MHz/5).CLKOUT1_DUTY_CYCLE (0.500),.CLKOUT1_PHASE (0.000),.CLKIN1_PERIOD (10.000), // 100MHz输入周期.CLKFBOUT_MULT_F (10.000), // VCO = 100MHz * 10 = 1000MHz.DIVCLK_DIVIDE (1),.REF_JITTER1 (0.010)) mmcm_inst (.CLKOUT0 (pcie_user_clk_bufg),.CLKOUT1 (ddr3_user_clk_bufg),.CLKFBOUT (pll_fb_out),.LOCKED (pll_locked),.CLKFBIN (pll_fb_out),.CLKIN1 (sys_clk),.PWRDWN (1'b0),.RST (1'b0) // 固定为0(复位由system_control处理));// =========================// 全局时钟缓冲器 (BUFGMUX)// =========================BUFG pcie_user_clk_bufg_inst (.I (pcie_user_clk_bufg),.O (pcie_user_clk));BUFG ddr3_user_clk_bufg_inst (.I (ddr3_user_clk_bufg),.O (ddr3_user_clk));endmodule
关键问题
1.在上述代码中,提到了BUFG 原语。
BUFG pcie_user_clk_bufg_inst (.I (pcie_user_clk_bufg), .O (pcie_user_clk));
BUFG ddr3_user_clk_bufg_inst (.I (ddr3_user_clk_bufg), .O (ddr3_user_clk));
- BUFG (Buffer Global) 是 Xilinx FPGA 中的全局时钟缓冲器原语,用于将时钟信号驱动到 FPGA 的全局时钟网络(Global Clock Network)。
- 全局时钟网络的特点:
- 低延迟:专门设计的低阻抗布线,确保时钟信号同步到达所有触发器。
- 高驱动能力:能够驱动大量负载(如数千个触发器)而不失真。
- 平衡延迟:所有时钟路径延迟一致,避免时钟偏移(skew)问题。
为什么需要 BUFG?
- FPGA 内部有多种时钟网络:
- 全局时钟网络(由 BUFG 驱动):用于高频、关键路径的时钟(如系统主时钟、PCIe 时钟)。
- 区域时钟网络:用于局部模块的时钟,驱动能力和延迟次于全局网络。
- 如果不使用 BUFG,时钟信号可能通过普通布线到达触发器,导致:
- 时钟延迟增加,影响时序收敛。
- 不同触发器的时钟到达时间不一致(时钟偏移),引发亚稳态。
- 本例中,
pcie_user_clk_bufg
和ddr3_user_clk_bufg
是 MMCM 生成的时钟信号,但需通过 BUFG 驱动到全局网络,确保:- PCIe 模块的所有触发器使用同步的 125MHz 时钟。
- DDR3 控制器的所有操作在 200MHz 全局时钟下同步执行。
2. 系统控制模块 (system_control
)
- 核心功能:
- 复位同步:将 PCIe 物理层复位信号同步到不同时钟域,避免亚稳态。
- 状态监控:接收系统状态和错误标志,通过 LED 实时显示(低 4 位状态,最高位错误)。
- 关键接口:
- 输入:时钟信号、PCIe 复位信号、DDR3/PCIe 初始化完成标志、系统状态、错误标志。
- 输出:同步后的复位信号、调试 LED 信号。
代码展示:
module system_control (// 时钟输入input sys_clk, // 系统主时钟 (100MHz, sys_clk域)input pcie_user_clk, // PCIe用户时钟 (125MHz, pcie_user_clk域)input ddr3_user_clk, // DDR3用户时钟 (200MHz, ddr3_user_clk域)// 复位输入input pcie_perst_n, // PCIe物理层复位 (异步, 低有效)input sys_rst_n, // 系统全局复位 (低有效, 异步)input pll_locked, // PLL锁定标志 (来自clock_manager)// 状态监控输入input init_calib_complete, // DDR3初始化完成标志 (高有效)input pcie_init_done, // PCIe初始化完成标志 (高有效)input [3:0] system_state, // 系统状态机状态 (来自顶层)input error_flag, // 系统错误标志 (来自顶层)// 复位输出output reg pcie_reset_n, // PCIe域同步复位 (低有效, pcie_user_clk域)output reg system_reset_n, // 系统级同步复位 (低有效, sys_clk域)output reg ddr3_reset_n, // DDR3域同步复位 (低有效, ddr3_user_clk域)// 调试输出output reg [7:0] debug_leds // 8位调试LED (低4位状态, 最高位错误标志)
);// 复位计数器 (确保PLL锁定后延时释放复位)reg [15:0] reset_counter;// ======================// 系统级复位同步 (sys_clk域)// ======================always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n || !pll_locked) beginreset_counter <= 16'h0000;system_reset_n <= 1'b0;end else beginif (reset_counter < 16'hFFFF) beginreset_counter <= reset_counter + 1'b1;system_reset_n <= 1'b0; // 保持复位状态end else beginsystem_reset_n <= 1'b1; // 释放复位endendend// ======================// PCIe复位同步 (pcie_user_clk域)// ======================reg [1:0] pcie_rst_sync;always @(posedge pcie_user_clk or negedge sys_rst_n) beginif (!sys_rst_n || !pll_locked) beginpcie_rst_sync <= 2'b00;pcie_reset_n <= 1'b0;end else beginpcie_rst_sync <= {pcie_rst_sync[0], system_reset_n}; // 同步system_reset_npcie_reset_n <= pcie_rst_sync[1];endend// ======================// DDR3复位同步 (ddr3_user_clk域)// ======================reg [1:0] ddr3_rst_sync;always @(posedge ddr3_user_clk or negedge sys_rst_n) beginif (!sys_rst_n || !pll_locked) beginddr3_rst_sync <= 2'b00;ddr3_reset_n <= 1'b0;end else beginddr3_rst_sync <= {ddr3_rst_sync[0], system_reset_n}; // 同步system_reset_nddr3_reset_n <= ddr3_rst_sync[1];endend// ======================// 调试LED控制逻辑// ======================always @(*) begindebug_leds = {error_flag, // 最高位: 错误标志3'b000, // 中间3位: 保留system_state[3:0] // 低4位: 系统状态编码};endendmodule
关键问题
1. 复位优先级管理
- 最高优先级:全局复位
sys_rst_n
和 PLL 锁定状态pll_locked
。 - 次优先级:模块级复位(如 PCIe 物理层复位
pcie_perst_n
)。
2. 复位释放顺序
1. 全局复位 sys_rst_n 释放
2. PLL锁定 pll_locked 有效
3. 计数器延时后释放 system_reset_n
4. 同步释放 pcie_reset_n 和 ddr3_reset_n
3.调试 LED 输出
将系统状态(system_state
)和错误标志(error_flag
)编码到 LED 输出,便于硬件调试。
3. PCIe 端点模块 (pcie_endpoint
)
- 核心功能:
- 实现 PCIe Gen2 x4 物理层和链路层,处理差分信号收发。
- 解析 PCIe 事务层包(TLP),支持 MMIO 读写,与主机通信。
- 完成 PCIe 链路训练,输出初始化完成标志
pcie_init_done
。 - 该模块负责处理 PCIe 接口的数据传输和配置,以及与外部设备进行通信。
- 关键接口:
- 物理层:差分信号
pcie_rx_p/n
、pcie_tx_p/n
。 - 控制层:MMIO 读写信号、地址和数据总线。
- 物理层:差分信号
代码展示
// Artix-7 PCIe Gen2 x4端点模块
module pcie_endpoint_acx750 (// 物理层接口input pcie_refclk_p, // 参考时钟正极性input pcie_refclk_n, // 参考时钟负极性input [3:0] pcie_rx_p, // 接收通道正极性 (x4)input [3:0] pcie_rx_n, // 接收通道负极性 (x4)output [3:0] pcie_tx_p, // 发送通道正极性 (x4)output [3:0] pcie_tx_n, // 发送通道负极性 (x4)// 时钟与复位output user_clk, // 用户时钟输出input reset_n, // 系统复位 (低有效)// 数据通道接口output [127:0] rx_data, // 接收数据 (128位)output [15:0] rx_be, // 接收字节使能 (16位,每字节1位)output rx_valid, // 接收数据有效input rx_ready, // 接收准备好input [127:0] tx_data, // 发送数据 (128位)input [15:0] tx_be, // 发送字节使能input tx_valid, // 发送数据有效output tx_ready, // 发送准备好// MMIO接口output mmio_rd, // MMIO读使能output mmio_wr, // MMIO写使能output [31:0] mmio_addr, // MMIO地址output [127:0] mmio_wdata, // MMIO写数据input [127:0] mmio_rdata, // MMIO读数据output mmio_rvalid, // MMIO读数据有效// 配置空间参数input [15:0] device_id, // 设备IDinput [15:0] vendor_id, // 供应商IDinput [15:0] subsystem_id, // 子系统IDinput [15:0] subsystem_vendor_id, // 子系统供应商ID// PCIe初始化完成标志output reg pcie_init_done // PCIe初始化完成 (高有效)
);// 参数定义:PCIe基地址寄存器(BAR)大小parameter BAR0_SIZE = 16'h1000; // 4KBparameter BAR1_SIZE = 16'h4000; // 16KB// 内部信号wire pcie_clk; // PCIe时钟wire pcie_rst_n; // PCIe复位 (低有效)wire [63:0] cfg_dw0, cfg_dw1, cfg_dw2, cfg_dw3; // 配置空间数据字// PCIe状态监控信号wire [7:0] pcie_status; // PCIe状态寄存器wire link_up; // 链路建立标志 (高有效)wire dll_up; // 数据链路层锁定标志 (高有效)wire [7:0] ltssm_state; // 链路训练状态机状态// 初始化状态机reg [2:0] init_state;localparam INIT_RESET = 3'b000, // 复位状态INIT_WAIT_LT = 3'b001, // 等待链路训练INIT_WAIT_DLL = 3'b010, // 等待数据链路层INIT_WAIT_L0 = 3'b011, // 等待进入L0状态INIT_COMPLETE = 3'b100; // 初始化完成// 初始化超时计数器reg [15:0] init_counter;parameter INIT_TIMEOUT = 16'hFFFF; // 初始化超时值// 错误标志reg init_error;// PCIe IP核例化 (Xilinx Artix-7 PCIe Gen2 x4)pcie_7x_0 u_pcie_ip (// 参考时钟和复位.pcie_clk_in_p(pcie_refclk_p),.pcie_clk_in_n(pcie_refclk_n),.reset(~reset_n), // 注意:IP核复位为高有效// 收发器接口.rxn(pcie_rx_n),.rxp(pcie_rx_p),.txn(pcie_tx_n),.txp(pcie_tx_p),// 用户时钟和复位.userclk_out(user_clk),.userclk2_out(), // 未使用.pclk_out(), // 未使用// 配置空间.cfg_dw0(cfg_dw0),.cfg_dw1(cfg_dw1),.cfg_dw2(cfg_dw2),.cfg_dw3(cfg_dw3),// 数据通道.rxdata(rx_data),.rxbe(rx_be),.rxvalid(rx_valid),.rxready(rx_ready),.txdata(tx_data),.txbe(tx_be),.txvalid(tx_valid),.txready(tx_ready),// 配置读写.cfg_mrdreq(), // 未使用.cfg_mwrreq(), // 未使用.cfg_srdack(), // 未使用.cfg_swrack(), // 未使用.cfg_rd(), // 未使用.cfg_wr(), // 未使用.cfg_addr(), // 未使用.cfg_data_in(), // 未使用.cfg_data_out(), // 未使用// 中断.intr(), // 未使用.msi_intr(), // 未使用.msix_intr(), // 未使用// 连接状态信号.pcie_status(pcie_status),.link_up(link_up),.dll_up(dll_up),.ltssm_state(ltssm_state));// 配置空间初始化// cfg_dw0: Vendor ID + Device IDassign cfg_dw0 = {vendor_id, device_id, 16'h0000};// cfg_dw1: Class Code + Header Type + Revision IDassign cfg_dw1 = {16'h0000, 16'h0000, 8'h06, 8'h04, 8'h00}; // 设备类代码: PCIe桥// cfg_dw2: Subsystem Vendor ID + Subsystem IDassign cfg_dw2 = {subsystem_vendor_id, subsystem_id, 32'h00000000};// cfg_dw3: 保留assign cfg_dw3 = 64'h0000000000000000;// MMIO接口控制器例化mmio_controller u_mmio_controller (.clk(user_clk),.reset_n(reset_n),.rx_data(rx_data),.rx_be(rx_be),.rx_valid(rx_valid),.rx_ready(rx_ready),.tx_data(tx_data),.tx_be(tx_be),.tx_valid(tx_valid),.tx_ready(tx_ready),.mmio_rd(mmio_rd),.mmio_wr(mmio_wr),.mmio_addr(mmio_addr),.mmio_wdata(mmio_wdata),.mmio_rdata(mmio_rdata),.mmio_rvalid(mmio_rvalid));// PCIe初始化状态机always @(posedge user_clk or negedge reset_n) beginif (!reset_n) begininit_state <= INIT_RESET;init_counter <= 16'h0000;pcie_init_done <= 1'b0;init_error <= 1'b0;end else begincase (init_state)INIT_RESET: begin// 复位状态:等待复位释放if (reset_n) begininit_state <= INIT_WAIT_LT;endendINIT_WAIT_LT: begin// 等待链路训练开始if (link_up) begininit_state <= INIT_WAIT_DLL;end else if (init_counter >= INIT_TIMEOUT) begininit_state <= INIT_RESET;init_error <= 1'b1;end else begininit_counter <= init_counter + 1'b1;endendINIT_WAIT_DLL: begin// 等待数据链路层锁定if (dll_up) begininit_state <= INIT_WAIT_L0;end else if (init_counter >= INIT_TIMEOUT) begininit_state <= INIT_RESET;init_error <= 1'b1;end else begininit_counter <= init_counter + 1'b1;endendINIT_WAIT_L0: begin// 等待进入L0工作状态if (ltssm_state == 8'h0F) begin // L0状态init_state <= INIT_COMPLETE;pcie_init_done <= 1'b1;end else if (init_counter >= INIT_TIMEOUT) begininit_state <= INIT_RESET;init_error <= 1'b1;end else begininit_counter <= init_counter + 1'b1;endendINIT_COMPLETE: begin// 初始化完成,保持状态if (!link_up || !dll_up || ltssm_state != 8'h0F) begin// 如果链路断开,回到等待状态init_state <= INIT_WAIT_LT;pcie_init_done <= 1'b0;endenddefault: init_state <= INIT_RESET;endcaseendendendmodule
关键问题
1.初始化状态机
// 初始化状态机
reg [2:0] init_state;
localparam INIT_RESET = 3'b000, // 复位状态INIT_WAIT_LT = 3'b001, // 等待链路训练INIT_WAIT_DLL = 3'b010, // 等待数据链路层INIT_WAIT_L0 = 3'b011, // 等待进入L0状态INIT_COMPLETE = 3'b100; // 初始化完成
- 功能:按阶段监控 PCIe 初始化过程,确保各步骤按序完成。
4. MMIO 控制器模块 (mmio_controller
)
- 核心功能:
- 解析主机通过 PCIe 发送的 MMIO 命令,实现寄存器映射。
- 配置 DMA 参数(源地址、目标地址、传输长度),生成采集启动和错误清除命令。
- 就是将PCIe的数据直接给外部
- 关键接口:
- 输入:PCIe MMIO 信号(读写命令、地址、数据)。
- 输出:DMA 参数、采集启动信号、错误清除信号。
首先需要了解什么是MMIO?
MMIO(Memory-Mapped I/O,内存映射输入输出) 是一种计算机系统中用于外设通信的技术,它将硬件设备的寄存器映射到内存地址空间,使得 CPU 可以像访问内存一样直接读写这些寄存器,从而控制外设或获取外设状态。
核心概念
-
地址映射
- 将外设的控制寄存器、状态寄存器等映射到系统内存地址空间的特定区域。
- CPU 无需使用特殊的 I/O 指令(如 x86 的
IN/OUT
指令),而是通过普通的内存访问指令(如LOAD/STORE
)与外设交互。
-
统一寻址
- 内存和外设共享同一地址空间,简化了编程模型。
- 例如,向地址
0x4000_0000
写入数据可能是控制网卡,而读取0x4000_0004
可能获取其状态。
代码展示
// MMIO控制器模块
module mmio_controller (input clk, // 用户时钟 (125MHz)input reset_n, // 复位信号// PCIe数据通道input [127:0] rx_data, // 接收数据input [15:0] rx_be, // 接收字节使能input rx_valid, // 接收数据有效output rx_ready, // 接收准备好output [127:0] tx_data, // 发送数据output [15:0] tx_be, // 发送字节使能output tx_valid, // 发送数据有效input tx_ready, // 发送准备好// MMIO接口output mmio_rd, // MMIO读使能output mmio_wr, // MMIO写使能output [31:0] mmio_addr, // MMIO地址output [127:0] mmio_wdata, // MMIO写数据input [127:0] mmio_rdata, // MMIO读数据output mmio_rvalid // MMIO读有效
);// MMIO寄存器映射(示例:假设BAR0基地址0x0000_0000,BAR1基地址0x1000_0000)
//定义设备内部资源的实际起始地址,用于地址解码。
parameter BAR0_BASE = 32'h00000000;
parameter BAR1_BASE = 32'h10000000;// 内部信号
reg [31:0] mmio_addr_reg;
reg mmio_rd_reg, mmio_wr_reg;
reg [127:0] mmio_wdata_reg;
reg [127:0] tx_data_reg;
reg [15:0] tx_be_reg;
reg tx_valid_reg;// 地址解码(解析32位MMIO地址)
assign mmio_addr = mmio_addr_reg;
assign mmio_rd = mmio_rd_reg;
assign mmio_wr = mmio_wr_reg;
assign mmio_wdata = mmio_wdata_reg;// PCIe接收处理(解析TLP包中的MMIO请求)
assign rx_ready = 1'b1; // 简化设计,假设始终准备好接收always @(posedge clk or negedge reset_n) beginif (!reset_n) beginmmio_addr_reg <= 0;mmio_rd_reg <= 0;mmio_wr_reg <= 0;mmio_wdata_reg <= 0;end else if (rx_valid) begin// 解析PCIe接收数据中的MMIO地址和命令(简化示例)mmio_addr_reg <= rx_data[31:0]; // 假设前32位为地址mmio_wdata_reg <= rx_data[127:32]; // 后96位为写数据(假设32位寄存器访问)mmio_rd_reg <= rx_data[128]; // 假设第128位为读命令mmio_wr_reg <= rx_data[129]; // 假设第129位为写命令end
end// PCIe发送处理(封装MMIO响应数据)
assign tx_data = {mmio_rdata, mmio_addr_reg}; // 读响应包含数据和地址
assign tx_be = tx_be_reg;
assign tx_valid = tx_valid_reg;// 读有效信号(假设读操作后一个周期有效)
assign mmio_rvalid = tx_valid;endmodule
5. 数据采集模块 (data_acquisition
)
- 核心功能:
- 采集双通道 12 位 ADC 数据,打包为 256 位数据块(16 个采样点 / 块)。
- 管理 2048 深度缓冲区,提供状态标志(缓冲区满 / 空、采集完成、错误)。
- 关键接口:
- 输入:ADC 数据、有效标志、启动信号、复位信号。
- 输出:打包后的数据、缓冲区状态、采集完成 / 错误标志。
代码展示
//数据采集模块
module data_acquisition (input adc_clk, // ADC时钟 (40MHz),双通道采集input [11:0] adc_data_ch0, // 通道0数据input [11:0] adc_data_ch1, // 通道1数据input adc_valid, // ADC数据有效标志input user_clk, // 用户时钟 (125MHz)input reset_n,input start_acq, // 开始采集标志位output acq_in_progress,//指示系统目前是否处于采集过程状态output acq_complete,//标志着系统一次完整的数据采集过程已完成output reg [255:0] data_out,output reg data_valid,//指示 data_out 中的数据有效,作为数据输出的握手信号input data_ready,//由外部模块发送的就绪信号,表示已准备好接收 data_out,与 data_valid 配合实现握手机制output reg [31:0] data_count,//记录已经输出的数据块总量(每成功打包256个数据形成一个数据块并输出就加一),用于之后的数据块索引output buffer_full,//用于指示内部缓冲区即将填满,防止溢出output buffer_empty//指示内部缓冲区已为空,防止无效数据读取
);// 状态机
localparam IDLE = 3'd0,//空闲状态,等待开始采集ACQUIRING = 3'd1,//正在采集数据状态PACKING = 3'd2,//打包数据状态READY = 3'd3,//数据打包完成,等待外界形成握手信号用于可以被读取COMPLETE = 3'd4;//表示整个过程完成reg [2:0] state, next_state;
reg [15:0] adc_buffer [0:2047]; // 双通道数据缓冲区 (可容纳2048个采样点),用于存储ADC数据
reg [15:0] buffer_wptr;//写指针
reg [15:0] buffer_rptr;//读指针
reg buffer_full_int;
reg buffer_empty_int;// 跨时钟域同步
reg start_acq_sync1, start_acq_sync2;
reg adc_valid_sync1, adc_valid_sync2;
reg [11:0] adc_data_ch0_sync;
reg [11:0] adc_data_ch1_sync;// 同步控制信号到ADC时钟域,使用两级触发器同步 (sync1, sync2) 防止亚稳态
//将 start_acq 信号从 user_clk 同步到 adc_clk 域
always @(posedge adc_clk or negedge reset_n) beginif (!reset_n) beginstart_acq_sync1 <= 0;start_acq_sync2 <= 0;end else beginstart_acq_sync1 <= start_acq;start_acq_sync2 <= start_acq_sync1;end
end// 同步ADC数据到用户时钟域
//将 ADC 数据和有效信号从 adc_clk 同步到 user_clk 域
always @(posedge user_clk or negedge reset_n) beginif (!reset_n) beginadc_valid_sync1 <= 0;adc_valid_sync2 <= 0;adc_data_ch0_sync <= 0;adc_data_ch1_sync <= 0;end else beginadc_valid_sync1 <= adc_valid;adc_valid_sync2 <= adc_valid_sync1;adc_data_ch0_sync <= adc_data_ch0;adc_data_ch1_sync <= adc_data_ch1;end
end// 状态机寄存器
always @(posedge user_clk or negedge reset_n) beginif (!reset_n) beginstate <= IDLE;buffer_wptr <= 0;buffer_rptr <= 0;data_count <= 0;data_valid <= 0;end else beginstate <= next_state;case (state)IDLE: begin//IDLE 状态:等待 start_acq_sync2 信号,初始化指针和计数器if (start_acq_sync2) beginbuffer_wptr <= 0;buffer_rptr <= 0;data_count <= 0;endendACQUIRING: beginif (adc_valid_sync2 && buffer_wptr < 2046) begin// 存储双通道ADC数据,将两个通道的数据交替存入缓冲区,每次写入后写指针加 2adc_buffer[buffer_wptr] <= adc_data_ch0_sync;adc_buffer[buffer_wptr+1] <= adc_data_ch1_sync;buffer_wptr <= buffer_wptr + 2;endendPACKING: begin// 打包数据到256位输出 (16个采样点: 8对双通道数据),读指针加 16data_out <= {adc_buffer[buffer_rptr+15],adc_buffer[buffer_rptr+14],adc_buffer[buffer_rptr+13],adc_buffer[buffer_rptr+12],adc_buffer[buffer_rptr+11],adc_buffer[buffer_rptr+10],adc_buffer[buffer_rptr+9],adc_buffer[buffer_rptr+8],adc_buffer[buffer_rptr+7],adc_buffer[buffer_rptr+6],adc_buffer[buffer_rptr+5],adc_buffer[buffer_rptr+4],adc_buffer[buffer_rptr+3],adc_buffer[buffer_rptr+2],adc_buffer[buffer_rptr+1],adc_buffer[buffer_rptr]};buffer_rptr <= buffer_rptr + 16;data_valid <= 1;data_count <= data_count + 1;endREADY: beginif (data_ready)//等待 data_ready 信号握手data_valid <= 0;endendcaseend
end// 状态机逻辑,定义状态转移条件
always @(*) beginnext_state = state;case (state)IDLE: beginif (start_acq_sync2)next_state = ACQUIRING;endACQUIRING: beginif (buffer_wptr >= 2046)next_state = PACKING;endPACKING: beginnext_state = READY;endREADY: begin//数据被读取后,若缓冲区还有数据则继续打包,若缓冲区已空则标记完成if (data_ready && buffer_rptr >= 2046)next_state = COMPLETE;else if (data_ready)next_state = PACKING;endCOMPLETE: beginif (!start_acq_sync2)next_state = IDLE;endendcase
end// 缓冲区状态
assign buffer_full = buffer_full_int;
assign buffer_empty = buffer_empty_int;always @(posedge user_clk or negedge reset_n) beginif (!reset_n) beginbuffer_full_int <= 0;buffer_empty_int <= 1;end else beginbuffer_full_int <= (buffer_wptr >= 2046);buffer_empty_int <= (buffer_rptr >= buffer_wptr);end
endassign acq_in_progress = (state == ACQUIRING);
assign acq_complete = (state == COMPLETE);endmodule
6. DDR3 控制器模块 (ddr3_controller
)
- 核心功能:
- 封装 Xilinx MIG IP 核,控制 DDR3 存储器的初始化、校准和数据读写。
- 提供用户接口与 DMA 引擎对接,支持 256 位突发传输。
- 关键接口:
- 用户接口:数据 / 地址总线、突发长度、读写使能。
- 物理接口:DDR3 地址 / 控制 / 数据总线(差分时钟、数据选通等)。
这个模块是基于 Xilinx MIG (Memory Interface Generator) IP 核的 DDR3 控制器实现,用于在 FPGA 和 DDR3 存储器之间建立高速数据通道。
MIG (Memory Interface Generator) 是 Xilinx 提供的一个关键 IP 核,用于为其 FPGA 产品生成针对特定存储器的控制器和物理接口。它支持多种存储器类型(如 DDR3、DDR4、LPDDR3/4 等),并自动处理复杂的时序和协议,让开发者无需深入了解底层存储器细节即可实现高速数据传输。
主要功能包括:
- 自动生成符合 JEDEC 标准的存储器控制器
- 实现高速数据通路(支持高达 3200Mbps 的数据率)
- 处理初始化、校准、刷新等复杂操作
- 提供用户友好的抽象接口(如 AXI4、Native 接口)
- 优化时序以满足特定 FPGA 和存储器组合的要求
在该模块中创建了命令转换逻辑,实现了用户接口和 MIG IP 核之间的信号转换:
assign app_clk = ui_clk; // 应用层时钟等于用户接口时钟
assign app_rst_n = !ui_clk_sync_rst && init_calib_complete;assign app_addr = addr;// 用户地址直接映射到应用层地址
assign app_cmd = write_en ? 3'b000 : 3'b001; // 000=写, 001=读
assign app_en = req_valid && app_rdy;
assign app_wdf_data = wdata;// 用户写数据映射到写数据FIFO
assign app_wdf_end = app_en && write_en;
assign app_wdf_wren = app_en && write_en;assign req_ready = app_rdy;// 控制器就绪状态反馈
assign rdata = app_rd_data;// 读取数据输出
assign rdata_valid = app_rd_data_valid;
-
时钟和复位处理:
- 使用 MIG 提供的用户接口时钟
ui_clk
- 复位条件结合了同步复位信号和初始化校准完成标志
- 使用 MIG 提供的用户接口时钟
-
读写命令处理:
- 根据
write_en
和read_en
生成对应的命令编码 - 只有当控制器就绪 (
app_rdy
) 且用户请求有效 (req_valid
) 时才发出命令
- 根据
-
写数据处理:
- 将用户提供的 256 位写数据
wdata
直接传递给 MIG - 生成写数据 FIFO 的控制信号
- 将用户提供的 256 位写数据
-
读数据处理:
- 将 MIG 返回的读数据
app_rd_data
传递给用户 - 同步读数据有效标志
app_rd_data_valid
- 将 MIG 返回的读数据
代码展示
// ACX750 DDR3控制器模块 (基于Xilinx MIG 7 Series)
//这个模块定义了三类接口:
//用户逻辑接口:包括时钟、复位、数据、地址和控制信号
//状态反馈接口:指示数据有效性和控制器状态
//物理 DDR3 接口:连接到实际 DDR3 芯片的电气信号
module ddr3_controller_acx750 (input user_clk,input reset_n,input [255:0] wdata,//写入DDR3的数据,256位output [255:0] rdata,//从DDR3中读取的数据,256位input [31:0] addr,//读写地址input [31:0] burst_len,//突发传输长度input write_en,input read_en,input req_valid,//请求有效信号output req_ready,//控制器就绪信号output rdata_valid,//读取数据有效信号// 物理接口output [13:0] ddr3_addr,//DD3地址线output [2:0] ddr3_ba,// DDR3存储体地址output ddr3_ras_n, // 行地址选通信号(低电平有效)output ddr3_cas_n,// 列地址选通信号(低电平有效)output ddr3_we_n,// 写使能信号(低电平有效)output [0:0] ddr3_ck_p,// DDR3时钟(正极性)output [0:0] ddr3_ck_n,// DDR3时钟(负极性)output [0:0] ddr3_cke,// DDR3时钟使能output [0:0] ddr3_odt,// DDR3片上终端匹配output [3:0] ddr3_dm,// DDR3数据掩码inout [31:0] ddr3_dq,// DDR3数据总线inout [3:0] ddr3_dqs_p,// DDR3数据选通(正极性)inout [3:0] ddr3_dqs_n // DDR3数据选通(负极性)
);// 内部信号,用于连接用户逻辑和 MIG IP 核,包括时钟、复位、数据、地址和控制信号。
wire app_clk;
wire app_rst_n;
wire [255:0] app_wdf_data; // 写数据FIFO数据
wire app_wdf_end; // 写数据FIFO结束指示
wire app_wdf_wren;
wire [31:0] app_addr;
wire [2:0] app_cmd;// 应用层命令(000=写,001=读)
wire app_en;
wire app_rdy;// 应用层就绪
wire [255:0] app_rd_data;// 读数据
wire app_rd_data_valid;
wire app_rd_data_end;
wire ui_clk; // 用户接口时钟
wire ui_clk_sync_rst;// 用户接口同步复位
wire init_calib_complete;// 初始化校准完成标志// MIG 7 Series IP核例化
mig_7series_0 u_mig (// 时钟和复位.sys_clk_i(user_clk),.sys_rst_n(reset_n),// 用户接口.app_addr(app_addr),.app_cmd(app_cmd),.app_en(app_en),.app_wdf_data(app_wdf_data),.app_wdf_end(app_wdf_end),.app_wdf_wren(app_wdf_wren),.app_rd_data(app_rd_data),.app_rd_data_valid(app_rd_data_valid),.app_rd_data_end(app_rd_data_end),.app_rdy(app_rdy),.app_wdf_rdy(),.app_sr_req(),.app_ref_req(),.app_zq_req(),.app_sr_active(),.app_ref_ack(),.app_zq_ack(),.ui_clk(ui_clk),.ui_clk_sync_rst(ui_clk_sync_rst),.init_calib_complete(init_calib_complete),// DDR3物理接口.ddr3_addr(ddr3_addr),.ddr3_ba(ddr3_ba),.ddr3_cas_n(ddr3_cas_n),.ddr3_ck_n(ddr3_ck_n),.ddr3_ck_p(ddr3_ck_p),.ddr3_cke(ddr3_cke),.ddr3_ras_n(ddr3_ras_n),.ddr3_we_n(ddr3_we_n),.ddr3_dq(ddr3_dq),.ddr3_dqs_n(ddr3_dqs_n),.ddr3_dqs_p(ddr3_dqs_p),.ddr3_odt(ddr3_odt),.ddr3_dm(ddr3_dm),// 其他信号.device_temp(),.sys_clk_eb(),.user_clk(),.user_rst(),.calib_done()
);// 命令转换逻辑
assign app_clk = ui_clk; // 应用层时钟等于用户接口时钟
assign app_rst_n = !ui_clk_sync_rst && init_calib_complete;assign app_addr = addr;// 用户地址直接映射到应用层地址
assign app_cmd = write_en ? 3'b000 : 3'b001; // 000=写, 001=读
assign app_en = req_valid && app_rdy;
assign app_wdf_data = wdata;// 用户写数据映射到写数据FIFO
assign app_wdf_end = app_en && write_en;
assign app_wdf_wren = app_en && write_en;assign req_ready = app_rdy;// 控制器就绪状态反馈
assign rdata = app_rd_data;// 读取数据输出
assign rdata_valid = app_rd_data_valid;endmodule
这个 DDR3 控制器模块通过 Xilinx MIG IP 核实现了 FPGA 与 DDR3 存储器之间的高速接口。主要特点包括:
- 用户友好的抽象接口:提供简单的读写命令、地址和数据接口
- 复杂时序自动处理:MIG 负责处理 DDR3 的所有低级时序要求
- 突发传输支持:通过
burst_len
参数支持高效的批量数据传输 - 多时钟域管理:正确处理不同时钟域之间的同步问题
- 初始化和校准:自动执行 DDR3 的初始化和校准流程
使用这个模块时,用户只需关注高层的读写操作,而无需关心 DDR3 的底层时序细节,大大简化了高速存储器系统的设计。
7. 高级 DMA 引擎 (dma_engine
)
- 核心功能:
- 实现高速数据传输,将采集模块的缓冲区数据搬移到 DDR3。
- 支持突发传输模式,优化带宽利用率,提供传输完成和错误标志。
- 关键接口:
- 输入:启动信号、传输参数(地址、长度、突发大小)。
- 数据通路:连接采集模块输出和 DDR3 控制器输入。
代码展示
//DMA控制模块
module advanced_dma (input clk,input reset_n,input start_dma,//控制信号,启动DMA传输input [31:0] src_addr,//源地址input [31:0] dest_addr,//目标地址input [31:0] transfer_len,//传输长度input [7:0] burst_size, // 突发配置,2^n 字节突发长度,它表示每次突发传输的数据块数量最大为8input [255:0] data_in,//256 位(32 字节),因此每次传输的数据块大小为 32 字节。input data_in_valid,output data_in_ready,//下列为DDR3状态接口output reg [255:0] ddr3_wdata,output reg [31:0] ddr3_addr,output reg [31:0] ddr3_burst_len,output reg ddr3_write_en,output reg ddr3_req_valid,input ddr3_req_ready,output reg dma_done,output reg dma_error
);// DMA状态机
localparam IDLE = 4'd0,//IDLE: 空闲状态,等待启动命令CONFIGURE = 4'd1,//配置DMA参数WAIT_DATA = 4'd2,//等待有效数据输入BURST_START = 4'd3,//开始突发传输BURST_TRANSFER = 4'd4,//进行突发传输BURST_END = 4'd5,//结束突发传输COMPLETE = 4'd6,//传输完成状态ERROR = 4'd7;//错误状态reg [3:0] state, next_state;
reg [31:0] bytes_transferred;//记录已传输字节数
reg [31:0] current_addr;//指向当前的传输位置
reg [31:0] ddr3_start_addr; // 记录当前突发的起始地址
reg [7:0] burst_count;//定义突发剩余数据块计数器
reg dma_active;//指示DMA是否处于活跃状态// 状态机寄存器
always @(posedge clk or negedge reset_n) beginif (!reset_n) beginstate <= IDLE;bytes_transferred <= 0;current_addr <= 0;burst_count <= 0;dma_active <= 0;dma_done <= 0;dma_error <= 0;end else beginstate <= next_state;case (state)IDLE: beginif (start_dma) begincurrent_addr <= dest_addr;//将当前传输位置指向目标地址bytes_transferred <= 0;dma_active <= 1;dma_done <= 0;dma_error <= 0;endendCONFIGURE: begin// 配置突发长度ddr3_burst_len <= burst_size;endBURST_START: beginif (ddr3_req_ready) beginddr3_start_addr <= current_addr; // 记录当前突发的起始地址burst_count <= burst_size;current_addr <= current_addr + (burst_size * 32); // 256位 = 32字节//bytes_transferred <= bytes_transferred + (burst_size * 32);endendBURST_TRANSFER: begin//处理单个数据块if (ddr3_req_ready && burst_count > 0) beginburst_count <= burst_count - 1;//每完成一个 256 位数据块传输,突发计数器减 1//current_addr <= current_addr + 32; // 256位 = 32字节bytes_transferred <= bytes_transferred + 32;//在此处累加已传输字节数endendCOMPLETE: begindma_active <= 0;dma_done <= 1;endERROR: begindma_active <= 0;dma_error <= 1;endendcaseend
end// 状态机逻辑
always @(*) beginnext_state = state;case (state)IDLE: beginif (start_dma)next_state = CONFIGURE;endCONFIGURE: beginnext_state = WAIT_DATA;endWAIT_DATA: beginif (data_in_valid)next_state = BURST_START;endBURST_START: beginif (ddr3_req_ready)next_state = BURST_TRANSFER;endBURST_TRANSFER: beginif (ddr3_req_ready && burst_count == 0) beginif (bytes_transferred >= transfer_len)//当实际的传输字节数到达传输长度时next_state = COMPLETE;elsenext_state = WAIT_DATA;endendCOMPLETE: beginif (!start_dma)next_state = IDLE;endERROR: beginif (!start_dma)next_state = IDLE;enddefault: next_state = IDLE;endcase
end// DDR3接口控制
always @(posedge clk or negedge reset_n) beginif (!reset_n) beginddr3_wdata <= 0;ddr3_addr <= 0;ddr3_write_en <= 0;ddr3_req_valid <= 0;end else begincase (state)BURST_START: beginddr3_wdata <= data_in;ddr3_addr <= ddr3_start_addr; // 使用记录的突发起始地址ddr3_write_en <= 1;ddr3_req_valid <= 1;endBURST_TRANSFER: beginddr3_wdata <= data_in;// 注意:DDR3控制器会自动递增地址,此处无需更新ddr3_addrddr3_write_en <= 1;ddr3_req_valid <= 1;enddefault: beginddr3_wdata <= 0;ddr3_addr <= 0;ddr3_write_en <= 0;ddr3_req_valid <= 0;endendcaseend
end// 数据输入控制
assign data_in_ready = (state == WAIT_DATA || (state == BURST_TRANSFER && burst_count > 0)) && !dma_error;// 错误检测
always @(posedge clk or negedge reset_n) beginif (!reset_n) begindma_error <= 0;end else beginif (bytes_transferred > transfer_len)dma_error <= 1;else if (state == ERROR)dma_error <= 1;end
endendmodule
8. 顶层模块(包含系统状态机)
- 核心功能:
- 协调全系统流程,控制状态转换(初始化→等待触发→采集→DMA→错误处理)。
- 监控硬件初始化状态,触发采集和 DMA,处理错误恢复。
-
状态机状态转换
- SYS_IDLE:等待系统复位释放(
system_reset_n
有效)。 - SYS_INIT:等待
pll_locked
(时钟稳定)、ddr3_init_done
(DDR3 初始化完成)、pcie_init_done
(PCIe 链路完成)。 - SYS_WAIT_TRIG:监听主机通过 MMIO 发送的
mmio_start_acq
或外部触发信号。 - SYS_ACQUIRING:启动数据采集模块,填充缓冲区,采集完成后进入 DMA 传输。
- SYS_DMA_XFER:DMA 引擎将缓冲区数据写入 DDR3,完成后返回等待触发。
- SYS_ERROR:处理采集或 DMA 错误,通过 MMIO 或复位清除错误。
代码展示
module system_top (// 系统时钟和复位input sys_clk, // 系统主时钟 (100MHz)input sys_rst_n, // 系统复位 (低有效)// PCIe接口input pcie_refclk_p, // PCIe参考时钟正极input pcie_refclk_n, // PCIe参考时钟负极input [3:0] pcie_rx_p, // PCIe接收通道正极input [3:0] pcie_rx_n, // PCIe接收通道负极output [3:0] pcie_tx_p, // PCIe发送通道正极output [3:0] pcie_tx_n, // PCIe发送通道负极// ADC接口input [11:0] adc_data_ch0, // ADC通道0数据input [11:0] adc_data_ch1, // ADC通道1数据input adc_valid, // ADC数据有效output adc_reset_n, // ADC复位 (低有效)// DDR3物理接口output [13:0] ddr3_addr, // DDR3地址总线output [2:0] ddr3_ba, // DDR3存储体地址output ddr3_ras_n, // 行地址选通 (低有效)output ddr3_cas_n, // 列地址选通 (低有效)output ddr3_we_n, // 写使能 (低有效)output [0:0] ddr3_ck_p, // DDR3时钟正极output [0:0] ddr3_ck_n, // DDR3时钟负极output [0:0] ddr3_cke, // 时钟使能output [0:0] ddr3_odt, // 片上终端output [3:0] ddr3_dm, // 数据掩码inout [31:0] ddr3_dq, // 数据总线inout [3:0] ddr3_dqs_p, // 数据选通正极inout [3:0] ddr3_dqs_n, // 数据选通负极// 调试输出output [7:0] debug_leds // 调试LED
);// ---------------------// 状态机定义// ---------------------localparam SYS_IDLE = 4'd0, // 等待复位释放SYS_INIT = 4'd1, // 等待初始化完成SYS_WAIT_TRIG = 4'd2, // 等待触发SYS_ACQUIRING = 4'd3, // 数据采集SYS_DMA_XFER = 4'd4, // DMA传输SYS_ERROR = 4'd5; // 错误处理reg [3:0] system_state;reg error_flag;reg start_acq; // 采集启动信号reg start_dma; // DMA启动信号reg [31:0] dma_src_addr; // DMA源地址(采集缓冲区)reg [31:0] dma_dest_addr;// DMA目标地址(DDR3)reg [31:0] dma_len; // DMA传输长度reg [7:0] dma_burst; // DMA突发大小// ---------------------// 模块实例化// ---------------------// 1. 时钟管理模块wire pcie_user_clk;wire ddr3_user_clk;wire pll_locked;clock_manager u_clock_mgr (.sys_clk (sys_clk),.pcie_refclk_p (pcie_refclk_p),.pcie_refclk_n (pcie_refclk_n),.pcie_user_clk (pcie_user_clk),.ddr3_user_clk (ddr3_user_clk),.pll_locked (pll_locked));// 2. 系统控制模块wire pcie_reset_n;wire system_reset_n;wire ddr3_reset_n;system_control u_sys_ctrl (.sys_clk (sys_clk),.pcie_user_clk (pcie_user_clk),.ddr3_user_clk (ddr3_user_clk),.pcie_perst_n (1'b1), // 假设无PCIe永久复位,实际需连接硬件.sys_rst_n (sys_rst_n),.pll_locked (pll_locked),.init_calib_complete(ddr3_init_done), // DDR3初始化完成.pcie_init_done (pcie_init_done), // PCIe初始化完成.system_state (system_state),.error_flag (error_flag),.pcie_reset_n (pcie_reset_n),.system_reset_n (system_reset_n),.ddr3_reset_n (ddr3_reset_n),.debug_leds (debug_leds));// 3. PCIe端点模块wire user_clk;wire [127:0] pcie_rx_data;wire [15:0] pcie_rx_be;wire pcie_rx_valid;wire pcie_rx_ready;wire [127:0] pcie_tx_data;wire [15:0] pcie_tx_be;wire pcie_tx_valid;wire pcie_tx_ready;wire mmio_rd;wire mmio_wr;wire [31:0] mmio_addr;wire [127:0] mmio_wdata;wire [127:0] mmio_rdata;wire mmio_rvalid;wire pcie_init_done;pcie_endpoint_acx750 u_pcie_ep (.pcie_refclk_p (pcie_refclk_p),.pcie_refclk_n (pcie_refclk_n),.pcie_rx_p (pcie_rx_p),.pcie_rx_n (pcie_rx_n),.pcie_tx_p (pcie_tx_p),.pcie_tx_n (pcie_tx_n),.user_clk (user_clk),.reset_n (system_reset_n), // 系统控制模块的同步复位.rx_data (pcie_rx_data),.rx_be (pcie_rx_be),.rx_valid (pcie_rx_valid),.rx_ready (pcie_rx_ready),.tx_data (pcie_tx_data),.tx_be (pcie_tx_be),.tx_valid (pcie_tx_valid),.tx_ready (pcie_tx_ready),.mmio_rd (mmio_rd),.mmio_wr (mmio_wr),.mmio_addr (mmio_addr),.mmio_wdata (mmio_wdata),.mmio_rdata (mmio_rdata),.mmio_rvalid (mmio_rvalid),.device_id (16'hABCD), // 示例设备ID.vendor_id (16'h10EE), // 示例供应商ID.subsystem_id (16'h0001),.subsystem_vendor_id(16'h10EE),.pcie_init_done (pcie_init_done));// 4. MMIO控制器模块wire mmio_start_acq;wire mmio_clear_error;mmio_controller u_mmio_ctrl (.clk (user_clk),.reset_n (system_reset_n),.rx_data (pcie_rx_data),.rx_be (pcie_rx_be),.rx_valid (pcie_rx_valid),.rx_ready (pcie_rx_ready),.tx_data (pcie_tx_data),.tx_be (pcie_tx_be),.tx_valid (pcie_tx_valid),.tx_ready (pcie_tx_ready),.mmio_rd (mmio_rd),.mmio_wr (mmio_wr),.mmio_addr (mmio_addr),.mmio_wdata (mmio_wdata),.mmio_rdata (mmio_rdata),.mmio_rvalid (mmio_rvalid),.mmio_start_acq (mmio_start_acq), // 主机通过MMIO启动采集.mmio_clear_error(mmio_clear_error) // 主机清除错误);// 5. 数据采集模块wire adc_clk = user_clk; // 使用PCIe用户时钟作为ADC时钟(需根据实际ADC调整)wire acq_in_progress;wire acq_complete;wire [255:0] acq_data_out;wire data_valid;wire data_ready;data_acquisition u_data_acq (.adc_clk (adc_clk),.adc_data_ch0 (adc_data_ch0),.adc_data_ch1 (adc_data_ch1),.adc_valid (adc_valid),.user_clk (user_clk),.reset_n (system_reset_n),.start_acq (start_acq),.acq_in_progress (acq_in_progress),.acq_complete (acq_complete),.data_out (acq_data_out),.data_valid (data_valid),.data_ready (data_ready),.data_count (), // 可选连接到MMIO监控.buffer_full (), // 可选错误处理.buffer_empty ());// 6. DDR3控制器模块wire ddr3_init_done;wire [255:0] ddr3_wdata;wire [255:0] ddr3_rdata;wire [31:0] ddr3_addr_reg;wire [31:0] ddr3_burst_len;wire ddr3_write_en;wire ddr3_req_valid;wire ddr3_req_ready;ddr3_controller_acx750 u_ddr3_ctrl (.user_clk (ddr3_user_clk),.reset_n (ddr3_reset_n),.wdata (ddr3_wdata),.rdata (ddr3_rdata),.addr (ddr3_addr_reg),.burst_len (ddr3_burst_len),.write_en (ddr3_write_en),.read_en (1'b0), // 本例仅写操作.req_valid (ddr3_req_valid),.req_ready (ddr3_req_ready),.rdata_valid (),.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_odt (ddr3_odt),.ddr3_dm (ddr3_dm),.ddr3_dq (ddr3_dq),.ddr3_dqs_p (ddr3_dqs_p),.ddr3_dqs_n (ddr3_dqs_n),.init_calib_complete(ddr3_init_done));// 7. DMA引擎模块wire dma_req_ready;advanced_dma u_dma_engine (.clk (user_clk),.reset_n (system_reset_n),.start_dma (start_dma),.src_addr (dma_src_addr),.dest_addr (dma_dest_addr),.transfer_len (dma_len),.burst_size (dma_burst),.data_in (acq_data_out),.data_in_valid (data_valid),.data_in_ready (data_ready),.ddr3_wdata (ddr3_wdata),.ddr3_addr (ddr3_addr_reg),.ddr3_burst_len (ddr3_burst_len),.ddr3_write_en (ddr3_write_en),.ddr3_req_valid (ddr3_req_valid),.ddr3_req_ready (ddr3_req_ready),.dma_done (dma_done),.dma_error (dma_error));// ---------------------// 系统状态机实现// ---------------------always @(posedge user_clk or negedge system_reset_n) beginif (!system_reset_n) beginsystem_state <= SYS_IDLE;start_acq <= 0;start_dma <= 0;error_flag <= 0;dma_src_addr <= 0;dma_dest_addr <= 0;dma_len <= 0;dma_burst <= 8; // 默认突发大小8(256字节)end else begincase (system_state)SYS_IDLE: beginerror_flag <= 0;if (system_reset_n) begin // 系统复位释放system_state <= SYS_INIT;endendSYS_INIT: beginif (pll_locked && ddr3_init_done && pcie_init_done) beginsystem_state <= SYS_WAIT_TRIG;endendSYS_WAIT_TRIG: begin// 触发条件:外部触发或MMIO命令if (mmio_start_acq /*|| external_trig*/) beginsystem_state <= SYS_ACQUIRING;start_acq <= 1; // 启动采集dma_src_addr <= 'h40000000; // 假设采集缓冲区基地址dma_dest_addr <= 'h80000000; // DDR3目标地址dma_len <= 'h10000; // 传输长度(示例:64KB)endendSYS_ACQUIRING: beginstart_acq <= 1; // 保持采集启动if (acq_complete || acq_in_progress) begin // 采集完成或缓冲区满system_state <= SYS_DMA_XFER;start_acq <= 0;start_dma <= 1; // 启动DMAend else if (acq_error) begin // 采集错误system_state <= SYS_ERROR;error_flag <= 1;endendSYS_DMA_XFER: beginstart_dma <= 1; // 保持DMA启动if (dma_done) beginsystem_state <= SYS_WAIT_TRIG;start_dma <= 0;end else if (dma_error) beginsystem_state <= SYS_ERROR;error_flag <= 1;endendSYS_ERROR: beginif (mmio_clear_error || !sys_rst_n) begin // 清除错误或系统复位system_state <= SYS_IDLE;error_flag <= 0;endenddefault: system_state <= SYS_IDLE;endcaseendendendmodule
模块间关键信号连接
-
时钟与复位:
clock_manager
生成pcie_user_clk
和ddr3_user_clk
,同步到system_control
生成复位信号。system_control
的system_reset_n
连接到所有模块的复位输入。
-
PCIe 与 MMIO:
pcie_endpoint_acx750
解析 PCIe 数据,通过mmio_controller
转换为内部寄存器操作(如mmio_start_acq
)。
-
数据通路:
- 采集模块
data_acquisition
的acq_data_out
连接到 DMA 引擎的data_in
。 - DMA 引擎的
ddr3_wdata
连接到 DDR3 控制器的wdata
,地址和控制信号自动适配。
- 采集模块
-
初始化标志:
- DDR3 控制器的
init_calib_complete
和 PCIe 模块的pcie_init_done
作为状态机初始化完成条件。
- DDR3 控制器的
错误处理
- 采集错误(
acq_error
)或 DMA 错误(dma_error
)触发SYS_ERROR
,通过 LED 显示错误标志(debug_leds[7]
)。 - 主机可通过 MMIO 写入
mmio_clear_error
清除错误状态。
调试与监控
debug_leds
低 4 位显示状态机状态(system_state
),最高位显示错误标志(error_flag
),便于硬件调试。
9. 系统工作流程
-
上电与初始化:
- 时钟管理器生成稳定时钟,系统控制模块同步复位信号。
- DDR3 和 PCIe 完成初始化后,状态机进入
SYS_WAIT_TRIG(
监听主机通过 MMIO 发送的mmio_start_acq
或外部触发信号。)
。 - 此处需注意:
SYS_ACQUIRING 的启动逻辑触发源独立:系统进入采集状态的条件由当前配置的触发源决定。例如:
- 若配置为软件触发,调用
mmio_start_acq
后立即启动采集,无论是否有数据输入。 - 若配置为外部触发,收到有效触发信号后启动采集,与数据无关。
- 若配置为数据触发,仅当数据满足条件时启动采集,此时触发条件与数据相关。多触发源共存:部分系统支持多种触发方式组合(如软件触发优先于外部触发),需通过寄存器配置触发优先级。
- 另外:无输入信号时,采集数据通常不是绝对全 0,可能是 接近 0 的噪声值或硬件默认状态值。或者全 0 结果更可能是软件处理的产物(如驱动默认填充),而非物理通道的真实状态。
- 若配置为软件触发,调用
-
数据采集触发:
- 主机通过 MMIO 命令或外部硬件触发采集,状态机启动采集模块,填充缓冲区(在数据采集模块)。
-
DMA 传输:
- 采集完成后,DMA 引擎将数据以突发模式写入 DDR3,利用 DDR3 控制器的高速接口提升带宽。
-
错误恢复:
- 任何阶段出错时进入错误状态,通过复位或主机命令恢复,确保系统可靠运行。
二、模块间连接关系
1. 时钟与复位信号流
时钟管理模块 → 系统控制模块 → 所有其他模块 (生成125MHz/200MHz时钟和同步复位)
-
时钟:
pcie_user_clk
→ PCIe 端点、MMIO 控制器、数据采集、DMA 引擎ddr3_user_clk
→ DDR3 控制器sys_clk
→ 系统控制模块(复位同步)
-
复位:
pcie_reset_n
→ PCIe 端点、MMIO 控制器、数据采集、DMA 引擎system_reset_n
→ DDR3 控制器ddr3_reset_n
→ DDR3 控制器(内部使用)
2. 数据通路连接
ADC → 数据采集模块(缓冲区) → DMA引擎 → DDR3控制器 → DDR3存储器 (256位数据块) (突发传输) (物理层信号)
- 采集模块输出:
acq_data_out
(256 位)→ DMA 引擎data_in
- DMA 输出:
ddr3_wdata
(256 位)→ DDR3 控制器app_wdf_data
- DDR3 物理接口:地址 / 控制信号由 DDR3 控制器生成,连接到 DDR3 芯片
3. 控制信号流
主机(PCIe) → MMIO控制器 → 系统状态机 → 数据采集/DMA引擎 (MMIO命令) (解析为启动/配置信号) (触发采集/传输)
-
MMIO 命令:主机通过 PCIe 发送读写命令,MMIO 控制器解析后生成:
mmio_start_acq
:启动数据采集mmio_clear_error
:清除错误标志- DMA 参数(
src_addr
、dest_addr
、transfer_len
)
-
状态机输出:
start_dma
:启动 DMA 传输- 状态标志(
system_state
、error_flag
)→ 系统控制模块(LED 显示)
4. 初始化与状态监控
DDR3控制器 → 系统控制模块(`init_calib_complete`)
PCIe端点 → 系统控制模块(`pcie_init_done`)
- 系统控制模块接收这两个标志,通知状态机进入
SYS_WAIT_TRIG
状态。
三、系统总体目标与技术亮点
1. 总体目标
实现一个 高速数据采集与存储系统,具备以下能力:
- 数据采集:双通道 12 位 ADC,40MSPS 采样率,实时打包为 256 位数据块。
- 高速存储:通过 DMA 将数据以突发模式写入 DDR3(512MB,1333MHz),带宽≥1GB/s。
- 主机通信:通过 PCIe Gen2 x4 接口,支持主机配置参数、启动采集、读取状态。
- 可靠性:多时钟域复位同步、缓冲区背压控制、错误检测与恢复。
2. 技术亮点
- 多时钟域设计:通过 PLL 生成专用时钟,满足 PCIe 和 DDR3 的严格时序要求。
- 突发传输优化:DMA 与 DDR3 控制器配合,减少传输开销,提升带宽利用率。
- 模块化架构:各功能模块独立,便于调试和替换(如更换 ADC 型号或升级 DDR3 容量)。
具体详细讲解可参考我的后续文章!