GD5F 补 DMA 守卫负路径用例 TC-704/705,导出阈值宏并对齐测试指南

This commit is contained in:
2026-09-21 03:01:49 +08:00
parent 45a3d0d06b
commit 5d386cedfb
4 changed files with 142 additions and 36 deletions
+75 -18
View File
@@ -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 <string.h>
#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 */