多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

浅析高性能AD采集芯片AD4630—四通道SPI模式的配置与采集(FPGA)

浅析高性能AD采集芯片AD4630—四通道SPI模式的配置与采集(FPGA) 目录一、浅析芯片手册Data Sheet1.芯片概述2.AD4630的SPI信号协议介绍3.配置寄存器与时序4.AD数据转换与采集二、FPGA代码设计1.稳定与复位2.初始化模式配置3.AD数据转换与读取三、CNV优化与测试验证1.CNV采样时钟的硬件优化2.回环模式验证配置3.测试模式验证AD采集转换4.一点心得体会前言做FPGA相关设计的时候用到了一块高精度的AD转换芯片是ADI公司的AD4630芯片网上对这块芯片的使用和配置并没有过多的详细介绍ADI公司有配套的评估板看了一下比较贵还是算了因此打算自己写一套AD4630的配置和采集程序之前也做过不少硬件那就浅浅操刀一下吧QAQ。一、浅析芯片手册Data Sheet1.芯片概述从Feature中可以看出所用的AD4630-24为双通道转换速率最高2M逐次逼近型的SARAD转换芯片其主要采用SPI协议通信支持1,24路并行转换降低了对SCK的频率要求使得慢SCK也可以完成快速的采样。逐次逼近型ADC位数越多转换的相对速率就要越慢因为需要一位一位比较因此AD4630-24适合对精度要求特别高而对转换速率要求一般的场景比如高精度传感器医疗仪器等在General Description中从“The wide differential input and common-mode ranges allow inputs to use the full voltage reference”可知该器件的输入为差分输入这将有效的克服共模干扰而带来的ADC的误差也就是意味着我们需要将采集的信号转换为差分形式给到AD4630手册后面附了全差分的配置。2.AD4630的SPI信号协议介绍SPI是摩托罗拉公司提出的一种广泛用于主控于外设之间数据传输的协议以SCLK本文引为SCK的时钟为同步时钟基准收发使用同一源时钟SCK以保证同步在通信中不同步很可能回造成乱码误码SPI的时钟速率决定其通信的速率为全双工通信。SPI通过拉低片选信号可以实现多主从机之间的通信。典型的SPI的构成为CSSCKSDISDO四根线有的SPI线多一点基本上多的是SDO比如AD4630SDO0-7共八组。从Data Sheet中可知CS片选低有效信号SDI接受FPGA发来的数据CNV关键引脚AD4630的转换基准时钟CNV的时钟频率决定转换速率这里援引一下Pin Function中对CNV的补充介绍。这表明CNV 输入的上升沿会启动器件并开始新的转换该信号必须具有低抖动才能实现 ADC 的指定性能所以CNV时钟的质量会影响AD4630转换的性能为后面的优化铺垫一下。SCK时钟基准AD4630支持三种SCK的模式正常模式从机ECHO回环HOST使用内部自己的时钟作为主机。最大频率支持为86MHz。SDO组0-3对应1通道的4-7对应2通道的至于用几个就看你配置是几LANE了。这里先援引一下时序后续会再分析BUSY/SCKOUT在正常SPI模式下BUSY信号是跟随CNV的当正在转换的时候BUSY会置高转换完了再拉低。本设计将利用这一特性进行采集。当ECHO回环和HOST模式的时候会时滞一个周期输出SCK信号本设计将利用这一特性辅助验证。3.配置寄存器与时序本文主要介绍基于Altera的Cyclon4系列FPGA主频为50MHz进行4LANESPI时钟模式SDR单倍速率输出为24位差分数据的模式配置并利用回环和测试模式用于配置过程中的验证。AD4630的寄存器配置和SPI协议稍微复杂一点为此本文采用逐步介绍Data Sheet援引原文FPGA需求拆解的方式力争简洁清晰。Step1重置复位AD4630-24复位为低有效本设计采用的是FPGA接入RST引脚也就是软件复位。从“Perform a reset no sooner than 3 ms after the power supplies are valid and stable”可知AD4630在上电到稳定需要3ms的稳定时间这段时间RST会置高RST拉低无效因此需要3ms后再拉低复位。从“The minimum RST pulse width is 50 ns”可知RST的复位低电平的信号至少持续50ns。从“After a hardware or software reset, no SPI commands or conversions can be started for 750µs”可知在复位后存在750μs的SPI指令和转换时钟的静默期。因此对于本步FPGA的设计则是需要一个时钟计数器计数3ms50ns750μs。而且几步跳转可以使用状态机。Step2寄存器配置模式——总体流程重点在右下角右下角的流程告诉我们要配置寄存器一共要分三步就像把大象装进冰箱一样首先是读一个虚拟的寄存器地址0X3FFF这里DISS一下它没有考虑首位读写的情况容易误判所以实际是0XBFFF。然后是你读或者写对应寄存器地址的对应指令也就是你发送的码是由地址和数据构成的如果你读完了写完了所有的操作那么你要往0X0014地址写一个0X01数据以保存并配置模式。本步没有特别指定的FPGA需要。Step3寄存器配置模式——配置模式寄存器绕口令hhhAD4630的Data Sheet的末尾很贴心的给了所以寄存器的地址和对应的功能我们选我们要看的看该看的看不该看的不要乱看重点关注模式配置寄存器地址0X20这将决定我们的AD4630如何工作。本设计的工作模式配置为4LaneSPI时钟模式SDR单倍速率24位差分数据输出。因此我们的数据码为10_00_0_0000X80。上面提到本设计会利用回环模式和测试模式辅助验证回环模式的数据码为10_01_0_0000X90测试模式的数据码为10_00_0_1000X84Step4寄存器配置模式——读与写重点来了时序芯片时序的逻辑顺序最好一点都别错。要看清时间的要求和时序的逻辑。配置模式的FPGA时序要求还是比较宽松的时序约束的时候这块可以适当放松一点。读寄存器配置的时序流程为本设计的VIO接口电压为1.8VCS至少应在SCK上升沿来之前的11.6ns就拉低CS至少要在SCK最后一个下降沿之后的5.2ns才能拉高SDI的数据至少在SCK上升沿来之前的1.5ns就应该准备好。SCK的周期不得低于11.6ns高电平、低电平有效时间不得低于5.2nsSCK一共最多需要24个周期才能完成。SDI的构成为1位读写标志15位地址最高位为1代表读0代表写所以那个虚拟地址0X3FFFF其实是全码是0XBFFF数据的写入和读出均遵循最高位在前也就是MSB模式所以上面的数据码也都是高位在前。读虚拟地址和写指令不需要数据传回不用关心SDO0本步的FPGA显然众多时序先后顺序和三条线的情况优选状态机配置模式的情况下对时序要求一般因此我们这里可以用部分独热码的状态机。请务必赏析语言艺术“就才一共只”其实我觉得FPGA写配置时序不如ARM的串行结构有优势因为这种串行协议计时还是ARM更方便一点直接delay_nsXXX的本设计的主频时钟为50MHz时钟周期为20ns显然不能为这些几点几的时钟单独各自拉PLL所以流程应该为CS拉低一个时钟后SDI开始输出最高位一个时钟后SCK拉高开始24个周期计数SDI同步发送数据24个周期计数完一个时钟后CS拉高。注意分号☆Step3里面的地址是不含首位的也就是15位但他却披着0X的外衣hhhh容易误判所以我们SDI要准备的码为读虚拟地址0XBFFFFF;写配置模式4laneSPI时钟SDR单倍速率24位差分数据0X002080因为MSB 所以前面00不能少;回环0X002090测试0X002084;保存并退出0X1401STEP5:检验你的配置是否生效对于配置AD4630的SPI来说最折磨的就是搞了一遍结果不对还不知道是卡在哪里了所以我们做一步就验证一步先保证配置模式生效在SPI模式下是不好判断的。因此我们利用回环模式来验证将寄存器模式码调到回环。仿照上文写一个程序先将CS先拉低一个周期后SCK给24个时钟然后过一个周期再拉高CS。用示波器/Quartus的Signal Tap/Vivado的ILA IP核去检测在BUSY/SCKOUT上是否回环了SCK的时钟并检查是否回环了24个周期如果是那么恭喜你你的配置的代码是正确滴别忘了再还原回去喔文末给出相关图。4.AD数据转换与采集下一个重点SPI模式下的AD的数据转换这块相对复杂一点我们一点点看。从第一段“Once the conversion completes, CS can be asserted, which causes the current conversion result to load into the output shift register”可知转换完成后CS才可以拉低当前的转换结果会寄存到输出寄存器上确保输出的结果暂时不会丢失。从左图中我们可以得知有两个读取转换结果的窗口区也就是Zone1,2。先看Zone1在SPI模式下CS的片选可以在BUSY信号结束后就立刻拉低启动读取转换如果是回环Echo或者主机Host模式下等300ns后再拉低CS片选。以2M的CNV时钟为例Zone1给我们留的时间是198.4ns。这里的300ns主要是考虑到CNV的2M周期在SPI模式下可以看到是CNV低电平一段时间后BUSY才会拉低文末给相关图从右图中可以解释一下Quiet Zone静默区通俗点就是这段时间不能有任何SPI的操作CSSCKSDI都维持该有的状态不然容易毁坏程序所以这段时间我们是不能执行任何操作的。Zone1留的窗口期时长有点短因此AD4630还提供了时间更长一点的Zone2区Zone2的CS拉低应该在下一个CNV的上升沿后的9.8ns之后静默期以2M转换速率为例Zone2提供了长达470.6ns的转换窗口期如果你的SDK很慢连4LANE都不能满足Zone1的时长限制的话可以使用Zone2窗口期但是你要注意你必须得在下一个采样周期的BUSY信号下降沿拉低之前的25ns就得把CS拉高不然数据就会被下一轮采样覆盖。简言之就是BUSY信号的下降沿更新数据。再来关注一下SPI模式下的数据转换的时序要求可以看见CS仍然有相对SCK超前和滞后的时间。而且转换数据超前SCK上升沿就准备好了。本设计的SCK时钟和主频时钟一样为50Mhz时钟周期为20ns198.4/20 大概是9个时钟周期4Lane模式SCK需要6个时钟周期CS前置拉低和滞后拉高各要1个周期总共8个周期时间裕量为38.4ns是可以满足Zone1时间要求的。本步FPGA的需求采集和转换涉及到多线的要求和逻辑先后顺序因此也是很推荐状态机的。而且转换是AD的关键我们这里的状态机推荐采用独热码状态机。二、FPGA代码设计按照咱们上文的分析一步步设计FPGA。1.稳定与复位需求等待3ms稳定复位信号拉低至少50s复位信号拉高后内750us内不得操作为了确保稳定我这里设计的是6ms200ns1ms的组合。// // 初始化时间参数定义 // localparam time_stab 24d300000, // 稳定时间6ms用于ADC上电稳定 time_keep 24d300010, // 复位保持时间6ms200ns低电平复位持续时间 time_realse 24d350010; // 复位释放时间6ms200ns1ms完成复位后稳定时间 // // 初始化配置计数器 // reg cnt_flag; // 初始化完成标志0:未完成 1:已完成 reg [23:0] cnt; // 初始化时间计数器 // 计数器逻辑从0计数到复位释放时间完成后保持终值 always (posedge CLK or negedge N_RST) begin if(N_RST 0) cnt 0; else if (cnt_flag 1) // 初始化完成后保持 cnt time_realse; else cnt cnt 1b1; // 计数递增 end复位的时序要求没那么严就用二进制的分离式状态机了cnt_flag标志着复位状态的结束意味着这一阶段已经过完但我并没有选择让计数器置零因为这样要翻转很多位不如直接停在最后一个数反正也不影响后面。// // 初始化状态机跳转与执行分离 // 功能实现ADC上电复位时序控制 // reg [2:0] state_initial; // 初始化状态寄存器 // 初始化状态定义 localparam empty 3d0, // 空闲状态 wait_stab 3d1, // 等待稳定状态 rst_keep 3d2, // 复位保持状态 rst_relese 3d3, // 复位释放状态 rst_end 3d4; // 复位完成状态 // 状态机转换逻辑基于计数器值跳转 always (posedge CLK or negedge N_RST) begin if(N_RST 0) state_initial empty; else if (cnt time_stab) state_initial wait_stab; else if (cnt time_keep) state_initial rst_keep; else if (cnt time_realse) state_initial rst_relese; else state_initial rst_end; end // 状态机执行逻辑控制NRST和初始化完成标志 always (posedge CLK or negedge N_RST) begin if(N_RST 0)begin NRST 1; // 复位无效高电平 cnt_flag 0; // 初始化未完成 end else begin case (state_initial) empty : NRST 1; wait_stab : NRST 1; rst_keep : NRST 0; // 触发复位低电平 rst_relese: NRST 1; // 释放复位高电平 rst_end : cnt_flag 1; // 初始化完成 default : ; endcase end end2.初始化模式配置需求先读虚拟地址配置模式退出。读/写都涉及先拉低CS数据提前准备开始读/写滞后CS拉高。三步的读写为了不相互干扰我每次读写完都延时了一段时间复用了地址计数器做计数器减少了资源开支配置模式对时序的要求一般但比part1要求高一点因此我在这里设计的是6位的局部独热码状态机前两位表明模式后四位表明操作阶段优化了一下时序其实主要是考虑read_pre,read这种来回跳转去回填数时候的时序稳定。// // 配置寄存器命令定义 // localparam REG_CONF_MODE 24hBFFFFF, // 进入配置模式命令读虚拟地址0x3FFF MODES_REGISTER 24h002080, // 模式配置寄存器4lane模式SPI时钟SDR速率 EXIT_CONFIGURATION_MODE 24h001401; // 退出配置模式命令 // // 配置状态机SPI通信控制 // 功能通过SPI接口配置ADC寄存器 // reg [5:0] state_setting; // 配置状态寄存器 // 配置状态定义局部独热码风格 localparam stand 6b11_0000, // 待机状态 // 读配置阶段 read_cs 6b00_0001, // 读操作片选使能 read_pre 6b00_0010, // 读操作数据准备 read 6b00_0100, // 读操作移位输出 read_after 6b00_1000, // 读操作完成 // 写配置阶段 write_cs 6b01_0001, // 写操作片选使能 write_pre 6b01_0010, // 写操作数据准备 write 6b01_0100, // 写操作移位输出 write_after 6b01_1000, // 写操作完成 // 退出配置阶段 back_cs 6b10_0001, // 退出操作片选使能 back_pre 6b10_0010, // 退出操作数据准备 back 6b10_0100, // 退出操作移位输出 back_after 6b10_1000, // 退出操作完成 finish 6b11_1111; // 配置完成状态 reg CS_S; // 配置阶段片选信号 reg SCK_S; // 配置阶段SPI时钟 reg [4:0] address; // 配置数据位索引 reg flag_setting; // 配置完成标志 // 配置状态机逻辑控制SPI时序和数据输出 always(posedge CLK or negedge N_RST)begin if(N_RST 0)begin state_setting stand; CS_S 1; // 片选无效高电平 SCK_S 0; // SPI时钟初始低 SDI 0; // 串行数据输出初始低 address 23; // 从最高位开始传输 flag_setting 0; // 配置未完成 end else begin case(state_setting) stand: // 等待初始化完成后进入配置 state_setting (cnt_flag 1) ? read_cs : stand; // 读配置命令传输 read_cs: begin CS_S 0; // 片选使能低电平 address 23; state_setting read_pre; end read_pre: begin // 准备当前位数据 SDI REG_CONF_MODE[address]; SCK_S 0; state_setting read; end read: begin // 时钟跳变移位传输 address address - 1; SCK_S 1; state_setting (address 0) ? read_after : read_pre; end read_after: begin // 读命令传输完成 SCK_S 0; CS_S (address 31) ? 0 : 1; address address 1; state_setting (address 23) ? write_cs : read_after; end // 写配置命令传输逻辑同读操作 write_cs: begin CS_S 0; address 23; state_setting write_pre; end write_pre: begin SDI MODES_REGISTER[address]; SCK_S 0; state_setting write; end write: begin address address - 1; SCK_S 1; state_setting (address 0) ? write_after : write_pre; end write_after: begin SCK_S 0; SDI 0; CS_S (address 31) ? 0 : 1; address address 1; state_setting (address 23) ? back_cs : write_after; end // 退出配置命令传输逻辑同读操作 back_cs: begin CS_S 0; address 23; state_setting back_pre; end back_pre: begin SDI EXIT_CONFIGURATION_MODE[address]; SCK_S 0; state_setting back; end back: begin address address - 1; SCK_S 1; state_setting (address 0) ? back_after : back_pre; end back_after: begin SCK_S 0; CS_S (address 31) ? 0 : 1; address address 1; state_setting (address 23) ? finish : back_after; end finish: begin // 配置完成 SCK_S 0; CS_S 1; SDI 0; address 0; flag_setting 1; // 配置完成标志置位 end default:; endcase end end3.AD数据转换与读取需求检测busy的下降沿CS拉低六个通道转换滞后CS拉高。对AD转换数据部分这块对时序要求相对高一点因此我设计的是全独热码状态机并且不在数据转存期间进行复杂的计算比如这里就没用上面配置时候用的来回状态跳转填数据先用多寄存器把数据存下来在存完之后才进行整体拼接。数据的输出打了一拍增强一下时序的稳定性。// // 数据采集状态机 // 功能从ADC读取转换后的数据 // localparam wait_setting 11b0000_0000_001, // 等待配置完成 wait_start 11b0000_0000_010, // 等待ADC就绪 cs_low 11b0000_0000_100, // 片选使能 sck_en 11b0000_0001_000, // 时钟使能 convert_1 11b0000_0010_000, // 采集第1组数据 convert_2 11b0000_0100_000, // 采集第2组数据 convert_3 11b0000_1000_000, // 采集第3组数据 convert_4 11b0001_0000_000, // 采集第4组数据 convert_5 11b0010_0000_000, // 采集第5组数据 convert_6 11b0100_0000_000, // 采集第6组数据 convert_end 11b1000_0000_000; // 采集完成 reg [10:0] state_convert; // 采集状态寄存器 reg SCK_C; // 采集阶段SPI时钟 reg CS_C; // 采集阶段片选信号 // 数据寄存器每组4位共6组拼接成24位数据 reg [3:0] lane1_1,lane1_2,lane1_3,lane1_4,lane1_5,lane1_6; reg [3:0] lane2_1,lane2_2,lane2_3,lane2_4,lane2_5,lane2_6; reg [23:0] lane1_O,lane2_O; // 通道1、2的24位数据 reg [2:0] cnt_convert; // 采集计数器 // 采集状态机逻辑 always(posedge CLK or negedge N_RST)begin if(N_RST 0)begin // 初始化采集相关寄存器 SCK_C 0; CS_C 1; state_convert wait_setting; {lane1_1,lane1_2,lane1_3,lane1_4,lane1_5,lane1_6} 0; {lane2_1,lane2_2,lane2_3,lane2_4,lane2_5,lane2_6} 0; cnt_convert 5; lane1_O 0; lane2_O 0; end else begin case (state_convert) wait_setting: // 等待配置结束完成 state_convert (flag_setting 1) ? wait_start : wait_setting; wait_start:begin // 等待ADC忙信号结束 state_convert (BUSY_SCKOUT 0) ? cs_low : wait_start; cnt_convert 5; end cs_low: begin // 使能片选 CS_C 0; state_convert sck_en; end sck_en: begin // 使能采集时钟 SCK_C 1; state_convert convert_1; end // 分6次采集24位数据每次4位先将数据存储下来避免在采集过程执行复杂的功能 convert_1: begin lane1_1 {SDO0,SDO1,SDO2,SDO3}; // 通道1第1组数据 lane2_1 {SDO4,SDO5,SDO6,SDO7}; // 通道2第1组数据 state_convert convert_2; end convert_2: begin lane1_2 {SDO0,SDO1,SDO2,SDO3}; // 通道1第2组数据 lane2_2 {SDO4,SDO5,SDO6,SDO7}; // 通道2第2组数据 state_convert convert_3; end convert_3: begin lane1_3 {SDO0,SDO1,SDO2,SDO3}; lane2_3 {SDO4,SDO5,SDO6,SDO7}; state_convert convert_4; end convert_4: begin lane1_4 {SDO0,SDO1,SDO2,SDO3}; lane2_4 {SDO4,SDO5,SDO6,SDO7}; state_convert convert_5; end convert_5: begin lane1_5 {SDO0,SDO1,SDO2,SDO3}; lane2_5 {SDO4,SDO5,SDO6,SDO7}; state_convert convert_6; end convert_6: begin lane1_6 {SDO0,SDO1,SDO2,SDO3}; lane2_6 {SDO4,SDO5,SDO6,SDO7}; SCK_C 0; state_convert convert_end; end convert_end: begin CS_C 1; //关闭片选 cnt_convert cnt_convert - 1; //稳定时序切换 state_convert (cnt_convert 0) ? wait_start : convert_end; lane1_O {lane1_1,lane1_2,lane1_3,lane1_4,lane1_5,lane1_6}; lane2_O {lane2_1,lane2_2,lane2_3,lane2_4,lane2_5,lane2_6}; end default:; endcase end end // // 输出数据同步 // 功能打一拍输出稳定时序 // always(posedge CLK or negedge N_RST)begin if(N_RST 0)begin lane_total1 0; lane_total2 0; end else begin lane_total1 lane1_O; // 通道1数据输出 lane_total2 lane2_O; // 通道2数据输出 end end补充说明在配置寄存器阶段我的SCK是人为的1,0写的这其实已经在分频了如果在转化过程中还人为的写1,0 实际的SCK的时钟是25M周期为40ns就不够时序裕量了因此我采用的是在配置的时候使用人为定义的在转化模式用系统时钟复用。CNV的时钟来自PLL 的IP核2MHz的输入采用类似两路选择器控制。// // 信号控制 // assign CNV_CLK (flag_setting 1) ? CLK_2M : 0; // 配置完成后输出转换时钟 assign SCK (flag_setting SCK_C) ? CLK : SCK_S;// 配置阶段用SCK_S采集阶段用系统时钟 assign CS (flag_setting 1) ? CS_C : CS_S; // 配置阶段用CS_S采集阶段用CS_C三、CNV优化与测试验证1.CNV采样时钟的硬件优化前文提到CNV的时钟质量很影响转换的情况在实测中不论是自己单独写一个高低电平持续时间不一样的采样时钟还是用PLL的IP核产生2MHz的时钟他们的振铃感觉都比较大实则为拿到的板子阻抗没做匹配。左为两种CNV时钟 右为FFT图​​​​​巧的是我之前做的比赛正是基于FPGA、DDS的脉冲波信号发生器甚至还专门设计方案优化了边沿时间过窄导致的过冲和振铃。主要是通过滤波滤除波形的高频谐波分量但我不能为一个CNV的采样时钟还专门写一套数字滤波器这样很占FPGA资源。巧的是我之前还搞过硬件所以想到可以利用电容和自身的阻抗进行RC低通滤波经过试验在我的板子上CNV与地并一个MLCC X7R 0603 容值在470pf-820pf之间的电容都可以较好的实现目标效果强调材质和封装是因为不同材质和封装大小他自身的ESR不一样可能会有点影响至于滤波效果就看自己取了多试几组注意电容过大大概10nF以上会滤成三角波相位时滞就很大了小了滤波不到位。来看看滤波后的效果吧比之前平滑多了。CNV高电平启动转换可根据设计的需要在PLL里面把占空比调小一点不过不影响反正转换速率都是2M2.回环模式验证配置回环模式下BUSY作为SCKOUT相对SCK滞后一个周期这表明我们的模式配置的程序是对的。我这里回环的是6个3.测试模式验证AD采集转换AD4630贴心的为大家准备了验证采样的测试模式该模式下可以修改相应的输出寄存器以改变固定输出我这里就不修改了用它默认的0X5A5A0F0F这个值会用于两通道也就是强制让两组SDO组都输出这组数据因为我是24位差分数据所以我的测试结果应该是0X5A5A0F测试结果正确从这里也能看到BUSY信号跟CNV是有时差的。记得选取MSB模式我这里的total[0:23]的因为位反了用的是LSB4.一点心得体会在最开始的时候我以为SCK和SDI的数据差个1.5ns不是什么大问题但是实际的情况来看就是会不对所以时序的先后逻辑顺序是一点都不能错的。时序是要一点一点抠的急不得快不得。在写AD转换的时候我还想着跟之前一样SCK手动写但是这样时序裕量就不满足了因此一直在想怎么还能复用50MHz的时钟我就想到了时钟和数据是同步的可以用一个控制信号控制其实我觉得逻辑运算门也可以这个日后尝试一下。AD4630的驱动从读DataSheet、写程序和modelsim仿真、到写完这篇文章大概花了四五天时间还是比较有意思的。欢迎广大朋友对其进行批评指正。2026.8.6更正秋招面试被问到该贴了感谢润石的面试官的批评指正我前面把时钟的抖动与振铃混为一谈了本帖CNV的优化主要是优化其振铃是由于我拿到的那个板子阻抗匹配没配好用端接电阻是更优解但我拿到的板子已经改不了了所以用的并小电容。时钟的抖动其实是相位噪声我最先拿到的代码是用Verilog状态机和cnt计数写的这种频率显然是不太固定的我后面自己写的有用PLL锁相环进行锁相算是比原先优化了一下相位噪声但时钟抖动如果是时钟源本身就不行的话后续也是很难优化太多的。
返回列表