Quick Start
- 准备硬件平台:选用Xilinx Artix-7 FPGA开发板(集成SDRAM颗粒与ADC模块),并安装Vivado 2020.1及以上版本开发环境。
- 创建Vivado工程,添加SDRAM控制器IP(如MIG 7系列),或自行编写简易SDRAM控制器RTL代码。
- 编写顶层模块,例化ADC接口(SPI或并行)与SDRAM控制器,将采集数据写入SDRAM。
- 编写SDRAM读模块,通过UART或VGA将存储数据输出至PC或显示器。
- 添加时钟管理模块(MMCM/PLL),为SDRAM提供100MHz或133MHz工作时钟,为ADC提供采样时钟。
- 编写约束文件(XDC),包含时钟周期、输入输出延迟以及SDRAM引脚分配。
- 运行综合与实现,检查时序报告(Setup/Hold无违例)。
- 生成比特流并下载至FPGA,通过串口助手或逻辑分析仪观察数据采集与回放结果。
前置条件与环境
| 项目 | 推荐值 | 说明 | 替代方案 |
|---|---|---|---|
| FPGA器件 | Xilinx Artix-7 XC7A35T | 主流入门级器件,资源充裕 | Altera Cyclone IV / Lattice ECP5 |
| SDRAM颗粒 | IS42S16160B (16M×16bit) | 兼容性良好,驱动成熟 | MT48LC16M16A2 (兼容) |
| EDA版本 | Vivado 2020.1 (或更高) | 支持7系列及后续器件 | ISE 14.7 (仅支持7系列) |
| 仿真器 | Vivado Simulator 或 ModelSim SE-64 | 支持混合语言仿真 | QuestaSim / Verilator (仅RTL) |
| 时钟源 | 板载50MHz晶振 + MMCM生成100MHz | 灵活配置,成本低 | 外部有源晶振 (如100MHz) |
| ADC接口 | SPI (如AD7606) 或并行 (如AD9226) | 根据采样率与精度选择 | 板上集成ADC (如AN108) |
| 约束文件 | XDC (Vivado) 或 SDC (Quartus) | 确保时序收敛 | 手动时序分析 (不推荐) |
| 调试工具 | UART (115200波特率) + 串口助手 | 简单易用,成本低 | 逻辑分析仪 (如Saleae) |
目标与验收标准
功能目标
- ADC以1MHz采样率采集模拟信号,数据实时写入SDRAM(深度16M×16bit)。
- 通过UART以115200bps回读存储数据,无丢数。
性能指标
- SDRAM读写带宽 ≥ 200MB/s(100MHz时钟,16位总线)。
- 实际使用带宽低于理论值50%(因刷新与命令开销)。
资源占用
- LUT ≤ 1200,FF ≤ 1500,BRAM ≤ 4块(36Kb),DSP ≤ 2。
时序约束
- SDRAM接口建立/保持余量 ≥ 0.2ns,系统时钟无违例。
验收方式
- 用信号发生器输入1kHz正弦波,串口输出数据在Python中绘图,波形无明显失真。
- 或逻辑分析仪抓取SDRAM读写命令序列,验证无数据覆盖。
实施步骤
1. 工程结构
project/
├── rtl/
│ ├── top.v # 顶层模块
│ ├── adc_if.v # ADC接口(SPI/并行)
│ ├── sdram_ctrl.v # SDRAM控制器(含初始化、刷新、读写状态机)
│ ├── uart_tx.v # UART发送器
│ └── clk_gen.v # 时钟生成(MMCM/PLL)
├── sim/
│ ├── tb_top.v # 测试平台
│ └── sdram_model.v # SDRAM仿真模型(可用厂商提供)
├── constraints/
│ └── top.xdc # 引脚与时序约束
└── ip/
└── clk_wiz_0.xci # 时钟IP(可选)顶层模块需例化所有子模块,并通过AXI4-Lite或自定义FIFO桥接ADC与SDRAM控制器。建议将ADC采样数据先存入异步FIFO(跨时钟域),再写入SDRAM,以避免跨时钟域亚稳态风险。
2. 关键模块:SDRAM控制器
// sdram_ctrl.v 核心状态机片段
localparam IDLE = 4'd0;
localparam INIT = 4'd1;
localparam REFRESH = 4'd2;
localparam WRITE = 4'd3;
localparam READ = 4'd4;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else
case (state)
IDLE: // 等待请求
INIT: // 初始化序列(预充电、刷新、模式寄存器设置)
REFRESH: // 定时刷新(每15.625μs一次)
WRITE: // 执行写操作
READ: // 执行读操作
endcase
endSDRAM控制器需处理初始化、自动刷新、读/写命令以及行/列地址复用。建议采用三段式状态机,将命令生成与数据路径分离,便于时序收敛。刷新周期必须严格满足SDRAM规格(通常每行64ms内刷新一次)。
3. 跨时钟域处理
ADC采样时钟与SDRAM工作时钟通常不同频或不同相,需使用异步FIFO进行数据缓冲。推荐使用Xilinx FIFO Generator IP(独立时钟模式),或手动实现双口BRAM加格雷码指针同步。FIFO深度建议至少256,以吸收瞬时写入速率波动。
4. 调试与验证
- 仿真阶段:使用SDRAM仿真模型(如厂商提供或开源模型),验证初始化序列、刷新时序与读写正确性。
- 硬件调试:通过ILA(集成逻辑分析仪)抓取SDRAM命令与数据总线,检查读写响应是否正常。
- 系统联调:输入已知波形(如正弦波),通过UART回读数据并绘图,确认采集与存储无失真。
验证结果
完成上述实施步骤后,应得到以下验证结果:
- 仿真通过:SDRAM初始化成功,读写操作无数据错误。
- 时序收敛:建立/保持余量≥0.2ns,无违例路径。
- 硬件输出:串口数据与输入模拟信号一致,波形无明显失真。
- 资源占用:LUT ≤ 1200,FF ≤ 1500,BRAM ≤ 4块,DSP ≤ 2。
排障指南
- SDRAM初始化失败:检查时钟频率是否在SDRAM规格范围内(通常100-133MHz),确认初始化序列中预充电、刷新、模式寄存器设置顺序正确。
- 数据写入后读出错误:检查跨时钟域FIFO是否溢出或空读,验证SDRAM地址是否递增正确,确认刷新间隔未超过64ms。
- UART输出乱码:确认波特率匹配(115200),检查UART发送模块的时钟分频是否准确,验证数据位、停止位配置一致。
- 时序违例:优化SDRAM数据路径的流水线级数,调整输出延迟约束,或降低工作频率。
扩展方向
- 增加多通道ADC采集,通过时分复用或并行写入SDRAM。
- 实现数据预处理(如数字滤波、FFT)后再存储,降低回传带宽需求。
- 使用DDR3/DDR4替代SDRAM,提升带宽与容量,适用于更高采样率场景。
- 添加以太网或USB接口,实现远程数据传输。
参考资源
- Xilinx UG586: 7 Series Memory Interface Solutions User Guide
- ISSI IS42S16160B Datasheet
- ADI AD7606/AD9226 Datasheet
- Vivado Design Suite User Guide: Using Constraints (UG903)
附录
A. 关键时序参数
| 参数 | 值 | 说明 |
|---|---|---|
| tCK | 10 ns | 时钟周期(100MHz) |
| tRCD | 20 ns | 行地址到列地址延迟 |
| tRP | 20 ns | 预充电周期 |
| tRFC | 70 ns | 刷新周期 |
| tREFI | 7.8125 μs | 刷新间隔(8192行/64ms) |
B. Python绘图脚本示例
import serial
import matplotlib.pyplot as plt
ser = serial.Serial('COM3', 115200, timeout=1)
data = []
for _ in range(1024):
val = ser.read(2)
if len(val) == 2:
data.append(int.from_bytes(val, 'little'))
plt.plot(data)
plt.show()


