一、SPI协议核心机制解析

1. 四线制通信架构

SCK
MOSI
MISO
NSS
主机
从机
  • SCK:时钟信号(主机控制)
  • MOSI:主机输出从机输入
  • MISO:主机输入从机输出
  • NSS:片选信号(低电平有效)

2. 时钟极性/相位组合

模式 CPOL CPHA 数据采样时刻
Mode0 0 0 SCK上升沿
Mode1 0 1 SCK下降沿
Mode2 1 0 SCK下降沿
Mode3 1 1 SCK上升沿

行业惯例:SD卡常用Mode0,FLASH常用Mode3


二、STM32硬件SPI深度配置

1. CubeMX关键配置项

// 典型SPI1配置(APB2=72MHz)
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;          // 主机模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES;// 双线全双工
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;    // 8位数据
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;  // CPOL=0
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;      // CPHA=0 (Mode0)
hspi1.Init.NSS = SPI_NSS_SOFT;              // 软件控制NSS
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 18MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;     // 高位先行

2. 波特率精密计算

SPI_Speed=APB_ClockPrescaler SPI\_Speed = \frac{APB\_Clock}{Prescaler} SPI_Speed=PrescalerAPB_Clock

// 时钟分频系数表
| 预分频值         | 实际分频比 |
|------------------|-----------|
| SPI_BAUDRATEPRESCALER_2   | 2         |
| SPI_BAUDRATEPRESCALER_4   | 4         |
| SPI_BAUDRATEPRESCALER_8   | 8         |
| ...              | ...       |
| SPI_BAUDRATEPRESCALER_256 | 256       |

三、软件模拟SPI(GPIO模拟)

1. 模式0实现核心代码

void Soft_SPI_Write(uint8_t data) {
    for(int i=0; i<8; i++) {
        // 下降沿准备数据
        MOSI_LOW(); 
        if(data & 0x80) MOSI_HIGH();
        
        // 上升沿采样
        SCK_HIGH();     
        data <<= 1;
        
        // 下降沿切换
        SCK_LOW();      
    }
}

2. 硬件SPI vs 软件SPI性能对比

指标 硬件SPI (72MHz) 软件SPI (2MHz)
传输速度 72 Mbps <2 Mbps
CPU占用率 0% (DMA模式) >90%
信号完整性 易受中断干扰
多从机支持 硬件NSS管理 需手动控制CS

四、SPI外设驱动实战

1. W25Q128 FLASH芯片驱动

// 读Flash ID(厂商+容量)
uint8_t cmd[4] = {0x9F, 0x00, 0x00, 0x00};
uint8_t id[2];
HAL_SPI_TransmitReceive(&hspi1, cmd, id, 4, 100);
// id[1]=0x40表示128Mbit

// 页编程(启用写使能)
void Flash_WritePage(uint32_t addr, uint8_t* data) {
    uint8_t cmd[4] = {0x06}; // WREN
    HAL_SPI_Transmit(&hspi1, cmd, 1, 100); 
    
    cmd[0] = 0x02; // Page Program
    cmd[1] = (addr>>16)&0xFF;
    cmd[2] = (addr>>8)&0xFF;
    cmd[3] = addr&0xFF;
    HAL_GPIO_WritePin(FLASH_CS_GPIO, FLASH_CS_PIN, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, cmd, 4, 100);
    HAL_SPI_Transmit(&hspi1, data, 256, 100);
    HAL_GPIO_WritePin(FLASH_CS_GPIO, FLASH_CS_PIN, GPIO_PIN_SET);
}

2. ILI9341 LCD屏驱动优化

// 使用16位色快速填充
#define LCD_CMD  0
#define LCD_DATA 1
void LCD_Fill(uint16_t color, uint32_t len) {
    uint8_t cmd = 0x2C; // Memory Write
    LCD_Send(LCD_CMD, &cmd, 1);
    
    // DMA传输优化(速度提升5倍)
    uint16_t *buf = malloc(len*2);
    for(int i=0; i<len; i++) buf[i] = color;
    HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)buf, len*2);
}

五、高级应用与性能优化

1. DMA链式传输(H7系列)

// 创建链表实现自动传输
void SPI_DMA_Chain_Config(void) {
    // 1. 初始化链表
    HAL_DMAEx_List_Init(&handle, LIST_SIZE);
    
    // 2. 构建传输节点
    HAL_DMAEx_List_BuildNode(&tx_config, &node1);
    HAL_DMAEx_List_BuildNode(&rx_config, &node2);
    
    // 3. 链接节点
    HAL_DMAEx_List_InsertNode_Head(&handle, &node1);
    HAL_DMAEx_List_InsertNode_Tail(&handle, &node2);
    
    // 4. 启动链表传输
    HAL_DMAEx_List_Start_IT(&handle);
}

2. 多从机硬件管理方案

// 使用I/O扩展器管理片选
void SPI_SelectDevice(uint8_t dev_id) {
    uint8_t mask = 1 << dev_id;
    uint8_t cmd[2] = {0x40, mask}; // TCA9538写命令
    HAL_I2C_Master_Transmit(&hi2c1, 0x70, cmd, 2, 100);
}

3. 信号完整性设计要点

50Ω特性阻抗
22Ω串联
PCB布局
阻抗匹配
等长走线
端接电阻
减少振铃

六、调试技巧与故障排除

1. 逻辑分析仪诊断SPI四要素

  1. 片选有效性:操作期间CS保持低电平
  2. 时钟模式匹配:CPOL/CPHA是否符合设备要求
  3. 数据对齐:MSB/LSB顺序是否正确
  4. 建立/保持时间:数据在时钟边沿的稳定性

2. 常见故障解决方案

故障现象 可能原因 解决方案
数据全为0xFF MISO未连接 检查硬件连接
偶发数据错误 时序裕量不足 降低波特率或增加时钟延时
DMA传输卡死 内存未对齐访问 使用__attribute__((aligned(4)))
多从机相互干扰 CS信号串扰 增加1KΩ下拉电阻

3. 示波器实测波形分析

正常波形:
SCK  _┌┐_┌┐_┌┐_┌┐_
MOSI __▁▁▃▃▅▅▇▇__  // 清晰电平跳变

故障波形:
SCK  _┌──┐_┌──┐_   // 时钟畸变
MOSI __▁~~▃▃~~~~__  // 信号振铃

七、跨系列兼容性设计

1. F1/F4/H7 SPI差异对比

特性 STM32F1 STM32F4 STM32H7
最大时钟 18 MHz 45 MHz 133 MHz
数据帧格式 8/16位 4-16位可编程 4-32位可编程
DMA触发方式 单次触发 FIFO+突发传输 MDMA矩阵传输
CRC计算 仅基本CRC 可配置多项式 硬件CRC32

2. 通用驱动封装技巧

// 抽象SPI操作接口
typedef struct {
    void (*Init)(void);
    uint8_t (*TransmitReceive)(uint8_t data);
    void (*CS_Control)(uint8_t state);
} SPI_Driver;

// 硬件SPI实现
SPI_Driver HW_SPI = {
    .Init = SPI1_Init,
    .TransmitReceive = HAL_SPI_TransmitReceive,
    .CS_Control = HW_CS_Control
};

// 软件SPI实现
SPI_Driver SW_SPI = {
    .Init = Soft_SPI_Init,
    .TransmitReceive = Soft_SPI_Transceive,
    .CS_Control = GPIO_CS_Control
};

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐