From 45a3d0d06b2cb324d0a426dbfa6808195e93b9b0 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Mon, 21 Sep 2026 02:56:54 +0800 Subject: [PATCH] =?UTF-8?q?GD5F=20=E9=A9=B1=E5=8A=A8=E5=A2=9E=E8=AE=BE=20D?= =?UTF-8?q?MA=20=E5=8F=AF=E8=BE=BE=E6=80=A7=E8=BF=90=E8=A1=8C=E6=97=B6?= =?UTF-8?q?=E5=AE=88=E5=8D=AB=EF=BC=8C=E9=9D=9E=20SRAM=20=E7=BC=93?= =?UTF-8?q?=E5=86=B2=E6=8B=92=E8=B5=B0=20DMA=20=E5=9B=9E=E8=90=BD=E8=BD=AE?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c | 72 ++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c index 093cf9ca..afe3e4fb 100644 --- a/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c +++ b/Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c @@ -53,6 +53,15 @@ volatile uint8_t g_spi1_dma_done; * 页级大块传输(2048)仍走 DMA,源/目的全部为文件作用域静态缓冲。 */ #define GD5F_DMA_THRESHOLD 1024 +/* DMA 可达内存区间:必须与分散加载文件 RW_IRAM1(0x20000000,128KB, + * SRAM1+SRAM2)一致。CCM(0x10000000,64KB)DMA1/DMA2 物理不可达, + * RW_CCM 区任何缓冲都不得进 DMA。阈值只能挡住"当前已知的小栈缓冲", + * 挡不住"将来新加的 >1024B 栈缓冲";gd5f_dma_buf_ok() 把这条约定 + * 升级为运行时强制检查(2026-09-21 加固)。若将来新增其它 DMA 可达 + * 内存(如外部 SDRAM),此处区间必须同步扩展。 */ +#define GD5F_DMA_RAM_BASE 0x20000000UL +#define GD5F_DMA_RAM_END 0x20020000UL + /* * 函数功能:SPI1 TX DMA 完成回调(PROGRAM_LOAD 数据发送用) * 入口参数:hspi - 触发回调的 SPI 句柄 SPI_HandleTypeDef* @@ -91,6 +100,42 @@ static int gd5f_private_bbt_find_best(void); static int gd5f_bbt_load(void); static int gd5f_bbt_save(void); +/* DMA 可达性守卫(见下方实现) */ +static int gd5f_dma_buf_ok(const void *p_buf, size_t size); + +/* ======================== DMA 可达性守卫 ======================== */ + +/* + * 函数功能:判定缓冲是否位于 DMA 可达内存(SRAM1+SRAM2) + * 入口参数:p_buf - 传输缓冲首地址 const void* + * size - 传输字节数 size_t + * 返回值:1 - 整段缓冲 DMA 可达;0 - 不可达(调用方须回落 CPU 轮询) + * 限定条件:无 + * 函数说明:DMA1/DMA2 物理不可达 CCM(0x10000000)——以 CCM 缓冲做 DMA + * 源/目的会静默不落地(2026-09-20 首轮 CCM 扩容实验实证根因)。 + * 本函数把"栈/堆缓冲禁入 DMA"的约定升级为运行时强制约束: + * 起止地址任一越出 SRAM 区间即判不可达。 + */ +static int gd5f_dma_buf_ok(const void *p_buf, size_t size) { + uint32_t start = (uint32_t)(uintptr_t)p_buf; + uint32_t end; + + if (size == 0U) { + return 0; + } + + end = start + (uint32_t)size; + if (end < start) { /* 地址回绕:不可能落在同一区间内 */ + return 0; + } + + if ((start < GD5F_DMA_RAM_BASE) || (end > GD5F_DMA_RAM_END)) { + return 0; + } + + return 1; +} + /* ======================== SPI 原语定义 ======================== */ /* @@ -223,6 +268,17 @@ int gd5f_page_read(uint32_t page_addr) { int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, size_t size) { uint8_t cmd[4] = {0}; + uint8_t use_dma = 0U; + + /* 守卫判定须在 CS 拉低之前完成:DBG_ERROR 走串口,不能占着 CS 窗口 */ + if (size > GD5F_DMA_THRESHOLD) { + use_dma = (uint8_t)gd5f_dma_buf_ok(p_buf, size); + if (use_dma == 0U) { + DBG_ERROR("RX DMA buffer not DMA-reachable " + "(p=0x%08lX size=%lu), fallback poll", + (unsigned long)(uintptr_t)p_buf, (unsigned long)size); + } + } cmd[0] = GD5F_CMD_READ_FROM_CACHE; cmd[1] = (column >> 8) & 0xFF; @@ -232,7 +288,7 @@ int gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, GD5F_CS_LOW(); HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT); - if (size > GD5F_DMA_THRESHOLD) { + if (use_dma != 0U) { uint32_t tick_start = HAL_GetTick(); g_spi1_dma_done = 0U; if (HAL_SPI_Receive_DMA(&hspi1, p_buf, (uint16_t)size) != HAL_OK) { @@ -294,6 +350,18 @@ static int gd5f_page_program(uint32_t page_addr, uint16_t column, */ int gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) { uint8_t cmd[3]; + uint8_t use_dma = 0U; + + /* 守卫判定须在 CS 拉低之前完成:DBG_ERROR 走串口,不能占着 CS 窗口 */ + if (size > GD5F_DMA_THRESHOLD) { + use_dma = (uint8_t)gd5f_dma_buf_ok(p_buf, size); + if (use_dma == 0U) { + DBG_ERROR("TX DMA buffer not DMA-reachable " + "(p=0x%08lX size=%lu), fallback poll", + (unsigned long)(uintptr_t)p_buf, (unsigned long)size); + } + } + cmd[0] = GD5F_CMD_PROGRAM_LOAD; cmd[1] = (uint8_t)(column >> 8); cmd[2] = (uint8_t)(column); @@ -301,7 +369,7 @@ int gd5f_program_load(uint16_t column, const uint8_t *p_buf, size_t size) { GD5F_CS_LOW(); HAL_SPI_Transmit(&hspi1, cmd, 3, GD5F_SPI_TIMEOUT); - if (size > GD5F_DMA_THRESHOLD) { + if (use_dma != 0U) { uint32_t tick_start = HAL_GetTick(); g_spi1_dma_done = 0U; if (HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)p_buf, (uint16_t)size)