1.信号功能拆解
- CONVST:上升沿启动 A/D 转换,需要 FPGA 主动输出一个脉冲。
- BUSY:芯片转换完成的状态反馈,FPGA 需要作为输入引脚,检测其下降沿来启动后续的串行传输。
- CS:低电平有效,在 BUSY 变低后拉低,整个串行传输周期保持有效,传输结束后拉高。
- SCLK:由 FPGA 产生,为 16 个时钟周期,用来同步数据的发送和接收,需满足
t_SCLK_LOW、t_SCLK_HIGH等时序要求。 - SDOA/SDOB:芯片输出的 16 位数据(DB15~DB0),在 SCLK 的上升沿或下降沿稳定输出,FPGA 在对应沿采样。
- SDI:FPGA 向芯片发送的 16 位配置数据,需在 SCLK 沿之前满足
t_DIN_SETUP的建立时间。
2. FPGA 实现的核心步骤
(1)状态机设计
用一个状态机来管理整个时序流程,推荐划分以下几个状态:
- IDLE:初始状态,等待触发或 BUSY 信号。
- WAIT_CONV:发送 CONVST 脉冲后,等待 BUSY 变低,表示转换完成。
- SERIAL_TX_RX:拉低CS,产生 16 个 SCLK 脉冲,同时在 SCLK 的对应沿发送 SDI 数据、采样 SDOA/SDOB 数据。
- DONE:传输结束后,拉高CS,回到 IDLE 状态。
(2)时钟与时序约束
- 首先根据芯片手册的
t_SCLK、t_SCLK_LOW、t_SCLK_HIGH等参数,确定 SCLK 的频率(例如如果t_SCLK最小为 20ns,则 SCLK 最大为 50MHz)。 - 可以用 FPGA 内部的 PLL 生成稳定的 SCLK,或者用系统时钟分频得到。
- 在代码中通过计数器精确控制各个时间参数(如
t_SCLK_SETUP、t_DOUT_HOLD),确保满足建立和保持时间。
(3)数据同步采样与发送
- 数据接收(SDOA/SDOB):在 SCLK 的上升沿或下降沿进行采样(需根据芯片手册确认采样沿),将 16 位数据存入移位寄存器。
- 数据发送(SDI):在 SCLK 的对应沿之前,提前将下一位数据放到 SDI 引脚上,以满足
t_DIN_SETUP的建立时间要求。
3. 关键代码示例(Verilog)
verilog
// 状态机定义 typedef enum logic [2:0] { IDLE, WAIT_BUSY_LOW, SERIAL_TRANS, DONE } state_t; state_t current_state, next_state; reg [4:0] sclk_cnt; // 16个时钟计数 reg sclk_en; reg cs_n; reg sclk; reg [15:0] sdi_data; reg [15:0] sdoa_data, sdob_data; // 状态转移逻辑 always @(posedge clk or posedge rst_n) begin if (!rst_n) begin current_state <= IDLE; end else begin current_state <= next_state; end end // 组合逻辑:状态跳转和输出控制 always @(*) begin next_state = current_state; cs_n = 1'b1; sclk_en = 1'b0; convst = 1'b0; case (current_state) IDLE: begin if (start_conv) begin convst = 1'b1; next_state = WAIT_BUSY_LOW; end end WAIT_BUSY_LOW: begin if (!busy) begin next_state = SERIAL_TRANS; end end SERIAL_TRANS: begin cs_n = 1'b0; sclk_en = 1'b1; if (sclk_cnt == 5'd15) begin next_state = DONE; end end DONE: begin next_state = IDLE; end endcase end // SCLK生成与移位逻辑 always @(posedge clk or posedge rst_n) begin if (!rst_n) begin sclk <= 1'b0; sclk_cnt <= 5'd0; sdi_data <= 16'h0000; sdoa_data <= 16'h0000; sdob_data <= 16'h0000; end else if (sclk_en) begin sclk <= ~sclk; if (sclk) begin // SCLK上升沿:采样数据 sdoa_data <= {sdoa_data[14:0], sdoa}; sdob_data <= {sdob_data[14:0], sdob}; sclk_cnt <= sclk_cnt + 1'b1; end else begin // SCLK下降沿:发送下一位 sdi <= sdi_data[15]; sdi_data <= {sdi_data[14:0], 1'b0}; end end else begin sclk <= 1'b0; sclk_cnt <= 5'd0; end end4. 调试与验证建议
- 仿真验证:先用 ModelSim 等工具做功能仿真,模拟 BUSY 信号的变化,检查状态机跳转、SCLK 生成、数据收发是否符合时序图。
- 时序约束:在 FPGA 工具(如 Vivado)中对 SCLK、CS、SDI 等信号添加时序约束,确保建立时间和保持时间满足芯片要求。
- 板级调试:使用逻辑分析仪抓取实际波形,对比手册中的时序参数,重点检查
t_SCLK_SETUP、t_DOUT_HOLD等关键时间是否达标。