From f4d4cef9e688c3954ddec1a6095cf0c53fdd3dff Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Sun, 20 Sep 2026 04:58:44 +0800 Subject: [PATCH] =?UTF-8?q?GD5F=E9=A1=B5=E8=AF=BB=E5=8F=96=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=E6=B2=89=E9=99=8D=E5=BB=B6=E6=97=B6=EF=BC=9A13h?= =?UTF-8?q?=E5=90=8E=E7=AD=895ms=E5=86=8D0Bh=EF=BC=8C=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E4=BD=8EVDD=E5=B0=B1=E7=BB=AA=E4=BF=A1=E5=8F=B7=E6=8F=90?= =?UTF-8?q?=E5=89=8D=E5=AF=BC=E8=87=B4=E7=9A=84=E5=8D=8A=E6=96=B0=E5=8D=8A?= =?UTF-8?q?=E6=97=A7=E9=A1=B5=EF=BC=88resume=E8=AF=BB=E6=97=A7=E6=A0=91?= =?UTF-8?q?=E6=A0=B9=E6=B2=BB=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c | 70 ++++++++++------------------- Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h | 10 +++++ 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c index 03e71b8a..70b9b4ab 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c @@ -153,14 +153,20 @@ int gd5f_read_status(uint8_t *p_status) { } /* - * 函数功能:发送一次 13h 页读取命令(gd5f_page_read 的装载单元) + * 函数功能:页读取(将数据从存储阵列加载到内部缓存) * 入口参数:page_addr - 页地址 uint32_t 0 ~ GD5F_TOTAL_BLOCKS*64-1 - * 返回值:无 + * 返回值:0 - 成功,其它 - 错误 * 限定条件:SPI 已初始化 - * 函数说明:发 13h + 3字节行地址(单次装载) + * 函数说明:发 13h + 3字节行地址,等待 OIP 清零 + 固定沉降延时 + * GD5F_PAGE_READ_SETTLE_MS(2026-09-20 台架实证:低 VDD 下 + * 就绪信号早于 array→buffer 整页装载完成,0Bh 会读到"前段新、 + * 后段旧"的混合页 → journal resume 锚定新 checkpoint 却读到 + * 旧树 → 数据静默丢失。固定沉降保证整页新鲜,双装载无法 + * 消除该确定性竞态,已弃用。) */ -static void gd5f_page_read_issue(uint32_t page_addr) { +int gd5f_page_read(uint32_t page_addr) { uint8_t cmd[4] = {0}; + int ret; cmd[0] = GD5F_CMD_PAGE_READ; cmd[1] = (page_addr >> 16) & 0xFF; @@ -170,31 +176,16 @@ static void gd5f_page_read_issue(uint32_t page_addr) { GD5F_CS_LOW(); HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT); GD5F_CS_HIGH(); -} -/* - * 函数功能:页读取(将数据从存储阵列加载到内部缓存,二次装载) - * 入口参数:page_addr - 页地址 uint32_t 0 ~ GD5F_TOTAL_BLOCKS*64-1 - * 返回值:0 - 成功,其它 - 错误 - * 限定条件:SPI 已初始化 - * 函数说明:发 13h + 3字节行地址,等待 OIP 清零;随后二次装载(2026-09-20 - * 台架实证:低 VDD 下就绪信号早于 buffer 整页装载完成,单次装载 - * 后读 cache 得到"前半新、后半旧"的混合页 → journal checkpoint - * header 有效而 meta 残留旧数据 → 复位后 resume 锚定新 checkpoint - * 却读到旧树 → 数据静默丢失。二次装载保证整页新鲜。) - */ -int gd5f_page_read(uint32_t page_addr) { - int ret; - - gd5f_page_read_issue(page_addr); ret = gd5f_wait_busy(100); if (ret != GD5F_OK) { return ret; } - /* 二次装载:消除"提前就绪"竞态(见函数说明) */ - gd5f_page_read_issue(page_addr); - return gd5f_wait_busy(100); + /* 固定沉降:等待 array→buffer 整页装载完成(见函数说明) */ + HAL_Delay(GD5F_PAGE_READ_SETTLE_MS); + + return GD5F_OK; } /* @@ -267,15 +258,17 @@ static int gd5f_page_program(uint32_t page_addr, uint16_t column, * 函数说明:发 02h + 2字节列地址后发送数据;超过 DMA 阈值走 DMA */ /* - * 函数功能:单次 program load(02h + 列地址 + 数据流) + * 函数功能:将数据加载到芯片内部缓存(PROGRAM LOAD) * 入口参数:column - 列(页内)偏移 uint16_t 本驱动恒为 0 * p_buf - 数据缓冲区 const uint8_t* 不为 NULL * size - 数据长度 size_t > 0 - * 返回值:无(SPI 传输错误由 DMA/超时机制内部处理) - * 限定条件:SPI 已初始化 - * 函数说明:gd5f_program_load 的装载单元,被调用两次(二次装载) + * 返回值:0 - 成功,其它 - 错误 + * 限定条件:SPI 已初始化;目标区域已擦除 + * 函数说明:发 02h + 2字节列地址后发送数据;超过 DMA 阈值走 DMA。 + * (buffer 由 SPI 数据流直接填充,无 array→buffer 竞态, + * 无需二次装载;program exec 的落盘校验由 FTL 回读完成) */ -static void gd5f_program_load_once(uint16_t column, const uint8_t *p_buf, size_t size) { +int gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) { uint8_t cmd[3]; cmd[0] = GD5F_CMD_PROGRAM_LOAD; cmd[1] = (uint8_t)(column >> 8); @@ -290,36 +283,19 @@ static void gd5f_program_load_once(uint16_t column, const uint8_t *p_buf, size_t if (HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)p_buf, (uint16_t)size) != HAL_OK) { GD5F_CS_HIGH(); - return; + return GD5F_ERROR; } while (g_spi1_dma_done == 0U) { if ((HAL_GetTick() - tick_start) >= GD5F_SPI_TIMEOUT) { HAL_SPI_DMAStop(&hspi1); GD5F_CS_HIGH(); - return; + return GD5F_BUSY_TIMEOUT; } } } else { HAL_SPI_Transmit(&hspi1, (uint8_t *)p_buf, size, GD5F_SPI_TIMEOUT); } GD5F_CS_HIGH(); -} - -/* - * 函数功能:将数据加载到芯片内部缓存(PROGRAM LOAD,二次装载) - * 入口参数:column - 列(页内)偏移 uint16_t 本驱动恒为 0 - * p_buf - 数据缓冲区 const uint8_t* 不为 NULL - * size - 数据长度 size_t > 0 - * 返回值:0 - 成功,其它 - 错误 - * 限定条件:SPI 已初始化;目标区域已擦除 - * 函数说明:发 02h + 2字节列地址后发送数据;超过 DMA 阈值走 DMA。 - * 连续装载两次(2026-09-20 台架实证:低 VDD 下数据流可能只 - * 部分落入芯片 buffer 即报就绪,program exec 只编程一半 → - * 静默数据损坏;二次装载覆盖同一 buffer 保证整页到位) - */ -int gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) { - gd5f_program_load_once(column, p_buf, size); - gd5f_program_load_once(column, p_buf, size); return GD5F_OK; } diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h index 8f1192e3..045b0db5 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h @@ -58,6 +58,16 @@ extern "C" { #define GD5F_TOTAL_PAGE_SIZE 2112 #define GD5F_PAGES_PER_BLOCK 64 #define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE) + +/* + * 页读取固定沉降延时(2026-09-20 台架实证):13h 发出后 array→buffer + * 的整页装载完成前,就绪信号可能提前清零(低 VDD 下内部传输速率下降, + * 确定性早于 0Bh 读完成)→ 0Bh 流式读到"前段新、后段旧"的混合页 + * (journal checkpoint header 有效而 meta 残留旧数据 → 复位后 resume + * 锚定新 checkpoint 却读到旧树 → 数据静默丢失)。13h 之后、0Bh 之前 + * 强制等待该时长,保证整页新鲜。取值须覆盖低 VDD 下 t_RR 最慢工况。 + */ +#define GD5F_PAGE_READ_SETTLE_MS 5 #define GD5F_TOTAL_BLOCKS 2048 #define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE)