From 5d386cedfbc672ae872831efb4bdd5725bea17d7 Mon Sep 17 00:00:00 2001
From: Wanderingss <1624155937@qq.com>
Date: Mon, 21 Sep 2026 03:01:49 +0800
Subject: [PATCH] =?UTF-8?q?GD5F=20=E8=A1=A5=20DMA=20=E5=AE=88=E5=8D=AB?=
=?UTF-8?q?=E8=B4=9F=E8=B7=AF=E5=BE=84=E7=94=A8=E4=BE=8B=20TC-704/705?=
=?UTF-8?q?=EF=BC=8C=E5=AF=BC=E5=87=BA=E9=98=88=E5=80=BC=E5=AE=8F=E5=B9=B6?=
=?UTF-8?q?=E5=AF=B9=E9=BD=90=E6=B5=8B=E8=AF=95=E6=8C=87=E5=8D=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c | 13 ++--
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h | 10 +++
docs/测试说明/GD5F2GQ5UE_Test_Guide.md | 62 ++++++++++++++---
test/gd5f_test_task.c | 93 +++++++++++++++++++++-----
4 files changed, 142 insertions(+), 36 deletions(-)
diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c
index afe3e4fb..0d4b92c6 100644
--- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c
+++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c
@@ -45,13 +45,12 @@ extern SPI_HandleTypeDef hspi1;
/* DMA 完成标志(ch395f.c 中的 HAL_SPI_TxRxCpltCallback 会设置此标志) */
volatile uint8_t g_spi1_dma_done;
-/* DMA 阈值(字节数超过此值使用 DMA 传输) */
-/* DMA 阈值 1024B(2026-09-20):阈值以下走 CPU 轮询。存在把**栈上小缓冲**
- * 直接传进本驱动做收发的大小(dhara meta 读 132B、dhara_nand_is_free 64B),
- * 任务栈随 FreeRTOS 堆驻留 CCM(0x10000000),而 DMA1/DMA2 物理上不可达
- * CCM——此类传输必须留在轮询域,否则静默失败(CCM 首次扩容实验实证的根因)。
- * 页级大块传输(2048)仍走 DMA,源/目的全部为文件作用域静态缓冲。 */
-#define GD5F_DMA_THRESHOLD 1024
+/* DMA 阈值(字节数超过此值使用 DMA 传输):取值定义在头文件,理由如下——
+ * 阈值以下走 CPU 轮询。存在把**栈上小缓冲**直接传进本驱动做收发的大小
+ * (dhara meta 读 132B、dhara_nand_is_free 64B),任务栈随 FreeRTOS 堆驻留
+ * CCM(0x10000000),而 DMA1/DMA2 物理上不可达 CCM——此类传输必须留在轮询域,
+ * 否则静默失败(CCM 首次扩容实验实证的根因)。页级大块传输(2048)仍走 DMA,
+ * 源/目的全部为文件作用域静态缓冲。 */
/* DMA 可达内存区间:必须与分散加载文件 RW_IRAM1(0x20000000,128KB,
* SRAM1+SRAM2)一致。CCM(0x10000000,64KB)DMA1/DMA2 物理不可达,
diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h
index 7823a96c..d2e82b06 100644
--- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h
+++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h
@@ -72,6 +72,16 @@ extern "C" {
#define GD5F_TOTAL_BLOCKS 2048
#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE)
+/*
+ * SPI DMA 传输阈值:超过该字节数走 DMA,否则走 CPU 轮询。
+ * 取值约束:① 必须 >= 存储路径上可能出现在任务栈的最大缓冲(dhara meta 132B、
+ * dhara_nand_is_free 64B)——任务栈随 FreeRTOS 堆驻留 CCM(0x10000000),
+ * 而 DMA1/DMA2 物理不可达 CCM,栈缓冲一旦进 DMA 即静默失败(2026-09-20 实证);
+ * ② 必须 < 页大小(2048),页级传输保留 DMA。
+ * 公开此宏供测试用例对齐阈值上下界,避免测试取值与驱动漂移。
+ */
+#define GD5F_DMA_THRESHOLD 1024
+
/* 坏块表持久化:保留块池数量(从 NAND 顶部向下挑选出厂好块存储 BBT) */
#define GD5F_BBT_POOL_COUNT 4
diff --git a/docs/测试说明/GD5F2GQ5UE_Test_Guide.md b/docs/测试说明/GD5F2GQ5UE_Test_Guide.md
index 562068c0..07a35868 100644
--- a/docs/测试说明/GD5F2GQ5UE_Test_Guide.md
+++ b/docs/测试说明/GD5F2GQ5UE_Test_Guide.md
@@ -28,7 +28,7 @@
| 总块数 | 2048 | `GD5F_TOTAL_BLOCKS` |
| 总容量 | 256 MB | `GD5F_TOTAL_SIZE` |
| 最小擦除单位 | 1 块(128 KB) | 不可按页/字节擦除 |
-| DMA 阈值 | 32 B | `GD5F_DMA_THRESHOLD`,>32B 走 `HAL_SPI_*_DMA` |
+| DMA 阈值 | 1024 B | `GD5F_DMA_THRESHOLD`,>1024B 走 `HAL_SPI_*_DMA`;非 SRAM 缓冲由运行时守卫回落轮询(见阶段 7) |
### 寄存器与状态位
@@ -422,9 +422,12 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
---
-## 8. 阶段 7:DMA 边界(阈值 32 字节)
+## 8. 阶段 7:DMA 边界与 DMA 可达性守卫(阈值 1024 字节)
-> 驱动 `GD5F_DMA_THRESHOLD=32`:`size>32` 走 `HAL_SPI_*_DMA`,否则轮询。两路径结果必须一致。
+> 驱动 `GD5F_DMA_THRESHOLD=1024`:`size>1024` 走 `HAL_SPI_*_DMA`,否则轮询。两路径结果必须一致。
+> **前置约束**:DMA 源/目的缓冲必须落在 SRAM(`RW_IRAM1`,0x20000000~0x2001FFFF)。CCM(0x10000000)
+> 为 DMA1/DMA2 物理不可达区,误用会静默不落地;驱动已加运行时守卫 `gd5f_dma_buf_ok()`,
+> 越界缓冲自动回落轮询并打印 `[ERR][NAND] … not DMA-reachable … fallback poll`。
### TC-GD5F-701: 阈值下界(轮询路径)
@@ -433,9 +436,9 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
| **ID** | TC-GD5F-701 |
| **优先级** | P1 |
| **类型** | 边界测试 |
-| **标题** | size=32 走非 DMA 路径,读写正确 |
+| **标题** | size=1024(= `GD5F_DMA_THRESHOLD`)走非 DMA 路径,读写正确 |
| **前置条件** | 目标块已擦除 |
-| **测试步骤** | 写/读 32 字节并比对 |
+| **测试步骤** | 写/读 1024 字节并比对 |
| **通过标准** | 数据一致 |
| **覆盖原则** | `GD5F_DMA_THRESHOLD` 下界 |
@@ -446,9 +449,9 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
| **ID** | TC-GD5F-702 |
| **优先级** | P1 |
| **类型** | 边界测试 |
-| **标题** | size=33 走 DMA 路径,读写正确 |
+| **标题** | size=1025(= `GD5F_DMA_THRESHOLD`+1)走 DMA 路径,读写正确 |
| **前置条件** | 目标块已擦除 |
-| **测试步骤** | 写/读 33 字节并比对 |
+| **测试步骤** | 写/读 1025 字节并比对 |
| **通过标准** | 数据一致 |
| **覆盖原则** | `GD5F_DMA_THRESHOLD` 上界 |
@@ -465,6 +468,41 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
| **通过标准** | 数据一致 |
| **覆盖原则** | DMA 大数据路径 |
+### TC-GD5F-704: DMA 可达性守卫负路径(读方向)
+
+| 字段 | 值 |
+|------|-----|
+| **ID** | TC-GD5F-704 |
+| **优先级** | P0 |
+| **类型** | 边界/健壮性测试 |
+| **标题** | 目的缓冲位于 CCM(不可达区)时守卫应拒绝 DMA 并回落轮询,数据仍正确 |
+| **前置条件** | FreeRTOS 堆驻留 CCM(scatter `RW_CCM`);探针缓冲由 `pvPortMalloc(2048)` 取得(堆不在 CCM 时用例跳过) |
+| **测试步骤** | 1. 先用 SRAM 静态缓冲参考读同页
2. 探针缓冲预填参考值的反码
3. `gd5f2gq5ue_read()` 整页读入 CCM 探针缓冲
4. 与参考缓冲逐字节比对 |
+| **通过标准** | 数据与参考完全一致,且串口出现 `[ERR][NAND] RX DMA buffer not DMA-reachable (p=0x1000xxxx size=2048), fallback poll` |
+| **判定依据** | 本板实证 DMA 对 CCM 静默不落地:若误走 DMA,探针缓冲保持预填反码必失配——故"数据一致"即证明回落真实发生,而非仅"未报错" |
+| **覆盖原则** | DMA 可达性守卫(读方向);堆缓冲禁入 DMA 的运行时强制(内存分配策略 R3) |
+
+### TC-GD5F-705: DMA 可达性守卫负路径(写方向)
+
+| 字段 | 值 |
+|------|-----|
+| **ID** | TC-GD5F-705 |
+| **优先级** | P0 |
+| **类型** | 边界/健壮性测试 |
+| **标题** | 源缓冲位于 CCM(不可达区)时守卫应拒绝 DMA 并回落轮询,数据仍正确落盘 |
+| **前置条件** | 同 TC-GD5F-704;目标块已擦除 |
+| **测试步骤** | 1. 探针缓冲填入 `i^0x5A` 图案
2. `gd5f2gq5ue_write()` 整页写入
3. 读回 SRAM 静态缓冲逐字节比对 |
+| **通过标准** | 写读一致,且串口出现 `[ERR][NAND] TX DMA buffer not DMA-reachable … fallback poll` |
+| **判定依据** | 同 TC-GD5F-704(写方向 DMA 读 CCM 同样不落地) |
+| **覆盖原则** | DMA 可达性守卫(写方向);堆缓冲禁入 DMA 的运行时强制(内存分配策略 R3) |
+
+> ⚠ **卷破坏警告**:阶段 8 会调用 `nand_ftl_format()` 清空 dhara map,阶段 9 会写入文件——
+> 整轮 GD5F 套件(含 Phase 8/9)运行后卷数据即失效,且大写入可能使 dhara 把若干块记为
+> 运行期坏块(2026-09-21 实测:一次整轮运行容量 95248 → 95200,日志见
+> `[ERR][NAND_FTL] program verify: data mismatch, blk 305`,该块由 dhara 自行隔离,测试仍 68/68 通过)。
+> 需要恢复干净态时,启用 `ENABLE_STORAGE_RECOVERY_TESTS` 跑一次 STORAGE 套件的 TC-STO-04
+> (重建 BBT + 重新格式化)。
+
## 9. 阶段 8:FTL 层(nand_ftl)
### TC-GD5F-801: nand_ftl_init 成功
@@ -673,9 +711,11 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
| TC-GD5F-603 | block_erase 原语 | P1 | PASS |
| TC-GD5F-604 | write_enable WEL 位 | P2 | PASS |
| TC-GD5F-605 | wait_busy 正常返回 | P2 | PASS |
-| TC-GD5F-701 | DMA 阈值下界(32) | P1 | PASS |
-| TC-GD5F-702 | DMA 阈值上界(33) | P1 | PASS |
+| TC-GD5F-701 | DMA 阈值下界(1024) | P1 | PASS |
+| TC-GD5F-702 | DMA 阈值上界(1025) | P1 | PASS |
| TC-GD5F-703 | 大块 DMA 一致性 | P1 | PASS |
+| TC-GD5F-704 | DMA 守卫负路径(读,CCM) | P0 | PASS |
+| TC-GD5F-705 | DMA 守卫负路径(写,CCM) | P0 | PASS |
| TC-GD5F-801 | nand_ftl_init | P0 | PASS |
| TC-GD5F-802 | nand_ftl_format | P1 | PASS |
| TC-GD5F-901 | FatFS 挂载写读 | P2 | PASS |
@@ -688,7 +728,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
| TC-STO-03 | 坏块注入下存储写入 | P1 | PASS |
| TC-STO-04 | BBT 重建 + 重新格式化(恢复) | P1 | 受 `ENABLE_STORAGE_RECOVERY_TESTS` 控制(默认关) |
-> 当前实测:`TEST_SUITE_GD5F` 构建一次运行全部阶段,结尾输出 `=== GD5F2GQ5UE Tests: 65/65 PASSED (failed=0) ===`(65 为各 TC 内部断言总数,含 TC-GD5F-205~207 BBT 持久化用例;TC 覆盖见上表)。`TEST_SUITE_STORAGE` 套件结尾输出 `=== Storage Tests: 11/11 PASSED (failed=0) ===`(TC-STO-01/02/03 各含若干内部断言,且 TC-STO-01 依赖的 `s_cached_lpn` 哨兵 bug 已修复)。两套件均 0 错误 0 警告通过 MDK 编译。
+> 当前实测:`TEST_SUITE_GD5F` 构建一次运行全部阶段,结尾输出 `=== GD5F2GQ5UE Tests: 68/68 PASSED (failed=0) ===`(68 为各 TC 内部断言总数,含 TC-GD5F-205~207 BBT 持久化用例、TC-GD5F-704/705 DMA 守卫负路径;TC 覆盖见上表)。`TEST_SUITE_STORAGE` 套件结尾输出 `=== Storage Tests: 11/11 PASSED (failed=0) ===`(TC-STO-01/02/03 各含若干内部断言,且 TC-STO-01 依赖的 `s_cached_lpn` 哨兵 bug 已修复)。两套件均 0 错误 0 警告通过 MDK 编译。
---
@@ -733,7 +773,7 @@ ECC 状态(`ECCS1:ECCS0`):`00`=无错;`01/10/11`=纠正 1/2/3 bit;`10`
| 总块数 / 容量 | 2048 / 256 MB |
| ID | MID=0xC8, DID=0x52 |
| 擦除最小单位 | 1 块(128 KB,须对齐) |
-| DMA 阈值 | 32 B(>32 走 DMA) |
+| DMA 阈值 | 1024 B(>1024 走 DMA;非 SRAM 缓冲由守卫回落轮询) |
| 状态寄存器 | 0xC0;OIP=0, WEL=1, E_FAIL=2, P_FAIL=3, ECCS=4/5 |
| Feature 寄存器 | 0xB0;ECC_EN=4, QE=0 |
| Protect 寄存器 | 0xA0;init 后写 0x00 解除保护 |
diff --git a/test/gd5f_test_task.c b/test/gd5f_test_task.c
index bd5bb685..2bc3b699 100644
--- a/test/gd5f_test_task.c
+++ b/test/gd5f_test_task.c
@@ -2,8 +2,9 @@
* 模块名称:GD5F2GQ5UE Driver Test Task
* 模块功能:GD5F2GQ5UE 驱动全阶段测试入口,统一在 defaultTask 上下文(同步阻塞)
* 中运行。各阶段由 gd5f_test.h 中的 ENABLE_GD5F_PHASE*_TESTS 宏独立开关,
- * 覆盖 init/read_id/reset、BBT、页读写、块擦除、ECC、SPI 原语、DMA 边界、
- * FTL 与 FatFS。所有结果通过 GD5F_TEST_CHECK / GD5F_TEST_REPORT 输出串口。
+ * 覆盖 init/read_id/reset、BBT、页读写、块擦除、ECC、SPI 原语、DMA 边界与
+ * DMA 可达性守卫负路径、FTL 与 FatFS。所有结果通过 GD5F_TEST_CHECK /
+ * GD5F_TEST_REPORT 输出串口。
* 作者:王建锋
* 创建日期:2026-08-26
*
@@ -12,6 +13,7 @@
******************************************************************************/
#include
+#include "FreeRTOS.h"
#include "test_config.h"
#include "gd5f_test.h"
#include "nand_ftl.h"
@@ -30,6 +32,10 @@ gd5f_test_stats_t g_gd5f_test_stats;
static uint8_t s_wbuf[GD5F_PAGE_SIZE * 2];
static uint8_t s_rbuf[GD5F_PAGE_SIZE * 2];
+/* CCM(SRAM3)区间:DMA1/DMA2 物理不可达,用于守卫负路径的前提判定 */
+#define GD5F_TEST_CCM_BASE 0x10000000UL
+#define GD5F_TEST_CCM_END 0x10010000UL
+
/* -------------------------------------------------------------------
* 辅助:从最高块向下寻找连续 n 个好块,返回其中最高块号;找不到返回 GD5F_TOTAL_BLOCKS
* ------------------------------------------------------------------- */
@@ -514,7 +520,7 @@ static void gd5f_phase6(void)
#endif /* ENABLE_GD5F_PHASE6_TESTS */
/* -------------------------------------------------------------------
- * Phase 7 — DMA 边界(阈值 32 字节)
+ * Phase 7 — DMA 边界与 DMA 可达性守卫(阈值见 GD5F_DMA_THRESHOLD)
* ------------------------------------------------------------------- */
#ifdef ENABLE_GD5F_PHASE7_TESTS
static void gd5f_phase7(void)
@@ -522,37 +528,42 @@ static void gd5f_phase7(void)
uint32_t blk;
int32_t base;
int32_t ret, ok, i;
+ uint8_t *p_heap; /* 堆缓冲探针(堆驻留 CCM → DMA 不可达) */
+ uintptr_t p_addr;
- DBG_INFO("=== GD5F Phase 7: DMA boundary (threshold 32) ===");
+ DBG_INFO("=== GD5F Phase 7: DMA boundary (threshold %d) ===",
+ (int)GD5F_DMA_THRESHOLD);
blk = gd5f_find_run(1);
base = (int32_t)blk * GD5F_BLOCK_SIZE;
- /* TC-GD5F-701: size=32 轮询路径 */
+ /* TC-GD5F-701: 阈值下界(= 阈值,轮询路径) */
gd5f2gq5ue_erase(base, GD5F_BLOCK_SIZE);
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < (int32_t)GD5F_DMA_THRESHOLD; i++) {
s_wbuf[i] = (uint8_t)(i + 0x10);
}
- ret = gd5f2gq5ue_write(base, s_wbuf, 32);
- GD5F_TEST_CHECK(ret == GD5F_OK, "TC-GD5F-701 write(32) ret=%d", ret);
- memset(s_rbuf, 0, 32);
- ret = gd5f2gq5ue_read(base, s_rbuf, 32);
+ ret = gd5f2gq5ue_write(base, s_wbuf, GD5F_DMA_THRESHOLD);
+ GD5F_TEST_CHECK(ret == GD5F_OK, "TC-GD5F-701 write(%d) ret=%d",
+ (int)GD5F_DMA_THRESHOLD, ret);
+ memset(s_rbuf, 0, GD5F_DMA_THRESHOLD);
+ ret = gd5f2gq5ue_read(base, s_rbuf, GD5F_DMA_THRESHOLD);
ok = 1;
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < (int32_t)GD5F_DMA_THRESHOLD; i++) {
if (s_rbuf[i] != (uint8_t)(i + 0x10)) { ok = 0; break; }
}
GD5F_TEST_CHECK(ok, "TC-GD5F-701 polling path %s", ok ? "OK" : "MISMATCH");
- /* TC-GD5F-702: size=33 DMA 路径 */
+ /* TC-GD5F-702: 阈值上界(= 阈值+1,DMA 路径,缓冲在 SRAM 静态区) */
gd5f2gq5ue_erase(base, GD5F_BLOCK_SIZE);
- for (i = 0; i < 33; i++) {
+ for (i = 0; i < (int32_t)GD5F_DMA_THRESHOLD + 1; i++) {
s_wbuf[i] = (uint8_t)(i + 0x20);
}
- ret = gd5f2gq5ue_write(base, s_wbuf, 33);
- GD5F_TEST_CHECK(ret == GD5F_OK, "TC-GD5F-702 write(33) ret=%d", ret);
- memset(s_rbuf, 0, 33);
- ret = gd5f2gq5ue_read(base, s_rbuf, 33);
+ ret = gd5f2gq5ue_write(base, s_wbuf, GD5F_DMA_THRESHOLD + 1U);
+ GD5F_TEST_CHECK(ret == GD5F_OK, "TC-GD5F-702 write(%d) ret=%d",
+ (int)GD5F_DMA_THRESHOLD + 1, ret);
+ memset(s_rbuf, 0, GD5F_DMA_THRESHOLD + 1U);
+ ret = gd5f2gq5ue_read(base, s_rbuf, GD5F_DMA_THRESHOLD + 1U);
ok = 1;
- for (i = 0; i < 33; i++) {
+ for (i = 0; i < (int32_t)GD5F_DMA_THRESHOLD + 1; i++) {
if (s_rbuf[i] != (uint8_t)(i + 0x20)) { ok = 0; break; }
}
GD5F_TEST_CHECK(ok, "TC-GD5F-702 DMA path %s", ok ? "OK" : "MISMATCH");
@@ -571,6 +582,52 @@ static void gd5f_phase7(void)
if (s_rbuf[i] != (uint8_t)(i & 0xFF)) { ok = 0; break; }
}
GD5F_TEST_CHECK(ok, "TC-GD5F-703 DMA whole page %s", ok ? "OK" : "MISMATCH");
+
+ /* ================= DMA 可达性守卫(负路径) =================
+ * 探针缓冲取自 FreeRTOS 堆:堆驻留 CCM(0x10000000),DMA1/DMA2 不可达。
+ * 期望:驱动守卫拒绝该缓冲 → 回落 CPU 轮询 → 数据仍正确落位(轮询可写 CCM)。
+ * 判定依据(本板实证):若误走 DMA,CCM 内容不会改变(静默不落地),
+ * 故"数据与参考一致"即证明回落确实发生——非仅未报错。
+ * 堆不在 CCM 时本用例前提不成立(改为验证正路径无意义),跳过并记录。 */
+ p_heap = (uint8_t *)pvPortMalloc(GD5F_PAGE_SIZE);
+ if (p_heap == NULL) {
+ GD5F_TEST_CHECK(0, "TC-GD5F-704 pvPortMalloc(2048) failed");
+ } else {
+ p_addr = (uintptr_t)p_heap;
+ if ((p_addr < GD5F_TEST_CCM_BASE) || (p_addr >= GD5F_TEST_CCM_END)) {
+ DBG_INFO("TC-GD5F-704/705 SKIP: heap buf not in CCM (p=0x%08lX)",
+ (unsigned long)p_addr);
+ } else {
+ /* TC-GD5F-704: 读方向 —— 目的缓冲在 CCM,应回落轮询 */
+ memset(s_rbuf, 0, GD5F_PAGE_SIZE);
+ (void)gd5f2gq5ue_read(base, s_rbuf, GD5F_PAGE_SIZE); /* 参考读(SRAM 静态) */
+ for (i = 0; i < GD5F_PAGE_SIZE; i++) {
+ p_heap[i] = (uint8_t)~s_rbuf[i]; /* 预填参考值反码:未落数必失配 */
+ }
+ ret = gd5f2gq5ue_read(base, p_heap, GD5F_PAGE_SIZE);
+ ok = (ret == GD5F_OK) &&
+ (memcmp(p_heap, s_rbuf, GD5F_PAGE_SIZE) == 0);
+ GD5F_TEST_CHECK(ok, "TC-GD5F-704 CCM(heap) rx poll fallback %s",
+ ok ? "OK" : "MISMATCH");
+
+ /* TC-GD5F-705: 写方向 —— 源缓冲在 CCM,应回落轮询 */
+ gd5f2gq5ue_erase(base, GD5F_BLOCK_SIZE);
+ for (i = 0; i < GD5F_PAGE_SIZE; i++) {
+ p_heap[i] = (uint8_t)(i ^ 0x5A);
+ }
+ ret = gd5f2gq5ue_write(base, p_heap, GD5F_PAGE_SIZE);
+ GD5F_TEST_CHECK(ret == GD5F_OK, "TC-GD5F-705 write(CCM src) ret=%d", ret);
+ memset(s_rbuf, 0, GD5F_PAGE_SIZE);
+ ret = gd5f2gq5ue_read(base, s_rbuf, GD5F_PAGE_SIZE);
+ ok = 1;
+ for (i = 0; i < GD5F_PAGE_SIZE; i++) {
+ if (s_rbuf[i] != (uint8_t)(i ^ 0x5A)) { ok = 0; break; }
+ }
+ GD5F_TEST_CHECK(ok, "TC-GD5F-705 CCM(heap) tx poll fallback %s",
+ ok ? "OK" : "MISMATCH");
+ }
+ vPortFree(p_heap);
+ }
}
#endif /* ENABLE_GD5F_PHASE7_TESTS */