ARTICLE DETAIL

资讯详情

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

CIS+AD9822+FPGA扫描采集系统设计:从300DPI到时序调试

CIS+AD9822+FPGA扫描采集系统设计:从300DPI到时序调试 接到一个文档扫描设备的核心采集板需求时客户最在意的就三件事分辨率要实打实300DPI、扫描速度要够快、图像畸变要小。原来那套用CMOS面阵相机翻拍的方案体积大边缘畸变明显扫到书本装订线附近还会糊。最后定的方案是CIS接触式图像传感器AD9822模拟前端FPGA做控制CIS贴着纸面走一条扫描线上每个像素的光路几乎等长分辨率天然均匀配合FPGA调时序也灵活。整套链路里CIS负责光电转换AD9822做相关双采样和16位AD转换FPGA负责所有驱动时序、数据锁存和向外传输。这篇文章会把系统拆解、300DPI背后的像素账、AD9822配置、FPGA时序设计以及调试阶段踩过的坑全部捋一遍给想上手CIS采集或者正在做扫描设备的朋友一个可以直接照抄的底稿。1. 一条扫描线背后的完整链路先把系统看懂1.1 三个模块怎么分工CIS传感器模块是光电转换部分。它本质是一条长线阵的光电二极管阵列内部还集成了LED光源、柱状透镜和玻璃条。扫描时LED照亮纸面反射光经过透镜聚焦到感光面上光生电荷在积分时间内积累行扫描开始后按照驱动时钟逐像素把电荷变成模拟电压串行输出。和面阵相机最大的区别是CIS不需要镜头对焦工作距离极短几乎贴着纸面所以整条线上的倍率一致性非常好300DPI的边缘和中心一样准。AD9822是模拟前端AFE干三件关键的事相关双采样CDS、可编程增益放大PGA和16位模数转换。CDS是CIS/CCD信号链里绕不开的一环。传感器每个像素的输出实际上是“复位电平”和“视频电平”叠在一起的复合波形CDS在一个像素周期内分别采样这两个电平再做差就能把复位噪声、开关馈通这些共模干扰消掉。不用CDS的话图像上的固定图案噪声会非常扎眼低照度下根本没法看。FPGA是整条链路的指挥。它负责给CIS产生驱动时序ROG、SHIFT、CLK给AD9822提供采样时钟并通过3线串口配置内部寄存器然后在正确的时刻锁存16位数字量做行缓存和像素重组最后把数据通过USB或千兆网发出去。说白了所有“按时钟周期精确动作”的活都是FPGA的这也是它在这类系统里不可替代的原因。1.2 为什么是FPGAAD9822而不是MCU方案有人会问CIS模块输出的模拟信号用MCU片内ADC直接采行不行答案是可以采但基本做不好。CIS逐像素输出的速率通常要几MHz到十几MHzMCU片内ADC在采样率、16位精度、CDS能力上都不够。AD9822这类专用AFE就是为这个场景设计的15MSPS转换率、16位分辨率、内置CDS和PGA一颗芯片就把模拟前端全包了。FPGA更不用多说。CIS的ROG脉冲宽度、SHIFT时钟频率、采样时刻全都要求逐周期精确单片机用IO口翻转时钟的话抖动大、频率上不去多路信号同步更是噩梦。FPGA用状态机加时钟约束来控制每个沿的行为都是确定的调试的时候还能用逻辑分析仪抓内部信号效率高得多。1.3 信号是怎么流动的以一行扫描为例完整信号流是FPGA发出ROG脉冲启动电荷转移 → 传感器内部把光生电荷搬到移位寄存器 → FPGA连续输出CLK/SHIFT时钟每个时钟沿把一位像素推到模拟输出端 → AD9822在每个像素周期内做CDS采样和AD转换 → 16位数字量随DATACLK输出 → FPGA用DATACLK锁存数据判断有效像素窗口写入FIFO → 上一行数据同时被读出并打包发送。搞明白这个流向之后后面所有设计都围绕一件事让每一步的事件时刻和前后级的时序要求对齐这就是“时序设计”的全部核心。2. 300DPI的参数账先算清楚再选型2.1 DPI、传感器分辨率、物理像素的关系300DPI的意思是一英寸内有300个采样点。1英寸等于25.4mm所以每个像素对应的物理尺寸是25.4/300≈0.0847mm约84.7μm。如果扫描A4纸宽度210mm那么一线需要的像素数是210÷25.4×300≈2480个像素这还没算传感器两端的光学余量和内部的暗像素。所以市面上A4幅面CIS模块的有效像素规格通常是2592或者2660多出来的部分一方面给光学对准留余量另一方面模块内部本来就有dummy像素用于时序衔接。要真做到300DPI传感器的有效像素数必须不低于2480否则只能靠软件插值那叫“假300DPI”。2.2 行速率和像素时钟怎么推导行速率取决于扫描速度和DPI像素时钟取决于行速率和单行像素数。我按两种典型速度算给你看假设扫描速度60mm/s常规文档扫描速度每秒线数 60÷25.4×300 ≈ 709行/秒行周期 1/709 ≈ 1.41ms像素时钟 2592÷1.41ms ≈ 1.84MHz假设扫描速度300mm/s高速扫描场景每秒线数 300÷25.4×300 ≈ 3543行/秒行周期 1/3543 ≈ 282μs像素时钟 2592÷282μs ≈ 9.19MHz9.2MHz离AD9822的15MSPS上限还有不少余量这是这套方案能站得住的根本原因。我们项目实际跑的是260mm/s左右像素时钟约8MHzAD9822工作在中速区间线性度和噪声表现都比较舒服。2.3 数据带宽与传输接口的取舍数据带宽这账必须提前算不然板子做完才发现传输接口不够用非常被动。按300mm/s的高速工况3543行/秒×2592像素×16bit≈147Mbps≈18.4MB/s。 按60mm/s的常规工况约3.8MB/s。USB2.0高速模式理论带宽60MB/s实际可靠传输大概30MB/s左右跑60mm/s完全没问题跑300mm/s也不算太吃力但加上上位机处理和磁盘写入的开销就会紧张。我们验证阶段用USB2.0加自定义协议把16位数据做了压缩实际有效位数12~13位截掉低位再用RLE压缩白底区域跑260mm/s很稳定。如果要做成产品扫提速建议直接上USB3.0或者千兆网省得后面返工。2.4 AD9822在参数上为什么合适AD9822关键指标16位分辨率最高15MSPS转换率内置相关双采样支持多种CDS模式内置可编程增益放大器增益范围以具体手册为准内置偏移DAC做黑电平校准支持三通道输入切换后面想扩展彩色三路CIS也方便3线串口配置寄存器16位输出对文档扫描来说非常充裕。实际有效位数大概在12~13位多出来的位数给了平场校正和灰度调整空间。CDS和PGA集成在一块省掉了外部运放和采样保持电路板级设计和调试成本都低了不少。3. AD9822的初始化与配置别被串口文档绕晕3.1 上电顺序别急稳定了再干活AD9822上电后不能立刻采数稳妥的顺序是AVDD和DVDD上电电源用LDO纹波控制在几十mV以内每个电源引脚都放10uF0.1uF1nF多级去耦等电源稳定后把SDATA、SCLK、SLOAD置为确定电平别悬空完整写一遍所有寄存器包括操作寄存器、增益、偏移再等至少几百微秒让内部偏置稳定这一步我吃过亏上电后立刻启动CIS前几百行数据全是乱的波形毛刺特别多。后来在FPGA逻辑里加了个“上电延时计数器”配置写完等够时间再让CIS空扫几行数据立刻就干净了。3.2 三线串口的写寄存器流程AD9822的串口格式是8位寄存器地址加8位数据。时序上先用SLOAD拉低作为启动然后SCLK逐位把地址和数据移进去最后SLOAD拉高结束。SCLK空闲默认电平、数据在哪个沿变化不同版本手册有细微差别一定要以你手上那颗芯片的datasheet为准。FPGA里写一个简单的SPI Master状态机就行本质就是一个计数器数16拍前8拍发地址后8拍发数据SDATA按位输出。需要特别注意一次传输的SLOAD必须完整包住16个SCLK中途不能拉高。有朋友图省事把SLOAD当普通片选用结果寄存器偶尔写不进去图像一会儿正常一会儿乱排查了很久才发现是SLOAD时序问题。3.3 关键字段怎么选我当时主要配了这几类列成表供参考功能配置选择说明通道选择单通道匹配CIS的输出通道数目CDS模式双CDS或像素CDSCIS信号强烈建议用CDS模式关掉噪声会很难看增益调试期设小增益等图像稳定后再逐步增大偏移初始为0黑电平校准放到最后一步时钟极性匹配采样关系必须和CIS输出波形对齐后面调试重点寄存器具体地址和位定义必须对着数据手册逐位核对。AD9822是经典芯片网上扫描版手册版本很杂有些寄存器描述在不同Revision里有更新。我的原则是功能描述加实测结果双重确认不要直接抄网上的配置表否则采数出来对不上都不知道错在哪。3.4 增益和偏移的调整次序调增益和偏移有个顺序问题。先调曝光和光源亮度让传感器输出幅度落在ADC量程的60%~80%再用PGA微调放大最后用偏移DAC校正黑电平。不要先动偏移再动增益因为偏移DAC和PGA的标定点是耦合的改偏移会影响增益校准结果。我们当时的操作是拿一张白纸垫底调光源电流让输出接近满量程再降一点PGA留余量最后拿黑盖子盖住传感器用偏移把黑底拉到接近0的参考值。这组参数定下来之后后面平场校正的工作量会小很多。4. FPGA侧的核心时序设计状态机、计数器、FIFO4.1 时钟怎么分板上用一个有源晶振比如50MHz进PLL产生两路时钟采样时钟约8~10MHz直接给AD9822做采样时钟也同步给CIS的SHIFT/CLK系统时钟100MHz用于状态机、FIFO读写和发送逻辑采样时钟和系统时钟是倍频关系跨时钟域要小心。最安全的做法是AD9822输出的DATACLK引回FPGA用它做数据锁存时钟不要自己拿系统时钟去采数字数据除非你花时间验证过相位关系。数据手册上的锁存关系图务必看懂这是后面调试的锚点。4.2 CIS行扫描状态机CIS一行扫描的时序大致分这几段ROG脉冲触发电荷转移、等待传感器内部建立、连续输出SHIFT/CLK逐像素送出、像素计数到有效数停止、进入下一行。不同厂家的CIS叫法不一样有的叫ROG、SP有的直接叫CLK和SHIFT但本质都是“启动信号移位时钟”的组合。我用的状态机是IDLE→ROG_HIGH→ROG_LOW→WAIT→SHIFT→LINE_DONE再回到ROG_HIGH。示意代码如下// 行扫描状态机骨架示意非完整工程代码 localparam IDLE 3d0; localparam ROG_HIGH 3d1; localparam ROG_LOW 3d2; localparam WAIT 3d3; localparam SHIFT 3d4; localparam LINE_DONE 3d5; reg [11:0] pixel_cnt; reg [15:0] cnt; always (posedge clk_scan or negedge rst_n) begin if (!rst_n) begin state IDLE; pixel_cnt 0; end else begin case (state) IDLE: begin if (start_scan) begin state ROG_HIGH; cnt ROG_HIGH_PULSE; // ROG高电平保持拍数 end end ROG_HIGH: begin if (cnt 0) state ROG_LOW; else cnt cnt - 1b1; end ROG_LOW: begin if (cnt 0) state WAIT; else cnt cnt - 1b1; end WAIT: begin if (cnt 0) state SHIFT; else cnt cnt - 1b1; end SHIFT: begin // 每个时钟周期输出一个CLK给CISpixel_cnt计数 // 到有效像素数后结束本行 if (pixel_cnt PIXEL_TOTAL) state LINE_DONE; else pixel_cnt pixel_cnt 1b1; end LINE_DONE: state ROG_HIGH; endcase end end这里WAIT的时长直接决定了积分时间改这个计数值就等于软件调曝光。ROG高电平宽度的取值要看传感器手册有的模块要求ROG至少保持多少纳秒太短电荷转移不彻底首行数据会暗。第一次上板时先把这些参数设成保守值比如ROG高电平拉长一点、WAIT拉长一点确认整条链路通了再慢慢收窄。4.3 有效像素窗口与dummy像素CIS一行总像素通常大于有效像素。比如模块总像素1100、有效1024多出来的部分是dummy像素和隔离像素用于内部时序衔接不能当图像数据。FPGA驱动状态机里维护一个像素计数器每来一个SHIFT时钟加1。计数器落在有效窗口内就把AD9822的16位数据写入FIFO落在窗口外直接丢弃。这里有个很容易踩的坑传感器手册给出的“第一个有效像素”位置是典型值实际板子上会因为时钟相位、模块批次而偏移几个像素。所以我把有效窗口的起始点做成了寄存器参数调试时上电抓一次白纸图像看图像是不是整体左移或右移直接在寄存器里补一个偏移量就行。图像对齐这个事靠代码改逻辑很麻烦靠参数调就很舒服。4.4 数据锁存与乒乓缓存AD9822输出的数据在DATACLK的某个沿有效。保险做法是先用DATACLK直接打一拍用示波器或在线逻辑分析仪看数据是否稳定如果出现偶发错位在FPGA里用PLL相位偏移把采样点往数据窗口中间挪。改相位比改代码快得多也更容易验证。进FPGA之后我做了两级双口RAM做行缓存乒乓结构第一行写入RAM_A时上一行从RAM_B读出打包发送下一行再交换。这样保证行与行之间不断流不用等整帧数据攒齐延迟也低。FIFO深度估算假设像素时钟10MHz、每行2592像素16bit、行周期282μs那么一行数据量约5184字节突发写入约2.6MB/ms。如果发送端的平均速率跟不上就必须靠FIFO吸收突发。公式是FIFO深度≈突发写入速率−平均读出速率×突发时间÷数据宽度最后留2倍余量。我们实际用的FIFO是8192字深跑高速工况没断流过。4.5 数据帧格式数据到了上位机要能还原成图像必须在流里带上行号或者同步标志。我每行数据前面加一段行头格式如下字节内容说明0~10xAA 0x55固定同步字2~3行号0~65535循环4~5有效像素数便于上位机解析6标志位bit0表示新帧开始7以后像素数据每像素2字节小端上位机先找同步字再按行号拼接即使中间丢了一行图像也只是少一行不会整幅错位到没法恢复。这个细节看着小但真到联调的时候能省下大量排查时间。5. 时序调试实录这些坑我花了最长时间5.1 图像整体发暗还带垂直条纹第一次接通CIS和AD9822出来的图像整体亮度只有预期的三分之一放大看还有垂直方向条状明暗变化。我当时先怀疑传感器坏了换了一块模块还是一样。抓模拟输出波形才发现问题AD9822的CDS采样点没对准CIS输出的有效视频电平。CIS每个像素的输出波形里复位电平和视频电平之间有一小段跳变CDS内部的两个采样保持点要分别落在正确的位置。我在寄存器里配了双CDS模式但采样时钟相对CIS输出有个固定相位偏差导致视频采样点落在斜坡上采到的电平偏低且不稳定。解决办法是调整AD9822采样时钟相对CIS输出信号的相位。折腾到最后其实就是把采样时钟做了一点点延迟图像发暗和条纹的问题同时消失。这类问题示波器上一抓就明白光靠脑子想很容易绕进去。5.2 固定竖线首像素没对上图像亮度正常之后每个扫描行里总有一条很细的暗线位置固定大概在第37个像素。我一开始怀疑是传感器坏点但坏点应该是单个像素的固定位置这条线出现在所有扫描行上而且换模块也还在。用示波器把CIS模拟输出、DATACLK、FPGA内部有效窗口标志三个信号抓在一起发现AD9822开始输出有效数据的时间点比FPGA里有效窗口开始的时间早了约6个像素周期。也就是说我把前6个真实像素丢进了无效窗口却把dummy像素当成了第1个有效像素。图像不是少了6个像素而是整幅图右移了6个像素最右边补进来6个dummy黑点。处理办法就是前面说的把有效窗口起始参数从0改成-6也就是提前6个CLK让出有效标志。改完再抓一次白纸图像竖线消失图像对齐了。这件事让我养成了一个习惯所有跟像素位置有关的参数一律做成可调寄存器不要写死在代码里。5.3 周期性噪点问题出在电源和地图像上出现等间隔的微弱白点间距和像素数无关但和CLK频率有关系。我一开始以为是数字线干扰把AD9822数据线加粗、加缓冲都没用。后来用示波器测模拟电源发现AVDD上是DC-DC的纹波大约50mV噪声频率和ADC采样时钟混叠后产生了周期性噪点。整改了三处AVDD改由LDO单独供电输出端加了10uF0.1uF1nF多级去耦AD9822的模拟地和数字地单点连接不跨分割CLK和数据线尽量短和模拟输入走线拉开距离改完噪点基本消失。AFE这类混合信号芯片电源和地的处理优先级比逻辑代码高得多这个案例值得记一辈子。5.4 DATACLK采样沿不稳定的时刻有一版PCB布局比较紧凑AD9822的DATACLK走线较长而且挨着CLK线。示波器上看DATACLK边沿有明显振铃导致FPGA采样偶发错误图像整行出现灰阶跳变。做了两件事第一在FPGA内部用相位偏移把采样点往数据窗口中间挪先把逻辑验证通过第二下一版PCB把DATACLK线加粗、拉远串接33Ω电阻衰减振铃。两件事都做完之后再没出现整行跳变。示波器测量时有个细节地线夹要靠近器件引脚不要用长地线夹子去勾远端地否则测到的噪声有一半是测量方法带来的。有条件用十倍衰减探头并做通道校准测得才准。5.5 开机前几行数据不可用上电后头几行数据乱的另一个原因是CIS内部电荷还没清空AD9822内部偏置也没建立。我的最终处理是在状态机里加了完整的启动序列FPGA配置完成后等500μs写一遍AD9822配置再让CIS空扫3行ROG和CLK照常跑但数据全部丢弃从第4行才开始正式采数。这样CIS电荷清零、AD9822偏置稳定前几行数据一次就干净。6. 图像质量评估与后续优化6.1 哪些指标能说明系统达标300DPI文档扫描的验收我们一般看这几项白底均匀度扫一张白纸8bit灰度下中心与边缘差值控制在6~10个灰度级以内黑底噪点水平黑底灰度均值加3σ要在可接受范围否则影响OCR识别灰阶线性度用灰阶卡扫描输出灰度和标准灰阶的相关系数达标分辨率测试卡能用肉眼分辨到对应DPI的线对才算真正的300DPI这些指标里白底均匀度基本靠平场校正兜底黑底噪点靠电源和CDS配置灰阶线性度靠AD9822的PGA和偏移调好分辨率靠CIS本身的光学素质。6.2 平场校正CIS先天有光照不均匀和光电响应非均匀性反映到图像上就是两边暗中间亮或反过来。光靠硬件调很难压到2%以内软件标定几乎必做。做法是扫一张白纸逐像素算出增益校正系数K(i)目标白电平÷实际白电平盖住光源扫一张全黑逐像素算偏移量B(i)实际像素校正Y(i)(X(i)−B(i))×K(i)这个算法在FPGA里实现不复杂给每个像素存一组校正系数和偏移量流水线里做一次乘加即可。查表和运算都在像素时钟周期内完成不影响行速率。6.3 坏点矫正CIS模块总有几个固定坏点表现为常亮白点或常暗暗点。FPGA里先做坏点检测找与周围像素差异超过阈值的点并记录位置再用邻域均值替换。注意坏点检测一定要放在平场校正之后做否则光照不均匀会被误判成坏点。6.4 还能往哪扩展这套硬件平台跑通之后扩展空间其实很大。A3幅面可以用两个CIS拼接FPGA需要做像素拼接和重叠区融合彩色扫描可以让AD9822切换三路RGB通道配合三路CIS就行想进一步提高DPI换更高分辨率的传感器模块逻辑基本复用。我现在这个项目最后就是做成了USB接口的便携扫描模块从设计到产品只改了两版PCB。个人最大的体会是这类系统的时序问题很少是单一原因往往是时钟相位、寄存器配置、电源噪声、版图布局叠加出来的。每遇到一个现象先列可能因素再用示波器逐项验证不要盲目改代码。FPGA的优势就是灵活但灵活的前提是你能把每个信号的timing关系彻底想清楚。这套CISAD9822FPGA的链路把我从“会写逻辑”逼到了“懂模拟、懂电源、懂时序”的状态回头再看这些坑都是学费而且是交得最值的那部分。
返回列表