一.SPI协议简要介绍

SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
  SPI总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于 CPU与各种外围器件进行全双工、同步串行通讯。SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。

SPI总线有四种工作方式(SP0, SP1, SP2, SP3),其中使用的最为广泛的是SPI0和SPI3方式。SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果 CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

SPI主模块和与之通信的外设时钟相位和极性应该一致。

以下是SPI时序图:

主要讲解一下广泛使用的两种方式设置:

SPI0方式:CPOL=0,CPHA=0;SCK空闲状态为低电平,第一个跳变沿(上升沿)采样数据,无论对Master还是Slaver都是如此。

SPI3方式:CPOL=1,CPHA=1;SCK空闲状态为高电平,第二个跳变沿(上升沿采样数据,无论对Master还是Slaver都是如此。

其实对于SPI0和SPI1发送与接收数据,可以总结为一句话:上升沿采样数据,下降沿发送数据。全双工同时进行,当然,必须在CS拉低使能情况下。

二.FPGA作为Slaver实现SPI3方式与STM32通信

1.STM32方面:用库函数配置SPI1,设置CPOL=1,CPHA=1.

2.FPGA方面:

(1)通过边沿检测技术得出SCK上升沿与下降沿标志,用于下面状态机中的数据采样及发送。

(2)根据时序图,采用2个状态机分别在SCK上升沿实现数据采样,下降沿实现数据发送。无论是采样还是发送,都是高位在前,从Bit[7]到Bit[0],共8位数据。

(3)最后通过边沿检测技术得出数据采样完成标志,用于用户操作。

以下是SPI3的时序图:

三.Verilog代码部分

测试工程代码:实现了STM32每隔200ms发送流水灯数据给FPGA,使FPGA系统板上的4个LED灯实现流水操作;同时,FPGA每隔1s发送计数数据给STM32,并在STM32系统板上的LCD屏出来,即:显示0-9循环计数。

但下面的代码只是SPI作为从机的驱动部分,包括SPI发送数据与接收数据。

 /***********************************************************************
   ****************** name:SPI_Slaver_Driver **************
   ********** author:made by zzuxzt **********
   ****************** time:2014.4.29 **********************
***********************************************************************/
//use SPI 3 mode,CHOL = 1,CHAL = 1
module spi(input clk,
input rst_n,
input CS_N,
input SCK,
input MOSI,
input [:] txd_data,
output reg MISO,
output reg [:] rxd_data,
output rxd_flag);   //recieve done,please transmit data //-------------------------capture the sck-----------------------------
reg sck_r0,sck_r1;
wire sck_n,sck_p;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
sck_r0 <= 'b1; //sck of the idle state is high
sck_r1 <= 'b1;
end
else
begin
sck_r0 <= SCK;
sck_r1 <= sck_r0;
end
end assign sck_n = (~sck_r0 & sck_r1)? 'b1:1'b0; //capture the sck negedge
assign sck_p = (~sck_r1 & sck_r0)? 'b1:1'b0; //capture the sck posedge //-----------------------spi_slaver read data-------------------------------
reg rxd_flag_r;
reg [:] rxd_state;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rxd_data <= 'b0;
rxd_flag_r <= 'b0;
rxd_state <= 'b0;
end
else if(sck_p && !CS_N)
begin
case(rxd_state)
'd0:begin
rxd_data[] <= MOSI;
rxd_flag_r <= 'b0; //reset rxd_flag
rxd_state <= 'd1;
end
'd1:begin
rxd_data[] <= MOSI;
rxd_state <= 'd2;
end
'd2:begin
rxd_data[] <= MOSI;
rxd_state <= 'd3;
end
'd3:begin
rxd_data[] <= MOSI;
rxd_state <= 'd4;
end
'd4:begin
rxd_data[] <= MOSI;
rxd_state <= 'd5;
end
'd5:begin
rxd_data[] <= MOSI;
rxd_state <= 'd6;
end
'd6:begin
rxd_data[] <= MOSI;
rxd_state <= 'd7;
end
'd7:begin
rxd_data[] <= MOSI;
rxd_flag_r <= 'b1; //set rxd_flag
rxd_state <= 'd0;
end
default: ;
endcase
end
end //--------------------capture spi_flag posedge--------------------------------
reg rxd_flag_r0,rxd_flag_r1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
rxd_flag_r0 <= 'b0;
rxd_flag_r1 <= 'b0;
end
else
begin
rxd_flag_r0 <= rxd_flag_r;
rxd_flag_r1 <= rxd_flag_r0;
end
end assign rxd_flag = (~rxd_flag_r1 & rxd_flag_r0)? 'b1:1'b0; //---------------------spi_slaver send data---------------------------
reg [:] txd_state;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
txd_state <= 'b0;
end
else if(sck_n && !CS_N)
begin
case(txd_state)
'd0:begin
MISO <= txd_data[];
txd_state <= 'd1;
end
'd1:begin
MISO <= txd_data[];
txd_state <= 'd2;
end
'd2:begin
MISO <= txd_data[];
txd_state <= 'd3;
end
'd3:begin
MISO <= txd_data[];
txd_state <= 'd4;
end
'd4:begin
MISO <= txd_data[];
txd_state <= 'd5;
end
'd5:begin
MISO <= txd_data[];
txd_state <= 'd6;
end
'd6:begin
MISO <= txd_data[];
txd_state <= 'd7;
end
'd7:begin
MISO <= txd_data[];
txd_state <= 'd0;
end
default: ;
endcase
end
end endmodule

六.Modelsim仿真图

FPGA作为从机与STM32进行SPI协议通信---Verilog实现 [转]的更多相关文章

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

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

  2. FPGA基础设计(四):IIC协议

    很多数字传感器.数字控制的芯片(DDS.串行ADC.串行DAC)都是通过IIC总线来和控制器通信的.不过IIC协议仍然是一种慢速的通信方式,标准IIC速率为100kbit/s,快速模式速率为400kb ...

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

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

  4. STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

    SPI是我最常用的接口之一,连接管脚仅为4根:在常见的芯片间通信方式中,速度远优于UART.I2C等其他接口.STM32的SPI口的同步时钟最快可到PCLK的二分之一,单个字节或字的通信时间都在us以 ...

  5. SPI的通信试验 --verilog (从机-全双工)

    SPI的 有关知识参考FPGA作为主机的通信实验. 本实验中FPGA作为从机通过SPI与MCU等通信的试验,可以在时钟上升沿接收数据并且在时钟下降沿发送数据,模仿全双工模式.接收的 数据作为地址,通过 ...

  6. oled stm32的spi

    其实各种协议是很重要的,这篇文章就当做我对spi协议的一个整理吧. 必要的spi简介: https://www.cnblogs.com/zengsf/p/7221207.html?utm_source ...

  7. STM32 F4 SPI Accelerometer

    STM32 F4 SPI Accelerometer

  8. [SPI]SPI协议详解

    转自:https://my.oschina.net/freeblues/blog/67400 1.SPI协议简介 1.1.SPI协议概括 SPI,是英语Serial Peripheral interf ...

  9. SPI总线通信电路设计

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

随机推荐

  1. (转)解决Mac OS X上PhpStorm不能输入中文

    看到Netbeans上类似问题的解决办法: /Applications/netbeans/NetBeans 6.7.1/Content/Resource/netbeans/etc/netbeans.c ...

  2. DPI

    [iOS]查找数组NSArray中是否包含指定的元素 http://blog.csdn.net/zyq527758142/article/details/51278172 Dpi(每平方英寸像素数目) ...

  3. ubuntu安装(owncloud-docker安装)

    1.源下载地址:http://mirrors.aliyun.com/ubuntu-releases/ ubuntu-16.04-server-amd64.iso 2.在虚拟机上安装完后 (1)查看IP ...

  4. d3.js读书笔记-1

    d3.js入门 d3入门 D3是一个强大的数据可视化工具,它是基于Javascript库的,用于创建数据可视化图形.在生成可视化图形的过程中,需要以下几步: 把数据加载到浏览器的内存空间: 把数据绑定 ...

  5. <转>好婚姻是彼此放心

    -01- 临下班,马丽听到隔壁桌的方雅在打电话,声音听起来嗲声嗲气:“有个朋友晚上约我吃饭,要晚点回来,你不用等我了哦.” 电话挂断时,已经到了下班的点.方雅扭头对马丽说:“丽姐,待会我们一起去吃个饭 ...

  6. nginx+lua实现简单的waf网页防火墙功能

    原文:http://www.2cto.com/net/201608/534272.html 安装LuaJIT http://luajit.org/download/LuaJIT-2.0.4.tar.g ...

  7. 把数据输出到Word (组件形式)

    上一篇的文章中我们介绍了在不使用第三方组件的方式,多种数据输出出到 word的方式,最后我们也提到了不使用组件的弊端,就是复杂的word我们要提前设置模板.编码不易控制.循环输出数据更是难以控制.接下 ...

  8. Linux shell ”Press any key to continue ”功能实现

    function process_continue(){ SAVESTTY=`stty -g` stty cbreak dd if=/dev/tty bs=1 count=1 > /dev/nu ...

  9. c# 邮件发送功能

    //统一由一个邮箱发送录用通知 string strfrom = "";//发件人邮箱地址 string strpow = "";//邮箱密码 string s ...

  10. 浅谈 原生javaScript&&react 实现全局触摸按钮(附带对addeventlistener的了解)

    1.采用原生javaACript 实现全局触摸按钮 首先在控制台输出,观察事件有哪些关于触摸的字段可以使用,然后拿这些字段的数据开始来写方法. 因为要做的是全局触摸按钮,我需要拿到的是按钮时时的坐标位 ...