当前位置: 首页 > news >正文

PCIe数据采集系统

PCIe数据采集系统

一、模块功能划分与职责

1. 时钟管理模块 (clock_manager)

  • 核心功能
    • 生成系统所需的多时钟信号(100MHz 系统时钟、125MHz PCIe 时钟、200MHz DDR3 时钟)。
  • 关键接口
    • 输入:系统主时钟 sys_clk、PCIe 差分参考时钟 pcie_refclk_p/n
    • 输出:各模块所需时钟(pcie_user_clkddr3_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/npcie_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 可以像访问内存一样直接读写这些寄存器,从而控制外设或获取外设状态。

核心概念
  1. 地址映射

    • 将外设的控制寄存器、状态寄存器等映射到系统内存地址空间的特定区域。
    • CPU 无需使用特殊的 I/O 指令(如 x86 的 IN/OUT 指令),而是通过普通的内存访问指令(如 LOAD/STORE)与外设交互。
  2. 统一寻址

    • 内存和外设共享同一地址空间,简化了编程模型。
    • 例如,向地址 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;
  1. 时钟和复位处理

    • 使用 MIG 提供的用户接口时钟ui_clk
    • 复位条件结合了同步复位信号和初始化校准完成标志
  2. 读写命令处理

    • 根据write_enread_en生成对应的命令编码
    • 只有当控制器就绪 (app_rdy) 且用户请求有效 (req_valid) 时才发出命令
  3. 写数据处理

    • 将用户提供的 256 位写数据wdata直接传递给 MIG
    • 生成写数据 FIFO 的控制信号
  4. 读数据处理

    • 将 MIG 返回的读数据app_rd_data传递给用户
    • 同步读数据有效标志app_rd_data_valid
代码展示
// 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 存储器之间的高速接口。主要特点包括:

  1. 用户友好的抽象接口:提供简单的读写命令、地址和数据接口
  2. 复杂时序自动处理:MIG 负责处理 DDR3 的所有低级时序要求
  3. 突发传输支持:通过burst_len参数支持高效的批量数据传输
  4. 多时钟域管理:正确处理不同时钟域之间的同步问题
  5. 初始化和校准:自动执行 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 作为状态机初始化完成条件。
错误处理
  • 采集错误(acq_error)或 DMA 错误(dma_error)触发 SYS_ERROR,通过 LED 显示错误标志(debug_leds[7])。
  • 主机可通过 MMIO 写入 mmio_clear_error 清除错误状态。
调试与监控
  • debug_leds 低 4 位显示状态机状态(system_state),最高位显示错误标志(error_flag),便于硬件调试。


9. 系统工作流程

  1. 上电与初始化
    • 时钟管理器生成稳定时钟系统控制模块同步复位信号
    • DDR3 和 PCIe 完成初始化后,状态机进入 SYS_WAIT_TRIG(监听主机通过 MMIO 发送的 mmio_start_acq 或外部触发信号。​​​​​​​
    • 此处需注意:

      SYS_ACQUIRING 的启动逻辑触发源独立:系统进入采集状态的条件由当前配置的触发源决定。例如:

      • 若配置为软件触发,调用mmio_start_acq后立即启动采集,无论是否有数据输入。
      • 若配置为外部触发,收到有效触发信号后启动采集,与数据无关。
      • 若配置为数据触发,仅当数据满足条件时启动采集,此时触发条件与数据相关。多触发源共存:部分系统支持多种触发方式组合(如软件触发优先于外部触发),需通过寄存器配置触发优先级。
      • 另外:无输入信号时,采集数据通常不是绝对全 0,可能是 接近 0 的噪声值硬件默认状态值。或者全 0 结果更可能是软件处理的产物(如驱动默认填充),而非物理通道的真实状态。
  2. 数据采集触发
    • 主机通过 MMIO 命令或外部硬件触发采集,状态机启动采集模块,填充缓冲区(在数据采集模块)。
  3. DMA 传输
    • 采集完成后,DMA 引擎将数据以突发模式写入 DDR3利用 DDR3 控制器的高速接口提升带宽
  4. 错误恢复
    • 任何阶段出错时进入错误状态,通过复位或主机命令恢复,确保系统可靠运行。


二、模块间连接关系

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_addrdest_addrtransfer_len
  • 状态机输出

    • start_dma:启动 DMA 传输
    • 状态标志(system_stateerror_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 容量)。


具体详细讲解可参考我的后续文章!​​​​​​​

相关文章:

  • 【系统架构师】2025论文《WEB系统性能优化技术》
  • Axure中继器高保真交互原型的核心元件
  • tomcat 400 The valid characters are defined in RFC 7230 and RFC 3986
  • 解锁数据密码:企业数据体系如何开启业务增长新引擎
  • 漏洞修复:tomcat 升级版本 spring-boot-starter-tomcat 的依赖项
  • 使用 TypeScript + dhtmlx-gantt 在 Next.js 中实现
  • 鸿蒙OSUniApp 制作自定义弹窗与模态框组件#三方框架 #Uniapp
  • 使用itextsharp5.0版本来合并多个pdf文件并保留书签目录结构
  • 从AlphaGo到ChatGPT:AI技术如何一步步改变世界?
  • 使用 Apache POI 生成 Word 文档
  • 第 83 场周赛:较大分组的位置、隐藏个人信息、连续整数求和、统计子串中的唯一字符
  • WordPress_Relevanssi Sql注入漏洞复现(CVE-2025-4396)
  • 2025最新ChatGPT Plus令牌(Token)限制完全指南:每日/每月用量详解与突破方法
  • 国产化Word处理控件Spire.Doc教程:通过C# 删除 Word 文档中的超链接
  • 网络安全-等级保护(等保) 2-5 GB/T 25070—2019《信息安全技术 网络安全等级保护安全设计技术要求》-2019-05-10发布【现行】
  • 2023CCPC河南省赛暨河南邀请赛个人补题ABEFGHK
  • Spark SQL 之 Analyzer
  • 基于vue3的权限管理系统脚手架搭建项目实战(二):登录与路由权限控制
  • 一个基于 Spring Boot 的实现,用于代理百度 AI 的 OCR 接口
  • React与Docker中的MySQL进行交互
  • 外企聊营商|武田制药:知识产权保护助创新药研发
  • 泽连斯基:乌代表团已启程,谈判可能于今晚或明天举行
  • 赖清德为“临阵脱逃”作准备,国台办:绝不会任“台独”祸首逍遥法外
  • 云南一男子持刀致邻居3死1重伤案二审开庭,未当庭宣判
  • 【社论】人工智能将为教育带来什么
  • 梅花奖在上海|“我的乱弹我的团”,民营院团首次入围终评