网络通,测试flash

This commit is contained in:
2026-07-17 15:16:29 +08:00
parent c8c7ec0992
commit 3466c4c062
19 changed files with 4411 additions and 26 deletions

View File

@@ -0,0 +1,35 @@
/**
******************************************************************************
* @file fal_cfg.h
* @brief FAL 配置Flash 设备表 + 分区表
******************************************************************************
*/
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#define FAL_DEBUG 0
#define FAL_PART_HAS_TABLE_CFG
/* ===================== Flash 设备表 ===================== */
extern const struct fal_flash_dev gd5f2gq5ue_flash;
#define FAL_FLASH_DEV_TABLE \
{ \
&gd5f2gq5ue_flash, \
}
/* ===================== 分区表 ===================== */
/* 分区名称 设备名称 偏移 大小 */
/* KVDB: 64MB @ 0 */
/* TSDB: 64MB @ 64MB */
#ifdef FAL_PART_HAS_TABLE_CFG
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", "gd5f2gq5ue", 0, 64*1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", "gd5f2gq5ue", 64*1024*1024, 64*1024*1024, 0}, \
}
#endif
#endif /* _FAL_CFG_H_ */

View File

@@ -0,0 +1,47 @@
/**
******************************************************************************
* @file fal_flash_gd5f2gq5ue.c
* @brief FAL 端口GD5F2GQ5UE SPI NAND Flash 适配层
******************************************************************************
*/
#include "fal_def.h"
#include "gd5f2gq5ue.h"
/* ===================== FAL Flash 设备操作函数 ===================== */
static int gd5f_fal_init(void)
{
return gd5f2gq5ue_init();
}
static int gd5f_fal_read(long offset, uint8_t *buf, size_t size)
{
return gd5f2gq5ue_read(offset, buf, size);
}
static int gd5f_fal_write(long offset, const uint8_t *buf, size_t size)
{
return gd5f2gq5ue_write(offset, buf, size);
}
static int gd5f_fal_erase(long offset, size_t size)
{
return gd5f2gq5ue_erase(offset, size);
}
/* ===================== FAL Flash 设备定义 ===================== */
const struct fal_flash_dev gd5f2gq5ue_flash = {
.name = "gd5f2gq5ue",
.addr = 0,
.len = GD5F_TOTAL_SIZE, /* 256MB */
.blk_size = GD5F_BLOCK_SIZE, /* 128KB */
.ops = {
.init = gd5f_fal_init,
.read = gd5f_fal_read,
.write = gd5f_fal_write,
.erase = gd5f_fal_erase,
},
.write_gran = 8,
};

View File

@@ -0,0 +1,32 @@
/**
******************************************************************************
* @file fdb_cfg.h
* @brief FlashDB 配置文件
******************************************************************************
*/
#ifndef _FDB_CFG_H_
#define _FDB_CFG_H_
/* 启用 KVDB键值数据库 */
#define FDB_USING_KVDB
#ifdef FDB_USING_KVDB
/* 当 KVDB 版本号变化时自动更新到最新默认值 */
/* #define FDB_KV_AUTO_UPDATE */
#endif
/* 启用 TSDB时序数据库 */
#define FDB_USING_TSDB
/* 使用 FAL 存储模式(非文件模式) */
#define FDB_USING_FAL_MODE
/* Flash 写入粒度单位bit
* STM32F4 = 8字节可编程 */
#define FDB_WRITE_GRAN 8
/* 调试输出 */
#define FDB_DEBUG_ENABLE
#endif /* _FDB_CFG_H_ */

View File

@@ -0,0 +1,367 @@
/**
******************************************************************************
* @file gd5f2gq5ue.c
* @brief GD5F2GQ5UE SPI NAND Flash 驱动实现
******************************************************************************
*/
#include "gd5f2gq5ue.h"
#include <string.h>
extern SPI_HandleTypeDef hspi1;
/* ===================== 内部辅助函数 ===================== */
/**
* @brief SPI 发送/接收单字节
*/
static uint8_t gd5f_spi_xfer(uint8_t tx)
{
uint8_t rx;
HAL_SPI_TransmitReceive(&hspi1, &tx, &rx, 1, 100);
return rx;
}
/**
* @brief SPI 发送缓冲区
*/
static void gd5f_spi_tx(const uint8_t *buf, size_t len)
{
HAL_SPI_Transmit(&hspi1, (uint8_t *)buf, len, 100);
}
/**
* @brief SPI 接收缓冲区
*/
static void gd5f_spi_rx(uint8_t *buf, size_t len)
{
HAL_SPI_Receive(&hspi1, buf, len, 100);
}
/**
* @brief 等待操作完成OIP 位清零)
* @param timeout_ms: 超时时间(毫秒)
* @retval GD5F_OK 成功, GD5F_BUSY_TIMEOUT 超时
*/
static int gd5f_wait_busy(uint32_t timeout_ms)
{
uint8_t cmd = GD5F_CMD_GET_FEATURE;
uint8_t addr = GD5F_REG_STATUS;
uint8_t status;
uint32_t tickstart = HAL_GetTick();
while (1) {
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_tx(&addr, 1);
gd5f_spi_rx(&status, 1);
GD5F_CS_HIGH();
if ((status & GD5F_STATUS_OIP) == 0) {
return GD5F_OK;
}
if ((HAL_GetTick() - tickstart) >= timeout_ms) {
return GD5F_BUSY_TIMEOUT;
}
}
}
/**
* @brief 写使能
*/
static int gd5f_write_enable(void)
{
uint8_t cmd = GD5F_CMD_WRITE_ENABLE;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 读取状态寄存器
*/
static int gd5f_read_status(uint8_t *status)
{
uint8_t cmd = GD5F_CMD_GET_FEATURE;
uint8_t addr = GD5F_REG_STATUS;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_tx(&addr, 1);
gd5f_spi_rx(status, 1);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 页读取到缓存Page Read to Cache
* @param page_addr: 页地址(行地址,包含 block + page
*/
static int gd5f_page_read(uint32_t page_addr)
{
uint8_t cmd[4];
cmd[0] = GD5F_CMD_PAGE_READ;
cmd[1] = (page_addr >> 16) & 0xFF;
cmd[2] = (page_addr >> 8) & 0xFF;
cmd[3] = page_addr & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
GD5F_CS_HIGH();
return gd5f_wait_busy(100);
}
/**
* @brief 从缓存读取数据Read from Cache
* @param column: 列地址(页内偏移)
* @param buf: 数据缓冲区
* @param size: 读取字节数
*/
static int gd5f_read_from_cache(uint16_t column, uint8_t *buf, size_t size)
{
uint8_t cmd[5];
cmd[0] = GD5F_CMD_READ_FROM_CACHE;
cmd[1] = (column >> 8) & 0xFF;
cmd[2] = column & 0xFF;
cmd[3] = 0x00; /* dummy byte */
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
gd5f_spi_rx(buf, size);
GD5F_CS_HIGH();
return GD5F_OK;
}
/**
* @brief 页编程(从缓存写入阵列)
* @param page_addr: 页地址
* @param column: 列地址
* @param buf: 数据缓冲区
* @param size: 写入字节数
*/
static int gd5f_page_program(uint32_t page_addr, uint16_t column, const uint8_t *buf, size_t size)
{
int ret;
uint8_t cmd[4];
/* 1. 写使能 */
gd5f_write_enable();
/* 2. 数据加载到缓存 (Program Load) */
cmd[0] = GD5F_CMD_PROGRAM_LOAD;
cmd[1] = (column >> 8) & 0xFF;
cmd[2] = column & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 3);
gd5f_spi_tx(buf, size);
GD5F_CS_HIGH();
/* 3. 编程执行 (Program Execute) */
cmd[0] = GD5F_CMD_PROGRAM_EXEC;
cmd[1] = (page_addr >> 16) & 0xFF;
cmd[2] = (page_addr >> 8) & 0xFF;
cmd[3] = page_addr & 0xFF;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
GD5F_CS_HIGH();
/* 4. 等待完成 */
ret = gd5f_wait_busy(1000);
if (ret != GD5F_OK) return ret;
/* 5. 检查编程结果 */
uint8_t status;
gd5f_read_status(&status);
if (status & GD5F_STATUS_P_FAIL) {
/* 清除 P_FAIL写使能 + 读状态 */
gd5f_write_enable();
return GD5F_PROGRAM_FAIL;
}
return GD5F_OK;
}
/**
* @brief 块擦除
* @param block_addr: 块地址 (0 ~ 2047)
*/
static int gd5f_block_erase(uint32_t block_addr)
{
int ret;
uint8_t cmd[4];
/* 1. 写使能 */
gd5f_write_enable();
/* 2. 块擦除命令 */
cmd[0] = GD5F_CMD_BLOCK_ERASE;
cmd[1] = (block_addr >> 8) & 0xFF;
cmd[2] = block_addr & 0xFF;
cmd[3] = 0x00;
GD5F_CS_LOW();
gd5f_spi_tx(cmd, 4);
GD5F_CS_HIGH();
/* 3. 等待完成(擦除较慢) */
ret = gd5f_wait_busy(5000);
if (ret != GD5F_OK) return ret;
/* 4. 检查擦除结果 */
uint8_t status;
gd5f_read_status(&status);
if (status & GD5F_STATUS_E_FAIL) {
gd5f_write_enable();
return GD5F_ERASE_FAIL;
}
return GD5F_OK;
}
/* ===================== 公共接口实现 ===================== */
int gd5f2gq5ue_init(void)
{
int ret;
uint8_t mid, did;
/* 确保控制引脚处于非激活状态 */
GD5F_CS_HIGH();
GD5F_WP_HIGH();
GD5F_HOLD_HIGH();
/* 小延时等待上电稳定 */
HAL_Delay(10);
/* 复位芯片 */
ret = gd5f2gq5ue_reset();
if (ret != GD5F_OK) return ret;
HAL_Delay(5);
/* 读取 ID 验证通信 */
ret = gd5f2gq5ue_read_id(&mid, &did);
if (ret != GD5F_OK) return ret;
if (mid != GD5F_MANUFACTURER_ID || did != GD5F_DEVICE_ID) {
return GD5F_ID_MISMATCH;
}
return GD5F_OK;
}
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did)
{
uint8_t cmd = GD5F_CMD_READ_ID;
uint8_t id_buf[3];
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
gd5f_spi_rx(id_buf, 3); /* dummy + MID + DID */
GD5F_CS_HIGH();
*mid = id_buf[1]; /* id_buf[0] = dummy */
*did = id_buf[2];
return GD5F_OK;
}
int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size)
{
int ret;
while (size > 0) {
/* 计算页地址和列偏移 */
uint32_t page_addr = offset / GD5F_PAGE_SIZE;
uint16_t column = offset % GD5F_PAGE_SIZE;
/* 本次读取字节数(不超过当前页剩余空间) */
size_t bytes = GD5F_PAGE_SIZE - column;
if (bytes > size) bytes = size;
/* Page Read to Cache */
ret = gd5f_page_read(page_addr);
if (ret != GD5F_OK) return ret;
/* Read from Cache */
ret = gd5f_read_from_cache(column, buf, bytes);
if (ret != GD5F_OK) return ret;
offset += bytes;
buf += bytes;
size -= bytes;
}
return GD5F_OK;
}
int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size)
{
int ret;
while (size > 0) {
/* 计算页地址和列偏移 */
uint32_t page_addr = offset / GD5F_PAGE_SIZE;
uint16_t column = offset % GD5F_PAGE_SIZE;
/* 本次写入字节数(不超过当前页剩余空间) */
size_t bytes = GD5F_PAGE_SIZE - column;
if (bytes > size) bytes = size;
/* 页编程 */
ret = gd5f_page_program(page_addr, column, buf, bytes);
if (ret != GD5F_OK) return ret;
offset += bytes;
buf += bytes;
size -= bytes;
}
return GD5F_OK;
}
int gd5f2gq5ue_erase(long offset, size_t size)
{
int ret;
/* 擦除起始地址必须块对齐 */
if (offset % GD5F_BLOCK_SIZE != 0) {
return GD5F_ERROR;
}
/* 擦除大小必须为块大小的整数倍 */
if (size % GD5F_BLOCK_SIZE != 0) {
return GD5F_ERROR;
}
/* 逐块擦除 */
while (size > 0) {
uint32_t block_addr = offset / GD5F_BLOCK_SIZE;
ret = gd5f_block_erase(block_addr);
if (ret != GD5F_OK) return ret;
offset += GD5F_BLOCK_SIZE;
size -= GD5F_BLOCK_SIZE;
}
return GD5F_OK;
}
int gd5f2gq5ue_reset(void)
{
uint8_t cmd = GD5F_CMD_RESET;
GD5F_CS_LOW();
gd5f_spi_tx(&cmd, 1);
GD5F_CS_HIGH();
HAL_Delay(5);
return GD5F_OK;
}

View File

@@ -0,0 +1,133 @@
/**
******************************************************************************
* @file gd5f2gq5ue.h
* @brief GD5F2GQ5UE SPI NAND Flash 驱动头文件
******************************************************************************
*/
#ifndef __GD5F2GQ5UE_H
#define __GD5F2GQ5UE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "spi.h"
/* ===================== 硬件引脚定义 ===================== */
#define GD5F_CS_LOW() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_RESET)
#define GD5F_CS_HIGH() HAL_GPIO_WritePin(GD_CS_GPIO_Port, GD_CS_Pin, GPIO_PIN_SET)
#define GD5F_WP_HIGH() HAL_GPIO_WritePin(GD_WP_GPIO_Port, GD_WP_Pin, GPIO_PIN_SET)
#define GD5F_HOLD_HIGH() HAL_GPIO_WritePin(GD_HOLD_GPIO_Port, GD_HOLD_Pin, GPIO_PIN_SET)
/* ===================== SPI 命令码 ===================== */
#define GD5F_CMD_WRITE_ENABLE 0x06
#define GD5F_CMD_WRITE_DISABLE 0x04
#define GD5F_CMD_GET_FEATURE 0x0F
#define GD5F_CMD_SET_FEATURE 0x1F
#define GD5F_CMD_READ_ID 0x9F
#define GD5F_CMD_PAGE_READ 0x13
#define GD5F_CMD_READ_FROM_CACHE 0x0B /* Fast Read, 1 dummy byte */
#define GD5F_CMD_PROGRAM_LOAD 0x02
#define GD5F_CMD_PROGRAM_EXEC 0x10
#define GD5F_CMD_BLOCK_ERASE 0xD8
#define GD5F_CMD_RESET 0xFF
/* ===================== 寄存器地址 ===================== */
#define GD5F_REG_STATUS 0xC0
#define GD5F_REG_PROTECT 0xA0
#define GD5F_REG_FEATURE 0xB0
#define GD5F_REG_DRIVER 0xD0
/* ===================== 状态位定义 ===================== */
#define GD5F_STATUS_OIP (1 << 0) /* 操作进行中 */
#define GD5F_STATUS_WEL (1 << 1) /* 写使能锁存 */
#define GD5F_STATUS_E_FAIL (1 << 2) /* 擦除失败 */
#define GD5F_STATUS_P_FAIL (1 << 3) /* 编程失败 */
#define GD5F_STATUS_BIT4 (1 << 4)
#define GD5F_STATUS_ECCS0 (1 << 5)
#define GD5F_STATUS_ECCS1 (1 << 6)
#define GD5F_STATUS_ECCSE0 (1 << 4) /* ECC 单 bit 错误低位 */
#define GD5F_STATUS_ECCSE1 (1 << 5) /* ECC 单 bit 错误高位 */
#define GD5F_STATUS_ECCSE2 (1 << 6) /* ECC 单 bit 错误高位 */
/* ===================== Feature 位定义 ===================== */
#define GD5F_FEATURE_ECC_EN (1 << 4)
#define GD5F_FEATURE_QE (1 << 0) /* Quad Enable, B0[0] */
/* ===================== 芯片参数 ===================== */
#define GD5F_PAGE_SIZE 2048 /* 主数据区字节数 */
#define GD5F_SPARE_SIZE 64 /* ECC 启用时 spare 区 */
#define GD5F_TOTAL_PAGE_SIZE 2112 /* 2048 + 64 */
#define GD5F_PAGES_PER_BLOCK 64
#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) /* 128KB */
#define GD5F_TOTAL_BLOCKS 2048
#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE) /* 256MB */
/* 制造商 ID 和设备 ID */
#define GD5F_MANUFACTURER_ID 0xC8
#define GD5F_DEVICE_ID 0x52
/* ===================== 返回值定义 ===================== */
#define GD5F_OK 0
#define GD5F_ERROR -1
#define GD5F_BUSY_TIMEOUT -2
#define GD5F_ECC_ERROR -3
#define GD5F_PROGRAM_FAIL -4
#define GD5F_ERASE_FAIL -5
#define GD5F_ID_MISMATCH -6
/* ===================== 公共接口函数 ===================== */
/**
* @brief 初始化 GD5F2GQ5UESPI + GPIO + 读 ID 验证)
* @retval GD5F_OK 成功, 其他为错误码
*/
int gd5f2gq5ue_init(void);
/**
* @brief 读取芯片 IDMID + DID
* @param mid: 制造商 ID 输出指针
* @param did: 设备 ID 输出指针
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_read_id(uint8_t *mid, uint8_t *did);
/**
* @brief 从 NAND 读取数据(支持跨页)
* @param offset: 起始字节偏移(相对于 Flash 起始地址)
* @param buf: 数据缓冲区
* @param size: 读取字节数
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size);
/**
* @brief 向 NAND 写入数据(支持跨页)
* @param offset: 起始字节偏移
* @param buf: 数据缓冲区
* @param size: 写入字节数
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size);
/**
* @brief 擦除块(按块擦除,最小单位 128KB
* @param offset: 起始字节偏移(必须块对齐)
* @param size: 擦除字节数(必须为块大小的整数倍)
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_erase(long offset, size_t size);
/**
* @brief 复位芯片
* @retval GD5F_OK 成功
*/
int gd5f2gq5ue_reset(void);
#ifdef __cplusplus
}
#endif
#endif /* __GD5F2GQ5UE_H */