ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于 FPGA 与 USB 2.0 的线阵 CCD 光谱数据采集系统设计

2026/8/17 21:04:15 拓冰建站 浏览量
基于 FPGA 与 USB 2.0 的线阵 CCD 光谱数据采集系统设计 基于 FPGA 与 USB 2.0 的线阵 CCD 光谱数据采集系统设计关键词FPGA、线阵 CCD、光谱采集、AD9240、FIFO、USB 2.0、FTDI、Vivado、ILA、数据传输摘要本文介绍一套基于 FPGA 的线阵光谱数据采集系统。系统从线阵探测器输出的模拟信号开始经模拟前端和 AD9240 转换为 14 位数字样本FPGA 负责产生采集时序、识别有效样本、组织帧边界、利用双 FIFO 完成跨时钟缓存并经 FTDI USB 2.0 接口将原始数据送至 PC。本文重点分析 FPGA 的模块划分、关键数据格式、FIFO/USB 数据通路和 ILA 波形验证不涉及光学设计、扫描控制、OCT 重建或图像识别。1. 引言线阵探测器输出的数据具有两个特点一是样本随时序连续到来二是 PC 端 USB 读取并不总是连续。若没有缓存USB 传输的等待会反过来干扰采集若没有帧边界主机也无法判断一段字节流是否是一帧完整光谱。因此数据采集系统的核心并不是“把数据传到电脑”而是保证下面四件事同时成立FPGA 在正确时刻驱动探测器和 ADC只有有效窗口内的 ADC 样本进入数据通路每帧数据都具有可识别边界采集时钟域和 USB 时钟域被缓存隔离数据按顺序送往 PC。2. 系统总体设计系统的硬件数据路径很明确线阵 CCD / 探测器 ↓ 模拟光谱信号 模拟前端滤波、幅度匹配 ↓ AD924014 位 ADC ↓ adc_data[13:0] FPGA时序、有效标志、帧封装、双 FIFO、USB 调度 ↓ FTDI 245 FIFO 型 USB 2.0 接口 ↓ PC原始帧接收、显示或保存FPGA 同时生成ccd_clk、st、data_en等时序信号PC 可以通过 USB 发送启动、停止和采集参数。由此形成“数据上送、控制下发”的双向接口但正文始终只围绕数据采集展开。3. FPGA 设计方案3.1 代码模块如何划分顶层ccd_usb_top没有把所有功能塞在同一段逻辑中而是按数据路径拆分tra_ccd → ad_dr → data_12_16 → fifo_temp × 2 → fifo_drive → usb_top_ft232h其中模块作用tra_ccd产生探测器时钟、启动和采集使能ad_dr接收 AD9240 的 14 位数据并输出有效标志data_12_16将有效样本转换为带帧边界的 16 位传输字fifo_temp × 2在采集时钟域和 USB 60 MHz 时钟域之间缓存数据fifo_drive根据 A/B FIFO 空满状态和 USB 状态调度读写usb_top_ft232h对接 FTDI 245 FIFO 型 USB 通道并解析控制帧这样写的好处是数据不对时看ad_dr帧不对时看data_12_16USB 卡顿时看 FIFO 与握手而不是面对一个无法拆分的大状态机。3.2 启动和停止为什么要先清 FIFO采集系统最容易被忽略的不是“如何启动”而是“停止后留下了什么”。如果一次采集停止时 FIFO 内还有残留字节而下一次采集直接启动PC 端可能会先读到上一轮的帧尾或半帧数据。代码中的star模块专门处理这一点。它用IDLE、RUNNING、CLEAR_FIFO、WAIT_STOP四个状态控制pll_flag和fifo_clean启动时放行采集时钟停止时关闭时钟放行、置位 FIFO 清空下一次启动前一直保持等待状态。这样采集会话的第一帧从干净的缓存开始。启动命令 → 放行采集时钟 → 接收一组组新帧 停止命令 → 停止写入 → 清空 FIFO → 等待下一次启动3.3 时序模块和采样模块为什么分开tra_ccd不直接处理 ADC 数据它只产生探测器相关的ccd_clk、st和data_en。当前实现中st_cnt负责周期计数trig_cnt在指定计数窗口后短暂置位data_en。这样“什么时候让探测器工作”和“什么时候允许数据写入”被分开表达。ad_dr再把trig输出为ad_clk并以IDLE → HIGH → LOW状态机产生ad_flag。其中data_en表示采集窗口已经打开eos用于结束当前有效段。后级并不是见到时钟就写数据而是依据ad_flag识别有效样本这一点对排除无效区和避免帧错位非常关键。3.2 从 14 位 ADC 样本到 USB 帧AD9240 数据经ccd_data[13:0]进入 FPGA。data_12_16利用ad_flag的边沿确定帧的开始与结束并采用如下组织方式0xAAAA | {2b00, ccd_data[13:0]} × N | 0x55550xAAAA是帧头0x5555是帧尾中间为扩展到 16 位的 ADC 样本。这使 PC 接收端可以在连续字节流中寻找边界、检查数据是否截断并在需要时重新同步。它解决的是数据对齐问题不是完整的差错校验协议。data_12_16的状态机逻辑可以理解为检测到ad_flag上升沿时先写帧头下一拍开始输出{2b00, ccd_data}在ad_flag保持期间持续输出样本检测到下降沿后输出最后一个样本再单独写帧尾。帧头、首个样本和帧尾因此不会挤在同一个数据字里。3.3 FIFO 为什么要分成两个采集数据写入 FIFO 的节奏由采集时钟决定USB 读数据的节奏由usb_clk_60m和 PC 握手状态决定。两端节奏不同所以需要把“持续采样”和“按 USB 条件发送”隔开。当前实现中FIFO 写侧接收 16 位帧数据FIFO 读侧输出 8 位字节流两个 FIFO 由fifo_drive统一调度A/B FIFO 的空满状态决定读写是否允许。这给系统提供了跨时钟域和位宽适配的缓冲位置。后续 FIFO 专题会专门讨论切换条件、缓存深度和连续帧验证。3.4 A/B FIFO 如何交替工作fifo_drive实际上有写、读两套状态机。写端运行在采集相关时钟下一帧开始后选择 FIFO A 或 B 写入发现eos时记录这一帧已经结束再切换到另一组 FIFO。读端运行在 USB 60 MHz 时钟下只有确认某一组 FIFO 已经完成一帧写入、并且尚未读空时才选择它送往 USB。采集第 n 帧写 FIFO A USB读上一帧的 FIFO B 采集第 n1 帧写 FIFO B USB读上一帧的 FIFO A这个过程把“采样不能停”和“USB 可能等待”分离开。它不是抽象概念上的乒乓缓存而是代码中fifo_wrreq_select、fifo_rd_select、eos_a/eos_b、fifo_empty_a/b共同完成的帧级调度。4. USB 2.0 数据传输数据从 FIFO 读出后进入usb_top_ft232h再经ftdi_245fifo_top与 FTDI 245 FIFO 风格接口握手。USB 可写时FPGA 按顺序发送缓存字节USB 接收方向则用于传入启动、停止和参数控制帧。对数据采集来说USB 模块的判断标准不是“接口能枚举”而是有数据时能从正确的 FIFO 读出FIFO 为空时不发生无效读USB 不可写时不会覆盖未发送的数据一段连续采集后PC 仍能找到完整帧头和帧尾。从代码接口可见上传侧是 8 位字节流控制接收侧则以 128 位帧进入tx_specified_len。启动标志为16h0024全1的 128 位帧用于停止。对数据采集而言这套控制帧的作用只有一个把“何时开始写新数据、何时停止并清空缓存”明确地交给 FPGA而不是依赖 PC 端随意断开读取。5. 数据通路的时钟域和位宽变化把一帧数据从 ADC 送往 USB需要跨过三个边界阶段数据宽度主要时钟/标志关键任务ADC 输入14 位trig/ad_clk、data_en、ad_flag只保留有效样本FPGA 帧数据16 位采集相关时钟、帧首尾状态机扩展数据位宽并加入帧边界FIFO 写侧16 位采集相关时钟连续写入当前帧FIFO 读侧/USB8 位usb_clk_60m、USB 握手字节化输出并等待接口可写因此FIFO 的 16 位写、8 位读不是为了压缩数据而是把 FPGA 内部的帧字适配为 USB 的字节流。PC 接收端只要按相同字节序重新拼回 16 位字就可以寻找0xAAAA和0x5555来恢复帧边界。6. ILA 波形如何验证这条链路这张 ILA 波形将data_en、FIFO A/B 的读写请求与空满状态、USB 相关状态、data_out[13:0]和data_16[15:0]放在同一时间轴上。它的价值在于把采样、封帧、缓存和传输放到一次观察中观察信号用于确认data_out[13:0]ADC 样本确实进入 FPGAdata_16[15:0]样本已被组织为传输用数据字fifo_wrreq_a/b有效帧数据正在进入缓存fifo_rdreq_a/bUSB 侧正在从缓存取数据fifo_empty/full_a/b缓存切换没有越过空/满边界USB 状态读写请求受接口握手条件约束看这张波形时建议不要只盯一个信号而是按顺序检查先确认data_en出现时data_out[13:0]有连续样本再确认data_16[15:0]产生对应传输字接着确认fifo_wrreq_a/b只在当前 FIFO 未满时写入最后看fifo_rdreq_a/b是否只在 FIFO 非空、USB 条件允许时产生。这样就能把“没有数据”“没有写入缓存”“缓存没有读出”“USB 没有发送”四类问题区分开。波形中的fifo_full_a/b在当前观察窗口保持低电平说明这一次捕获窗口内没有写满fifo_empty_a/b则配合读请求判断缓存是否已经被读空。对外展示时应把它表述为“本次波形观察结果”不把单个窗口写成长期稳定性的结论。工程保存的实现报告还显示该 FPGA 快照的用户时序约束满足WNS 为 9.900 ns、TNS 为 0。它是 RTL 已完成实现和时序检查的证据不用于外推整机性能。7. 总结这套数据采集系统只做一件事以 FPGA 为核心稳定地把线阵探测器经 AD9240 得到的数字光谱样本组织、缓存并传输到 PC。其关键不是单一模块而是探测器时序 → ADC 有效样本 → 帧边界 → FIFO 跨时钟缓存 → USB 握手的连续关系。下一篇将从 线阵光谱探测器驱动与采集 开始继续拆解tra_ccd与ad_dr的时序和样本有效窗口之后依次展开 AD9240、FIFO 和 USB 专题。本文仅分享公开架构、局部波形和设计思路完整 RTL、约束、IP 配置、原理图、PCB 和原始数据后续分享。