GD25Q40E Flash 存储器驱动
一个针对兆易创新 GD25Q40E 4Mbit SPI Flash 存储器的完整驱动程序,支持标准的 SPI 接口通信和各种存储操作。
源码下载
📋 特性概述
- 完整协议支持: 实现所有 GD25Q40E 标准指令集
- 多种读写模式: 支持标准读、快速读、页编程等功能
- 灵活擦除选项: 提供扇区(4KB)、块(32KB/64KB)和整片擦除
- 电源管理: 支持低功耗模式和唤醒功能
- 设备识别: 可读取制造商ID、设备ID和唯一ID
- 错误检查: 包含地址边界检查和参数验证
🏗️ 硬件连接
SPI 接口连接
1
2
3
4
5
6
7
8
9
10
|
GD25Q40E MCU
─────────────────────
CS (Pin 1) → GPIO Output (片选)
SO (Pin 2) → SPI MISO
WP (Pin 3) → VCC (写保护禁用)
GND (Pin 4) → GND
SI (Pin 5) → SPI MOSI
SCK (Pin 6) → SPI SCK
HOLD (Pin 7) → VCC (保持禁用)
VCC (Pin 8) → 3.3V
|
必要配置
在 SysConfig.h 中定义硬件配置:
1
2
3
|
#define FLASH_SPI_PORT GPIOA // 片选端口
#define FLASH_SPI_SS_SF GPIO_PIN_4 // 片选引脚
extern SPI_HandleTypeDef hspi1; // SPI 句柄
|
🔧 快速开始
1. 初始化 Flash
1
2
3
4
5
6
7
8
9
|
#include "GD25Q40E.h"
// 初始化并检测Flash
uint32_t flash_id = GD25Q40E_Init();
if (flash_id == 0xC84013) {
printf("GD25Q40E 初始化成功\n");
} else {
printf("Flash 检测失败: 0x%06lX\n", flash_id);
}
|
2. 基本读写操作
1
2
3
4
5
6
7
|
// 写入数据
uint8_t write_data[] = {0x01, 0x02, 0x03, 0x04};
GD25Q40E_WriteData(write_data, 0x1000, sizeof(write_data));
// 读取数据
uint8_t read_data[4];
GD25Q40E_ReadBytes(read_data, 0x1000, sizeof(read_data));
|
3. 擦除操作
1
2
3
4
5
|
// 擦除一个扇区 (4KB)
GD25Q40E_EraseSector(0x1000);
// 擦除整个芯片
GD25Q40E_EraseChip();
|
📊 存储结构
| 参数 |
数值 |
说明 |
| 总容量 |
512KB |
4Mbit |
| 页大小 |
256字节 |
编程最小单位 |
| 扇区大小 |
4KB |
擦除最小单位 |
| 32K块大小 |
32KB |
块擦除选项 |
| 64K块大小 |
64KB |
块擦除选项 |
| 地址范围 |
0x00000-0x7FFFF |
24位地址 |
🎯 API 参考
初始化函数
GD25Q40E_Init() - 初始化并检测Flash设备
GD25Q40E_ReadID() - 读取设备ID (预期值: 0xC84013)
数据读取
GD25Q40E_ReadBytes() - 标准模式读取数据
GD25Q40E_FastReadByte() - 快速模式读取数据
数据写入
GD25Q40E_PageProgram() - 页编程 (256字节/页)
GD25Q40E_WriteData() - 自动处理跨页写入
擦除操作
GD25Q40E_EraseSector() - 擦除4KB扇区
GD25Q40E_EraseBlock32K() - 擦除32KB块
GD25Q40E_EraseBlock64K() - 擦除64KB块
GD25Q40E_EraseChip() - 整片擦除
电源管理
GD25Q40E_PowerDown() - 进入低功耗模式
GD25Q40E_WakeUp() - 从低功耗模式唤醒
设备信息
GD25Q40E_ReadREMS() - 读取REMS ID
GD25Q40E_ReadUniqueID() - 读取唯一ID
⚙️ 移植指南
1. 修改硬件配置
在 GD25Q40E.c 中修改硬件相关宏:
1
2
|
#define WTRITE_PIN(__PORT__, __PIN__, __VALUE) HAL_GPIO_WritePin(__PORT__, __PIN__, __VALUE)
#define Delay_1ms(X) HAL_Delay(X)
|
2. 实现SPI通信函数
修改 GD25Q40E_TransmitReceiveData() 函数以匹配您的SPI驱动:
1
2
3
4
5
6
7
|
static uint8_t GD25Q40E_TransmitReceiveData(uint8_t txdata)
{
uint8_t rxdata = 0;
// 替换为您的SPI收发函数
HAL_SPI_TransmitReceive(GD25Q40E_SPI, &txdata, &rxdata, 1, HAL_MAX_DELAY);
return rxdata;
}
|
3. 配置SPI句柄
在 GD25Q40E.h 中指定使用的SPI句柄:
1
|
#define GD25Q40E_SPI &hspi1 // 修改为您的SPI句柄
|
💡 使用示例
存储配置数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
typedef struct {
uint32_t magic;
uint8_t version;
uint16_t checksum;
} config_t;
config_t config = {0xAA55AA55, 0x01, 0};
// 写入配置数据
GD25Q40E_EraseSector(0x0000);
GD25Q40E_WriteData((uint8_t*)&config, 0x0000, sizeof(config));
// 读取验证
config_t read_config;
GD25Q40E_ReadBytes((uint8_t*)&read_config, 0x0000, sizeof(read_config));
|
数据日志记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void log_data(uint32_t timestamp, float temperature)
{
static uint32_t log_address = 0x1000;
uint8_t log_entry[8];
memcpy(log_entry, ×tamp, 4);
memcpy(log_entry + 4, &temperature, 4);
GD25Q40E_WriteData(log_entry, log_address, 8);
log_address += 8;
if (log_address >= 0x2000) {
log_address = 0x1000; // 循环写入
GD25Q40E_EraseSector(0x1000);
}
}
|
⚠️ 注意事项
- 写保护: 确保WP引脚接高电平以禁用写保护
- 擦除必要: 写入前必须擦除目标区域(变为0xFF)
- 页边界: 单次写入不能跨页边界,使用
GD25Q40E_WriteData() 自动处理
- 操作等待: 擦除和写入操作需要时间,使用内置等待机制
- 电压匹配: 确保使用3.3V电压供电和信号电平
🔍 故障排除
常见问题
- 初始化失败: 检查SPI连接、片选引脚的配置
- 写入失败: 确认写使能序列正确执行
- 数据错误: 验证地址没有越界,确保区域已擦除
调试建议
1
2
3
4
5
6
7
|
// 检查设备ID
uint32_t id = GD25Q40E_ReadID();
printf("Device ID: 0x%06lX\n", id);
// 检查状态寄存器
uint8_t status = GD25Q40E_ReadStatusReg();
printf("Status: 0x%02X\n", status);
|
📝 版本历史
- v0.1 (2025-08-13)
- 初始版本发布
- 实现所有基本功能
- 添加详细的错误检查
👥 作者信息
N1netyNine99 - 嵌入式系统开发者
📄 许可证
MIT License - 可自由用于个人和商业项目。
💡 提示: 在使用前请仔细阅读GD25Q40E的数据手册,确保理解各项时序要求和电气特性。