1、SPI协议
SPI相对于I2C传输速度更快;设计简单,通信协议使用硬件线比较多,有些资源浪费
以下设备需要进行共地,如果从机没有独立的供电源,主机需要给供电
SS线低电平有效,主机只能选择一个从机
推挽输出的高低电平均有高驱动能力,(I2C为防止电路短路采用开漏输出模式)
当某个从机未被选中时,它的MISO为高阻态,并不输出有用信息
首先由波特率发生器产生时钟上升下降沿
当主机中的数据是10101010,从机为01010101时,此时产生一个上升沿
此时MOSI通信线上为1,为高电平,MISO线为0,为下降沿,之后迎来一个下降沿时
主从机都会进行数据采样输入,如下所示:
同样的方式,直到第8个时钟之后:
以上是同时发送和接收
只有发送不想接收时,只读从机数据即可;只想接收不想发送,只看主机接收数据即可
之后是SPI时序条件:
上升沿时主机和从机分别移出数据最高位,下降沿时,主机移出的数据移入从机数据的最低位,从机的最高位移入主机数据的最低位。模式1与模式3的CPOL=1,SCK取反
MISO在SS为高电平是一直处于高阻态。以下和上述介绍的一样
除了以上模式外,还有提前半个相位的模式0,此时SCK的动作不一致,它需要在第0个边沿移出数据,然后移入等,相当于SS的下降沿也当为时钟的一部分,(这种模式使用更多)与模式2不同就是CPOL=1,SCL极性取反:
一些指令时序:
写使能指令,厂家定义0X06是写使能,由主机发送从机接收
高组态时没有规定为什么电平,因此这里设置为高电平
相当于主机发送0X06,从机发送0XFF(因为发送接收同时发生,如果是只发送,不管从机发送来的数据即可)
第二条指令:
首先发送写指令0X02
指定位置为24位,需要分成3个字节来构成,写指令之后的字节定义为地址高位,因此
0X12就是指定地址的23~16位
继续发送剩余字节 0X34、0X56,最终构成指定地址0X123456:
之后发送数据0X55:
以上表示在0X123456的地址写入0X55数据。
之后是:
先是读指令0X03
之后是地址与上边一样,之后读取数据,此次在MISO线上读取数据:
2、W25Q64芯片
数据掉电不丢失
Dual SPI表示厂商为不浪费资源,让MISO和MOSI同时收发数据相当于80MHz成为160MHz,可传输2位。实际上还是80MHz.
24位地址最大存储16M字节
上面有一杠表示低电平有效
之后是Flash一些操作事项:
掉电不丢失、容量大、成本低
在擦除后Flash显示为0XFF,此时为没有数据(擦除也算忙状态)
擦除时最小是一个扇区擦除(页>块>扇区)
之后是软件编程实现读写功能:
其中SPI需要完成封装、通信引脚初始化、起始、终止、交换字节
W25Q64需要完成写使能、擦除、页编程、读数据等
首先编写SPI协议代码:
对引脚进行初始化,输出(相对于主机)配置为推挽输出,输入(相对于主机)配置为上拉模式
因此主机有3条输出线,一条输入线
此时SS为高电平(无选择从机),SCL为低电平
之后为配置电平方便,将以上程序进行封装:
对SS进行写封装
SCL写封装
MOSI写封装
MISO读封装
之后是3个时序单元
起始条件:SS置低电平(由于引脚初始化时SS为高电平,这里可以直接置为低电平,不需要先置高电平再低电平)
终止条件:SS置高电平
交换一个字节:
对于硬件来说,由于存在移位寄存器,所以时钟的上升或者下降沿时,数据的移入或移出是同时发生的;
但是对于软件来说,程序是一条条执行,存在先后顺序,因此是时钟上升沿——移入数据,时钟下降沿——移出数据
通过掩码的方式取出数据指定一位
模式0就是相当于在第0个SCL电平变化时移出数据,第一个上升沿移入,第二个下降沿。
移出数据——上升沿——移入数据——下降沿
之后是W25Q64的代码:
主要分为初始化(调用MySPI初始化)、读ID号、写数据、是否忙状态、页编程、擦除、读数据
初始化:
1、读ID号:分为8位厂商ID和16位设备ID(高8位是寄存器类型,低8位是容量)
首先发送读ID的指令,不要接收的信息,没用;之后发送无意义信息为了接收到ID信息
第一次DID直接接收8位信息,第二次需要写成或等于防止高8位被覆盖。
2、写使能
3、是否忙状态
4、页编程(输入为写入地址、数据、写入的数量)
起始条件——发送指令码02——发送3个字节地址(高8位,中间8位,低8位,Swap只接受8位数据)——发送数据组(最大发256个字节,超过将会覆盖从第一个开始)——停止条件——等待忙状态
5、擦除(输入一个地址)
一共有4种擦除,以扇区擦除为例:
起始——发送指令20——发送3个字节地址——停止——等待忙
6、读使能
起始——发送读取数据指令——3个字节地址——发送无用信息接收有用信息——停止
由于注意事项中写入之前要有写指令,因此在页编程和擦除前先加一个写使能!!!以及最后加一个是否忙状态(对应写入状态结束后,芯片进入忙状态),事后等待。
之后是实验结果:
1、输入01、02、03、04
2、只擦除不写入
此时读的数据就是擦除之后的结果,全为1,FF
3、验证只能1写0,不能0写1
先写入AA、BB、CC、DD(此时擦除开启)
之后关闭擦除功能,并写入55、66、77、88
可以看出写入的数据改变,读取的数据因为没有擦除功能后,只能1写0,不能0写1,因此读出的状态就由一开始的AA:10101010,到55:01010101,没有擦除就变成了00000000,即显示的结果。相当于读取的数据=写入的数据&原始数据(按位与)
4、写入不能跨页,读取可以跨页
之前知道页地址是从xxxx00到xxxxFF,因此将读、写地址直接改到FF时观察写入的数据能否到下一页写
此时写入01、02、03、04,读出来是01、FF、FF、FF
表明写入的01在地址FF,02由于不能跨页,因此又返回该页页首00;
不过读取可以跨页,剩余FF是第二页的数据,由于被擦除,所以都是FF
之后修改读取地址,从00开始读,写依然在FF开始写,可以看出此时06、07、08均在该页地址的00、01、02处,由于地址03为写入因此读取结果为FF
页编程的写入如下所示:写不能跨页!!!
之后学习SPI的硬件外设读写功能。