AD9826 FPGA驱动完整攻略:从CDS原理到时序代码实战
2026/9/16 2:43:27 网站建设 项目流程

做FPGA图像采集或者工业相机相关项目的人,大概率绕不开一个芯片:AD9826。这是一颗ADI出品的老牌CCD/CIS传感器信号处理器,虽然芯片已经有很多年头了,但在扫描仪、条码识别、部分工业视觉对焦模块里依然大量服役。它内部集成了相关双采样(CDS)、可编程增益放大器(PGA)和一颗16位ADC,核心工作就是把CCD传感器那微弱的模拟信号调理成干净的、可以直接送进FPGA做后续处理的数字信号。

最近我把这颗芯片从驱动到时序完整调通了一遍,踩了不少坑,尤其是时序分析那块,对着数据手册画波形图画到眼睛花。这篇博文就把AD9826的工作机制、时序关键点,以及我最终调通的Verilog驱动代码从头到尾讲一遍。既有对芯片内部工作原理的拆解,也有可直接抄作业的代码实现,还会有我个人实测中遇到的典型问题排查实录。适合正在用这颗芯片、准备用这颗芯片,或者纯粹想了解工业级ADC驱动时序逻辑的朋友参考。

1. 内容整体设计与思路拆解

1.1 为什么偏偏是AD9826:这颗芯片到底解决什么问题

先聊个实际场景。CCD传感器输出的是像素电荷经过转换后的模拟电压信号,这个信号有几个“难伺候”的地方:幅度非常小,一般只有几百毫伏;带很强的复位噪声,因为CCD每个像素读取前都要复位,复位电平会叠加在有效信号上;不同的传感器暗电流和增益特性还不一样。如果直接把这种信号送给普通ADC去采样,出来的图像会花到没法看——固定模式噪声、复位噪声全混在里面。

AD9826干的事情就是把信号链做完整。它的输入端有一个相关双采样电路,也就是CDS,专门对付复位噪声;后面跟了PGA可编程增益放大器,能把小信号放大到ADC满量程范围附近,最大增益能到12dB左右,从-2dB到12dB多档可调;再后面就是一颗16位、最高采样率12MSPS的ADC。输出侧是二进制补码格式的并行数字信号,跟FPGA对接非常直观。这基本上就是一条完整的模拟前端信号链了,不需要你自己用运放和分立ADC去搭,稳定性和精度都更容易保证。

1.2 整体工作流程:从模拟输入到数字输出要经过哪些环节

如果你只看AD9826的数据手册,会看到一大推寄存器配置和时序图,容易一头雾水。但本质上它的工作流程可以拆成下面几步:

第一,配置阶段。芯片上电之后,通过三线SPI接口把工作参数写进内部寄存器,包括输入极性选择、CDS模式、PGA增益、偏置电平、输出格式等。这些寄存器配置好之后,芯片就进入固定工作状态,不会再变了。

第二,像素采样阶段。在SCLK时钟的驱动下,AD9826对每个像素周期执行两次采样:一次采复位电平,也就是所谓的前沿;一次采信号电平,也就是后沿。CDS电路把这两个电平相减,就得到了干净的像素电压。

第三,数字化输出阶段。芯片每个时钟周期处理一个像素,在CDS完成之后,ADC完成转换,结果经过输出寄存器,在数据有效信号DOUTVALID的伴随下,从D0到D15这16根数据线上并行输出。

从时序控制的角度看,FPGA侧的任务就是两件事:给芯片提供正确的SCLK、CDS采样点位置和转换时序,然后把输出的16位数据正确地读回来,再根据输出帧同步信号(通常是CCD传感器自己的行/帧同步信号,AD9826内部也有相关标志位)把像素数据组织拼接成完整图像。

1.3 时序方案选型考量:FPGA和AD9826之间到底谁主动

我刚开始搞这个项目的时候有个误区,以为FPGA只要给个持续时钟,AD9826自己就能把活干完,FPGA在边上等数据就行。实际上这个方案需要对“谁是主”理解清楚。AD9826的高速转换CDS时序完全由外部输入的SCLK决定,芯片自己只有一个内部参考时钟用于控制逻辑,它不会自动产生采样脉冲。也就是说所有采样动作、转换动作、输出动作都跟着你给的那个主时钟走。这跟我们平时用SPI从机芯片不一样,SPI从机至少还能靠片选信号来圈定一次传输的边界,AD9826是纯流水的,时钟不停它就一直采,根本不管你是不是想要这个像素。

所以正确的方案是:FPGA主动控制整个时序,SCLK给多少、什么相位关系、每个像素周期怎么划分,全部由FPGA根据CCD传感器的驱动波形来设计。AD9826只是被动响应。理解了这一点,你就知道为什么时序分析这么重要——时序不对,后面全白搭。

我最终选择的方案是用FPGA内部PLL把像素时钟打进AD9826作为SCLK,然后根据AD9826数据手册要求的时序关系,在FPGA内部生成对应的内部采样脉冲和数据读出窗口。SCLK频率我设为6MHz,这是CCD传感器行输出速率和AD9826最高12MSPS之间取的一个平衡点。6MHz也方便后续FPGA内部处理逻辑按像素周期翻倍计算。

2. 核心细节解析与实操要点

2.1 深入理解CDS相关双采样:为什么能消掉复位噪声

CDS是AD9826最核心的功能模块,理解它的原理直接决定你能不能调出干净的图像。CCD像素读取过程大致是:先把像素电容复位到一个固定电平,然后光生电荷逐渐转移并充放这个电容,使电平线性下降或者上升,具体极性取决于CCD类型。问题在于,每次读取像素之前那个复位电平并不是完全一致的,会有热噪声和残余电荷差异,如果不处理,每一个像素都叠了一个随机直流偏置,图像就呈现出网状噪声。

CDS的做法很巧妙:在复位电平和信号电平期间各采样一次,然后把两次采样值做减法。复位噪声在两次采样中几乎是共模的,减法操作把它抵消掉了。留下的是真正的光生信号电压差。这就像你拿一个称去称东西,两次称重之间的系统零点偏了,但你把两次读数相减之后零点偏置就没了。AD9826内部的CDS实现方式,是在外部SCLK的特定相位控制下,依次启动两个片内采样保持电容的开关,一个存复位值,一个存信号值,然后在后级相减。

具体到AD9826,数据手册上的典型时序可以看到,每个像素周期SCLK有两个上升沿(或者两个有效沿,取决于配置),第一个沿控制复位电平采样,第二个沿控制信号电平采样。这里有一个关键点:不是所有的SCLK周期都必须执行两次采样,AD9826支持多种CDS模式,包括普通CDS、无CDS光电二极管模式、单采样模式等。对于CCD传感器一般都用普通CDS模式。

2.2 盯住这张图:AD9826核心时序参数解析

数据手册里画了几张时序图,其中最核心的是CDS采样时序和输出数据时序。我重点分析一下这几个参数:

时钟频率范围:SCLK最高12MHz,最低没有硬性限制,但考虑到芯片内部电容的漏电,建议不要低于1MHz,否则采样保持的电压会掉。我最终用6MHz就是考虑到这个余量。

CDS采样脉冲宽度:数据手册给出tCDS参数,也就是CDS采样脉冲的典型宽度在20ns左右。如果SCLK周期是166ns(6MHz),这个20ns只占12%的时间窗口,看起来不大,但对FPGA来说关键是:采样脉冲必须落在正确的位置,即输入模拟信号已经稳定并且CCD输出已经稳定后。

内部延迟参数tP、tDout等:这些定义了从CDS采样完成到数据出现在输出引脚之间的时间。这个延迟不是固定值,与SCLK频率有一定关系,但整体上接近一个像素周期减去一小段内部路径延迟。

输出锁存点:这是FPGA侧最容易出错的地方。AD9826在DOUTVALID信号拉高期间输出有效数据,FPGA必须在DOUTVALID为高且数据已经稳定以后再采样,不能一看到时钟边沿就去读。

我把关键时序参数整理成表,方便参考:

参数符号典型值备注
SCLK最高频率fCLK12MHz我实测6MHz最稳
CDS采样脉冲宽度tCDS20ns芯片内部自动产生
SCLK高电平时间tCLKH25ns占空比40%-60%
数据建立时间tDS15ns对FPGA侧而言
数据保持时间tDH10ns对FPGA侧而言
输出延迟tD12-20nsSCLK沿到数据有效
通道间串扰-60dB越小越好

这里着重说一下输出数据时序的理解。AD9826的输出数据由SCLK的某个边沿触发更新,数据在DOUTVALID有效期间保持稳定。FPGA读数据的时候,很多人图省事直接用SCLK的同一个边沿去采数据,结果发现时对时不对。原因在于芯片内部有一个很大的延迟,从SCLK沿发生到数据真正稳定在引脚上需要一个过程。如果FPGA采样沿太靠近芯片数据变化沿,建立时间不够,采到毛刺或者中间态太正常了。正确的做法是:用SCLK的反相沿(也就是相对于芯片数据触发沿偏移了半个时钟周期)来锁存数据,这样留给数据足够的稳定时间。这点在后面代码实现部分有具体体现。

2.3 PGA和偏置电平配置:别让图像产生“削顶”或“黑底发灰”

PGA增益设置关系到图像质量,这个环节很多初次调试的人会忽略。AD9826的PGA增益范围是从-2dB到+12dB,通过寄存器字节的低六位来配置,每步0.27dB左右。你可能觉得增益嘛,随便设个中间值就行。但实际调试中我发现,如果增益过大,信号被ADC削顶,高光部分的细节全部丢失,图像上一片死白;如果增益过小,整个画面灰蒙蒙的,暗部噪声都被放大了。

我的经验是:先用示波器看CCD输出最亮处的电压幅度,假设是Vmax,目标是把Vmax放大到ADC满量程的85%左右。因为ADC是16位的,满量程参考电压内部默认约4V(具体看寄存器配置),那目标电压大约3.4V。初始增益设为目标电压除以Vmax,听起来很简单,但实际工程上CCD边缘像素和中心像素响应不一致,保险起见把增益设低一档,留出余量,等整体图像出来再慢慢调。

偏置电平(CLAMP和OB相关)是另一个容易出问题的地方。AD9826有黑电平箝位功能,可以把CCD暗像素的输出电平钳制到AD转换的零点附近,确保黑色是纯黑而不是偏灰。如果这个没处理好,图像的暗部会有很明显的底色。

3. 实操过程与核心环节实现

3.1 Verilog接口模块设计:先看外部长什么样

在设计代码之前,先梳理一下AD9826的引脚和FPGA的对应关系。AD9826接口侧主要引脚包括:SCLK(时钟输入)、SDATA(SPI数据输入)、LOAD(SPI加载,相当于芯片选择)、CDS控制相关的输入,以及数字输出D0-D15、DOUTVALID(数据有效标志)、HSYNC输出等。

我写驱动代码时拆成两大部分:寄存器配置模块和像素数据读取模块。这两个模块分开的好处是,后续调试的时候可以单独仿真、单独定位问题。寄存器配置模块就是普通的SPI写时序,把需要的参数按手册指定的地址和数据格式写给芯片;像素数据读取模块则是等配置完成后,持续跟踪SCLK和DOUTVALID,把有效数据采进来。

核心接口定义如下:

module ad9826_driver #( parameter DATA_WIDTH = 16 )( input wire clk, // 系统时钟 input wire rst_n, // 复位 // AD9826 接口 output wire adc_sclk, // 像素时钟输出 output wire adc_load, // SPI加载信号 output wire adc_sdata, // SPI数据线 input wire adc_doutvalid,// 数据有效 input wire [DATA_WIDTH-1:0] adc_dout, // 16位并行数据 // 给上层的数据 output reg [DATA_WIDTH-1:0] pixel_data, // 输出的像素数据 output reg pixel_valid, // 像素数据有效标志 input wire cfg_start, // 启动配置 output reg cfg_done // 配置完成 );

这里有个细节:adc_sclk虽然是输入到AD9826的时钟,但它是从系统时钟分频或者PLL产生的。考虑到数据读取的时序关系,我在模块内部产生一个sclk_gen信号,一方面输出给AD9826的SCLK引脚,另一方面用一个延迟版本作为内部数据采样的时钟使能,这样能精确控制采样位置。

3.2 SPI寄存器配置:这些参数别配错

AD9826的SPI配置是三线的:SCLK、SDATA和LOAD。芯片规定数据在SCLK的下降沿被写入,LOAD拉高时加载到锁存器。仔细看手册有一句话:LOAD应该在最后一个SCLK边沿之后拉高,并且在下一个字节开始前拉低。这里最容易出错的是LOAD拉高的时机,如果最后一个SCLK下降沿还没出现就拉高LOAD,最后一位数据可能没写进去。我第一次调试就是这个原因,寄存器写入老是失败,排查了半天。

AD9826的寄存器地址我列一下最关键的几个:

寄存器地址功能重要位
配置寄存器00x00CDS模式、输入极性等bit2: 输入极性
配置寄存器10x01偏置电流、输出格式bit0: 二进制补码/偏移码
增益寄存器0x02PGA增益设置8位整数增益
相位寄存器0x03采样相位调整各bit对应延迟
箝位寄存器0x04黑电平箝位箝位门控设置

相位寄存器值得单独说一句。AD9826的CDS采样点相对SCLK的位置可以通过相位寄存器微调,步进标称约1.2ns。实际调试中,如果你发现图像明暗交界的边缘有偏色或者拖尾,往往可以通过微调这个寄存器改善。但这个寄存器修改要非常谨慎,每次改一个step然后看图像,改多了容易弄巧成拙。我的经验是先用默认值,等确认整体链路没问题了再回头微调。

配置模块的Verilog代码,我用一个简单的状态机来做。值得注意的地方是发送完一个字节后,要把LOAD信号保持高电平至少一个SCLK周期,让芯片内部锁存可靠。具体代码片段如下:

// SPI写寄存器状态机 localparam IDLE = 3'd0; localparam WRITE_BYTE = 3'd1; localparam LOAD_PULSE = 3'd2; localparam NEXT_REG = 3'd3; localparam ALL_DONE = 3'd4; reg [2:0] state; reg [7:0] reg_addr; reg [7:0] reg_data; reg [4:0] bit_cnt; reg [3:0] reg_cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= IDLE; adc_load <= 1'b0; adc_sdata <= 1'b0; cfg_done <= 1'b0; end else begin case (state) IDLE: begin if (cfg_start) begin state <= WRITE_BYTE; bit_cnt <= 5'd15; // 8位地址+8位数据,从最高位发 reg_cnt <= 4'd0; cfg_done <= 1'b0; end end WRITE_BYTE: begin // 前8位是地址,后8位是数据,在SCLK下降沿发送 adc_sdata <= (bit_cnt >= 8) ? config_regs[reg_cnt][bit_cnt-8] : config_regs[reg_cnt][7:0][bit_cnt]; // 此处省略sclk分频逻辑 if (sclk_fall) begin bit_cnt <= bit_cnt - 1'b1; if (bit_cnt == 0) state <= LOAD_PULSE; end end LOAD_PULSE: begin adc_load <= 1'b1; if (load_done) begin adc_load <= 1'b0; reg_cnt <= reg_cnt + 1'b1; if (reg_cnt == 4'd4) state <= ALL_DONE; else state <= WRITE_BYTE; end end ALL_DONE: begin cfg_done <= 1'b1; state <= ALL_DONE; end endcase end end

写SPI配置的关键点总结:一是SCLK尽量用低速,配置过程不需要快,几百kHz到几MHz都行;二是LOAD信号的时序严格按照手册来,拉高保持在SCLK停止之后;三是每写一个寄存器之后,最好留一点延时再写下一个,避免芯片内部状态还没稳定就收到新的配置字。我在FPGA里加了一个计数器做了几十个时钟周期的延时,实测非常稳妥。

3.3 像素数据读取:核心代码与锁存时机分析

像素数据读取模块是整个驱动里最关键的。前面说了,数据锁存时机要避开芯片输出数据的翻转沿。我的做法是:内部维护一个sclk_delay信号,这个信号相对于adc_sclk延迟了大约90度相位(四分之一周期),用这个信号来产生采样使能。

具体逻辑如下:AD9826在SCLK的上升沿更新输出数据(对大多数工作模式是这样),那么当SCLK上升沿到来时,数据线上实际上是旧的、在变化的、新的这三者的混合状态。为了保证FPGA采到的是新的稳定数据,就需要在当前SCLK上升沿之后、下一个上升沿之前的某个时间点去采样。理论上这个时间点越靠近下一个上升沿,数据稳定储备越充足。但也不能太靠后,万一芯片内部有个走线延迟导致数据更新点比理想位置晚怎么办?折中方案就是用90度相位偏移来采样。

代码实现时,我用系统时钟对SCLK周期进行计数。假设系统时钟100MHz,SCLK是6MHz,那么SCLK周期大约是16.7个系统时钟周期。我用一个计数器,从0数到16刚好一个SCLK周期。当计数到8的时候,就是SCLK周期的中间点,也就是相位偏移90度的位置。此时采样模块去锁存数据。

// 数据采样逻辑:在SCLK中间点采样 reg [4:0] clk_cnt; reg sclk_mid; wire sclk_r = adc_sclk; // 输入回芯片的时钟占空比50% always @(posedge clk or negedge rst_n) begin if (!rst_n) begin clk_cnt <= 5'b0; sclk_mid <= 1'b0; end else if (clk_cnt == 5'd16) begin clk_cnt <= 5'b0; sclk_mid <= 1'b1; // 一个周期只产生一个周期中点脉冲 end else begin clk_cnt <= clk_cnt + 1'b1; sclk_mid <= 1'b0; end end // 用sclk_mid去锁存数据,确保避开输出翻转沿 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin pixel_data <= 16'b0; pixel_valid <= 1'b0; end else begin pixel_valid <= 1'b0; // 默认无效,只有采样时刻有效 if (sclk_mid && adc_doutvalid) begin pixel_data <= adc_dout; pixel_valid <= 1'b1; end end end

用DOUTVALID信号做闸门,只有它拉高时采的数据才有效。AD9826的DOUTVALID和图像数据的对齐关系,手册里有时序图,我在实际调试中也用ILA(Integrated Logic Analyzer)抓过波形验证,确实验证了数据是在DOUTVALID拉高之后不久就有效了。采样的时钟中点脉冲位置,我做了参数化设计,就是为了方便调节。如果后续发现采到的数据有毛刺,可以调整这个参数往前或往后移几个系统时钟周期。

3.4 数据定标与像素重组:从16位原始码到可显示图像

拿到16位原始数据之后,不能直接往显示器上扔。AD9826默认输出是二进制补码格式,也就是说,满量程中点对应数字0,负信号对应负数,正信号对应正数。这是一种有符号表示,如果直接当无符号数传给后面的图像模块,画面会乱。

我处理方式是:判断数据MSB是否为1,如果是负数就取反加一得到绝对值,再移位量化到目标位宽。但更简单且常见的做法是直接把16位有符号数加上一个固定偏移,转换成无符号偏移码。因为CCD信号经过CDS之后是一个正的电压差,理论上应该是正值,加上偏移之后变成无符号表示就很自然。

差分模式下的数据定标逻辑我这样写:

// 二进制补码转偏移码,并截取高12位用于图像显示 reg [15:0] offset_bin; reg [11:0] pixel_out; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin offset_bin <= 16'b0; pixel_out <= 12'b0; end else begin offset_bin <= pixel_data + 16'h8000; // 加偏移转偏移码 pixel_out <= offset_bin[15:4]; // 右移4位为截取高12位 end end

加0x8000这个偏移在数学上就是把原本以0为中心的补码范围映射到0到65535的无符号整数范围。这样做的效果是黑色的像素大约在0附近,白色的像素在65535附近。截取高12位是因为图像显示或者后续算法处理不一定需要完整的16位精度,12位已经可以有4096级灰度了。如果做医学影像或者科学应用需要高精度,可以直接保留16位。

3.5 仿真与上板验证:自己踩过的坑和检查方法

代码写完之后,我先做了行为级仿真。仿真环境里我需要给AD9826的行为建模,但如果手头没有仿真模型,最简单的做法是根据手册的时序参数来写一个简化模型:接收SCLK,按寄存器配置的输出时序产生DOUTVALID和DOUT。仿真重点关注三件事:第一,SPI配置是否正确写入;第二,AD9826的SCLK频率和占空比是否满足要求;第三,数据采样点是否在有效窗口内。

仿真通过之后就是上板调试。我用的是Xilinx的FPGA开发板,抓波形的工具是ILA核。上板调试第一件事不是看图像,而是先把SCLK测一下,看引脚上输出的是不是6MHz,占空比是否合理。如果占空比不对,后面全是玄学错误。然后抓DOUTVALID和数据。我第一次上板时发现DOUTVALID几乎一直为高,数据也是乱的,排查了半天,结果是我把AD9826的SPI配置写错了——寄存器地址位和数据位顺序搞反了。手册上明确说了先发地址再发数据,我代码里发的是现发数据再发地址,检查仿真波形的时候居然没发现(因为仿真模型没有严格校验)。后来我把配置模块的仿真代码写得严谨了一些,每个寄存器的值都验证了一遍,问题就暴露出来了。

这里强烈建议:有条件的在AD9826数据手册里把每个寄存器的默认值、推荐值再核一遍。很多问题不是我写的代码,而是寄存器配置和数据手册不符,比如相位寄存器的默认值在某些版本芯片上表现不一样。

4. 常见问题与排查技巧实录

4.1 图像出现固定竖条纹或网纹:多半不是FPGA的锅

这类问题的根源往往是模拟信号质量。CCD输出到AD9826输入之间的走线如果太长、屏蔽不好,或者电源噪声偏大,CDS采样后叠加了共模干扰,很难在后端滤除。排查的时候,我习惯先用示波器看CCD输出节点、AD9826模拟输入引脚的波形。正常情况下,每个像素周期对应的电压台阶应该是清晰稳定的,如果看到有高频毛刺叠加在台阶上,先解决模拟走线。

CDS本身对低频共模干扰抑制得不错,但对高频干扰效果有限。AD9826的模拟电源和数字电源要分开走,最好在芯片电源引脚旁边就近放0.1uF和10uF的去耦电容。这是一个很小的细节,但我见过很多项目因为这一步没做好,图像质量始终上不去。

4.2 数据对不上:像素数和CCD实际输出数差一个

CCD传感器一行像素可能是2000个,但AD9826输出的数据可能是2005个或者1998个。这个问题多半是同步没找对。AD9826输出的HSYNC信号对应的图像数据在它之后的一个或两个像素周期才出现,不同传感器差距很明显。

我调试时用了一个笨办法也最有效:CCD传感器给一个全黑遮光环境,然后观察HSYNC之后输出的数据。理论上黑色像素的数值应该在零点附近,如果有几个像素明显偏大,那就是同步偏了。调整方法是在FPGA侧对HSYNC打拍,延迟1到2个像素周期对齐数据起始位置。

具体操作是在像素读取模块里加一个行同步计数器,HSYNC拉高后第N个像素视为行首,N根据实测调整。我在系统里做了一个寄存器来动态配置N,调试时用ILA观察数据,直到黑色行数据的起始位置正确为止。

4.3 图像左右错位:很有可能是采样相位不对

这个问题的特征是对着一个竖直的对比强烈的条纹目标,图像上黑白分界线左右偏移或者边缘模糊。因为CCD上同一个物理像素被采样到哪个位置取决于你对AD9826输出数据的取样时刻。如果采样点太靠近数据变化沿,采到的可能是上一像素和当前像素的混合值,表现出来就是边缘模糊。

处理方法是微调前面提到的采样相位参数。我在代码里预留了一个samp_delay参数,可以在线通过串口工具调整,每次调整约3ns,观察图像边缘锐度变化。实测下来,当采样点落在数据窗口中间偏后35%的位置时,图像表现最好。这个比例和AD9826手册上推荐的建立时间有关,太多余的延时会吃进下一个像素的数据,一定要注意。

4.4 寄存器写不进或配置偶尔失效:检查LOAD时序和SCLK频率

这个问题我遇到过一次,表现是芯片上电后第一次配置有效,复位后再次配置偶尔失效。排查发现是我配置模块的LOAD拉高持续时间太短,只有两个系统时钟周期,约20ns,远小于手册要求的至少一个SCLK周期的LOAD高电平时间。修改方案是LOAD拉高后保持至少四个系统时钟周期,并且等SCLK完全停止在高电平之后再拉高LOAD。修改后问题没有再出现过。

另外还需要注意SPI配置在SCLK下降沿发送数据这个细节。AD9826手册里有一句口吻很明确的话:“Data is clocked into the part on the falling edge of SCLK。”我在仿真里一直用下降沿打数据,上板的时候实际波形才反映出来。如果你用的是上升沿触发发送的SPI,配置有时候能成功有时候失败,很影响调试心情。

4.5 一个容易被忽略的问题:输出数据位序和字节顺序

AD9826是16位并行输出,但它在内部输出格式上有一个选择:可以输出高字节在前也可以输出低字节在前。手册里配置寄存器1的bit1控制这个格式。我当时没仔细设置,发现图像数据MSB和LSB颠倒,整个图像变成乱码一样的噪点。

配置寄存器1的bit1设为0时输出高字节优先,D15是最高位;设为1时则相反。我们常用的是高字节优先,所以把这个位配置为0。如果你自己用的系统是小端对齐,那就设1,关键是和你的后续数据使用方保持一致。我第一次调的时候这个位忘设了,图像出来全是雪花,排查了很久才发现是数据位序问题。

4.6 调试经验速查表:遇到问题先去查哪里

我把这段时间调试遇到的所有问题整理成一个速查表,下次再遇到类似现象可以直接对号入座:

现象大概率原因排查优先级
图像全是雪花噪点数据位序错误/采样相位严重偏移
图像有网纹模拟电源噪声/走线干扰
图像偏灰底黑电平箝位没配置好
高光处一片白PGA增益太大
整体很暗且噪声大PGA增益太小
行方向错位HSYNC对齐参数不对
图像边缘模糊采样相位偏早或偏晚
寄存器配置无效LOAD时序/数据位序错误低(但调试时第一优先级)

5. 扩展思路与后续演进方向

AD9826驱动调通只是一个起点,实际项目中它前面的CCD驱动时序和后面的图像处理往往是更大的工作量。

关于CCD传感器驱动时序,常见的是需要FPGA产生CCD的水平转移时钟、垂直转移时钟、复位栅极脉冲等。AD9826虽然集成了CDS,但并不会为CCD生成这些驱动脉冲,它只是被动采样CCD输出信号。所以一个完整的图像采集系统要有两套时序引擎:一套是CCD的驱动时序生成器,另一套是AD9826的采样数据读取器。这两套时序必须严格同步,通常做法是共用同一个像素时钟计数器,从计数器的不同相位切出各自需要的脉冲。

后续如果需要在FPGA侧做实时图像处理,比如滤波、自动曝光、直方图均衡,AD9826输出的数据流是逐像素同步的,处理逻辑可以按行像素进行流水线设计。这里特别提醒一点:AD9826的像素速率如果是6MHz,那么一行2000像素的时间大约是333us,一秒钟3000行,这对于大多数FPGA的实时图像处理绰绰有余。但如果在高速应用里用满12MSPS的采样率,那么数据处理管道每个像素只有约83ns的时间,这时候FPGA时序布局就要格外留意了。

在项目演进过程中,我从AD9826转向过更现代的AFE芯片比如AD9995、ADDI7000等,它们的原理和AD9826类似,不过把CDS、PGA、ADC做得更精细,寄存器也更多了。但有了AD9826的调试经验,新芯片上手速度快很多,因为底层都是相同的信号链逻辑:配置、采样、锁存、数据重组。这也是我为什么把这篇时序分析和代码经验写这么细——技术会换代,但方法论可以沉淀下来反复用。

最后再分享一个我自己的习惯:不管芯片有多老,拿到数据手册先别急着写代码,静下心把每一张时序图看明白,把每一个参数的意义搞清楚。AD9826是一颗已经成熟了十几年的芯片,资料非常全,踩过的坑也都在各个老工程师的博客和论坛帖子里出现过。花半天时间研读时序图,比上板瞎调一星期有效得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询