ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AD9826 CCD模拟前端时序分析与Verilog控制模块实现

AD9826 CCD模拟前端时序分析与Verilog控制模块实现 做CCD图像采集的项目时AD9826 是绕不开的一个前端芯片。这颗来自ADI的模拟前端AFE把CCD输出的模拟信号直接变成16位数字量集成了相关双采样CDS、可变增益放大VGA、暗电平钳位和ADC一颗芯片就能搞定三通道R、G、B的信号链。如果你正在做扫描仪、工业相机或者医疗影像设备大概率会在调研时遇到它。但AD9826有个门槛它不像普通ADC那样给个时钟就出数据配套的CDS采样时钟、钳位脉冲、串口配置和输出数据对齐关系第一次接触时确实容易栽跟头。这篇博文我想把AD9826的关键时序掰开揉碎讲清楚并给出我用Verilog实现的一个完整控制模块设计思路包括时序怎么生成、配置寄存器怎么写、输出数据怎么接收对齐。内容偏实战代码思路和仿真经验都会覆盖适合正在做CCD前端采集、手里刚拿到数据手册却不知道从哪下手的工程师。1. AD9826芯片特性与选型思路拆解1.1 这芯片到底解决什么问题CCD传感器的输出非常特殊它输出的不是一个干干净净的电压而是一个被复位噪声污染的脉冲信号。CCD每个像素的输出包含一个复位电平和一个信号电平真正的光生电荷信息是两者之差而且差值非常小往往只有毫伏级别。如果直接拿普通ADC去采复位噪声会把有效信号淹没根本分不清哪是光生信号哪是噪声。AD9826这类CCD模拟前端做的事情就是先用相关双采样技术把这个差值提取出来。它的架构可以简化成CCD信号进来后经过CDS模块在复位电平期采一个样在信号电平期再采一个样两个采样值相减复位噪声因为相关性被抵消掉。然后信号进入可变增益放大器把小信号放大到ADC满量程范围内再经过暗电平钳位校准黑电平最后16位ADC输出。这一整套信号链是专门为CCD传感器优化的用分立器件搭也能实现同样功能但体积、功耗、匹配性完全没法比。当初我选这颗芯片主要看重的几个点是三通道独立可编程增益每个通道能单独调节方便做白平衡、16位分辨率、单颗芯片支持20MHz像素时钟以下的应用场景。市场上还有AD9824、AD9920等兄弟型号但AD9826的资料和应用笔记最多社区讨论也丰富踩坑参考多对新手友好度高。1.2 关键引脚与功能模块的对应关系先梳理一下引脚和内部模块的对应关系这是后面写时序代码的基础ADCCLKMCLK主时钟输入所有内部时序都以它为基准。典型频率范围几百kHz到20MHz具体上限要看数据手册中的电气参数表。CDSCLK1、CDSCLK2相关双采样的两个采样开关时钟。它们必须在ADCCLK的某个相位区域内产生拿捏好位置直接关系到信噪比。CLAMP暗电平钳位脉冲。当这个信号有效时内部会把当前输入信号与目标黑电平做比较调整暗电平校准DAC。RIN、GIN、BIN三路CCD模拟信号输入分别对应红绿蓝通道。每个通道内部有独立的CDS和VGA电路。G1、G0增益模式选择引脚也可以和寄存器配合使用。它决定内部增益范围是0-6dB、0-12dB还是0-18dB具体档位以数据手册增益表为准。DOUT[15:0]16位数字输出总线。根据配置可以工作在“三通道独立输出”模式也可以工作在“单通道分时输出”模式一个总线轮流输出R、G、B。SL、SDATA、SCLK、SLOAD三线串口配置接口。SL选择串行模式SLOAD作为加载使能SCLK提供移位时钟SDATA传数据。DRVDD/DRGND、AVDD/AGND、VREF数字电源、模拟电源和基准电压引脚。这些引脚里最容易被忽略的是G1、G0和SL的上下拉配置。上电时如果SL状态不确定芯片可能进入并口模式而不是串口模式导致寄存器写不进去。我一般会在FPGA里用电阻固定拉高或拉低确保上电就能确定工作模式。2. AD9826核心时序拆解与实操要点2.1 相关双采样时序CDSCLK1和CDSCLK2的位置决定成败AD9826的CDS工作原理不复杂但对时序位置的要求很高。每个像素周期内内部有4个相位区间复位电平期、复位保持期、信号电平期、信号稳定期。CDSCLK1负责采样复位电平CDSCLK2负责采样信号电平两个采样点之间的时间差就是CDS的关键。从数据手册的时序波形来看CDSCLK1和CDSCLK2都是高电平有效脉冲持续时间通常是一个ADCCLK周期左右。它们必须在ADCCLK的下降沿附近产生具体相位偏移量以手册提供的tCDS参数为准这个参数在不同频率下略有不同一般在几纳秒到十几纳秒之间。如果CDSCLK1采的太早复位电平还没完全稳定采的太晚又会侵入信号建立区域导致采样值不准确。CDSCLK2同样如此必须在CCD输出信号完全建立之后再采样留足建立时间。实际工程项目中CCD驱动芯片比如AD9826的前级CCD时序发生器输出的像素有效信号PIXVALID和行同步信号HSYNC可以帮我们对齐CDS时钟。最稳妥的做法是在PIXVALID有效期间启动一个像素计数器每个像素的周期分成M个时钟节拍然后在固定的节拍位置产生CDSCLK1隔N拍后产生CDSCLK2。这个M和N的取值需要根据实际CCD输出波形用示波器测量来标定不能只看理论值。我记得第一次调试时CDSCLK2的位置放在了信号刚建立的时候导致图像暗部噪声特别大。后来把CDSCLK2往后移了半个像素周期信噪比立刻提升了好几个dB。这个经验和数据手册上“尽量在像素周期后段采样”的建议是一致的但具体挪多少还得靠实际波形说话。2.2 输出数据的对齐关系DOUT与ADCCLK的建立保持时间AD9826的16位数据输出与ADCCLK的关系是设计接收逻辑的关键。数据手册给出的典型时序是数据在ADCCLK的下降沿之后有效在下一个下降沿之前必须被接收端采走。也就是说如果你用FPGA在ADCCLK的上升沿采样DOUT大概率能采到稳定的数据但前提是时钟偏斜和PCB走线延迟不会侵蚀掉建立时间。具体参数上数据手册会给一个tOD输出延迟和tODZ输出高阻延迟单位是ns级。AD9826在20MHz主时钟下典型tOD在10-20ns左右这个值会随电压、温度有偏差。如果你的ADCCLK频率较高必须认真约束FPGA的时序路径否则在芯片内部产生的ADCCLK经过引脚输出、PCB走线、FPGA输入引脚、全局时钟网络这一大圈后相位可能已经偏了。我的做法是在FPGA内部用PLL把ADCCLK再生成一份相位偏移45度到90度。用这个偏移后的时钟去采DOUT刚好能落在数据窗口的中心。这种方法比直接用ADCCLK采样鲁棒得多尤其在PCB布线不完美、走线长短不一的场景下能显著降低误码率。输出模式也要特别注意。在“三通道独立输出”模式下DOUT[15:0]输出三路R通道的数据只在R通道的像素周期出现G、B通道同理。但在“单通道分时输出”模式下DOUT[15:0]在一个像素周期内依次输出R、G、B通道的数据你必须额外用一个输出指示信号数据手册里叫DATA_VALID之类的辅助信号实际工程中需要自己根据配置模式来识别数据归属来区分当前总线上是哪一通道的数据。2.3 三线串口配置时序SLOAD、SCLK、SDATA的配合方式AD9826的寄存器配置接口是类似SPI的三线串口但协议细节和标准SPI略有不同。SL引脚置高时芯片进入串行配置模式。配置过程需要SLOAD先拉高然后SCLK产生16个上升沿每个上升沿同步移入一位SDATA数据先传地址MSB在前再传数据MSB在前。16位传完后SLOAD拉低完成一次写入。这里容易踩坑的点有三个首先是SLOAD的时序位置它必须保持高电平直到整个16位数据传完不能在地址传完后就拉低其次是SLOAD拉低后的保持时间必须满足寄存器锁存要求如果立刻拉高进行下一次写入有可能导致数据未锁存最后是SCLK与SLOAD的时序关系新的一帧配置传输必须在SLOAD拉低后重新开始不要在SLOAD高电平期间试图通过暂停SCLK来分包传输数据。实际代码中我习惯把串口配置做成一个独立的小状态机每个寄存器的写入流程固定为拉高SLOAD - 串行移出地址和数据 - 拉低SLOAD - 等待几个时钟周期再操作下一个寄存器。这样做的好处是如果后面加通道增益、偏置校准等寄存器只需要在寄存器表中增加条目即可状态机本身不用改。3. Verilog控制模块设计与实现3.1 顶层模块划分与端口定义我在写AD9826的Verilog控制模块时按照功能把整个逻辑分成了四个子模块这样代码维护起来清晰调试时也能快速定位问题。第一个是时钟管理模块负责用PLL生成ADCCLK以及对ADCCLK做相位偏移生成采样时钟第二个是时序生成模块核心是一个像素周期计数器从HSYNC有效开始对每个像素周期计数在预定的计数值位置生成CDSCLK1、CDSCLK2、CLAMP脉冲第三个是串口配置模块通过状态机实现三线串口写入寄存器第四个是数据接收模块负责采样DOUT、识别通道、拼接像素数据并生成同步信号。这样的划分有两点好处一是各个模块之间通过简单的信号连接减少耦合二是每个模块可以独立仿真比如先把时序生成模块跑通再单独验证串口配置最后联调问题定位速度快很多。顶层模块端口大致如下module ad9826_ctrl ( input clk_50m, // 系统时钟 input rst_n, // 复位 input ccd_hsync, // CCD行同步 input ccd_pix_valid, // CCD像素有效 output adc_adcclk, // AD9826 主时钟 output adc_cdsclk1, output adc_cdsclk2, output adc_clamp, output adc_sload, output adc_sclk, output adc_sdata, input [15:0] adc_dout, output pixel_valid, // 输出像素有效 output [13:0] pixel_data // 拼接后的像素数据 );pixel_data位宽取14位是我的习惯因为AD9826的16位输出在工程中常根据信号幅度截取高14位。如果你需要全分辨率自然还是保留16位这里按你的应用灵活调整。3.2 像素计数卡与CDS时钟生成逻辑时序生成模块的核心是个自由运行的像素计数器。每当HSYNC有效或PIXVALID上升沿到来时计数器清0重新开始。每个像素周期内ADCCLK的周期数即每个像素对应的时钟节拍数取决于AD9826的配置和CCD的输出格式。假设CCD像素输出频率是5MHzADCCLK频率也是5MHz那一个像素周期就是1个ADCCLK周期所有内部时序都在同一个时钟周期里切换这种情况对时序裕量最不利。如果ADCCLK是10MHz而像素是5MHz那每个像素有2个时钟节拍CDS时序就好做得多。我实际用得比较多的配置是ADCCLK跑10MHzCCD像素时钟5MHz这样每个像素周期对应2个ADCCLK周期。此时我在第一个ADCCLK周期内产生CDSCLK1在第二个ADCCLK周期内产生CDSCLK2和CLAMP。用计数器实现类似这样reg [3:0] cnt_pixel; wire ccd_clk_en; always (posedge adcclk_int or negedge rst_n) begin if (!rst_n) cnt_pixel 4d0; else if (ccd_hsync || !ccd_pix_valid) cnt_pixel 4d0; else if (ccd_clk_en) cnt_pixel (cnt_pixel PIXEL_TIMES - 1) ? 4d0 : cnt_pixel 1b1; end assign cdsclk1 ccd_pix_valid (cnt_pixel 4d0); assign cdsclk2 ccd_pix_valid (cnt_pixel 4d1); assign clamp ccd_pix_valid (cnt_pixel 4d1);这种同步赋值的写法比组合逻辑产生脉冲更可靠能避免毛刺。PIXEL_TIMES参数定义为每个像素的时钟节拍数可以做成parameter供顶层修改方便适配不同CCD格式。这里有个细节值得提CDSCLK1、CDSCLK2的高电平宽度如果只持续一个ADCCLK周期在一些CCD输出信号建立时间比较长的场景下可能不够。AD9826手册中CDS采样开关的闭合时间是有要求的如果高电平时间太窄内部采样电容可能采集不充分。所以有些工程师会把CDSCLK脉冲拓宽到两个ADCCLK周期代价是脉冲位置变得不那么“尖”但换来更可靠的采样。我建议在仿真时对比一下不同脉冲宽度下的输出图像质量选择一个合适值。3.3 串口配置状态机实现串口配置模块用三段式状态机实现核心逻辑是把“传输一组16位数据”作为一个任务。状态机包含四个状态IDLE、START、SHIFT、DONE。IDLE状态等待配置请求信号START状态把SLOAD拉高准备开始传输SHIFT状态在SCLK的上升沿逐位输出数据用一个3位计数器记录已传输位数到16后进入DONEDONE状态把SLOAD拉低并产生一个寄存器写入完成脉冲。三线接口的波形要求是SLOAD高电平期间SCLK连续产生16个脉冲。SDATA在SCLK上升沿前建立足够时间在上升沿后被采样。我用的是SCLK空闲为低、上升沿采样SDATA的模式。AD9826手册对这种模式的描述比较明确照着做就行。reg [15:0] shift_reg; reg [4:0] shift_cnt; reg sclk_reg; reg sdata_reg; reg sload_reg; localparam IDLE 2d0, START 2d1, SHIFT 2d2, DONE 2d3; always (posedge clk_50m or negedge rst_n) begin if (!rst_n) begin state IDLE; end else begin case (state) IDLE: if (cfg_start) begin state START; shift_reg {cfg_addr, cfg_data}; // 16位8地址 8数据 shift_cnt 5d16; end START: begin sload_reg 1b1; sclk_reg 1b0; state SHIFT; end SHIFT: begin if (shift_cnt 5d0) begin state DONE; end else begin // SCLK产生每个位周期做一次上升沿 ... end end DONE: begin sload_reg 1b0; cfg_done 1b1; state IDLE; end endcase end end实际工程中SLOAD拉低之后AD9826内部需要一定的锁存时间所谓“寄存器写入完成后等待几个时钟周期”非常有必要。我在DONE状态至少停留8个系统时钟周期再回IDLE确保芯片内部逻辑稳定。3.4 数据接收与通道对齐技巧数据接收模块的难点不在“采样DOUT”本身而在于不同输出模式下的通道对齐。在单通道分时输出模式下AD9826一个像素周期内会依次送出R、G、B通道的16位数据。接收端必须知道当前总线上是哪一通道的数据才能正确拼接、缓存和输出。如果你在配置寄存器时选择了三通道独立输出模式那每个通道有独立的DOUT引脚接收逻辑最省事每个通道单独一组采样寄存器即可。但如果选择单通道输出节省引脚就需要一个通道指示信号。AD9826在这个模式下会有一个内部标志或外部引脚用于区分通道顺序通常顺序是固定的像素周期内先输出R再输出G最后输出B。你的接收状态机只需要在每个像素周期内按顺序把三组数据锁存到对应的寄存器里即可。关键是要在正确的采样窗口采样DOUT。我前面提到用相位偏移后的采样时钟偏移量大约30度到60度的ADCCLK周期这样能落在数据有效窗口的中间。接收端的代码大致是always (posedge sample_clk or negedge rst_n) begin if (!rst_n) begin r_ch_data 16d0; g_ch_data 16d0; b_ch_data 16d0; end else if (pixel_cycle_cnt CH_R) begin r_ch_data adc_dout; end else if (pixel_cycle_cnt CH_G) begin g_ch_data adc_dout; end else if (pixel_cycle_cnt CH_B) begin b_ch_data adc_dout; end end其中pixel_cycle_cnt是接收模块内部的像素计数器它需要和时序生成模块保持同步通常通过HSYNC来对齐起点。这个模块在仿真阶段容易发现问题如果接收计数器和数据通道不同步图像会出现红绿蓝通道错位、颜色混乱的现象。我的排查方法是先发一个单像素的测试图像抓取波形确认数据顺序再进入整帧调试。4. 实际调试与仿真验证经验4.1 用Icarus Verilog搭建仿真环境在写AD9826控制代码时仿真比直接上板重要得多。因为CCD和AD9826都是物理器件出现问题很难分辨是模拟前端的问题还是数字逻辑的问题。用仿真先把数字逻辑验证清楚了上板调试时就能把精力放在模拟信号上。我用Icarus Verilogiverilog搭建了一个基础仿真环境写了一个简单的AD9826行为模型模拟CDS采样和16位数据输出。模型不需要实现芯片内部模拟功能但必须模拟时序关系根据时序生成模块送来的CDSCLK1、CDSCLK2、CLAMP信号在固定时刻更新DOUT数据。这样一来测试平台可以完整验证整条链路配置寄存器 - 产生CDS时序 - 接收DOUT - 还原像素数据。我用Verilog写了一个小的SCPI风格的测试激励模拟CCD输出一行像素测了三个通道的数据恢复是否正确。仿真时甚至能检查CDS采样位置是否合理因为行为模型可以把DOUT数据设置为与采样时钟位置相关的值。4.2 仿真波形的关键检查点仿真时我重点检查三处波形位置第一处是CDSCLK1和CDSCLK2的上升沿是否在预期的像素计数值位置。如果一个像素周期是2个ADCCLK周期两个CDS脉冲不应该重叠并且保持合适的间隔。如果它们重叠了说明CDS采样窗口太窄或者说时序生成逻辑有bug。第二处是SLOAD从高到低的时刻是否晚于最后一个SCLK上升沿。如果SLOAD提前拉低了寄存器写入失败芯片的配置会保持默认值。仿真时我习惯把SLOAD、SCLK、SDATA三个信号放大波形视图逐个时钟周期核对位顺序。第三处是采样时钟对DOUT的采样点是否在数据有效窗口内。仿真里无法体现PCB延迟但可以通过在行为模型里加一个tOD延迟来实现接近真实的效果。如果你的采样时钟沿在这个扩展延迟下仍然能采到正确数据上板后出问题的概率会小很多。4.3 上板调试踩过的坑和排查方法上板调试阶段我踩过几个典型的坑写出来大家避一避。第一个坑是电源噪声导致AD9826输出跳动。在某个版本PCB上AVDD和DRVDD走线靠得太近数字部分翻转时的噪声耦合到模拟电源上导致ADC输出低几位频繁跳动。解决办法是把模拟电源和数字电源分开布线必要时在AVDD引脚旁边加一个10uF的钽电容和一个100nF陶瓷电容组合去耦。第二个坑是ADCCLK信号质量差。FPGA输出ADCCLK时如果IO驱动强度设置太大或走线过长信号会出现振铃导致AD9826内部时序不稳定。建议用示波器检查ADCCLK的过冲和振铃情况必要时在FPGA的IO配置里降低驱动强度或者在芯片引脚附近串联一个22欧姆的匹配电阻。第三个坑是CLAMP信号幅值不足。AD9826要求CLAMP输入高电平至少要满足数字高电平的门限如果驱动能力不够导致高电平被拉低到门限附近暗电平钳位就会时好时坏图像黑电平漂移。用万用表实测CLAMP引脚高电平电压确认在数据手册要求的VOH以上。排查顺序上我一般先看电源纹波再看时钟信号质量最后才查数字逻辑。因为模拟前端的很多诡异问题本质上都是电源和时钟惹的祸。5. 常见问题与调试速查表5.1 寄存器配置相关的典型问题现象可能原因检查/解决办法写寄存器后芯片行为不变SL引脚电平不对芯片处于并行模式确认SL上拉到高电平并检查焊接是否虚焊串口写入后增益无变化SLOAD拉低太早数据未锁存把SLOAD高电平持续时间拉长到16个SCLK周期以上并在低电平后加延时图像整体偏暗/饱和VGA增益配置错误检查增益寄存器和G1/G0引脚的组合是否匹配期望增益档位三个通道颜色错位单通道分时输出下接收计数未对齐用单像素测试图示波器或仿真确认通道顺序5.2 时序和信号完整性相关问题现象可能原因检查/解决办法输出数据在边界处抖动采样时钟相位未对齐到数据中心用PLL相位偏移确保采样点在数据有效窗口内暗部噪声大CDSCLK2采样过早信号未建立用示波器看CCD输出信号将CDSCLK2往后移半个像素周期图像整体偏绿或偏红通道间增益不一致分别调节R/G/B三通道增益寄存器或用白平衡算法校准图像有条纹干扰接地环路或驱动能力不足检查模拟地和数字地单点连接走线是否过长必要时加缓冲器帧起始位置不对HSYNC同步处理错误在FPGA内部用两级触发器同步HSYNC并做边沿检测5.3 排查工具与经验心得调试AD9826示波器至少要有两个通道最好四个通道。我用的是四通道示波器把ADCCLK、CDSCLK1、CDSCLK2、DOUT[0]或DOUT[15]挂上对比观察能直观看到采样点是否落在稳定区域。如果没有示波器完全靠仿真调试那就要在仿真里加足够多的时序余量验证上板后再逐步放宽约束。另外强烈建议在PCB上预留测试点尤其是ADCCLK、CDSCLK1、SLOAD、DOUT这四根线方便调试时测量。别小看这几个测试点关键时刻能省你好几个小时。软件开发层面FPGA工程里建议把AD9826寄存器的配置值做成一个寄存器表使用SystemVerilog的struct或者简单的parameter数组保存在单独的模块里。后期调增益、调偏置时不需要改代码逻辑只改数据就能生效。这个设计习惯帮我在项目后期调参时省了不少事。写在最后的个人体会AD9826的时序控制整体不算复杂但它让你对“模拟前端芯片”有了实打实的敬畏——每一个脉冲的位置差几纳秒最后图像质量就差一个档次。在做的过程中我越来越体会到数据手册上那一堆时序参数不是摆设而是决定系统性能的命门。尤其是CDS两个采样脉冲的位置如果你有时间建议在项目里专门预留一两周做参数标定用不同位置采样同一场景对比图像噪声和细节找到最优位置。这比事后拿图像去噪做后处理要划算得多。如果你手头恰好正在做类似的CCD采集项目希望这篇关于时序分析和Verilog实现的经验对你有帮助。有具体问题欢迎在评论区交流踩过的坑都值得拿出来晒一晒。
返回列表