W25Q128 是一种常见的串行闪存器件,它采用 SPI(Serial Peripheral Interface)接口协议,具有高速读写和擦除功能,可用于存储和读取数据。W25Q128 芯片容量为 128 Mbit(16 MB),其中名称后的数字代表不同的容量选项。不同的型号和容量选项可以满足不同应用的需求,通常被用于嵌入式设备、存储设备、路由器等高性能电子设备中。
W25Q128 闪存芯片的内存分配是按照扇区(Sector)和块(Block)进行的,每个扇区的大小为 4KB,每个块包含 16 个扇区,即一个块的大小为 64KB。
存储结构图
引脚说明
引脚编号 |
引脚名称 |
描述 |
1 |
/CS |
芯片选择引脚(Chip Select) |
2 |
DO (IO₁) |
数据输出引脚(Data Out,I/O1) |
3 |
/WP (IO₂) |
写保护引脚(Write Protect,I/O2) |
4 |
GND |
地引脚(Ground) |
5 |
DI (IO₀) |
数据输入引脚(Data In,I/O0) |
6 |
CLK |
时钟信号引脚(Clock) |
7 |
/HOLD or /RESET (IO₃) |
保持或复位引脚(Hold/Reset,I/O3) |
8 |
VCC |
电源引脚(Power Supply) |
/ 表示引脚是低电平有效。
HOLD:当它有效时允许设备暂停,低电平:DO 引脚高阻态,DI CLK 引脚的信号被忽略。高电平:设备重新开始,当多个设备共享相同的 SPI 信 号的时候该功能可能会被用到。
示例电路
SPI
根据 W25Q128 的数据手册,得到以下配置:
- SPI 配置为了全双工模式,可以同时发送与接收数据;
- STM32F407 配置为主机模式,由 STM32F407 产生时钟,与从机 W25Q128 进行通信;
- 数据的传输以 8 位进行传输。
- 片选方式选择软件控制片选。在硬件 SPI 中,一个 SPI 只有一个片选线,这会导致硬件 SPI 如果选择硬件控制片选信号,只能控制一个从机。我们是希望能够一个 SPI 可以控制多个从机,因此选择软件方式片选,片选线可以随意设定。
- 时钟分频选择 4 分频,根据 W25Q128 的数据手册说明,W25Q128 的 SPI 时钟可以达到 30MHz,而我们的 SPI0 的时钟来源为 PCLK2=84MHz,SPI 的配置中必须要求进行分频,分频之后的频率是 21MH,低于 30Mhz,W25Q1282 完全可以兼容。
- 字节顺序选择高位在前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(BSP_SPI, &SPI_InitStructure);
SPI_Cmd(BSP_SPI, ENABLE);
|
示例代码
https://github.com/TooUpper/SensorDrive
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include "board.h" #include "bsp_uart.h" #include <stdio.h> #include "spi_flash.h" #include <string.h>
int main(void){ board_init(); uart1_init(115200U);
bsp_spi_init();
unsigned char buff[20] = {0};
printf("\r\n=========【开始】========\r\n");
printf("\r\n【1】擦除Flash扇区0......\r\n"); W25Q128_erase_sector(0); printf("Flash扇区0擦除完成!!\r\n"); delay_ms(200);
printf("\r\n【2】读取设备的id......\r\n"); printf("设备ID = %X\r\n",W25Q128_readID());
printf("\r\n【3】读取0地址长度为10个字节的数据到buff......\r\n"); W25Q128_read(buff, 0, 10); printf("读取到的数据= %s\r\n",buff); delay_ms(200);
printf("\r\n【4】往0地址写入8个字节的数据 “TooUpper”......\r\n"); W25Q128_write((uint8_t *)"TooUpper", 0, 8); delay_ms(200); printf("数据写入成功!\r\n");
printf("\r\n【5】读取0地址长度为8个字节的数据到buff......\r\n"); W25Q128_read(buff, 0, 8); printf("读取到的数据= %s\r\n",buff); delay_ms(1000);
printf("\r\n【6】功能测试完毕擦除写入的数据......\r\n"); W25Q128_erase_sector(0); delay_ms(200);
memset(buff,0,sizeof(buff));
printf("\r\n=========【结束】========\r\n");
while(1) { delay_ms(100); } }
|