基础知识:
SPI是一种高速的,全双工,同步的通信总线。使用3 条总线及n个片选线(n取决于从机数量),SPI可以一个主机连接单个或多个从机,每个从机都有唯一片选线。
- MOSI(主机输出/从机输入)——主机向从机发送数据的线
- MISO(主机输入/从机输出)——从机向主机发送数据的线
- SCLK(时钟)——时钟信号线
- SS/CS/NSS(片选线)——用于主机选择与哪个从机数据交互的线
协议原理
理解两部分
第一部分(信号的开始与结束)
某从机NSS信号线 由高变低 (被选中),是SPI 通讯的起始信号。开始准备与主机通讯。此从机NSS 信号 由低变高( 取消选中 ) ,是 SPI 通讯的停止信号,表示本次通讯结束。第二部分(时钟线的极性与相位)
SPI一共有四种通讯模式,是由SCK空闲时的两种状态和数据的两种采样方式产生的。在此引入“ 时钟极性CPOL ” 和 “ 时钟相位CPHA ” 的概念。时钟极性 CPOL 是指 SPI 通讯设备处于空闲状态时, SCK 信号线的电平信号 ( 即 SPI 通讯开始前、 NSS 线为高电平时SCK 的状态 ) 。CPOL=0 时,SCK 在空闲状态时为低电平,CPOL=1 时,SCK 在空闲状态时为高电平。时钟相位CPHA 是指数据的采样的时刻,即MOSI 或MISO 数据线上的信号将会在当CPHA=0 时,数据线在SCK 的“奇数边沿”采样。当CPHA=1 时,数据线在SCK 的“偶数边沿”采样。例:(奇数1、3、5、7、9......)补充
MOSI 及 MISO 数据线在SCK 的每个时钟 周期 传输 一位 数据,且数据输入输出是 同步 的。若只进行发送操作,主机需忽略接收到的字节;若主机要读取从机的一个字节,就必须发送一个字节(一般0XFF)来引发从机的传输。 你发一个数据必然会收到一个数据;你要收一个数据必须也要 先 发一个数据(主机产生时钟信号)。
应用(片上外设FLASH)
因为是片上外设,所有根据STM32F407的原理图,查找对应引脚,直接引脚复用即可,(别的开发板或外设,需简单配置引脚)
FLASH
芯片中还有
WP#
和
HOLD
引脚。
- WP 引脚可控制写保护功能,当该引脚为低电平时,禁止写入数据。我们直接接电源,不使用写保护功能。
- HOLD 引脚可用于暂停通讯,该引脚为低电平时,通讯暂停,数据输出引脚输出高阻抗状态,时钟和数据输入引脚无效。我们直接接电源,不使用通讯暂停功能。
思路:
- 初始化通讯使用的目标引脚及端口时钟;
- 使能SPI 外设的时钟;
- 配置SPI 外设的模式、地址、速率等参数并使能SPI 外设;
- 编写基本SPI 按字节收发的函数;
- 编写对FLASH 擦除及读写操作的的函数;
- 编写测试程序,对读写数据进行校验。
SPI_InitTypeDef SPI_InitStructure;
/*spi 时钟使能*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
/* FLASH_SPI 模式配置 */
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//通讯方向双线全双工
SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//主机模式
SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//数据帧大小是8位
/* FLASH芯片支持SPI模式0及模式3 可设置CPOL=1 CPHA=1 */
SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;//片选信号由软件触发,我们可自行编程
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;//时钟分频,84Mhz/2=42Mhz
SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;//高位先行
SPI_Init(SPI1,&SPI_InitStructure);
/*使能FLASH_SPI*/
SPI_Cmd(SPI1,ENABLE);
参数介绍
- SPI_Direction
设置
SPI
的通讯方向,可设置为双线全双工
(SPI_Direction_2Lines_FullDuplex)
,双线只接收(SPI_Direction_2Lines_RxOnly),单线只接收
(SPI_Direction_1Line_Rx)
、单线只发送模式(SPI_Direction_1Line_Tx)。
- SPI_Mode
设置
SPI
工作在主机模式
(SPI_Mode_Master)
或从机模式
(SPI_Mode_Slave )
,这两个模式的最大区别为SPI
的
SCK
信号线的时序,
SCK
的时序是由通讯中的主机产生的。若被配置为从机模式,
STM32的SPI
外设将接受外来的
SCK
信号。
- SPI_DataSize
选择
SPI
通讯的数据帧大小是为
8
位
(SPI_DataSize_8b)
还是
16
位
(SPI_DataSize_16b)
。
- SPI_CPOL 和SPI_CPHA
配置
SPI
的时钟极性
CPOL
和时钟相位
CPHA
,这两个配置影响到
SPI
的通讯模式,时钟极性
CPOL
成员,可设置为高电平(SPI_CPOL_High)
或低电平
(SPI_CPOL_Low )
。时钟相位
CPHA
则可以设置为SPI_CPHA_1Edge(在
SCK
的奇数边沿采集数据
)
或
SPI_CPHA_2Edge(
在
SCK
的偶数边沿采集数据
)。
- SPI_NSS
配置
NSS
引脚的使用模式, 可以选择为硬件模式
(SPI_NSS_Hard )
与软件模式
(SPI_NSS_Soft )
,在硬件模式中的SPI
片选信号由
SPI
硬件自动产生,而软件模式则需要我们亲自把相应的
GPIO
端口拉高或置低产生非片选和片选信号。实际中软件模式应用比较多。
- SPI_BaudRatePrescaler
设置波特率分频因子,分频后的时钟即为
SPI
的
SCK
信号线的时钟频率。这个成员参数可设置为
fpclk的2
、
4
、
6
、
8
、
16
、
32
、
64
、
128
、
256
分频。
- SPI_FirstBit
所有串行的通讯协议都会有
MSB
先行
(
高位数据在前
)
还是
LSB
先行
(
低位数据在前
)
的问题,而
STM32的SPI
模块可以通过这个结构体成员,对这个特性编程控制。
- SPI_CRCPolynomial
SPI
的
CRC
校验中的多项式,若我们使用
CRC
校验时,就使用这个成员的参数
(
多项式
)
,来计算
CRC的值。