基于FPFAI的 SP外设驱动ADF4351(状态机编写)

三线SPI器件设计文档

设计目的:

(1) 根据ADF4351的SPI接口,产生正确的读写时序;

(2) 根据需求对ADF4351的六个寄存器进行配置;

(3) 进行板级验证对仿真结果进行验证和分析。

设计过程:

【SPI的相关知识】

(1) SPI的速度比串口的快,采用源同步传输的方式,且为串行传输,应用场景不同则时序和接口名称会有不同;

(2) 串行flash的读写擦除命令可通过SPI接口进行通信,CPU芯片与FPGA可通过SPI接口进行通信,某些芯片的参数寄存器也可通过SPI的方式配置;

(3)通用SPI接口说明

        

                                图1  SPI接口

SCLK: 主机给从机的时钟信号;

SDI:主机输出给从机的数据信号;

SDO:从机输出给主机的数据信号;

CS:片选信号;

SDIO:(三线模式)主机与从机的双向数据总线。

【ADF4351芯片与SPI有关的内容】

ADF4351芯片的寄存器映射图如图2所示:

   

                              图2  ADF4351芯片寄存器映射图

       从图二可知,此ADF芯片共有6个寄存器需要配置(寄存器0-寄存器5),每个寄存器均为32bit。

【关于这些寄存器的配置方法】第一种方法,对于寄存器数量比较少的情况,可以用几个参变量parameter定义寄存器0-寄存器5,把每个参变量需要配置的值初始化后赋值给参变量,然后通过一个BUFF寄存器保存起来,最后将这些参数通过FPGA的输出SDI接口写入到ADF4351当中。第二种方法,对于寄存器比较多的情况,则通过FPGA的ROM或者RAM完成寄存器的初始化,即:现将要配置的寄存器参数写到FPGA的ROM或者RAM中,然后通过FPGA把这些参数读出并写入到ADF4351当中。在本设计中采用第一种方法实现对ADF4351的配置。

【ADF4351芯片的时序】

       

                                  图3  ADF4351的读写时序图  

       首先,图3中的几个信号名称的实际意义分别是:

CLK: 主机给从机驱动SPI的时钟信号,即:串行时钟输入。数据在CLK上升沿时逐个输入32位移位寄存器;

DATA:串行数据输入。串行数据以MSB优先方式加载,三个LSB用作控制位;

LE:加载使能。当LE变为高电平时,存储在32位移位寄存器中的数据载入三个控制位所选择的寄存器。

然后,图3中t1-t6所代表的不同的物理意义:

t1:LE建立时间(至少20ns),即:完成一个寄存器的配置后进行下一个寄存器配置所需的时间间隔;

t2:DATA到CLK建立时间(至少10ns);

t3:DATA到CLK保持时间(至少10ns);

t4:CLK高电平持续时间(至少20ns);

t5:CLK低电平持续时间(至少20ns);

通过t4和t5我们可以知道ADF4351所需的最小周期为50ns,即:最高频率为20Mhz.

t6:CLK到LE建立时间(至少10ns),即:完成一个寄存器配置后需要等待下一个配置的建立时间;

t7:LE脉冲宽度(至少20ns)。

SPI接口的状态机

 

                 图四   ADF4351芯片寄存器初始化操作状态机

IDLE是起始状态(默认状态),work_en是从外部输入的启动信号(高电平有效);WAIT是等待状态,在本例中,等待了六个半时钟周期,即130ns,进入R_MEM状态(读存储器状态)直接读取shift_buf中的寄存器的初始值,W_REG是写寄存器状态将需要配置的寄存器的一个初始值通过串行移位的方式送给ADF4351后(shift_cnt == 5'd31 && pose_flag == 1'b1 && data_end != 1'b1)就回到WAIT状态,然后重新等待六个半的时钟周期,即130ns,重新执行R_MEM状态和W_REG状态,直到六个寄存器的初始值全部读写完毕后才进入STOP状态(shift_cnt == 5'd31 && pose_flag == 1'b1 && data_end == 1'b1),拉高conf_end信号。

设计步骤

(1) 写spi_adf4351.v文件,首先是通过锁相环倍频,将50Mhz的系统时钟通过锁相环4倍频200Mhz,即:建立一个能4倍频的锁相环IP核,并将其例化到

spi_adf4351.v中,(注意:锁相环输入的复位信号要取反,~rst_n),通过分析ADF4351的时序可得,驱动ADF4351的最高时钟频率为20Mhz,即:将倍频后的时钟进行10分频。同时产生clk_p和clk_n两个相位相反、频率为20Mhz的reg信号,clk_p是正相时钟信号,用来触发脉冲标志信号pose_flag(标记上升沿,用来分频同步的标志信号)clk_n是反相的时钟信号,用作spi_clk。

       (2) 定义六个寄存器,六个被寄存器所需配置值初始化了的参变量,建立一个shift_buf,用来存放每一个寄存器的初始值,串行移位将存放的值一位一位的移出去。

(3) 声明状态机变量,即:写状态机(两段式),包括等待下的计数器,读MEM的地址模块,shift_buf串行移位给sdi模块,data_end数据全部读写结束模块,conf_end配置结束模块,LE数据加载使能信号等模块。

(4)添加激励文件和脚本仿真文件,运行仿真并分析结果。

【代码实现】

(1)建立一个锁相环IP核,输出四倍频200Mhz,并且例化到spi_adf4351.v中过程如下:

第一页,把VALUE的值改成50,如下图中深颜色的地方,点击下一步。

第二页,如下图深色的地方改为200。

 

第3-5页点击NEXT,到第六页点击Generate ,例化后的代码如下:

其中CLK是系统时钟50Mhz,sclk是锁相环倍频出来的200Mhz,复位信号取反。

(2)10分频产生的模块

 

(3)产生clk_p和clk_n两个相位相反、频率为20Mhz的reg信号的模块

 

(4)产生触发脉冲标志信号pose_flag(标记上升沿,用来分频同步的标志信号)

 

(5)声明状态变量和状态参数,写状态机,初始化配置状态机的参变量值

 

  (6)跳转状态控制

 

写状态机写到WAIT状态时,发现需要产生等待结束信号,而等待结束信号是由计数等待六个半个时钟周期后产生的,即:wait_cnt==3’d3,在这里使用了 wait_cnt==3’d3作为等待结束信号。

 

发现写状态机写到R_MEM状态时,需要先将shift_buf中的数据读出来,因此需要设计产生读shift_buf的地址模块:

 

写状态机到R_REG状态时,需要将shift_buf中的数据一位一位的读出来,然后然后逐比特地通过sdi线送给ADF4351芯片(串行移位寄存器),并且发现在移位当中需要移位寄存器计数器模块:

 

然后,设计模块产生所有数据移位完成的标志信号data_end:

 

然后产生使能加载信号LE,包括使能加载信号的高脉冲持续时间以及等待时间对应着时序图中的t1,t6,t7:

 

最后设计产生配置完成信号模块:

 

(4)添加激励文件;

 

(5)添加脚本文件:

 

原文地址:https://www.cnblogs.com/lgy-gdeu/p/11427306.html