SPI和RAM IP核
学习目的:
(1) 熟悉SPI接口和它的读写时序;
(2) 复习Verilog仿真语句中的$readmemb命令和$display命令;
(3) 掌握SPI接口写时序操作的硬件语言描述流程(本例仅以写时序为例),为以后描述更复杂的时序逻辑电路奠定基础。
学习过程:
【SPI的相关知识】
① SPI的速度比串口的快,采用源同步传输的方式,且为串行传输,应用场景不同则时序和接口名称会有不同;
② 串行flash的读写擦除命令可通过SPI接口进行通信,CPU芯片与FPGA可通过SPI接口进行通信,某些芯片的参数寄存器也可通过SPI的方式配置;
③ SPI接口说明

图1 SPI接口
SCLK:主机给从机的系统时钟信号;
SDI:主机输出给从机的数据信号;
SDO:从机输出给主机的数据信号;
CS:片选信号(此处为高电平有效);
SDIO(三线模式):主机与从机之间的双向数据总线。
【DAC3283芯片与SPI有关内容】
DAC3283芯片的寄存器映射如图1所示:

图1 DAC3283芯片的寄存器映射图
从图1可知,此DAC芯片共有32个寄存器需要配置(CONFIG0~CONFIG31),且每个寄存器均为8bit。
【关于这些寄存器的配置方法】对于寄存器数量少的情况,可以直接定义几个reg型变量,然后用这些reg变量初始化那些待配置的寄存器;而对于像本例这样有如此多的寄存器需要配置,则需通过FPGA的ROM或RAM完成寄存器的初始化,即:先将配置参数写到FPGA的ROM或者RAM中,然后再通过FPGA把这些参数从ROM或者RAM中读出并写入到外部芯片的寄存器中去。在本例中,是通过SPI接口写入到DAC3283芯片的。
【DAC3283芯片的SPI接口时序】

图2 SPI的写时序图

图3 SPI的读时序图
首先,对图2、图3中的几个信号名称作介绍。SCLK是由FPGA送给DAC芯片的时钟信号;SDENB是串行接口的使能信号(相当于片选信号),只有当它为低电平时,SPI的读写才有效;对于“三线模式”的SPI,SDIO是一个双向的数据线,负责数据的读写数据传输;对于“四线模式”的SPI,SDIO也是一个双向的数据线,但ALARM_SDO是一个只读数据线,仅负责DAC芯片输出数据的传输。数据在SCLK的上升沿时刻写入DAC芯片,在SCLK的下降沿时刻从DAC芯片中读出。
然后,介绍一下SPI每次传输的数据内容。本例中,SPI采用的是先传高位后传低位的串行传输方式,每次传输16bit,其中,前8bit构成SPI的指令周期,后8bit构成SPI的数据周期。在前8bit中,rwb(R/W)是读/写控制信号,即:若rwb为高电平时,此条指令为读指令;若rwb为低电平时,此条指令为写指令。N1、N0指明每帧传输的数据字节数(范围为1~4字节,不包含前面的那个指令字节),A3…A0是DAC芯片各寄存器的地址。
【SPI接口的状态机】

图4 DAC芯片寄存器初始化操作状态机(概念模型)
IDLE是起始状态(默认态),work_en是从外部输入的启动使能信号(高电平有效);WAIT是等待状态,在本例中,等待8个时钟周期后(wait_cnt[3] == 1'b1)即进入到READ_MEM状态(读存储器状态),直接读取RAM中的数据;WRITE_REG是写寄存器状态,将32个16bit位宽的数据通过串行移位的方式送给DAC芯片的寄存器,移位完1个16bit位宽的数据后(shift_cnt == 4'd15 && pose_flag == 1'b1 && data_end != 1'b1)就回到WAIT状态,然后重新等待8个时钟周期,重新执行READ_MEM状态和WRITE_REG状态,直到32个数据全都读写完毕后才进入STOP状态(shift_cnt == 4'd15 && pose_flag == 1'b1 && data_end == 1'b1),拉高conf_end信号。
【设计步骤】
(1) 写spi_ctrl.v文件,首先写分频计数器,将50MHz的系统时钟分频为1MHz作为SPI的时钟spi_clk(一般是50~60MHz,但此处仅是演示实验,用1MHz即可),同时,产生clk_p和clk_n两个相位相反、频率为1MHz的reg信号,clk_p是正相时钟信号,用以触发脉冲标志信号pose_flag(标志SPI时钟信号上升沿的到来),clk_n是反相的时钟信号,用作spi_clk,送给SPI当作时钟使用,以上共需写4个always语句块。
(2) 建立一个16bit x 32的单口RAM IP核(仅读不写),并例化到spi_ctrl.v中,完成mif文件的编辑和拷贝。
(3) 声明状态机变量,写状态机(两段式),包括等待状态下的计数器、读RAM的地址产生模块(1个系统时钟周期读出1个数据)、串行移位寄存器(左移,移出最高位)、移位操作的计数器、data_end信号控制模块、数据输出模块、片选信号控制模块、conf_end信号控制模块以及状态跳转模块等部分。
(4) 写testbench文件和run.do文件,运行仿真并分析仿真结果(跑300us)。对testbench文件的要求如下:①能使用$readmemb命令读出dac_ini_16x32.mif文件中的数据;②能在rec_spi任务块中实现对SPI传输数据的回收,并与dac_ini_16x32.mif文件中的数据进行校对,然后用$display命令显示校对结果和数据信息。
【代码实现】
(1)设计一个计数分频模块,用50MHz的系统时钟产生1MHz的时钟信号给SPI读/写操作使用,同时产生clk_p和clk_n两个相位相反、频率均为1MHz的信号:

同时,产生一个标志clk_p上升沿的标志信号pose_flag,用它统一系统的全局时钟:

【注意事项】尽量不要使用分频产生的clk_p或clk_n当作always块的触发条件!原因:时钟信号在很大程度上决定了整个设计的性能和可靠性,应尽量避免使用FPGA内部逻辑产生的时钟,因为它很容易导致功能或时序出现问题,内部逻辑产生的时钟信号容易出现毛刺(布线用线的质量较差),影响信号质量,同时,组合逻辑电路固有的延时也容易导致时序问题。详细的解说请见特权的《深入玩转FPGA》一书的P59。
(2)RAM IP核的创建和例化:

图5 RAM IP核的参数配置

图6 去掉q端寄存器

图7 新建和添加mif文件

图8 勾选例化文件
例化到spi_ctrl.v文件中:

(3)声明状态变量和状态参数,写状态机:

状态跳转控制:


① 写状态机写到WAIT状态时,发现需要产生wait_end信号,而wait_end信号是由计数等待8个时钟周期后产生的,故先需要设计WAIT状态等待计数模块:

然后,用设计wait_end信号产生模块:

② 写状态机写到READ_MEM状态时,发现需要先将RAM中的数据读出来,故先需设计产生读RAM地址的模块:

③ 写状态机写到WRITE_REG状态时,发现先要将从RAM读出来的数据缓存起来(通过shift_buf缓存),然后逐比特地通过sdi线送给DAC芯片(串行移位寄存器):

然后,设计模块产生移位完成的标志信号shift_end:

然后,设计SPI接口的数据输出模块、片选信号控制模块以及时钟信号产生模块:



数据逐比特地送给spi_sdi接口,每帧传输16bit的数据,当传输完32个16bit的数据后,需要产生一个data_end标志信号,标志所有数据已经传输完毕:

当传输完32个16bit的数据时,也即完成了DAC芯片32个寄存器的配置工作,故需要产生一个conf_end标志信号,标志配置操作的完成:

【Testbench和run.do】
Testbench文件:
① 用文件控制任务$readmemb读出dac_ini_16x32.mif文件中的数据,并用这些数据初始化存储器mif_data(reg [15:0] mif_data[0:31]):

② 计一个名为spi_check的任务,用它回收spi通信的数据,并将其与dac_ini_16x32.mif文件中的数据进行校对,如果数据一致则输出数据的索引和具体内容,否则提示“SPI write is error!”:

run.do文件:

【仿真结果及分析】

图9 transcript窗口的信息1

图10 transcript窗口的信息2
如图9、图10所示,Testbench从SPI接口回收的数据与mif文件中的数据一致,由此可见SPI数据传输的正确性。

图11 状态机视图
如图12所示,是SPI仿真波形的整体图:

图12 仿真波形图1
如图13所示,spi_clk的上升沿对准spi_sdi数据的中心,满足DAC芯片SPI写时序的要求,即:数据在时钟信号上升沿到来的时候写入DAC芯片。

图13 仿真波形图2
如图14所示,展示了状态机跳转到STOP状态(10000)及data_end上升沿的出现。

图14 仿真波形图3

图15 仿真波形图4
由图15可知,在WRITE_REG状态下,片选信号spi_csn低电平状态的持续时间约为16us,而spi_clk的周期是1us,故由此可知SPI每次移位传输占用了16个SPI时钟周期,这与代码中设计的每帧传输16bit数据的设想是一致的。
转载:https://www.cnblogs.com/huangsanye/p/5256494.html
SPI和RAM IP核的更多相关文章
- 第7讲 SPI和RAM IP核
学习目的: (1) 熟悉SPI接口和它的读写时序: (2) 复习Verilog仿真语句中的$readmemb命令和$display命令: (3) 掌握SPI接口写时序操作的硬件语言描述流程(本例仅以写 ...
- 用嵌入式块RAM IP核配置一个双口RAM
本次设计源码地址:http://download.csdn.net/detail/noticeable/9914173 实验现象:通过串口将数据发送到FPGA 中,通过quartus II 提供的in ...
- 自定义AXI总线形式SPI接口IP核,点亮OLED
一.前言 最近花费很多精力在算法仿真和实现上,外设接口的调试略有生疏.本文以FPGA控制OLED中的SPI接口为例,重新夯实下基础.重点内容为SPI时序的RTL设计以及AXI-Lite总线分析.当然做 ...
- IP核——RAM
一.Quartus 1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager 2.弹出创建页面,选择Creat a new custom megafunc ...
- 7系列高速收发器总结 GTP IP核使用篇
上一篇7系列收发器博文讲解了GTP IP核的基本配置,本文继续分析如何将它使用起来.生成IP核后打开example design,先看看工程中包含的文件结构. 顶层文件下包含了gtp ip核系统顶层文 ...
- Vivado中xilinx_BRAM IP核使用
Vivado2017.2 中BRAM版本为 Block Memory Generator Specific Features 8.3 BRAM IP核包括有5种类型: Single-port RA ...
- EMAC IP 核
在有线连接的世界里,以太网(Ethernet)无所不在.以太网具有各种速度模式.接口方式.以及灵活的配置方式.现在的以太网卡都是10/100/1000Mbps自适应网卡.以太网的物理层(PHY)通常使 ...
- IP核——FIFO
一.Quartus 1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager 2.弹出创建页面,选择Creat a new custom megafunc ...
- ARM架构授权和IP核授权有什么不一样啊?
比如,华为分别拿到这2个授权,能做的有什么区别啊? 匿名 | 浏览 2976 次 推荐于2016-06-09 02:43:35 最佳答案 一个公司若想使用ARM的内核来做自己的处理器,比如苹果 ...
随机推荐
- Using Custom Java code in ODI
在ODI中调用jar包java方法的过程如下: 1.编写Java代码如下 代码写hello world字符串到一个文件. package odi; import java.io.File; impor ...
- Java之创建对象>3.Enforce the singleton property with a private constructor or an enum type
1. 通过一个公开的字段来获取单例 // Singleton with public final field public class Elvis { public static final Elv ...
- Leetcode 240 Search a 2D Matrix II (二分法和分治法解决有序二维数组查找)
1.问题描写叙述 写一个高效的算法.从一个m×n的整数矩阵中查找出给定的值,矩阵具有例如以下特点: 每一行从左到右递增. 每一列从上到下递增. 2. 方法与思路 2.1 二分查找法 依据矩阵的特征非常 ...
- 深入理解JVM(三)——垃圾收集策略具体解释
Java虚拟机的内存模型分为五个部分.各自是:程序计数器.Java虚拟机栈.本地方法栈.堆.方法区. 这五个区域既然是存储空间,那么为了避免Java虚拟机在执行期间内存存满的情况,就必须得有一个垃圾收 ...
- linux下的文本编辑器VI的使用命令
1. 移动光标 H #移到屏幕的左上角 M #移到屏幕的中间行开头 L #移到屏幕的最后一行 [ #移到文件开始位置 (双击) ] #移到文件结束位置(双击) :n #移到文件的第n行 Ctrl + ...
- FTP命令字和响应码解释
FTP命令: 命令 描述 ABOR 中断数据连接程序 ACCT <account> 系统特权帐号 ALLO <bytes> 为服务器上的文件存储器分配字节 APPE &l ...
- springmvc是如何和前端页面联系起来的
springmvc的使用,在controller中通过注解的形式,获取从前端jsp页面传过来的action参数. 方法/步骤 使用springmvc必须在web.xml中配置(Dispatcher ...
- HDUOJ---老人是真饿了
悼念512汶川大地震遇难同胞——老人是真饿了 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/O ...
- 快排法求第k大
快排法求第k大,复杂度为O(n) import com.sun.media.sound.SoftTuning; import java.util.Arrays; import java.util.Ra ...
- java unicode转码为中文 实例
package com.infomorrow.parser_report; import org.junit.Test; public class Decode { @Test public void ...