#ifndef __GD5F2GQ5UE_H #define __GD5F2GQ5UE_H /* * 模块名称:GD5F2GQ5UE SPI NAND Flash 驱动 * 模块功能:提供 GD5F2GQ5UE SPI NAND Flash 的初始化、读、写、擦除接口 * 适用平台:STM32F407ZGT6 + SPI1 硬件 SPI * 作者:王建锋 * 创建日期:2026-07-16 * 修改记录: * 2026-07-16 王建锋 创建初始版本 * 2026-07-17 王建锋 切换为硬件 SPI,修正擦除地址,参考 NuttX 驱动 */ #ifdef __cplusplus extern "C" { #endif #include "main.h" #include /* ======================== 宏定义 ======================== */ /* 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 #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_PROTECT 0xA0 #define GD5F_REG_FEATURE 0xB0 #define GD5F_REG_STATUS 0xC0 #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_ECCS0 (1 << 4) #define GD5F_STATUS_ECCS1 (1 << 5) /* Feature 位定义 */ #define GD5F_FEATURE_ECC_EN (1 << 4) #define GD5F_FEATURE_QE (1 << 0) /* 芯片参数 */ #define GD5F_PAGE_SIZE 2048 #define GD5F_SPARE_SIZE 64 #define GD5F_TOTAL_PAGE_SIZE 2112 #define GD5F_PAGES_PER_BLOCK 64 #define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) #define GD5F_TOTAL_BLOCKS 2048 #define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE) /* 坏块表持久化:保留块池数量(从 NAND 顶部向下挑选出厂好块存储 BBT) */ #define GD5F_BBT_POOL_COUNT 4 /* 制造商 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 /* 控制引脚宏 */ #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) /* ======================== 函数声明 ======================== */ /* * 函数功能:初始化 GD5F2GQ5UE(读 ID + 使能 ECC + 解除块保护) * 入口参数:无 * 返回值:0 - 成功,其他 - 错误码 * 限定条件:SPI1 和相关 GPIO 已由 CubeMX 初始化完成 * 函数说明:1. 发送复位命令并等待完成 * 2. 读取芯片 ID 并校验 * 3. 使能内部 ECC (B0h bit4) * 4. 解除所有块保护 (A0h = 0x00) */ int32_t gd5f2gq5ue_init(void); /* * 函数功能:读取芯片 ID(MID + DID) * 入口参数:mid - 制造商 ID 输出指针 uint8_t* 不为 NULL * did - 设备 ID 输出指针 uint8_t* 不为 NULL * 返回值:0 - 成功 * 限定条件:SPI 已初始化 * 函数说明:发送 9Fh 命令后接收1个 dummy + MID + DID */ int32_t gd5f2gq5ue_read_id(uint8_t *p_mid, uint8_t *p_did); /* * 函数功能:从 NAND 读取数据(支持跨页) * 入口参数:offset - 起始字节偏移 int32_t 0 - GD5F_TOTAL_SIZE-1 * buf - 数据缓冲区 uint8_t* 不为 NULL * size - 读取字节数 uint32_t > 0 * 返回值:0 - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:自动处理跨页读取,每次读取不超过当前页剩余空间 */ int gd5f2gq5ue_read(long offset, uint8_t *buf, size_t size); /* * 函数功能:向 NAND 写入数据(支持跨页) * 入口参数:offset - 起始字节偏移 int32_t 0 - GD5F_TOTAL_SIZE-1 * buf - 数据缓冲区 uint8_t* 不为 NULL * size - 写入字节数 uint32_t > 0 * 返回值:0 - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用,目标区域已擦除 * 函数说明:自动处理跨页写入,每次写入不超过当前页剩余空间 */ int gd5f2gq5ue_write(long offset, const uint8_t *buf, size_t size); /* * 函数功能:擦除块(按块擦除,最小单位 128KB) * 入口参数:offset - 起始字节偏移 int32_t 必须 GD5F_BLOCK_SIZE 对齐 * size - 擦除字节数 uint32_t 必须 GD5F_BLOCK_SIZE 整数倍 * 返回值:0 - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:擦除操作以块为单位,offset 和 size 必须块对齐 */ int gd5f2gq5ue_erase(long offset, size_t size); /* * 函数功能:复位芯片 * 入口参数:无 * 返回值:0 - 成功 * 限定条件:SPI 已初始化 * 函数说明:发送 FFh 复位命令后等待 5ms */ int32_t gd5f2gq5ue_reset(void); /* * 函数功能:查询块是否坏块 * 入口参数:block - 块编号 uint32_t 0 ~ GD5F_TOTAL_BLOCKS-1 * 返回值:0 - 好块,1 - 坏块 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:通过 BBT(Bad Block Table)查询,BBT 在 init 阶段 ECC 使能前扫描构建 */ int32_t gd5f2gq5ue_is_block_bad(uint32_t block); /* * 函数功能:标记块为坏块 * 入口参数:block - 块编号 uint32_t 0 ~ GD5F_TOTAL_BLOCKS-1 * 返回值:无 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:更新 RAM 中的 BBT,并持久化到保留块池(带版本号 + CRC, * 轮转写入,掉电安全);仅在管理区内的块才纳入持久化 BBT */ void gd5f2gq5ue_mark_block_bad(uint32_t block); void gd5f2gq5ue_bbt_clear(void); void gd5f2gq5ue_print_bbt(void); /* * 函数功能:重建 BBT(重新扫描出厂坏块并持久化,覆盖运行时注入的坏块) * 入口参数:无 * 返回值:GD5F_OK - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:用于测试(如 TC-STO-03 注入坏块后)或出厂重置后恢复。 * 临时关闭 ECC 重新扫描每块 page0 spare[0] 的出厂坏块标记,覆盖 RAM BBT, * 再写回持久化 BBT 池(版本 +1,掉电安全),从而清除运行时 mark 的坏块。 * 调用后建议再执行 nand_ftl_format() 清空 dhara map。 */ int gd5f2gq5ue_bbt_rebuild(void); /* * 函数功能:获取 dhara 可用块数(总块数减去保留块池) * 入口参数:无 * 返回值:dhara 可见的块数量(= 保留块池起始块号) * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:保留块池用于存储持久化 BBT,不交给 dhara 管理 */ uint32_t gd5f_get_usable_blocks(void); /* * 函数功能:从闪存读取当前生效的 BBT 位图(测试/调试用) * 入口参数:p_bbt - 位图输出缓冲 uint8_t* 不为 NULL,长度 >= GD5F_BBT_SIZE * p_version - 版本号输出 uint32_t* 不为 NULL * 返回值:0 - 成功,其他 - 错误码 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:返回闪存中版本号最高的有效 BBT 拷贝(供测试验证持久化) */ int32_t gd5f_bbt_dump_flash(uint8_t *p_bbt, uint32_t *p_version); /* * 函数功能:擦除保留块池(撤销持久化 BBT,回到仅工厂扫描态) * 入口参数:无 * 返回值:0 - 成功 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:仅供测试/出厂重置使用;擦除后下次启动 load 找不到副本, * 仅保留 RAM 中工厂扫描结果(调用方需自行还原 RAM BBT)。 */ int32_t gd5f_bbt_wipe_pool(void); /* * 函数功能:从保留块池重新加载持久化 BBT 到 RAM(测试/调试用) * 入口参数:无 * 返回值:0 - 成功 * 限定条件:gd5f2gq5ue_init() 已成功调用 * 函数说明:将闪存中版本号最高的有效副本 OR 进 RAM BBT */ int32_t gd5f_bbt_reload(void); /* ==================== SPI 原语(FTL 共享) ==================== */ int32_t gd5f_wait_busy(uint32_t timeout_ms); int32_t gd5f_write_enable(void); int32_t gd5f_read_status(uint8_t *p_status); int32_t gd5f_page_read(uint32_t page_addr); int32_t gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, uint32_t size); int32_t gd5f_program_load(uint16_t column, const uint8_t *p_buf, uint32_t size); int32_t gd5f_program_exec(uint32_t page_addr); int32_t gd5f_block_erase(uint32_t block_addr); int32_t gd5f_check_ecc(void); #ifdef __cplusplus } #endif #endif /* __GD5F2GQ5UE_H */