1.简介
1.通信线:SCK((也做SCLK,CLK,CK)串行时钟线),MOSI(也做DO)(主机输出从机输入),MISO(越做DI)(主机输入从机输出),SS(也做NSS,CS)(从机选择)
1.SCK引脚提供时钟信号,数据位的输出和输入,都是在SCK的上升沿或下降沿进行的,以确定数据位的收发时刻
2.SS用于指定从机的通信线
2.同步(同步时序),全双工(数据发送和接收单独占一条线,发送用发送的线路,接收用接收的线路)
3.支持总线挂载多设备(一主多从)(仅支持一主多从)
4.SPI无应答机制
2.SPI相对于I2C的优缺点:SPI协议并没有严格规定最大传输速度,最大传输速度取决于芯片厂商的设计需求
3.硬件电路
1.所有的SPI设备的SCK,MOSI,MISO,分别连在一起
2.主机另外引出多条SS控制线,分别接到各从机的SS引脚
1.主机的SS线都是输出,从机的SS线都是输入
2.SS线是低电平有效的,主机想指定谁,就把对应的SS输出线置低电平就行了
3.当SS引脚为高电平,即从机未被选中时,MISO引脚必须切换为高阻态(引脚断开,不输出任何电平),以此防止一条线有多个输出而导致的电平冲突
4.在SS为低电平时,MISO才允许变为推挽输出
3.输出引脚配置为推挽输出,输入引脚配置位浮空或上拉输入
4.示意图

1.SS线有3根:有3个从机
2.SPI所用通信线都是单端信号,它们的高低电平都是相对GND的电压差,所以,单端信号,所有设备需共地
3.若从机无独立供电,主机还需要再额外引出正极电源VCC,给从机供电
4.SCK时钟线:完全由主机掌握,对于主机而言,时钟线位输出,对于所有从机而言,时钟线都为输入
5.MOSI:主机输入从机输出:数据传输方向是,主机通过MOSI输出,所有从机通过MOSI输入
6.MISO:主机输入从机输出:数据传输方向:从机通过MISO输出,主机通过MOSI输入
5.I2C不用推挽输出的原因
1.要实现半双工,经常要切换输入输出
2.要实现多主机时钟同步和总线仲裁,易招致电源短路
4.移位示意图
1.图例

1.时钟输入端,SPI一般高位先行,每来一个时钟,移位寄存器就会向左进行移位
2.移位寄存器的时钟源由主机(波特率发生器)提供,它产生的时钟驱动主机的移位寄存器进行移位,同时也通过SCK引脚进行输出,接到从机的移位寄存器里
3.移位寄存器接法:主机移出左边移出去的数据,通过MOSI引脚输入到从机寄存器的右边,从机移位寄存器左边移出去时,通过MISO,输入到主机移位寄存器的右边,即将主机和从机的最高位分别移到MOSI和MISO的通信线上
4.上升沿之后,进行下降沿,此时,主机和从机内,都会进行数据采样输入。也就是在MOSI的数据会采样输出到从机最低位,MISO会采样输入到主机最低位
5.SPI的数据收发,都是基于字节交换这个基本单元来进行的,当主机需要发送一个字节,并且同时需要接收一个字节时,就可以执行字节交换的时序
6.只想接收数据,不想发送数据时,需调用交换字节时序,并随便发送一个数据,一般是0x00或0xFF
5.SPI时序基本单元
1.示意图

2.起始和终止条件
1.起始条件:SS从高电平切换到低电平
2.终止条件:SS从低电平切换到高电平
3.示意图

3.数据传输基本单元
1.交换一个字节(模式0)
1.CPOL(时钟极性)=0:空闲状态时,SCK为低电平
2.CPHA(时钟相位)=0:SCK第一个边沿移入数据,第二个边沿移出数据
3.示意图
1.SS高电平时,MISO用一条中间的线,表示高阻态
2.SS下降沿之后,从机的MISO1被允许开启输出
3.SS上升沿之后,从机的MISO1必须置回高阻态

2.交换一个字节(模式1)
1.CPOL(时钟极性)=0:空闲状态时,SCK为低电平
2.CPHA(时钟相位)=1:SCK第一个边沿移入数据,第二个边沿移出数据
3.示意图
1.SCK上升沿,主机和从机同时移出数据,主机通过MOSI移出最高位,从机通过MISO移出最高位
2.SCK进入下降沿,主机从机移入数据,也就i是进行数据采样

3.时钟相位仅决定第一个时钟采样移入还是第二个时钟采样移入并不是规定上升沿采样还是下降沿采样(在时钟极性确定时,时钟相位确实会改变采样时刻的上升沿和下降沿)
6.SPI时序波形(以W25Q64为例)
1.在SPI中通常采用的是指令码加读写数据的模型
1.过程:在SPI起始后第一个交换发送给从机的数据一般叫做指令码,在从机中,对应的会定义一个指令集,当我们需要发送一个指令时,就可以在起始后第一个字节,发送指令集里的数据,指导从机完成相应的功能,不同指令可以有不同数据个数
2.发送指令:向SS制定的设备发送指令(0x06)
1.在W25Q64里表示写使能

2.指定地址写
1.向SS指定的设备,发送写指令(0x02)
2.在指定地址(Address23:0)下,写入指定数据(Data)

3.指定地址读
1.向SS指定的设备发送读指令(0x03)
2.随后在指定地址Address23:0)下,读取从机数据(Data)
7.W25Q64
1.简介:常用于数据存储,字库存储,固件程序存储等场景的低成本,小型化,使用简单的非易失性存储器(数据掉电不丢失)
2.存储介质:Nor Flash(闪存)
3.时钟频率:80MHz/160MHz(Dual SPI)/320MHz(Quad SPI)
4.硬件电路



5.框图

6.Flash操作注意事项
1.写入数据前,必须先进行写使能(防止误操作)
2.每个数据只能由1改写为0,不能由0改写为1(无完全覆盖改写能力)
3.写入数据前必须先擦除,擦除后,所有数据变为1
4.擦除必须按最小擦除单元进行(最小擦除单元是1个扇区)
5.连续写入多字节时,最多写入一页(256字节)的数据,超过页尾位置的数据,会回到页首覆盖写入
6.写入操作结束后,芯片进入忙状态,不响应新的读写操作
7.读取操作时,直接调用读取时序,无需使能,无需额外操作,没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态读取
7.事前等待和事后等待
1.事后等待最保险,事前等待效率高
2.事后等待,只需在写入操作后调用,事前等待,在写入操作和读取操作之前,都得调用
8.若不执行擦除,读出的数据=原始数据&(按位与)写入的数据
9.SPI外设
1.简介:
1.可配置8位/16位数据帧,高位先行/低位先行
2.时钟频率:Fpclk/(2,4,8,16,32,64,128,256)(分母是分频系数)
3.支持多主机模型、主或从操作
4.可精简为半双工,单工通信
5.支持DMA
6.兼容I2S协议
7.集成了硬件SPI收发电路,可以由硬件自动执行时钟生成,数据收发等功能,减轻CPU的负担
8.f103c8t6的硬件资源有SPI1(时钟频率为72MHz,APB2外设),SPI2(时钟频率为36MHz,APB1外设)
2.框图

1.移位寄存器:数据低位从MOSI移出,MISO的数据移入到左边的数据高位
2.LSBFIRST(帧格式)控制位:可以控制低位先行还是高位先行
1.给0:先发送MSB(高位)
2.给1:先发送LSB(低位)
3.当通信在进行时不能改变该位的值(I2S不使用)
3.下图用于进行主从模式引脚变换

4.缓冲区(占用同一个地址,统一叫做DR)
1.接收缓冲区:接收数据寄存器RDR
2.发送缓冲区:发送数据寄存器TDR
5.波特率发生器:主要用于产生SCK时钟,输入时钟是PCLK(72或36MHz),经过分频输出到SCK引脚(时钟和移位寄存器同步,每产生一个周期的时钟,移入移出一个bit)
6.CR1寄存器的BR0,BR1,BR2用于控制分频系数
7.TXE:发送寄存器空,RXNE:接收寄存器非空
8.NSS引脚:从机选择,低电平有效,偏向于实现多主机模型
3.SPI基本机构

4.主模式全双工连续输出(借助缓冲区,数据连续传输,实现连续数据流)

5.非连续传输发送

1.发送数据时,检测到TXE置1,TDR为空,就可以软件写入0xF1至SPI_DR,此时TDR值为1,TXE为0此时,移位寄存器为空,F1会立即转入移位寄存器开始发送,波形产生,并且TXE置1
2.一直等待到第一个字节时序结束,RXNE置1,先把第一个接收到的数据读出来,之后,再写入下一个字节数据
3.流程:等待TXE为1->写入发送的数据至TDR->等待RXNE为1->读取RDR接收的数据
6.库函数
1.void SPI_I2S_DeInit(SPI_TypeDef* SPIx);:恢复缺省配置
2.void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);:初始化
3.void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct);:结构体变量初始化
4.void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);:外设使能
5.void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);:中断使能
6.void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);:DMA使能
7.void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);:写DR数据寄存器
8.uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);:读DR寄存器
9.FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);:获取TXE和RXNE标志位