关于SPI通讯速度笔记
SPI(Serial Peripheral Interface,串行外设接口)是一种高速全双工的同步串行通信协议,常用于单片机(主机)与外设(如 Flash、传感器、显示屏等,从机)之间的数据传输。
一、硬件基础:核心引脚与连接
SPI 通信至少需要 4 根线(主机和从机对应连接):
- SCK(Serial Clock):时钟线,由主机产生,控制数据传输节奏(速度由主机决定)。
- MOSI(Master Out Slave In):主机输出、从机输入线,主机通过这条线向从机发送数据。
- MISO(Master In Slave Out):主机输入、从机输出线,从机通过这条线向主机返回数据。
- NSS(Chip Select,也叫 CS):片选线,由主机控制(低电平有效),用于选择要通信的从机(一主多从时,通过不同 NSS 线区分从机)。
连接特点:
- 支持 “一主多从”(1 个主机带多个从机),每个从机单独接一根 NSS 线,由主机控制选通。
- 无应答机制(区别于 I2C),数据传输是否成功需软件额外判断。
二、软件基础:核心配置与通信流程
1. 初始化配置(以主机为例)
软件需要配置 SPI 的核心参数,才能正常通信:
- 通信模式:主机(Master)或从机(Slave)(通常单片机作为主机)。
- 时钟频率:通过 “总线时钟分频” 设置(如 APB 总线 168MHz,分频系数 8,则 SPI 时钟 = 21MHz),需低于外设支持的最高速度。
- 数据帧格式:通常是 8 位(1 字节),也可支持 16 位。
- 时钟极性(CPOL):SCK 空闲时的电平(0 或 1)。
- 时钟相位(CPHA):数据采样的时机(SCK 第 1 个边沿还是第 2 个边沿)。
- 片选方式:硬件自动控制(NSS 引脚)或软件手动控制(通过 GPIO 模拟)。
2. 通信流程(主机发送 + 接收数据)
以 “读取从机数据” 为例,步骤如下:
- 选通从机:主机拉低目标从机的 NSS 线(告诉从机 “准备通信”)。
- 发送 + 接收数据:
- 主机通过 MOSI 线发送数据(即使是读取,也需要发送一个 “读命令”);
- 同时,从机通过 MISO 线返回数据(主机同步接收);
- 数据按位传输,每一个 SCK 时钟边沿传输 1 位。
- 结束通信:主机拉高 NSS 线(告诉从机 “通信结束”)。
三、核心特点
- 速度快:时钟频率通常可达几 MHz 到几十 MHz(远高于 I2C),适合传输大量数据(如 Flash 读写)。
- 全双工:发送和接收可同时进行(MOSI 和 MISO 独立)。
- 简单灵活:硬件实现简单,软件配置步骤少,无需复杂协议(如地址解析)。
缺点是需要的线较多(比 I2C 多 2 根),且无硬件错误检测,需软件处理超时或数据校验。
开发底层驱动需要知道芯片主频,以及对应SPI挂载在哪条总线上面。再结合实际需求,配置分频系数。
从机不会主动适配主机的 SPI 频率,SPI 通信的频率完全由主机决定,从机只能被动接受主机提供的时钟(SCK),并要求主机的频率必须在从机支持的范围内(≤从机最大 SPI 频率),否则会通信失败
比如下面的GD32F405芯片
比如SPI2,挂载在APB1下面,最大频率42MHZ,128分频,得到频率是328,125 Hz(约 328.125 kHz)
还有下面STM32F4芯片关于SPI 的配置。
时钟相位和时钟极性:
时钟相位:数据会在时钟线的第几个边沿开始传输(第一个和第二个可选)。
时钟极性:在空闲状态下(未开始通信时--CS未拉低)时,时钟线的电平(高电平和低电平可选)。
两个参数共可以组成四种时序模式,具体选择哪一种时序取决于从机支持哪一种。
关于利用SPI,驱动w25qxx芯片,有可能遇到的问题,以及处理办法?
常见问题集中在硬件连接、SPI 软件配置、协议交互、操作时序四个维度
这是通过SPI协议进行通讯的存储芯片外围电路图
问题:
1、信号线过长(超过 20cm),导致 SCK/MOSI 信号干扰(高频下易受噪声影响)
处理办法:缩短 SPI 信号线长度
2、主机与从机地电位不共地(导致信号电平参考点不一致)
处理办法:确保主机与 W25Qxx 共地
SPI 频率配置过高,超过从机最大支持频率。
处理办法:降低 SPI 频率
3、字节序错误(W25Qxx 默认高位在前(MSB),若主机配置为 LSB(低位在前),会导致数据位反转)
处理办法:配置endian = SPI_ENDIAN_MSB
(高位在前)
4、操作后立即读写失败,未等待操作完成(W25Qxx 的擦除 / 写入是异步操作,需要时间(擦除可能需数百 ms),若未等待直接读写,会读到旧数据或错误值)
处理办法:每次擦除 / 写入后,轮询 “状态寄存器 1” 的 BUSY 位(bit0),直到 BUSY=0(操作完成)