SPI(Serial Peripheral Interface)作为一种高速全双工同步串行通信协议,在嵌入式系统中扮演着重要角色。我第一次接触SPI是在调试一个传感器模块时,当时被其简洁的四线制设计和高效的传输速率所吸引。与I2C相比,SPI最大的特点在于其采用主从架构下的全双工通信模式,这意味着数据可以同时双向传输,理论带宽利用率可达100%。
标准的SPI接口包含四条关键信号线:
重要提示:SPI没有正式的流控机制,当从机处理速度跟不上主机时,需要通过软件实现缓冲机制。我在实际项目中就遇到过因从机FIFO溢出导致数据丢失的情况。
SPI最让人困惑的莫过于CPOL和CPHA这两个参数的配置。通过示波器抓取波形可以直观理解:
CPOL(Clock Polarity):
CPHA(Clock Phase):
这组合出四种工作模式,不同厂商设备可能支持的模式不同。例如:
我在调试STM32与NRF24L01模块通信时,就曾因模式设置错误导致通信失败。后来通过逻辑分析仪捕获波形才发现问题所在。
一个完整的SPI数据传输周期包含以下几个阶段:
片选激活:主机拉低目标从机的SS线
时钟建立:主机产生SCK信号
数据交换:
片选释放:主机拉高SS线结束通信
SPI的核心是移位寄存器的工作原理。以8位传输为例:
我在调试时发现一个有趣现象:即使不读取MISO数据,主机也必须发送虚拟数据(通常0xFF)来产生时钟信号。
W25Q64是Winbond推出的64Mbit串行Flash,具有以下特点:
硬件连接注意事项:
在每次写入操作前必须执行:
c复制void W25Q_WriteEnable(void) {
SPI_CS_LOW();
SPI_Transmit(0x06); // 写使能指令
SPI_CS_HIGH();
Delay_us(5); // 等待指令完成
}
典型写入流程:
经验分享:连续写入时要注意页边界,跨页写入会导致数据回卷。我有次就因忽略这点导致关键配置数据被覆盖。
读取操作相对简单:
c复制uint8_t W25Q_ReadByte(uint32_t addr) {
uint8_t data;
SPI_CS_LOW();
SPI_Transmit(0x03); // 读指令
SPI_Transmit(addr >> 16);
SPI_Transmit(addr >> 8);
SPI_Transmit(addr);
data = SPI_Transmit(0xFF); // 虚拟数据产生时钟
SPI_CS_HIGH();
return data;
}
W25Q64支持三种擦除方式:
关键点:
当SPI通信异常时,建议按以下流程排查:
案例1:数据错位
现象:接收数据总是偏移几位
原因:CPHA设置错误导致采样边沿不对
解决:调整相位参数
案例2:从机无响应
现象:MISO始终为高阻态
原因:SS信号接触不良或从机供电异常
解决:检查硬件连接和电源
案例3:高频干扰
现象:高速通信时数据错误
原因:走线过长或未加匹配电阻
解决:缩短走线,在SCK上加33Ω串联电阻
我在一个工业传感器项目中,通过优化SPI配置将采样率从100kHz提升到1MHz,满足了实时性要求。这需要仔细平衡时钟速度、信号质量和电源噪声等因素。