一、SPI总线
1、SPI简介
SPI,是Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
2、SPI特征
● 3线全双工同步传输
● 8或16位传输帧格式选择
● 主或从操作,支持多主模式
● 8个主模式波特率预分频系数(最大为fPCLK/2)
● 主模式和从模式下均可以由软件或硬件进行NSS管理:主/从操作模式的动态改变
● 可编程的时钟极性和相位
● 可编程的数据顺序,MSB在前或LSB在前
● 可触发中断的专用发送和接收标志
● SPI总线忙状态标志
● 支持可靠通信的硬件CRC
● 可触发中断的主模式故障、过载以及CRC错误标志
● 支持DMA功能的1字节发送和接收缓冲器:产生发送和接受请求
3、SPI工作模式
SPI通信中可作为从机也可以作为主机,这取决于硬件设计和软件设置。
当器件作为主机时,使用一个IO引脚拉低相应从机的选择引脚(NSS),传输的起始由主机发送数据来启动,时钟(SCK)信号由主机产生。通过MOSI发送数据,同时通过MISO引脚接收从机发出的数据。
当器件作为从机时,传输在从机选择引脚(NSS)被主机拉低后开始,接收主机输出的时钟信号,在读取主机数据的同时通过MISO引脚输出数据。
4、SPI框图
5、通常SPI通过4个引脚与外部器件相连:
● MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
● MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
● SCK: 串口时钟,作为主设备的输出,从设备的输入。
● NSS: 从设备选择。这是一个可选的引脚,用来选择主/从设备。它的功能是用来作为“片选引脚”,让主设备可以单独地与特定从设备通讯,避免 数据线上的冲突。从设备的NSS引脚可以由主设备的一个标准I/O引脚来驱动。
6、(NSS)输出管理
对于每个SPI的NSS可以输入,也可以输出。所谓输入,就是NSS的电平信号给自己,所谓输出,就是将NSS的电平信号发送出去,给从机。配置为输出,还是不输出,我们可以通过SPI_CR2寄存器的SSOE位。当SSOE=1时,并且SPI处于主模式控制时(MSTR=1),NSS就输出低电平,也就是拉低,因此当其他SPI设备的NSS引脚与它相连,必然接收到低电平,则片选成功,都成为从设备了。
7、 (NSS)输入管理
NSS软件模式:
1.SPI主机:
需要设置SPI_CR1寄存器的SSM=1和SSI=1,SSM=1是为了使能软件管理,NSS有内部和外部引脚。这时候外部引脚留作他用(可以用来作为GPIO驱动从设备的片选信号)。内部NSS引脚电平则通过SPI_CRL寄存器的SSI位来驱动。SSI=1是为了使NSS内电平为高电平。为什么主设备的内部NSS电平要为1呢?
STM32手册上说,要保持MSTR=1和SPE=1,也就是说要保持主机模式,只有NSS接到高电平信号时,这两位才能保持置‘1’。
2.SPI从机: NSS引脚在完成字节传输之前必须连接到一个低电平信号。在软件模式下,则需要设置SPI_CR1寄存器的SSM=1(软件管理使能)和SSI=0.
NSS硬件模式:
对于主机,我们的NSS可以直接接到高电平.对于从机,NSS接低就可以。
8、单主和单从应用
9、时钟信号的相位和极性
SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态保持低电平;如果CPOL被置’1’,SCK引脚在空闲状态保持高电平。如果CPHA(时钟相位)位被置’1’,SCK时钟的第二个边沿(CPOL位为0时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。如果CPHA位被清’0’,SCK时钟的第一边沿(CPOL位为’0’时就是下降沿,CPOL位为’1’时就是上升沿)进行数据位采样,数据在第一个时钟边沿被锁存。
CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。
(1)数据时钟时序图
(2).数据时钟时序图
10、数据帧格式
根据SPI_CR1寄存器中的LSBFIRST位,输出数据位时可以MSB在先也可以LSB在先。根据SPI_CR1寄存器的DFF位,每个数据帧可以是8位或是16位。所选择的数据帧格式对发送和/或接收都有效。
11、SPI主模式工作原理
配置SPI主模式的步骤如下:
设置SPI_CR1寄存器的BR[2:0]位,来定义串行时钟波特率。
选择CPOL和CPHA位,定义数据传输和串行时钟间的相位关系。
设置DFF位来定义8或16位数据帧格式。
配置SPI_CR1寄存器的LSBFIRST位定义帧格式。
如果NSS引脚需要工作在输入模式,硬件模式中在整个数据帧传输期间应把NSS引脚连接到高电平;在软件模式中,需设置SPI_CR1寄存器的SSM=1和SSI=1。如果NSS引脚工作在输出模式,则只需设置SSOE=1位。
设置MSTR=1和SPE=1,只当NSS引脚被连到高电平,这些位才能保持置位。
12、SPI从模式工作原理
配置SPI从模式的步骤如下:
设置DFF位以定义数据帧格式为8位或16位。
定义数据传输和串行时钟之间的相位关系。
帧格式必须和主设备相同,MSB在前还是LSB在前取决于SPI_CR1寄存器中的LSBFIRST位。
硬件模式下,在完整的数据帧(8位或16位)发送过程中,NSS引脚必须为低电平。软件模式下,设置SPI_CR1寄存器中的SSM=1,SSI=0。
MSTR=0位,设置SPE=1,使相应引脚工作于SPI模式下。
13、状态标志
应用程序通过3个状态标志可以完全监控SPI总线的状态。
1.发送缓冲器空闲标志(TXE)
此标志为’1’时表明发送缓冲器为空,可以写下一个待发送的数据进入缓冲器中。当写入SPI_DR时,TXE标志被清除。
2.接收缓冲器非空(RXNE)
此标志为’1’时表明在接收缓冲器中包含有效的接收数据。读SPI数据寄存器可以清除此标志。
3.忙(Busy)标志
BSY标志由硬件设置与清除(写入此位无效果),此标志表明SPI通信层的状态。
14、SPI中断
二、SST25VF016B工作原理
1、特性
2、框图
3、引脚说明
5、器件操作
SST25VF016B 支持 SPI 总线操作的模式 0(0,0)和模式 3(1,1)。两种模式之间的差异在于当总线主器件处于待机模式并且没有数据传送时的SCK信号状态。SCK信号在模式 0 时为低电平,在模式 3 时为高电平。对于这两种模式,串行数据输入 (SI)在 SCK 时钟信号的上升沿被采样,串行数据输出 (SO)在 SCK 时钟信号的下降沿之后被驱动。
6、写保护引脚 (WP#)
写保护 (WP#)引脚用于使能状态寄存器的 BPL 位 (bit 7)的锁定功能。当 WP# 驱动为低电平时,是否执行写状态寄存器 (WRSR)指令由 BPL 位的值 (见表 2)决定。当 WP# 为高电平时, BPL 位的锁定功能被禁止。
7、状态寄存器
软件状态寄存器提供有关闪存存储器阵列是否可进行任何读或写操作的状态、器件是否写使能以及存储器写保护的状态。在内部擦除或编程操作期间,可对状态寄存器只进行读操作,以确定正在进行的操作的完成状态。
8、写使能锁存器 (WEL)
写使能锁存器 (Write-Enable Latch, WEL)位表示内部寄存器的写使能锁存器状态。如果写使能锁存器位置 “1”,则表示器件写使能。如果该位置 “0”(复位),则表示器件未写使能,并且不接受任何存储器写 (编程 / 擦除)命令。在下列条件下,写使能锁存器位自动复位:
•上电
•写禁止 (WRDI)指令完成
•字节编程指令完成
•自动地址递增 (AAI)编程完成或达到其最高的不受保护的存储器地址
•扇区擦除指令完成
•块擦除指令完成
•全片擦除指令完成
•写状态寄存器指令
9、块保护 (BP3、 BP2、 BP1 和 BP0)
块保护(BP3、BP2、BP1 和 BP0)位定义了要通过软件保护方式防止任何存储器写(编程或擦除)操作的存储器区域的大小,如表 4 中定义。只要 WP# 为高电平或块保护锁定(Block-Protect-Lock,BPL)位为 0,就可以使用写状态寄存器(WRSR)指令编程 BP3、 BP2、 BP1 和 BP0 位。仅当块保护位全部为 0 时,才能执行全片擦除。上电后, BP3、 BP2、 BP1 和 BP0 置为 1。
10、块保护锁定 (BPL)
WP# 引脚驱动为低电平 (VIL)时,将使能块保护锁定 (BPL)位。当 BPL 置 1 时,将阻止对 BPL、BP3、BP2、BP1 和 BP0 位的任何进一步修改。当 WP# 引脚驱动为高电平(VIH) 时,BPL 位没有任何作用,其值为 “无关”。上电后, BPL 位复位为 0。
11、指令
指令用于读、写 (擦除和编程)和配置 SST25VF016B。指令总线周期是 8 个表示命令 (操作码)、数据和地址的位。在执行任何字节编程、自动地址递增 (AAI)编程、扇区擦除、块擦除、写状态寄存器或全片擦除指令之前,必须先执行写使能 (WREN)指令。表 5 提供了完整的指令列表。所有指令在CE# 从高电平转换到低电平时同步。在 SCK 的上升沿从最高有效位开始接受输入。在输入指令之前,CE# 必须驱动为低电平,而在输入指令的最后一位后,CE# 必须驱动为高电平(读、读 ID 和读状态寄存器指令除外)。在接收到指令总线周期的最后一位之前,CE# 上任何低电平到高电平的转换都将终止正在进行的指令,并将器件恢复为待机模式。指令命令(操作码)、地址和数据都先从最高有效位(MostSignificant Bit, MSb)输入。
12、读 (25 MHz)
读指令 (03H)支持最高为 25 MHz 的读操作。器件从指定的地址单元开始输出数据。数据输出流连续遍历所有地址,直到被 CE# 上低电平到高电平的转换终止。内部地址指针将自动递增,直到达到最高的存储器地址为止。达到最高的存储器地址后,地址指针将自动递增到地址空间的开始位置 (回绕)。从地址单元 1FFFFFH 读取数据之后,下一次输出将来自地址单元 000000H。通过执行 8 位命令 03H(后面紧跟地址位 [A23-A0])来启动读指令。在读周期的持续时间内,CE# 必须保持有效低电平。
13、高速读 (80 MHz)
高速读指令支持最高为 80 MHz 的读操作,通过执行 8 位命令 0BH(后面紧跟地址位 [A23-A0] 和一个空字节)来启动。在高速读周期的持续时间内,CE# 必须保持有效低电平。有关高速读序列,请参见图 6。在一个空周期之后,高速读指令从指定的地址单元开始输出数据。数据输出流连续遍历所有地址,直到被 CE# 上低电平到高电平的转换终止。内部地址指针将自动递增,直到达到最高的存储器地址为止。达到最高的存储器地址后,地址指针将自动递增到地址空间的开始位置 (回绕)。从地址单元 1FFFFFH读取数据之后,下一次输出将来自地址单元 000000H。
14、字节编程
字节编程指令用于将所选字节中的位编程为所需数据。当启动编程操作时,所选字节必须处于擦除状态(FFH)。应用到受保护存储器区域的字节编程指令将被忽略。在执行任何写操作之前,必须先执行写使能(WREN)指令。在字节编程指令的持续时间内,CE# 必须保持有效低电平。通过执行 8 位命令 02H (后面紧跟地址位 [A23-A0])来启动字节编程指令。在地址后面,按照从 MSb(bit 7)到 LSb(bit 0)的顺序输入数据。在执行指令之前,CE# 必须驱动为高电平。用户可以轮询软件状态寄存器中的 BUSY 位,或等待 TBP(10µs)时间让内部自定时字节编程操作完成。
15、自动地址递增 (AAI)字编程
AAI 编程指令允许对多个字节的数据进行编程,无需再次发出下一连续地址单元。当要对多个字节或整个存储器阵列编程时,该特性可减少总编程时间。指向受保护存储器区域的 AAI 字编程指令将被忽略。当启动 AAI 字编程操作时,所选地址范围必须处于已擦除状态(FFH)。
当处于 AAI 字编程序列中时,仅下列指令有效: 1 软件写操作结束检测指令 AAI 字(ADH)、写禁止WRDI(04H)、读取状态寄存器RDSR(05H)。 2.硬件写操作结束检测指令 AAI 字(ADH)、写禁止 WRDI(04H)。
在执行任何写操作之前,必须先执行写使能(WREN)指令。通过执行 8 位命令 ADH(后面紧跟地址位[A23-A0])来启动 AAI 字编程指令。在地址后面,连续输入两个字节的数据,每个字节都从 MSb(Bit 7)到 LSb (Bit 0)。 在执行 AAI 字编程指令之前, CE# 必须驱动为高电平。在输入下一个有效命令之前,请检查 BUSY 状态。一旦器件指示不再忙,就可以对下两个连续地址的数据进行编程,然后对再下两个连续地址的数据进行编程,依此类推。
当编程最后一个所需字或最高的不受保护存储器地址时,通过硬件或软件(RDSR 指令)方法检查忙状态,以确定编程是否完成。编程完成之后,使用适用的方法终止 AAI。如果器件处于软件写操作结束检测模式,则执行写禁止 (WRDI)指令 04H。如果器件处于 AAI 硬件写操作结束检测模式,则执行写禁止(WRDI)指令 04H,再执行 8 位 DBSY 命令 80H。在达到最高的不受保护的存储器地址之后,AAI编程期间不存在回绕模式。
(1)使用硬件写操作结束检测时的自动地址递增 (AAI)字编程序列
(2)使用软件写操作结束检测时的自动地址递增 (AAI)字编程序列
16、4 KB 扇区擦除
扇区擦除指令会将所选 4 KB 扇区中的所有位清除为 FFH。应用到受保护存储器区域的扇区擦除指令将被忽略。在执行任何写操作之前,必须先执行写使能 (WREN)指令。在任何命令序列的持续时间内,CE# 都必须保持有效低电平。通过执行 8 位命令 20H (后面紧跟地址位 [A23-A0])来启动扇区擦除指令。在执行指令之前,CE#必须驱动为高电平。用户可以轮询软件状态寄存器中的 BUSY 位,或等待 TSE(25ms)时间让内部自定时扇区擦除周期完成。
17、32 KB 和 64 KB 块擦除
17、全片擦除
全片擦除指令会将器件中的所有位清除为 FFH。如果有任何存储器区域受到保护,全片擦除指令将被忽略。在执行任何写操作之前,必须先执行写使能 (WREN)指令。在全片擦除指令序列的持续时间内,CE# 必须保持有效低电平。通过执行 8 位命令 60H 或 C7H 来启动全片擦除指令。在执行指令之前,CE#必须驱动为高电平。用户可以轮询软件状态寄存器中的 BUSY 位,或等待 TCE(50ms)时间让内部自定时全片擦除周期完成。
18、读取状态寄存器 (RDSR)
读取状态寄存器(RDSR)指令允许读取状态寄存器。可在任何时间读取状态寄存器,甚至是在写(编程 / 擦除)操作期间。当进行写操作时,应在发送任何新命令前检查 BUSY 位,以确保新命令会被器件正确接收。在输入 RDSR 指令之前,CE# 必须驱动为低电平,并保持低电平直到状态数据被读取为止。读状态寄存器继续使用当前时钟周期,直到被 CE# 上低电平到高电平的转换终止。
19、使能写状态寄存器 EWSR、写状态寄存器WRSR
写状态寄存器指令将新值写入状态寄存器的 BP3、BP2、BP1、BP0 和 BPL 位。在输入 WRSR(0x01) 指令的命令序列之前,需先输入EWSR(0x50)使能写状态寄存器。
20、写使能 (WREN)
写使能 (WREN)指令可将状态寄存器中的写使能锁存器位设置为 “1”,以允许进行写操作。在执行任何写 (编程 / 擦除)操作之前,都必须先执行 WREN 指令。 在执行 WREN 指令之前, CE# 必须驱动为高电平。
21、写禁止 (WRDI)
写禁止 (WRDI)指令将写使能锁存器位和 AAI 位复位为 0,以禁止任何新的写操作发生。 WRDI 指令不会终止任何正在进行的编程操作。执行WRDI指令之后,所有正在进行的编程操作都可以持续到TBP。在执行 WRDI 指令之前, CE# 必须驱动为高电平。
22、读 ID (RDID)
读ID指令(RDID)将器件标识为SST25VF016B,将制造商标识为SST。此命令向后兼容所有SST25xFxxxA器件,当在一个设计中使用多个版本的 SPI 串行闪存器件时,应将此命令用作默认器件标识命令。通过执行 8 位命令 90H 或 ABH(后面紧跟地址位 [A23-A0])来读取器件信息。执行读 ID 指令之后,制造商ID 位于地址 00000H,器件 ID 位于地址 00001H。器件处于读 ID 模式之后,制造商 ID 和器件 ID 输出数据在地址 00000H 和 00001H 之间翻转,直到被 CE# 上低电平到高电平的转换终止。
23、产品订购信息
三、例程:用SPI读取 SST25VF016Bflash
1、例程代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /************************************************************************************************************************************* 2 * 3 * 文件名称:main.c 4 * 文件功能:主函数文件 5 * 6 ***************************************************************************************************************************************/ 7 8 #include "pbdata.h"//调用自定义公共函数库 9 10 11 /********************************************************************************* 12 * 13 * 初始化操作 14 * 15 *********************************************************************************/ 16 void RCC_Configuration(void);//系统时钟初始化函数声明 17 void GPIO_Configuration(void);//GPIO初始化函数声明 18 void NVIC_Configuration(void);//中断优先级配置函数声明 19 void USART_Configuration(void);//串口配置函数声明 20 21 22 23 24 /******************************************************************************** 25 * 26 * 函数名称:main(void) 27 * 函数功能:主函数 28 * 函数说明:不能用void定义主函数 29 * 30 ********************************************************************************/ 31 int main(void) 32 { 33 34 u16 id=0; //ID 35 u16 TxSize1=0; //发送字符的大小 36 u16 i=0; //用于循环 37 38 u8 TxBuffer1[]="liubo tobebest"; //发送的字符 39 TxSize1=sizeof(TxBuffer1)/sizeof(TxBuffer1[0]); //获取发送的字符的大小 40 41 RCC_Configuration(); //系统时钟高初始化 42 GPIO_Configuration(); //GPIO初始化 43 USART_Configuration();//串口初始化 44 NVIC_Configuration();//串口优先级初始化 45 SPI_Configuration();//SPI初始化