STM32 SPI驱动W25Q128实战:从CubeMX配置到读写测试的完整流程(附源码)

张开发
2026/6/5 22:30:16 15 分钟阅读

分享文章

STM32 SPI驱动W25Q128实战:从CubeMX配置到读写测试的完整流程(附源码)
STM32 SPI驱动W25Q128实战从CubeMX配置到读写测试的完整流程附源码在嵌入式开发中外部存储芯片的集成是常见需求。W25Q128作为一款16MB容量的SPI Flash芯片因其性价比高、接口简单而广受欢迎。本文将手把手带你使用STM32CubeMX工具完成SPI外设配置并实现W25Q128的完整驱动开发。1. 开发环境准备工欲善其事必先利其器。在开始项目前我们需要准备好以下软硬件环境硬件清单STM32开发板本文以STM32F103C8T6为例W25Q128 Flash模块杜邦线若干USB转串口模块用于调试输出软件工具STM32CubeMX版本6.6.1或更高Keil MDK-ARM或IAR Embedded Workbench串口调试助手如Putty、SecureCRT提示W25Q128模块通常有8个引脚我们主要关注以下四个SPI接口引脚CS片选、CLK时钟、DOMISO、DIMOSI。VCC接3.3VGND接地其余引脚可悬空。2. CubeMX SPI外设配置STM32CubeMX极大地简化了外设初始化流程。按照以下步骤配置SPI1外设2.1 引脚分配与基本参数打开CubeMX新建工程选择对应型号在Pinout视图中找到SPI1设置为Full-Duplex Master自动分配的引脚通常为PA4 - SPI1_NSSPA5 - SPI1_SCKPA6 - SPI1_MISOPA7 - SPI1_MOSISPI参数配置表参数项推荐值ModeFull-Duplex MasterHardware NSSDisabledFrame FormatMotorolaData Size8 bitsFirst BitMSB FirstBaud Rate Prescaler256分频约281.25kHzClock Polarity (CPOL)LowClock Phase (CPHA)1 Edge2.2 时钟配置技巧在Clock Configuration标签页中建议将系统时钟配置为72MHzSTM32F103的最高频率。SPI时钟由APB2总线提供确保其时钟源正确。// CubeMX生成的SPI初始化代码片段 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_LOW; hspi1.Init.CLKPhase SPI_PHASE_1EDGE; hspi1.Init.NSS SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_256; hspi1.Init.FirstBit SPI_FIRSTBIT_MSB;3. W25Q128驱动开发W25Q128的操作基于指令集我们需要实现几个核心功能函数。3.1 基础通信函数首先实现字节读写函数这是所有高级操作的基础// spi.c uint8_t SPI_ReadWriteByte(uint8_t TxData) { uint8_t RxData; HAL_SPI_TransmitReceive(hspi1, TxData, RxData, 1, 1000); return RxData; } // w25q128.h #define W25Q128_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET) #define W25Q128_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET)3.2 常用指令实现W25Q128有几十条指令我们实现最常用的几个1. 读取芯片ID验证通信uint16_t W25Q128_ReadID(void) { uint16_t ID 0; W25Q128_CS_LOW(); SPI_ReadWriteByte(0x90); // 读ID指令 SPI_ReadWriteByte(0x00); SPI_ReadWriteByte(0x00); SPI_ReadWriteByte(0x00); ID | SPI_ReadWriteByte(0xFF) 8; ID | SPI_ReadWriteByte(0xFF); W25Q128_CS_HIGH(); return ID; }2. 写使能/禁止void W25Q128_WriteEnable(void) { W25Q128_CS_LOW(); SPI_ReadWriteByte(0x06); // 写使能指令 W25Q128_CS_HIGH(); } void W25Q128_WriteDisable(void) { W25Q128_CS_LOW(); SPI_ReadWriteByte(0x04); // 写禁止指令 W25Q128_CS_HIGH(); }3. 状态寄存器读取uint8_t W25Q128_ReadStatusReg(uint8_t regNum) { uint8_t status 0; W25Q128_CS_LOW(); SPI_ReadWriteByte(0x05); // 读状态寄存器指令 SPI_ReadWriteByte(regNum); status SPI_ReadWriteByte(0xFF); W25Q128_CS_HIGH(); return status; }4. 存储操作实战4.1 扇区擦除Flash存储器必须先擦除后写入擦除最小单位通常是4KB扇区。void W25Q128_SectorErase(uint32_t sectorAddr) { W25Q128_WriteEnable(); W25Q128_CS_LOW(); SPI_ReadWriteByte(0x20); // 扇区擦除指令 SPI_ReadWriteByte((sectorAddr 16) 0xFF); SPI_ReadWriteByte((sectorAddr 8) 0xFF); SPI_ReadWriteByte(sectorAddr 0xFF); W25Q128_CS_HIGH(); while(W25Q128_ReadStatusReg(1) 0x01); // 等待擦除完成 }4.2 页编程写入数据W25Q128支持页编程最大256字节但需要注意跨页处理。void W25Q128_PageProgram(uint32_t addr, uint8_t *data, uint16_t len) { W25Q128_WriteEnable(); W25Q128_CS_LOW(); SPI_ReadWriteByte(0x02); // 页编程指令 SPI_ReadWriteByte((addr 16) 0xFF); SPI_ReadWriteByte((addr 8) 0xFF); SPI_ReadWriteByte(addr 0xFF); for(uint16_t i0; ilen; i) { SPI_ReadWriteByte(data[i]); } W25Q128_CS_HIGH(); while(W25Q128_ReadStatusReg(1) 0x01); // 等待写入完成 }4.3 数据读取读取操作相对简单没有页大小限制void W25Q128_ReadData(uint32_t addr, uint8_t *buf, uint32_t len) { W25Q128_CS_LOW(); SPI_ReadWriteByte(0x03); // 读数据指令 SPI_ReadWriteByte((addr 16) 0xFF); SPI_ReadWriteByte((addr 8) 0xFF); SPI_ReadWriteByte(addr 0xFF); for(uint32_t i0; ilen; i) { buf[i] SPI_ReadWriteByte(0xFF); } W25Q128_CS_HIGH(); }5. 完整测试流程在main函数中实现完整的测试流程int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI1_Init(); MX_USART1_UART_Init(); uint16_t flashID W25Q128_ReadID(); if(flashID 0xEF17) { printf(W25Q128 detected!\r\n); } else { printf(Unknown Flash: 0x%04X\r\n, flashID); while(1); } // 测试数据 uint8_t writeData[] Hello, W25Q128!; uint8_t readData[sizeof(writeData)]; // 擦除第一个扇区 W25Q128_SectorErase(0x000000); // 写入数据 W25Q128_PageProgram(0x000000, writeData, sizeof(writeData)); printf(Data written: %s\r\n, writeData); // 读取验证 W25Q128_ReadData(0x000000, readData, sizeof(readData)); printf(Data read: %s\r\n, readData); while(1) { // 主循环 } }6. 性能优化与注意事项在实际项目中还需要考虑以下优化点SPI时钟速度初始调试时使用低速如256分频稳定后可提高至8分频甚至更高双缓冲机制大数据量读写时使用双缓冲减少等待时间磨损均衡频繁写入区域应采用算法分散写入位置掉电保护关键数据写入后应立即验证必要时采用备份机制// 高速SPI配置示例8分频约9MHz hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_8; HAL_SPI_Init(hspi1);通过本文的完整流程你应该已经掌握了STM32与W25Q128的SPI通信全流程。在实际项目中遇到问题时建议先降低SPI速度验证基本通信再逐步优化。完整工程源码可从附件获取包含了所有驱动函数和示例代码。

更多文章