SPI又是另一个超级常见的外设通信方式。
大部分图片来源:正点原子HAL库课程
专栏目录:记录自己的嵌入式学习之路-CSDN博客
目录
1 基本概念
SPI:串行外设设备接口(Serial Peripheral Interface),是一种高速的,全双工,同步的通信总线。主要应用在存储芯片、AD转换器以及LCD中。
1.1 与IIC的区别
- SPI是边沿协议(以边沿的产生为信号),IIC是电平协议(以电平的高低为信号);
- SPI可以选择MSB(高位)先发和LSB(低位)先发两种模式,一般是根据从机的需要进行选择;
- SPI也可以只使用一根数据线,实现半双工通信。
1.2 引脚
MOSI(Master Out / Slave In):输出数据线
MISO(Master In / Slave Out):输入数据线
SCK(Serial Clock):时钟
NSS():片选线,上方的横线代表低电平有效。实现上一般使用软件管理NSS,而将硬件的NSS引脚省下来用作他用。
软件管理CS的意思是:将主机配置为软件管理NSS,而从机的CS在物理上就可以连接MCU的任意一个IO了,只要和该从机通信的时候拉低该IO的电平即可。
1.3 移位原理
如上图,当时钟线产生一个上升沿触发时,主机和从机的最高位都会被传输到发送引脚上;当时钟线产生一个下降沿触发时,接收引脚上的数据将被写进移位寄存器中。通过8个时钟脉冲,一个字节的数据就被发送/接收完成了。也就是说,收发是同时进行的。所以:
- 若主机只向从机进行写操作,可以忽略接收到的从机数据;
- 若主机要对从机进行读操作,需要发送一个空数据来引发从机发送数据。
1.4 四种工作模式
- 主机SPI的工作模式的选择要结合从机支持的模式来,因为从机不一定支持这么多模式;
2 NOR Flash
2.1 25Q128系列 NOR Flash
- HOLD用于一主多从的通信;
2.2 25Q128存储结构
一片25Q128有256个块(Block),一个块有16个扇区(Sector),一个扇区有16页,一页有256个字节。最终算出来就是16M Byte/128M bit。
- 擦除的单位:扇区、块、片
- 写的单位:页写,与EEPROM的页写一样存在写完一页需要翻页的情况,否则再写会发生覆盖;
- 地址长度:根据原件数据手册可知,为0- FFFFFFH;
2.3 常用指令及其时序
NOR FLASH的指令总数比较多, 但是如果只需要实现基本操作,还是比较简单的,一般我们只需要:5条指令即可完成对NOR FLASH的基本使用(以NM25Q128为例):
- 写使能
拉低片选→发送06H→拉高片选 - 读SR1
拉低片选→发送05H→返回SR1的值→拉高片选- 其中,05H、35H、15H分别对应SR1、SR2、SR3三个状态寄存器;
- 若拿到SR1数据后不拉高片选,从机会持续发送SR1的数值;
- 读数据
拉低片选→发送03H→发送24位地址→读取数据1~n→拉高片选- 与读SR1类似,在发送完地址后,要是时钟线一直给脉冲,就会一直读数据;
- 页写
拉低片选→发送02H→发送24位地址→发送数据1~n→拉高片选- 页写命令最多可以向FLASH传输256个字节的数据,因为一页就256字节;
- 与上面的命令一样,只要保持片选和时钟脉冲就可以持续写入;
- 扇区擦除
拉低片选→发送20H→发送24位地址→拉高片选- FLASH存储器的特性决定了它只能把原来为“1”的数据位改写成“0”,而原来为“0”的数据位不能直接改写为“1”;
- 写入数据前,检查内存空间情况是否满足,不满足需擦除;
2.4 重要的状态寄存器
- 除了上图所述的BUSY位和WEL位外,对大容量FLASH进行操作时还需要对ADP位进行操作;
2.5 读操作步骤
- 分三次发送是因为帧格式那里设置了每帧8位;
- 发送空字节是因为读写是同时进行的,要读就要发送写数据;
2.6 擦除扇区
- 注意:发送要擦除的字节地址即可,Flash芯片会自动擦除该地址所在扇区;
2.7 写操作(极简版)
3 配置
3.1 相关HAL库函数
- 使能时钟也可以放在HAL_SPI_MspInit()函数中;
3.2 关键结构体
- Direction:选择双线全双工,SPI_DIRECTION_2LINES;
- NSS:选择软件,SPI_NSS_SOFT;
- TIMode:选择不开启,即默认的摩托罗拉模式,SPI_TIMode_DISABLE;
- CRCCalculation:关闭CRC校验;
- CRCPolynomial:找寄存器的默认值,7;
3.3 NOR Flash基本驱动步骤
- 关键的函数:HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
- pTxData:发送数据的指针;
- pRxData:接收数据的指针;
- Size:发送数据的数目,要是帧格式是字节就是字节数,帧格式是半字就是半字数;
- Timeout:超时时间,例程内设置为1000;
- 如果需要一次性发送16位数据(SPI的单帧数据格式可以设置为16位)
- 方法1:在配置SPI时配置好16位帧格式,在发送数据时,则将数据指针强转为8位指针发送:
- 方法2:配置SPI时依然配置为8位,但发送两个字节:
- 方法1:在配置SPI时配置好16位帧格式,在发送数据时,则将数据指针强转为8位指针发送:
- 一般SPI初始化完毕后最好发送一个0xFF,以达到清空数据寄存器的作用;
- 注意⚠️:GPIO应设置为初始上拉,以保证对一些有上下拉电阻功能的MCU,不会因为初始拉低而发生片选;
- 注意⚠️:设置传输速度前必须__HAL_SPI_DISABLE,失能SPI才行;
- 读取数据时应发送一个空的8位数据出去,从而获得返回值,因为根据19.1.3,需要发送空数据以启动移位操作;
- 发送24位地址需要分开三次发,高8位→中8位→低8位;
- 每次操作完毕后记得拉高片选;
- 这里的GPIO初始化指的是Flash芯片的片选引脚初始化;
- 读、改、写的步骤是为了避免要写入的扇区原来就有数据,因此要先将扇区的数据读出来,然后放到一个大数组中;在大数组中写入自己需要写入的数据,然后擦除扇区,再将数组的数据写入扇区中;
- 如在写入前不进行数据读取与比对,那么直接写入后与写入地址同扇区的数据将被擦除,因为擦除的最小单位是扇区;
4 QSPI
4.1 基本概念
STM32F1系列并没有QSPI的外设。了解有更快的SPI传输数据的方式即可。
4.2 SPI的分类
- SPI加速的思路:复用更多的引脚做IO,以提高一次性传输的数据;