精华内容
下载资源
问答
  • 两个芯片(STM32F103)之间SPI通信 (主机:串口发送命令,触发发送数据) (从机:中断接收,并通过串口,把发送的数据打印到串口助手) 工程keil
  • MCU:STM32F303VC,在SPI通信中,可以同时开启发送和接收DMA请求,自动数据的发送和接收,完成数据的交换。
  • SPI通信原理及通信协议:SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,...
  • SPI(Serial Peripheral Interface)总线是主要应用于嵌入式系统内部通信的串行同步传输总线协议。通常为四线制的SPI总线支持全双工通信SPI最初由Motorola在2000年提出,Motorola所定义的SPI标准为业界广泛引用,...

    摘要:本文转载于JawSoW的博客,·相比于网上其他介绍SPI协议的博客,本文更加侧重于底层细节。

    原文转载链接:http://www.wangdali.net/spi/

    概述


    SPI(Serial Peripheral Interface)总线是主要应用于嵌入式系统内部通信的串行同步传输总线协议。通常为四线制的SPI总线支持全双工通信。SPI最初由Motorola在2000年提出,Motorola所定义的SPI标准为业界广泛引用,但不同半导体公司的实施细节可能有所不同,这些区别体现在寄存器设置、信号定义、数据格式等。业界没有统一的SPI标准,具体应用需要参考特定器件手册。

    SPI协议特点包括主从模式、全双工通信、片选功能、模式错误标识及CPU中断、缓冲数据寄存器和可配置时钟相位极性等。SPI允许数据一位一位的传送,甚至允许暂停,因为SCK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据。也就是说,主设备通过对SCK时钟线的控制可以完成对通讯的控制。

     

    应用


    SPI以其简单高效应用于绝大多数SoC系统上,这些SoC通常同时支持作为主模式或从模式(二选一)。

    FPGA和其它专用芯片也广泛使用SPI传输数据。比如:

    • 传感器:温度、压力传感器等
    • 控制设备:音频编解码器等
    • 通信设备:USB、以太网设备等
    • 存储器:Flash、EEPROM等
    • RTC时钟
    • LCD设备
    • MMC和SD卡

    在高性能系统中,FPGA通常使用SPI连接主从设备,比如连接外部传感器,和应用SPI加载配置。相比于JTAG,SPI定位用于高速配置(初始化)板上设备;而JTAG的初衷是为控制设备以相对低的准确度扫描和检测板上IO,在严格要求的场合,JTAG协议支持改变时钟占空比以满足建立和保持时间的要求。因此,JTAG并不定位于高速数据传输的场合。

     

    优点和缺点


    优点

    • 支持全双工通信
    • Push-Pull驱动性能相比Open Drain信号完整性更好,支持高速应用(100MHz以上)
    • 协议支持字长不限于8bits,可根据应用特点灵活选择消息字长
    • 硬件连接简单
      • 只需要四根信号线(部分应用可以缩减到三根)
      • 相比I2C和SMbus节省上拉电阻
      • 相比I2C和SMbus不需要仲裁机制
      • 从设备使用主设备时钟,节约时钟要求
      • 从设备无需地址寻址
      • 无需收发器

    缺点

    • 相比I2C两根线,SPI四根线更多
    • 没有寻址机制,只能靠设备片选(chip select)选择不同从设备
    • 没有数据流控制(但主设备可以通过延缓时钟边缘降低传输速度)
    • 没有从设备接收数据ACK,主设备对于发送成功与否不得而知
    • 典型应用只支持单主控
    • 没有定义数据校验机制
    • 没有统一的国际组织维护,变种多不利于不同厂商设备的互操作性(interoperability)
    • 相比于RS232、RS422、RS485和CAN,SPI传输距离短
    • 不支持热插拔
    • 中断操作只能通过额外的信号线,或类似USB 1.1 and 2.0的Periodic Polling实现

     

    内部框图


    本文主要参考三家公司SPI协议手册,其原理大同小异:

    1. SPI Block Guide V04.01 -Motorola
    2. KeyStone Architecture Serial Peripheral Interface (SPI) User Guide -Texas Instruments
    3. TN0897: ST SPI protocol -STMicroelectronics

    图1表示Motorola定义SPI模块的内部框图,其主要构成包括状态/控制/数据寄存器(Status,Control and Data Registers)、移位寄存器(Shifter Logic)、波特率发生器(Baud Rate Generator)、主从控制逻辑(Master/Slave Control Logic)和端口控制逻辑(Port Control Logic)。

    p1_spi_block
    图1. SPI模块框图(Motorola)

     

    电路连接


    图2表示基本的SPI设备连接示意图。片选信号SS通常低电平有效。SPI数据传输原理是基于主从设备内部移位寄存器的数据交换。在主设备SCK的控制下,待传数据由各自设备的数据寄存器(Data Register)传输到移位寄存器(Shift Register),再通过MOSI和MISO信号线完成主从设备间的数据交换。

    p2_spi_ms_mod_hw
    图2. SPI主从模式传输示意图(电路)

    主从设备间数据交换逻辑示意图如下图3所示:

    p3_spi_ms_mod_reg
    图3. SPI主从模式传输示意图(逻辑)

    硬件拓扑



    单个主设备和单个从设备的SPI连接比较简单,以上图2和图3表示的就是这种拓扑结构。
    通过多个片选信号(SS)或菊花链方式(Daisy Chain Configuration),单个主设备可以同时控制多个不同从设备。

     

    片选方式

    如图4示,每个从设备都需要单独的片选信号,主设备每次只能选择其中一个从设备进行通信。因为所有从设备的SCK、MOSI、MISO都是连在一起的,未被选中从设备的MISO要表现为高阻状态(Hi-Z)以避免数据传输错误。由于每个设备都需要单独的片选信号,如果需要的片选信号过多,可以使用译码器产生所有的片选信号。

    p4_spi_cs_mod
    图4. 主设备以片选方式控制多个从设备

     

    菊花链方式

    如图5示,数据信号经过主从设备所有的移位寄存器构成闭环。数据通过主设备发送绿色线)经过从设备返回蓝色线)到主设备。在这种方式下,片选和时钟同时接到所有从设备,通常用于移位寄存器和LED驱动器。注意,菊花链方式的主设备需要发送足够长的数据以确保数据送达到所有从设备。切记主设备所发送的第一个数据需(移位)到达菊花链中最后一个从设备。

    菊花链式连接常用于仅需主设备发送数据而不需要接收返回数据的场合,如LED驱动器。在这种应用下,主设备MISO可以不连。如果需要接收从设备的返回数据,则需要连接主设备的MISO形成闭环。同样地,切记要发送足够多的接收指令以确保数据(移位)送达主设备。

    p5_spi_daisy_chain_mod
    图5. 主设备以菊花链方式控制多个从设备

     

    电源管理


    Motorola在SPI Block Guide中定义以下三种SPI电源模式:

    • 运行模式 Run Mode
    • 等待模式 Wait Mode
    • 停止模式 Stop Mode

    运行模式下,SPI工作处于正常工作状态。通过修改SPICR1寄存器的SPE位更改此模式:

    0: 禁用SPI模块(进入低功耗状态)
    1: 使能SPI模块

    等待模式下,修改SPICR2寄存器的SPISWAI位:

    0: 运行模式
    1: 低功耗模式 SPI时钟停止运作

    对于主设备,进入等待模式意味终止SPI总线上所有数据传输,唯有将SPISWAI 重新置为0方可恢复通信;对于从设备,进入等待模式后仍将与主设备保持同步,从设备数据的接收和发送还是正常的。

    停止模式下,对于主设备,进入停止模式意味着所有总线上通信的终止;对于从设备,进入停止模式后数据的发送和接收还是正常的,仍然与主设备保持同步状态。

    TI在SPI User Guide定义两种低功耗状态:

    • 全局低功耗模式 Global Low-Power Mode
    • 局部低功耗模式 Local Low-Power Mode

    全局低功耗模式受系统控制,此模式下SPI时钟停止,处于完全不作为状态。
    通过写SPI全局寄存器(SPIGCR1)可以是SPI模块进入局部低功耗模式。此模式下,所有寄存器可以正常访问,但SPI的状态机处于停摆状态,数据收发可能异常。软件设置时需要注意不要在收发数据时让SPI进入低功耗模式。

     

    寄存器说明


    Motorola定义的SPI寄存器包括:

    • SPI Control Register 1 (SPICR1)
    • SPI Control Register 2 (SPICR2)
    • SPI Baud Rate Register (SPIBR)
    • SPI Status Register (SPISR)
    • SPI Data Register (SPIDR)

    其中除了状态寄存器SPISR为只读(Read-only),其它寄存器都是可读写的。通过往寄存器中写入不同的值,设置SPI模块的不同属性。

     

    控制寄存器1 SPICR1

     

    p6_reg_spicr1
    图6. 控制寄存器1 SPICR1

     

    SPIE — SPI Interrupt Enable Bit
    1 = SPI interrupts enabled
    0 = SPI interrupts disabled

    SPE — SPI System Enable Bit
    1 = SPI enabled, port pins are dedicated to SPI functions
    0 = SPI disabled (lower power consumption)

    SPTIE — SPI Transmit Interrupt Enable
    1 = SPTEF interrupt enabled
    0 = SPTEF interrupt disabled

    MSTR — SPI Master/Slave Mode Select Bit
    1 = SPI is in Master mode
    0 = SPI is in Slave mode

    CPOL — SPI Clock Polarity Bit
    1 = Active-low clocks selected. In idle state SCK is high
    0 = Active-high clocks selected. In idle state SCK is low

    CPHA — SPI Clock Phase Bit
    1 = Sampling of data occurs at even edges (2,4,6,...,16) of the SCK clock
    0 = Sampling of data occurs at odd edges (1,3,5,...,15) of the SCK clock

    SSOE — Slave Select Output Enable
    SSOE 用于主设备设置SS管脚功能,它和MODFEN组合决定主设备SS管脚功能。如表1所示其功能组合:

    t1_ssoe_mod
    表1. SS输入/输出选择

    LSBFE — LSB-First Enable
    1 = Data is transferred least significant bit first
    0 = Data is transferred most significant bit first

     

    控制寄存器2 SPICR2

    p7_reg_spicr2
    图7. 控制寄存器1 SPICR2

    MODFEN — Mode Fault Enable Bit
    1 = SS port pin with MODF feature
    0 = SS port pin is not used by the SPI

    BIDIROE — Output enable in the Bidirectional mode of operation
    控制双向模式(Bidirectional Mode)下主设备的MOSI和从设备MISO的输出缓冲器
    1 = Output buffer enabled
    0 = Output buffer disabled

    SPISWAI — SPI Stop in Wait Mode Bit
    1 = Stop SPI clock generation when in wait mode
    0 = SPI clock operates normally in wait mode

    SPC0 — Serial Pin Control Bit 0
    控制(单个)数据管脚是否配置为双向模式,与BIDIROE组合控制(单个)数据管脚同时支持收发功能(如下表2)

    t2_spi_bidir
    表2. MOSI/MISO双向管脚配置

     

    波特率寄存器 SPIBR

    p8_reg_spibr
    图8. 波特率寄存器 SPIBR

     

    SPPR2–SPPR0 — SPI Baud Rate Preselection Bits
    SPR2–SPR0 — SPI Baud Rate Selection Bits

    以上五个寄存器通过下面公式决定波特率除数因子(BaudRateDivisor),进而决定SCK时钟频率。

    除数因子:(通过五个参数计算出来的除数因子不仅包括2^N,还包括4/6/10等总计64个组合)

    eq1_brdiv

    计算波特率

    eq1_br

    举例,SPPR[2:0]设为101,SPR[2:0]设为000,计算得除数因子(5+1) * (2^1) = 12。如果系统时钟速率为25MHz,则SCK时钟速率 = 25MHz/12 = 2.0833MHz.

     

    状态寄存器 SPISR

    p9_reg_spisr
    图9. 状态寄存器 SPISR

    SPISR表征SPI传输状态,只可读,不可写。

    SPIF — SPIF Interrupt Flag
    数据byte写入SPI数据寄存器后,此位被置为1。读取数据寄存器后,此位清零。
    1 = New data copied to SPIDR
    0 = Transfer not yet complete

    SPTEF — SPI Transmit Empty Interrupt Flag
    1 = SPI Data register empty 表示发送数据寄存器为空,可以接收待发送数据
    0 = SPI Data register not empty 此时忽略任何写入数据寄存器的指令

    MODF — Mode Fault Flag
    如表1,错误检测功能使能后,MODF表示检测到SPI模式错误。
    1 = Mode fault has occurred.
    0 = Mode fault has not occurred

    根据Motorola的定义,SPI仅提供一种错误——即模式错误(Mode Fault Error)——的检测机制,通过SS管脚状态判断SPI总线上是否存在两个及以上的设备同时驱动SCK和MOSI。模式错误检测仅适用于主设备(前提是在寄存器中激活此功能)。对于从设备,SS总是作为片选信号的。
    在发生模式错误后(MODF = 1),系统通过写入控制寄存器SPICR1(使设备由Master改为Slave模式,SCK、MISO和MOSI表现为高阻态以避免与总线上其它驱动设备冲突),随后系统自动将此bit置为零(MODF = 0)。

     

    数据寄存器 SPIDR

    p10_reg_spidr
    图10. 数据寄存器 SPIDR

     

    SPIDR作为SPI收发两用的寄存器,数据在写入SPIDR后进入待传输队列,队列中的数据字节在前面数据传输结束后立即进行传输。状态寄存器SPISR的SPTEF位表示数据寄存器可以接收新数据。数据寄存器接收数据完毕后将SPIF置为1。
    如果SPIF已经置为1,但服务并未运行(not serviced),则下一个(第二个)接收的数据字节将暂存在移位寄存器中直到下次传输。数据寄存器中的数据字节不变。

    如果SPIF已经置为1,并且移位寄存器中已经暂存数据(即第二个数据字节),并且SPIF服务在第三个数据字节传输前完成,则移位寄存器中的数据(即第二个数据字节 )正常写入数据寄存器,SPIF仍保持置位状态(高),如图11所示;

    p11_spif_ser
    图11. SPIF服务及时完成

    如果SPIF已经置为1,并且移位寄存器中已经暂存数据(即第二个数据字节),并且SPIF服务在第三个数据字节传输后完成,则移位寄存器中的数据(即第二个数据字节 )遭破坏,不能正常写入到数据寄存器,SPIF仍保持置位状态(高),如图12所示 。

    p12_spif_un_ser
    图12. SPIF服务未及时完成

     

    SPI传输模式


    通过设置控制寄存器SPICR1中的CPOLCPHA位,将SPI可以分成四种传输模式。

    CPOL,即Clock Polarity,决定时钟空闲时的电平为高或低。对于SPI数据传输格式没有显著影响。
    1 = 时钟低电平时有效,空闲时为高
    0 = 时钟高电平时有效,空闲时为低

    CPHA,即Clock Phase,定义SPI数据传输的两种基本模式。
    1 = 数据采样发生在时钟(SCK)偶数(2,4,6,...,16)边沿(包括上下边沿)
    0 = 数据采样发生在时钟(SCK)奇数(1,3,5,...,15)边沿(包括上下边沿)

    四种模式如下图13所示。先看第一列两张图(CPHA = 0),采样发生在第一个时钟跳变沿,即数据采样发生在SCK奇数边沿;再看第二列CPHA =1),采样发生在第二个时钟跳变沿,即数据采样发生在SCK偶数边沿第一行两张图(CPOL = 0),SCK空闲状态为低电平第二行两张图(CPOL = 1),SCK空闲状态为高电平

    主从设备进行SPI通讯时,要确保它们的传输模式设置相同。对于某些场合,可能需要调整CPOL/CPHA设置以满足设备特定要求。

    p13_spi_mod
    图13. SPI四种传输模式

     

    时序要求


    具体时序要求参考器件手册。以下Motorola标准对CPHA = 0(图14)和CPHA =1(图15)不同设置时序的简要说明:

    CPHA = 0

    • 有些器件在片选后数据立即出现在MOSI/MISO管脚,数据锁存于第一个时钟边沿
    • 片选SS先于SCK半个时钟有效
    • 在SCK的第二个时钟边沿,上个时钟边沿锁存的数据写入移位寄存器(MSB或LSB)
    • 以此类推,数据在奇数边沿锁存,在偶数边沿写入移位寄存器
    • 经过16个时钟边沿后,串行传输的数据全部写入(并行的)移位寄存器,完成主从设备的数据交换
    p14_spi_cpha_0
    图14. SPI时钟模式(CPHA = 0)

     

    CPHA = 1

    • 有些设备要求数据输出在SCK第一个时钟边沿之后,数据锁存于第二个时钟边沿
    • 片选SS先于SCK半个时钟有效
    • 在SCK的第三个时钟边沿,上个时钟边沿锁存的数据写入移位寄存器(MSB或LSB)
    • 以此类推,数据在偶数边沿锁存,在奇数边沿写入移位寄存器
    • 经过16个时钟边沿后,串行传输的数据全部写入(并行的)移位寄存器,完成主从设备的数据交换
    p15_spi_cpha_1
    图15. SPI时钟模式(CPHA = 1)

     

    SPI通信过程


    简要说明STSpansion器件的SPI通讯过程。

     

    1. STMicroelectronics

    ST SPI规范定义,在系统启动后,主设备读取从设备8位SPI寄存器以确定从设备字长(16,24或32bit)及其它特性。每个帧(读/写)包括1个操作字节(Instruction Byte)和紧接着的1-3个数据字节(Data Byte)。

    操作字节可能是指令字节全局状态字节。记住指令字节总是出现在(主从)设备的输入管脚(SDI),全局状态字节总是出现在(主从)设备的输出管脚(SDO)。

    • Command Byte 指令字节
    p16_st_spi_cb
    图16. 指令字节格式

    指令字节前2位OC0/OC1指定SPI操作的四种类型,包括写操作、读操作、读和复位状态操作、读取设备信息操作;
    指令字节后6位Ax指定操作对象(RAM/ROM)的地址。

    • Global Byte 全局状态字节
    p17_st_spi_gb
    图17. 全局状态字节格式

    指示设备状态信息,如工作模式、通讯错误等。

    如下图18读写操作数据帧格式。对于写操作,SDO输出全局变量字节之后紧接着地址寄存器中先前缓存的数据;对于读操作,全局变量字节后紧接着寻址待取的数据。

    p19_st_spi_flow
    图18. SPI读写操作(ST)

     

    2. Spansion

    以常见的SPI接口Flash为例。如图19所示,在CS#低有效后,基于操作模式,决定在SCK的上升或下降沿触发采样数据。8位指令字节后紧接着24位地址,寻址Flash内部存储块。随着Flash容量增大,可能需要更多的寻址位。比如Micron的N25Q等器件,需要使能4 Byte地址模式以支持容量在128Mbit以上的器件。(单个地址寻址对应1 Byte数据,则24位地址寻址最大2^24 = 16 M Byte = 128Mbit)。

    p18_sp_spi_flash
    图19. SPI读操作(Spansion Flash)

     

    复位和中断


    复位后,寄存器值恢复初始状态(以上寄存器表下方所列出)。对于从设备,如果复位后不对SPIDR写入数据,它将输出随机数据或复位前从主设备接收到的数据;复位后SPIDR的数据全部清零。

    SPI的中断向量和优先级因设备而异。中断请求由状态寄存器SPISR中MODF、SPIF和SPTEF位逻辑或产生。

     

    协议分析


    利用示波器逻辑分析仪的SPI协议分析功能(电气特性 & 译码),可以快速定位通信链路上出现的问题。示波器支持不同的触发方式,以Tektronix示波器为例,其支持SPI的触发方式包括:

    • SS触发,基于片选信号状态变化触发
    • SOF触发,根据时钟空闲时间确定Start Of a Frame触发
    • MOSI触发,基于MOSI上特定的数据格式触发
    • MISO触发,基于MISO上特定数据格式触发
    • MOSI/MISO触发,基于MOSI和MISO上特定数据格式触发

     

    I2C & JTAG


    SPI和I2C,JTAG对比参考表3:

    t3_spi_i2c_jtag
    表3. SPI, I2C和JTAG协议概览

     

    参考资料


    1. Serial Peripheral Interface Bus -Wikipedia
    2. SPI Block Guide V04.01 -Motorola
    3. KeyStone Architecture User Guide: Serial Peripheral Interface, Literature Number: SPRUGP2A -Texas Instruments
    4. TN0897: ST SPI Protocol -STMicroelectronics
    5. Comparing Serial Interfaces -Spansion
    6. Serial Peripheral Interface Tutorial -Sparkfun
    7. Debugging Serial Buses in Embedded System Designs -Tektronix
    展开全文
  • 此外,还提供了如UART、CAN、SPI等 摘要 介绍dsPIc数字信号控制器以厦ISD4002语音芯片的功能特点;特别介绍dsPIC的SPl库函数的功能及使用,并给出一种简单的语音录放电路。具有低成本、易使用等特点,有较高的实用...
  • 1、首先为了驱动一款TFT屏,理所应当的应该知道屏幕的驱动芯片,比如我们这次使用的TFT屏就是ST7735R的驱动芯片,所以理所应当的要查找芯片手册,ST7735的芯片手册上网查也是一大堆,这个不赘述。 当然,一款驱动...
  • 在此基础上,根据TRF796x的时序特性和访问要求,采用ARM芯片的硬件 SPI方式实现对TRF796x的读写访问与控制,并在RFID门禁系统中验证了通信结果。  引言  SPI(同步串行外围接口)是由Motorola公司最早提出的,出现...
  • 基于STM32F4xxZGT6芯片核心板,利用单片机上的SPI1与Flash芯片进行读写,可可移植性高,便于读者阅读
  • ARM与射频芯片TRF796x的SPI通信研究,摘要:针对SPI总线接口缺乏标准协议的特点,提出了SPI器件之间通信的一般方法。论文阐述了ARM芯片内置SPI硬件控制器的工作原理和时序,并对射频芯片TRF7960x的工作模式与读写要求...
  • S32K144芯片基于FreeRTOS的SPI通信,有问题可以联系我
  • SPI通信详解

    千次阅读 多人点赞 2018-04-24 14:32:42
    SPI接口主要应用在EEPROM、FLASH、实时时钟、AD转换器等器件之间的通信。它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的引脚 数目, 同时为 PCB 在布局上节省了空间. 正是出于这...

    一、SPI简介

    1、什么是SPI?

    SPI是串行外设接口(Serial Peripheral Interface)的缩写,是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在EEPROM、FLASH、实时时钟、AD转换器等器件之间的通信。它在芯片中只占用四根管脚 (Pin) 用来控制以及数据传输, 节约了芯片的引脚 数目, 同时为 PCB 在布局上节省了空间. 正是出于这种简单易用的特性, 现在越来越多的芯片上都集成了 SPI技术。

    2、SPI的优点

    SPI支持高速、同步、全双工、非差分、总线式通信

    3、SPI的缺点

    没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据可靠性上有一定的缺陷。

    二、SPI物理连接

    1、主从模式

    SPI规定了两个SPI设备之间通信必须由主设备(Master)来控制从设备(Slave)。一个主设备可以通过时钟线和片选线来控制多个从设备,时钟线由主设备提供,从设备不能产生或控制时钟线。


    2、SPI物理连接方式

    SPI的物理连接比较简单,至少需要4根线(双向),其实要是单向通信的话,3根线也是可以的。这4根线分别是是SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。SPI通信没有读和写的说法,实质上每次通信都是数据的交换,也就是主设备发送了一个数据必会收到一个数据,要收到一个数据也要发送一个数据。

    (1)SDO/MOSI – 主设备数据输出,从设备数据输入;

    (2)SDI/MISO – 主设备数据输入,从设备数据输出;

    (3)SCLK – 时钟信号,由主设备产生;

    (4)CS/SS – 从设备使能信号,由主设备控制。当有多个从设备的时候,因为每个从设备上都有一个片选引脚接入到主设备机中,当我们的主设备和某个从设备通信时,要将从设备对应的片选引脚电平拉低或者是拉高。


    三、SPI通信的时序(四种模式)

    1、SPI通信支持四种模式,从设备从出厂开始可能就已经配置成某种模式,这是不能改变的,通信双方的通信模式要一致才能正常通信,我们只能配置主设备的通信模式。SPI的通信模式是通过CPOL(时钟极性)和CPHA(时钟相位)来控制我们主设备的通信模式。

    CPOL(时钟极性):用来配置SCLK的电平出于哪种状态时是空闲态或者有效态。

    (1)CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时;

    (2)CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时.。

    CPHA(时钟相位):用来配置数据采样是在SCL的第几个跳变边沿。

    (1)CPHA=0,表示数据采样是在第1个跳变边沿,数据发送在第2个跳变边沿。

    (2)CPHA=1,表示数据采样是在第2个跳变边沿,数据发送在第1个跳变边沿。

    对CPOL和CPHA进行不同设置是SPI通信的四种模式

    Mode0:CPOL=0,CPHA=0
    Mode1:CPOL=0,CPHA=1
    Mode2:CPOL=1,CPHA=0

    Mode3:CPOL=1,CPHA=1

    2、SPI通信时序分析

    CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。
    CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。
    CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。

    CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。


    3、注意事项

    需要注意的是:我们的主设备能够控制时钟,因为我们的SPI通信并不像UART或者IIC通信那样有专门的通信周期,有专门的通信起始信号,有专门的通信结束信号;所以我们的SPI协议能够通过控制时钟信号线,当没有数据交流的时候我们的时钟线要么是保持高电平要么是保持低电平。

    4、通信过程数据交换


    从图中可以看出, 主机和从机都有一个串行移位寄存器,主机通过向它的 SPI 串行寄存器写入一个字节来发起一次传输。寄存器通过 MOSI 信号线将字节传送给从机,从机也将自己的移位寄存器中的内容通过 MISO 信号线返回给主机。这样,两个移位寄存器中的内容就被交换。外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。



    展开全文
  • SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,这四根引脚分别是: SS(Slave Select)从设备片选信号,由主设备控制。 SCK(Serial Clock)时钟信号,由主设备产生。 MISO(Master ...

    通俗易懂,看这篇就够了!
    SPI 接口主要应用在 EEPROM, FLASH,实时时钟, AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,这四根引脚分别是:

    • SS(Slave Select)从设备片选信号,由主设备控制。
    • SCK(Serial Clock)时钟信号,由主设备产生。
    • MISO(Master Output,Slave Input) 主设备数据输入,从设备数据输出。
    • MOSI(Master Input,Slave Output) 主设备数据输出,从设备数据输入。
      在这里插入图片描述
      硬件连线如上图,从设备的SCK,MOSI,MISO线均并联到主机MCU上,但片选信号线要直接连在主机MCU上,当片选信号线拉低时,则开启该从机与主机间的通信。

    SPI根据时钟极性(CPOL)和时钟相位(CPHA)配置的不同,分为4种SPI模式。

    时钟极性:当SPI通信设备处于空闲时(也可以认为是SPI通信开始时,即片选信号SS被拉低时),SCK信号线的电平信号。CPOL=0时,SCK在空闲状态时为低电平,CPOL=1时,SCK为高电平。

    时钟相位:指数据采样的时刻。数据采样可以时发送,也可以是接收。当CPHA=0时,MOSI或MISO数据线上的信号将会在SCK时钟线的奇数边沿被采样。当CPHA=1时,数据线在SCK偶数边沿采样。
    在这里插入图片描述
    这选择主机四种模式时要看从机的模式,因为按照SPI通信的协议,主从双方使用的SPI模式应该一致,而并不是所有的从机设备都支持SPI的四种通信模式,可能只能支持其中的两种,这时选择模式时就要注意了。

    那SPI通信发送的过程是怎么样的呢?

    首先应该拉低我们要进行通信的从机设备片选信号SS,这个就不必多说了。

    然后,以时钟极性CPOL为0,时钟相位CPHA为0时(即初始时钟为低电平,在第奇数个时钟跳变信号,即上升沿时发送数据)为例:
    在这里插入图片描述
    数据(不论是发送的数据还是要接收的)在跳变信号到来前准备好,在时钟跳变时(上图为时钟上升沿)将数据发送出去,并开始准备新的数据。

    因此,我们可以通过三个标志位完全监控SPI通信的状态:

    发送缓冲器空闲标志(TXE):

    此标志为1时表明发送缓冲器为空,可以写入下一个待发送的数据。

    接收缓冲期非空(RXNE):

    此标志位为1时表明在接收缓冲器中包含有效的接收数据。

    忙(Busy)标志:

    BUSY标志有硬件设置与清除(写入此位无效果)。

    这时我们便可以理解下面函数内容了:
    在这里插入图片描述
    其中,SPI_I2S_GetFlagStatus();函数为检测标志位的库函数,SPI_I2S_SendData();和SPI_I2S_ReceiveData();为接收和发送数据的库函数。

    SPI初始化

    上述程序实现了接收和发送一个字节。

    那SPI初始化配置是如何的呢?

    在这里插入图片描述
    上图为SPI初始化函数。

    1:1处我们看出,我们可以用此SPI与多种设备进行通信。如果我们想用一个SPI接口同时连接这三个设备,并分别与之通信,就如本文第一张图所画那样。就需要三个片选信号线,但从下图可看出SPI1接口规定的只有一个片选信号线NSS。但其实没有关系,我们可以通过软件设置一个引脚拉低拉高就可以了。
    在这里插入图片描述
    2:在2处初始化了3个引脚分别为SPI1_SCK,SPI1_MISO,SPI1_MOSI。

    3:3处即为SPI接口初始化,结构体如图:
    在这里插入图片描述

    • SPI_Direction:选择数据传输是单向还是双向
    • SPI_Mode:设置SPI模式为主机模式还是从机模式。若为主机模式,则时钟SCK由主机产生。
    • SPI_DataSize:每次通信数据包大小。可以为8位或者16位。
    • SPI_CPOLSPI_CPHA分别位时钟极性和时钟相位
    • SPI_NSS:可设置为硬件模式或软件模式。硬件模式是SPI片选信号可自动产生,而软件模式则需要我们亲自把相应的GPIO口拉高或置低产生片选或非片选信号。如果我们需要同多个从设备进行通信,则往往设为软件模式。
    • SPI_BaudRatePrescaler:设置波特率分频值,可以为2,4,6,8,16,32,64,128,256。
    • SPI_FirstBit:所有串行的通信协议都会由MSB先行(高位数据在前)还是LSB先行(低位数据在前)的问题。
    • SPI_CRCPolynomial:SPI的CRC效验中的多项式。CRC校验仅用于保证全双工通信的可靠性。数据发送和数据接收分别使用单独的CRC计算器。通过对每一个接收位进行可编程的多项式运算来计算CRC。CRC的计算是在由SPI_CR1寄存器中CPHA和CPOL位定义的采样时钟边沿进行的。
      在这里插入图片描述
      按照原子哥的程序配置,我们便可以实现SPI发送数据了。

    编写从设备的驱动程序

    理解了SPI如何与设备发送数据后,我们常常还需要编写从设备的驱动程序。我们首先要知道设备使用的是什么通信协议,如有的设备使用的I2C通信方式,有的则是SPI通信方式。

    而不同的设备都会有不同的指令。这些指令也不过是主机按照基本的SPI通信协议发送的数据,只是其对从设备有特殊的意义,我们便是依靠通信来发送指令进而操作从设备的。

    例如我们对从设备发送写指令,随后我们发送的数据便将写入从设备之中。从设备的指令集,往往有厂家给出,有时还会附带设备驱动案例。
    在这里插入图片描述

    展开全文
  • SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,比如...
  •  介绍dsPIc数字信号控制器以厦ISD4002语音芯片的功能特点;特别介绍dsPIC的SPl库函数的功能及使用,并给出一种简单的语音录放电路。具有低成本、易使用等特点,有较高的实用价值。  1 dsPlC系列的简单介绍  ...
  • 通信协议篇——SPI通信

    千次阅读 2020-02-12 19:21:05
    通信协议篇——SPI通信

    通信协议篇——SPI通信

    1.简介

    SPI(Serial Peripheral Interface)是一种高速、同步、全双工串行通信总线,采用主从机通信模式,主要应用在EEPROM,FLASH,实时时钟,AD转换器等。

    2.原理

    通信方式

    SPI通信属于串行通信,利用芯片选择/使能线CS、串行时钟线SCLK、数据输入线DATAIN、数据输出线DATAOUT四线实现同步全双工通信。

    通信模式

    SIP通信有四种模式,由时钟极性和时钟相位设置不同模式;

    CPOL:时钟极性选择,为0时SPI总线空闲为低电平,为1时SPI总线空闲为高电平;

    CPHA:时钟相位选择,为0时在SCLK第一个跳变沿采样,为1时在SCLK第二个跳变沿采样;

    Mode0: CPOL=0,CPHA=0;SPI总线空闲状态为低电平,SCLK第一个跳变沿是上升沿,所以在时钟上升沿对数据采样,在时钟下降沿发送数据;

    Mode1: CPOL=0,CPHA=1;SPI总线空闲状态为低电平,SCLK第一个跳变沿是上升沿,所以在时钟上升沿发送数据,在时钟下降沿对数据采样;

    Mode2: CPOL=1,CPHA=0;SPI总线空闲状态为高电平,SCLK第一个跳变沿是下降沿,所以在时钟上升沿发送数据,在时钟下降沿对数据采样;

    Mode3: CPOL=1,CPHA=1;SPI总线空闲状态为高电平,SCLK第一个跳变沿是下降沿,所以在时钟上升沿对数据采样,在时钟下降沿发送数据;
    在这里插入图片描述

    数据格式

    SPI通信并没有固定的数据格式,可以根据不同的应用进行灵活地运用。数据内容大致可以分为三类——指令、地址、数据。以FLASH中的SPI为例,指令长度为8位,地址长度为24位,数据长度以字节为单位,数据格式主要有指令、指令+地址、指令+数据、指令+地址+数据。

    操作时序

    以FLASH的操作控制为例,展示几种SPI读写时序(采用Mode0或Mode3):

    1. 写使能:发送命令字0X06

    在这里插入图片描述

    1. Sector擦除:发送命令字0X20,再发送24位地址

    在这里插入图片描述

    1. 数据读:发送命令字0X03,再发送24位地址,然后接收数据

    在这里插入图片描述

    标准接口

    namedescriptiondirectionlength
    clk系统时钟input1
    rst复位信号input1
    spi_cs从机选择信号output1
    spi_clkSPI时钟信号output1
    spi_mosiSPI数据输出output1
    spi_misoSPI数据输入input1

    3.程序实现

    RTL视图

    在这里插入图片描述

    spi模块

    `timescale 1ns/1ps
    
    //Module Name	:	spi
    //Description	:	spi communication module
    //Editor		:	Yongxiang
    //Time			:	2020-02-03
    
    module spi
    	(
    		output	wire	flash_clk,
    		output 	reg		flash_cs,
    		output	reg		flash_datain,
    		input	wire	flash_dataout,
    		
          	input	wire	clock25M,
    		input	wire	flash_rstn,
    		input	wire[3:0]	cmd_type,
    		output	reg		Done_Sig,
    		input	wire[7:0]	flash_cmd,
    		input	wire[23:0]	flash_addr,
    		output 	reg[7:0]	mydata_o,
    		output	wire	myvalid_o
    	);
    
    assign myvalid_o = myvalid;
    assign flash_clk = spi_clk_en ? clock25M : 1'b0;
    
    reg myvalid;
    reg[7:0] mydata;
    reg spi_clk_en = 1'b0;
    reg data_come;
    
    parameter idle = 3'b000;
    parameter cmd_send = 3'b001;
    parameter address_send = 3'b010;
    parameter read_wait = 3'b011;
    parameter write_data = 3'b101;
    parameter finish_done = 3'b110;
    
    reg[2:0] spi_state;
    reg[7:0] cmd_reg;
    reg[23:0] address_reg;
    reg[7:0] cnta;
    reg[8:0] write_cnt;
    reg[7:0] cntb;
    reg[8:0] read_cnt;
    reg[8:0] read_num;
    reg read_finish;
    
    //发送读flash命令
    always @(negedge clock25M)
    begin
    	if(!flash_rstn)begin
    		flash_cs <= 1'b1;		
    		spi_state <= idle;
    		cmd_reg <= 8'd0;
    		address_reg <= 24'd0;
    	   spi_clk_en <= 1'b0;		//SPI clock输出不使能
    		cnta <= 8'd0;
    		write_cnt <= 9'd0;
    		read_num <= 9'd0;	
    		Done_Sig <= 1'b0;
    	end
    	else begin
    		case(spi_state)
    			idle:begin	//idle 状态		  
    				spi_clk_en <= 1'b0;
    				flash_cs <= 1'b1;
    				flash_datain <= 1'b1;	
    			   cmd_reg <= flash_cmd;
                address_reg <= flash_addr;
    		      Done_Sig <= 1'b0;				
    				if(cmd_type[3] == 1'b1)begin	//bit3为命令请求,高表示操作命令请求
    					spi_state <= cmd_send;
    					cnta <= 8'd7;		
    					write_cnt <= 9'd0;
    					read_num <= 9'd0;					
    				end
    			end
    			
    			cmd_send:begin	//发送命令状态	
    			   spi_clk_en <= 1'b1;	//flash的SPI clock输出
    				flash_cs <= 1'b0;	//cs拉低
    			   if(cnta > 8'd0)begin	//如果cmd_reg还没有发送完
    					flash_datain <= cmd_reg[cnta];	//发送bit7~bit1位
                   cnta <= cnta - 8'd1;
    				end
    				else begin	//发送bit0
    					flash_datain <= cmd_reg[0];
    					if((cmd_type[2:0] == 3'b001) | (cmd_type[2:0] == 3'b100))begin	//如果是Write Enable/disable instruction
    						spi_state <= finish_done;
    					end						 
    					else if(cmd_type[2:0] == 3'b011)begin	//如果是read register1
    						spi_state <= read_wait;
    						cnta <= 8'd7;
    						read_num <= 9'd1;	//接收一个数据
    					end	 
    					else begin	//如果是sector erase, page program, read data,read device ID      
    						spi_state <= address_send;
    						cnta <= 8'd23;
    					end
    				end
    			end
    			
    			address_send:begin	//发送flash address	
    			   if(cnta > 8'd0)begin	//如果cmd_reg还没有发送完
    					flash_datain <= address_reg[cnta];	//发送bit23~bit1位
                   cnta <= cnta - 8'd1;						
    				end				
    				else begin	//发送bit0
    					flash_datain <= address_reg[0];   
                   if(cmd_type[2:0] == 3'b010)begin	//如果是	sector erase
     						spi_state <= finish_done;	
                   end
                   else if(cmd_type[2:0] == 3'b101)begin	//如果是page program				
    				      spi_state <= write_data;
    						cnta <= 8'd7;                       
    					end
    					else if(cmd_type[2:0] == 3'b000)begin	//如果是读Device ID
    					   spi_state <= read_wait;
    						read_num <= 9'd2;		//接收2个数据的Device ID
                   end						 
    					else begin
    					   spi_state <= read_wait;
    						read_num <= 9'd256;	//如果是block读命令,接收256个数据							 
                   end						 
    				end
    			end
    			
    			read_wait:begin	//等待flash数据读完成
    				if(read_finish)begin
    					spi_state <= finish_done;
    					data_come <= 1'b0;
    				end
    				else begin
    					data_come <= 1'b1;
    				end
    			end
    			
    			write_data:begin	//写flash block数据
    				if(write_cnt < 9'd256)begin	// program 256 byte to flash
    					if(cnta > 8'd0)begin	//如果data还没有发送完
    						flash_datain <= write_cnt[cnta];	//发送bit7~bit1位
                      cnta <= cnta - 8'd1;						
    					end				
    					else begin                                 
    						flash_datain <= write_cnt[0];	//发送bit0
    					   cnta <= 8'd7;
    					   write_cnt <= write_cnt + 9'd1;
    					end
    				end
    				else begin
    					spi_state <= finish_done;
    					spi_clk_en <= 1'b0;
    				end 
    			end
    			
    			finish_done:begin	//flash操作完成
    				flash_cs <= 1'b1;
    				flash_datain <= 1'b1;
    				spi_clk_en <= 1'b0;
    				Done_Sig <= 1'b1;
    				spi_state <= idle;
    			end
    			
    			default:begin
    				spi_state <= idle;
    			end
    			
    		endcase;		
    	end
    end
    	
    //接收flash数据	
    always @(posedge clock25M)
    begin
    	if(!flash_rstn)begin
    		read_cnt <= 9'd0;
    		cntb <= 8'd0;
    		read_finish <= 1'b0;
    		myvalid <= 1'b0;
    		mydata <= 8'd0;
    		mydata_o <= 8'd0;
    	end
    	else begin
    		if(data_come)begin
    			if(read_cnt < read_num)begin	//接收数据			  
    				if(cntb < 8'd7)begin	//接收一个byte的bit0~bit6		  
    					myvalid <= 1'b0;
    					mydata <= {mydata[6:0], flash_dataout};
    					cntb <= cntb + 8'd1;
    				end
    				else begin
    					myvalid <= 1'b1;	//一个byte数据有效
    					mydata_o <= {mydata[6:0], flash_dataout};	//接收bit7
    					cntb <= 8'd0;
    					read_cnt <= read_cnt + 9'd1;
    				end
    			end				 			 
    			else begin 
    				read_cnt <= 9'd0;
    				read_finish <= 1'b1;
    				myvalid <= 1'b0;
    			end
    		end
    		else begin
    			read_cnt <= 9'd0;
    			cntb <= 8'd0;
    			read_finish <= 1'b0;
    			myvalid <= 1'b0;
    			mydata <= 8'd0;
    		end
    	end
    end	
    
    endmodule
    
    

    flash_control模块

    `timescale 1ns/1ps
    
    //Module Name	:	flash_control
    //Description	:	flash read and write control
    //Editor		:	Yongxiang
    //Time			:	2020-02-03
    
    module flash_control
        (
            input	wire	CLK,
            input	wire	RSTn,
            output	reg		clock25M,
            output	reg[3:0]	cmd_type,
            input	wire	Done_Sig,
            output	reg[7:0]	flash_cmd,
            output	reg[23:0]	flash_addr,
            input	wire[7:0]	mydata_o,
            input	wire	myvalid_o
        );
     
    reg[3:0] i;
    reg[7:0] time_delay;
    
    //FLASH 擦除,Page Program,读取程序	
    always @(posedge clock25M)
    begin
       if(!RSTn)begin
    		i <= 4'd0;
    		flash_addr <= 24'd0;
    		flash_cmd <= 8'd0;
    		cmd_type <= 4'b0000;
    		time_delay <= 8'd0;
    	end
    	else begin
    	   case(i)
    			4'd0:begin	//读Device ID
    				if( Done_Sig )begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h90;
    					flash_addr <= 24'd0;
    					cmd_type <= 4'b1000;
    				end	
    			end
    			
    	      4'd1:begin	//写Write Enable instruction
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h06;
    					cmd_type <= 4'b1001;
    				end
    			end
    			
    			4'd2:begin	//Sector擦除
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type<=4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h20;
    					flash_addr <= 24'd0;
    					cmd_type <= 4'b1010;
    				end
    			end
    			
    	      4'd3:begin	//waitting 100 clock
    				if(time_delay < 8'd100)begin
    					flash_cmd <= 8'h00;
    					time_delay <= time_delay + 8'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					i <= i + 4'd1;
    					time_delay <= 8'd0;
    				end	
    			end
    			
    			4'd4:begin	//读状态寄存器1, 等待idle
    				if(Done_Sig)begin 
    					if(mydata_o[0] == 1'b0)begin
    						flash_cmd <= 8'h00;
    						i <= i + 4'd1;
    						cmd_type <= 4'b0000;
    					end
    					else begin
    						flash_cmd <= 8'h05;
    						cmd_type <= 4'b1011;
    					end
    				end
    				else begin
    					flash_cmd <= 8'h05;
    					cmd_type <= 4'b1011;
    				end
    			end
    			
    	      4'd5:begin	//写Write disable instruction
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h04;
    					cmd_type <= 4'b1100;
    				end
    			end
    			
    			4'd6:begin	//读状态寄存器1, 等待idle
    				if(Done_Sig)begin
    					if(mydata_o[0] == 1'b0)begin
    						flash_cmd <= 8'h00;
    						i <= i + 4'd1;
    						cmd_type <= 4'b0000;
    					end
    					else begin
    						flash_cmd <= 8'h05;
    						cmd_type <= 4'b1011;
    					end
    				end
    				else begin
    					flash_cmd <= 8'h05;
    					cmd_type <= 4'b1011;
    				end
    			end
    			
    	      4'd7:begin	//写Write Enable instruction
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h06;
    					cmd_type <= 4'b1001;
    				end 
    			end
    			
    	      4'd8:begin	//waitting 100 clock
    				if(time_delay < 8'd100)begin
    					flash_cmd <= 8'h00;
    					time_delay <= time_delay + 8'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					i <= i + 4'd1;
    					time_delay <= 8'd0;
    				end	
    			end
    			
    	      4'd9:begin	//page program: write 0~255 to flash
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h02;
    					flash_addr <= 24'd0;
    					cmd_type <= 4'b1101;
    				end
    			end
    			
    	      4'd10:begin	//waitting
    				if(time_delay < 8'd100)begin
    					flash_cmd <= 8'h00;
    					time_delay <= time_delay + 8'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					i <= i + 4'd1;
    					time_delay <= 8'd0;
    				end	
    			end
    			
    			4'd11:begin	//读状态寄存器1, 等待idle
    				if(Done_Sig)begin 
    					if(mydata_o[0] == 1'b0)begin
    						flash_cmd <= 8'h00;
    						i <= i + 4'd1;
    						cmd_type <= 4'b0000;
    					end
    					else begin
    						flash_cmd <= 8'h05;
    						cmd_type <= 4'b1011;
    					end
    				end
    				else begin
    					flash_cmd <= 8'h05;
    					cmd_type <= 4'b1011;
    				end
    			end
    			
    	      4'd12:begin	//写Write disable instruction
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h04;
    					cmd_type <= 4'b1100;
    				end		
    			end
    			
    			4'd13:begin	//读状态寄存器1, 等待idle
    				if(Done_Sig)begin
    					if(mydata_o[0] == 1'b0)begin
    						flash_cmd <= 8'h00;
    						i <= i + 4'd1;
    						cmd_type <= 4'b0000;
    					end
    					else begin
    						flash_cmd <= 8'h05;
    						cmd_type <= 4'b1011;
    					end
    				end
    				else begin
    					flash_cmd <= 8'h05;
    					cmd_type <= 4'b1011;
    				end
    			end
    			
    			4'd14:begin	//read 256byte
    				if(Done_Sig)begin
    					flash_cmd <= 8'h00;
    					i <= i + 4'd1;
    					cmd_type <= 4'b0000;
    				end
    				else begin
    					flash_cmd <= 8'h03;
    					flash_addr <= 24'd0;
    					cmd_type <= 4'b1110;
    				end
    			end
    			
    			4'd15:begin	//idle
    				i <= 4'd15;
    			end
    			
    		endcase
    	end
    end
    
    
    //产生25Mhz的SPI Clock		  
    always @(posedge CLK)
    begin
       if(!RSTn)begin
    		clock25M <= 1'b0;
    	end
    	else begin
    		clock25M <= ~clock25M;
    	end
    end
    
    endmodule
    
    

    顶层模块

    `timescale 1ns/1ps
    
    //Module Name	:	flash
    //Description	:	top_file
    //Editor		:	Yongxiang
    //Time			:	2020-02-03
    
    module flash
        (
           	input	wire	CLK,
            input	wire	RSTn,
    
           	output	wire	flash_clk,		//spi flash clock 
            output	wire	flash_cs,		//spi flash cs 
            output	wire	flash_datain,	//spi flash data input  
            input	wire	flash_dataout	//spi flash data output
        );
    
    wire[7:0] flash_cmd;
    wire[23:0] flash_addr;
    wire clock25M;
    wire[3:0] cmd_type;
    wire Done_Sig;
    wire[7:0] mydata_o;
    wire myvalid_o;
    
    //spi通信
    spi spi_inst
        (
            .flash_clk(flash_clk),
            .flash_cs(flash_cs),
            .flash_datain(flash_datain),  
            .flash_dataout(flash_dataout),    
    
            .clock25M(clock25M),		//input clock
            .flash_rstn(RSTn),		//input reset 
            .cmd_type(cmd_type),		// flash command type		  
            .Done_Sig(Done_Sig),		//output done signal
            .flash_cmd(flash_cmd),	// input flash command 
            .flash_addr(flash_addr),// input flash address 
            .mydata_o(mydata_o),		// output flash data 
            .myvalid_o(myvalid_o)	// output flash data valid 		
        );
    
    //flash控制
    flash_control flash_control_inst
        (
           	.CLK(CLK),
            .RSTn(RSTn),
            .clock25M(clock25M),
            .cmd_type(cmd_type),
            .Done_Sig(Done_Sig),
            .flash_cmd(flash_cmd),
            .flash_addr(flash_addr),
            .mydata_o(mydata_o),
            .myvalid_o(myvalid_o)
        );
    
    endmodule
    
    
    展开全文
  • 两块板子之间的stm32spi通信例程

    热门讨论 2011-11-09 15:29:44
    本例程适合于刚开始接触stm32spi的程序员 本程序配备有详细的注解
  • SPI 通信原理详述

    千次阅读 2020-06-29 15:17:09
    SPI 通信原理详述新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...
  • SPI通信

    万次阅读 多人点赞 2018-03-26 16:49:28
    1 SPI的简介及基本特点1 SPI的简单介绍最近工作中使用了SPI通信方式来做TM4C129和STM32之间的通信,为了更好地解决问题就学习了SPI原理的相关内容,完成了项目之后,也对这种通信方式有了较为深入的了解,现在来对...
  • 串口通信协议之SPI通信协议

    千次阅读 2020-07-01 23:14:23
    串口通信协议之SPI通信协议 SPI通信协议 什么是SPI? SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一 种同步串行接口技术,是一种高速的,全双工,同步的通信总线。 SPI优点...
  • 嵌入式实验 之 SPI通信实验

    千次阅读 2019-09-25 17:33:34
    文章目录【实验目的】【实验原理】一、SPI原理二、SPI特性三、SPI库函数分析四、蓝牙模块NRF2401五、软件流程图【实验环境】操作系统硬件设备软件【实验步骤】一、配置工程环境二、开启时钟,完...
  • 软件模拟SPI串口实现单片机与液晶驱动芯片通信的方法
  • SPI通信分析

    2021-07-14 21:36:57
    STM官方的芯片手册中对于SPI通信模式的配置过程,CPHA和CPCL的配置对于通信模式的影响如下图所示: note :中断模式下的连续从机数据传输。 STM32通信接口介绍: 对于STM32F103ZET6配置: Up to 13 ...
  • SPI通信协议基础

    千次阅读 2020-08-12 09:01:17
    当您将微控制器连接到传感器,显示器或其他模块时,您是否考虑过这两种设备如何相互通信?他们到底在说什么?他们如何互相了解?
  •  介绍dsPIc数字信号控制器以厦ISD4002语音芯片的功能特点;特别介绍dsPIC的SPl库函数的功能及使用,并给出一种简单的语音录放电路。具有低成本、易使用等特点,有较高的实用价值。  1 dsPlC系列的简单介绍  ...
  • SPI(Serial Peripheral Interface)总线是主要应用于嵌入式系统内部通信的串行同步传输总线协议。通常为四线制的SPI总线支持全双工通信SPI最初由Motorola在2000年提出,Motorola所定义的SPI标准为业界广泛引用,...
  • 什么是SPI通信

    千次阅读 2020-10-10 11:55:13
    ARM体系-SPI通信 一、什么是SPI通信 1、SPI是串行外设接口(Serial Peripheral Interface),可以理解为一种通信协议,也就是用来传输数据的。 2、SPI 是由摩托罗拉(Motorola)公司开发的全双工同步串行总线,是微处理...
  • SPI通信简介

    2019-06-27 22:58:43
    SPI简介SPI特点1采用主-从模式Master-Slave 的控制方式 2采用同步方式Synchronous传输数据3数据交换Data Exchanges4 SPI有四种传输模式5 SPI只有主模式和从模式之分工作机制 1概述2 Timing 21 SPI相关...
  • 用verilog 写的与ADC121S101通过SPI通信的程序 ,希望对有写ADC SPI的朋友有帮助
  • STM32之SPI通信

    万次阅读 多人点赞 2017-12-15 15:15:19
    考虑到之前是结合Flash芯片来学的,十分不直观,而且主要把时间和精力都花在Flash芯片的datasheet和驱动上了,SPI通信也没学好。所以这次就考虑用4位数码管显示模块,模块是直接买的现成的,如下图所示,这样可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,526
精华内容 5,810
关键字:

双spi通信芯片