一种通过FPGA对AD9558时钟管理芯片进行配置的方法

2019-08-06 14:04发布

原本一个很普通的时钟管理芯片,通过自带软件用串口很容易就能够进行配置,但尝试着写FPGA代码进行配置却遇到了各种困难,等最终问题解决后才发现,是忽略了一个很小的细节。硬件调试就是这样,只要是没有调试经验,一个很小的细节就有可能耽搁很长时间。正如现在做芯片一样,大家最耽误不起的就是时间。市场的时间窗口一过,即便做出来了,也没有任何意义了。所以,经验的积累非常重要,平常点点滴滴的经验积累,可能以后在不经意的时候用上,并且还起到非常重要的作用。画一条线值一元钱,但知道往哪里画,什么时候画这条线却可能值一百万元。

970de95f2bdc4a7796f193ec0fac5d70

图一

37eee1cf158b425aac9f6d800947ba8f

图二

配置前,我们通过读芯片的引脚功能介绍,获取各个引脚的输入输出特性,包括引脚的功能,电压等信息。

接下来进行寄存器的配置,手册在gettingstarted给了一个AD9558的初始化流程图,系统时钟初始化子框图,APLL初始化子框图。读完这些流程图之后你会发现自己更加迷惑!这些流程图只有大体的流程框架,没有具体的寄存器配置顺序和相应的寄存器值。

谈到寄存器的配置顺序和其对应的值,首先要去手册最后查看每一个寄存器所代表的含义。从register map我们可以看到下面的图,寄存器地址为16位,最高位都是0,也即是说地址有效位是低12位,数据位D7-D0分别对应不同的含义,最后一列是寄存器的默认值。不同的寄存器配置的功能有所区别,比如0x0101开始的一系列寄存器对应的就是系统时钟的配置,其他的在手册上也有具体说明。

b8ae51a365c34caab928e31d8f0c1e6f

了解了寄存器的功能之后我们需要了解,寄存器的值是怎么配置到芯片内部的。其实在开头的芯片管脚处,我们就能看到命名为spio/spo等的管脚,顾名思义,数据通过spi总线,以串行的方式配置到寄存器内。

Spi总线读写时序图我们也可以从手册查到:

dc061b070ad84a7e824bf34f459865ce

上图可以看到,spi总线核心是三个信号,片选信号cs(低有效),时钟信号和sdio数据信号。这里面sdio信号由四部分组成,R/W为1时代表读,为0代表写。接下来的W1,W0指示数据传输类型(00代表一次发1字节数据,01代表一次发2字节,10代表一次发3字节,11代表流模式)。上图显示了一次传输2字节的情况,在已知初始地址的情况下地址会自加。

所以我们在配置寄存器时只要将片选信号拉低,在时钟上升沿时让24位的数据从低到高依次传输,数据的构成按照上图的结构,在传输完成时拉高片选信号。

在具体的配置中,我们根据芯片公司提供的配置软件,手动输入需要配置的参数,如系统时钟频率,参考时钟频率,输出时钟频率,输出端口片选,软件会自动计算出相应寄存器的参数。下图左为配置软件打开的初始化界面,下图右为时钟配置wizard界面。可以看到我们选择参考时钟c和参考时钟d输入,频率都为125Mhz。

68ae04c8b60547dcb8a1c6abedd78967

856d10120c2540eda78679e704466940

配置好的界面如下图:

5786be96d5e74293ad39ad857a77c03a

此软件配置的寄存器地址及其值还可以通过file-setup files进行导出。

遇到的问题及解决思路

下面说一下配置时遇到的问题及解决思路。

按照上面的思路,我们将由配置软件导出的文件转化成coe文件,通过rom读出,然后以spi串行时序由fpga输入到ad9558芯片,但是配置完成后没有时钟输出。

此时的现象是可以通过vio配置和读取寄存器的值,但是读到的0D01寄存器的值为0X16,0D01寄存器是状态指示寄存器,0X16代表系统时钟pll没有锁定。

58348542a19b4dc09416d0d551df33d6

我们可以看到,系统时钟没有锁定则过程1没有输出,那么后面的过程2和过程3更不可能稳定了。查看coe文件我们发现,导出的寄存器地址按照从小到大的顺序排列,由此我们怀疑,寄存器配置应该遵循特定的顺序,不是地址从小到大的顺序配置。

为了获取寄存器的正确配置顺序,我们想到了通过usb串口捕获软件,捕获通过配置软件配置的寄存器的顺序和值。捕获软件的界面如下:

ff5a3cbb26ec43fd93ce4e3a0b4aea00

捕获到的值如下:

9f86328f7a764c94ab0a899e6bafdb5d

经过分析,我们认为长度为24且连续输出的是有效信息,其他的是usb板卡和电脑之间的通信信息。

01314e80b004469c9f062911844e002f

我们取每个两位数据的第二位,然后四个二进制数组合成一个十六进制数,最后上图对应的就是000501,也就是地址为0005的寄存器值为01,该寄存器起到更新IO的作用。为了提高效率,我们使用python处理文本,得到了软件配置时的寄存器配置顺序和相应的值。Python程序如下:

0851981373fd493389b3ee70d7d152e3

接下来按照上文的配置方法,将rom里的coe文件通过fpga写到AD9558芯片。但是结果仍然出人意料,还是没有时钟输出!

为了做到fpga配置和软件配置的一致性,我们查看电路图,发现usb下载器对应的管脚和fpga下载的管脚之间仅仅隔了电阻,可以认为是直连。

df7c6c57dcdd4beeb680ff53b42dbdb2

这时我们有了新思路,既然usb下载管脚和fpga下载管脚直连,那么通过usb下载的数据在进入到AD9558芯片的同时也会进入到fpga,我们只要将fpga相应管脚全部设为input类型即可捕获usb下载的数据。为了保证不对fpga造成伤害,我们通过万用表测试了usb管脚的输出电压,同时用示波器捕获了usb板卡配置寄存器时的输出波形。

e72ba1813f484af4a976093b9487b599a04f73a77370432e96bc04cff9c7ca3c

万用表测试结果为3.3V左右,通过fpga捕获到的sclk的波形如上图,我们可以看到usb板卡的输出信号类似于一种门控时钟,在片选信号拉底时时钟也停止。

由此我们怀疑,是否要将自己的配置信号波形完全做成这个样子,即是否要加上门控时钟,是否要将频率降低?

我们之前的配置频率是25Mhz,上面示波器读到的频率为227Hz左右,而通过fpga捕获到的波形频率大致为1Mhz左右。

1a4e80f6996f4143829d76bd5ef94120再次查看手册,spi总线支持40Mhz以下的时钟,我们决定不更改自己的时钟,

fea23379906a43f1b4b87114dca731e0

同时,手册上也说明,不关心cs拉高时的时钟和数据值。由此说明,不是配置的时钟频率或者门控的问题。

接下来的操作就有点“玄学”了,使用usb板卡进行配置就能成功,但是fpga输入同样的东西结果却是错的,我怀疑usb板卡在配置完成后会给出一个“结束信号”,用此信号标志配置完成,然后芯片收到“结束信号”后才进行时钟输出。

抱着这个想法,我先通过fpga将配置信息烧进板子,然后接上usb板卡,此时我打开usb串口捕获软件进行捕获,由于没有打开ad9558配置软件,串口捕获软件还没捕获到任何信息,但是chipscope却触发了。也就是说通过fpga配置之后,只需要插上usb板卡,不需要用软件进行配置,芯片就有时钟输出。但是只插上usb板卡,不通过fpga进行配置,芯片仍无时钟输出。与此同时,串口捕获软件没有捕获到任何信息,说明板卡没有发送任何信息。那就奇怪了?usb板卡没输出信息但是却让AD9558芯片产生时钟输出!

usb板卡如下:

a250ac3ffc6041158098ed429aa83611

为了找出板卡到底怎么对通过fpga配置后的AD9558芯片起作用,我将板卡的杜邦线一根根与芯片进行连接,最后发现sync连接到芯片上时,芯片就有时钟输出了!我用万用表测试了sync的电压,发现usb板卡的sync电压为3.3v,但是芯片上对应的sync为0.3v,然后去芯片手册查询sync功能,发现sync作用时同步复位,低有效,也就是说我们之前一直没配成功的原因是:没有进行复位!插上usb板卡后,芯片输入sync为高,取消复位!

8f1d7857201448e2a022c7716a018f80

其实一开始就应该发现,这里有两个复位信号,但是我们由于思维惯性,仅接了reset一个复位信号,导致排查问题排查了好久,做了许多无用功!

这也告诉我们一个道理,在问题排查时要从全局开始,首先看复位,时钟以及有效信号,再查看内部具体的原因。进行芯片相关的应用时,一定要认真读芯片的配置手册,要了解芯片的逻辑和电路特征,这样也许一开始就发现,sync信号为低了。