MCU - SPI总线介绍 + W25Qx驱动设计
目录
1. SPI总线介绍
2. SPI通信原理详解
3. SPI时序解析
4. SPI + W25Qx存储驱动设计
1. SPI总线介绍
1.1 总线概述
SPI(Serial Peripheral Interface)是一种高速全双工的同步串行通信协议,由Motorola于1980年代提出。其典型特性包括:
- 四线通信:SCLK/MOSI/MISO/CS ;
- 主从架构:支持一主多从模式 ;
- 无寻址机制:通过硬件片选(CS)选择设备;
- 时钟驱动:传输速率可达50MHz+ ;
1.2 核心优势对比
特性 | SPI | I2C | UART |
---|---|---|---|
通信模式 | 全双工 | 半双工 | 全双工 |
最高速率 | 50Mbps | 3.4Mbps | 1Mbps |
硬件复杂度 | 中等 | 低 | 低 |
寻址方式 | 硬件片选 | 软件地址 | 无 |
2. SPI通信原理详解
2.1 信号线定义
信号线 | 名称 | 方向 | 作用描述 |
---|---|---|---|
SCLK | 串行时钟线 | 主→从 | 同步数据传输时钟 |
MOSI | 主设备输出从设备输入 | 主→从 | 主设备数据发送通道 |
MISO | 主设备输入从设备输出 | 从→主 | 从设备数据响应通道 |
CS/SS | 片选信号 | 主→从 | 从设备使能控制(低电平有效) |
2.2 数据传输机制
数据以 移位寄存器 方式传输,典型工作流程:
// 典型数据交换伪代码
void SPI_Transfer(uint8_t* txData, uint8_t* rxData, uint32_t size) {CS_LOW();for(int i=0; i<size; i++){SCLK_TOGGLE();rxData[i] = ShiftByte(txData[i]); }CS_HIGH();
}
2.3 SPI总线主从通信应用
3. SPI时序解析
3.1 时钟极性相位
SPI协议通过 CPOL(Clock Polarity) 和 CPHA(Clock Phase) 组合定义四种工作模式:
模式 | CPOL | CPHA | 时钟极性 | 采样边沿 |
---|---|---|---|---|
0 | 0 | 0 | 低电平空闲 | 上升沿采样 |
1 | 0 | 1 | 低电平空闲 | 下降沿采样 |
2 | 1 | 0 | 高电平空闲 | 下降沿采样 |
3 | 1 | 1 | 高电平空闲 | 上升沿采样 |
3.2 通信时序
4. SPI + W25Qx存储驱动设计
4.1 W25Q128芯片简介
W25Q128 是华邦电子(Winbond)推出的一款高性能串行闪存芯片,主要参数:
参数 | 数值 |
---|---|
容量 | 16MB (128M-bit) |
页大小 | 256字节 |
扇区大小 | 4KB |
块大小 | 64KB |
接口电压 | 2.7V-3.6V |
时钟频率 | 最高104MHz(Dual SPI) |
4.2 驱动程序设计
4.2.1 驱动初始化
void MX_SPI1_Init(void)
{/* USER CODE BEGIN SPI1_Init 0 *//* USER CODE END SPI1_Init 0 *//* USER CODE BEGIN SPI1_Init 1 *//* USER CODE END SPI1_Init 1 */hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_2LINES;hspi1.Init.DataSize = SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; // 串行同步时钟的空闲状态为高电平hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;hspi1.Init.NSS = SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi1.Init.TIMode = SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN SPI1_Init 2 *//* USER CODE END SPI1_Init 2 */}
4.2.2 写使能
static void w25QWriteEnable(void)
{// CS 拉低电平,开始通讯W25Q_CS_LOW();// 发送写使能命令W25QHardWriteReadByte( W25Q_CMD_WRITE_ENABLE);// CS 拉高电平,结束通讯W25Q_CS_HIGH();
}
4.2.3 页编程
static uint8_t W25QPageProgram(uint32_t writeAddr, uint8_t* data, uint32_t len)
{// 判断数据的有效性if((!data) || (len <= 0) || (len > 256)) return 1;w25QWriteEnable(); // 写使能// 若等待空闲状态超时,就返回 falseif( !W25QWaitIdle()) return 1;// CS 拉低电平,开始通讯W25Q_CS_LOW();// 发送 页编程 命令W25QHardWriteReadByte( W25Q_CMD_PAGE_PROGRAM);// 发送地址w25QWriteAddr( writeAddr);W25QHardWriteReadMultByte(data, len);// CS 拉高电平,结束通讯W25Q_CS_HIGH();// 等待空闲W25QWaitIdle();return 0;
}
4.2.4 数据读取
static uint32_t w25QxRead(uint32_t readAddr, uint8_t* buf, uint32_t numByte)
{uint8_t len = numByte, i = 0;// 判断数据的有效性if((!buf) || (numByte <= 0)) return 0;// CS 拉低电平,开始通讯W25Q_CS_LOW();// 发送 读取 命令W25QHardWriteReadByte( W25Q_CMD_READ_DATA);// 发送地址w25QWriteAddr( readAddr);for(i = 0; i < numByte; i++) buf[i] = W25Q_DUMMY_VALUE;W25QHardWriteReadMultByte(buf, numByte);// CS 拉高电平,结束通讯W25Q_CS_HIGH();return len;
}
SPI+W25Qx驱动源程序 : https://download.csdn.net/download/weixin_43176196/90888095?spm=1011.2124.3001.6210