哈尔滨市聚伦激光科技有限公司 — MS1052NA TDC 阵列高精度时间测量系统
基于 MS1052NA TDC 阵列的高精度时间测量数据采集系统,用于单光子探测/激光测距场景。
核心数据链路:
单光子/探测器信号
→ MS1052NA × 5 (TDC时间数字转换, 4通道/片, 共20通道)
→ FPGA XC7A100T (17路LVDS接收 → 仲裁 → 组8字节记录 → 写双端口RAM)
→ CY7C025AV 双端口RAM (MCU与FPGA数据缓冲)
→ GD32F470 MCU (SPI配置TDC → 读RAM → 校验 → UART/TCP上传)
→ 上位机 (PySide6实时显示 / TCP数据 / telemetry日志)
julun/
├── fpga/ # FPGA 工程
│ ├── fpga_main/ # TDC数据采集主工程 (XC7A100T)
│ │ ├── sources_1/ # Verilog 源码
│ │ │ ├── tdc_fpga_top.v # 顶层 (17路LVDS + MMCM + 仲裁 + RAM)
│ │ │ ├── tdc_group_rx.v # 每组TDC接收器 (IBUFDS→capture→FIFO)
│ │ │ ├── tdc_async_fifo.v # 异步FIFO (gray code跨时钟域)
│ │ │ ├── tdc_arbiter.v # 17通道round-robin仲裁器
│ │ │ ├── tdc_record_packer.v # 8字节记录组包
│ │ │ ├── tdc_ram_writer.v # CY7C025AV写控制器
│ │ │ ├── tdc_handshake.v # MCU↔FPGA握手协议
│ │ │ ├── tdc_stream_capture.v# LVDS位流捕获 (复用旧模块)
│ │ │ ├── fpga_to_ram.v # [旧] 2路bring-up基线
│ │ │ └── sim_define.v # 仿真定义
│ │ ├── constrs_1/ # XDC 约束
│ │ │ ├── tdc_fpga_top.xdc # 新顶层管脚/时钟约束 (17路LVDS+RAM+握手)
│ │ │ └── tdc_fpga_constraints_bringup.xdc # [旧] 2路bring-up约束
│ │ ├── sim_1/ # 仿真 testbench
│ │ └── scripts/ # TCL 综合脚本
│ ├── tdc_dev/ # 当前1052 bring-up工程,A1单片验证基准
│ └── ram_test/ # CY7C025AV RAM测试工程,已实现并生成bitstream
│
├── mcu/ # MCU 固件 (GD32F470ZKT6)
│ └── tdc_acquisition/ # TDC数据采集
│ │ └── Drivers/BSP/
│ ├── HANDSHAKE/ # MCU↔FPGA GPIO握手驱动
│ ├── ENET/ # LAN8720A + LwIP + TCP/telemetry
│ ├── TDC/ # TDC SPI配置 (5片)
│ ├── SPI/ # SPI0-4驱动
│ ├── SDRAM/ # CY7C025AV RAM读取
│ └── ...
│
├── host_software/ # Python上位机 (pixi管理)
│ ├── main.py # 入口
│ ├── pixi.toml # pixi 环境配置
│ ├── pyproject.toml # 项目元数据
│ ├── requirements.txt # 兼容旧工具的依赖清单
│ ├── scripts/
│ │ ├── smoke_test.py # 冒烟测试
│ │ └── mock_data.py # Mock数据源
│ └── tdc_acq/
│ │ ├── analysis/statistics.py # 实时统计
│ │ ├── connection/ # UART + TCP + Mock 连接层
│ │ │ ├── base.py
│ │ │ ├── serial_conn.py
│ │ │ ├── tcp_conn.py
│ │ │ ├── telemetry.py
│ │ │ ├── discovery.py
│ │ │ └── mock_conn.py
│ │ ├── parser/ # 8字节记录 + TCP帧解析
│ │ │ ├── crc.py
│ │ │ └── record.py
│ │ └── ui/ # 企业级 PySide6 + pyqtgraph GUI
│ ├── main_window.py # 主窗口
│ ├── simple_plot.py # Qt fallback绘图 (无pyqtgraph时)
│ ├── theme.py # 暗色/浅色企业主题
│ ├── state.py # 采集状态机
│ ├── widgets/ # UI组件
│ │ ├── app_header.py # 品牌Header + 时钟 + 状态
│ │ ├── acquisition_bar.py # 采集控制栏
│ │ ├── channel_matrix.py # 5×4通道矩阵
│ │ ├── plot_workspace.py # Waveform/Histogram/REF Index
│ │ ├── raw_record_table.py # Raw Records表格
│ │ ├── stats_panel.py # 统计卡片
│ │ ├── event_log.py # 事件日志
│ │ └── status_footer.py # 状态栏
│ └── dialogs/
│ ├── confirm_dialogs.py # 确认弹窗
│ └── about_dialog.py # 关于对话框
│
├── docs/ # 项目文档
├── tools/ # 工具脚本
├── archives/ # 压缩包归档
└── README.md
| 模块 | 器件 | 职责 |
|---|---|---|
| TDC | MS1052NA × 5 | 4通道/片时间数字转换, LVDS输出 |
| FPGA | XC7A100T-2FGG484C | 17路LVDS接收→仲裁→组包→写RAM |
| RAM | CY7C025AV | MCU与FPGA数据缓冲 (8K×16bit) |
| MCU | GD32F470ZKT6 | 配置TDC, 读RAM, UART+TCP上传 |
| PHY | LAN8720A | 10/100Mbps以太网PHY (RMII) |
① MCU_CONFIG_DONE: MCU PA3 / FPGA1 → FPGA D22 MCU完成TDC SPI配置
② FPGA_RDY: FPGA E21 / FPGA2 → MCU PA5 FPGA就绪 (MMCM锁定)
③ MCU_START: MCU PA6 / FPGA3 → FPGA D21 MCU授权开始采集
④ FPGA_IRQ: FPGA G21 / FPGA4 → MCU PB0 64-record block_ready
FPGA1–FPGA4 位于 FPGA Bank16 (LVCMOS33)。旧 PE0/PE1/PE2/PE3 ↔ M13/L13/K17/J17 是早期错误假设。 FPGA5–FPGA8 (B21/A21/E22/G22) 是备用/调试线,不作为当前握手协议。
| TDC组 | SPI外设 | CS引脚 | CLK/MISO/MOSI |
|---|---|---|---|
| A1 | SPI0 | PA4 | PB3/PB4/PB5 |
| A2 | SPI1 | PB12 | PB13/PB14/PB15 |
| A5 | SPI2 | PA15 | PC10/PC11/PC12 |
| A3 | SPI3 | PE11 | PE12/PE13/PE14 |
| A4 | SPI4 | PF6 | PF7/PF8/PF9 |
| 字节 | 内容 |
|---|---|
| 0-2 | STOP_DATA (时间数据, 24-bit LE) |
| 3-5 | REFERENCE_INDEX (参考索引, 24-bit LE) |
| 6 | INFO: bit[4:2]=TDC编号(1-5), bit[1:0]=STOP编号(0-3) |
| 7 | CHECKSUM: 字节0-6的低8位和 |
[0xAA][0x55][count_lo][count_hi][record0..N][crc16_lo][crc16_hi]
CRC16-CCITT: 多项式 0x1021, 初始值 0xFFFF
- MCU: Keil MDK-ARM / GD32F4xx DSP
- FPGA: Xilinx Vivado (目标器件: xc7a100tfgg484-2)
- 上位机: pixi + Python 3.11+ + PySide6 + pyqtgraph + pyserial
上位机启动:
cd host_software
pixi install
pixi run startMock 演示模式 (无硬件):
pixi run start
# 界面中 Source → Mock → Connect → Start测试:
pixi run smoke
pixi run -e test test
pixi run compile| 任务 | 状态 |
|---|---|
| MCU SPI配置TDC | ✅ 完成 (5片) |
| FPGA 17路LVDS接收 | ✅ RTL完成 |
| FPGA→RAM写入 | ✅ RTL完成 |
| XDC管脚/时钟约束 | ✅ 主工程完成;LCLK非CCIO仍需上板验证 |
| FPGA时序闭合 | ✅ tdc_dev routed WNS=0.110ns、DRC=0;ram_test routed WNS=1.104ns、DRC=0;主工程仍需按实测I/O delay复核 |
| MCU↔FPGA握手 | ✅ 双侧完成 |
| MCU读RAM + UART上传 | ✅ 完成,UART作为低速调试/回退链路 |
| LAN上传 (TCP) | ✅ 代码完成并已编译通过,默认 192.168.88.100:7000 |
| TCP telemetry | ✅ 端口 7001,上位机可读取ASCII状态日志 |
| UDP自动发现 | 暂停:Host代码保留,当前MCU bring-up固件不启用7002 |
| Host→MCU控制通道 | 规划中:复用7001下发TDC配置/模式,减少MCU反复烧录 |
| 上位机软件 | ✅ 企业级GUI完成 |
| 上板调试 | ✅ A1 test-pattern链路已打通;当前切到 normal STOP 输入验证 |
| 功能 | 状态 |
|---|---|
| UART 115200 数据接收 | ✅ |
| TCP 7000 数据接收 | ✅ |
| TCP 7001 telemetry日志 | ✅ |
| UDP 7002 设备发现 / Scan按钮 | Host保留,当前MCU固件未启用 |
| 8字节记录解析 + 校验和验证 | ✅ |
| TCP AA55帧解析 + CRC16验证 | ✅ |
| 20通道 (5 TDC × 4 STOP) 实时统计 | ✅ |
| Waveform / Histogram / REF Index / Raw Records 四Tab | ✅ |
| 5×4 通道矩阵 (计数/速率/状态) | ✅ |
| CSV / JSON / Parquet 导出 | ✅ |
| Mock 数据源 (4 pattern + 错误注入) | ✅ |
| 暗色/浅色企业主题切换 | ✅ |
| 高错误率告警横幅 | ✅ |
| REFERENCE_INDEX rollback/duplicate 检测 | ✅ |
| Stop/Clear 确认弹窗 | ✅ |
| pyqtgraph fallback (无pyqtgraph也能运行) | ✅ |
- LAN/TCP 是项目主通信链路,需求文档定义的通信方式为 LAN 或 USB,非 UART。 UART 115200 仅适合低速调试(上限 ~1440 rec/s),正式采集应使用 TCP。
- LAN8720A RMII 按当前原理图使用
TX_EN=PB11, TXD0=PG13, TXD1=PG14;A2 SPI 仍为PB12/PB13/PB14/PB15,因此5 TDC + LAN可以同时开启。 - LAN 联调使用独立直连网段:PC 有线口
192.168.88.20/24,MCU192.168.88.100:7000,避免与 WiFi/路由器常见网段重复。 - MCU/FPGA 握手按原理图 FPGA1–FPGA4:
PA3/D22 (CONFIG_DONE)、PA5/E21 (FPGA_RDY)、PA6/D21 (MCU_START)、PB0/G21 (FPGA_IRQ),Bank16 LVCMOS33。FPGA5–FPGA8 为备用调试线。旧PE0..PE3 ↔ M13/K17/L13/J17不是当前板级闭合路径。 - 当前 definitive 状态入口为
docs/项目状态报告.md。该文档记录最新 block=64、normal STOP、字节序、packer、stable-poll恢复、TCP背压处理和控制通道方案。 - A5 TDC 仅有1路LVDS连接 (SDO2管脚有重叠,待确认)
- A1-A5 LCLK 位于非 CCIO 管脚,XDC 使用
CLOCK_DEDICATED_ROUTE FALSE;250 MHz 余量必须上板验证 - Bank14 已统一为 2.5 V 约束,需确认板级电平兼容
tdc_fpga_top.xdc中 LVDS/RAM I/O delay 只保留模板,需根据实测波形填写- LwIP协议栈需集成到Keil工程中
- Vivado综合需使用
tdc_fpga_top.v作为顶层