SPI的 有关知识参考FPGA作为主机的通信实验。

本实验中FPGA作为从机通过SPI与MCU等通信的试验,可以在时钟上升沿接收数据并且在时钟下降沿发送数据,模仿全双工模式。接收的

数据作为地址,通过读取ROM中地址的数据然后发送出去。注意 发送完成以及接收完成之后的数据处理的关系。

程序:

顶层文件:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :spi_slave_send.v
** CreateDate :2015.04
** Funtions :FPGA作为从机在接收主机发来的地址信号时,输出数据信号,同时还接收主机发来的地址数据(全双工),一直到CS线拉高,没有信号再从主机中发出。
数据地址都为8bit,spi的时钟在发送完8位之后最好能够间隔一下再发生另外8个时钟
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ module spi_slave (
clk,
rst_n, spi_cs,
spi_sck,
spi_miso,
spi_mosi, spi_over
);
input clk;
input rst_n; input spi_cs;
input spi_sck;
output spi_miso;
input spi_mosi; output spi_over; //-----------------------------
wire [:] rdata;
wire rover;
wire txd_en;
wire [:] txd_data;
wire txd_over;
spi_slave_rxd spi_slave_rxd_1(
.clk(clk),
.rst_n(rst_n), .spi_cs(spi_cs),
.spi_sck(spi_sck),
.spi_miso(),
.spi_mosi(spi_mosi), .rdata_out(rdata),
.rover(rover)
); data_read data_read_1(
.clk(clk),
.rst_n(rst_n), .rover(rover),
.rdata(rdata), .txd_en(txd_en),
.txd_data(txd_data) );
spi_slave_txd spi_slave_txd_1(
.clk(clk),
.rst_n(rst_n), .txd_en(txd_en),
.txd_data(txd_data), .spi_cs(spi_cs),
.spi_sck(spi_sck),
.spi_mosi(spi_mosi),
.spi_miso(spi_miso), .spi_over(spi_over),
.txd_over(txd_over)
); endmodule

接收程序:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :SPI_slave_rd.v
** CreateDate :2015.04
** Funtions :SPI的通信实验,FPGA作为从机,接收主机数据以及向主机发送数据
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ module spi_slave_rxd (
clk,
rst_n, spi_cs,
spi_sck,
spi_miso,
spi_mosi, rdata_out,
rover
);
input clk;
input rst_n; input spi_cs;
input spi_sck;
input spi_mosi;
output spi_miso; output reg [:] rdata_out;
output reg rover;
//---------------------------------------
reg spi_cs_0,spi_cs_1; /* 延时两个时钟,配合检测时钟边沿 */
reg spi_sck_0,spi_sck_1;
reg spi_mosi_0,spi_mosi_1;
wire spi_sck_pos;
// wire spi_sck_neg;
wire spi_cs_pos;
wire spi_cs_neg;
wire spi_cs_flag;
wire spi_miso_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
{spi_cs_1,spi_cs_0} <= 'b11;
{spi_sck_1,spi_sck_0} <= 'b00;
{spi_mosi_1,spi_mosi_0} <= 'b00;
end
else
begin
{spi_cs_1,spi_cs_0} <= {spi_cs_0,spi_cs};
{spi_sck_1,spi_sck_0} <= {spi_sck_0,spi_sck};
{spi_mosi_1,spi_mosi_0} <= {spi_mosi_0,spi_mosi};
end
end
assign spi_sck_pos = ~spi_sck_1 &spi_sck_0; /* 取上升沿 */
// assign spi_sck_neg = ~spi_sck_0 &spi_sck_1; /* 取下降沿 */
assign spi_cs_pos = ~spi_cs_1&spi_cs_0; /* 取spi_cs上升沿,作为结束信号 */
assign spi_cs_neg = ~spi_cs_0&spi_cs_1; /* 取spi_cs下降沿,作为开始信号 */
assign spi_cs_flag = spi_cs_1;
assign spi_miso_flag = spi_mosi_1;
//----------------------------------------------------------
localparam idel = 'd0;
localparam rxd_sta = 'd1;
localparam rxd_over = 'd2;
reg [:] cnt;
reg [:] rdata;
reg [:] state;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= ;
rdata <= ;
state <= idel;
rover <= ;
rdata_out <= ;
end
else
begin
case(state)
idel:
begin
cnt <= ;
rdata <= ;
rover <= ;
rdata_out <= ;
if(spi_cs_neg)
state <= rxd_sta;
else
state <= idel;
end
rxd_sta:
begin
if(spi_cs_flag)
state <= idel;
else
begin
// if((cnt == 8)&&(spi_sck_neg)) /* 更严谨 */
if((cnt == ))
begin
cnt <= ;
state <= rxd_over;
rdata_out <= rdata;
rover <= ;
end
else
begin
if(spi_sck_pos)
begin
cnt <= cnt + ; /* 最后cnt=8 */
rdata['d7 - cnt] <= spi_miso_flag; /* 从最高位到最低位逐渐接收数据 */
end
else
begin
cnt <= cnt ;
rdata <= rdata;
end
end
end
end
rxd_over:
begin
rover<= ;
state <= rxd_sta;
end
default : state <= idel;
endcase
end
end // assign rdata_out = rdata;
// else if(!psi_cs_flag)
// begin
// if(spi_sck_pos)
// begin
// cnt <= cnt + 1; /* 最后cnt=8 */
// rdata[4'd7 - cnt] <= spi_miso_flag; /* 从最高位到最低位逐渐接收数据 */
// end
// else
// begin
// cnt <= cnt ;
// rdata <= rdata;
// end
// end
// else
// begin
// cnt <= 0 ;
// rdata <= rdata; /* 注意:保持,不清除 */
// end
// end
//
// //------------------------
// always @(posedge clk or negedge rst_n)
// begin
// if(!rst_n)
// begin
// rdata_out <= 8'd0;
// rover <= 0;
// end
// else if(spi_cs_pos)
// begin
// rdata_out <= rdata; /* 赋值 */
// rover <= 1; /* 置位 */
// end
// else
// begin
// rdata_out <= rdata_out; /* 注意:保持,不清除 */
// rover <= 0; /* 清除 */
// end
// end endmodule

数据转换程序:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :data_read.v
** CreateDate :2015.04
** Funtions : 因为接收完成标志只有一个时钟周期,所以需要马上寄存地址数据,并且地址读取待发送的数据,然后置位发送是能信号。
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ module data_read(
clk,
rst_n, rover,
rdata, txd_en,
txd_data ); input clk;
input rst_n; input rover;
input [:] rdata; output txd_en;
output [:] txd_data; //------------------------------//
reg r_over_1;
reg [:] r_addr;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
r_addr <= ;
r_over_1 <= ;
end
else if(rover)
begin
r_addr <= rdata;
r_over_1 <= ;
end
else if(txd_en)
r_over_1 <= ;
end reg r_over_1_1;
reg r_over_1_2;
reg r_over_1_3;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
{r_over_1_3,r_over_1_2,r_over_1_1} <= 'b000;
end
else
begin
{r_over_1_3,r_over_1_2,r_over_1_1} <= {r_over_1_2,r_over_1_1,r_over_1};
end
end
assign txd_en = ~r_over_1_3&r_over_1_2; data_rom data_rom_1(
.addr(r_addr),
.data(txd_data)
);
endmodule

rom程序:

/********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :data_rom.v
** CreateDate :2015.04
** Funtions : 简单 rom 文件
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ module data_rom (
addr, data );
input [:] addr;
output [:] data; // always @(*)
// begin
// case()
// end
assign data = addr + ; endmodule

发送程序:

    /********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :spi_slave_txd.v
** CreateDate :2015.04
** Funtions :FPGA作为从机的发送数据程序
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ module spi_slave_txd (
clk,
rst_n, txd_en,
txd_data, spi_cs,
spi_sck,
spi_mosi,
spi_miso, spi_over,
txd_over
);
input clk;
input rst_n; input txd_en;
input [:] txd_data;
input spi_cs;
input spi_sck;
input spi_mosi;
output reg spi_miso; output spi_over;
output reg txd_over; //----------------------------------
reg spi_cs_0,spi_cs_1;
reg spi_sck_0,spi_sck_1;
wire spi_sck_neg;
wire spi_over;
wire spi_cs_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
{spi_cs_1,spi_cs_0} <= 'b11;
{spi_sck_1,spi_sck_0} <= 'b00;
end
else
begin
{spi_cs_1,spi_cs_0} <= {spi_cs_0,spi_cs};
{spi_sck_1,spi_sck_0} <= {spi_sck_0,spi_sck};
end
end assign spi_cs_flag = spi_cs_1;
assign spi_sck_neg = (spi_sck_1&(~spi_sck_0));
assign spi_over = ~spi_cs_1&spi_cs_0;
//---------------------------------------------//
localparam idel = 'd0;
localparam txd_sta= 'd2;
localparam txd_data_sta = 'd1;
reg [:] state;
reg [:] cnt;
reg [:] txdata; always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= idel;
cnt <= ;
txdata <= ;
spi_miso <= ; /* 拉高 */
end
else
begin
case(state)
idel:
begin
cnt <= ;
txdata <= ;
spi_miso <= ; /* 拉高 */
if(txd_en)
begin
state <= txd_data_sta; end
else
begin
state <= idel;
end
end
txd_data_sta:
begin
txdata <= txd_data;
state <= txd_sta;
txd_over <=;
end
txd_sta:
begin
if(spi_cs_flag )
state <= idel;
else if(cnt == )
begin
cnt <= ;
txd_over <= ;
state <= txd_data_sta;
end
else
begin
if(spi_sck_neg)
begin
spi_miso <= txdata[-cnt[:]] ; /* 先高位再低位传输 */
cnt <= cnt +; /* 范围:0-8 */
end
else
begin
spi_miso <= spi_miso; /* 保持 */
cnt <= cnt;
end
end
end
default:state <= idel;
endcase
end
end endmodule

仿真程序:

    /********************************Copyright**************************************
**----------------------------File information--------------------------
** File name :spi_slave_tb.v
** CreateDate :2015.04
** Funtions :测试文件
** Operate on :M5C06N3L114C7
** Copyright :All rights reserved.
** Version :V1.0
**---------------------------Modify the file information----------------
** Modified by :
** Modified data :
** Modify Content:
*******************************************************************************/ `timescale ns/ ns module spi_slave_tb ;
reg clk;
reg rst_n; reg spi_cs;
reg spi_sck;
wire spi_miso;
reg spi_mosi; wire spi_over; spi_slave spi_slave_1(
.clk,
.rst_n, .spi_cs,
.spi_sck,
.spi_miso,
.spi_mosi, .spi_over
); parameter tck = ;
parameter t = /tck; always
#(t/) clk = ~clk; //-------------------------------
/* 模仿spi主机的发送程序,这个task很好,仿顺序操作,可以直观的显示过程 */
task spi_sd;
input [:] data_in;
begin
#(*t); spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[7]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[6]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[5]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[4]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[3]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[2]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[1]
spi_sck = ; spi_mosi= data_in[]; #(*t); spi_sck = ; #(*t); //send bit[0]
spi_sck = ; end
endtask initial
begin
clk = ;
rst_n = ;
spi_cs = ;
spi_sck = ;
spi_mosi = ; #(*t) rst_n = ;
#(*t);
spi_cs = ;
spi_sd('h01);
#(*t);
spi_sd('h04);
#(*t);
spi_sd('h00);
#(*t);
spi_cs = ;
end endmodule

仿真图:

SPI的通信试验 --verilog (从机-全双工)的更多相关文章

  1. SPI通信实验---verilog(FPGA作为从机,使用可读可写)

    本实验讲究实用性,故设计思想为:主机先向从机发送地址,若是向从机写入数据,则向从机发送数据,若是读取从机数据,则向从机发送时钟,然后在时钟下降沿读取数据即可.cs信号上升沿作为SPI通信的结束信号.r ...

  2. SPI试验---verilog(实用单通模式)

    SPI通信的读写操作 一.     SPI简介: SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时).也是所有基于SP ...

  3. SPI总线通信电路设计

    数据带宽=(总线频率×数据位宽)÷8 B表示带宽,F表示存储器时钟频率,D表示存储器数据总线位数,则带宽为: B(峰值带宽)=F(时钟频率MHz)×D(总线位数bit)/8 例如,PC-100的SDR ...

  4. 张高兴的 .NET Core IoT 入门指南:(四)使用 SPI 进行通信

    什么是 SPI 和上一篇文章的 I2C 总线一样,SPI(Serial Peripheral Interface,串行外设接口)也是设备与设备间通信方式的一种.SPI 是一种全双工(数据可以两个方向同 ...

  5. 基于STM32F1与NRF24L01模块的SPI简单通信

    一.前言 1.简介: 本文是基于STM32F1,将数据发送至NRF模块的寄存器,并将数据重新读取,通过串口发送出来的简单SPI单通信. 2.SPI简介: 调过STM8的都已经对SPI有所了解,调法都一 ...

  6. FPGA作为从机与STM32进行SPI协议通信---Verilog实现 [转]

    一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...

  7. FPGA作为从机与STM32进行SPI协议通信---Verilog实现

    一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...

  8. SPI以及IIC的verilog实现以及两者之间的对比

    一.SPI是一种常用的串行通信接口,与UART不同的地方在于.SPI可以同时挂多个从机,但是UART只能点对点的传输数据,此外SPI有四条线实现数据的传输,而UART采用的是2条实现串行数据的传输 1 ...

  9. TMS320VC5509的MCBSP配置成SPI模式通信

    1. 首先是把MCBSP的配置 其次是时钟停止模式的配置,关闭大同小异 SPI有4中模式,怎么根据上面的寄存器选择哪种模式?下面展示了其中两种,CLKXP=1的时候有另外两种,暂时不整出来了 2. 代 ...

随机推荐

  1. 用VSCode写python的正确姿势

    最近在学习python,之前一直用notepad++作为编辑器,偶然发现了VScode便被它的颜值吸引.用过之后发现它启动快速,插件丰富,下载安装后几乎不用怎么配置就可以直接使用,而且还支持markd ...

  2. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  3. Bootstrap教程:[4]栅格系统详解

    http://jingyan.baidu.com/article/6f2f55a1852aa1b5b83e6c5a.html 们都知道bootstrap3.0使用了四种栅格选项来形成栅格系统,这四种选 ...

  4. 工匠若水 Android应用开发编译框架流程与IDE及Gradle概要

    http://blog.csdn.net/yanbober/article/details/45306483 http://blog.csdn.net/yanbober/article/details ...

  5. 修改eclipse/MyEclipse中包的显示结构为树形

    在右上边三角那里进去设置 选第一个是显示完整的包名,第二个显示的是树形结构,我们一般用第一种,如下图:

  6. 初学Hibernate持久化

    hibernate三种持久化对象状态:(持久化对象:Persistent Object=POJO + hbm映射) 1.瞬时状态(临时状态或自由态):PO对象刚创建(即new)开始进入瞬时状态,此时对 ...

  7. 生成元(Digit Generator ,ACM/ICPC Seoul 2005 ,UVa 1583)

    生成元:如果 x 加上 x 各个数字之和得到y,则说x是y的生成元. n(1<=n<=100000),求最小生成元,无解输出0. 例如:n=216 , 解是:198 198+1+9+8=2 ...

  8. 如何获取xcassets中LaunchImage图片

    NSDictionary * dic = @{@"320x480" : @"LaunchImage-700", @"320x568" : @ ...

  9. 锋利的jQuery-7--一个$.fn.color插件的编写过程

    编写一个设置和获取元素的color的插件: 首先实现第一个功能,设置: ;(function($){ $.fn.extend({ color:function(value){ return this. ...

  10. python -os、sys

    个人还不是很懂 os操作文件目录.sys针对系统环境的交互.大概是这样 使用os.system函数运行其他程序 os模块中的system()函数可以方便地运行其他程序或者脚本.其函数原型如下所示. o ...